From 765e74fe71433d612c5d60e31200760dd1084fe7 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 17 Feb 2025 13:51:18 -0800
Subject: [PATCH] SDL2 joystick and sensor IDs were guaranteed to start from 0
Fixes https://github.com/libsdl-org/sdl2-compat/issues/359
---
src/sdl2_compat.c | 241 ++++++++++++++++++++++++++++++++++++++++------
1 file changed, 209 insertions(+), 32 deletions(-)
diff --git a/src/sdl2_compat.c b/src/sdl2_compat.c
index aaae481..6b6683f 100644
--- a/src/sdl2_compat.c
+++ b/src/sdl2_compat.c
@@ -1028,10 +1028,14 @@ static SDL_mutex *EventWatchListMutex = NULL;
static SDL2_LogOutputFunction LogOutputFunction2 = NULL;
static EventFilterWrapperData *EventWatchers2 = NULL;
static SDL2_bool relative_mouse_mode = SDL2_FALSE;
+static SDL_JoystickID *joystick_instance_list = NULL;
+static int num_joystick_instances = 0;
static SDL_JoystickID *joystick_list = NULL;
static int num_joysticks = 0;
static SDL_JoystickID *gamepad_button_swap_list = NULL;
static int num_gamepad_button_swap_list = 0;
+static SDL_SensorID *sensor_instance_list = NULL;
+static int num_sensor_instances = 0;
static SDL_SensorID *sensor_list = NULL;
static int num_sensors = 0;
static SDL_HapticID *haptic_list = NULL;
@@ -1068,6 +1072,11 @@ static int NumTouchFingers = 0;
static SDL_PropertiesID timers = 0;
+static SDL_JoystickID JoystickID2to3(SDL2_JoystickID id);
+static SDL2_JoystickID JoystickID3to2(SDL_JoystickID id);
+static SDL_SensorID SensorID2to3(SDL2_SensorID id);
+static SDL2_SensorID SensorID3to2(SDL_SensorID id);
+
/* Functions! */
static SDL_InitState InitSDL2CompatGlobals;
@@ -1618,8 +1627,7 @@ static int GetIndexFromAudioDeviceInstance(SDL_AudioDeviceID devid, bool recordi
static int GetIndexFromJoystickInstance(SDL_JoystickID jid);
-static SDL2_Event *
-Event3to2(const SDL_Event *event3, SDL2_Event *event2)
+static SDL2_Event *Event3to2(const SDL_Event *event3, SDL2_Event *event2)
{
SDL_Renderer *renderer;
SDL_Event cvtevent3;
@@ -1749,27 +1757,27 @@ Event3to2(const SDL_Event *event3, SDL2_Event *event2)
wheel->mouseY = (Sint32)event3->wheel.mouse_y;
}
break;
- case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
- case SDL_EVENT_GAMEPAD_BUTTON_UP:
- if (ShouldSwapGamepadButtons(event2->cbutton.which)) {
- event2->cbutton.button = SwapGamepadButton(event2->cbutton.button);
- }
+ case SDL_EVENT_JOYSTICK_AXIS_MOTION:
+ event2->jaxis.which = JoystickID3to2(event3->jaxis.which);
break;
- /* sensor timestamps are in nanosecond in SDL3 */
- case SDL_EVENT_GAMEPAD_SENSOR_UPDATE:
- event2->csensor.timestamp_us = SDL_NS_TO_US(event3->gsensor.sensor_timestamp);
+ case SDL_EVENT_JOYSTICK_BALL_MOTION:
+ event2->jball.which = JoystickID3to2(event3->jball.which);
break;
- case SDL_EVENT_SENSOR_UPDATE:
- event2->sensor.timestamp_us = SDL_NS_TO_US(event3->sensor.sensor_timestamp);
+ case SDL_EVENT_JOYSTICK_HAT_MOTION:
+ event2->jhat.which = JoystickID3to2(event3->jhat.which);
+ break;
+ case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
+ case SDL_EVENT_JOYSTICK_BUTTON_UP:
+ event2->jbutton.which = JoystickID3to2(event3->jbutton.which);
break;
- /* Change SDL3 InstanceID to index */
case SDL_EVENT_JOYSTICK_ADDED:
event2->jdevice.which = GetIndexFromJoystickInstance(event3->jdevice.which);
break;
- case SDL_EVENT_GAMEPAD_ADDED:
- event2->cdevice.which = GetIndexFromJoystickInstance(event3->gdevice.which);
+ case SDL_EVENT_JOYSTICK_REMOVED:
+ event2->jdevice.which = JoystickID3to2(event3->jdevice.which);
break;
case SDL_EVENT_JOYSTICK_BATTERY_UPDATED:
+ event2->jbattery.which = JoystickID3to2(event3->jbattery.which);
switch (event3->jbattery.state) {
case SDL_POWERSTATE_CHARGING:
case SDL_POWERSTATE_CHARGED:
@@ -1791,17 +1799,48 @@ Event3to2(const SDL_Event *event3, SDL2_Event *event2)
break;
}
break;
+ case SDL_EVENT_GAMEPAD_AXIS_MOTION:
+ event2->caxis.which = JoystickID3to2(event3->gaxis.which);
+ break;
+ case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
+ case SDL_EVENT_GAMEPAD_BUTTON_UP:
+ event2->cbutton.which = JoystickID3to2(event3->gbutton.which);
+ if (ShouldSwapGamepadButtons(event2->cbutton.which)) {
+ event2->cbutton.button = SwapGamepadButton(event2->cbutton.button);
+ }
+ break;
+ case SDL_EVENT_GAMEPAD_ADDED:
+ event2->cdevice.which = GetIndexFromJoystickInstance(event3->gdevice.which);
+ break;
+ case SDL_EVENT_GAMEPAD_REMOVED:
+ case SDL_EVENT_GAMEPAD_REMAPPED:
+ case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED:
+ event2->cdevice.which = JoystickID3to2(event3->gdevice.which);
+ break;
+ case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN:
+ case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION:
+ case SDL_EVENT_GAMEPAD_TOUCHPAD_UP:
+ event2->ctouchpad.which = JoystickID3to2(event3->gtouchpad.which);
+ break;
+ /* sensor timestamps are in nanosecond in SDL3 */
+ case SDL_EVENT_GAMEPAD_SENSOR_UPDATE:
+ event2->csensor.which = JoystickID3to2(event3->gsensor.which);
+ event2->csensor.timestamp_us = SDL_NS_TO_US(event3->gsensor.sensor_timestamp);
+ break;
case SDL_EVENT_AUDIO_DEVICE_ADDED:
event2->adevice.which = GetIndexFromAudioDeviceInstance(event3->adevice.which, event3->adevice.recording);
break;
+ case SDL_EVENT_SENSOR_UPDATE:
+ event2->sensor.which = SensorID3to2(event3->sensor.which);
+ event2->sensor.timestamp_us = SDL_NS_TO_US(event3->sensor.sensor_timestamp);
+ break;
default:
break;
}
return event2;
}
-static SDL_Event *
-Event2to3(const SDL2_Event *event2, SDL_Event *event3)
+static SDL_Event *Event2to3(const SDL2_Event *event2, SDL_Event *event3)
{
/* currently everything _mostly_ matches up between SDL2 and SDL3, but this might
drift more as SDL3 development continues. */
@@ -1846,6 +1885,19 @@ Event2to3(const SDL2_Event *event2, SDL_Event *event3)
event3->wheel.mouse_x = (float)event2->wheel.mouseX;
event3->wheel.mouse_y = (float)event2->wheel.mouseY;
break;
+ case SDL_EVENT_JOYSTICK_AXIS_MOTION:
+ event3->jaxis.which = JoystickID2to3(event2->jaxis.which);
+ break;
+ case SDL_EVENT_JOYSTICK_BALL_MOTION:
+ event3->jball.which = JoystickID2to3(event2->jball.which);
+ break;
+ case SDL_EVENT_JOYSTICK_HAT_MOTION:
+ event3->jhat.which = JoystickID2to3(event2->jhat.which);
+ break;
+ case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
+ case SDL_EVENT_JOYSTICK_BUTTON_UP:
+ event3->jbutton.which = JoystickID2to3(event2->jbutton.which);
+ break;
case SDL_EVENT_JOYSTICK_ADDED:
if (event2->jdevice.which >= 0 &&
event2->jdevice.which < num_joysticks) {
@@ -1854,6 +1906,19 @@ Event2to3(const SDL2_Event *event2, SDL_Event *event3)
event3->jdevice.which = 0;
}
break;
+ case SDL_EVENT_JOYSTICK_REMOVED:
+ event3->jdevice.which = JoystickID2to3(event2->jdevice.which);
+ break;
+ case SDL_EVENT_JOYSTICK_BATTERY_UPDATED:
+ /* This should never happen, but see Event3to2() for details */
+ break;
+ case SDL_EVENT_GAMEPAD_AXIS_MOTION:
+ event3->gaxis.which = JoystickID2to3(event2->caxis.which);
+ break;
+ case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
+ case SDL_EVENT_GAMEPAD_BUTTON_UP:
+ event3->gbutton.which = JoystickID2to3(event2->cbutton.which);
+ break;
case SDL_EVENT_GAMEPAD_ADDED:
if (event2->cdevice.which >= 0 &&
event2->cdevice.which < num_joysticks) {
@@ -1862,8 +1927,19 @@ Event2to3(const SDL2_Event *event2, SDL_Event *event3)
event3->gdevice.which = 0;
}
break;
- case SDL_EVENT_JOYSTICK_BATTERY_UPDATED:
- /* This should never happen, but see Event3to2() for details */
+ case SDL_EVENT_GAMEPAD_REMOVED:
+ case SDL_EVENT_GAMEPAD_REMAPPED:
+ case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED:
+ event3->gdevice.which = JoystickID2to3(event2->cdevice.which);
+ break;
+ case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN:
+ case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION:
+ case SDL_EVENT_GAMEPAD_TOUCHPAD_UP:
+ event3->gtouchpad.which = JoystickID2to3(event2->ctouchpad.which);
+ break;
+ case SDL_EVENT_GAMEPAD_SENSOR_UPDATE:
+ event3->gsensor.which = JoystickID2to3(event2->csensor.which);
+ event3->gsensor.sensor_timestamp = SDL_US_TO_NS(event2->csensor.timestamp_us);
break;
case SDL_EVENT_AUDIO_DEVICE_ADDED:
if (event2->adevice.iscapture) {
@@ -1880,6 +1956,10 @@ Event2to3(const SDL2_Event *event2, SDL_Event *event3)
}
}
break;
+ case SDL_EVENT_SENSOR_UPDATE:
+ event3->sensor.which = SensorID2to3(event2->sensor.which);
+ event3->sensor.sensor_timestamp = SDL_US_TO_NS(event2->sensor.timestamp_us);
+ break;
default:
break;
}
@@ -6197,12 +6277,24 @@ SDL_Quit(void)
GestureQuit();
}
+ if (joystick_instance_list) {
+ SDL3_free(joystick_instance_list);
+ joystick_instance_list = NULL;
+ }
+ num_joystick_instances = 0;
+
if (joystick_list) {
SDL3_free(joystick_list);
joystick_list = NULL;
}
num_joysticks = 0;
+ if (sensor_instance_list) {
+ SDL3_free(sensor_instance_list);
+ sensor_instance_list = NULL;
+ }
+ num_sensor_instances = 0;
+
if (sensor_list) {
SDL3_free(sensor_list);
sensor_list = NULL;
@@ -9140,8 +9232,46 @@ SDL_JoystickEventState(int state)
/* SDL3 dumped the index/instance difference for various devices. */
-static SDL_JoystickID
-GetJoystickInstanceFromIndex(int idx)
+static void AddJoystickID(SDL_JoystickID id)
+{
+ int i;
+ SDL_JoystickID *new_instance_list;
+
+ for (i = 0; i < num_joystick_instances; ++i) {
+ if (id == joystick_instance_list[i]) {
+ return;
+ }
+ }
+
+ /* Need to add this joystick to the instance list */
+ new_instance_list = (SDL_JoystickID *)SDL_realloc(joystick_instance_list, (num_joystick_instances + 1) * sizeof(*new_instance_list));
+ if (new_instance_list) {
+ joystick_instance_list = new_instance_list;
+ joystick_instance_list[num_joystick_instances++] = id;
+ }
+}
+
+static SDL_JoystickID JoystickID2to3(SDL2_JoystickID id)
+{
+ if (id >= 0 && id < num_joystick_instances) {
+ return joystick_instance_list[id];
+ }
+ return 0;
+}
+
+static SDL2_JoystickID JoystickID3to2(SDL_JoystickID id)
+{
+ SDL2_JoystickID i;
+
+ for (i = 0; i < num_joystick_instances; ++i) {
+ if (joystick_instance_list[i] == id) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static SDL_JoystickID GetJoystickInstanceFromIndex(int idx)
{
if ((idx < 0) || (idx >= num_joysticks)) {
SDL3_SetError("There are %d joysticks available", num_joysticks);
@@ -9155,17 +9285,21 @@ GetJoystickInstanceFromIndex(int idx)
SDL_DECLSPEC int SDLCALL
SDL_NumJoysticks(void)
{
+ int i;
SDL3_free(joystick_list);
joystick_list = SDL3_GetJoysticks(&num_joysticks);
if (joystick_list == NULL) {
num_joysticks = 0;
return -1;
}
+ for (i = 0; i < num_joysticks; ++i) {
+ AddJoystickID(joystick_list[i]);
+ }
return num_joysticks;
}
-static int
-GetIndexFromJoystickInstance(SDL_JoystickID jid) {
+static int GetIndexFromJoystickInstance(SDL_JoystickID jid)
+{
if (jid != 0) {
int i;
for (i = 0; i < num_joysticks; i++) {
@@ -9241,7 +9375,7 @@ SDL_JoystickGetDeviceInstanceID(int idx)
if (!jid) {
return -1;
}
- return (SDL2_JoystickID)jid;
+ return JoystickID3to2(jid);
}
SDL_DECLSPEC Uint8 SDLCALL
@@ -9257,19 +9391,19 @@ SDL_JoystickInstanceID(SDL_Joystick *joystick)
if (!jid) {
return -1;
}
- return (SDL2_JoystickID)jid;
+ return JoystickID3to2(jid);
}
SDL_DECLSPEC SDL_Joystick* SDLCALL
SDL_JoystickFromInstanceID(SDL2_JoystickID jid)
{
- return SDL3_GetJoystickFromID((SDL_JoystickID)jid);
+ return SDL3_GetJoystickFromID(JoystickID2to3(jid));
}
SDL_DECLSPEC SDL_GameController* SDLCALL
SDL_GameControllerFromInstanceID(SDL2_JoystickID jid)
{
- return SDL3_GetGamepadFromID((SDL_JoystickID)jid);
+ return SDL3_GetGamepadFromID(JoystickID2to3(jid));
}
SDL_DECLSPEC int SDLCALL
@@ -9693,8 +9827,46 @@ SDL_JoystickDetachVirtual(int device_index)
}
-static SDL_SensorID
-GetSensorInstanceFromIndex(int idx)
+static void AddSensorID(SDL_SensorID id)
+{
+ int i;
+ SDL_SensorID *new_instance_list;
+
+ for (i = 0; i < num_sensor_instances; ++i) {
+ if (id == sensor_instance_list[i]) {
+ return;
+ }
+ }
+
+ /* Need to add this sensor to the instance list */
+ new_instance_list = (SDL_SensorID *)SDL_realloc(sensor_instance_list, (num_sensor_instances + 1) * sizeof(*new_instance_list));
+ if (new_instance_list) {
+ sensor_instance_list = new_instance_list;
+ sensor_instance_list[num_sensor_instances++] = id;
+ }
+}
+
+static SDL_SensorID SensorID2to3(SDL2_SensorID id)
+{
+ if (id >= 0 && id < num_sensor_instances) {
+ return sensor_instance_list[id];
+ }
+ return 0;
+}
+
+static SDL2_SensorID SensorID3to2(SDL_SensorID id)
+{
+ SDL2_SensorID i;
+
+ for (i = 0; i < num_sensor_instances; ++i) {
+ if (sensor_instance_list[i] == id) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static SDL_SensorID GetSensorInstanceFromIndex(int idx)
{
if ((idx < 0) || (idx >= num_sensors)) {
SDL3_SetError("There are %d sensors available", num_sensors);
@@ -9706,12 +9878,17 @@ GetSensorInstanceFromIndex(int idx)
SDL_DECLSPEC int SDLCALL
SDL_NumSensors(void)
{
+ int i;
+
SDL3_free(sensor_list);
sensor_list = SDL3_GetSensors(&num_sensors);
if (sensor_list == NULL) {
num_sensors = 0;
return -1;
}
+ for (i = 0; i < num_sensors; ++i) {
+ AddSensorID(sensor_list[i]);
+ }
return num_sensors;
}
@@ -9744,7 +9921,7 @@ SDL_SensorGetDeviceInstanceID(int idx)
if (!sid) {
return -1;
}
- return (SDL2_SensorID)sid;
+ return SensorID3to2(sid);
}
SDL_DECLSPEC SDL2_SensorID SDLCALL
@@ -9754,13 +9931,13 @@ SDL_SensorGetInstanceID(SDL_Sensor *sensor)
if (!sid) {
return -1;
}
- return (SDL2_SensorID)sid;
+ return SensorID3to2(sid);
}
SDL_DECLSPEC SDL_Sensor* SDLCALL
SDL_SensorFromInstanceID(SDL2_SensorID sid)
{
- return SDL3_GetSensorFromID((SDL_SensorID)sid);
+ return SDL3_GetSensorFromID(SensorID2to3(sid));
}
SDL_DECLSPEC SDL_Sensor* SDLCALL