如何在按住 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為第一個所需的按鍵。替換3為第二個所需按鍵的 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,您必須替換Ctrls,刪除M,並進行更簡單的比較,例如OutputVar = C代替Asc(OutputVar) = 3。不知道如何將其擴展到AltandWin但你可能必須嘗試L2或類似的東西。

解釋

Input似乎是一個明顯的起點。Input要求 AHK 等待用戶輸入,例如

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

上面的訊息框將在CtrlEthen上觸發C。但我們正在尋找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現在我們在按下then 時會出現一個訊息框CtrlC。但這有一個問題:即使我發布 Ctrl兩次擊鍵之間。那麼,我們要如何檢測本質上的{Ctrl Up}中間輸入呢?你不能僅僅檢查入口——

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

——也不能只輸入後檢查——

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

——你甚至不能同時做這兩件事,因為無論如何,你都會錯過{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,沒有任何反應,正如預期的那樣!

還有最後一件事要解決。在「取消」(「斷弦」)時,我希望所有擊鍵都恢復正常。但在上面的程式碼中,Input無論是斷弦還是不相關的輔助擊鍵,在返回之前都必須「吃掉」擊鍵。增加一個Else案例很好地解決了這個問題:

    Else
    {
        SendInput %OutputVar%
    }

現在,您已經知道了 AutoHotkey 中的“和弦”。 (不過,我不會確切地稱其為“和弦”。更像是旋律,有低音線;-)


@hippibruder 慷慨地指出,我可以$Ctrl::透過使用來避免~定義$Ctrl UP::非阻塞。這可以進行一些簡化! (有關最終結果,請參閱頂部的 tl;dr 部分。)


還有一件事。如果,也許,在「取消」(「斷弦」)時,您想發出第一次擊鍵,IE CtrlE就其本身而言,只需將其添加到Else區塊中,

    Else
    {
        SendInput ^e
        SendInput %OutputVar%
    }

並且不要忘記將熱鍵更改為

$^e::

以避免無限循環。

答案2

我認為 AHK 中沒有關鍵和弦的內建支援。檢測這些的一種方法是為和弦 (^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

相關內容