HOME About NCOT Documentation SineSoft Social Media Support Me


Made from 100% Programmer Art

[Blog] [Prototypes] [Labs]
Easier Game Controller Input in SDL with SDL_GameController

Easier Game Controller Input in SDL with SDL_GameController


Game controllers on computers are somewhat irritating to manage compared to a console. Has the user plugged in an XBox controller? A PS4 controller, or have they obtained some random USB controller they found on eBay?

Coping with this in SDL was difficult, with SDL just telling you “button 13 pressed” or “joystick axis 4 moved”, which is great except all your code really wants to know is “did the user just press the A button?”.

SDL_GameController fixes all this, and it needs better documentation, so this is my attempt at providing some useful information.

Include the headers

#include <vector>
#include <SDL_gamecontroller.h>
The vector is needed to hold the attached game controllers so our games can work with multiple players.

Create a structure for the controller data

Each controller gets a struct to hold the button states and values of each axis.

struct  GamePad {
    bool buttons[SDL_CONTROLLER_BUTTON_MAX];

Set up variables

We’re keeping a list of connected controllers, and then two lists of controller input states. Having a previous as well as the current state means checking for a button being pressed and then released is easy.

std::vector<SDL_GameController*> connectedControllers;
std::vector<GamePad> controllerInputs;
std::vector<GamePad> lastControllerInputs;
int numGamepads;

Give things meaningful names with enums

Nobody wants to be asking for controllerInputs[0].buttons[0] in their code, they want to be writing controllerInputs[PLAYER1].buttons[SDL_CONTROLLER_BUTTON_A] because self documenting code is good. Note that this isn’t how the code actually works, there’s functions to get the button states.

enum Controllers {PLAYER1, PLAYER2, PLAYER3, PLAYER4};
Buttons are referenced by SDL’s own enums which are found in SDL_gamecontroller.h

 *  The list of buttons available from a controller
typedef enum
} SDL_GameControllerButton;

Initialise SDL’s game controller subsystem

There’s quite a bit of code here, but all it does is

  • Initialise SDL’s game controller system
  • Count how many controllers are connected and add them to a list
  • Clear the vectors of button/stick states

int nJoysticks = SDL_NumJoysticks();
numGamepads = 0;

// Count how many controllers there are
for (int i = 0; i < nJoysticks; i++)
	if (SDL_IsGameController(i))
// If we have some controllers attached
if (numGamepads > 0)
	for (int i = 0; i < numGamepads; i++)
		// Open the controller and add it to our list
		SDL_GameController* pad = SDL_GameControllerOpen(i);
		if (SDL_GameControllerGetAttached(pad) == 1)
			std::cout << "SDL_GetError() = " << SDL_GetError() << std::endl;

// Vectors are empty to begin with, this sets their size

// Set the status of the controllers to "nothing is happening"
for (int i = 0; i < numGamepads; i++) {
	for (int a = 0; a < SDL_CONTROLLER_AXIS_MAX; a++) {
		controllerInputs[i].axis[a] = 0;
		lastControllerInputs[i].axis[a] = 0;
	for (int b = 0; b < SDL_CONTROLLER_BUTTON_MAX; b++) {
		controllerInputs[i].buttons[b] = false;
		lastControllerInputs[i].buttons[b] = false;

Game loop code

This small piece of code copies the button states from the previous frame into our “previous” list.

for (int i = 0; i < numGamepads; i++) {
	for (int a = 0; a < SDL_CONTROLLER_AXIS_MAX; a++) {
		lastControllerInputs[i].axis[a] = controllerInputs[i].axis[a];
	for (int b = 0; b < SDL_CONTROLLER_BUTTON_MAX; b++) {
		lastControllerInputs[i].buttons[b] = controllerInputs[i].buttons[b];

SDL’s event system is used to actually update the controller states

SDL_Event event;
if (SDL_PollEvent(&event))
	switch (event.type) {
	case SDL_QUIT:
		return false;
	// This happens when a device is added
	// A future improvement is to cope with new controllers being plugged in
	// when the game is running
		std::cout << "DEVICEADDED cdevice.which = " << event.cdevice.which << std::endl;

	// If a controller button is pressed
		// Cycle through the controllers
		for (int i = 0; i < numGamepads; i++) {
			// Looking for the button that was pressed
			if (event.cbutton.which == SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(connectedControllers[i]))) {
				// So the relevant state can be updated
				controllerInputs[i].buttons[event.cbutton.button] = true;
	// Do the same for releasing a button
		for (int i = 0; i < numGamepads; i++) {
			if (event.cbutton.which == SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(connectedControllers[i]))) {
				controllerInputs[i].buttons[event.cbutton.button] = false;

	// And something similar for axis motion
		for (int i = 0; i < numGamepads; i++) {
			if (event.cbutton.which == SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(connectedControllers[i]))) {
				controllerInputs[i].axis[event.caxis.axis] = event.caxis.value;

Use the controller data easily

Checking nested structures within vectors would quickly become tedious, so I wrote some routines to do it for me. They’re part of a larger “input” class, but the logic should make sense.

Has a button been pressed?

bool Input::isControllerButtonPressed(Inputs::Controllers controllerID, SDL_GameControllerButton button)
	if (controllerID < 0 || controllerID > numGamepads) return false;

	return controllerInputs[controllerID].buttons[button] && !lastControllerInputs[controllerID].buttons[button];

Is a button being pressed?

bool Input::isControllerButtonHeld(Inputs::Controllers controllerID, SDL_GameControllerButton button)
	if (controllerID < 0 || controllerID > numGamepads) return false;

	return controllerInputs[controllerID].buttons[button] && lastControllerInputs[controllerID].buttons[button];

Get an axis value

float Input::getControllerAxis(Inputs::Controllers controllerID, SDL_GameControllerAxis axis)
	if (controllerID < 0 || controllerID > numGamepads) return 0.0;

	return controllerInputs[controllerID].axis[axis] / 32768.0f;


This code is inside the update loop of my player character.

if (inputs->isControllerButtonHeld(PLAYER1, SDL_CONTROLLER_BUTTON_DPAD_LEFT)) {
	rightAcc = -acceleration/3.0;
} else
if (inputs->isControllerButtonHeld(PLAYER1, SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) {
	leftAcc = -acceleration/3.0;	
} else

if (inputs->isControllerButtonHeld(PLAYER1, SDL_CONTROLLER_BUTTON_DPAD_UP)) {
	leftAcc = rightAcc = acceleration;
} else
if (inputs->isControllerButtonHeld(PLAYER1, SDL_CONTROLLER_BUTTON_DPAD_DOWN)) {
	leftAcc = rightAcc = -acceleration;
if (inputs->isControllerButtonPressed(PLAYER1, SDL_CONTROLLER_BUTTON_A)) {
	Vec2D temp = (muzzle->transform->globalPosition - transform->globalPosition).getNormal() * 10;
	bullets->Emit(1, muzzle->transform->globalPosition, temp);
	leftAcc = rightAcc = -acceleration * 5;


I used these sites:

Related Content

  • Text printing using bitmap characters in C++ and SDL
    February 4, 2019
    How to print text from a sprite map, using old school programming techniques.

  • Component Based Game Engine From Scratch Part 1
    March 10, 2019
    This is going to be the first part in a continuing series where I try to explain how and why I'm creating my own game engine using C++ and the SDL library.

  • Maths for Programmers 1 Rearranging Equations
    March 28, 2019
    Straight forward instructions on how to rearrange algebraic equations, all wrapped up in a nice free PDF to download. Don't fear maths or algebra again!

  • Creating a Modern Static Website Using Hugo
    February 8, 2019
    This post is sponsored by hand coded HTML and CSS. Hand coding your HTML is a quick and effective method of getting your presence online! The first 20 people to click the link below will get 100% off their own hand coded website! You will require your own hands and knowledge of HTML.

  • 0x03 Documenting things
    February 3, 2019
    I'm going to be making a lot of uninspiring clones of existing games so the process is really the thing I want to write about. My current plan is to pick interesting parts of the code and explain them by using diagrams, some pseudocode, annotated code listings or screenshots.