From 534ce02756e3eab37b53690458ce81bb576dc4b4 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 6 Jun 2026 16:11:37 -0500 Subject: [PATCH] Track keyboard grab state internally rather than using SDL Versions of sdl2-compat prior to 2.32.64 (and native SDL3) won't set the grab flag if grabbing the keyboard fails, even though the compositor still may be exclusively passing system keys to us via some external configuration by the user. This causes the super key to not be sent to the host, because we think the client OS will consume it and don't want to duplicate the input. Fixes #1900 --- app/streaming/input/input.cpp | 26 +++++++++++++------------- app/streaming/input/input.h | 3 ++- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/app/streaming/input/input.cpp b/app/streaming/input/input.cpp index 432f236a..6647cf18 100644 --- a/app/streaming/input/input.cpp +++ b/app/streaming/input/input.cpp @@ -19,7 +19,8 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, int streamWidth, i m_PendingMouseButtonsAllUpOnVideoRegionLeave(false), m_PointerRegionLockActive(false), m_PointerRegionLockToggledByUser(false), - m_FakeCaptureActive(false), + m_FakeMouseCaptureActive(false), + m_KeyboardCaptureActive(false), m_CaptureSystemKeysMode(prefs.captureSysKeysMode), m_MouseCursorCapturedVisibilityState(SDL_DISABLE), m_LongPressTimer(0), @@ -319,7 +320,7 @@ bool SdlInputHandler::isCaptureActive() } // Some platforms don't support SDL_SetRelativeMouseMode - return m_FakeCaptureActive; + return m_FakeMouseCaptureActive; } void SdlInputHandler::updateKeyboardGrabState() @@ -342,6 +343,8 @@ void SdlInputHandler::updateKeyboardGrabState() // SDL 2.0.18 adds keyboard grab on macOS (if built with non-AppStore APIs). SDL_SetWindowKeyboardGrab(m_Window, shouldGrab ? SDL_TRUE : SDL_FALSE); #endif + + m_KeyboardCaptureActive = shouldGrab; } bool SdlInputHandler::isSystemKeyCaptureActive() @@ -354,15 +357,12 @@ bool SdlInputHandler::isSystemKeyCaptureActive() return false; } + // NB: We used to check SDL_WINDOW_KEYBOARD_GRABBED here, but this isn't + // always set when capture "fails" on SDL3, even though the user may have + // configured the compositor to pass through system keys to us anyway. + // See issues #1776 and #1900 for details. Uint32 windowFlags = SDL_GetWindowFlags(m_Window); - if (!(windowFlags & SDL_WINDOW_INPUT_FOCUS) -#if SDL_VERSION_ATLEAST(2, 0, 15) - || !(windowFlags & SDL_WINDOW_KEYBOARD_GRABBED) -#else - || !(windowFlags & SDL_WINDOW_INPUT_GRABBED) -#endif - ) - { + if (!(windowFlags & SDL_WINDOW_INPUT_FOCUS) || !m_KeyboardCaptureActive) { return false; } @@ -381,7 +381,7 @@ void SdlInputHandler::setCaptureActive(bool active) if (m_AbsoluteMouseMode || SDL_SetRelativeMouseMode(SDL_TRUE) < 0) { // Relative mouse mode didn't work or was disabled, so we'll just hide the cursor SDL_ShowCursor(m_MouseCursorCapturedVisibilityState); - m_FakeCaptureActive = true; + m_FakeMouseCaptureActive = true; } // Synchronize the client and host cursor when activating absolute capture @@ -411,10 +411,10 @@ void SdlInputHandler::setCaptureActive(bool active) } } else { - if (m_FakeCaptureActive) { + if (m_FakeMouseCaptureActive) { // Display the cursor again SDL_ShowCursor(SDL_ENABLE); - m_FakeCaptureActive = false; + m_FakeMouseCaptureActive = false; } else { SDL_SetRelativeMouseMode(SDL_FALSE); diff --git a/app/streaming/input/input.h b/app/streaming/input/input.h index 1c5af856..92b914bf 100644 --- a/app/streaming/input/input.h +++ b/app/streaming/input/input.h @@ -218,7 +218,8 @@ private: int m_GamepadMask; GamepadState m_GamepadState[MAX_GAMEPADS]; QSet m_KeysDown; - bool m_FakeCaptureActive; + bool m_FakeMouseCaptureActive; + bool m_KeyboardCaptureActive; QString m_OldIgnoreDevices; QString m_OldIgnoreDevicesExcept; QStringList m_IgnoreDeviceGuids;