GetKeyState( ,"P") keeps returning true for already released keys

Report problems with documented functionality
drUniversalis

GetKeyState( ,"P") keeps returning true for already released keys

Post by drUniversalis » 27 Mar 2017, 23:58

This happens in 1 out of 100+ presses, the keyhistory shows the down event, but no up event (even though i only tapped the key) and GetKeyState is locked on true forever.

i so far only tested this with the "f" key

Windows 10
Laptop + USB Keyboard
$f:: is used in the script
the script does send keystrokes itself inbetween the physical press and release of f, sometimes it sends f itself or shift+f (i think this triggers the error)
this might only happen when shift down is send before the physical release of f (not verified yet)

i am using these directives:

Code: Select all

#NoEnv
#InstallKeybdHook
#InstallMouseHook
#KeyHistory 500
#Persistent
#SingleInstance force
SendMode Input
SetWorkingDir %A_ScriptDir%
CoordMode, Pixel, Screen
CoordMode, Mouse, Screen
the script just loops (~150ms per loop) and sends keypresses based on several GetKeyStates

drUniversalis
Posts: 2
Joined: 28 Mar 2017, 13:19

Re: GetKeyState( ,"P") keeps returning true for already released keys

Post by drUniversalis » 28 Mar 2017, 13:25

*removed old info*
Last edited by drUniversalis on 28 Mar 2017, 14:50, edited 1 time in total.

drUniversalis
Posts: 2
Joined: 28 Mar 2017, 13:19

Re: GetKeyState( ,"P") keeps returning true for already released keys

Post by drUniversalis » 28 Mar 2017, 14:18

reproduced it a few times now in a new tidy script, in different applications (one beeing notepad), best try took me 70 keypresses, worst was beyond 400

keyhistory: (replaced f with d too exclude the possibilty of an broken "f" key on my keyboard)

Code: Select all

52  013	i	d	0.17	r              	
52  013	i	u	0.00	r              	
52  013	i	d	0.17	r              	
52  013	i	u	0.00	r              	
44  020	h	d	0.02	d              	<--- physical press
44  020	s	u	0.14	d              	<--- up event
52  013	i	d	0.02	r              	
52  013	i	u	0.00	r              	
52  013	i	d	0.17	r              	
52  013	i	u	0.00	r              	
52  013	i	d	0.17	r              	
52  013	i	u	0.00	r              	
44  020	h	d	0.03	d              	<--- physical press (script locked on d down)
A0  02A	i	d	0.14	LShift         	
52  013	i	d	0.00	r              	
52  013	i	u	0.00	r              	
A0  02A	i	u	0.00	LShift         	
A0  02A	i	d	0.17	LShift         	
52  013	i	d	0.00	r              	
52  013	i	u	0.00	r              	
A0  02A	i	u	0.00	LShift         	
A0  02A	i	d	0.17	LShift         	
52  013	i	d	0.00	r              	
52  013	i	u	0.00	r              	
A0  02A	i	u	0.00	LShift         	
A0  02A	i	d	0.17	LShift         	
52  013	i	d	0.00	r              	
52  013	i	u	0.00	r              	
A0  02A	i	u	0.00	LShift         	
A0  02A	i	d	0.17	LShift         	
52  013	i	d	0.00	r              	
52  013	i	u	0.00	r              	
A0  02A	i	u	0.00	LShift         	
A0  02A	i	d	0.17	LShift         	
52  013	i	d	0.00	r              	
52  013	i	u	0.00	r              	
A0  02A	i	u	0.00	LShift         	
A0  02A	i	d	0.17	LShift         	
52  013	i	d	0.00	r              	
52  013	i	u	0.00	r         
another keyhistory:

Code: Select all

52  013	i	u	0.00	r              	
44  020	h	d	0.11	d              	<--- physical press
A0  02A	i	d	0.06	LShift         	
52  013	i	d	0.00	r              	
52  013	i	u	0.00	r              	
A0  02A	i	u	0.00	LShift         	
44  020	s	u	0.09	d              	<--- up event
52  013	i	d	0.08	r              	
52  013	i	u	0.00	r              	
52  013	i	d	0.17	r              	
52  013	i	u	0.00	r              	
52  013	i	d	0.17	r              	
52  013	i	u	0.00	r              	
44  020	h	d	0.03	d             	 <--- physical press (script locked on d down)
A0  02A	i	d	0.14	LShift         	
52  013	i	d	0.00	r              	
52  013	i	u	0.00	r              	
A0  02A	i	u	0.00	LShift         	
A0  02A	i	d	0.17	LShift         	
52  013	i	d	0.00	r              	
52  013	i	u	0.00	r              	
A0  02A	i	u	0.00	LShift         	
A0  02A	i	d	0.17	LShift         	
52  013	i	d	0.00	r              	
52  013	i	u	0.00	r              	
A0  02A	i	u	0.00	LShift         	
44  020	h	d	0.14	d              	<--- physical press
A0  02A	i	d	0.03	LShift         	
52  013	i	d	0.00	r              	
52  013	i	u	0.00	r              	
A0  02A	i	u	0.00	LShift         	
44  020	s	u	0.14	d              	<--- up event
52  013	i	d	0.03	r              	
52  013	i	u	0.00	r              	
52  013	i	d	0.17	r              	
52  013	i	u	0.00	r              	
52  013	i	d	0.17	r              	
52  013	i	u	0.00	r              	


here is the test script, would love for someone to try reproduce this on his machine. Any thoughts why this could happen? Possible fixes?

Code: Select all

#NoEnv
#InstallKeybdHook
#InstallMouseHook
#KeyHistory 500
#Persistent
#SingleInstance force
#MaxHotkeysPerInterval 10000
#HotkeyInterval 10000
; ListLines Off
SendMode Input
SetWorkingDir %A_ScriptDir%
SetBatchLines, -1
SetKeyDelay, -1, -1
SetWinDelay, -1
SetControlDelay, -1
CoordMode, Pixel, Screen
CoordMode, Mouse, Screen

Gui, 50:+AlwaysOnTop 
Gui, 50:Add, Text, cBlue vgui1 x10 y10 w120, N/A
Gui, 50:Add, Text, cBlue vgui2 x140 y10 w120, N/A
Gui, 50:Show, x1580 y980 W320 H40

foo := 1
keypresses := 0
step()

$d::
keypresses++
return

F1::
foo := 0
Suspend
return

F10::ExitApp

step() {
	global
	while (foo == 1) {
		sleep 170
		
		dllstate := DllCall("GetKeyState", Uint, 0x44)
		dllstateasync := DLLCall("GetAsyncKeyState", Uint, 0x44)
		if (GetKeyState("d", "P")) {
			send +r
			GuiControl, 50:, gui1, % "d PRESSED DOWN" . " dll:" . dllstate . " adll:" . dllstateasync
		} else {
			GuiControl, 50:, gui1, % "d released" . " dll:" . dllstate . " adll:" . dllstateasync
			send r
		}


		GuiControl, 50:, gui2, % keypresses

	}
	return
}

EDIT1: tested it without the $d:: hotkey set, still occurs
also the logical state seems to revert to normal, only physical has this bug.
DllCall("GetKeyState", Uint, 0x44) and DLLCall("GetAsyncKeyState", Uint, 0x44) return 0 after i physically release the key, obviously those are no help when i block the $d key (which is required in my original script)

EDIT2: tested without shift modifier, still occurs

EDIT3: unable to reproduce when the script does not send hotkeys itself, 1500 keystrokes in and my fingers need a break

EDIT4: could it have something to do with this?
SendInput and SendPlay [v1.0.43+]: SendInput and SendPlay use the same syntax as Send but are generally faster and more reliable. In addition, they buffer any physical keyboard or mouse activity during the send, which prevents the user's keystrokes from being interspersed with those being sent. SendMode can be used to make Send synonymous with SendInput or SendPlay. For more details about each mode, see SendInput and SendPlay below.

EDIT5: unable to reproduce when SendMode Event is used (1000 keystrokes tested)
The autohotkey source is exceptionally well documented btw. Still, hard to find the right spot for when the buffering mentioned in EDIT4 is taking place, is keyboard_mouse.cpp the right place to look?

Code: Select all

if (sSendMode == SM_INPUT)
	{
		// Remove hook(s) temporarily because the presence of low-level (LL) keybd hook completely disables
		// the uninterruptibility of SendInput's keystrokes (but the mouse hook doesn't affect them).
im getting the feeling that my bug is a feature :D

Philister
Posts: 33
Joined: 01 Apr 2016, 07:31

Re: GetKeyState( ,"P") keeps returning true for already released keys

Post by Philister » 17 Jun 2021, 03:11

Glad I found this thread! I am also experiencing this bug! Have now changed SendMode to use the event method and will report back whether that solves the problem for me, too. If it turns out that's the case, it would be great if the issue with the SendInput / SendPlay buffering interfering with GetKeyState (Is that this the cause?) could be fixed...

lexikos
Posts: 9589
Joined: 30 Sep 2013, 04:07
Contact:

Re: GetKeyState( ,"P") keeps returning true for already released keys

Post by lexikos » 08 Jul 2023, 02:53

GetKeyState with "P" reports the state as recorded by the keyboard hook. If the keyboard hook is not notified of key-up, it will not appear in KeyHistory or affect the hook's record of key state.

AutoHotkey's SendInput automatically uninstalls the keyboard hook and reinstalls it afterward, because leaving it installed would defeat all of the advantages of SendInput.
If a script other than the one executing SendInput has a low-level keyboard hook installed, SendInput automatically reverts to SendEvent (or SendPlay if SendMode "InputThenPlay" is in effect). This is done because the presence of an external hook disables all of SendInput's advantages, making it inferior to both SendPlay and SendEvent.
Source: Send - Syntax & Usage | AutoHotkey v2
The documentation does seem to imply that the script's own hook isn't an issue, but that's only because it is deactivated temporarily.


The system buffers physical keystrokes during the SendInput call, and apparently processes all of them before returning, so by the time AutoHotkey reinstalls its hook, it has missed those events. There is a related comment by Chris Mallett:

Code: Select all

				// The above call to SendInput() has not only sent its own events, it has also emptied
				// the buffer of any events generated outside but during the SendInput.  Since such
				// events are almost always physical events rather than simulated ones, it seems to do
				// more good than harm on average to consider any such changes to be physical.
				// The g_PhysicalKeyState array is also updated by GetModifierLRState(true), but only
				// for the modifier keys, not for all keys on the keyboard.  Even if adjust all keys
				// is possible, it seems overly complex and it might impact performance more than it's
				// worth given the rarity of the user changing physical key states during a SendInput
				// and then wanting to explicitly retrieve that state via GetKeyState(Key, "P").

wysnxzm
Posts: 6
Joined: 16 Jul 2020, 22:51

Re: GetKeyState( ,"P") keeps returning true for already released keys

Post by wysnxzm » 30 Oct 2023, 20:06

This problem is reproduced in the latest version 2.0.10. It occurs when GetKeyState and SendInput are used at the same time. It works normally after changing to SendEvent.

wysnxzm
Posts: 6
Joined: 16 Jul 2020, 22:51

Re: GetKeyState( ,"P") keeps returning true for already released keys

Post by wysnxzm » 30 Oct 2023, 20:28

lexikos wrote:
08 Jul 2023, 02:53
GetKeyState with "P" reports the state as recorded by the keyboard hook. If the keyboard hook is not notified of key-up, it will not appear in KeyHistory or affect the hook's record of key state.

AutoHotkey's SendInput automatically uninstalls the keyboard hook and reinstalls it afterward, because leaving it installed would defeat all of the advantages of SendInput.
If a script other than the one executing SendInput has a low-level keyboard hook installed, SendInput automatically reverts to SendEvent (or SendPlay if SendMode "InputThenPlay" is in effect). This is done because the presence of an external hook disables all of SendInput's advantages, making it inferior to both SendPlay and SendEvent.
Source: Send - Syntax & Usage | AutoHotkey v2
The documentation does seem to imply that the script's own hook isn't an issue, but that's only because it is deactivated temporarily.


The system buffers physical keystrokes during the SendInput call, and apparently processes all of them before returning, so by the time AutoHotkey reinstalls its hook, it has missed those events. There is a related comment by Chris Mallett:

Code: Select all

				// The above call to SendInput() has not only sent its own events, it has also emptied
				// the buffer of any events generated outside but during the SendInput.  Since such
				// events are almost always physical events rather than simulated ones, it seems to do
				// more good than harm on average to consider any such changes to be physical.
				// The g_PhysicalKeyState array is also updated by GetModifierLRState(true), but only
				// for the modifier keys, not for all keys on the keyboard.  Even if adjust all keys
				// is possible, it seems overly complex and it might impact performance more than it's
				// worth given the rarity of the user changing physical key states during a SendInput
				// and then wanting to explicitly retrieve that state via GetKeyState(Key, "P").
Is there any other solution besides changing to SendEvent? Thanks for the answer

wysnxzm
Posts: 6
Joined: 16 Jul 2020, 22:51

Re: GetKeyState( ,"P") keeps returning true for already released keys

Post by wysnxzm » 18 Mar 2024, 05:01

lexikos wrote:
08 Jul 2023, 02:53
GetKeyState with "P" reports the state as recorded by the keyboard hook. If the keyboard hook is not notified of key-up, it will not appear in KeyHistory or affect the hook's record of key state.

AutoHotkey's SendInput automatically uninstalls the keyboard hook and reinstalls it afterward, because leaving it installed would defeat all of the advantages of SendInput.
If a script other than the one executing SendInput has a low-level keyboard hook installed, SendInput automatically reverts to SendEvent (or SendPlay if SendMode "InputThenPlay" is in effect). This is done because the presence of an external hook disables all of SendInput's advantages, making it inferior to both SendPlay and SendEvent.
Source: Send - Syntax & Usage | AutoHotkey v2
The documentation does seem to imply that the script's own hook isn't an issue, but that's only because it is deactivated temporarily.


The system buffers physical keystrokes during the SendInput call, and apparently processes all of them before returning, so by the time AutoHotkey reinstalls its hook, it has missed those events. There is a related comment by Chris Mallett:

Code: Select all

				// The above call to SendInput() has not only sent its own events, it has also emptied
				// the buffer of any events generated outside but during the SendInput.  Since such
				// events are almost always physical events rather than simulated ones, it seems to do
				// more good than harm on average to consider any such changes to be physical.
				// The g_PhysicalKeyState array is also updated by GetModifierLRState(true), but only
				// for the modifier keys, not for all keys on the keyboard.  Even if adjust all keys
				// is possible, it seems overly complex and it might impact performance more than it's
				// worth given the rarity of the user changing physical key states during a SendInput
				and then wanting to explicitly retrieve that state via GetKeyState(Key, "P").
Will this issue be fixed in the latest update?

Post Reply

Return to “Bug Reports”