Wie erstelle ich einen Hotkey für eine Folge von Eingaben, während ich die Strg-Taste gedrückt halte, z. B. {Ctrl Down} ec {Ctrl Up}?

7

In Visual Studio Express 2013 wurden beispielsweise viele der Formatierungsverknüpfungen in Ctrl+ "gefaltet" E. Um eine Auswahl zu kommentieren, würde man gedrückt halten Ctrl, schlagen E, schlagen Cund dann loslassen Ctrl.

    Geben Sie hier die Bildbeschreibung ein

Wenn ich solche Eingaben senden würde, würde ich schreiben

SendInput {Ctrl Down}ec{Ctrl Up}

Aber wie mache ich aus dieser Sequenz einen Hotkey? Ich habe es versucht

{Ctrl Down}EC{Ctrl Up}::
    MsgBox, "Hello, world!"
    Return

Dies führt jedoch natürlich zu einem Syntaxfehler:

    Geben Sie hier die Bildbeschreibung ein

Andrew Cheong
quelle
2
Wenn ich das richtig verstehe, ist Ihre Frage nicht spezifisch für Visual Studio und Sie möchten im Allgemeinen einen Hotkey erstellen, der mehr als einen Nicht-Modifikator-Schlüssel verwendet. Die Syntax Ihrer Hotkey-Deklaration ist weit entfernt. Deshalb empfehle ich, den entsprechenden Teil der Dokumente zu lesen . Zu Ihrem Problem: Das Kombinieren von mehr als einem Nicht-Modifikator-Schlüssel in einem Hotkey ist in der Standard-AHK nicht vorgesehen, aber es gibt eine Problemumgehung, die dieses Verhalten ziemlich gut simuliert. Schauen Sie sich das hier an .
MCL
@MCL, danke für den Link! Die Loop-Lösung hat tatsächlich funktioniert! Aber ich war entschlossen, eine Lösung ohne Schleife zu finden, und fand schließlich eine (selbst beantwortet, unten). Vielen Dank auch für Ihre nachdenkliche Antwort. Eigentlich war das {Ctrl Down}EC{Ctrl Up}keine Lösung, die ich ernsthaft versuchte. Ich habe viele andere Dinge ausprobiert (Sie können einige Beispiele in meiner Erklärung sehen), aber ich wollte nicht alles erklären, was ich versucht habe, und ich wollte auch keine Benutzer abschrecken, die mir helfen könnten, indem ich so aussehe, als hätte ich es bereits versucht fortgeschrittene Techniken. Ich hoffe es ist verständlich ...
Andrew Cheong

Antworten:

7

Endlich herausgefunden.

tl; dr

Durch ^eersten gewünschten Tastendruck ersetzen . Ersetzen Sie den 3zweiten gewünschten Tastendruck durch den ASCII-Index. Dies erzwingt, dass Ctrldurch beide Tastenanschläge gehalten wird, andernfalls wird abgebrochen.

~$Ctrl UP::
    ChordIsBroken := True
    Return
^e::
    ChordIsBroken := False
    Input, OutputVar, L1 M
    If (!ChordIsBroken && Asc(OutputVar) = 3)
    {
        MsgBox "Hello, World!"
    }
    Else
    {
        SendInput %OutputVar%
    }
    Return

Zur Anpassung dies Shiftstatt Ctrl, dann würden Sie die ersetzen müssen Ctrls, entfernen Sie das M, und machen Sie einen einfacheren Vergleich wie OutputVar = Cstatt der Asc(OutputVar) = 3. Nicht sicher , wie dies zu erweitern , um Altund Winaber Sie könnten versuchen müssen , L2oder etwas ähnliches.

Erläuterung

Inputschien ein naheliegender Ort zu sein, um anzufangen. Inputfordert AHK auf, auf Benutzereingaben zu warten, z

^e::
    Input, OutputVar, L1        ; "L1" means wait for 1 keystroke then continue.
    If (OutputVar = "c")
    {
        MsgBox, "Hello, World!"
    }
    Return

Das Meldungsfeld über Trigger auf CtrlEdann C. Aber wir suchen CtrlC, also lassen Sie uns das beheben:

^e::
    Input, OutputVar, L1 M      ; "M" allows storage of modified keystrokes (^c).
    If (Asc(OutputVar) = 3)     ; ASCII character 3 is ^c.
    {
        MsgBox "Hello, World!"
    }
    Return

Jetzt haben wir ein Meldungsfeld auf drücken bekommen CtrlEdann CtrlC. Aber es gibt ein Problem damit: Das Meldungsfeld wird ausgelöst, selbst wenn ich zwischen den beiden Tastenanschlägen loslasse Ctrl . Wie erkennen wir also im Wesentlichen einen {Ctrl Up}Mid-Input? Sie können nicht nur am Eingang nachsehen -

^e::
    if (!GetKeyState("Ctrl"))
    {
        Return
    }
    Input, OutputVar, L1 M 
    ; ...

- oder können Sie nicht nur nach der Eingabe überprüfen -

^e::
    Input, OutputVar, L1 M 
    if (!GetKeyState("Ctrl"))
    {
        Return
    }
    ; ...

- Sie können nicht einmal mit beidem davonkommen, denn egal was passiert, Sie werden die {Ctrl Up}Blockierung für die Eingabe verpassen .

Dann habe ich mich in der DokumentationHotkey nach Inspiration umgesehen. Der benutzerdefinierte Kombinationsoperator &schien vielversprechend. Aber leider,

^e & ^c::
    ; ...

verursachte einen Kompilierungsfehler; Anscheinend dient das &nur zum Kombinieren von unveränderten Tastenanschlägen.

Schließlich war es an UP, und dort habe ich endlich den Durchbruch geschafft. Ich habe Ctrl's neu definiert , UPum einen Umschalter zu setzen , der verhindert, dass das Meldungsfeld ausgelöst wird!

$Ctrl::Send {Ctrl Down}     ; The $ prevents an infinite loop. Although this
$Ctrl UP::                  ; line seems redundant, it is in fact necessary.
    ChordIsBroken := True   ; Without it, Ctrl becomes effectively disabled.
    Send {Ctrl Up}
    Return
^e::
    ChordIsBroken := False
    Input, OutputVar, L1 M
    If (!ChordIsBroken && Asc(OutputVar) = 3)
    {
        MsgBox "Hello, World!"
    }
    Return

Wenn ich jetzt drücke CtrlE, dann loslasse Ctrlund drücke CtrlC, passiert wie erwartet nichts!

Es gab noch eine letzte Sache zu beheben. Bei "Stornierung" (ein "gebrochener Akkord") wollte ich, dass alle Tastenanschläge wieder normal sind. Aber im obigen Code Inputmüsste der einen Tastenanschlag "essen", bevor er zurückkehrt, unabhängig von einem gebrochenen Akkord oder einem irrelevanten sekundären Tastenanschlag. Durch Hinzufügen eines ElseFalls wird das Problem behoben:

    Else
    {
        SendInput %OutputVar%
    }

Da haben Sie es also - "Akkorde" in AutoHotkey. (Obwohl ich das nicht gerade als "Akkord" bezeichnen würde. Eher wie eine Melodie mit einer Basslinie ;-)


@hippibruder weist großzügig darauf hin, dass ich das Definieren vermeiden kann, $Ctrl::indem ~ich $Ctrl UP::nicht blockiere. Dies ermöglicht eine gewisse Vereinfachung! (Das endgültige Ergebnis finden Sie oben im Abschnitt tl; dr.)


Eine Sache noch. Wenn Sie möglicherweise bei "Stornierung" (einem "gebrochenen Akkord") den ersten Tastendruck ausgeben möchten, dh CtrlE alleine, fügen Sie diesen einfach in den ElseBlock ein.

    Else
    {
        SendInput ^e
        SendInput %OutputVar%
    }

und vergessen Sie nicht, den Hotkey in zu ändern

$^e::

eine Endlosschleife zu vermeiden.

Andrew Cheong
quelle
Haben Sie etwas dagegen, ein Beispiel zu veröffentlichen oder auf ein Beispiel für Ctrl+ Shift+ aoder einen bestimmten Schlüssel zu verlinken ? Ich verstehe deine Logik in der Post nicht wirklich. Vielen Dank!
William
Dies ist der Fall, wenn Sie beispielsweise Ctrl+ eine Aktion zuweisen möchten, kgefolgt von Ctrl+, a ohne die freizugebenCtrl . Für so etwas wie Ctrl+ Shift+ wäre anatürlich die richtige Methode einfach ^+a::.
Andrew Cheong
Wow schnelle Antwort. Nun, ich versuche das Folgende ohne Glück zu tun AppsKey::, Ctrl & AppsKey::und ^+AppsKey::. Das 1. und 2. Werk, aber nicht das 3.
William
Ich denke, das liegt daran, dass es AppsKeytechnisch gesehen kein Modifikatorschlüssel ist. Werfen Sie einen Blick auf Ist es möglich, AppsKey oder andere Schlüssel als Modifikator zu verwenden, wenn Sie dies noch nicht getan haben. Viel Glück!
Andrew Cheong
2

Ich glaube nicht, dass es in AHK eine integrierte Unterstützung für Tastenakkorde gibt. Eine Möglichkeit, diese zu erkennen, besteht darin, einen Hotkey für die erste Taste im Akkord (^ e) zu registrieren und dann mit dem Eingabebefehl die nächsten Tasten zu erkennen.

; Tested with AHK_L U64 v1.1.14.03 (and Visual Studio 2010)
; This doesn't block the input. To block it remove '~' from the hotkey and 'V' from Input-Cmd
~^e::
  ; Input-Cmd will capture the next keyinput as its printable representation. 
  ; (i.e. 'Shift-a' produces 'A'. 'a' produces 'a'. 'Ctrl-k' produces nothing printable. This can be changed with 'M' option. Maybe better approch; See help) 
  ; Only the next, because of 'L1'. (Quick-Fail; Not necessary)
  ; To detect 'c' and 'u' with control pressed I used them as EndKeys.
  ; If a EndKey is pressed the Input-Cmd will end and save the EndKey in 'ErrorLevel'.
  Input, _notInUse, V L1 T3, cu

  ; Return if Input-Cmd was not terminated by an EndKey
  ; or 'Control' is no longer pressed. (It would be better if Input-Cmd would be also terminated by a {Ctrl Up}. I don't know if that is possible)
  if ( InStr(ErrorLevel, "Endkey:") != 1
    || !GetKeyState("Control") )
    {
    return
    }

  ; Extract the EndKey-Name from 'ErrorLevel' (ErrorLevel == "Endkey:c")
  key := SubStr(ErrorLevel, 8)    
  if ( InStr(key, "c") == 1 )
    {
    TrayTip,, ^ec
    }
  else if ( InStr(key, "u") == 1 )
    {
    TrayTip,, ^eu
    }
  else
    {
    MsgBox, wut? key="%key%"
    }
return
Hippibruder
quelle
Hallo, @hippibruder. Vielen Dank für Ihre Antwort. Leider hat es sich auf meiner AHK seltsam verhalten (und ich verwende auch AHK_L), und ich konnte nicht herausfinden, warum. Wenn Sie Ihren Code ein wenig erklären könnten (der _, der ErrorLevelusw.), wäre ich bereit, es erneut zu versuchen und zu prüfen, ob Sie tatsächlich die überlegene Lösung haben, die ich akzeptieren sollte.
Andrew Cheong
1
@ acheong87 Ich habe Kommentare hinzugefügt. Zu Ihrer Antwort (Kommentar kann dort nicht hinzugefügt werden): Um "$ Ctrl :: Send {Ctrl Down}" zu entfernen, fügen Sie "$ Ctrl UP ::" ein '~' hinzu und entfernen Sie "Send {Ctrl Up}". Auch Ihr Code funktioniert perfekt (dh wie in VS) für mich ohne die Variable 'ChordIsBroken' insgesamt (nur "^ e" Hotkey).
Hippibruder
Cool, du hast absolut Recht mit dem ~! Vielen Dank. Ich brauche das ChordIsBrokenallerdings, weil ich sonst Ctrlzwischen den beiden Tastenanschlägen loslassen kann , was ich nicht zulassen möchte. Ich bin verblüfft darüber, warum Ihre Lösung bei mir nicht funktioniert. Ich denke, ich verwende AHK_L v1.1.09.00, also sollte ich vielleicht aktualisieren? Aber für mich führt das Drücken Ihres Skripts derzeit dazu, Ctrl+Edass eine Zeile (in einem Texteditor) gelöscht wird.
Andrew Cheong
Ich bin sowieso + 1'ing Sie, weil Sie definitiv wissen, wovon Sie sprechen, und mir mit Ihrem Kommentar geholfen haben. Ich werde meine AHK später aktualisieren und zurückmelden, wenn sich etwas geändert hat.
Andrew Cheong
Mein Code blockiert die Tastenanschläge nicht. Möglicherweise löscht Ihr Editor die aktuelle Zeile mit Ctrl+E. Mir ist gerade klar geworden, dass du überhaupt nichts zulassen willst {Ctrl Up}. Meins ahmt das VS-Verhalten nach. ( {Ctrl Down}e{Ctrl Up}{Ctrl Down}c{Ctrl Up}ist legitim)
Hippibruder