From e88be5dce229debaeedfaa49ef817fdc3cec57eb Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Thu, 12 Feb 2026 01:36:36 -0700 Subject: [PATCH] Align input policy startup flow and fix gamepad reconnect handling --- app/streaming/input/gamepad.cpp | 14 +++++++++++++ app/streaming/input/input.cpp | 35 +++++++++++++++++++++++++++++++++ app/streaming/input/input.h | 4 ++++ app/streaming/session.cpp | 16 +++++++++++---- 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/app/streaming/input/gamepad.cpp b/app/streaming/input/gamepad.cpp index 94625f6c..86ff3996 100644 --- a/app/streaming/input/gamepad.cpp +++ b/app/streaming/input/gamepad.cpp @@ -890,6 +890,20 @@ void SdlInputHandler::handleJoystickArrivalEvent(SDL_JoyDeviceEvent* event) } } +void SdlInputHandler::handleJoystickRemovalEvent(SDL_JoyDeviceEvent* event) +{ + SDL_assert(event->type == SDL_JOYDEVICEREMOVED); + + if (findStateForGamepad(event->which) == nullptr) { + return; + } + + SDL_ControllerDeviceEvent controllerEvent = {}; + controllerEvent.type = SDL_CONTROLLERDEVICEREMOVED; + controllerEvent.which = event->which; + handleControllerDeviceEvent(&controllerEvent); +} + void SdlInputHandler::rumble(unsigned short controllerNumber, unsigned short lowFreqMotor, unsigned short highFreqMotor) { // Make sure the controller number is within our supported count diff --git a/app/streaming/input/input.cpp b/app/streaming/input/input.cpp index 819519a0..c5f8f95b 100644 --- a/app/streaming/input/input.cpp +++ b/app/streaming/input/input.cpp @@ -307,6 +307,41 @@ void SdlInputHandler::raiseAllMouseButtons() LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_X2); } +void SdlInputHandler::raiseAllGamepadInputs() +{ + uint16_t raisedIndexMask = 0; + + for (auto &state : m_GamepadState) { + if (state.controller == nullptr) { + continue; + } + + state.buttons = 0; + state.lt = 0; + state.rt = 0; + state.lsX = 0; + state.lsY = 0; + state.rsX = 0; + state.rsY = 0; + state.emulatedClickpadButtonDown = false; + + if ((raisedIndexMask & (1 << state.index)) != 0) { + continue; + } + + LiSendMultiControllerEvent(state.index, + m_GamepadMask, + 0, + 0, + 0, + 0, + 0, + 0, + 0); + raisedIndexMask |= (1 << state.index); + } +} + void SdlInputHandler::notifyMouseLeave() { // SDL on Windows doesn't send the mouse button up until the mouse re-enters the window diff --git a/app/streaming/input/input.h b/app/streaming/input/input.h index 780e0383..4bcdd2de 100644 --- a/app/streaming/input/input.h +++ b/app/streaming/input/input.h @@ -116,6 +116,8 @@ public: void handleJoystickArrivalEvent(SDL_JoyDeviceEvent* event); + void handleJoystickRemovalEvent(SDL_JoyDeviceEvent* event); + void sendText(QString& string); void rumble(uint16_t controllerNumber, uint16_t lowFreqMotor, uint16_t highFreqMotor); @@ -136,6 +138,8 @@ public: void raiseAllMouseButtons(); + void raiseAllGamepadInputs(); + void notifyMouseLeave(); void notifyFocusLost(); diff --git a/app/streaming/session.cpp b/app/streaming/session.cpp index 57ba29b1..c2a6b380 100644 --- a/app/streaming/session.cpp +++ b/app/streaming/session.cpp @@ -579,6 +579,10 @@ Session::Session(NvComputer* computer, NvApp& app, StreamingPreferences *prefere void Session::setGamepadInputAllowed(bool allowed) { + if (!allowed && m_InputHandler != nullptr) { + m_InputHandler->raiseAllGamepadInputs(); + } + m_AllowGamepadInput.store(allowed, std::memory_order_relaxed); sendInputPermissionStateToHost(LI_SESSION_INPUT_POLICY_REASON_USER_TOGGLE); notifyInputPermissionState(); @@ -777,7 +781,10 @@ void Session::applyHostInputPolicy(bool allowKeyboard, bool allowMouse, bool all m_InputHandler->raiseAllMouseButtons(); } - m_AllowGamepadInput.store(allowGamepad, std::memory_order_relaxed); + const bool previousGamepad = m_AllowGamepadInput.exchange(allowGamepad, std::memory_order_relaxed); + if (previousGamepad && !allowGamepad && m_InputHandler != nullptr) { + m_InputHandler->raiseAllGamepadInputs(); + } if (reason != LI_SESSION_INPUT_POLICY_REASON_STREAM_START) { notifyInputPermissionState(); @@ -1925,8 +1932,6 @@ bool Session::startConnectionAsync() return false; } - sendInputPermissionStateToHost(LI_SESSION_INPUT_POLICY_REASON_STREAM_START); - emit connectionStarted(); return true; } @@ -1970,7 +1975,7 @@ void Session::start() s_ActiveSession = this; m_AllowGamepadInput.store(true, std::memory_order_relaxed); - m_AllowKeyboardMouseInput.store(true, std::memory_order_relaxed); + m_AllowKeyboardMouseInput.store(false, std::memory_order_relaxed); m_ManualAudioMuted.store(false, std::memory_order_relaxed); m_AudioMuted.store(false, std::memory_order_relaxed); m_AudioVolumeScalar.store(1.0f, std::memory_order_relaxed); @@ -2530,6 +2535,9 @@ void Session::exec() case SDL_JOYDEVICEADDED: m_InputHandler->handleJoystickArrivalEvent(&event.jdevice); break; + case SDL_JOYDEVICEREMOVED: + m_InputHandler->handleJoystickRemovalEvent(&event.jdevice); + break; case SDL_FINGERDOWN: case SDL_FINGERMOTION: case SDL_FINGERUP: