GetKeyboardState Lag/Delay?

Basically I’ve been writing a system for macros where someone types in the keys they want in a specific window and the application relays the keys after recording them, essentially a bot to do different little tasks and allow them to save those tasks into a script file so they can re-run them at any time they want almost like a simplistic programming language of sorts via recording what a user enters, clicks on, mouse movements, and pixel color detection at some points as well.

The problem I’m encountering currently though is while using the GetKeyboardState API in order to determine the states of all the keys and passing that into ToAscii it seems to be lagging or delayed.

For example if I hold shift and press A immediately after holding shift down it will report “a” instead of A(which is what is really being entered), if I were to press 1 immediately after holding shift it would report 1 instead of “!” which is what is really being typed.

Like wise the key up event is also delayed/lagged when I let go of shift and I press “1” it reports “!” instead of 1 which is what’s really being entered, and likewise with “a” it reports “A” when it should report “a” as shift has been lifted.

With the above being said I thank anyone in advance who can help me out with this here’s the code, hopefully someone here knows if I’m doing something wrong or what could possibly be causing this issue.

It’s actually a very bad/program destroying issue as when recording and playing back it doesn’t work as the end user intended,
it’ll start pressing the wrong keys.

For instance I was making it play a game like a pre-programmed bot and it would press the wrong keys every once in awhile due to this issue.

I’d run using shift then try to use the action bound to 1 and it would type ! instead of 1 and fail to perform the action.

Function ToAscii(uVirtKey as UInt32,uScanCode as UInt32, uFlags as UInt32) As string
  Declare Function GetKeyboardState Lib "User32" ( lpKeyState as Ptr ) as Integer
  Declare Function ToAscii Lib "User32" ( uVirtKey as uint32, uScanCode as uint32, lpKeyState as Ptr, lpChar as Ptr, uFlags as Uint32) as Integer
  
  dim mb as new MemoryBlock( 256 )
  dim char as New MemoryBlock(2)
  Dim RetString As String
  if GetKeyBoardState( mb ) <> 0 Then // Non-Zero is success
    
    if ToAscii(uVirtKey,uScanCode,mb,char,uFlags) > 0 Then // 0 is invalid ASCII character, from what I read.
      return char.CString(0)
    end
    
  else
    MsgBox "Issue getting keyboardstate" // I never actually got this so I know it's not returning zero
  end
  
End Function

Keypress messages are queued up until they are handled by the process that receives them. GetKeyboardState returns the state at the head of the queue. Therefore, it is possible that it’s information is stale. This is a good thing if you’re handling an event, because you want the state of the keyboard at the time the event occured. It’s not so good if you’re “sniffing” the keystrokes. You could use GetAsyncKeyState or similar to get the current state of the keyboard in real time.

Yeah, I was doing some testing and realized it wasn’t actually properly detecting the state of me holding or letting go of shift even though I thought the event would’ve been recorded properly.

During my tests I noticed if I did something along the lines of hold shift press 1(!) let go of shift hit backspace then hit 1(1) it would actually operate properly almost like a “queue” as you’ve said wasn’t being updated until another key was pressed after shift was pressed (beyond shift there aren’t any problems with similar keys like capslock or etc).

So I’m wondering how would you yourself go about implementing GetAsyncKeyState,
I was originally using something along those lines but I couldn’t get a timer to operate properly while getting each key’s state so I wound up having keys repeat which is why I went with a low level keyboard hook instead it seemed more reliable up until now.

If I wanted to avoid using GetAsyncKeyState do you have any idea how I’d be able to make the “queue” periodically update even when keys aren’t being pressed or such maybe a timer which requests the KeyboardState every so often?

The other reason why I needed to use toAscii was the fact that using GetKeyNameText couldn’t account for the shift/control keys,
Where as toAscii appeared to be able to with this slight lag and or delay.

Another reason why I was wanting to avoid GetAsyncKeyState is that I’d have to manually determine whether or not shift is pressed and perform my own actions based on such instead of being able to use an API like the toAscii one which can automatically get the symbol/key being pressed uppercase, lowercase, or shift alternative included.

Thanks for the excellent answer/explanation though just as I had figured out that it was queuing up some how (via pressing backspace after pressing shift to trigger the queue update) I wound up reading this and you confirmed what I thought to be true.

EDIT:
I seem to have fixed it my self by changing up the toAscii sub routine and requesting additional key states which appears to update the message queue appropriately.

[code]Function ToAscii(uVirtKey as UInt32,uScanCode as UInt32, uFlags as UInt32) As string
Declare Function GetKeyState Lib “User32” ( nVirtKey As integer ) as short
Declare Function GetKeyboardState Lib “User32” ( lpKeyState as Ptr ) as Integer
Declare Function ToAscii Lib “User32” ( uVirtKey as uint32, uScanCode as uint32, lpKeyState as Ptr, lpChar as Ptr, uFlags as Uint32) as Integer

dim mb as new MemoryBlock( 256 )
dim char as New MemoryBlock(2)

const VK_CAPITAL = &h14
const VK_NUMLOCK = &h90
const VK_SCROLL = &h91

Dim CapitalState as Short = GetKeyState(VK_CAPITAL)
Dim NumState as Short = GetKeyState(VK_NUMLOCK)
Dim ScrollState as Short = GetKeyState(VK_SCROLL)

if GetKeyBoardState( mb ) <> 0 Then

if ToAscii(uVirtKey,uScanCode,mb,char,uFlags) > 0 Then
  return char.CString(0)
end

else
MsgBox “Issue getting keyboardstate”
end

End Function
[/code]

Just requesting them seems to update the keyboard state’s shift to the appropriate value before I request it, and I’ve tested through and through with no issues at all so far.