Voyons comment gérer le/les joysticks avec la SDL3 

En SDL3, la gestion du joystick a été légèrement revue par rapport à la SDL2, en plus des fonctions renommées.

Le gros changement est qu'au lieu de parcourir les joysticks à l'aide de l'index de périphérique, il existe maintenant une nouvelle fonction SDL_GetJoysticks() pour obtenir la liste actuelle des joysticks, comme le monter l'exemple de la documentation.

{
    if (SDL_InitSubSystem(SDL_INIT_JOYSTICK)) {
        int i, num_joysticks;
        SDL_JoystickID *joysticks = SDL_GetJoysticks(&num_joysticks);
        if (joysticks) {
            for (i = 0; i < num_joysticks; ++i) {
                SDL_JoystickID instance_id = joysticks[i];
                const char *name = SDL_GetJoystickNameForID(instance_id);
                const char *path = SDL_GetJoystickPathForID(instance_id);

                SDL_Log("Joystick %" SDL_PRIu32 ": %s%s%s VID 0x%.4x, PID 0x%.4x\n",
                        instance_id, name ? name : "Unknown", path ? ", " : "", path ? path : "", 
                        SDL_GetJoystickVendorForID(instance_id), SDL_GetJoystickProductForID(instance_id));
            }
            SDL_free(joysticks);
        }
        SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
    }
}

 

On dispose aussi de nouvelles fonctions pour obtenir des informations sur les joysticks à partir de leur ID d'instance, comme SDL_GetJoystickNameForID, SDL_GetJoystickVendorForID.

 

Etapes pour une utilisation :

D'abord on initialise le sous système du joystick

    if (SDL_Init(SDL_INIT_JOYSTICK) < 0) {
        std::cerr << "Unable to initialize the joystick subsystem: " << SDL_GetError() << std::endl;
        return -1;
    }

Ensuite, on lit les joysticks que l'on place dans une map pour faire la correspondance entre le matériel et son ID

    using JoystickMap = std::unordered_map<SDL_JoystickID, SDL_Joystick*>;
   
    int joystick_count = 0;
    SDL_JoystickID *joystick_ids = SDL_GetJoysticks(&joystick_count);

    if (joystick_count == 0) {
        std::cout << "No joystick connected.\n";
        return;
    }

    std::cout << joystick_count << " joystick(s) connected.\n";

    for (int i = 0; i < joystick_count; ++i) {
        SDL_JoystickID id = joystick_ids[i];

        // Avoid reopening an already connected joystick
        if (joysticks.find(id) != joysticks.end()) {
            continue;
        }

        SDL_Joystick *joystick = SDL_OpenJoystick(id);
        if (!joystick) {
            std::cerr << "Failed to open joystick ID " << id << ": " << SDL_GetError() << std::endl;
            continue;
        }

        joysticks[id] = joystick;

 

On peut voir les propriétés du joystick

        // Shows joystick information
        std::cout << "Joystick ID " << id << ": " << SDL_GetJoystickName(joystick) << "\n";
        std::cout << "Path: " << SDL_GetJoystickPath(joystick) << "\n";
        std::cout << "Vendor: " << SDL_GetJoystickVendor(joystick) << " Product: " << SDL_GetJoystickProduct(joystick) << "\n";
        std::cout << "Axes: " << SDL_GetNumJoystickAxes(joystick)
                  << ", Buttons: " << SDL_GetNumJoystickButtons(joystick)
                  << ", Hats: " << SDL_GetNumJoystickHats(joystick)
                  << ", Balls: " << SDL_GetNumJoystickBalls(joystick) << "\n";

 

Puis il reste à l'utiliser dans un méga switch concernant le traitement des events de la SDL:

SDL_Event event;
    while (!quit) {
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
                case SDL_EVENT_QUIT:
                    quit = true;
                    break;

                case SDL_EVENT_JOYSTICK_AXIS_MOTION:
                    if (abs(event.jaxis.value) > deadZone) {
                        std::cout << "Joystick " << event.jaxis.which << " axis "
                                  << static_cast<int>(event.jaxis.axis)
                                  << " moved to " << event.jaxis.value << ".\n";
                    }
                    break;

                case SDL_EVENT_JOYSTICK_HAT_MOTION:
                    std::cout << "Joystick " << event.jhat.which << " hat "
                              << static_cast<int>(event.jhat.hat)
                              << " moved to " << static_cast<int>(event.jhat.value) << ".\n";
                    break;

                case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
                    std::cout << "Joystick " << event.jbutton.which << " button "
                              << static_cast<int>(event.jbutton.button) << " pressed.\n";
                    break;

                case SDL_EVENT_JOYSTICK_BUTTON_UP:
                    std::cout << "Joystick " << event.jbutton.which << " button "
                              << static_cast<int>(event.jbutton.button) << " released.\n";
                    break;

                case SDL_EVENT_JOYSTICK_BALL_MOTION:
                    std::cout << "Joystick " << event.jball.which << " ball "
                              << static_cast<int>(event.jball.xrel) << " x "
                              << static_cast<int>(event.jball.yrel) << ".\n";
                    break;

                case SDL_EVENT_JOYSTICK_ADDED:
                    std::cout << "Joystick connected.\n";
                    connect_joystick(joysticks);
                    break;

                case SDL_EVENT_JOYSTICK_REMOVED:
                    std::cout << "Joystick disconnected.\n";
                    close_joystick(joysticks, event.jdevice.which);
                    break;

                default:
                    break;
            }
        }
    }

 

Les fonctions connect_joystick() et close_joystick() servent à maintenir à jour la map, elles sont données ici.

void close_joystick(JoystickMap &joysticks, SDL_JoystickID id) {
    auto it = joysticks.find(id);
    if (it != joysticks.end()) {
        SDL_CloseJoystick(it->second);
        joysticks.erase(it);
        std::cout << "Closed joystick ID " << id << ".\n";
    }
}

 

Vous pouvez retrouver l'intégrale du code source sur github.