I am using the following AutoHotkey script originally written by Laszlo to detect single, multiple, short and long presses of the Ctrl key:
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
The script works well to differentiate between Short and long Ctrl presses. However, I am facing an issue when using Ctrl key together with another keys like z, c, v, etc. In these cases, the script detects these combos as a long press on Ctrl key and dispalys the "Long press" message box. Instead, I want it to ignore any combination of Ctrl + other keys and allow the default system behavior.
Appreciate any help modifing the script
Here is the correct answer:
#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 or even 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::
XButton1::
; Tab::
; Capslock::
{
hotkey := A_ThisHotkey
Patterm := Morse() ; Morse(, 2) ; Call like this if you need the following 6 patterns only.
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
}
CHANGELOG:
I used the original Morse function written by Laszlo
which detects single/multiple, short/long presses of any key. But it had some problems specially with modifier keys.
With the great help of Rohwedder
, the script modified to detect key combinations (eg.Ctrl+z
) or mouse movement (eg. Ctrl+Mouse drag
) and let them to perform their default functionality.
At the next step, I improved the script to reach a better performance.
Finally, I solved the conflicts of the Alt
key with disabling "Alt key acceleration", as well as the Win
key conflicts with the start menu.
USAGE:
For different hotkeys, you can set different timeouts, as well as different pattern sequences.
For example, in a real case, I needed a single Shift key press (Pattern: 0) to send Alt + Shift
to change the input language.
But I noticed a lag when switching languages while typing very fast.
So, I decided to call the Morse function with these parameters: Pattern := Morse(400, 1)
.
This removed the lag, since it goes through the loop just once. It also fixed my other problem which conflicting short and long Shift key presses, as the timeout to detect the long press increased. The downside is that there are only two patterns to use: short and long presses !
REFERENCES: