Ctrl キーを押しながら一連の入力 (例: {Ctrl Down}ec{Ctrl Up}) のホットキーを作成するにはどうすればよいですか?

Ctrl キーを押しながら一連の入力 (例: {Ctrl Down}ec{Ctrl Up}) のホットキーを作成するにはどうすればよいですか?

たとえば、Visual Studio Express 2013では、多くの書式設定ショートカットがCtrl+に「折りたたまれて」いますE。選択範囲をコメントするには、 をCtrl押したまま を押しE、 を押しますCそれからリリースCtrl

    ここに画像の説明を入力してください

私がいた場合送信そのような入力については、私は書きます

SendInput {Ctrl Down}ec{Ctrl Up}

しかし、そのシーケンスをホットキーにするにはどうすればいいでしょうか?試してみました

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

しかし、もちろん、これは構文エラーを引き起こします。

    ここに画像の説明を入力してください

答え1

やっと分かりました。

要約

^e最初のキーストロークに置き換えます。 32 番目のキーストロークの ASCII インデックスに置き換えます。 これにより、Ctrl両方のキーストロークで が保持され、それ以外の場合はキャンセルされます。

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

Shiftこれを の代わりに に適用するには、 を置き換え、 を削除し、の代わりに のようなより単純な比較を行うCtrl必要があります。これを および に拡張する方法はよくわかりませんが、などを試してみる必要があるかもしれません。CtrlMOutputVar = CAsc(OutputVar) = 3AltWinL2

説明

Input明らかにここから始めるべきだと思いました。AHKInputにユーザー入力を待つように指示し、例えば

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

上記のメッセージ ボックスは でトリガーされますCtrlECしかし、 を探しているCtrlCので、これを修正しましょう。

^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

CtrlEこれで、を押すとメッセージボックスが表示されますCtrlC。しかし、これには問題があります。メッセージボックスは、リリース Ctrl2回のキー入力の間にある。では、{Ctrl Up}入力途中をどう検出するのでしょうか?単に入力時にチェックするだけではだめです。

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

—入力後に単に確認することもできません—

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

—また、両方を実行することもできません。どちらにしても、入力をブロックする while が失われるからです{Ctrl Up}

それから私は調べたドキュメントHotkeyインスピレーションを得るために、カスタム組み合わせ演算子 が&有望に思えました。しかし残念なことに、

^e & ^c::
    ; ...

コンパイルエラーが発生しています。どうやら は&結合するためのようです修正なしキーストロークのみ。

最終的に まで到達しUP、そこで私はついに突破口を開いた。 を再定義してCtrlUP設定し、トグルメッセージ ボックスがトリガーされなくなります。

$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

さて、 を押してCtrlEから を放しCtrl、 を押してもCtrlC、予想どおり何も起こりません。

最後に修正すべき点が 1 つありました。「キャンセル」(「壊れたコード」) では、すべてのキーストロークが通常に戻るようにしたかったのです。しかし、上記のコードでは、Input壊れたコードや無関係なセカンダリ キーストロークに関係なく、戻る前にキーストロークを「消費」する必要がありました。ケースを追加すると、Elseこの問題はうまく解決されます。

    Else
    {
        SendInput %OutputVar%
    }

ということで、AutoHotkeyの「コード」が完成しました。(ただし、これを「コード」と呼ぶのは適切ではありません。メロディー、ベースライン付き ;-)


@hippibruder は、非ブロッキングにするために$Ctrl::を使用することで定義を回避できることを親切に指摘してくれました。これにより、いくらかの簡素化が可能になります! (最終結果については、上部の tl;dr セクションを参照してください。)~$Ctrl UP::


もう1つ。もし、キャンセル(「壊れたコード」)の際に、最初のキーストロークを打つと、つまり CtrlE単独では、Elseブロックにそれを追加するだけです。

    Else
    {
        SendInput ^e
        SendInput %OutputVar%
    }

ホットキーを変更することを忘れないでください

$^e::

無限ループを回避するためです。

答え2

AHK にはキー コードの組み込みサポートはないと思います。これを検出する 1 つの方法は、コードの最初のキー (^e) にホットキーを登録し、入力コマンドを使用して次のキーを検出することです。

; 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

関連情報