Belated thanks to Hotkeyit for an extremely useful script. I've been using it a lot for making double or triple clicks of Shift, LCtrl, RCtrl, CapsLock do useful things like opening and closing various search windows (
http://www.autohotkey.com/forum/topic46083.html)
With the original version I get occasional false activations. It happens when I'm typing fast and happen to press a normal key in between two presses of the special key.
I've solved this by slightly modifying Morse() so that it detects an intervening alien key and aborts the multiple key press. To make it work I have to define all the possible alien keys as hotkeys. I can then use A_ThisHotkey inside the Morse loop to see if the last hotkey is an alien.
To use it all you have to do is call subroutine DefHotkeys near the beginning of your application program and replace Morse in your RapidHotkey function with the modified version here. The modified RapidHotkey works like the unmodified version with main programs that don't run DefHotkeys, but of course you lose the protection against false alarms.
It seems a bit crude to have to make all these 'do-nothing' hotkey assigments but since they don't conflict with any assignments in other scripts, it appears to be only an aesthetic issue. Thanks to Laszlo for the guts of DefHotkeys. References are in the script below.
There's also a test section that demonstrates it working. To use it run the script and try rapidly tapping the Right-Control key once, twice, thrice, etc.
Code:
;;;;;;;;;;;;;;;;
; Test:
; Action1 happens for single keypress of the right control key,
; Action2 for double press, and so on.
; If you change the parameters in RapidHotkey() to say,
; ("Action1""Action2""Action3""Action4",2,0.3,1), then Action1
; happens for double keypress and Action2 for triple, and so on.
Pip = 75
Tone = 2000
Gosub , DefHotkeys
~RControl::RapidHotkey("Action1""Action2""Action3""Action4",1,0.3,1)
Action1:
Peep(1)
Return
Action2:
Peep(2)
Return
Action3:
Peep(3)
Return
Action4:
Peep(4)
Return
Peep(Rpts) {
Global
Loop , %Rpts% {
SoundBeep , %Tone% , %Pip%
sleep, %pip%
}
Return
}
; end of test section
;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;
; Subroutine to define lots of keys as 'do-nothing' hotkeys.
; As described by Laszlo's at http://www.autohotkey.com/forum/topic17614.html
; and http://www.autohotkey.com/forum/topic7081.html.
;
DefHotkeys:
keys = ``1234567890-=qwertyuiop[]\asdfghjkl;'zxcvbnm,./
Loop Parse, keys
HotKey , ~*%A_LoopField%, DoNothing
SpecialKeys =LShift RShift LCtrl RCtrl LAlt RAlt LWin RWin ; Add as required
Loop Parse, SpecialKeys , %A_Space%
HotKey , ~*%A_LoopField%, DoNothing
DoNothing:
; SoundBeep , 3000, 10
Return
;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;
/*RapidHotkey() is unchanged from the 24.02.2009 version posted by
Hotkeyit at http://www.autohotkey.com/forum/viewtopic.php?t=38795
but Morse is modified slightly from Laszlo's original at
http://www.autohotkey.com/forum/viewtopic.php?t=16951. The morse
code aspect has gone - it just detects multiple hits of the same key
that are separated by less than 'timeout'. It returns 0 for one hit,
00 for two, and so on. It now returns blank if any other key is
detected during what would otherwise count as a multiple key-press.
*/
RapidHotkey(keystroke, times="2", delay=0.2, IsLabel=0)
{
Pattern := Morse(delay*1000)
If (StrLen(Pattern) < 2 and Chr(Asc(times)) != "1")
Return
If (times = "" and InStr(keystroke, """"))
{
Loop, Parse, keystroke,""
If (StrLen(Pattern) = A_Index+1)
continue := A_Index, times := StrLen(Pattern)
}
Else if (RegExMatch(times, "^\d+$") and InStr(keystroke, """"))
{
Loop, Parse, keystroke,""
If (StrLen(Pattern) = A_Index+times-1)
times := StrLen(Pattern), continue := A_Index
}
Else if InStr(times, """")
{
Loop, Parse, times,""
If (StrLen(Pattern) = A_LoopField)
continue := A_Index, times := A_LoopField
}
Else if (times = "")
continue = 1, times = 2
Else if (times = StrLen(Pattern))
continue = 1
If !continue
Return
Loop, Parse, keystroke,""
If (continue = A_Index)
keystr := A_LoopField
Loop, Parse, IsLabel,""
If (continue = A_Index)
IsLabel := A_LoopField
hotkey := RegExReplace(A_ThisHotkey, "[\*\~\$\#\+\!\^]")
IfInString, hotkey, %A_Space%
StringTrimLeft, hotkey,hotkey,% InStr(hotkey,A_Space,1,0)
Loop % times
backspace .= "{Backspace}"
keywait = Ctrl|Alt|Shift|LWin|RWin
Loop, Parse, keywait, |
KeyWait, %A_LoopField%
If ((!IsLabel or (IsLabel and IsLabel(keystr))) and InStr(A_ThisHotkey, "~") and !RegExMatch(A_ThisHotkey
, "i)\^[^\!\d]|![^\d]|#|Control|Ctrl|LCtrl|RCtrl|Shift|RShift|LShift|RWin|LWin|Escape|BackSpace|F\d\d?|"
. "Insert|Esc|Escape|BS|Delete|Home|End|PgDn|PgUp|Up|Down|Left|Right|ScrollLock|CapsLock|NumLock|AppsKey|"
. "PrintScreen|CtrlDown|Pause|Break|Help|Sleep|Browser_Back|Browser_Forward|Browser_Refresh|Browser_Stop|"
. "Browser_Search|Browser_Favorites|Browser_Home|Volume_Mute|Volume_Down|Volume_Up|MButton|RButton|LButton|"
. "Media_Next|Media_Prev|Media_Stop|Media_Play_Pause|Launch_Mail|Launch_Media|Launch_App1|Launch_App2"))
Send % backspace
If (WinExist("AHK_class #32768") and hotkey = "RButton")
WinClose, AHK_class #32768
If !IsLabel
Send % keystr
else if IsLabel(keystr)
Gosub, %keystr%
Return
}
;;;;;;;;;
;;;;;;;
; Based on Morse by Laszlo at http://www.autohotkey.com/forum/viewtopic.php?t=16951.
; Modified by DAT 14-09-2009 to avoid false alarms
; (Modified lines are marked DAT).
;
Morse(timeout = 400) {
tout := timeout/1000
CurrentKey = %A_ThisHotKey% ; DAT: Stored so can trap wrong hotkey within the loop
key := RegExReplace(A_ThisHotKey,"[\*\~\$\#\+\!\^]")
IfInString, key, %A_Space%
StringTrimLeft, key, key,% InStr(key,A_Space,1,0)
Loop
{ ; Loops until KeyWait test fails, or 'alien' hotkey spotted.
t := A_TickCount
KeyWait %key%, T%tout% ; Wait for key to be released.
Pattern .= 0 ; DAT: 'Morse' aspect not being used anyway...
If(ErrorLevel)
Return Pattern ; It timed out, so finish.
KeyWait %key%,DT%tout% ; Wait for next key-down...
If (ErrorLevel) ; and allow to loop if key repeats,
Return Pattern ; otherwise finish if it times out.
IfNotEqual, A_ThisHotkey, %CurrentKey% ; DAT: Abort if another key has intervened
{
Pattern =
Return Pattern
}
}
}
;;;;;;;;;;;;;;;;;;;;;;;;