Handling single, double, triple, quadruple... infinite key presses.

Post your working scripts, libraries and tools
User avatar
GollyJer
Posts: 56
Joined: 19 Sep 2015, 19:33
GitHub: GollyJer

Handling single, double, triple, quadruple... infinite key presses.

Post by GollyJer » 18 Nov 2017, 13:43

I wanted an easy way to handle multiple presses of a hotkey. As far as I could Google there weren't any good solutions, so I dug in created this one. :P

It took a lot of reading and learning along the way and uses a couple techniques I don't see much on the forums. It also relies on the ErrorLevel returned from KeyWait, which is useful to understand.

Without further ado... here is...
HandleMultiplePresses()

Code: Select all

HandleMultiplePresses(pressHandlerNames*) {
  Recurse:

  keyPresses += 1
  strippedHotkey := StripHotkeyModifiers(A_ThisHotkey)
  KeyWait, %strippedHotkey%         ; Wait for KeyUp. 
  KeyWait, %strippedHotkey%, D T.12 ; Wait for same KeyDown or .12 seconds to elapse.
  keyPressedBeforeTimeout := (ErrorLevel = 0)

  If (keyPressedBeforeTimeout) {
    Goto, Recurse
  }
  
  Return pressHandlerNames[keyPresses]()
}

StripHotkeyModifiers(hotkeyToStrip) {
  ; from https://autohotkey.com/board/topic/32973-func-waitthishotkey/
  RegExMatch(hotkeyToStrip, "i)(?:[~#!<>\*\+\^\$]*([^ ]+)( UP)?)$", Key)
  Return Key1, ErrorLevel := (Key2 ? "Down" : "Up")
}
How do you use it?
After a hotkey, call HandleMultiplePresses with the number of function names matched to the number of key press counts you want to handle. The order defines the handler.
2 presses? Handled by the second parameter. 3? The third. etc.
An example will help.

Code: Select all

F1:: HandleMultiplePresses("SayGo", "SayFight", "SayWin")
^F1:: HandleMultiplePresses("SayGo", "SayFight", "SayWin")
F2:: HandleMultiplePresses("SayWin", "SayGo")

SayGo() {
  MsgBox, %A_ThisHotkey% says Go!
}

SayFight() {
  MsgBox, %A_ThisHotkey% says Fight!
}

SayWin() {
  MsgBox, %A_ThisHotkey% says Win!
}
I'm certain I'm missing something and this can be improved. But, it works pretty great.
I'll keep the post up to date with any improvements. Feedback welcome!
Last edited by GollyJer on 25 Apr 2018, 19:37, edited 3 times in total.
Helgef
Posts: 3185
Joined: 17 Jul 2016, 01:02
Contact:

Re: Handling single, double, triple, quadruple... infinite key presses.

Post by Helgef » 18 Nov 2017, 14:53

Very nice, well done :thumbup: .
Suggestion, on the last press, call the function without waiting, eg

Code: Select all

keyPresses += 1
if (keyPresses == pressHandlerNames.length())
	return pressHandlerNames[keyPresses]()
You might aswell use return, if the function returns something.

Cheers, thanks for sharing.
User avatar
GollyJer
Posts: 56
Joined: 19 Sep 2015, 19:33
GitHub: GollyJer

Re: Handling single, double, triple, quadruple... infinite key presses.

Post by GollyJer » 18 Nov 2017, 15:17

Very nice, well done :thumbup: .
Hi Helgef... thanks.
Suggestion, on the last press, call the function without waiting?
I would consider this unexpected behavior. What if some game needs me to press the key 20 times but I only want to do something special up to 3 times?
You might aswell use return, if the function returns something.
I don't see how it can hurt... code updated.
Cheers, thanks for sharing.
You're welcome!
rommmcek
Posts: 372
Joined: 15 Aug 2014, 15:18

Re: Handling single, double, triple, quadruple... infinite key presses.

Post by rommmcek » 21 Nov 2017, 21:17

Exorbitant! Specially I like this behavior:

Code: Select all

$F1:: HandleMultiplePresses("F1", "SayFight", "SayWin", "", "", "", "", "SayGo")
F1(){
	Send, {F1}
}
preserving native key response and not throwing an error for empty function "" !
I modified to:

Code: Select all

KeyWait, %strippedHotkey%, D T.3
Works fine for me, but have you any concerns about it?

Thanks!
User avatar
GollyJer
Posts: 56
Joined: 19 Sep 2015, 19:33
GitHub: GollyJer

Re: Handling single, double, triple, quadruple... infinite key presses.

Post by GollyJer » 22 Nov 2017, 15:58

Exorbitant! Specially I like this behavior:

Code: Select all

$F1:: HandleMultiplePresses("F1", "SayFight", "SayWin", "", "", "", "", "SayGo")
F1(){
	Send, {F1}
}
preserving native key response and not throwing an error for empty function "" !
Happy to know you like it!
And yes. That behavior is exactly what I was going for... the flexibility to handle (or not) any press sequence you desire.
I modified to:

Code: Select all

KeyWait, %strippedHotkey%, D T.3
Works fine for me, but have you any concerns about it?
No concerns. I chose a wait time that didn't feel long after a single press and I could achieve multiple presses without making a mistake.
fenchai
Posts: 186
Joined: 28 Mar 2016, 07:57

Re: Handling single, double, triple, quadruple... infinite key presses.

Post by fenchai » 22 Nov 2017, 17:51

Same as RapidHotkey() ?
I think RapidHotkey even allows sending texts, subs, actions.

but still pretty awesome work
User avatar
GollyJer
Posts: 56
Joined: 19 Sep 2015, 19:33
GitHub: GollyJer

Re: Handling single, double, triple, quadruple... infinite key presses.

Post by GollyJer » 27 Nov 2017, 20:51

fenchai wrote:Same as RapidHotkey() ?
I think RapidHotkey even allows sending texts, subs, actions.

but still pretty awesome work
HandleMultiplePresses allows you to define ANY function. So it can send texts, subs, actions... or am I missing what you mean?

It seems RapidHotkey does the same thing but is significantly more complicated. Also it doesn't, as far as I can tell, allow for different functions to be executed depending on the press count.
For those interested RapidHotkey is here.
fenchai
Posts: 186
Joined: 28 Mar 2016, 07:57

Re: Handling single, double, triple, quadruple... infinite key presses.

Post by fenchai » 28 Nov 2017, 13:48

GollyJer wrote:
fenchai wrote:Same as RapidHotkey() ?
I think RapidHotkey even allows sending texts, subs, actions.

but still pretty awesome work
HandleMultiplePresses allows you to define ANY function. So it can send texts, subs, actions... or am I missing what you mean?

It seems RapidHotkey does the same thing but is significantly more complicated. Also it doesn't, as far as I can tell, allow for different functions to be executed depending on the press count.
For those interested RapidHotkey is here.
I think RapidHotkey is more complicated but allows more customization while yours is simpler but has no way to change the timing of how long is double press and so on.

But I still would use yours for simplicity.
Post Reply

Return to “Scripts and Functions”