From MSDN , I have learned that GetKeyState is associated with message queue of current thread.
Then I created two sample applications : KeyPresser and BackChecker.
I press a key in KeyPresser , in this application , I am using GetKeyState/GetAsyncKeyState/GetKeyboardState to retrieve the pressed key state , and they tell me that key is pressing down.
Then I send(or post) a message form KeyPresser to BackChecker , to notify BackChecker to check the key state in it's thread .
I get same result from BackChecker indicate that key is pressed. But I think GetKeyState/GetKeyboardState should return zero because the key is pressed in thread of KeyPresser , which is not associated with thread of BackChecker.
Why?
Keyboard input on Windows is buffered. It ensures the user can keep typing, even if the program is temporarily unresponsive. It always is, to some degree, no loss of keystrokes that way. They are added to the message queue, the program's message loop retrieves them with GetMessage() later.
Along with the keystroke, it also stores the state of all the other keys. To ensure that, when the message is eventually retrieved, you can reliable tell what other keys were down. Very important for the modifier keys for example. A shortcut keystroke like Ctrl+A would not work reliably otherwise.
So you generally always use GetKeyState(), you get the state of the keys as they were recorded originally. Or GetKeyboardState(), you get the whole enchilada. Using GetAsyncKeyState() is much less common, it doesn't rely on the buffered state, only needed if the app has very unusual message handling. Might be appropriate in a game perhaps.
Related
I'm having a hard time with GLFW's input system, figuring out how to make it work the way I want it, so I've come to people with more experience for wisdom. Using GLFW 3.
There are 3 states 0 Release, 1 Press and 2 Repeat. This is exactly what I would want, only, the key state from Press to Repeat takes about a second to change. Ideally, I would want it to have a state "Press" only for 1 frame, and then change into a repeat state.
The goal: Be able to easily call functions based on what state my key is as follows:
press Tap (do once)
repeat Continuous (do every frame)
release Don't respond
LINK
Please have a look in the files on the link above, and let me know if there's another way around it. Or is the approach itself rubbish, the way I do it? Thanks guys, all feedback and help appreiated.
One way is to simply ignore the "repeat" event, and only go with the "press" and "release" events.
When you get the "press" event set a flag, and clear the flag on the "release" event. Then simply check this flag every frame.
It is very important that there is a delay between "press" and "repeat". Most human beings are incapable of pressing and releasing a key, such that your game only registers the key being pressed for exactly one frame. And the few who are capable of that cannot do so consistently, with any accuracy.
So a user will never be able to "do once". They will be doing it for multiple frames. That's generally bad.
Also, there is a conceptual difference between pressing, holding, and repeating. Holding is just what happens when you hold down the key. Repeating is a facility that is governed by the OS (which is why GLFW doesn't give you a way to set the repeat rate). Key repeating is typically meant for text input (which GLFW takes care of for you anyway via its text-based callback).
Essentially, you should ignore it. In a game situation, a key has 4 possible useful states: not pressed, was just pressed, being held down, and was just released. You can infer this from the button's previous state (which you can store) and the button's current state provided by the callback.
If all you want to do is take an action when a button "was just pressed", then you need to know that the button was not pressed in the previous frame. If the key is pressed now but not in the previous frame, take the action.
I'm making a program that will take keystrokes entered and change the output to form a message of my choosing. I'm thinking of using GetAsyncKeystate() to see if a key is down, but I'm not sure how to change the value of the key pressed.
Your best bet is a low-level keyboard hook. You don't get a ton of context, but you do get the raw keystrokes. If you need context, then you're probably looking at a text service via TSF, but that tends to get complex quickly.
I am making a wrapper for keyboard input using Direct Input. To grab the key states, the function GetDeviceState() is called with a char buffer.
This is all well and good, but now to send key events I must iterate through the buffer and check against all the keys that were pressed. I was hoping there would be a callback instead that only passed the key codes that were pressed.
If anybody has experience with Direct Input, is iterating through the key code buffer the only way to check for key presses?
That answer is to use GetDeviceData() instead. You will be able to get whether the key was pressed or released and the offset of the key that was pressed, which is pretty close to what I was looking for as now I can initiate my own callbacks and the overhead if no key is pressed is minimal.
What is the fastest way to determine a key press and also how to determine if a key is being held? It appears that window messaging is slow. Please provide an example of how to do so, and why it is faster than an alternative.
To be clear, this for a real time loop (a simulation) so I am looking for the fastest way to determine if a key has been pressed and also to check to see if it is being held.
GetAsyncKeyState() is what you're looking for. It reads the physical state of the keyboard, regardless of the input queue state. If the high-bit is set, then the key was down at the time of the call.
// Fetch tab key state.
SHORT tabKeyState = GetAsyncKeyState( VK_TAB );
// Test high bit - if set, key was down when GetAsyncKeyState was called.
if( ( 1 << 15 ) & tabKeyState )
{
// TAB key down...
}
Also, for the record, Windows is not a real-time operating system. If your application requires real-time precision, you may want to select another platform.
If you just want to poll the keyboard state so as to discover which keys are up/down as well as the shift/alt/ctrl state, just call GetKeyboardState (MSDN reference).
When I worked in a game studio, this is exactly how we got keyboard state for each frame. Should be applicable to your simulation code.
TL;DR: you can use GetAsyncKeyState for checking if a key is currently down, but for best application responsiveness to key presses and releases, you want to use the Win32 pipeline code near the bottom of my post.
GetAsyncKeyState works perfectly fine for determining if a key is currently down, but in terms of determining whether a key was first pressed or released and how many times this was done, GetAsyncKeyState misses keystrokes in a CPU-intensive application, even after storing the previous key state.
This was what I tried:
static const unsigned int NumberOfKeys = 256U;
bool previousKeyboardState[NumberOfKeys];
//Get the current state of each key as the application starts to ensure that keys held down beforehand are not processed as pressed keys.
for (unsigned int keyNum = 0U; keyNum < NumberOfKeys; ++keyNum)
{
previousKeyboardState[keyNum] = isKeyDown(keyNum);
}
//Works fine.
bool isKeyDown(int key)
{
return (GetAsyncKeyState(key) & (1 << 16));
}
//Misses key presses when application is bogged down.
bool isKeyFirstPressed(int key)
{
bool previousState = previousKeyboardState[key];
previousKeyboardState[key] = isKeyDown(key);
return (previousKeyboardState[key] && !previousState);
}
//Misses key releases when application is bogged down.
bool isKeyFirstReleased(int key)
{
bool previousState = previousKeyboardState[key];
previousKeyboardState[key] = isKeyDown(key);
return (!previousKeyboardState[key] && previousState);
}
//Example usage:
if (isKeyDown(VK_W))
{
//W key.
}
if (isKeyFirstReleased(VK_SNAPSHOT))
{
//Print screen.
}
GetKeyboardState is no good either, as it does not keep track of the number of key presses or releases. As Erik Philips said in his answer, these are unbuffered solutions, which are no good if you are e.g. writing a game. You would have to process all keystrokes faster than they are received.
Now, my code above works decently well, and may be suitable for many people, but I much prefer not to miss a single keystroke. I hate using applications that are unresponsive. I think the best solution for Win32 applications is to catch WM_KEYDOWN and WM_KEYUP messages in the pipeline and process them. What's nice is that WM_KEYDOWN also provides an auto-repeat count, which could be useful for applications that support entering text (e.g. chat, IDE's, etc.). This also adds a slight complication, which is mentioned in the WM_KEYDOWN documentation:
Because of the autorepeat feature, more than one WM_KEYDOWN message
may be posted before a WM_KEYUP message is posted. The previous key
state (bit 30) can be used to determine whether the WM_KEYDOWN message
indicates the first down transition or a repeated down transition.
There are also Windows keyboard hooks you could look into, but those are more difficult to use. They're good for receiving global key presses though.
Considering that all inter-windows communications are through windows messaging (keyboard events, mouse events, pretty much all events you can imagine), there isn't a lower level way to access the keyboard events (unless you write your own keyboard driver) that I know of.
DirectX still uses the windows keyboard messaging to provide DirectX programmers easier access to keyboard events.
Updated
My note about DirectX was not to use it, but that when Microsoft wanted to make an interface for programmers to use for real time games, they still wrote DirectX on top of the Windows Message Queue.
I would suggest taking a look at how to write a program that can read directly from the message queue. I believe there is a good example Code Project Windows Message Handling - Part 1.
Your two options are to either read from the message queue (buffered) or read directly from the keyboard state (as Bukes states) which means your own loop could techinically miss a keyboard event for any number of reasons.
Basically, when one types, a keydown event happens. If the key is held for more than a certain time (~1 sec) then the key is repeatedly pressed until keyup hapens. I would like to change the time it takes for the key to be automatically repressed in my c++ application. How can this be done?
Thanks
The speed at which a keypress becomes automatically recurring is controlled by Windows.
If you want to manipulate automatic recurrences of key-presses, it might be more advantageous to poll for the state of the key rather than waiting for the keydown event. It depends on how responsive you need your application to be.
This article may help you in figuring out how to query for key states: link
You can use the SystemParametersInfo function to change the keyboard delay and refresh rate, as described in this newsgroup thread.
A simple way to handle this is to establish a buffer of time around the OnKeyDown event. Setup a timer that determines whether control passes to a secondary event handler. If the timer has expired, then it is OK to pass control. If the timer hasn't expired, then you should return and leave the event unhandled. Start the timer right before passing control to your secondary event handler.
void KeyDownHandler(...)
{
// ...
if (TimeLeft() <= 0)
{
StartTimer();
handleKeyDown();
}
}
A timer is better than counting duplicate events because you can't assume that a given system will have the same repeat rate set as yours.
I agree with Stuart that polling for the state of the key might work better. It depends upon what you are trying to accomplish.
Also note that this type of behavior might be highly annoying to your user - why do you need to ignore duplicates?
You might be able to tap into a Windows API but this might be controlled by the OS. Not sure...
You might need to manually draw a command such as to simulate a key press multiple times after a set number of seconds after the key has been pressed.
Use SetKeySpeed api (Kernel)