Glusoft

Use Gamepads and Joysticks with SDL3

In this tutorial the goal is to be able to use a gamepad or a joystickw with SDL3, for that I will use a xbox controller.

Initialize and open the gamepad

The first thing to check is wether a gamepad is connected for that you can use the function: SDL_HasGamepad

if (!SDL_HasGamepad()) {
    std::cout << "No gamepads connected.\n";
    SDL_Quit();
    return 0;
}

After we know at least one gamepad is connected we can list the gamepad and pick the first one, the function to list th gamepads is: SDL_GetGamepads

int count = 0;
SDL_JoystickID *ids = SDL_GetGamepads(&count);
SDL_Gamepad* gamepad = NULL;

// Iterate over the list of gamepads
for(int i = 0; i < count; i++) {
    SDL_Gamepad* gamepd = SDL_OpenGamepad(ids[i]);
    if(gamepad == NULL) {
        gamepad = gamepd;
    }
        
    std::cout << "Gamepad connected: " << SDL_GetGamepadName(gamepd) << "\n";
    
    // Close the other gamepads
    if(i > 0) {
        SDL_CloseGamepad(gamepd);
    }
}
if (!gamepad) {
    std::cerr << "Failed to open gamepad: " << SDL_GetError() << "\n";
    SDL_Quit();
    return 1;
}

Record all the events

After the gamepad is opened we can record the event when a button is pressed (SDL_EVENT_GAMEPAD_BUTTON_DOWN) and released (SDL_EVENT_GAMEPAD_BUTTON_UP) or when a joysticks is moved (SDL_EVENT_GAMEPAD_AXIS_MOTION):

bool running = true;
SDL_Event event;

while (running) {
    while (SDL_PollEvent(&event)) {
        switch (event.type) {
            case SDL_EVENT_QUIT:
                running = false;
                break;

            case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
                std::cout << "Button pressed: "
                            << SDL_GetGamepadStringForButton((SDL_GamepadButton)event.gbutton.button)
                            << "\n";
                break;

            case SDL_EVENT_GAMEPAD_BUTTON_UP:
                std::cout << "Button released: "
                            << SDL_GetGamepadStringForButton((SDL_GamepadButton)event.gbutton.button)
                            << "\n";
                break;

            case SDL_EVENT_GAMEPAD_AXIS_MOTION:
                std::cout << "Axis moved: "
                            << SDL_GetGamepadStringForAxis((SDL_GamepadAxis)event.gaxis.axis)
                            << " Value: " << event.gaxis.value << "\n";
                break;
        }
    }

    SDL_Delay(16); // Sleep 16ms (~60FPS)
}

Define a deadzone to have more precise triggers

If you test this code you can see the axis of the joystick are trigger very easily, to avoid that you need to define a threshold for a deadzone, this threshold is a constant:


Thumbstick axis values range from SDL_JOYSTICK_AXIS_MIN (-32768) to SDL_JOYSTICK_AXIS_MAX (32768), and are centered within ~8000 of zero, though advanced UI will allow users to set or autodetect the dead zone, which varies between gamepads.

bool running = true;
SDL_Event event;
const int DEADZONE = 9000;

while (running) {
    while (SDL_PollEvent(&event)) {
        switch (event.type) {
            case SDL_EVENT_QUIT:
                running = false;
                break;

            case SDL_EVENT_GAMEPAD_AXIS_MOTION:
                if(event.gaxis.axis == SDL_GAMEPAD_AXIS_LEFTX && event.gaxis.value > DEADZONE) {
                        std::cout << "left axis right\n";
                } else if(event.gaxis.axis == SDL_GAMEPAD_AXIS_LEFTX && event.gaxis.value < -DEADZONE) {
                    std::cout << "left axis left\n";
                }
                
                if(event.gaxis.axis == SDL_GAMEPAD_AXIS_LEFTY && event.gaxis.value > DEADZONE) {
                            std::cout << "left axis down\n";
                } else if(event.gaxis.axis == SDL_GAMEPAD_AXIS_LEFTY && event.gaxis.value < -DEADZONE) {
                    std::cout << "left axis up\n";
                }
                break;
        }
    }

    SDL_Delay(16); // Sleep ~16ms (~60FPS)
}

Values of SDL_GamepadButtonLabel and SDL_GamepadAxis

The buttons (event.gbutton.button) for the gamepad can have these values:

The values for the axis (event.gaxis.axis) are the following:

Download the full project : Use gamepads and joysticks with SDL3

Need another OS ? => Windows, Mac, Linux