1

I'm trying to develop a robust game input system with SDL 2.0.1. I want there to be no input lag at all.

I used to do this with SDL_GetKeyboardState(), but I switched over to using SDL_Event and SDL_PollEvent() to have a uniform interface for Keyboard, Mouse and Joystick input (everything done with events).

This works fine, but if I want a continuous input when the key is held down (e.g. to move a character), there is a slight delay before SDL notices that the key is being repeated.

In SDL 1.2, it was possible to set this delay using a function call. Now it is no longer (as far as I'm aware).

How can I remove this delay? Should I switch back to reading the Keyboard state directly?

For reference, here is how I'm currently getting input...

SDL_Event sdlEvent;
while (running)
{
    SDL_PollEvent(&sdlEvent);
    switch (sdlEvent.type)
    {
    case SDL_QUIT:
        running = false;
        break;
    case SDL_KEYDOWN:
        printf("Key down!\n");
        break;
    default:
        break;
    }
}

The application prints "Key down!", then nothing for a small time (about a second), and then repeatedly prints until the key is released.

So how do I get rid of this delay?

RaptorDotCpp
  • 1,425
  • 14
  • 26
  • Do you receive a `SDL_KEYUP` event for that key in the meantime? – olevegard Jan 23 '14 at 15:16
  • No. It's all `SDL_KEYDOWN` events until I release the key. Then it's a constant stream of `SDL_KEYUP` events (until I move the mouse or press another key, so I guess that `SDL_PollEvent(&sdlEvent)` doesn't change `sdlEvent` if there is no event - interesting). – RaptorDotCpp Jan 23 '14 at 15:51

3 Answers3

3

Since you're not getting an SDL_KEYUP you can just have a bool that's true until you get a SDL_KEYUP

SDL_Event sdlEvent;
while (running)
{
    bool keyDown = false;
    while ( SDL_PollEvent(&sdlEvent) )
    {
        switch (sdlEvent.type)
        {
            case SDL_QUIT:
                running = false;
                break;
            case SDL_KEYDOWN:
                keyDown = true;
                break;
            case SDL_KEUP:
                keyDown = false;
                break;
            default:
                break;
        }
    }
    if ( keyDown )
        printf("Key down!\n");
}

Of course you'll need something to store all keys, like an array. ( Or even better; use C++ with std::map) Then you can use the SDL_Keycode ( event.key.keysym.sym ) as key.

olevegard
  • 5,294
  • 1
  • 25
  • 29
  • This code will do the same error are the initial one, only the first event on the stack will be checked per frame. – jordsti Jan 23 '14 at 16:02
  • @jordsti Ahh... Of course, didn't see that it wasn't put in a loop – olevegard Jan 23 '14 at 16:04
  • You put me in the right direction. As I work with actions (as strings) and callbacks, I now keep a set of actions that should be fired. On keydown, I add the relevant action to the set. On keyup, I remove it. Works flawlessly. Thanks! – RaptorDotCpp Jan 23 '14 at 16:34
  • @RaptorDotCpp No problems. Good luck on your game! =) – olevegard Jan 23 '14 at 16:35
3

As is noted here, the correct procedure to make this work cross-platform is using SDL keystates instead of events:

const Uint8* keystates = SDL_GetKeyboardState(NULL);

if(keystates[SDL_SCANCODE_DOWN])
{
    printf("Key down!\n");    
}

In this way you bypass any OS-based keyboard delays. A full tutorial: http://lazyfoo.net/tutorials/SDL/18_key_states/index.php

metamorphosis
  • 1,972
  • 16
  • 25
2

First, you should Poll your event into a loop, else you will just get one event per frame so

SDL_Event sdlEvent;
while (running)
{
    while(SDL_PollEvent(&sdlEvent))
    {
        switch (sdlEvent.type)
        {
        case SDL_QUIT:
            running = false;
            break;
        case SDL_KEYDOWN:
            printf("Key down!\n");
            break;
        default:
            break;
        }
    }
}

And, to handle your Key Delay, should create a struct with the key pressed, and the timestamp when the key down was launch. You can put those struct into a vector and then remove them when key up is catched for this key. And to handle key delay just iterate your key down, and check the difference between the current timestamp and the key down inital timestamp.

jordsti
  • 746
  • 8
  • 12
  • What is the purpose of the timestamp? As long as you set the `bool` to `true` when the `SDL_KEYDOWN` is recieved and not set it to `false` until you recieve `SDL_KEYUP`, there should be no delay. – olevegard Jan 23 '14 at 16:10
  • this -> then nothing for a small time (about a second), and then repeatedly prints until the key is released. With a bool, it work too, but only for one key or action, if you want to do this behavior for many keys, that's the way to do it. – jordsti Jan 23 '14 at 16:13
  • Which will be resolved as long as the `bool` remains set to `true`. Unless I'm misinterpreting, he doesn't want a delay, thus there's no need for the timestamp. – olevegard Jan 23 '14 at 16:15
  • Yes you need a timestamp, if you want to repeat your action bind to your key at each second, you need to know when the last action tick was... – jordsti Jan 23 '14 at 16:17
  • His application does just that. It prints "Key Down" then nothing for a second, then it continuously prints "Key Down". As I understand, he wants it to print "Key Down" every frame. – olevegard Jan 23 '14 at 16:20
  • @olevegard yes, he want to test the feature, but I give it a solution to handle key delay in a game, in general. He wrotes this : "to have a uniform interface for Keyboard, Mouse and Joystick input (everything done with events)." So he will need to handle many keys. – jordsti Jan 23 '14 at 16:25