Skip to main content TerryFunggg Blog

SDL - Keyboard Listening

I was moving two rects with SDL. Player 1 on W/S, player 2 on up/down.

Up and down felt fine. But W and S felt like delay.

The loop was this:

c code snippet start

if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_s)
   // player 1 down
if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_w)
   // player 1 up
if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_DOWN)
   // player 2 down
if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_UP)
   // player 2 down

c code snippet end

SDL_KEYDOWN fires once when the key goes down. Then nothing, until the OS key-repeat timer starts, usually a few hundred milliseconds later.

That pause is the delay. Holding W does not mean “move every frame”. It means “one event, wait, then more events at the repeat rate”.

SDL already keep a snapshot of every key. SDL_GetKeyboardState returns a pointer to that array. Pump the queue, then index it with a scancode.

c code snippet start

const Uint8 *keys = SDL_GetKeyboardState(NULL);
SDL_StopTextInput();

while (running) {
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
        if (event.type == SDL_QUIT)
            running = 0;
    }

    if (keys[SDL_SCANCODE_W])
        pl1.y -= MOVEMENT_SPEED;
    if (keys[SDL_SCANCODE_S])
        pl1.y += MOVEMENT_SPEED;
    if (keys[SDL_SCANCODE_UP])
        pl2.y -= MOVEMENT_SPEED;
    if (keys[SDL_SCANCODE_DOWN])
        pl2.y += MOVEMENT_SPEED;

    SDL_FillRect(surface, NULL, 0);
    SDL_FillRect(surface, &pl1, 0xFFFFFF);
    SDL_FillRect(surface, &pl2, 0xFFFFFF);
    SDL_UpdateWindowSurface(window);
    SDL_Delay(16);
}

c code snippet end

SDL_SCANCODE_W is the position of the W key. It does not care what letter the layout would emit.

The slot is 1 while the finger is down and 0 on release, so a held key moves every frame. No repeat timer.

The pointer is stable. Call SDL_GetKeyboardState once. The bytes change when you pump events.