From ccefce8321a676e7047401735e3bced4037a8f6d Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 18 Jul 2023 09:01:14 -0700
Subject: [PATCH] Send gamepad and joystick removed events when quitting
This helps applications do proper cleanup when reinitializing gamepads, e.g. to reset controller mappings
---
src/joystick/SDL_gamepad.c | 44 +++++++++++++++++++++++--------------
src/joystick/SDL_joystick.c | 10 ++++++++-
2 files changed, 37 insertions(+), 17 deletions(-)
diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c
index dc6d74c6314d..3147caa07a8a 100644
--- a/src/joystick/SDL_gamepad.c
+++ b/src/joystick/SDL_gamepad.c
@@ -178,6 +178,26 @@ static GamepadMapping_t *SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, co
static int SDL_SendGamepadAxis(Uint64 timestamp, SDL_Gamepad *gamepad, SDL_GamepadAxis axis, Sint16 value);
static int SDL_SendGamepadButton(Uint64 timestamp, SDL_Gamepad *gamepad, SDL_GamepadButton button, Uint8 state);
+static void SDL_PrivateGamepadAdded(SDL_JoystickID instance_id)
+{
+ SDL_Event event;
+
+ event.type = SDL_EVENT_GAMEPAD_ADDED;
+ event.common.timestamp = 0;
+ event.gdevice.which = instance_id;
+ SDL_PushEvent(&event);
+}
+
+static void SDL_PrivateGamepadRemoved(SDL_JoystickID instance_id)
+{
+ SDL_Event event;
+
+ event.type = SDL_EVENT_GAMEPAD_REMOVED;
+ event.common.timestamp = 0;
+ event.gdevice.which = instance_id;
+ SDL_PushEvent(&event);
+}
+
static SDL_bool HasSameOutput(SDL_GamepadBinding *a, SDL_GamepadBinding *b)
{
if (a->outputType != b->outputType) {
@@ -374,12 +394,7 @@ static int SDLCALL SDL_GamepadEventWatcher(void *userdata, SDL_Event *event)
case SDL_EVENT_JOYSTICK_ADDED:
{
if (SDL_IsGamepad(event->jdevice.which)) {
- SDL_Event deviceevent;
-
- deviceevent.type = SDL_EVENT_GAMEPAD_ADDED;
- deviceevent.common.timestamp = 0;
- deviceevent.gdevice.which = event->jdevice.which;
- SDL_PushEvent(&deviceevent);
+ SDL_PrivateGamepadAdded(event->jdevice.which);
}
} break;
case SDL_EVENT_JOYSTICK_REMOVED:
@@ -393,14 +408,8 @@ static int SDLCALL SDL_GamepadEventWatcher(void *userdata, SDL_Event *event)
}
}
- /* We don't know if this was a gamepad, so go ahead and send an event */
- {
- SDL_Event deviceevent;
-
- deviceevent.type = SDL_EVENT_GAMEPAD_REMOVED;
- deviceevent.common.timestamp = 0;
- deviceevent.gdevice.which = event->jdevice.which;
- SDL_PushEvent(&deviceevent);
+ if (SDL_IsGamepad(event->jdevice.which)) {
+ SDL_PrivateGamepadRemoved(event->jdevice.which);
}
} break;
case SDL_EVENT_JOYSTICK_UPDATE_COMPLETE:
@@ -3135,10 +3144,15 @@ void SDL_CloseGamepad(SDL_Gamepad *gamepad)
void SDL_QuitGamepads(void)
{
SDL_LockJoysticks();
+
+ SDL_DelEventWatch(SDL_GamepadEventWatcher, NULL);
+
while (SDL_gamepads) {
+ SDL_PrivateGamepadRemoved(SDL_gamepads->joystick->instance_id);
SDL_gamepads->ref_count = 1;
SDL_CloseGamepad(SDL_gamepads);
}
+
SDL_UnlockJoysticks();
}
@@ -3156,8 +3170,6 @@ void SDL_QuitGamepadMappings(void)
SDL_free(pGamepadMap);
}
- SDL_DelEventWatch(SDL_GamepadEventWatcher, NULL);
-
SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES,
SDL_GamepadIgnoreDevicesChanged, NULL);
SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT,
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index e2373fba90bc..4fcd547a618a 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -1501,12 +1501,20 @@ void SDL_CloseJoystick(SDL_Joystick *joystick)
void SDL_QuitJoysticks(void)
{
int i;
+ SDL_JoystickID *joysticks;
SDL_LockJoysticks();
SDL_joysticks_quitting = SDL_TRUE;
- /* Stop the event polling */
+ joysticks = SDL_GetJoysticks(NULL);
+ if (joysticks) {
+ for (i = 0; joysticks[i]; ++i) {
+ SDL_PrivateJoystickRemoved(joysticks[i]);
+ }
+ SDL_free(joysticks);
+ }
+
while (SDL_joysticks) {
SDL_joysticks->ref_count = 1;
SDL_CloseJoystick(SDL_joysticks);