How to check if a key sequence is press? - c++

I would like to check if a key sequence is press. Like a password, i would like that to see the message box you must type "bcqwl" in right sequenze. I tried
#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
while(true)
{
if(GetKeyState('B') & 0x8000)
{
cout<<"b has been press"<<endl;
if(GetKeyState('C') & 0x8000)
{
cout<<"c has been press"<<endl;
if(GetKeyState('Q') & 0x8000)
{
cout<<"Q has been press"<<endl;
if(GetKeyState('W') & 0x8000)
{
cout<<"W has been press"<<endl;
if(GetKeyState('L') & 0x8000)
{
MessageBox(NULL,"YES","YES",MB_OK);
}
else
{
continue;
}
}
else
{
continue;
}
}
else
{
continue;
}
}
else
{
continue;
}
}
else
{
continue;
}
}
}
But it doesn't works. He print "B has been press" ,many times but not infinitely times,if b is pressed. If after to press b I press c nothing happens.
So i tired:
step:
if(GetKeyState('B') & 0x8000)
{
cout<<"B has been press"<<endl;
goto step1;
}
else
{
goto step;
}
step1:
if(GetKeyState('C') & 0x8000)
{
MessageBox(NULL,"WORK","yes",MB_OK);
}
else
{
goto step;
}
But doesn't work.
I also tired:
#include <iostream>
#include <windows.h>
int main()
{
int progress = 0;
while(progress<=4)
{
if(GetKeyState('B') & 0x8000)
{
std::cout<<"b has been press"<<std::endl;
progress=1;
}
else
{
progress=0;
}
if(progress==1)
{
if(GetKeyState('C') & 0x8000)
{
std::cout<<"c has been press"<<std::endl;
progress=2;
}
else
{
progress=0;
}
}
if(progress==2)
{
if(GetKeyState('Q') & 0x8000)
{
std::cout<<"q has been press"<<std::endl;
progress=3;
}
else
{
progress=0;
}
}
if(progress==3)
{
if(GetKeyState('W') & 0x8000)
{
std::cout<<"w has been press"<<std::endl;
progress=4;
}
else
{
progress=0;
}
}
if(progress==4)
{
if(GetKeyState('L') & 0x8000)
{
std::cout<<"l has been press"<<std::endl;
progress=5;
}
else
{
progress=0;
}
}
}
return 0;
}
But that output "b has been press" for many times but not infinitely if i press b, and after if i press c nothing is happening, praticaly after press b and the program go in if(process==1) but if i press c nothing happen
P.S. sorry for my bad english.

The problem you are still having comes from the fact that you are in no way storing the progress in your key sequence.
Let's say your password is stored in a char array (for easier access to the single characters later on):
#define PWD_LEN 6 // bcqwl has a length of 5 characters but you need +1 for the '\0' (terminating character) at the end of your string
// ...
char password[PWD_LEN] = "bcqwl";
In addition you will need a counter:
#define PWD_LEN 5
// ...
char password[PWD_LEN] = "bcqwl";
int progress = 0;
while(true) { ... }
Both need to be stored before and outside the while loop because both store data that you don't want to reset in each iteration step in your loop.
The counter will be used to track the progress of the user towards completing the key sequence your password represents.
Whenever the user presses a key you will need to do the following checks:
Is the key allowed? - if you have a password abc but the user presses y or !, or something other then a, b or c the key is not allowed.
If the key is allowed take the character it represents and check if it's the same as the character in your password at index progress:
if ( key allowed )
{
if (password[progress] == '<your key character here>')
{
++progress;
}
else
{
// Handle incorrect key stroke relative to key sequence
}
}
Now in order to prevent the counter going bananas I would suggest doing all the checking upon key released, which unlike key pressed is a one time event. A key being pressed can also be part of key hold, in which case you will land in the else (from the code snippet above) many times, which might not be such a good idea.
If the key is ok and in terms of sequence it fits your password then you increase the progress so that in the next iteration step you can do the same check with a new released key event and a new index value for accessing your password array.
When your progress reaches the required value indicating that the key sequence is completed and that all the characters your password consists of have been "inserted" you can break the loop.
This is very basic so I hope that the instructions are clear enough for you to implement.
PREVIOUS ANSWER (now obsolete due to change in the question)
Unless other out-of-the-box way is available to do that (I haven't used GetKeyState() or anything else from windows.h) the general practice is to simply store the pressed state of each button (in an array, a struct etc.).
In your loop you can use a simple chain of if statements (but not nested like you do it!) to check which button is pressed during the current iteration step. Whenever a known key (one that you application wants to process) is pressed, you just need to toggle the respective state of that button in your array, struct or whatever other container you use to store this information:
while(true)
{
// Check state of supported buttons
if(GetKeyState('A') & 0x8000)
{
// store change of state of key A
}
if(GetKeyState('B') & 0x8000)
{
// store change of state of key B
}
if (...)
{
// ...
}
}
At the end or beginning of your while's body you can then ask for the state of each button and also make combined queries:
while(true)
{
// Check state of supported buttons
if(GetKeyState('A') & 0x8000)
{
// store change of state of key A
}
if(GetKeyState('B') & 0x8000)
{
// store change of state of key B
}
if (...)
{
// ...
}
// Do something
// Check for states of buttons
// ...
}
For example let's say you are using the following structure to store the key's state:
typedef struct Key
{
char keyCode;
bool pressed;
} Key;
Key keyA;
keyA.pressed = false;
you can simply do
if (keyA.pressed)
{
// Trigger some change that key 'A' controls
}
to check if your specific button is currently pressed and respectively trigger some action.
For key combinations things are not much different. You just need to use simply boolean logic to handle it:
if (keyA.pressed && keyB.pressed)
{
// Both key 'A' and 'B' are pressed - we have a key combo!
}
You can improve the readability of your code by storing all supported buttons in an array and even adding a nice enum to provide easy access to each button:
enum KeyCode
{
A,
B,
...
};
Key keys[n]; //with n being the number of keys you want to support and also the number of elements your enum has
// Access with an improved readability
if (keys[A].pressed && keys[B].pressed)
{
// ...
}
If you can't find any code for GetKeyState() in particular (highly unlikely) you can look at SDL for example.

Related

How do I assign a value in an array when a mouse is pressed SFML C++

I am trying to make a program where you are allowed to select between an option of shapes, and then drawing it. To allow for multiple shapes I created a vector of a class which creates shapes (Shapes are set up with the chosen function). My problem is the mouse click is too long, so it assigns it to everything in the vector, so you can't create a new shape. Is there a problem in my logic, or is there a problem in the code?
Here is my attempt:
for (auto& it : onCanvas) {
if (Mouse::isButtonPressed(Mouse::Left)) {
if (mousepointer.getGlobalBounds().intersects(circleOption.getGlobalBounds())) {
it.chosen(circles);
}
if (mousepointer.getGlobalBounds().intersects(rectOption.getGlobalBounds())) {
it.chosen(rectangle);
}
if (mousepointer.getGlobalBounds().intersects(triOption.getGlobalBounds())) {
it.chosen(triangles);
}
if (mousepointer.getGlobalBounds().intersects(it.shape.getGlobalBounds()) || it.dragging) {
it.shape.setPosition(mousepointer.getPosition());
it.dragging = true;
}
}
if (!Mouse::isButtonPressed) {
it.dragging = false;
}
win.draw(it.shape);
}
Your source-code is a bit incomplete (what is onCanvas and mousepointer). But I guess the problem is that this snippet is called multiple times while your mouse is clicked. To avoid that you can do two thing.
In the first solution you use events, so you only add shapes when the state of the mousebutton changes (you can additionally listen to the MouseButtonReleased to simulate a full click):
if (event.type == sf::Event::MouseButtonPressed)
{
if (event.mouseButton.button == sf::Mouse::Left)
{
// Hit Detection
}
}
or second solution you remember the last state of the button (probably do the mouse check once outside of the for loop):
bool mouse_was_up = true;
if (mouse_was_up && Mouse::isButtonPressed(Mouse::Left)) {
mouse_was_up = false;
for (auto& it : onCanvas) {
// Hit Detection
}
}
else if (!Mouse::isButtonPressed(Mouse::Left))
mouse_was_up = true;
I would rather stick to the first solution because when your click is too short and your gameloop is in another part of the game logic, you can miss the click.

SDL_KEYDOWN triggering twice

I am following lazy foo's tutorial, however I realized every time I press press s or p, SDL_KEYDOWNtriggers twice. How can this be fixed?
Here is the code snippet:
while(SDL_PollEvent(&e) != 0) {
if(e.type == SDL_QUIT) {
quit = true;
}
else if(e.type == SDL_KEYDOWN) {
if(e.key.keysym.sym == SDLK_s) {
if(timer.isStarted()) {
timer.stop();
printf("stop\n");
}
else {
timer.start();
printf("start\n");
}
}
else if(e.key.keysym.sym == SDLK_p) {
if(timer.isPaused()) {
timer.unpause();
printf("unpause\n");
}
else {
timer.pause();
printf("pause\n");
}
}
}
}
Pressing s once:
start
stop
TL;DR: Check if e.key.repeat equals to 0 before handling the events.
SDL generates fake repeated keypresses if you hold a key long enough. This is used mostly for text input.
The original key press has .repeat == 0, and fake presses have .repeat == 1.
For convenience reasons probably (I'd argue that it's rather inconvenient), since SDL 2.0.5 the actual key press generates two events instead of one. One has .repeat set to 0, and other (new) one has it set to 1.

NCURSES keyboard input while calling sleep

I'm trying to use ncurses to create a game. I set it so that the character moves by arrow key input, but if I hold the arrow key for a while and then let go the character will keep moving for a while before stopping.
These are my initializations:
initscr();
start_color();
cbreak();
noecho();
nodelay(stdscr,TRUE);
keypad(stdscr, TRUE);
This is my main loop:
while(1) {
...
if (key == (char)27) {
break;
}
else if (key == KEY_DOWN) {
key = 0;
player->advance(0, 1);
}
else if (key == KEY_UP) {
key = 0;
player->advance(0, -1);
}
else if (key == KEY_LEFT) {
key = 0;
player->advance(-1, 0);
}
else if (key == KEY_RIGHT) {
key = 0;
player->advance(1, 0);
}
else {
key = getch();
}
std::this_thread::sleep_for(std::chrono::milliseconds {1000/30});
}
I'm using the sleep_for because I noticed that if I use timeout then the framrate changes if I'm pressing a key. Using sleep_for creates a consistent framerate, but input is somehow "sticky" as I explained. I need to fix this somehow. Either get a consistent framrate using timeout, or "un-stick" the input when using sleep_for.
player->advance(int, int) moves the player one step in the specified direction. Direction is specified as change in x and change in y to be applied to the current position.
You could call flushinp after each call on getch, to ignore type-ahead.

Better implantation of key pressed down

I am currently executing a GetAsyncKeyState event handler when the 'c' key is pressed down in C++.
Here is my code:
bool isKeyPressed = false;
void someFuntionOne()
{
if( GetAsyncKeyState( 'C' ) & 0x8000)
{
if(isKeyPressed)
{
isKeyPressed = false;
}
else
{
isKeyPressed = true;
}
}
}
void someFunctionTwo()
{
if(isKeyPressed)
{
// Do something
}
}
So bassically I want to know if the 'C' has been pressed not held down so I use my boolean variable isKeyPressed to tell me if the key was pushed down at any point. If it was pressed, set isKeyPressed to true and if it was pressed again set isKeyPressed to false.
The problem I have with this is I am running a huge OpenGL/C++ program that takes a lot of time to go around and execute the entire program in a single iteration so if the user presses down on the 'C' key, the program may not catch that event in time because it is still executing the rest of the other code and is currently not at the section of the code where it checks if GetAsyncKeyState( 'C' ) & 0x8000.
Is there a better way I can check for this event where the program is always listening for the event to happen at any point of execution time? How can I implement this?
Usually whoever delivers the events to your application will queue them until the application has the chance to process them, i.e. at the end of each main loop iteration. So ideally you would react to the events at that stage. An (ugly) alternative is something like:
bool keyWasPressed = false;
void processKeyEvent() {
if( <C is pressed>) {
keyWasPressed = true;
}
}
void someFunction() {
if(keyWasPressed) {
keyWayPressed = false;
// Do something
}
}

C++: GetKeyState() has to run once

I need to listen keyboard key states for my tiny application.
#include <windows.h>
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
while(1)
{
if(GetKeyState(VK_SPACE) & 0x80)
{
cout << "Space pressed.\r\n";
DoSpaceKeyTask();
}
if(GetKeyState(OTHER_KEY) & 0x80)
{
cout << "Other key pressed.\r\n";
DoOtherKeyTask();
}
}
return 0;
}
Once I click some keys from my keyboard, these functions has to run once. They're just some tiny tasks for my applications, which is not related in this topic.
My problem is, when I press a key, it executes the functions few times, due to while(1) looping few times during key press. I cannot use Sleep() in this case, because it still won't be effective.
I'm looking for a solution like this.
I press SPACE key.
DoSpaceKeyTask() executes "once."
I press OTHER key.
DoOtherKeyTask() executes "once."
I have like 5 keys that I will be using. Could anyone help me on this case?
Ps. If GetKeyState() function isn't useful on this task, feel free to suggest yours. My function knowledge is pretty limited on C++.
Your functions are called multiple times because of the duration time the button stays pressed. The system is very sensitive. So this is a workaround.
You could do something like this (set a flag that will assign a value when the key is down, and then reasign it when the key is up).
int k=0;//Flag
while(1){
//check if the key was pressed (key_down)
if((GetAsyncKeyState('0') & 0x8000) && (k == 0)){k=1; cout<<"'0' PRESSED."<<k<<endl;}//do your stuff here
//check if the key was released (key up)
else if(GetAsyncKeyState('0') == 0) k = 0;//reset the flag
}
I think that you will prefer to execute your functions "once" only when you have released up your keys, not when you have depressed (pressed) them down.
You don't need any additional flags and helper variables to define, allocate, assign to 0, and set each one to 1 and reset to 0 and so on, in order to achieve this goal. All what you need is just: First you have to use GetKeyState function inside the scope of while(1) to check when you have depressed a key. When the expression returns true, the executor pointer (the arrow that carry out a code line and then proceeds forward to the next code line when you either step into or step over) will enter into the if statement's scope. Then immediately trap it inside a loop and keep it trapped in there while the key you have depressed is still down and stop it before it is going to execute the function and free it when you have released that key up and then let it to execute the function.
For example, to execute the DoSpaceKeyTask function only "once" when you have depressed and released the space bar, then do the following code that should work:
while (1)
{
if (GetKeyState(VK_SPACE) & 0x80)
{
//The code here executes ONCE at the moment the space bar was pressed
cout << "Space pressed.\r\n";
while (GetKeyState(VK_SPACE) & 0x80) //You can write there ';' instead '{' and '}' below
{
//The executor pointer is trapped here while space bar is depressed and it will be free once space bar is released
}
//The code here executes ONCE at the moment the space bar was released
cout << "Space released.\r\n";
DoSpaceKeyTask();
}
}
Just the same with DoOtherKeyTask function:
while (1)
{
if (GetKeyState(OTHER_KEY) & 0x80)
{
//The code here executes ONCE at the moment the other key was pressed
cout << "Other key pressed.\r\n";
while (GetKeyState(OTHER_KEY) & 0x80) //You can write there ';' instead '{' and '}' below
{
//The executor pointer is trapped here while other key is depressed and it will be free once other key is released
}
//The code here executes ONCE at the moment the other key was released
cout << "Other key released.\r\n";
DoOtherKeyTask();
}
}
If you have already used either BT_'s idea or Pawel Zubrycki's idea, and now you want to use my idea, then you can delete all flags and variables that they suggested, because you don't need them anymore.
By the way, I have already tried the code that Pawel Zubrycki posted, but it doesn't work for me. The output that says that I have pressed either space bar or other key was not displayed when I have really pressed the space bar or other key that I chose.
Try this approach:
#include <windows.h>
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
char lastSpaceState = 0, lastOtherKeyState = 0, spaceState, otherKeyState;
while(1)
{
spaceState = (GetKeyState(VK_SPACE & 0x80) != 0);
lastSpaceState = (spaceState && !lastSpaceState);
if(lastSpaceState)
{
cout << "Space pressed.\r\n";
DoSpaceKeyTask();
}
otherKeyState = (GetKeyState(OTHER_KEY) & 0x80 != 0);
lastOtherKeyState = (otherKeyState && !lastOtherKeyState);
if(lastOtherKeyState)
{
cout << "Other key pressed.\r\n";
DoOtherKeyTask();
}
}
return 0;
}
or as Chris suggest in OP comment more "modern" async approach.
You want a windows hook to hook the game and react to the keyboard input that game gets. Now I haven't really done this specific type of hook, but I can give you a good idea of the flow. I'll leave it up to you to cut down the space by looping through a map of keys you need rather than a huge, repetitive switch, and also to work out any small kinks I put in.
int main()
{
//I imagine the last argument here is the thread
//containing the game's message loop
HHOOK hook = SetWindowsHookEx (WH_CALLWNDPROC, hookProc, NULL, NULL);
//main loop
UnhookWindowsHookEx (hook);
}
LRESULT CALLBACK hookProc (int code, WPARAM wParam, LPARAM lParam)
{
if (code == HC_ACTION)
{
CWPSTRUCT details = *((LPCWPSTRUCT)lParam);
if (details.message == WM_KEYDOWN)
{
switch (details.wParam)
{
case KEY_ONE:
if (last [KEY_ONE] == UP)
{
DoKeyOneStuff();
last [KEY_ONE] = DOWN;
}
break;
}
}
else if (details.message == WM_KEYUP)
{
switch (details.wParam)
{
case KEY_ONE:
last [KEY_ONE] = UP;
break;
}
}
}
return CallNextHookEx (NULL, code, wParam, lParam);
}
Note how I use last [KEY_ONE]. I would recommend using an std::map to store keys you need by their vk code. Then you can just loop through the map and cut down a lot of space that a switch would take.
I was having the same issue. I have several keys that act like toggle buttons and only want to register the key events once per press. My solution was to make a simple object to handle the logic. This keeps the main code clean:
class KeyToggle {
public:
KeyToggle(int key):mKey(key),mActive(false){}
operator bool() {
if(GetAsyncKeyState(mKey)){
if (!mActive){
mActive = true;
return true;
}
}
else
mActive = false;
return false;
}
private:
int mKey;
bool mActive;
};
And here is the usage:
#include <windows.h>
KeyToggle toggleT(0x54); // T key toggle
KeyToggle toggleF(0x46); // F key toggle
void main(void)
{
while(true){
if(toggleT) {;} // do something
if(toggleF) {;} // do something
}
}
I know that this is pretty old thread but I still want to share my solution. I think that creating some kind of "flags" or "switches" is really not needed. Here is my code of looping all keycodes:
while (true)
{
for (int i = 0x01; i < 0xFE; i++)
{
if (GetKeyState(i) & 0x8000)
{
std::cout << (char)i << "\n";
while (GetKeyState(i) & 0x8000) {}
}
}
}
As you can see, you can easily just use while and the same GetKeyState function to wait for the key unpress. Much simpler solution.
Try sth. like this;
while (!GetKeyState(VK_SPACE) && !GetKeyState('A') == 1) {
//std::cout << "Key not pressed... \n";
Sleep(40);
}
if (GetKeyState('A')) {
std::cout << "\"A \" key pressed... \n";
}
else if (GetKeyState(VK_SPACE)) {
std::cout << "Space key pressed... \n";
}