# How can I process continuously-held keys with SDL?

I have created a cube in opengl using SDL. Now I am trying to move the camera in X direction if user presses left or right arrow keys and Y direction if user presses up or down arrow keys. Right now the camera moves by a fixed amount in a particular direction if the key gets pressed once. It doesn't matter how long does a person hold the key down, it moves by that fixed amount only. I want the camera to move continuously as long as the key is pressed.

Below is the code for keyboard polling.

        while ( SDL_PollEvent( &event ) )
{
switch( event.type )
{
case SDL_ACTIVEEVENT:
if ( event.active.gain == 0 )
isActive = FALSE;
else
isActive = TRUE;
break;
case SDL_VIDEORESIZE:
surface = SDL_SetVideoMode( event.resize.w,
event.resize.h,
16, videoFlags );
if ( !surface )
{
fprintf( stderr, "Could not get a surface after resize: %s\n", SDL_GetError( ) );
Quit( 1 );
}
resizeWindow( event.resize.w, event.resize.h );
break;
case SDL_KEYDOWN:
handleKeyPress( &event.key.keysym );
break;
case SDL_QUIT:
done = TRUE;
break;
default:
break;
}
}


And below i have mentioned the keypress handler function

void handleKeyPress( SDL_keysym *keysym )
{
switch( (keysym->sym) ){
case SDLK_ESCAPE:
Quit(0);
break;
case SDLK_LEFT:
eye[0] -= 0.1;
break;
case SDLK_RIGHT:
eye[0] += 0.1;
break;
case SDLK_UP:
eye[1] -= 0.1;
break;
case SDLK_DOWN:
eye[1] += 0.1;
break;
default:
break;
}

return;
}


What changes should I make in my code to handle continuous keystroke detection?

Note: The following code does the required job but I don't understand why

if ( ( SDL_EnableKeyRepeat( 100, SDL_DEFAULT_REPEAT_INTERVAL ) ) )
{
fprintf( stderr, "Setting keyboard repeat failed: %s\n",
SDL_GetError( ) );
Quit( 1 );
}

– user1430
Nov 9 '11 at 15:55

void Main::processInput()
{
Uint8* keystate = SDL_GetKeyState(NULL);

//continuous-response keys
if(keystate[SDLK_LEFT])
{
}
if(keystate[SDLK_RIGHT])
{
}
if(keystate[SDLK_UP])
{
}
if(keystate[SDLK_DOWN])
{
}

//single-hit keys, mouse, and other general SDL events (eg. windowing)
while(SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_MOUSEMOTION:
break;

case SDL_QUIT:
case SDL_KEYDOWN:
if(event.key.keysym.sym == SDLK_ESCAPE)
done = true; //quit
break;
}
}
}


Usage:

Main::Main()
{
//set up SDL etc.
//set up timing variables etc.
timeStepMs = 1000.f / yourUpdateFrequency; //eg. 30Hz
//set up game world etc.

//main loop, run like the wind!
while(!done)
{

timeLastMs = timeCurrentMs;
timeCurrentMs = SDL_GetTicks();
timeDeltaMs = timeCurrentMs - timeLastMs;
timeAccumulatedMs += timeDeltaMs;

while (timeAccumulatedMs >= timeStepMs)
{
processInput();
//update world: do ai, physics, etc. here
timeAccumulatedMs -= timeStepMs;
}
render(); //render update only once
}
}

• You should call SDL_PumpEvents() before SDL_GetKeyState(), otherwise you're operating on last frame's key state. Alternatively, call SDL_GetKeyState() after the SDL_PollEvents() loop. Jun 11 '12 at 2:24
• while(SDL_PollEvent(&event)) where is event defined? Dec 21 '12 at 15:08
• @NickWiggill: +1 Thanks, the idea helped me do the same in GLFW :) Mar 2 '14 at 11:17
• For those using SDL2: This is a good solution but you have to use SDL_GetKeyboardState() rather than SDL_GetKeyState() and key code constants SDL_SCANCODE_x rather than SDLK_x. See e.g. cs.umb.edu/~bazz/cms/index.php?id=sdl-sdl2-migration-experience
– V.K.
Mar 18 '16 at 9:42

If you're using SDL version 1.x, use SDL_GetKeyState() to determine whether a key is up or down.

If you're using SDL version 2.x, use SDL_GetKeyboardState() to determine whether a key is up or down.

• Fair enough - it's just frustrating that this question has come up about 3 times and it's right in the docs. I don't think we should be essentially duplicating external documentation. Nov 9 '11 at 20:34
• Agreed, though your answer would have been better as a comment instead of a full answer in that case. Nov 9 '11 at 20:53
• The page you were looking for couldn't be found. There is a reason why posting ONLY a link is considered bad. Oct 24 '15 at 20:16

I don't know exactly how to do it in SDL, but in pseudo code this is the approach

bool[] isKeyDown
bool[] isKeyPressed

public void Check(){
foreach Key k in Keys
if(k.isDown && !isKeyDown[k]){
isKeyDown[k] = true;
isKeyPressed[k] = true;
}
else if(k.IsDown && isKeyDown[k]){
isKeyPressed[k] = false;
}
else{
isKeyDown[k] = false;
isKeyPressed[k] = false;
}
}
}


This way isKeyPressed[k] is true and only true the first time k was pressed, you can use that for menu navigation. Alternatively isKeyDown[k] is true the entire time that k was pressed.

Now I'm pretty confident that SDL has a way to request the current key state, but if you can only repsond to events you just clear isKeyPressed[k] at the start of every game loop, make isKeyPressed[k] and isKeyDown[k] true on every KeyDown event and make isKeyDown[k] false on every KeyUp event.

You're going to want it to read SDL_KEYUP and SDL_KEYDOWN. You can either have it so it sets a boolean to true when the key is pressed and to false when the key is unpressed and then have it check the booleans and perform an action if true, or you can do something like this...

if(SDL_PollEvent(&event)) {
if(event.type==SDL_KEYDOWN) {
switch(event.key.keysym.sym) {
case SDLK_UP:    yVel-=2; break;
case SDLK_DOWN:  yVel+=2; break;
case SDLK_LEFT:  xVel-=2; break;
case SDLK_RIGHT: xVel+=2; break;
}
}
if(event.type==SDL_KEYUP) {
switch(event.key.keysym.sym) {
case SDLK_UP:    yVel+=2; break;
case SDLK_DOWN:  yVel-=2; break;
case SDLK_LEFT:  xVel+=2; break;
case SDLK_RIGHT: xVel-=2; break;
}
}
}


And then simply add the x/yVel to the x/y position of what you want to move...

x+=xVel;
y+=yVel;