Reputation: 3663
I've started writing an SDL2 program. I want integer count
to go up one when the user presses the right arrow key, down one when user presses left.
#include <iostream>
#include <SDL2/SDL.h>
int main(){
SDL_Window *window= SDL_CreateWindow("test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
int count= 0;
bool isRunning= true;
SDL_Event ev;
while(isRunning){
if(SDL_PollEvent(&ev)){
if(ev.type == SDL_QUIT || ev.key.keysym.scancode == SDL_SCANCODE_ESCAPE)
return 0;
}
const Uint8 *keystate= SDL_GetKeyboardState(NULL);
if(keystate[SDL_SCANCODE_LEFT])
--count;
else if(keystate[SDL_SCANCODE_RIGHT])
++count;
std::cout << count << std::endl;
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
Here's a sample of what's printed when I start the program and briefly tap right -- all within a second or two:
0
0
0
0
0
0
0
0
0
0
0
1
2
3
4
4
4
4
4
When I do a quick tap on the right arrow key, I want count
to go up by just one, but instead it went from 0
to 4
.
Why?
How do I fix this problem?
Upvotes: 1
Views: 2798
Reputation: 262
Your problem is that you ask SDL for a keystate array, which, in your scenario, is not the best method. So, what does SDL do in this case? It simply gives you an array containing information, wheter the current key is being held or not. You try to press the button as short as you can, but your loop is really quick in time. So, to resolve this, you can use the event system's keydown feature, which gives you true, when you pressed down a button (its pair is the SDL_KEYUP
for key released event).
The main difference is in the question: is the key being held, or I just pressed down and changed its state?
So, here is an example (use within the SDL_PumpEvent or SDL_PollEvent):
//...
if (event.type == SDL_KEYDOWN)
{
if (event.key.keysym.sym == SDLK_LEFT)
//do left key things...;
else if (event.key.keysym.sym == SDLK_RIGHT)
//do right key stuff...;
}
//...
Note that this method doesn't use scancodes, but keycodes. (They can produce different result than scancodes, due to different types of keyboards). SDLK_
constants are all keycodes. Moreover (if you think about games), scancodes are good for player movement, keydown events are good for GUI elements
Reference for more information: https://www.libsdl.org/release/SDL-1.2.15/docs/html/guideinputkeyboard.html
I hope you understand! Lasoloz
Upvotes: 3
Reputation: 3663
I changed the while
loops to this:
while(isRunning){
while(SDL_PollEvent(&ev)){
if(ev.type == SDL_QUIT || ev.key.keysym.scancode == SDL_SCANCODE_ESCAPE)
return 0;
else if(ev.type == SDL_KEYDOWN){
if(ev.key.keysym.scancode == SDL_SCANCODE_LEFT){
--count;
std::cout << count << std::endl;
}
else if(ev.key.keysym.scancode == SDL_SCANCODE_RIGHT){
++count;
std::cout << count << std::endl;
}
}
}
}
If I understand it right, SDL_PollEvent
fires only while address of object ev
is true. If user presses a key down, it continues. If the key is left arrow, count
goes down one. If key is right arrow, count
increases one.
Now cout
prints the way I hoped it would.
Output after I press right a few times:
0
1
2
3
4
Then left:
4
3
2
1
0
Upvotes: 1
Reputation: 50550
Even though the example is far from being a minimal, complete one and it doesn't compile, I guess that the problem could be due to the lack of a call to SDL_PumpEvents
.
As from the documentation:
Note: Use SDL_PumpEvents() to update the state array.
Otherwise, the state array won't be updated, with the results you are experiencing.
NOTE
That said, try to rely on events instead of the internal state array used to represent the keyboard.
EDIT
Updated after the question has been updated.
You should replace the if
on SDL_PollEvent
with a while
, like the following one:
while (SDL_PollEvent(&event)) {
// here you have an event, you can use it
}
Otherwise, even if there are no events, it skips the if
and goes through the other statements.
That means that the state of the keyboard won't be updated after the first key press if there are no events, but still you iterate over it.
See here for further details about how SDL_PollEvent
works.
Upvotes: 1
Reputation: 4275
Similar to this Question (it actually asks about mouse buttons, but its the same for keyboards):
Instead of using keyboardState use the SDL events. SDL will trigger exactly one event per pressed button, while a fast while
-loop can trigger multiple times during a single key-press.
Upvotes: 1