Prevent GetAsyncKeyState function from detecting inputs after it is called? C++ - c++

I have a game which is turn based. During your turn, it prompts you for a move and will ask for one key press input. As soon as a key press is detected, the game continues and you are no longer prompted until your next turn.
I am having problems though with GetAsyncKeyState function though because it stores key presses even after it is called.
From the MSDN website:
Determines whether a key is up or down at the time the function is called, and whether the key was pressed after a previous call to GetAsyncKeyState.
The bolded area is what is causing problems for me, as the user can spam key inputs while it is not his/her turn, then when it becomes his/her turn, the game will prompt the user and instantly confirm an input that was pressed from beforehand.
My function for this is very similar to this:
unsigned int getUserInput(){
while (true) //Await a user's input
{
if (GetAsyncKeyState(0x31))
{
return 1; //User pressed 1 key
}
else if (GetAsyncKeyState(0x32))
{
return 2; //User pressed 2 key
}
else if (GetAsyncKeyState(0x33))
{
return 3; //User pressed 3 key
}
else if (GetAsyncKeyState(0x34))
{
return 4; //User pressed 4 key
}
else if (GetAsyncKeyState(0x35))
{
return 5; //User pressed 5 key
}
else if (GetAsyncKeyState(0x36))
{
return 6; //User pressed 6 key
}
}
}
Should I just not use Asnc Key State in this case? If so, what is a better alternative?

The value that GetAsyncKeyState returns is a bit field. You can isolate the bit you are looking for with bitwise operations. In your specific case (for detecting if the key is currently pressed), you are looking for the high bit. You can test it like this:
if (GetAsyncKeyState(0x31) & 0x8000)
{
return 1; //User pressed 1 key
}
However, if I am understanding your problem description correctly, I don't think this will fully solve it. It sounds like you want the user to have to press the key down while the function is running (rather than just being able to hold the key down). What you should do for that, is at the beginning of the function check if the key is pressed. If it is, wait for it to be released. Something like this:
bool key_is_pressed = true;
while (key_is_pressed) {
key_is_pressed = false;
// the key codes you are checking are consecutive,
// so we can just loop over them
for (int key = '1'; key <= '6'; ++key) {
if (GetAsyncKeyState(key) & 0x8000))
key_is_pressed = true;
}
}
Then continue to the part where you wait for a key to be pressed.
Note that the text you highlight, "and whether the key was pressed after a previous call to GetAsyncKeyState", could actually have been the solution to your problem. That information is stored in a different bit (the low bit), so you could isolate that and ensure that the key wasn't previously pressed. Unfortunately, MSDN clearly documents that this behavior should not be relied upon. So you should pretty much always ignore everything but the hi bit when using GetAsyncKeyState.

Related

Is there a way to detect when a key is pressed only once? (not held down)

I have been looking for ways to detect when a key has been pressed but only once, but the only things I can find are GetAsyncKeyState and GetKeyState. I am making a rhythm game for fun and I use a while(true) statement to get everything done. Is there anyway to detect when a key is pressed once? (I'm also using GLFW if that helps)
You could store the state of the previous key presses, if it was not pressed in the last frame and is now, that would mean that the key is held down.
Here's an example with the LMB:
bool previousMouseState = false;
if (GetKeyState(VK_LBUTTON) < 0) {
if (!prevMouseState) {
previousMouseState = true;
//Mouse clicked.
}
} else previousMouseState = false;

C++ Check if key is pressed, not held down

I have the following code:
for (int i = 0; i < 1;) {
if (GetKeyState(VK_SHIFT) & 0x8000)
{
cout << "op";
}
}
This prints out op if the Shift key is held down, actually it spams the output if you hold down the key.
This is what I want instead:
The program prints out something ONCE when you press/hold down a key instead of spamming it, and the only way to print it again is to let go of the key and press it again. No matter how long you hold down the key, the program will only execute the following code ONCE, unless you press it again.
How do I make my code do this?
You could simply set a bool to true when you've detected a "key down" event and then only set it back to false once you detect a "key up" event. That way you can know if the key was already down and only report that it was pressed if it was not already in that state.

Am I using the getch() function from the ncurses library incorrectly?

I am writing a Pacman game in c++ using the ncurses library, but I am not able to move the Pacman properly. I have used getch() to move it it up, down, left and right, but it only moves right and does not move anywhere else when I press any other key.
This is a code snippet for moving up. I have written similar code with some conditions altered accordingly for moving left, right and down.
int ch = getch();
if (ch == KEY_RIGHT)
{
int i,row,column;
//getting position of cursor by getyx function
for (i=column; i<=last_column; i+=2)
{
//time interval of 1 sec
mvprintw(row,b,"<"); //print < in given (b,row) coordinates
//time interval of 1 sec
mvprintw(row,(b+1),"O"); //print "O" next to "<"
int h = getch(); //to give the option for pressing another key
if (h != KEY_RIGHT) //break current loop if another key is pressed
{
break;
}
}
}
if (condition)
{
//code to move left
}
Am I using getch() wrong, or is there something else I have to do?
Many of the "special" keys on a keyboard -- Up, Down, Left, Right, Home, End, Function keys, etc. actually return two scan codes from the keyboard controller back to the CPU. The "standard" keys all return one. So if you want to check for special keys, you'll need to call getch() twice.
For example up arrow is first 224, then 72.
261 is consistent with KEY_RIGHT (octal 0405 in curses.h). That tells us at least that keypad was used to allow getch to read special keys.
The fragment shown doesn't give clues to how it was incorporated into the rest of the program. However, the use of getch in a loop is likely a source of confusion, since on exiting the loop the value is discarded. If you expect to do something different (from KEY_RIGHT), you could use ungetch to save the (otherwise discarded) value within the loop, e.g.,
if (h != KEY_RIGHT) //break current loop if another key is pressed
{
ungetch(h); //added
break;
}
Doing that will allow the next call to getch to return the key which exits the loop.

How I can prevent every key being sent to KeyboardUpFunc in GLUT?

I'm fairly new to OpenGL, and I am writing a simple game in 2D, for fun. However, I ran into an issue I am having a hard time wrapping my head around.
It seems that whenever my keyboardUpFunc is called, that not only the key that has actually come up sent to the function, but every single key currently being pressed as well.
I'm using a simple key buffer to manage the keys, keyUp marks the key as up and is only called in this function. keyDown is called in my keyboardFunc. isDown returns a boolean value of whether or not the key is pressed. Take this code for example:
#include <iostream>
...
void keyboardUp(unsigned char key, int x, int y)
{
keys.keyUp(key);
if (keys.isDown('s') == false)
{
std::cout << "It's resetting s as well!" << std::endl;
}
// reset acceleration here, for each key
if ( (key == 'w') || (key == 's') )
{
yStep = 0.1;
}
if ( (key == 'a') || (key == 'd') )
{
xStep = 0.1;
}
std::cout << key << " is now up." << std::endl;
}
If you run this code, if you for example, hold S and D, then release the D key, you will note that S has been marked as up too, since this is the only location keyUp is being called.
Assuming my keyBuffer code is working correctly (and it is, but let me know if you want me to post it...), is there any way to get around this? Where if you were holding a key, and then pressed another key, the application would go back to what you were doing when you were just holding the original key? Instead of marking both as up? Or is this not feasible with GLUT?
Not very clear what is going wrong.. But where/how exactly are you calling this function ?? Directly in the Main Game loop, or are you checking certain conditions in an 'update' function. I ask because you need to check for input every run of the infinite loop, and if you are using a boolean to determine if a key is down, you should essentially reset it after its corresponding action has been performed. Anyway, just my 2 cents.
I changed my implementation of the keyboard buffer, and what I was describing above now works. The difference is that before I was using a vector to pile on the keys that were being pressed, whereas now, I am using a fixed-size array of boolean values.
Apparently, a vector implementation of a key buffer won't work properly with GLUT.

GLUT key down and key up on CTRL key

I've found a lot of information about using GLUT to detect whether the Ctrl key is pressed using the GLUT_ACTIVE_CTRL macro. This macro only works, apparently, within a keyboard or mouse callback function. I need to know whether or not the Ctrl key is pressed at a point in my main loop, but GLUT_ACTIVE_CTRL doesn't seem to work in this context.
So, is there a way to detect key up and key down events on the Ctrl key (without any other keys being typed) in a platform independent GLUT-ish way?
EDIT: The keyboard callback is not fired (at least for a default setup) when the Ctrl key is pressed. This is the basic problem, that I can only test whether the Ctrl key is or isn't pressed when another key is pressed and thus fires the keyboard callback.
My setup is something like:
// ... in main function:
glutKeyboardFunc(keyboard);
//later in the code:
void keyboard(unsigned char key, int _x, int _y)
{
printf("keydown \n");
if (glutGetModifiers() == GLUT_ACTIVE_CTRL) {
printf("control key is pressed.\n");
}
//etc.
When I press any normal character "keydown " is printed to stdout. When I press the Ctrl key, nothing happens. If I press Ctrl+C, "keydown control key is pressed." is printed.
However, in my main loop I added:
if (glutGetModifiers() == GLUT_ACTIVE_CTRL) {
printf("Control key down.\n");
} else {
printf("Control key up.\n");
}
and it always prints "Control key up." regardless of whether I am pressing the Ctrl key or not.
Not using GLUT as specced. You may wish to check out GLFW.
I use a makeshift in my GLUT application that does the trick. The problem with GLUT is that it realizes only Ctrl or Shift or Alt pressed together with another key. However, the workaround simulates a continuously pressed key running in the background that GLUT can then pick up with a modifier key.
You can implement this idea by usingSendInput from the windows.h library.
UINT WINAPI SendInput(_In_ UINT nInputs, _In_ LPINPUT pInputs, _In_ int cbSize);
simulates a hardware keystroke. This works together with the glutGetModifiers() callback. You can run the simulated key stroke in the background of your loop, e.g. within your idlefunc and you need to chose a key that is not in regular use in your program.
To see how it works, have first the standard callback within your GLUT code to recognize the Ctrl key through glutGetModifiers().
bool CTRLpress=0;
int checkModifiers(void)
{
int mod_key = glutGetModifiers();
if (mod_key!= 0)
{
if (mod_key == GLUT_ACTIVE_CTRL)
{
CTRLpress=1;
}
return 1;
}
else if (CTRLpress)
{
CTRLpress=0;
return 1;
}
return 0;
}
Declare and define the variable bool CTRLpress globally or in your own keyboard class as an indicator for the CTRL key being pressed (1) or released (0). Then make sure that the function checkModifiers() is being called from within your glutKeyboardFunc as usual.
Now initiate an INPUT object within your main code:
#define WINVER 0x0500 // Note: This needs to be put in here as SendInput is compatible from Windows 2000 onwards
#include <windows.h>
INPUT permkey; //optionally you could also use a pointer to INPUT with *premkey here
int main (int argc, char **argv)
{
permkey.type = INPUT_KEYBOARD;
permkey.ki.wVk = 0x42; // keystroke 'b' but check out all ASCII codes
permkey.ki.time = 0;
permkey.ki.dwFlags = 0;
//your code here
}
Finally, put within your glutIdleFunc a regular call that simulates a continuous pressing of a key stroke:
void idle()
{
SendInput(1, &permkey, sizeof(INPUT));
// your other code here
}
When pressing Ctrl alone without any other pressed key, the code triggers CTRLpressed to be 1. Alternatively, when released CTRLpressed becomes (You might want to further extended your own modifier-class to overcome other GLUT shortcomings - like difficulties in detecting Ctrl +Number.)
This works with me well and I haven't come across any other drawbacks other than having to sacrifice a key.
In the event handler record the setting of the key. You can then expose that storage to be read from your main loop.