From ca41cf32cc8ddb683bca827db1ae543394c724bd Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Thu, 12 Feb 2026 01:44:04 -0700 Subject: [PATCH] Clean up stale detached gamepads before hotplug reattach --- app/streaming/input/gamepad.cpp | 21 +++++++++++++++++++++ app/streaming/input/input.h | 2 ++ 2 files changed, 23 insertions(+) diff --git a/app/streaming/input/gamepad.cpp b/app/streaming/input/gamepad.cpp index 86ff3996..70854dd1 100644 --- a/app/streaming/input/gamepad.cpp +++ b/app/streaming/input/gamepad.cpp @@ -63,6 +63,25 @@ SdlInputHandler::findStateForGamepad(SDL_JoystickID id) return nullptr; } +void SdlInputHandler::cleanupDetachedGamepads() +{ + for (int i = 0; i < MAX_GAMEPADS; i++) { + if (m_GamepadState[i].controller == nullptr || + SDL_GameControllerGetAttached(m_GamepadState[i].controller)) { + continue; + } + + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, + "Found detached gamepad in slot %d without removal event; cleaning up", + i); + + SDL_ControllerDeviceEvent controllerEvent = {}; + controllerEvent.type = SDL_CONTROLLERDEVICEREMOVED; + controllerEvent.which = m_GamepadState[i].jsId; + handleControllerDeviceEvent(&controllerEvent); + } +} + void SdlInputHandler::sendGamepadState(GamepadState* state) { SDL_assert(m_GamepadMask == 0x1 || m_MultiController); @@ -582,6 +601,8 @@ void SdlInputHandler::handleControllerDeviceEvent(SDL_ControllerDeviceEvent* eve GamepadState* state; if (event->type == SDL_CONTROLLERDEVICEADDED) { + cleanupDetachedGamepads(); + int i; const char* name; SDL_GameController* controller; diff --git a/app/streaming/input/input.h b/app/streaming/input/input.h index 4bcdd2de..2cab20f7 100644 --- a/app/streaming/input/input.h +++ b/app/streaming/input/input.h @@ -185,6 +185,8 @@ private: GamepadState* findStateForGamepad(SDL_JoystickID id); + void cleanupDetachedGamepads(); + void sendGamepadState(GamepadState* state); void sendGamepadBatteryState(GamepadState* state, SDL_JoystickPowerLevel level);