Key hold does not work

Hello everyone. I am writing a doodle jump game now and I forced to use the framework written by someone other than me. it contains the event handlers I need to implement. Its event-checking loop looks like this:

enum class FRKey {
	RIGHT,
	LEFT,
	DOWN,
	UP,
	COUNT
};

enum class FRMouseButton {
	LEFT,
	MIDDLE,
	RIGHT,
	COUNT
};

bool GKeyState[(int)FRKey::COUNT] = {};

FRAMEWORK_API int run(Framework* framework)
{
    int done;
    SDL_Event event;

	for (int i = 0; i < (int)FRKey::COUNT; ++i)
	{
		GKeyState[i] = false;
	}

	Framework* GFramework = framework;

        /* some unrelated staff */

        done = 0;
        while ( ! done ) {
            while ( SDL_PollEvent(&event) ) {
                switch (event.type) {
                    case SDL_KEYUP:
                        switch (event.key.keysym.sym) {
                            case SDLK_RIGHT:
                            case SDLK_LEFT:
                            case SDLK_DOWN:
                            case SDLK_UP:
							{
								int key_index = (event.key.keysym.sym - SDLK_RIGHT);
								if (GKeyState[key_index])
								{
									GFramework->onKeyReleased((FRKey)key_index);
									GKeyState[key_index] = false;
								}
								break;
							}
                            case SDLK_ESCAPE:
								done = 1;
                            break;
	                        default:
		                        break;
                        }
                        break;
					case SDL_KEYDOWN:
						switch (event.key.keysym.sym) {
						case SDLK_RIGHT:
						case SDLK_LEFT:
						case SDLK_DOWN:
						case SDLK_UP:
						{
							int key_index = (event.key.keysym.sym - SDLK_RIGHT);
							if (!GKeyState[key_index])
							{
								GFramework->onKeyPressed((FRKey)key_index);
								GKeyState[key_index] = true;
							}
							//GFramework->onKeyPressed((FRKey)key_index);
						}
							break;

						default:
							break;
						}
						break;
  
                    case SDL_QUIT:
                        done = 1;
                        break;
                    default:
                        break;
                }
            }
        }
    }
    SDL_Quit();
    return(0);
}

And with this code, when I press a key, the event only happens once even with the key held down. And I need to move the doodle by pressing the left and right arrows. That’s the problem.
In general, this code looks as if it purposely prevents the possibility of responding to a key press. But what should I do then? Is there any way to solve the problem without changing the above code, just by changing the onKeyPressed() and onKeyReleased() methods?
Does anyone have any ideas what is wrong here?

You could use the GKeyState array to check if the key is down.
(When using SDL you would normally use the array returned by SDL_GetKeyboardState for this)

Another option is to manually set some flag to true inside onKeyPressed and to false inside onKeyReleased and then you can use it in other parts of your code to check if the key is down.

So instead of updating the position of the doodle whenever you receive an event you instead update it once each frame depending on the keys that are currently held down.

1 Like

You can use the event repeat field to determine if the key is freshly pressed or held for a longer period. Each entry in your lookup table should have two flags — the state of being down and the state of being repeated.

1 Like

Thank you!I’m a little dumb about something) In my situation, you could do something like this:

enum class Move { Left, Right, None } move;

void onKeyPressed(FRKey k)
{
    switch (k)
    {
        case FRKey::Left:
               move = Move::Left;
               break;
        case FRKey::Right:
               move = Move::Right;
               break;
    }
}

void onKeyReleased(FRKey k)
{
    move = Move::None;
}

And then check move flag in update() method.

You can do it like that but using a separate flag for each key/direction is probably better because then you can properly handle the situation when both the left and the right key are held down at the same time. In that situation you probably don’t want the doodle to move at all. It’s also possible that the player releases some other key than left or right and you might not want the movement to stop because of that.

I don’t use events to update logic myself, because passing them in parameters to various engine subsystems is simply inconvenient and vastly complicates the implementation. Instead, I have declared mouse, keyboard and gamepad objects, the state of which is updated based on SDL events.


Each object representing an input device has data about individual parameters/triggers in the form of state objects. A state object is a simple, generic structure containing data about the default, previous and current state and also accumulator (for multi-step update).

In the main loop, SDL events are processed and passed to the input device object update functions. When this process is finished, while updating the game logic, I can query the device object about the status of its parameters and triggers anywhere and at any time.

Because the state object has the previous and current state, based only on these two data, I can easily check whether a given trigger is freshly pressed, held, or e.g. freshly released. The state may be a logical value determining the use (e.g. being down), but also the coordinate (e.g. of the mouse cursor or analog stick), the magnitude (e.g. of the analog stick in a normalized form), etc.

Since the main loop performs a fixed number of iterations (currently: 60 ups), at the beginning of each frame (before event processing) I prepare objects for updating, then update their state based on events, and finally finalize the update. So in one second, the state of all parameters and triggers of all input devices (and all other data used by the engine) is determined 60 times (60 new states per second).

In the event that a given device parameter or trigger has not changed its value since the previous frame, state objects simply use the last state as the current state. In this case, the object contains data that indicates that the state has not changed since the previous frame (e.g. the key is still down).

If, within one frame, the SDL event queue may contain many events of a specific type, related to changing the state of an input device (e.g. changing the value of a gamepad axis), you cannot update the state object of this axis multiple times because the state from the previous frame will be overridden multiple times. For this purpose, the state object has an accumulator so that only the last value is remembered. Once the update is done, the accumulator value is set as the current value during object update finalization.


I know that this system may seem complicated and redundant, but it offers a lot of possibilities and is relatively simple to implement. If you are currently learning SDL and gamedev, you can handle input in any way. However, if you intend to work on something larger, I recommend that you first think about the architecture, determine the requirements and necessary features, and then create a decent, functional implementation of input handling.