 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
HotKeyIt
Joined: 18 Jun 2008 Posts: 4652 Location: AHK Forum
|
Posted: Sat Dec 13, 2008 2:01 am Post subject: RapidHotkey() |
|
|
Using this function you can send keystrokes or launch a Label by pressing a key several times.
Include the function in your script or save it in .\Lib folder (RapidHotkey.ahk).
Many thanks to Laszo for Morse(), I have modified it to capture invalid keys.
Please note, my Morse() version does not detect long key presses
Syntax:
| Code: | Key::RapidHotkey("keystrokes" ;Enter keystrokes here. E.g.: "^o"
, times ;optional. The number of times the key must be pressed to execute. E.g.: 3
, delay ;optional. How quick the key must be pressed to execute. E.g.: 0.2
, IsLabel) ;optional. specify 1 to indicate that parameter 1 is a label.
;E.g.
~o::RapidHotkey("^o") ;open file dialog if o pressed twice
;To specify several actions , use " as separator and leave times parameter empty.
If press times parameter is omitted, first action would be triggered on 2 presses.
~e::RapidHotkey("#r""#e""#f") ; #r if pressed twice, #e 3 times and so on
;You can specify also one (can be also 1) or separated value for times
~s::RapidHotkey("^s""{F12}""^+s", 5) ;so pressing 5 times = ^s, 6 times = {F12} and so on
;You can also specify separated times value
$x::RapidHotkey("x""#r""#e", "1""5""3")
;use same separator for delay and islabel parameter |
ChangeLog:
02.06.2010
- Added exeption for Capslock,LButton,MButton + RButton
20.05.2010
- Invalid hotkey presses are detected using Input command now.
19.09.2009
- Detects invalid hotkey presses as well now
18.09.2009
- Removed some invalid keys from GetKeyState list
17.09.2009
- Detects invalid key presses and terminates execution
24.02.2009
- Use combination of Hotkeys, e.g. ~LButton & RButton::...
14.01.2009
- Use "" instead of Chr(4). E.g. ...RapidHotkey("^a""Hello""World")
14-12-2008
- You can use 1 for times to do action on one press as well.
- changed standard delay parameter to 0.1.
Examples:
| Code: | ~+::RapidHotkey("Plus")
~h::RapidHotkey("{Raw}Hello World!", 3) ;Press h 3 times rapidly to send Hello World!
~o::RapidHotkey("^o", 4, 0.2) ;be careful, if you use this hotkey, above will not work properly
~Esc::RapidHotkey("exit", 4, 0.2, 1) ;Press Esc 4 times rapidly to exit this script
~LControl::RapidHotkey("!{TAB}",2) ;Press LControl rapidly twice to AltTab
~RControl::RapidHotkey("+!{TAB}",2) ;Press RControl rapidly twice to ShiftAltTab
~LShift::RapidHotkey("^{TAB}", 2) ;Switch back in internal windows
~RShift::RapidHotkey("^+{TAB}", 2) ;Switch between internal windows
~e::RapidHotkey("#e""#r",3) ;Run Windows Explorer
~^!7::RapidHotkey("{{}{}}{Left}", 2)
~a::RapidHotkey("test", 2, 0.3, 1) ;You Can also specify a Label to be launched
test:
MsgBox, Test
Return
Exit:
ExitApp
~LButton & RButton::RapidHotkey("Menu1""Menu2""Menu3",1,0.3,1)
Menu1:
Menu2:
Menu3:
MsgBox % A_ThisLabel
Return
|
Functions | Code: | 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)
backspace := "{BS " times "}"
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|Alt|LAlt|RAlt|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
}
Morse(timeout = 400) { ;by Laszo -> http://www.autohotkey.com/forum/viewtopic.php?t=16951 (Modified to return: KeyWait %key%, T%tout%)
tout := timeout/1000
key := RegExReplace(A_ThisHotKey,"[\*\~\$\#\+\!\^]")
IfInString, key, %A_Space%
StringTrimLeft, key, key,% InStr(key,A_Space,1,0)
If Key in Shift,Win,Ctrl,Alt
key1:="{L" key "}{R" key "}"
Loop {
t := A_TickCount
KeyWait %key%, T%tout%
Pattern .= A_TickCount-t > timeout
If(ErrorLevel)
Return Pattern
If key in Capslock,LButton,RButton,MButton
KeyWait,%key%,T%tout% D
else if Asc(A_ThisHotkey)=36
KeyWait,%key%,T%tout% D
else
Input,pressed,T%tout% L1 V,{%key%}%key1%
If (ErrorLevel="Timeout" or ErrorLevel=1)
Return Pattern
else if (ErrorLevel="Max")
Return
}
} |
_________________ AHK_H (2alpha) AHF TT _Struct WatchDir Yaml _Input ObjTree RapidHotkey DynaRun 
Last edited by HotKeyIt on Sat Jun 04, 2011 8:28 am; edited 66 times in total |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Sat Dec 13, 2008 7:08 pm Post subject: |
|
|
| Nice! You can extend the idea with detecting the lengths of key presses, like here. |
|
| Back to top |
|
 |
HotKeyIt
Joined: 18 Jun 2008 Posts: 4652 Location: AHK Forum
|
|
| Back to top |
|
 |
HotKeyIt
Joined: 18 Jun 2008 Posts: 4652 Location: AHK Forum
|
Posted: Sat Dec 13, 2008 11:24 pm Post subject: |
|
|
Now you can specify a different action on specified times of presses.
| Code: | ;To specify several actions continuously, so one if pressed twice, another if 3 times, and so on use "" as separator and leave times parameter empty ("").
~e::RapidHotkey("#r""#e""#f") ; #r if pressed twice, #e 3 times and so on
;You can also specify separated times value
~x::RapidHotkey("#r""#e", "5""3") |
_________________ AHK_H (2alpha) AHF TT _Struct WatchDir Yaml _Input ObjTree RapidHotkey DynaRun 
Last edited by HotKeyIt on Wed Jan 14, 2009 12:47 pm; edited 2 times in total |
|
| Back to top |
|
 |
HotKeyIt
Joined: 18 Jun 2008 Posts: 4652 Location: AHK Forum
|
Posted: Sun Dec 14, 2008 9:26 pm Post subject: |
|
|
Easy MultiMenu example.
Press RButton twice to display Programs Menu, 3 times for Settings Menu, 4 times for FolderMenu.
To add a menu item, you need to add a new Label in your script and add its name to programs, settings or folders variable in first lines.
| Code: | Menu = Programs|Settings|Folders
Programs = PROGRAMS|Notepad|Explorer|Calculator
Settings = SETTINGS|ControlPanel|Display
Folders = FOLDERS|Windows|ProgramFiles|Desktop
Loop, Parse, Menu, |
{
B_LoopField := A_LoopField
Loop, Parse, %B_LoopField%, |
{
Menu, %B_LoopField%, Add, %A_LoopField%, %A_LoopField%
If A_Index = 1
{
Menu, %B_LoopField%, Default, %A_LoopField%
Menu, %B_LoopField%, Add
}
}
}
Return
~RButton::RapidHotkey("Programs""Settings""Folders", 2,0.4,1)
Folders:
Settings:
Programs:
Menu,%A_ThisLabel%, Show
Return
Notepad:
Run, notepad.exe
Return
Explorer:
Run, explorer.exe
Return
Calculator:
Run, calc.exe
Return
ControlPanel:
Run, control.exe
Return
Display:
Run, desk.cpl
Return
Windows:
Run, explorer.exe "C:\Windows"
Return
ProgramFiles:
Run, explorer.exe "%A_ProgramFiles%"
Return
Desktop:
Run, explorer.exe "%A_Desktop%"
Return
RapidHotkey(keystroke, times="", delay=0.15, 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 = 1
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, "[\*\~\$\#\+\!\^]")
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
}
Morse(timeout = 400) { ;by Laszo -> http://www.autohotkey.com/forum/viewtopic.php?t=16951 (Modified to return: KeyWait %key%, T%tout%)
static lastkey
tout := timeout/1000
key := RegExReplace(A_ThisHotKey,"[\*\~\$\#\+\!\^]")
Loop {
t := A_TickCount
KeyWait %key%, T%tout%
Pattern .= A_TickCount-t > timeout
If(ErrorLevel)
Return Pattern
KeyWait %key%,DT%tout%
If (ErrorLevel)
Return Pattern
}
} |
_________________ AHK_H (2alpha) AHF TT _Struct WatchDir Yaml _Input ObjTree RapidHotkey DynaRun 
Last edited by HotKeyIt on Wed Jan 14, 2009 12:48 pm; edited 1 time in total |
|
| Back to top |
|
 |
EricCartman
Joined: 13 Oct 2008 Posts: 60 Location: South Park, Colorado
|
Posted: Sun Dec 21, 2008 11:09 pm Post subject: |
|
|
You guys are my new heroes.
With all of the heavy lifting done by HotKeyIt, Laszlo, and ManaUser, the following script disables the Caps Lock key on one press, brings up ManaUser's super handy capitalization utility on two presses, and toggles the CapsLock state on three presses. I get credit only for hating the Caps Lock key and being able to copy and paste.
| Code: | ; RapidHotkey:
; http://www.autohotkey.com/forum/viewtopic.php?t=38795
; by HotKeyIt
;
; Morse:
; http://www.autohotkey.com/forum/viewtopic.php?t=16951
; by Laszlo
;
; Cap Menu and string manipulation:
; http://www.autohotkey.com/forum/topic27797.html
; by ManaUser
Menu Case, Add, &UPPERCASE, CCase
Menu Case, Add, &lowercase, CCase
Menu Case, Add, &Title Case, CCase
Menu Case, Add, &Sentence case, CCase
Menu Case, Add
Menu Case, Add, &Fix Linebreaks, CCase
Menu Case, Add, &Reverse, CCase
CapsLock::RapidHotkey("CapMenu" Chr(4) "ToggleCapsLock", 2, 0.1,1)
CapMenu:
GetText(TempText)
If NOT ERRORLEVEL
Menu Case, Show
Return
CCase:
If (A_ThisMenuItemPos = 1)
StringUpper, TempText, TempText
Else If (A_ThisMenuItemPos = 2)
StringLower, TempText, TempText
Else If (A_ThisMenuItemPos = 3)
StringLower, TempText, TempText, T
Else If (A_ThisMenuItemPos = 4)
{
StringLower, TempText, TempText
TempText := RegExReplace(TempText, "((?:^|[.!?]\s+)[a-z])", "$u1")
} ;Seperator, no 5
Else If (A_ThisMenuItemPos = 6)
{
TempText := RegExReplace(TempText, "\R", "`r`n")
}
Else If (A_ThisMenuItemPos = 7)
{
Temp2 =
StringReplace, TempText, TempText, `r`n, % Chr(29), All
Loop Parse, TempText
Temp2 := A_LoopField . Temp2
StringReplace, TempText, Temp2, % Chr(29), `r`n, All
}
PutText(TempText)
Return
;******************************************************************************
; Copies the selected text to a variable while PRESERVING the clipboard.
;******************************************************************************
GetText(ByRef MyText = "")
{
SavedClip := ClipboardAll
Clipboard =
Send ^c
ClipWait 0.5
If ERRORLEVEL
{
Clipboard := SavedClip
MyText =
Return
}
MyText := Clipboard
Clipboard := SavedClip
Return MyText
}
; Pastes text from a variable while preserving the clipboard.
PutText(MyText)
{
SavedClip := ClipboardAll
Clipboard = ; For better compatability
Sleep 20 ; with Clipboard History
Clipboard := MyText
Send ^v
Sleep 100
Clipboard := SavedClip
Return
}
;This makes sure sure the same window stays active after showing the InputBox.
;Otherwise you might get the text pasted into another window unexpectedly.
SafeInput(Title, Prompt, Default = "")
{
ActiveWin := WinExist("A")
InputBox OutPut, %Title%, %Prompt%,,, 120,,,,, %Default%
WinActivate ahk_id %ActiveWin%
Return OutPut
}
;This checks if a window is, in fact a window.
;As opposed to the desktop or a menu, etc.
IsWindow(hwnd)
{
WinGet, s, Style, ahk_id %hwnd%
return s & 0xC00000 ? (s & 0x80000000 ? 0 : 1) : 0
;WS_CAPTION AND !WS_POPUP(for tooltips etc)
}
RapidHotkey(keystroke, times="", delay=0.1, IsLabel=0)
{
;Suspend, On
Pattern := Morse(delay*1000)
If (StrLen(Pattern) < 2 and Chr(Asc(times)) != "1")
Return
If (times = "" and InStr(keystroke, Chr(4)))
{
Loop, Parse, keystroke,% Chr(4)
If (StrLen(Pattern) = A_Index+1)
continue := A_Index, times := StrLen(Pattern)
}
Else if (RegExMatch(times, "^\d+$") and InStr(keystroke, Chr(4)))
{
Loop, Parse, keystroke,% Chr(4)
If (StrLen(Pattern) = A_Index+times-1)
times := StrLen(Pattern), continue := A_Index
}
Else if InStr(times, Chr(4))
{
Loop, Parse, times,% Chr(4)
If (StrLen(Pattern) = A_LoopField)
continue := A_Index, times := A_LoopField
}
Else if (times = "")
continue := 1, times := 1
Else if (times = StrLen(Pattern))
continue := 1
If !continue
Return
Loop, Parse, keystroke,% Chr(4)
If (continue = A_Index)
keystr := A_LoopField
Loop, Parse, IsLabel,% Chr(4)
If (continue = A_Index)
IsLabel := A_LoopField
hotkey := RegExReplace(A_ThisHotkey, "[\*\~\$\#\+\!\^]")
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
, "\^[^\!\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
}
Morse(timeout = 400) { ;by Laszo -> http://www.autohotkey.com/forum/viewtopic.php?t=16951
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
}
}
ToggleCapsLock:
state := GetKeyState("Capslock", "T")
If (state = False)
SetCapsLockState, On
Else
SetCapsLockState, Off |
|
|
| Back to top |
|
 |
lilalurl.T32
Joined: 17 May 2007 Posts: 391 Location: Titan
|
Posted: Mon Dec 29, 2008 6:51 pm Post subject: |
|
|
Nice work Hotkeyit.
________
MICHIGAN MEDICAL MARIJUANA DISPENSARY
Last edited by lilalurl.T32 on Fri Feb 11, 2011 8:41 pm; edited 1 time in total |
|
| Back to top |
|
 |
HotKeyIt
Joined: 18 Jun 2008 Posts: 4652 Location: AHK Forum
|
|
| Back to top |
|
 |
HotKeyIt
Joined: 18 Jun 2008 Posts: 4652 Location: AHK Forum
|
|
| Back to top |
|
 |
HotKeyIt
Joined: 18 Jun 2008 Posts: 4652 Location: AHK Forum
|
Posted: Tue Feb 24, 2009 8:44 pm Post subject: |
|
|
RapidHotkey can now be triggered on a combination of hotkeys as well. For example:
| Code: | ~LButton & RButton::RapidHotkey("Menu1""Menu2""Menu3",1,0.3,1)
Menu1:
Menu2:
Menu3:
MsgBox % A_ThisLabel
Return
;#####################################
;RapidHotkey() and Morse() functions #
;#####################################
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
}
Morse(timeout = 400) { ;by Laszo -> http://www.autohotkey.com/forum/viewtopic.php?t=16951 (Modified to return: KeyWait %key%, T%tout%)
tout := timeout/1000
key := RegExReplace(A_ThisHotKey,"[\*\~\$\#\+\!\^]")
IfInString, key, %A_Space%
StringTrimLeft, key, key,% InStr(key,A_Space,1,0)
Loop {
t := A_TickCount
KeyWait %key%, T%tout%
Pattern .= A_TickCount-t > timeout
If(ErrorLevel)
Return Pattern
KeyWait %key%,DT%tout%
If (ErrorLevel)
Return Pattern
}
} |
_________________ AHK_H (2alpha) AHF TT _Struct WatchDir Yaml _Input ObjTree RapidHotkey DynaRun 
Last edited by HotKeyIt on Wed Mar 18, 2009 10:35 pm; edited 3 times in total |
|
| Back to top |
|
 |
meep.com
Joined: 11 Feb 2009 Posts: 5
|
Posted: Wed Mar 18, 2009 9:55 pm Post subject: Does Not Work? |
|
|
When I copied your code into a script it gave me an error:
| Quote: | Error at line 1.
Invalid Hotkey |
How do I fix it?
Thanks |
|
| Back to top |
|
 |
HotKeyIt
Joined: 18 Jun 2008 Posts: 4652 Location: AHK Forum
|
|
| Back to top |
|
 |
DAT
Joined: 01 Dec 2008 Posts: 49 Location: UK
|
Posted: Tue Sep 15, 2009 2:13 pm Post subject: Modification avoids false detection of multiple key-presses |
|
|
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
}
}
}
;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Tue Sep 15, 2009 9:47 pm Post subject: |
|
|
If you don't type too fast, that Input misses keystrokes, the following version of Morse also brakes out at foreign keys, but it is simpler than DAT's solution. | Code: | Morse(timeout = 400) { ;
tout := timeout/1000
key := RegExReplace(A_ThisHotKey,"[\*\~\$\#\+\!\^]") ; remove modifiers: +BS -> BS
Loop {
t := A_TickCount
KeyWait %key% ; Wait for key release
Pattern .= A_TickCount-t > timeout ; How long the key was pressed
Input k,L1MT%tout%V,{LControl}{RControl}{LAlt}{RAlt}{LShift}{RShift}{LWin}{RWin}{AppsKey}{F1}{F2}{F3}{F4}{F5}{F6}{F7}{F8}{F9}{F10}{F11}{F12}{Left}{Right}{Up}{Down}{Home}{End}{PgUp}{PgDn}{Del}{Ins}{BS}{Capslock}{Numlock}{PrintScreen}{Pause}
If (ErrorLevel && ErrorLevel!="Max" || k != key) ; Break at long no-press time or foreign keys
Return Pattern
}
} | If the key we watch is in the list of the endkeys, some more work is needed. |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Tue Sep 15, 2009 10:10 pm Post subject: |
|
|
... e.g. this version works with the Backspace key. (Don't use the BS shorthand!) | Code: | Morse(timeout = 400) {
tout := timeout/1000
key := RegExReplace(A_ThisHotKey,"[\*\~\$\#\+\!\^]") ; remove modifiers: +BS -> BS
Loop {
t := A_TickCount
KeyWait %key% ; Wait for key release
Pattern .= A_TickCount-t > timeout ; How long the key was pressed
Input k,L1MT%tout%V,{LControl}{RControl}{LAlt}{RAlt}{LShift}{RShift}{LWin}{RWin}{AppsKey}{F1}{F2}{F3}{F4}{F5}{F6}{F7}{F8}{F9}{F10}{F11}{F12}{Left}{Right}{Up}{Down}{Home}{End}{PgUp}{PgDn}{Del}{Ins}{BS}{Capslock}{Numlock}{PrintScreen}{Pause}
If (ErrorLevel && ErrorLevel != "Max" && ErrorLevel != "EndKey:" key
|| !ErrorLevel && k != key) ; Break at long no-press time or foreign keys
Return Pattern
}
}
+Backspace::MsgBox % "Morse press pattern " Morse()
#!z::MsgBox % "Morse press pattern " Morse() |
|
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|