Split keyboard and mouse policy handling
Some checks are pending
Build / setup (push) Waiting to run
Build / build-appimage (push) Blocked by required conditions
Build / build-steamlink (push) Blocked by required conditions
Build / build-windows-macos (push) Blocked by required conditions

This commit is contained in:
Joey Yakimowich-Payne 2026-02-12 09:11:40 -07:00
commit 87f4e90ca2
7 changed files with 75 additions and 43 deletions

View file

@ -11,7 +11,7 @@
static bool isKeyboardMouseInputAllowed() static bool isKeyboardMouseInputAllowed()
{ {
auto session = Session::get(); 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 // How long the fingers must be stationary to start a right click

View file

@ -12,10 +12,10 @@ static bool isGamepadInputAllowed()
return session == nullptr || session->isGamepadInputAllowed(); return session == nullptr || session->isGamepadInputAllowed();
} }
static bool isKeyboardMouseInputAllowed() static bool isMouseInputAllowed()
{ {
auto session = Session::get(); 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 // 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; deltaX = qAbs(deltaX) > MOUSE_EMULATION_DEADZONE ? deltaX - MOUSE_EMULATION_DEADZONE : 0;
deltaY = qAbs(deltaY) > MOUSE_EMULATION_DEADZONE ? deltaY - 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); LiSendMouseMoveEvent((short)deltaX, (short)deltaY);
} }
@ -497,47 +497,47 @@ void SdlInputHandler::handleControllerButtonEvent(SDL_ControllerButtonEvent* eve
} }
else if (state->mouseEmulationTimer != 0) { else if (state->mouseEmulationTimer != 0) {
if (event->button == SDL_CONTROLLER_BUTTON_A) { if (event->button == SDL_CONTROLLER_BUTTON_A) {
if (isKeyboardMouseInputAllowed()) { if (isMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT); LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
} }
} }
else if (event->button == SDL_CONTROLLER_BUTTON_B) { else if (event->button == SDL_CONTROLLER_BUTTON_B) {
if (isKeyboardMouseInputAllowed()) { if (isMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT); LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
} }
} }
else if (event->button == SDL_CONTROLLER_BUTTON_X) { else if (event->button == SDL_CONTROLLER_BUTTON_X) {
if (isKeyboardMouseInputAllowed()) { if (isMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_MIDDLE); LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_MIDDLE);
} }
} }
else if (event->button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) { else if (event->button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
if (isKeyboardMouseInputAllowed()) { if (isMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_X1); LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_X1);
} }
} }
else if (event->button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) { else if (event->button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) {
if (isKeyboardMouseInputAllowed()) { if (isMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_X2); LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_X2);
} }
} }
else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_UP) { else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_UP) {
if (isKeyboardMouseInputAllowed()) { if (isMouseInputAllowed()) {
LiSendScrollEvent(1); LiSendScrollEvent(1);
} }
} }
else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) {
if (isKeyboardMouseInputAllowed()) { if (isMouseInputAllowed()) {
LiSendScrollEvent(-1); LiSendScrollEvent(-1);
} }
} }
else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) {
if (isKeyboardMouseInputAllowed()) { if (isMouseInputAllowed()) {
LiSendHScrollEvent(1); LiSendHScrollEvent(1);
} }
} }
else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) { else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) {
if (isKeyboardMouseInputAllowed()) { if (isMouseInputAllowed()) {
LiSendHScrollEvent(-1); LiSendHScrollEvent(-1);
} }
} }
@ -570,27 +570,27 @@ void SdlInputHandler::handleControllerButtonEvent(SDL_ControllerButtonEvent* eve
} }
else if (state->mouseEmulationTimer != 0) { else if (state->mouseEmulationTimer != 0) {
if (event->button == SDL_CONTROLLER_BUTTON_A) { if (event->button == SDL_CONTROLLER_BUTTON_A) {
if (isKeyboardMouseInputAllowed()) { if (isMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT); LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
} }
} }
else if (event->button == SDL_CONTROLLER_BUTTON_B) { else if (event->button == SDL_CONTROLLER_BUTTON_B) {
if (isKeyboardMouseInputAllowed()) { if (isMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT); LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
} }
} }
else if (event->button == SDL_CONTROLLER_BUTTON_X) { else if (event->button == SDL_CONTROLLER_BUTTON_X) {
if (isKeyboardMouseInputAllowed()) { if (isMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_MIDDLE); LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_MIDDLE);
} }
} }
else if (event->button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) { else if (event->button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
if (isKeyboardMouseInputAllowed()) { if (isMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_X1); LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_X1);
} }
} }
else if (event->button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) { else if (event->button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) {
if (isKeyboardMouseInputAllowed()) { if (isMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_X2); LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_X2);
} }
} }

View file

@ -16,7 +16,7 @@
static bool isKeyboardMouseInputAllowed() static bool isKeyboardMouseInputAllowed()
{ {
auto session = Session::get(); auto session = Session::get();
return session == nullptr || session->isKeyboardMouseInputAllowed(); return session == nullptr || session->isKeyboardInputAllowed();
} }
void SdlInputHandler::performSpecialKeyCombo(KeyCombo combo) void SdlInputHandler::performSpecialKeyCombo(KeyCombo combo)

View file

@ -8,7 +8,7 @@
static bool isKeyboardMouseInputAllowed() static bool isKeyboardMouseInputAllowed()
{ {
auto session = Session::get(); auto session = Session::get();
return session == nullptr || session->isKeyboardMouseInputAllowed(); return session == nullptr || session->isMouseInputAllowed();
} }
void SdlInputHandler::handleMouseButtonEvent(SDL_MouseButtonEvent* event) void SdlInputHandler::handleMouseButtonEvent(SDL_MouseButtonEvent* event)

View file

@ -9,7 +9,7 @@
static bool isKeyboardMouseInputAllowed() static bool isKeyboardMouseInputAllowed()
{ {
auto session = Session::get(); 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 // How long the mouse button will be pressed for a tap to click gesture

View file

@ -557,7 +557,8 @@ Session::Session(NvComputer* computer, NvApp& app, StreamingPreferences *prefere
m_ManualAudioMuted(false), m_ManualAudioMuted(false),
m_AudioVolumeScalar(1.0f), m_AudioVolumeScalar(1.0f),
m_AllowGamepadInput(true), m_AllowGamepadInput(true),
m_AllowKeyboardMouseInput(false), m_AllowKeyboardInput(false),
m_AllowMouseInput(false),
m_ControlPanelVisible(true), m_ControlPanelVisible(true),
m_ConnectionStatus(CONN_STATUS_OKAY), m_ConnectionStatus(CONN_STATUS_OKAY),
m_StatusOverlayGeneration(0), m_StatusOverlayGeneration(0),
@ -627,9 +628,13 @@ void Session::notifyAudioVolumeState()
void Session::setKeyboardMouseInputAllowed(bool allowed) void Session::setKeyboardMouseInputAllowed(bool allowed)
{ {
bool previous = m_AllowKeyboardMouseInput.exchange(allowed, std::memory_order_relaxed); const bool previousKeyboard = m_AllowKeyboardInput.exchange(allowed, std::memory_order_relaxed);
if (previous && !allowed && m_InputHandler != nullptr) { if (previousKeyboard && !allowed && m_InputHandler != nullptr) {
m_InputHandler->raiseAllKeys(); m_InputHandler->raiseAllKeys();
}
const bool previousMouse = m_AllowMouseInput.exchange(allowed, std::memory_order_relaxed);
if (previousMouse && !allowed && m_InputHandler != nullptr) {
m_InputHandler->raiseAllMouseButtons(); m_InputHandler->raiseAllMouseButtons();
} }
@ -656,11 +661,12 @@ void Session::toggleControlPanelVisibility()
void Session::notifyInputPermissionState() void Session::notifyInputPermissionState()
{ {
char buffer[96]; char buffer[160];
SDL_snprintf(buffer, SDL_snprintf(buffer,
sizeof(buffer), sizeof(buffer),
"Keyboard/Mouse: %s\nGamepad: %s", "Input policy: host controlled\nKeyboard: %s\nMouse: %s\nGamepad: %s",
isKeyboardMouseInputAllowed() ? "ON" : "OFF", isKeyboardInputAllowed() ? "ON" : "OFF",
isMouseInputAllowed() ? "ON" : "OFF",
isGamepadInputAllowed() ? "ON" : "OFF"); isGamepadInputAllowed() ? "ON" : "OFF");
showTemporaryStatusOverlay(buffer); showTemporaryStatusOverlay(buffer);
@ -668,10 +674,11 @@ void Session::notifyInputPermissionState()
void Session::sendInputPermissionStateToHost(uint8_t reason) void Session::sendInputPermissionStateToHost(uint8_t reason)
{ {
const bool allowKeyboardMouse = isKeyboardMouseInputAllowed(); const bool allowKeyboard = isKeyboardInputAllowed();
const bool allowMouse = isMouseInputAllowed();
const bool allowGamepad = isGamepadInputAllowed(); const bool allowGamepad = isGamepadInputAllowed();
const int err = LiSendSessionInputPolicy(allowKeyboardMouse, const int err = LiSendSessionInputPolicy(allowKeyboard,
allowKeyboardMouse, allowMouse,
allowGamepad, allowGamepad,
reason); reason);
@ -719,11 +726,14 @@ void Session::refreshControlPanelOverlay()
SDL_snprintf(panelText, SDL_snprintf(panelText,
sizeof(panelText), sizeof(panelText),
"Stream Controls\n" "Stream Controls\n"
"KB/M (Ctrl+Alt+Shift+K): %s\n" "Keyboard: %s\n"
"Pad (Ctrl+Alt+Shift+G): %s\n" "Mouse: %s\n"
"Pad: %s\n"
"Vol (U/J, mute N): %s\n" "Vol (U/J, mute N): %s\n"
"UI (Ctrl+Alt+Shift+P / Select+L1+R1+B): ON", "UI (Ctrl+Alt+Shift+P / Select+L1+R1+B): ON\n"
isKeyboardMouseInputAllowed() ? "ON" : "OFF", "Input policy: host controlled",
isKeyboardInputAllowed() ? "ON" : "OFF",
isMouseInputAllowed() ? "ON" : "OFF",
isGamepadInputAllowed() ? "ON" : "OFF", isGamepadInputAllowed() ? "ON" : "OFF",
volumeState); 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) void Session::applyHostInputPolicy(bool allowKeyboard, bool allowMouse, bool allowGamepad, uint8_t reason)
{ {
const bool allowKeyboardMouse = allowKeyboard && allowMouse; const bool previousKeyboard = m_AllowKeyboardInput.exchange(allowKeyboard, std::memory_order_relaxed);
const bool previousKeyboardMouse = m_AllowKeyboardMouseInput.exchange(allowKeyboardMouse, std::memory_order_relaxed); if (previousKeyboard && !allowKeyboard && m_InputHandler != nullptr) {
if (previousKeyboardMouse && !allowKeyboardMouse && m_InputHandler != nullptr) {
m_InputHandler->raiseAllKeys(); m_InputHandler->raiseAllKeys();
}
const bool previousMouse = m_AllowMouseInput.exchange(allowMouse, std::memory_order_relaxed);
if (previousMouse && !allowMouse && m_InputHandler != nullptr) {
m_InputHandler->raiseAllMouseButtons(); m_InputHandler->raiseAllMouseButtons();
} }
@ -786,11 +799,18 @@ void Session::applyHostInputPolicy(bool allowKeyboard, bool allowMouse, bool all
m_InputHandler->raiseAllGamepadInputs(); m_InputHandler->raiseAllGamepadInputs();
} }
if (reason != LI_SESSION_INPUT_POLICY_REASON_STREAM_START) { const bool policyChanged =
notifyInputPermissionState(); 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 { else {
refreshControlPanelOverlay(); notifyInputPermissionState();
} }
} }
@ -1975,7 +1995,8 @@ void Session::start()
s_ActiveSession = this; s_ActiveSession = this;
m_AllowGamepadInput.store(true, std::memory_order_relaxed); 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_ManualAudioMuted.store(false, std::memory_order_relaxed);
m_AudioMuted.store(false, std::memory_order_relaxed); m_AudioMuted.store(false, std::memory_order_relaxed);
m_AudioVolumeScalar.store(1.0f, std::memory_order_relaxed); m_AudioVolumeScalar.store(1.0f, std::memory_order_relaxed);

View file

@ -131,9 +131,19 @@ public:
return m_AllowGamepadInput.load(std::memory_order_relaxed); 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 bool isKeyboardMouseInputAllowed() const
{ {
return m_AllowKeyboardMouseInput.load(std::memory_order_relaxed); return isKeyboardInputAllowed() && isMouseInputAllowed();
} }
void setGamepadInputAllowed(bool allowed); void setGamepadInputAllowed(bool allowed);
@ -298,7 +308,8 @@ private:
std::atomic<bool> m_ManualAudioMuted; std::atomic<bool> m_ManualAudioMuted;
std::atomic<float> m_AudioVolumeScalar; std::atomic<float> m_AudioVolumeScalar;
std::atomic<bool> m_AllowGamepadInput; std::atomic<bool> m_AllowGamepadInput;
std::atomic<bool> m_AllowKeyboardMouseInput; std::atomic<bool> m_AllowKeyboardInput;
std::atomic<bool> m_AllowMouseInput;
std::atomic<bool> m_ControlPanelVisible; std::atomic<bool> m_ControlPanelVisible;
std::atomic<int> m_ConnectionStatus; std::atomic<int> m_ConnectionStatus;
std::atomic<uint32_t> m_StatusOverlayGeneration; std::atomic<uint32_t> m_StatusOverlayGeneration;