Polling events vs get keyboardstate

Hello!

I’m making a small game. The structure is along the lines of a main.cpp, then there’s a ship.cpp which receives a renderer to render and some object to update itself and its location before rendering,

The process I’m thinking of so far goes

Init sdl, window, renderer,
Enter game loop:
  update gamestate  << this is where the decision is. <<
  do computation based on game state (collisions, etc)
  render gamestate + computation to screen 
  redo loop.

(Some code to help imagine the situation.)

// Ship.hpp
class Ship {
private:
  SDL_Rect currLocation;
public:
  int render(SDL_Renderer* renderer); //render yourself, ship.
  int update(GameState* gamestate); //update yourself ship, based on what the gamestate is
}

My question is, for my GameState, object, should I have it use SDL_PollEvent and then populate a map of the relevant keys events to track? or should I use SDL_GetKeyboardState and use that to track the relevant keys?

// GameState.hpp
// option 1
class GameState {
private:
  int** keyboardState; //populated by being a pointer to SDL's maintained keyboard [SDL_getKeyboardState]
public:
  int updateGameState(); //pumpevents or whatever.
  int getKeyboardState(); //return keyboard state
}
// option 2
class GameState {
private:
  std::map<SDL_Scancode, bool>; //populate to be true when a key is pressed and false when a key is released
public:
  int updateGameState(); // poll events.
  int getKeyboardState(); //return keyboard state
}
/

Are there any benefits or drawbacks, comparing one to the other?

Usually that comes down to how you want the game’s UI to work. Do you want the ship to move in response to a key being pressed (e.g. like a typing keyboard), or do you want the ship to move in the direction currently being held down (e.g. like a joystick)? The former is easier to do by tracking events, and the latter is easier to do by periodically checking key states.

1 Like

Keep in mind that you need to poll events anyway, because there are other events besides just input.

Also, polling events won’t miss multiple events that all happen in the same frame, whereas just checking the keyboard state once per frame can. Super annoying when a game misses input because the framerate dropped and the player wasn’t presseing a key right at the exact time when it checked the keyboard state.

1 Like

You can use SDL_GetKeyboardState() if you want to do something for as long as a key is pressed. E.g. rotate while the player press the “left” button, or deaccelerate while the player press the “brake” button.

Key events (from SDL_PollEvent()) are useful if you want to react to some action when a key is pressed. E.g. fire a bullet, pick up an item, etc.

Sometimes you can have a combination of these two. E.g. you might want to play a sound effect and always jump a little when the player press the “jump” button, but you might also want to keep pushing the player upwards to increase the height of the jump for as long as the “jump” key is being pressed (or until the player lands on the ground).

Check what works better …
I have the following procedure at BasicC:

void GetSDLEvents() {
  Uint32 windowID = SDL_GetWindowID(SDLWindow);
  WindowEvent=0;
  InKey=0;
  while (SDL_PollEvent(&SDLEvent)) {
    switch (SDLEvent.type) {
      case SDL_WINDOWEVENT:
        if (SDLEvent.window.windowID == windowID) WindowEvent=SDLEvent.window.event;
      break;
      case SDL_QUIT:
        Quit=SDL_TRUE;
      break;
      case SDL_KEYDOWN:
        InKey=SDLEvent.key.keysym.sym;
        break;
      case SDL_TEXTINPUT:
        strncat(STRING$,SDLEvent.text.text,STRLEN-strlen(STRING$));
      break;
  } }
  SDLKeyboardState = SDL_GetKeyboardState(NULL);
  MouseK = SDL_GetMouseState(&MouseX, &MouseY);
}

It triggers it in a loop, it handles the most important things. We usually use InKey for menus, to move objects: SDLKeyboardState

@ROSY In other words, InKey keeps track of the last pressed key since you called GetSDLEvents() the previous time.

I had a quick look at your “BasicC” code and if I understand correctly the following code would check if D is the last pressed key (since the previous time you called GetSDLEvents()):

GetSDLEvents();
if (InKey == SDLK_d)

Note that this can “miss” key presses if you press multiple keys at (almost) the same time.

And the following code (which uses a function-like macro named “InKey” and is not the same as the InKey variable) would check if D is “currently” pressed down:

if (InKey(SDL_GetScancodeFromKey(SDLK_d)))

It expands to:

if (SDLKeyboardState[SDL_GetScancodeFromKey(SDLK_d)])

Note that this can “miss” key presses that are released very quickly.

I find it an “interesting” design decision to use the name “InKey” for both of these different usages (and perhaps also a bit inconsistent that one of them uses keycodes while the other uses scancodes). I have to admit that I have no experience with BASIC so I don’t really know what your goal is.

You understand well, but it’s not like that;) If the game works in 60 frames, I don’t see the possibility of anything getting lost, I never had a problem with it. Using the first option to control a player is, in my opinion, a bad idea. Even if something is lost between the frames, it doesn’t matter.
There are differences between the two options that are not mentioned in the SDL documentation. Below is a translation from the BasicC instruction:
InKey (K)
Returns 1 if the SDL_Scancode K key is pressed, 0 if not.
There are several differences between the InKey (K) function and the InKey variable. The function is based on SDL_Scancode, which are physical key codes independent of the system. The variable contains system dependent SDL_Keycode, the system usually causes delays in entering characters from the keyboard as well. The variable contains the code of only 1 key, the function reads the state of the SDLKeyboardState table containing information about all the keys, instead of InKey (K) you can use SDLKeyboardState [K]. However, usually the amount of correct information about pressed keys simultaneously is limited to a few, possibly due to hardware reasons.
Overall, the InKey variable is better suited for menus or text input, and the function is better for controlling moving objects, such as in games.

There is a possibility. A higher fps just means the chance is lower.

I think whether it matters or not depends on what kind of action it is. If the key fires a bullet or picks up an item I would say it’s pretty bad if that does not happen. It gives a bad user experience. That’s why you normally handle these kind of actions from within the SDL_PollEvent loop itself, because you want to handle all events.

Note that you have the same problem with WindowEvent. If you get two window events you probably want to handle both of them. No this is not unrealistic. If I for example minimize a window I get SDL_WINDOWEVENT_FOCUS_LOST, SDL_WINDOWEVENT_HIDDEN and SDL_WINDOWEVENT_MINIMIZED all at once.

As for the windows - thanks, this is not in the documentation …

If you’re able to hang a key for less than 17 ms, good luck … I still say it’s physically impossible. I was unable to hit a key so that it would appear in the queue rather than appear in KeyboardState.

If, when editing the text, you press 2 keys at a time and only 1 letter appears - I can safely consider it as a correct operation.

Did you do an arcade game where the player is handled by PollEvent? I want to see it … It works with a delay! If you are on the run and want to take an item, it may be out of reach and the item will not be picked up before it takes effect.

If you’re able to hang a key for less than 17 ms, good luck …

I don’t know how much I trust the timers but it seem like I can come close. If the game misses one VSYNC, or just slows down a little for other reasons, then we’re not talking about 17 ms any more.

Did you do an arcade game where the player is handled by PollEvent?

I do have an unfinished game where I use SDL_PollEvent for the player’s movement. There it doesn’t matter how long you press the key. Pressing it just toggles between move and not move (a bit simplified). If you have played old Sierra adventure games you know what I’m talking about.

… It works with a delay!

No it doesn’t. Not more than SDL_GetKeyboardState.

The only reason I can think of why you would say that is if you only handle one event per frame. I’ve seen some people do that mistake. Instead of calling SDL_PollEvent in a loop they use an if statement (or just call it without even checking the return value).

If you are on the run and want to take an item, it may be out of reach and the item will not be picked up before it takes effect.

If you want it to be possible to just hold down the key to pick up any item you come close to while walking around then by all means use the keyboard state (or a combination to rule out “missed” key presses as discussed earlier although that might be overkill).

But if all you want is to pick up the closest item that is within reach when the key is pressed down, and to pick up two items you need to press twice, then I think using events is the more natural approach.

I misspelled it … The point was that if you hold down a key, the events will be interrupted, so not every frame will tell you that a key is pressed.

It’s only good advice, do what you want … :slight_smile:

I improved the window handling, but in Windows, when minimizing, it does not report SDL_WINDOWEVENT_HIDDEN only SDL_WINDOWEVENT_FOCUS_LOST

That isn’t how it works. When using SDL_PollEvent() you get an event once when the key is pressed and once when it’s released; it’s up to you to set/clear a flag when a key you care about gets pressed/released. Nothing gets interrupted by holding down a key.

If you say so :thinking:

I don’t know what spacetime you are in. It doesn’t work that way for me. As I hold the key, from time to time I receive the events of subsequent presses. I did not check the release events.

OK, there is only one KEYUP so you can get it over with, but it’s extra work …

With SDL_KEYDOWN you can get repeated events (event.key.repeat != 0) but that is mostly a convenience feature to make it easy to implement the behaviour you expect in many GUI applications. For example when typing a letter, moving the text cursor or jumping between selected menu items you can often hold down the key to repeat the action. It only happens for the last pressed key and the delay between the initial event and the first repeated event is longer than between the repeated events (x.........x..x..x..x..x..) so it’s normally not suitable for movements in games but that is not really what it’s designed for either.

Note that for other “press” events such as SDL_MOUSEBUTTONDOWN, SDL_JOYBUTTONDOWN and SDL_CONTROLLERBUTTONDOWN there are no repeated events.

Yeah, I forgot about the key repeat. Still, it doesn’t “interrupt” other events.