Chapter 4 – Keyboard Input in SDL

You can’t really make a game without some kind of input. Whether it’s just the plain old keyboard or 3 button joypad like in the 70’s and 80’s. Or it’s something like the DualShock (R) and DualShock (R) 2 from the 90’s and early 2000’s. Or it’s those awesome motion controllers and XBox Kinect (TM).

A game always requires input of some kind or other. So, let’s start from the good ol’ keyboard. One way to detect keyboard presses and releases is to track the event loop’s SDL_KEYUP and SDL_KEYDOWN event types. SDL_KEYDOWN is sent when a key is pressed. Similarly, SDL_KEYUP is sent when a key is released. Then you can use the SDL_KeyboardEvent in the SDL_Event union to check which key was pressed or released.

Let’s take a closer look at the SDL_KeyboardEvent.

typedef struct{
  Uint8 type;
  Uint8 state;
  SDL_keysym keysym;
} SDL_KeyboardEvent;

Firstly, like most events, it contains type. It also contains state which is for knowing whether it was a key press, or a key release (it has two values, SDL_PRESSED and SDL_RELEASED). The last member, keysym is the one that is used to find out which key was pressed or released. Looking at the SDL_keysym structure:

typedef struct{
  Uint8 scancode;
  SDLKey sym;
  SDLMod mod;
  Uint16 unicode;
} SDL_keysym;

We see that there are four members. First there comes the scancode. It shouldn’t really be used for cross-platform games. Why? Because it’s platform-specific. That means it is different on different platforms. Even if you use a single platform, it may not be the same on different keyboards. For example, The scan-codes for USB keyboards are different from those of PS/2 Keyboards. Let’s say you create a game which runs perfectly on your Dell PS/2 Keyboard. Now, you decide to share it with your buddy, who has a laptop with a built-in keyboard, or a USB keyboard, or even a slightly newer keyboard model. The game won’t work!

Second is sym, which is a virtual key code (like the VK_* codes in the Windows API). Now a virtual key-code is a kind of platform-independent wrapper over the hardware specific key-codes. No matter what platform or keyboard you use, the virtual key-code will remain the same. Virtual key-codes should be used for cross-platform development. In fact, if you’re developing games, you should almost always use these. Here is a complete list of SDL Virtual key-codes.

Third is mod, this checks whether modifier keys such as SHIFT or CTRL are pressed currently. The last member, unicode, is a unicode representation of the character.

Let’s add a key-press handler in our sample program.

#include <SDL/SDL.h>

void handle_keys(SDL_Event* event, int* quit)
{
    if (event->type == SDL_KEYDOWN)
    {
        if (event->key.keysym.sym == SDLK_ESCAPE)
        {
            *quit = 1;
        }
    }
}

int main(int argc, char* argv[])
{
    /* skipped all irrelevant code */
    ...

    /* An SDL_Event struct */
    SDL_Event event;

    /* A bool to check if the program has exited */
    int quit = 0;

    /* While the program is running */
    while (!quit)
    {
        /* Check for new events */
        while(SDL_PollEvent(&event))
        {
            /* If a quit event has been sent */
            if (event.type == SDL_QUIT)
            {
                /* Quit the application */
                quit = 1;
            }

            handle_keys(&event, &quit);
        }
    }

    ...
}

Let’s explain the code now.

    if (event->type == SDL_KEYDOWN)

Check if the event it is a keyboard event. I discussed the relation between events and their types in the last chapter. If the event type is SDL_KEYDOWN, we can deduce that it is a keyboard event and that is is a key press (if the type was SDL_KEYUP, it would have been a key release). Okay, so we now know that a key on the keyboard has been pressed. So, which key? For that we have:

        if (event->key.keysym.sym == SDLK_ESCAPE)

As I explained earlier, we check the virtual key-code which is stored in the SDL_KeyboardEvent‘s keysym member to check which key has been pressed. Here I compare it with SDLK_ESCAPE. If this evaluates to true, then that means the key pressed was the “Escape” key, usually found on the top-left corner of the keyboard.

*quit = 1;

Not much to explain here, we quit the application when the escape key is pressed. Setting the value of quit to true ends the game loop and the program exits.

            handle_keys(&event, &quit);

We have to regularly call our key handler function in the event loop for it to work.

Although the above method is pretty commonly used for handling keyboard input, it is dependent on the event loop. This may present some difficulties. A non event-loop dependent way is to use the SDL_GetKeyState() function. The advantage here is that SDL_GetKeyState() can be used anywhere in your program, not just inside the event loop. Let’s rewrite the program to use SDL_GetKeyState() instead.


#include <SDL/SDL.h>

int main(int argc, char* argv[])
{
    ...

    Uint8* keys = NULL;

    /* While the program is running */
    while (!quit)
    {
        /* Check for new events */
        while(SDL_PollEvent(&event))
        {
            ...
        }

        keys = SDL_GetKeyState(NULL);
        if (keys[SDLK_ESCAPE]) quit = 1;
    }
  
    ...
    return 0;
}

To explain the above code…

       keys = SDL_GetKeyState(NULL);

SDL_GetKeyState() actually returns a pointer to an array which is indexed by all SDL virtual key-code values. The value at the index of every key-code is either a 0 (false), if it is not pressed or a 1 (true) if it is pressed. So, the best way to check whether a certain key is pressed is to check if the value of the array at that key-code’s index evaluates to true. Which we do in the next line:

        if (keys[SDLK_ESCAPE]) quit = 1;

If it evaluates to true (which means that the escape key is pressed), we set the value of quit to true and end the main loop.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s