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.