Finalize session input policy host sync
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 00:38:05 -07:00
commit 7e9a4add09
5 changed files with 81 additions and 3 deletions

View file

@ -29,6 +29,7 @@
#define SDL_CODE_GAMECONTROLLER_SET_CONTROLLER_LED 104
#define SDL_CODE_GAMECONTROLLER_SET_ADAPTIVE_TRIGGERS 105
#define SDL_CODE_HIDE_STATUS_OVERLAY 106
#define SDL_CODE_SET_INPUT_POLICY 107
#include <openssl/rand.h>
@ -61,7 +62,8 @@ CONNECTION_LISTENER_CALLBACKS Session::k_ConnCallbacks = {
Session::clRumbleTriggers,
Session::clSetMotionEventState,
Session::clSetControllerLED,
Session::clSetAdaptiveTriggers
Session::clSetAdaptiveTriggers,
Session::clSetInputPolicy
};
Session* Session::s_ActiveSession;
@ -277,6 +279,20 @@ void Session::clSetAdaptiveTriggers(uint16_t controllerNumber, uint8_t eventFlag
SDL_PushEvent(&setControllerLEDEvent);
}
void Session::clSetInputPolicy(uint8_t allowKeyboard, uint8_t allowMouse, uint8_t allowGamepad, uint8_t reason)
{
SDL_Event setInputPolicyEvent = {};
setInputPolicyEvent.type = SDL_USEREVENT;
setInputPolicyEvent.user.code = SDL_CODE_SET_INPUT_POLICY;
setInputPolicyEvent.user.data1 = nullptr;
setInputPolicyEvent.user.data2 = (void*)(uintptr_t)(
((uintptr_t)allowKeyboard << 24) |
((uintptr_t)allowMouse << 16) |
((uintptr_t)allowGamepad << 8) |
(uintptr_t)reason);
SDL_PushEvent(&setInputPolicyEvent);
}
bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
SDL_Window* window, int videoFormat, int width, int height,
@ -562,7 +578,7 @@ Session::Session(NvComputer* computer, NvApp& app, StreamingPreferences *prefere
m_ManualAudioMuted(false),
m_AudioVolumeScalar(1.0f),
m_AllowGamepadInput(true),
m_AllowKeyboardMouseInput(true),
m_AllowKeyboardMouseInput(false),
m_StatusOverlayGeneration(0),
m_QtWindow(nullptr),
m_UnexpectedTermination(true), // Failure prior to streaming is unexpected
@ -582,6 +598,7 @@ Session::Session(NvComputer* computer, NvApp& app, StreamingPreferences *prefere
void Session::setGamepadInputAllowed(bool allowed)
{
m_AllowGamepadInput.store(allowed, std::memory_order_relaxed);
sendInputPermissionStateToHost(LI_SESSION_INPUT_POLICY_REASON_USER_TOGGLE);
notifyInputPermissionState();
}
@ -627,8 +644,10 @@ void Session::setKeyboardMouseInputAllowed(bool allowed)
bool previous = m_AllowKeyboardMouseInput.exchange(allowed, std::memory_order_relaxed);
if (previous && !allowed && m_InputHandler != nullptr) {
m_InputHandler->raiseAllKeys();
m_InputHandler->raiseAllMouseButtons();
}
sendInputPermissionStateToHost(LI_SESSION_INPUT_POLICY_REASON_USER_TOGGLE);
notifyInputPermissionState();
}
@ -654,6 +673,22 @@ void Session::notifyInputPermissionState()
showTemporaryStatusOverlay(buffer);
}
void Session::sendInputPermissionStateToHost(uint8_t reason)
{
const bool allowKeyboardMouse = isKeyboardMouseInputAllowed();
const bool allowGamepad = isGamepadInputAllowed();
const int err = LiSendSessionInputPolicy(allowKeyboardMouse,
allowKeyboardMouse,
allowGamepad,
reason);
if (err != 0 && err != LI_ERR_UNSUPPORTED) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"Failed to send input policy update to host: %d",
err);
}
}
Uint32 Session::statusOverlayTimeoutCallback(Uint32, void* param)
{
SDL_Event event = {};
@ -678,6 +713,22 @@ void Session::showTemporaryStatusOverlay(const char* text, Uint32 timeoutMs)
SDL_AddTimer(timeoutMs, statusOverlayTimeoutCallback, (void*)(uintptr_t)generation);
}
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) {
m_InputHandler->raiseAllKeys();
m_InputHandler->raiseAllMouseButtons();
}
m_AllowGamepadInput.store(allowGamepad, std::memory_order_relaxed);
if (reason != LI_SESSION_INPUT_POLICY_REASON_STREAM_START) {
notifyInputPermissionState();
}
}
void Session::updateEffectiveAudioMuteState()
{
bool muted = m_ManualAudioMuted.load(std::memory_order_relaxed);
@ -1824,6 +1875,8 @@ bool Session::startConnectionAsync()
return false;
}
sendInputPermissionStateToHost(LI_SESSION_INPUT_POLICY_REASON_STREAM_START);
emit connectionStarted();
return true;
}
@ -2160,6 +2213,15 @@ void Session::exec()
m_InputHandler->setAdaptiveTriggers((uint16_t)(uintptr_t)event.user.data1,
(DualSenseOutputReport *)event.user.data2);
break;
case SDL_CODE_SET_INPUT_POLICY: {
const uintptr_t packed = (uintptr_t)event.user.data2;
const bool allowKeyboard = ((packed >> 24) & 0xFF) != 0;
const bool allowMouse = ((packed >> 16) & 0xFF) != 0;
const bool allowGamepad = ((packed >> 8) & 0xFF) != 0;
const uint8_t reason = (uint8_t)(packed & 0xFF);
applyHostInputPolicy(allowKeyboard, allowMouse, allowGamepad, reason);
break;
}
case SDL_CODE_HIDE_STATUS_OVERLAY:
if ((uint32_t)(uintptr_t)event.user.data1 == m_StatusOverlayGeneration.load(std::memory_order_relaxed) &&
m_MouseEmulationRefCount == 0) {