From 87f4e90ca25ba3880a4d1278a1fd615a3575d7c4 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Thu, 12 Feb 2026 09:11:40 -0700 Subject: [PATCH] Split keyboard and mouse policy handling --- app/streaming/input/abstouch.cpp | 2 +- app/streaming/input/gamepad.cpp | 34 +++++++++--------- app/streaming/input/keyboard.cpp | 2 +- app/streaming/input/mouse.cpp | 2 +- app/streaming/input/reltouch.cpp | 2 +- app/streaming/session.cpp | 61 +++++++++++++++++++++----------- app/streaming/session.h | 15 ++++++-- 7 files changed, 75 insertions(+), 43 deletions(-) diff --git a/app/streaming/input/abstouch.cpp b/app/streaming/input/abstouch.cpp index 9e8b51a9..6c8529a2 100644 --- a/app/streaming/input/abstouch.cpp +++ b/app/streaming/input/abstouch.cpp @@ -11,7 +11,7 @@ static bool isKeyboardMouseInputAllowed() { auto session = Session::get(); - return session == nullptr || session->isKeyboardMouseInputAllowed(); + return session == nullptr || session->isMouseInputAllowed(); } // How long the fingers must be stationary to start a right click diff --git a/app/streaming/input/gamepad.cpp b/app/streaming/input/gamepad.cpp index 810659fa..fdc896ab 100644 --- a/app/streaming/input/gamepad.cpp +++ b/app/streaming/input/gamepad.cpp @@ -12,10 +12,10 @@ static bool isGamepadInputAllowed() return session == nullptr || session->isGamepadInputAllowed(); } -static bool isKeyboardMouseInputAllowed() +static bool isMouseInputAllowed() { auto session = Session::get(); - return session == nullptr || session->isKeyboardMouseInputAllowed(); + return session == nullptr || session->isMouseInputAllowed(); } // How long the Start button must be pressed to toggle mouse emulation @@ -387,7 +387,7 @@ Uint32 SdlInputHandler::mouseEmulationTimerCallback(Uint32 interval, void *param deltaX = qAbs(deltaX) > MOUSE_EMULATION_DEADZONE ? deltaX - MOUSE_EMULATION_DEADZONE : 0; deltaY = qAbs(deltaY) > MOUSE_EMULATION_DEADZONE ? deltaY - MOUSE_EMULATION_DEADZONE : 0; - if ((deltaX != 0 || deltaY != 0) && isKeyboardMouseInputAllowed()) { + if ((deltaX != 0 || deltaY != 0) && isMouseInputAllowed()) { LiSendMouseMoveEvent((short)deltaX, (short)deltaY); } @@ -497,47 +497,47 @@ void SdlInputHandler::handleControllerButtonEvent(SDL_ControllerButtonEvent* eve } else if (state->mouseEmulationTimer != 0) { if (event->button == SDL_CONTROLLER_BUTTON_A) { - if (isKeyboardMouseInputAllowed()) { + if (isMouseInputAllowed()) { LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT); } } else if (event->button == SDL_CONTROLLER_BUTTON_B) { - if (isKeyboardMouseInputAllowed()) { + if (isMouseInputAllowed()) { LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT); } } else if (event->button == SDL_CONTROLLER_BUTTON_X) { - if (isKeyboardMouseInputAllowed()) { + if (isMouseInputAllowed()) { LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_MIDDLE); } } else if (event->button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) { - if (isKeyboardMouseInputAllowed()) { + if (isMouseInputAllowed()) { LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_X1); } } else if (event->button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) { - if (isKeyboardMouseInputAllowed()) { + if (isMouseInputAllowed()) { LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_X2); } } else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_UP) { - if (isKeyboardMouseInputAllowed()) { + if (isMouseInputAllowed()) { LiSendScrollEvent(1); } } else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { - if (isKeyboardMouseInputAllowed()) { + if (isMouseInputAllowed()) { LiSendScrollEvent(-1); } } else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { - if (isKeyboardMouseInputAllowed()) { + if (isMouseInputAllowed()) { LiSendHScrollEvent(1); } } else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) { - if (isKeyboardMouseInputAllowed()) { + if (isMouseInputAllowed()) { LiSendHScrollEvent(-1); } } @@ -570,27 +570,27 @@ void SdlInputHandler::handleControllerButtonEvent(SDL_ControllerButtonEvent* eve } else if (state->mouseEmulationTimer != 0) { if (event->button == SDL_CONTROLLER_BUTTON_A) { - if (isKeyboardMouseInputAllowed()) { + if (isMouseInputAllowed()) { LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT); } } else if (event->button == SDL_CONTROLLER_BUTTON_B) { - if (isKeyboardMouseInputAllowed()) { + if (isMouseInputAllowed()) { LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT); } } else if (event->button == SDL_CONTROLLER_BUTTON_X) { - if (isKeyboardMouseInputAllowed()) { + if (isMouseInputAllowed()) { LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_MIDDLE); } } else if (event->button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) { - if (isKeyboardMouseInputAllowed()) { + if (isMouseInputAllowed()) { LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_X1); } } else if (event->button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) { - if (isKeyboardMouseInputAllowed()) { + if (isMouseInputAllowed()) { LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_X2); } } diff --git a/app/streaming/input/keyboard.cpp b/app/streaming/input/keyboard.cpp index 7d5a03c4..ed12a6f2 100644 --- a/app/streaming/input/keyboard.cpp +++ b/app/streaming/input/keyboard.cpp @@ -16,7 +16,7 @@ static bool isKeyboardMouseInputAllowed() { auto session = Session::get(); - return session == nullptr || session->isKeyboardMouseInputAllowed(); + return session == nullptr || session->isKeyboardInputAllowed(); } void SdlInputHandler::performSpecialKeyCombo(KeyCombo combo) diff --git a/app/streaming/input/mouse.cpp b/app/streaming/input/mouse.cpp index c86eae54..d452ed07 100644 --- a/app/streaming/input/mouse.cpp +++ b/app/streaming/input/mouse.cpp @@ -8,7 +8,7 @@ static bool isKeyboardMouseInputAllowed() { auto session = Session::get(); - return session == nullptr || session->isKeyboardMouseInputAllowed(); + return session == nullptr || session->isMouseInputAllowed(); } void SdlInputHandler::handleMouseButtonEvent(SDL_MouseButtonEvent* event) diff --git a/app/streaming/input/reltouch.cpp b/app/streaming/input/reltouch.cpp index 1649f1c1..6269537f 100644 --- a/app/streaming/input/reltouch.cpp +++ b/app/streaming/input/reltouch.cpp @@ -9,7 +9,7 @@ static bool isKeyboardMouseInputAllowed() { auto session = Session::get(); - return session == nullptr || session->isKeyboardMouseInputAllowed(); + return session == nullptr || session->isMouseInputAllowed(); } // How long the mouse button will be pressed for a tap to click gesture diff --git a/app/streaming/session.cpp b/app/streaming/session.cpp index 7d27e095..c4d1d455 100644 --- a/app/streaming/session.cpp +++ b/app/streaming/session.cpp @@ -557,7 +557,8 @@ Session::Session(NvComputer* computer, NvApp& app, StreamingPreferences *prefere m_ManualAudioMuted(false), m_AudioVolumeScalar(1.0f), m_AllowGamepadInput(true), - m_AllowKeyboardMouseInput(false), + m_AllowKeyboardInput(false), + m_AllowMouseInput(false), m_ControlPanelVisible(true), m_ConnectionStatus(CONN_STATUS_OKAY), m_StatusOverlayGeneration(0), @@ -627,9 +628,13 @@ void Session::notifyAudioVolumeState() void Session::setKeyboardMouseInputAllowed(bool allowed) { - bool previous = m_AllowKeyboardMouseInput.exchange(allowed, std::memory_order_relaxed); - if (previous && !allowed && m_InputHandler != nullptr) { + const bool previousKeyboard = m_AllowKeyboardInput.exchange(allowed, std::memory_order_relaxed); + if (previousKeyboard && !allowed && m_InputHandler != nullptr) { m_InputHandler->raiseAllKeys(); + } + + const bool previousMouse = m_AllowMouseInput.exchange(allowed, std::memory_order_relaxed); + if (previousMouse && !allowed && m_InputHandler != nullptr) { m_InputHandler->raiseAllMouseButtons(); } @@ -656,11 +661,12 @@ void Session::toggleControlPanelVisibility() void Session::notifyInputPermissionState() { - char buffer[96]; + char buffer[160]; SDL_snprintf(buffer, sizeof(buffer), - "Keyboard/Mouse: %s\nGamepad: %s", - isKeyboardMouseInputAllowed() ? "ON" : "OFF", + "Input policy: host controlled\nKeyboard: %s\nMouse: %s\nGamepad: %s", + isKeyboardInputAllowed() ? "ON" : "OFF", + isMouseInputAllowed() ? "ON" : "OFF", isGamepadInputAllowed() ? "ON" : "OFF"); showTemporaryStatusOverlay(buffer); @@ -668,10 +674,11 @@ void Session::notifyInputPermissionState() void Session::sendInputPermissionStateToHost(uint8_t reason) { - const bool allowKeyboardMouse = isKeyboardMouseInputAllowed(); + const bool allowKeyboard = isKeyboardInputAllowed(); + const bool allowMouse = isMouseInputAllowed(); const bool allowGamepad = isGamepadInputAllowed(); - const int err = LiSendSessionInputPolicy(allowKeyboardMouse, - allowKeyboardMouse, + const int err = LiSendSessionInputPolicy(allowKeyboard, + allowMouse, allowGamepad, reason); @@ -719,11 +726,14 @@ void Session::refreshControlPanelOverlay() SDL_snprintf(panelText, sizeof(panelText), "Stream Controls\n" - "KB/M (Ctrl+Alt+Shift+K): %s\n" - "Pad (Ctrl+Alt+Shift+G): %s\n" + "Keyboard: %s\n" + "Mouse: %s\n" + "Pad: %s\n" "Vol (U/J, mute N): %s\n" - "UI (Ctrl+Alt+Shift+P / Select+L1+R1+B): ON", - isKeyboardMouseInputAllowed() ? "ON" : "OFF", + "UI (Ctrl+Alt+Shift+P / Select+L1+R1+B): ON\n" + "Input policy: host controlled", + isKeyboardInputAllowed() ? "ON" : "OFF", + isMouseInputAllowed() ? "ON" : "OFF", isGamepadInputAllowed() ? "ON" : "OFF", volumeState); @@ -774,10 +784,13 @@ void Session::showTemporaryStatusOverlay(const char* text, Uint32 timeoutMs) void Session::applyHostInputPolicy(bool allowKeyboard, bool allowMouse, bool allowGamepad, uint8_t reason) { - const bool allowKeyboardMouse = allowKeyboard && allowMouse; - const bool previousKeyboardMouse = m_AllowKeyboardMouseInput.exchange(allowKeyboardMouse, std::memory_order_relaxed); - if (previousKeyboardMouse && !allowKeyboardMouse && m_InputHandler != nullptr) { + const bool previousKeyboard = m_AllowKeyboardInput.exchange(allowKeyboard, std::memory_order_relaxed); + if (previousKeyboard && !allowKeyboard && m_InputHandler != nullptr) { m_InputHandler->raiseAllKeys(); + } + + const bool previousMouse = m_AllowMouseInput.exchange(allowMouse, std::memory_order_relaxed); + if (previousMouse && !allowMouse && m_InputHandler != nullptr) { m_InputHandler->raiseAllMouseButtons(); } @@ -786,11 +799,18 @@ void Session::applyHostInputPolicy(bool allowKeyboard, bool allowMouse, bool all m_InputHandler->raiseAllGamepadInputs(); } - if (reason != LI_SESSION_INPUT_POLICY_REASON_STREAM_START) { - notifyInputPermissionState(); + const bool policyChanged = + previousKeyboard != allowKeyboard || + previousMouse != allowMouse || + previousGamepad != allowGamepad; + if (reason == LI_SESSION_INPUT_POLICY_REASON_STREAM_START || + reason == LI_SESSION_INPUT_POLICY_REASON_HOST_ACK || + reason == LI_SESSION_INPUT_POLICY_REASON_HOST_OVERRIDE || + !policyChanged) { + refreshControlPanelOverlay(); } else { - refreshControlPanelOverlay(); + notifyInputPermissionState(); } } @@ -1975,7 +1995,8 @@ void Session::start() s_ActiveSession = this; m_AllowGamepadInput.store(true, std::memory_order_relaxed); - m_AllowKeyboardMouseInput.store(false, std::memory_order_relaxed); + m_AllowKeyboardInput.store(false, std::memory_order_relaxed); + m_AllowMouseInput.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); diff --git a/app/streaming/session.h b/app/streaming/session.h index 13eca494..856e4aac 100644 --- a/app/streaming/session.h +++ b/app/streaming/session.h @@ -131,9 +131,19 @@ public: return m_AllowGamepadInput.load(std::memory_order_relaxed); } + bool isKeyboardInputAllowed() const + { + return m_AllowKeyboardInput.load(std::memory_order_relaxed); + } + + bool isMouseInputAllowed() const + { + return m_AllowMouseInput.load(std::memory_order_relaxed); + } + bool isKeyboardMouseInputAllowed() const { - return m_AllowKeyboardMouseInput.load(std::memory_order_relaxed); + return isKeyboardInputAllowed() && isMouseInputAllowed(); } void setGamepadInputAllowed(bool allowed); @@ -298,7 +308,8 @@ private: std::atomic m_ManualAudioMuted; std::atomic m_AudioVolumeScalar; std::atomic m_AllowGamepadInput; - std::atomic m_AllowKeyboardMouseInput; + std::atomic m_AllowKeyboardInput; + std::atomic m_AllowMouseInput; std::atomic m_ControlPanelVisible; std::atomic m_ConnectionStatus; std::atomic m_StatusOverlayGeneration;