In the previous chapter we saw how events are processed to handle input of any kind (keyboard, mouse, joystick,…). However, especially for game development I’d like to introduce a simple, yet powerful way to handle keyboard input via the so called keyboard state.
Advantages of using Keyboard States
Instead of triggering a key event once and process it perhaps with some delay, you look for the state (pressed or released) of all keys of a keyboard at once and whenever you desire. This is especially useful for continuous actions that happen along with key presses. E. g. a game character moving as long as a key is pressed.
Using the keyboard state is very fast and efficient compared to processing keyboard events. Also, the keyboard state can be accessed at every point in the program. In contrast to that events usually are processed periodically (in the game loop). The usage of the keyboard state and keyboard events can (and should) be combined freely.
Disadvantages of using the keyboard state
The keyboard states does not consider key modifiers like the shift-key. So you know a key has been pressed but you cannot distinguish between a letter and a capital letter for example. There are no equivalent input states for other devices like mouse, joystick, joypad, and so on. Last but not least, you still need the event processing in the program loop because otherwise the state does not get updated (see below for more information on that). This also means, if the key state of a certain key changes from unpressed to pressed and back to unpressed before the event loop has been processed, the pressed key remains unnoticed.

The following code example will draw a red rectangle which can be moved by the WASD keys. Therefore we read out their key states on every cycle of the program loop. The ESC key or the Q key stop the program from running.
program SDL_KeyboardStates;
uses SDL3;
var
sdlWindow1: PSDL_Window;
sdlRenderer: PSDL_Renderer;
sdlRectangle: TSDL_FRect;
sdlKeyboardState: PBoolean;
RunLoop: Boolean = True;
begin
// initilization of video subsystem
if not SDL_Init(SDL_INIT_VIDEO) then
Halt;
// create window and renderer
if not SDL_CreateWindowAndRenderer('SDL3 Keyboard State', 500, 500, 0, @sdlWindow1, @sdlRenderer) then
Halt;
// prepare rectangle
sdlRectangle.x := 250;
sdlRectangle.y := 250;
sdlRectangle.w := 10;
sdlRectangle.h := 10;
// get keyboard state pointer
sdlKeyboardState := SDL_GetKeyboardState(nil);
// program loop
while RunLoop do
begin
SDL_PumpEvents;
// ESC key or Q key pressed
if sdlKeyboardState[SDL_SCANCODE_ESCAPE] or sdlKeyboardState[SDL_SCANCODE_Q] then
RunLoop := False;
// WASD keys pressed
if sdlKeyboardState[SDL_SCANCODE_W] then
sdlRectangle.y := sdlRectangle.y-1;
if sdlKeyboardState[SDL_SCANCODE_A] then
sdlRectangle.x := sdlRectangle.x-1;
if sdlKeyboardState[SDL_SCANCODE_S] then
sdlRectangle.y := sdlRectangle.y+1;
if sdlKeyboardState[SDL_SCANCODE_D] then
sdlRectangle.x := sdlRectangle.x+1;
// grey background
SDL_SetRenderDrawColor(sdlRenderer, 50, 50, 50, SDL_ALPHA_OPAQUE);
SDL_RenderClear(sdlRenderer);
// draw red rectangle
SDL_SetRenderDrawColor(sdlRenderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderRect(sdlRenderer, @sdlRectangle);
SDL_RenderPresent(sdlRenderer);
SDL_Delay(10);
end;
// clear memory
SDL_DestroyRenderer(sdlRenderer);
SDL_DestroyWindow (sdlWindow1);
// quit SDL3
SDL_Quit;
end. To get the keyboard state, we define a boolean pointer variable sdlKeyboardState in the var clause.
After setting up a SDL3 window and and preparing a SDL3 rectangle, we jump right into allocating the keyboard state pointer to the sdlKeyboardState variable by the function SDL_GetKeyboardState.
Lets have a look at this function here.
function SDL_GetKeyboardState(numkeys: pcint): PBooleanThe keyboard state represents the state of all the keyboard keys, hence the key states. The states are accessed by an array of boolean values. Every position in this array represent a certain key of your keyboard. Unpressed keys have a boolean value of false. If one or more keys are pressed, their values switch to true as long as they are pressed. If a key is released, its value is switching back to false.
This is a highly efficient and fast way of gathering keyboard information without the need to queue any events.
The argument when calling this function should be nil. It is sufficient to call it once in your program code as you see in the second line:
// get keyboard state pointer
sdlKeyboardState := SDL_GetKeyboardState(nil);
// program loop
while RunLoop do
begin
SDL_PumpEvents; In the program event loop we need to update the event queue by procedure SDL_PumpEvents (or SDL_PollEvent or SDL_WaitEvent; both call SDL_PumpEvent implicitly). Only calling one of these procedures in the program loop updates the keyboard state.
// ESC key or Q key pressed
if sdlKeyboardState[SDL_SCANCODE_ESCAPE] or sdlKeyboardState[SDL_SCANCODE_Q] then
RunLoop := False;
// WASD keys pressed
if sdlKeyboardState[SDL_SCANCODE_W] then
sdlRectangle.y := sdlRectangle.y-1;
if sdlKeyboardState[SDL_SCANCODE_A] then
sdlRectangle.x := sdlRectangle.x-1;
if sdlKeyboardState[SDL_SCANCODE_S] then
sdlRectangle.y := sdlRectangle.y+1;
if sdlKeyboardState[SDL_SCANCODE_D] then
sdlRectangle.x := sdlRectangle.x+1; We now can check for pressed keys in the keyboard state array by sdlKeyboardState[SDL_SCANCODE_…] using its scan code as a handle (e.g. SDL_SCANCODE_ESCAPE for the escape key). If it evaluates to true, we react as desired, e.g. exit the program loop or change the x/y coordinates of the rectangle. The scan code represents the position of the related key state in the array. A detailed description of scan codes you find in paragraph “The Difference between Key code and Scan code” in the event handling chapter. A list of all the scancodes shows all possible scancodes.
← previous Chapter | next Chapter →
[Title AI image created with Le Chat from Mistral AI]