From e00558780649b7082eba1161ca6a5f50ed855873 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Thu, 12 Feb 2026 02:00:45 -0700 Subject: [PATCH] Recover gamepad state when add events are missed --- app/streaming/input/gamepad.cpp | 44 +++++++++++++++++++++++++++++---- app/streaming/input/input.h | 3 +++ 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/app/streaming/input/gamepad.cpp b/app/streaming/input/gamepad.cpp index d6a05902..2a4038a7 100644 --- a/app/streaming/input/gamepad.cpp +++ b/app/streaming/input/gamepad.cpp @@ -63,6 +63,40 @@ SdlInputHandler::findStateForGamepad(SDL_JoystickID id) return nullptr; } +GamepadState* +SdlInputHandler::ensureStateForGamepad(SDL_JoystickID id) +{ + GamepadState* state = findStateForGamepad(id); + if (state != nullptr) { + return state; + } + + cleanupDetachedGamepads(); + + const int joystickCount = SDL_NumJoysticks(); + for (int deviceIndex = 0; deviceIndex < joystickCount; deviceIndex++) { + if (!SDL_IsGameController(deviceIndex)) { + continue; + } + + if (SDL_JoystickGetDeviceInstanceID(deviceIndex) != id) { + continue; + } + + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, + "Recovering gamepad state for missing add event (instance ID: %d)", + id); + + SDL_ControllerDeviceEvent controllerEvent = {}; + controllerEvent.type = SDL_CONTROLLERDEVICEADDED; + controllerEvent.which = deviceIndex; + handleControllerDeviceEvent(&controllerEvent); + break; + } + + return findStateForGamepad(id); +} + void SdlInputHandler::cleanupDetachedGamepads() { for (int i = 0; i < MAX_GAMEPADS; i++) { @@ -226,7 +260,7 @@ Uint32 SdlInputHandler::mouseEmulationTimerCallback(Uint32 interval, void *param void SdlInputHandler::handleControllerAxisEvent(SDL_ControllerAxisEvent* event) { SDL_JoystickID gameControllerId = event->which; - GamepadState* state = findStateForGamepad(gameControllerId); + GamepadState* state = ensureStateForGamepad(gameControllerId); if (state == NULL) { return; } @@ -296,7 +330,7 @@ void SdlInputHandler::handleControllerButtonEvent(SDL_ControllerButtonEvent* eve return; } - GamepadState* state = findStateForGamepad(event->which); + GamepadState* state = ensureStateForGamepad(event->which); if (state == NULL) { return; } @@ -516,7 +550,7 @@ void SdlInputHandler::handleControllerButtonEvent(SDL_ControllerButtonEvent* eve void SdlInputHandler::handleControllerSensorEvent(SDL_ControllerSensorEvent* event) { - GamepadState* state = findStateForGamepad(event->which); + GamepadState* state = ensureStateForGamepad(event->which); if (state == NULL) { return; } @@ -555,7 +589,7 @@ void SdlInputHandler::handleControllerSensorEvent(SDL_ControllerSensorEvent* eve void SdlInputHandler::handleControllerTouchpadEvent(SDL_ControllerTouchpadEvent* event) { - GamepadState* state = findStateForGamepad(event->which); + GamepadState* state = ensureStateForGamepad(event->which); if (state == NULL) { return; } @@ -586,7 +620,7 @@ void SdlInputHandler::handleControllerTouchpadEvent(SDL_ControllerTouchpadEvent* void SdlInputHandler::handleJoystickBatteryEvent(SDL_JoyBatteryEvent* event) { - GamepadState* state = findStateForGamepad(event->which); + GamepadState* state = ensureStateForGamepad(event->which); if (state == NULL) { return; } diff --git a/app/streaming/input/input.h b/app/streaming/input/input.h index 2cab20f7..c306441c 100644 --- a/app/streaming/input/input.h +++ b/app/streaming/input/input.h @@ -185,6 +185,9 @@ private: GamepadState* findStateForGamepad(SDL_JoystickID id); + GamepadState* + ensureStateForGamepad(SDL_JoystickID id); + void cleanupDetachedGamepads(); void sendGamepadState(GamepadState* state);