AutoHotkey Community

It is currently May 26th, 2012, 3:37 pm

All times are UTC [ DST ]




Post new topic Reply to topic  [ 71 posts ]  Go to page 1, 2, 3, 4, 5  Next
Author Message
 Post subject: RapidHotkey()
PostPosted: December 13th, 2008, 3:01 am 
Offline

Joined: June 18th, 2008, 8:36 am
Posts: 4923
Location: AHK Forum
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 :wink:


Last edited by HotKeyIt on June 4th, 2011, 9:28 am, edited 66 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 13th, 2008, 8:08 pm 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
Nice! You can extend the idea with detecting the lengths of key presses, like here.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 13th, 2008, 9:54 pm 
Offline

Joined: June 18th, 2008, 8:36 am
Posts: 4923
Location: AHK Forum
Laszlo wrote:
Nice! You can extend the idea with detecting the lengths of key presses, like here.

Thank you a lot for that :D

Using your function now, RapidHotkey looks to work perfectly and you can use modifiers as well. I've updated the post.

_________________
AHK_H (2alpha) AHF TT _Struct WatchDir Yaml _Input ObjTree RapidHotkey DynaRun :wink:


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 14th, 2008, 12:24 am 
Offline

Joined: June 18th, 2008, 8:36 am
Posts: 4923
Location: AHK Forum
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 :wink:


Last edited by HotKeyIt on January 14th, 2009, 1:47 pm, edited 2 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 14th, 2008, 10:26 pm 
Offline

Joined: June 18th, 2008, 8:36 am
Posts: 4923
Location: AHK Forum
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 :wink:


Last edited by HotKeyIt on January 14th, 2009, 1:48 pm, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 22nd, 2008, 12:09 am 
Offline

Joined: October 13th, 2008, 4:14 pm
Posts: 60
Location: South Park, Colorado
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


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 29th, 2008, 7:51 pm 
Offline

Joined: May 17th, 2007, 6:03 pm
Posts: 391
Location: Titan
Nice work Hotkeyit.
________
MICHIGAN MEDICAL MARIJUANA DISPENSARY


Last edited by lilalurl.T32 on February 11th, 2011, 9:41 pm, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 29th, 2008, 8:31 pm 
Offline

Joined: June 18th, 2008, 8:36 am
Posts: 4923
Location: AHK Forum
lilalurl.T32 wrote:
Nice work Hotkeyit.

Thanks, I'm glad you find it useful. :)

_________________
AHK_H (2alpha) AHF TT _Struct WatchDir Yaml _Input ObjTree RapidHotkey DynaRun :wink:


Report this post
Top
 Profile  
Reply with quote  
 Post subject: NumBoard
PostPosted: January 9th, 2009, 10:54 am 
Offline

Joined: June 18th, 2008, 8:36 am
Posts: 4923
Location: AHK Forum
I've written a NumBoard for fun so you can type one handed using numpad

NumBoard

_________________
AHK_H (2alpha) AHF TT _Struct WatchDir Yaml _Input ObjTree RapidHotkey DynaRun :wink:


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 24th, 2009, 9:44 pm 
Offline

Joined: June 18th, 2008, 8:36 am
Posts: 4923
Location: AHK Forum
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 :wink:


Last edited by HotKeyIt on March 18th, 2009, 11:35 pm, edited 3 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject: Does Not Work?
PostPosted: March 18th, 2009, 10:55 pm 
Offline

Joined: February 11th, 2009, 2:59 am
Posts: 5
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


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 18th, 2009, 11:37 pm 
Offline

Joined: June 18th, 2008, 8:36 am
Posts: 4923
Location: AHK Forum
You have to include both functions in your script or include RapidHotkey.ahk and Morse.ahk in your Lib directories or:
Code:
#include RapidHotkey.ahk
#include Morse.ahk

_________________
AHK_H (2alpha) AHF TT _Struct WatchDir Yaml _Input ObjTree RapidHotkey DynaRun :wink:


Report this post
Top
 Profile  
Reply with quote  
PostPosted: September 15th, 2009, 3:13 pm 
Offline

Joined: December 1st, 2008, 12:34 pm
Posts: 49
Location: UK
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
      }
   }
}
;;;;;;;;;;;;;;;;;;;;;;;;


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: September 15th, 2009, 10:47 pm 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: September 15th, 2009, 11:10 pm 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
... 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()


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 71 posts ]  Go to page 1, 2, 3, 4, 5  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: No registered users and 19 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group