Fix capturing mouse motion outside the window on sdl2-compat

This commit is contained in:
Cameron Gutman
2026-07-27 00:10:06 -05:00
parent 7794a42843
commit 7f7f2c26d0
4 changed files with 33 additions and 19 deletions
-4
View File
@@ -718,10 +718,6 @@ int main(int argc, char *argv[])
SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, "Moonlight"); SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, "Moonlight");
SDL_SetHint(SDL_HINT_APP_NAME, "Moonlight"); SDL_SetHint(SDL_HINT_APP_NAME, "Moonlight");
// We handle capturing the mouse ourselves when it leaves the window, so we don't need
// SDL doing it for us behind our backs.
SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0");
// SDL will try to lock the mouse cursor on Wayland if it's not visible in order to // SDL will try to lock the mouse cursor on Wayland if it's not visible in order to
// support applications that assume they can warp the cursor (which isn't possible // support applications that assume they can warp the cursor (which isn't possible
// on Wayland). We don't want this behavior because it interferes with seamless mouse // on Wayland). We don't want this behavior because it interferes with seamless mouse
+28 -13
View File
@@ -40,6 +40,19 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, int streamWidth, i
m_CaptureSystemKeysMode = StreamingPreferences::CSK_ALWAYS; m_CaptureSystemKeysMode = StreamingPreferences::CSK_ALWAYS;
} }
// SDL3 breaks our auto-capture-on-leave logic because the mouse focus has already
// been lost by the time we attempt to call SDL_CaptureMouse(). Fortunately, SDL3's
// own auto-capture logic seems to be stable now (unlike SDL2), so we can rely on
// that instead of our own hack when running on sdl2-compat.
// https://github.com/libsdl-org/SDL/commit/e54001b02809dcebbb822bd0297919c8c76976a1
SDL_version ver;
SDL_GetVersion(&ver);
m_NeedsManualCaptureOnLeave = !(ver.major == 2 && ver.minor >= 30 && ver.patch >= 50) && !SDL_GetHint("SDL3_VERSION");
if (m_NeedsManualCaptureOnLeave) {
// Disable the buggy auto-capture on earlier SDL2 builds
SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0");
}
// Allow gamepad input when the app doesn't have focus if requested // Allow gamepad input when the app doesn't have focus if requested
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, prefs.backgroundGamepad ? "1" : "0"); SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, prefs.backgroundGamepad ? "1" : "0");
@@ -276,19 +289,21 @@ void SdlInputHandler::raiseAllKeys()
void SdlInputHandler::notifyMouseLeave() void SdlInputHandler::notifyMouseLeave()
{ {
// SDL on Windows doesn't send the mouse button up until the mouse re-enters the window if (m_NeedsManualCaptureOnLeave) {
// after leaving it. This breaks some of the Aero snap gestures, so we'll capture it to // SDL on Windows doesn't send the mouse button up until the mouse re-enters the window
// allow us to receive the mouse button up events later. // after leaving it. This breaks some of the Aero snap gestures, so we'll capture it to
// // allow us to receive the mouse button up events later.
// On macOS and X11, capturing the mouse allows us to receive mouse motion outside the //
// window (button up already worked without capture). // On macOS and X11, capturing the mouse allows us to receive mouse motion outside the
if (m_AbsoluteMouseMode && isCaptureActive()) { // window (button up already worked without capture).
// NB: Not using SDL_GetGlobalMouseState() because we want our state not the system's if (m_AbsoluteMouseMode && isCaptureActive()) {
Uint32 mouseState = SDL_GetMouseState(nullptr, nullptr); // NB: Not using SDL_GetGlobalMouseState() because we want our state not the system's
for (Uint32 button = SDL_BUTTON_LEFT; button <= SDL_BUTTON_X2; button++) { Uint32 mouseState = SDL_GetMouseState(nullptr, nullptr);
if (mouseState & SDL_BUTTON(button)) { for (Uint32 button = SDL_BUTTON_LEFT; button <= SDL_BUTTON_X2; button++) {
SDL_CaptureMouse(SDL_TRUE); if (mouseState & SDL_BUTTON(button)) {
break; SDL_CaptureMouse(SDL_TRUE);
break;
}
} }
} }
} }
+1
View File
@@ -210,6 +210,7 @@ private:
bool m_ReverseScrollDirection; bool m_ReverseScrollDirection;
bool m_SwapFaceButtons; bool m_SwapFaceButtons;
bool m_NeedsManualCaptureOnLeave;
bool m_MouseWasInVideoRegion; bool m_MouseWasInVideoRegion;
bool m_PendingMouseButtonsAllUpOnVideoRegionLeave; bool m_PendingMouseButtonsAllUpOnVideoRegionLeave;
bool m_PointerRegionLockActive; bool m_PointerRegionLockActive;
+4 -2
View File
@@ -128,8 +128,10 @@ void SdlInputHandler::handleMouseMotionEvent(SDL_MouseMotionEvent* event)
Uint32 buttonState = SDL_GetMouseState(nullptr, nullptr); Uint32 buttonState = SDL_GetMouseState(nullptr, nullptr);
if (buttonState == 0) { if (buttonState == 0) {
if (m_PendingMouseButtonsAllUpOnVideoRegionLeave) { if (m_PendingMouseButtonsAllUpOnVideoRegionLeave) {
// Stop capturing the mouse now if (m_NeedsManualCaptureOnLeave) {
SDL_CaptureMouse(SDL_FALSE); // Stop capturing the mouse now
SDL_CaptureMouse(SDL_FALSE);
}
m_PendingMouseButtonsAllUpOnVideoRegionLeave = false; m_PendingMouseButtonsAllUpOnVideoRegionLeave = false;
} }
} }