From 4dc33f975cb90fa39c418656f252b446c33cd18b Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 9 Mar 2025 09:53:54 -0700
Subject: [PATCH] Fixed crash during controller hotplug in RetroArch
RetroArch calls SDL_PumpEvents() followed by SDL_PeepEvents(), so we need to update the joystick list inside of Event3to2(). This event doesn't happen often, so this should be fine.
---
src/sdl2_compat.c | 33 ++++++++++++++++++---------------
1 file changed, 18 insertions(+), 15 deletions(-)
diff --git a/src/sdl2_compat.c b/src/sdl2_compat.c
index 0fe3aac..f381b48 100644
--- a/src/sdl2_compat.c
+++ b/src/sdl2_compat.c
@@ -2211,9 +2211,17 @@ static SDL2_Event *Event3to2(const SDL_Event *event3, SDL2_Event *event2)
event2->jbutton.which = JoystickID3to2(event3->jbutton.which);
break;
case SDL_EVENT_JOYSTICK_ADDED:
+ SDL_NumJoysticks(); /* Refresh */
+ SDL_NumHaptics(); /* Refresh */
event2->jdevice.which = GetIndexFromJoystickInstance(event3->jdevice.which);
+ if (event2->jdevice.which < 0) {
+ /* Applications like RetroArch assume the index is always valid */
+ event2->jdevice.which = 0;
+ }
break;
case SDL_EVENT_JOYSTICK_REMOVED:
+ SDL_NumJoysticks(); /* Refresh */
+ SDL_NumHaptics(); /* Refresh */
event2->jdevice.which = JoystickID3to2(event3->jdevice.which);
break;
case SDL_EVENT_JOYSTICK_BATTERY_UPDATED:
@@ -2250,9 +2258,17 @@ static SDL2_Event *Event3to2(const SDL_Event *event3, SDL2_Event *event2)
}
break;
case SDL_EVENT_GAMEPAD_ADDED:
+ /* Refresh the joystick list here in case the joystick added event is ignored */
+ SDL_NumJoysticks(); /* Refresh */
+ SDL_NumHaptics(); /* Refresh */
event2->cdevice.which = GetIndexFromJoystickInstance(event3->gdevice.which);
break;
case SDL_EVENT_GAMEPAD_REMOVED:
+ /* Refresh the joystick list here in case the joystick removed event is ignored */
+ SDL_NumJoysticks(); /* Refresh */
+ SDL_NumHaptics(); /* Refresh */
+ event2->cdevice.which = JoystickID3to2(event3->gdevice.which);
+ break;
case SDL_EVENT_GAMEPAD_REMAPPED:
case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED:
event2->cdevice.which = JoystickID3to2(event3->gdevice.which);
@@ -2268,9 +2284,11 @@ static SDL2_Event *Event3to2(const SDL_Event *event3, SDL2_Event *event2)
event2->csensor.timestamp_us = SDL_NS_TO_US(event3->gsensor.sensor_timestamp);
break;
case SDL_EVENT_AUDIO_DEVICE_ADDED:
+ SDL_GetNumAudioDevices(event3->adevice.recording ? SDL2_TRUE : SDL2_FALSE); /* Refresh */
event2->adevice.which = GetIndexFromAudioDeviceInstance(event3->adevice.which, event3->adevice.recording);
break;
case SDL_EVENT_AUDIO_DEVICE_REMOVED:
+ SDL_GetNumAudioDevices(event3->adevice.recording ? SDL2_TRUE : SDL2_FALSE); /* Refresh */
event2->adevice.which = AudioDeviceID3to2(event3->adevice.which);
break;
case SDL_EVENT_SENSOR_UPDATE:
@@ -2804,21 +2822,6 @@ SDL_WaitEventTimeout(SDL2_Event *event2, int timeout)
SDL_Event event3;
const int retval = SDL3_WaitEventTimeout(event2 ? &event3 : NULL, timeout);
if ((retval == 1) && event2) {
- /* Ensure joystick and haptic IDs are updated before calling Event3to2() */
- switch (event3.type) {
- case SDL_EVENT_JOYSTICK_ADDED:
- case SDL_EVENT_GAMEPAD_ADDED:
- case SDL_EVENT_GAMEPAD_REMOVED:
- case SDL_EVENT_JOYSTICK_REMOVED:
- SDL_NumJoysticks(); /* Refresh */
- SDL_NumHaptics(); /* Refresh */
- break;
-
- case SDL_EVENT_AUDIO_DEVICE_ADDED:
- case SDL_EVENT_AUDIO_DEVICE_REMOVED:
- SDL_GetNumAudioDevices(event3.adevice.recording ? SDL2_TRUE : SDL2_FALSE); /* Refresh */
- break;
- }
Event3to2(&event3, event2);
}
return retval;