使用 AHK 进行多按键检测

问题描述 投票:0回答:1

我正在使用以下最初由 Laszlo 编写的 AutoHotkey 脚本来检测 Ctrl 键的单次、多次、短按和长按:

Morse(timeout = 150) { ;
    tout := timeout/1000
    key := RegExReplace(A_ThisHotKey,"[\*\~\$\#\+\!\^]")
    Loop {
        t := A_TickCount
        KeyWait %key%
        Pattern .= A_TickCount-t > timeout
        KeyWait %key%,DT%tout%
        If (ErrorLevel)
            Return Pattern
    }
}

~Ctrl::
    p := Morse()
    If (p = "0")
        MsgBox Short press
    Else If (p = "1")
        MsgBox Long press
    Else If (p = "00")
        MsgBox Two short presses
    Else If (p = "01")
        MsgBox Short+Long presses
    Else
        MsgBox Press pattern %p%
    Return

该脚本可以很好地区分短按和长按 Ctrl。但是,当我将 Ctrl 键与 z、c、v 等其他键一起使用时,我遇到了问题。 在这些情况下,脚本将这些组合检测为长按 Ctrl 键并显示“长按”消息框。 相反,我希望它忽略 Ctrl + 其他键的任意组合并允许默认的系统行为。

感谢修改脚本的任何帮助

autohotkey long-press
1个回答
1
投票

正确答案是:

#Requires AutoHotkey v2.0
#SingleInstance Force

; Morse Function (To detect single, double, tripple or ... , short or long press)
Morse(Timeout := 200, PatternSequence := 10) ; Set patternSequence to 3, 2 for better performance. However, this will decrease the number of patterns detected.
{
    Global Pattern := ""
    Win := WinExist("A")
    RegExMatch(Hotkey := A_ThisHotkey, "\W$|\w*$", &Key)
    IsModifier := InStr(Hotkey, "Control") or InStr(Hotkey, "Alt") Or InStr(Hotkey, "Shift") Or InStr(Hotkey, "Win")
    CoordMode("Mouse", "Screen")
    MouseGetPos(&X1, &Y1, &Win1)
    Counter := 0

    Loop (PatternSequence) {
        ; Disabling Alt menu acceleration / Windows Start menu
        If InStr(Hotkey, "Alt") Or InStr(Hotkey, "Win") ; Comment second condition if you need WIN key to open the start menu.
            Send("{Blind}{vkE8}")

        T := A_TickCount
        ErrorLevel := !KeyWait(Key[0])
        Pattern .= A_TickCount - T > Timeout
        MouseGetPos(&X2, &Y2, &Win2)
        
        ; Skiping the operation for modifiers, if another key is pressed or mouse is moved.
        IF (IsModifier) And (((Win Key[0] Hotkey Win1) != (WinExist("A") A_PriorKey A_ThisHotkey Win2)) Or (30 < (X2 - X1) ** 2 + (Y2 - Y1) ** 2))
            Exit
            
        ; Skiping the last keywait to improve speed!
        Counter += 1
        If (Counter = PatternSequence)
            return Pattern

        ; Waiting for the next key sequence to be pressed      
        ErrorLevel := !KeyWait(Key[0], "DT" Timeout / 1500)
        If ErrorLevel
            return Pattern
    }
}


; Hotkey handler
~LControl::
~LAlt::
~LShift::
~LWin::
Tab::
Capslock::
{
    hotkey := A_ThisHotkey
    Patterm := Morse() ;  Morse(, 2) ; If you only need the following patterns.
    Switch Patterm
    {
        Case "0":
            MsgBox(hotkey " " Patterm)
        Case "1":
            MsgBox(hotkey " " Patterm)
        Case "00":
            MsgBox(hotkey " " Patterm)
        Case "01":
            MsgBox(hotkey " " Patterm)
        Case "10":
            MsgBox(hotkey " " Patterm)
        Case "11":
            MsgBox(hotkey " " Patterm)
        Default: ; Preferably comment these two lines after testing
            MsgBox(hotkey " " Patterm)
    }
    Return
}

变更日志:

我使用了

Laszlo
编写的原始莫尔斯电码函数,它可以检测任意键的单次/多次、短按/长按。但它有一些问题,特别是修饰键。

Rohwedder
的大力帮助下,脚本被修改为检测组合键(例如
Ctrl+z
)或鼠标移动(例如
Ctrl+Mouse drag
)并让它们执行默认功能。

下一步,我改进了脚本以获得更好的性能。

最后,我解决了

Alt
键与禁用“Alt键加速”的冲突,以及
Win
键与开始菜单的冲突。

用途:

对于不同的热键,您可以设置不同的超时时间,以及不同的模式序列。

例如,在实际情况中,我需要按一次 Shift 键(模式:0)来发送

Alt + Shift
来更改输入语言。 但我注意到在快速打字的情况下切换语言时会出现延迟。 因此,我决定使用以下参数调用 Morse 函数:
Pattern := Morse(400, 1)

这消除了滞后,因为它只经历一次循环。 它还解决了我的另一个问题,即短按和长按 Shift 键冲突,因为检测长按的超时时间增加。 缺点是只有两种模式可供使用:短按和长按!

参考资料:

Laszlo 的原创莫尔斯电码

Rohwedder 代码

© www.soinside.com 2019 - 2024. All rights reserved.