Thank you!, made the post here: https://autohotkey.com/boards/viewtopic.php?f=5&t=45585nnnik wrote:I think you should ask in Ask for Help and or inform yourself about threads and their limitations.
Why you should avoid while(GetKeyState("a", "P")) to detect release of key a
Re: Why you should avoid while(GetKeyState("a", "P")) to detect release of key a
Re: Why you should avoid while(GetKeyState("a", "P")) to detect release of key a
Sorry, just re-reading and noticed this comment:
2) "Useful"? Yes. "Works properly"? No - only when there is only one of them.
To properly enforce repeat suppression:
1) The key would not repeat 50 times a secondNextron wrote:On a side note, there are useful situations to wait for a key to be released by halting the execution of the hotkey like in the first example, for example to prevent key-repeat from executing a hotkey ~50 times per second as it would in the second example
2) "Useful"? Yes. "Works properly"? No - only when there is only one of them.
To properly enforce repeat suppression:
Code: Select all
a::
if (a_pressed)
return
a_pressed := 1
; [...]
return
a up::
a_pressed := 0
return
Re: Why you should avoid while(GetKeyState("a", "P")) to detect release of key a
I guess the topic 'How to disable repeat?' made you think about this topic too? I was considering whether to reply here or there.
Sure, under specific circumstances it will not work as one would want: If KeyWait is waiting AND a new pseudo thread interrupts AND that thread also does not return timely AND the first hotkey is pushed again. Perhaps that is a frequent occurrence in gaming or input emulation, but I doubt it is in office situations. Considering its ease of use, it shouldn't be dismissed outright. I would hate to create an accompanying up-hotkey every time I want to wait for a key or even update any existing up-hotkeys for each #If duplicate. Even then, I would need three different blocks of code for each of my three use cases instead of one command.
Besides that, although I use #UseHook,On for my main script, I tend to be conservative in applying the invasiveness of a hook in separate scripts or scripts that may be used by others. I wouldn't want to use a hook just to prevent key repeat unless there is a real indication that using KeyWait would actually be blocking.
My key history showed a held key sending a down event every 0.02 seconds, minus an activation delay of half a second. A F1::Tooltip % i++ script shows an execution rate close to the value above.1) The key would not repeat 50 times a second
So it has its limitations. So does Looping Input,foobar,L1 or AHK's hook detecting its own SendInput. Perhaps your use of held keys is is different from mine so that you strongly oppose KeyWait, but I use it frequently without problems. I even use a wrapper function that makes it easier to use and adds functionality. Either to prevent key repeat, to delay execution until the hotkey is released or segment the execution in consecutive blocks triggered by the same hotkey.2) "Useful"? Yes. "Works properly"? No - only when there is only one of them.
Sure, under specific circumstances it will not work as one would want: If KeyWait is waiting AND a new pseudo thread interrupts AND that thread also does not return timely AND the first hotkey is pushed again. Perhaps that is a frequent occurrence in gaming or input emulation, but I doubt it is in office situations. Considering its ease of use, it shouldn't be dismissed outright. I would hate to create an accompanying up-hotkey every time I want to wait for a key or even update any existing up-hotkeys for each #If duplicate. Even then, I would need three different blocks of code for each of my three use cases instead of one command.
Besides that, although I use #UseHook,On for my main script, I tend to be conservative in applying the invasiveness of a hook in separate scripts or scripts that may be used by others. I wouldn't want to use a hook just to prevent key repeat unless there is a real indication that using KeyWait would actually be blocking.
Re: Why you should avoid while(GetKeyState("a", "P")) to detect release of key a
Thanks for this topic @evilC!
I have been having problems in my scripts where I will discovered my LWin or LAlt (or something!) key is getting "stuck" and it's giving me quite the headache!
I will take the ideas in this thread and start working through my scripts to find the one (or more) that is causing this error. In the meantime, is there a way to notify me when a key is stuck down / on programatically, even when I have physically released the key(s)?
I found this topic that would pop up a tooltip when you held down the left or right win keys...
I was thinking of creating something that will check all keys so I know if something is stuck. Is there a better way than just making a timer for all the keys I want to check?
I have been having problems in my scripts where I will discovered my LWin or LAlt (or something!) key is getting "stuck" and it's giving me quite the headache!
I will take the ideas in this thread and start working through my scripts to find the one (or more) that is causing this error. In the meantime, is there a way to notify me when a key is stuck down / on programatically, even when I have physically released the key(s)?
I found this topic that would pop up a tooltip when you held down the left or right win keys...
I was thinking of creating something that will check all keys so I know if something is stuck. Is there a better way than just making a timer for all the keys I want to check?
____________________________________
Check out my site, submeg.com
Connect with me on LinkedIn
Courses on AutoHotkey
Check out my site, submeg.com
Connect with me on LinkedIn
Courses on AutoHotkey
Re: Why you should avoid while(GetKeyState("a", "P")) to detect release of key a
You could create an array, and whenever you programmatically hold or release a key, update the array.
Then, if you want to know if anything is stuck, just check the state of the array
Then, if you want to know if anything is stuck, just check the state of the array
Code: Select all
keyStates := {}
return
a::
SendKey("x", true)
while (GetKeyState("a")){
Sleep 100
}
SendKey("x", false)
return
F1::Gosub CheckKeys
SendKey(key, state){
global keyStates
Send % "{" key (state ? " down" : " up") "}"
keyStates[key] := state
return
}
CheckKeys:
for key, state in keyStates {
if (state){
msgbox % "Key " key " is held"
}
}
return
^Esc:: ExitApp
Last edited by evilC on 30 May 2021, 05:09, edited 1 time in total.
Re: Why you should avoid while(GetKeyState("a", "P")) to detect release of key a
Hey @evilC,
Thanks for the idea! I could see the idea in the code and I modified slightly to get my head around what was going on. What I notice is that even when you programmatically "force" a key down, (LWin in the example below), the array is not remembering it? When you check out KeyHistory, it's definitely down - pressing F1 brings up Windows help, so it has to be down, but it's not in the array?
Code: Select all
global keyStates
keyStates := {}
return
a::
KeyHistory
StuckKey("LShift")
StuckKey("LCtrl")
StuckKey("LAlt")
StuckKey("a")
Send, {LWin down}
StuckKey("LWin")
return
F1::
CheckKeys()
Return
StuckKey(key)
{
;Send, %key% (state ? " down" : " up")
;CheckState := %key% (state ? " down" : " up")
GetKeyState, state, %key%
If %state% = "down"
{
CheckState := "down"
}
else
{
CheckState := "up"
}
msgbox % "key is: " key ", and it is " CheckState
If CheckState = "down"
{
keyStates[key] := CheckState
}
return
}
CheckKeys()
{
CheckedStates := 0 ;No keys are stuck
for key, state in keyStates
{
if (state = "down")
{
msgbox % "Key " key " is down"
CheckedStates := 1 ;At least one key is stuck
}
}
If CheckedStates = 0
{
msgbox % "All keys are released."
}
}
return
____________________________________
Check out my site, submeg.com
Connect with me on LinkedIn
Courses on AutoHotkey
Check out my site, submeg.com
Connect with me on LinkedIn
Courses on AutoHotkey
Re: Why you should avoid while(GetKeyState("a", "P")) to detect release of key a
Your code is not doing anything like what mine was doing.
Granted, my code contained some typos (I wrote it from memory, didn't test it) - I was missing a bracket on the GetKeyState, and my send syntax was a bit garbled but once I fixed that it exhibits what I am talking about (Post edited to fix code).
Hold a, hit F1
Or, to demonstrate it another way
Tap a, then hit F1
Granted, my code contained some typos (I wrote it from memory, didn't test it) - I was missing a bracket on the GetKeyState, and my send syntax was a bit garbled but once I fixed that it exhibits what I am talking about (Post edited to fix code).
Hold a, hit F1
Or, to demonstrate it another way
Code: Select all
keyStates := {}
return
a::
SendKey("x", true)
;~ while (GetKeyState("a")){
;~ Sleep 100
;~ }
;~ SendKey("x", false)
return
F1::Gosub CheckKeys
SendKey(key, state){
global keyStates
Send % "{" key (state ? " down" : " up") "}"
keyStates[key] := state
return
}
CheckKeys:
for key, state in keyStates {
if (state){
msgbox % "Key " key " is held"
}
}
return
^Esc:: ExitApp
Re: Why you should avoid while(GetKeyState("a", "P")) to detect release of key a
Or, to demonstrate the kind of bug that this thread is about:
Hold a, hold b, release a
And then hit F1 while b is still held
It will say that both x and y are held, despite the fact that you released a, so x should be not held
Code: Select all
keyStates := {}
return
a::
SendKey("x", true)
while (GetKeyState("a")){
Sleep 100
}
SendKey("x", false)
return
b::
SendKey("y", true)
while (GetKeyState("b")){
Sleep 100
}
SendKey("y", false)
return
F1::Gosub CheckKeys
SendKey(key, state){
global keyStates
Send % "{" key (state ? " down" : " up") "}"
keyStates[key] := state
return
}
CheckKeys:
for key, state in keyStates {
if (state){
msgbox % "Key " key " is held"
}
}
return
^Esc:: ExitApp
And then hit F1 while b is still held
It will say that both x and y are held, despite the fact that you released a, so x should be not held
Re: Why you should avoid while(GetKeyState("a", "P")) to detect release of key a
Or, to demonstrate a slightly more elegant way of doing it:
In this example, you don't even need to iterate the array to see if anything is stuck, because when the key is released, instead of setting the array entry to say that the key is released, it completely removes that key from the array
Therefore, a simple keyStates.length() == 0 check will tell you if there is anything held
Code: Select all
keyStates := {}
return
a::
SendKey("x", true)
while (GetKeyState("a")){
Sleep 100
}
SendKey("x", false)
return
b::
SendKey("y", true)
while (GetKeyState("b")){
Sleep 100xy
}
SendKey("y", false)
return
F1::Gosub CheckKeys
SendKey(key, state){
global keyStates
Send % "{" key (state ? " down" : " up") "}"
if (state){
keyStates[key] := 1
} else {
keyStates.Delete(key)
}
return
}
CheckKeys:
if (keyStates.length() == 0){
msgbox Nothing is held
} else {
for key, state in keyStates {
msgbox % "Key " key " is held"
}
}
return
Therefore, a simple keyStates.length() == 0 check will tell you if there is anything held
Re: Why you should avoid while(GetKeyState("a", "P")) to detect release of key a
Yep, I worked that out quick smart!Your code is not doing anything like what mine was doing.
I was able to get my idea working, but it's definitely not elegant. I will give you examples a test tomorrow; my brain is too tired to do any more coding tonight.
Thank you for this thread (and scripts), I know that using KeyWait and GetKeyState are currently causing me issues and this thread will help me iron them out.
Absolute champion @evilC.
____________________________________
Check out my site, submeg.com
Connect with me on LinkedIn
Courses on AutoHotkey
Check out my site, submeg.com
Connect with me on LinkedIn
Courses on AutoHotkey
Re: Why you should avoid while(GetKeyState("a", "P")) to detect release of key a
I don't do hotkeys much, this looks like a better design, thank you!
Return to “Tips and Tricks (v1)”
Who is online
Users browsing this forum: No registered users and 19 guests