Wie erstelle ich einen Hotkey für eine Eingabefolge bei gedrückter Strg-Taste, z. B. {Strg nach unten} oder {Strg nach oben}?

Wie erstelle ich einen Hotkey für eine Eingabefolge bei gedrückter Strg-Taste, z. B. {Strg nach unten} oder {Strg nach oben}?

Beispielsweise wurden in Visual Studio Express 2013 viele der Formatierungsverknüpfungen in Ctrl+ „eingebettet“ E. Um eine Auswahl zu kommentieren, muss man gedrückt halten Ctrl, drücken E, drücken C,Dannfreigeben Ctrl.

    Bildbeschreibung hier eingeben

Wäre ichVersendungSolche Eingaben 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

aber das verursacht natürlich einen Syntaxfehler:

    Bildbeschreibung hier eingeben

Antwort1

Endlich herausgefunden.

tl;dr

Ersetzen Sie ^edurch den ersten gewünschten Tastendruck. Ersetzen Sie 3durch den ASCII-Index des zweiten gewünschten Tastendrucks. Dies erzwingt, dass die Taste Ctrlwährend beider Tastendrücke gedrückt gehalten wird, andernfalls wird der Vorgang 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

ShiftUm dies auf anstelle von anzupassen Ctrl, müssten Sie das Ctrls ersetzen, das entfernen Mund einen einfacheren Vergleich wie OutputVar = Canstelle von durchführen. Ich bin nicht sicher, wie ich dies auf und Asc(OutputVar) = 3erweitern kann , aber vielleicht müssen Sie es versuchen oder so etwas in der Art.AltWinL2

Erläuterung

Inputschien ein naheliegender Ausgangspunkt zu sein. Inputfordert AHK auf, auf Benutzereingaben zu warten,z.B

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

Das Meldungsfeld oben wird CtrlEdann ausgelöst C. Aber wir suchen nach CtrlC, also beheben wir das:

^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 Meldungsfenster, wenn wir CtrlEdann drücken CtrlC. Aber es gibt ein Problem damit: Das Meldungsfenster wird ausgelöst, auch wenn ichfreigeben Ctrlzwischen den beiden Tastenanschlägen. Wie erkennen wir also im Wesentlichen eine {Ctrl Up}Eingabe in der Mitte? Sie können nicht einfach beim Eingeben prüfen –

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

—auch können Sie nicht einfach nach der Eingabe prüfen—

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

– und Sie können nicht einmal mit beidem durchkommen, denn egal, was Sie tun, Sie werden die {Ctrl Up}„while“-Blockierung für die Eingabe verpassen.

Dann schaute ich inDokumentation überHotkeyzur Inspiration. Der benutzerdefinierte Kombinationsoperator, &, schien vielversprechend. Aber leider

^e & ^c::
    ; ...

hat einen Kompilierungsfehler verursacht; anscheinend &dient das zum Kombinierenunverändertnur Tastenanschläge.

Schließlich war es soweit UP, und dort gelang mir endlich der Durchbruch. Ich habe Ctrl's neu definiert UP, um einenUmschaltenDadurch wird die Auslösung des Meldungsfelds verhindert!

$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 wieder drücke CtrlC, passiert wie erwartet nichts!

Es gab noch eine letzte Sache zu beheben. Bei „Abbruch“ (ein „gebrochener Akkord“) wollte ich, dass alle Tastenanschläge wieder normal sind. Aber im obigen Code Inputmüsste ein Tastenanschlag „aufgebraucht“ werden, bevor er zurückkehrt, unabhängig davon, ob es sich um einen gebrochenen Akkord oder einen irrelevanten sekundären Tastenanschlag handelt. Das Hinzufügen eines ElseFalls löst dieses Problem auf schöne Weise:

    Else
    {
        SendInput %OutputVar%
    }

So, da haben Sie es – „Akkorde“ in AutoHotkey. (Obwohl ich das nicht gerade als „Akkord“ bezeichnen würde. Eher alsMelodie, mit Basslinie ;-)


@hippibruder weist großzügig darauf hin, dass ich die Definition vermeiden kann, $Ctrl::indem ich verwende ~, um nicht blockierend zu machen $Ctrl UP::. Dies ermöglicht eine gewisse Vereinfachung! (Das Endergebnis finden Sie im Abschnitt tl;dr oben.)


Und noch etwas. Wenn Sie vielleicht bei einer "Stornierung" (einem "gebrochenen Akkord") den ersten Tastendruck ausführen möchten,dh CtrlEallein, fügen Sie das einfach in den ElseBlock ein,

    Else
    {
        SendInput ^e
        SendInput %OutputVar%
    }

und vergessen Sie nicht, den Hotkey zu ändern in

$^e::

um eine Endlosschleife zu vermeiden.

Antwort2

Ich glaube nicht, dass es in AHK integrierte Unterstützung für Tastenklänge gibt. Eine Möglichkeit, diese zu erkennen, wäre, einen Hotkey für die erste Taste im Akkord (^e) zu registrieren und dann den Input-Befehl zu verwenden, um 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

verwandte Informationen