From f1e310727a0882f9950289d8468088e72bf7ad35 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Mon, 6 Jan 2025 17:30:17 +0000 Subject: [PATCH] Fix #13286: Use relative mouse movement when cursor position is fixed. This ensures the movement isn't constrained by the window boundary. As this switches us from automatic to manual mouse capture modes, this also removes the `no_mouse_capture` driver option. --- src/video/sdl2_v.cpp | 42 ++++++++++++++++++++++++++++-------------- src/video/sdl2_v.h | 2 ++ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/video/sdl2_v.cpp b/src/video/sdl2_v.cpp index 8cea6be506..58c7bc64c7 100644 --- a/src/video/sdl2_v.cpp +++ b/src/video/sdl2_v.cpp @@ -205,6 +205,20 @@ bool VideoDriver_SDL_Base::ClaimMousePointer() return true; } +void VideoDriver_SDL_Base::FixMousePointer(bool fix_at) +{ + if (_cursor.fix_at == fix_at) return; + + this->VideoDriver::FixMousePointer(fix_at); + + SDL_SetRelativeMouseMode(fix_at ? SDL_TRUE : SDL_FALSE); + + if (!fix_at) { + /* Move cursor back to where it was before being fixed. */ + SDL_WarpMouseInWindow(this->sdl_window, _cursor.pos.x, _cursor.pos.y); + } +} + /** * This is called to indicate that an edit box has gained focus, text input mode should be enabled. */ @@ -385,21 +399,23 @@ bool VideoDriver_SDL_Base::PollEvent() switch (ev.type) { case SDL_MOUSEMOTION: { - int32_t x = ev.motion.x; - int32_t y = ev.motion.y; - if (_cursor.fix_at) { + /* Use relative motion events. */ + int32_t x = ev.motion.xrel; + int32_t y = ev.motion.yrel; + /* Get all queued mouse events now in case we have to warp the cursor. In the * end, we only care about the current mouse position and not bygone events. */ while (SDL_PeepEvents(&ev, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION)) { - x = ev.motion.x; - y = ev.motion.y; + x += ev.motion.xrel; + y += ev.motion.yrel; } + + _cursor.UpdateCursorPositionRelative(x, y); + } else { + _cursor.UpdateCursorPosition(ev.motion.x, ev.motion.y); } - if (_cursor.UpdateCursorPosition(x, y)) { - SDL_WarpMouseInWindow(this->sdl_window, _cursor.pos.x, _cursor.pos.y); - } HandleMouseEvents(); break; } @@ -560,12 +576,10 @@ std::optional VideoDriver_SDL_Base::Start(const StringList &pa if (error) return error; #ifdef SDL_HINT_MOUSE_AUTO_CAPTURE - if (GetDriverParamBool(param, "no_mouse_capture")) { - /* By default SDL captures the mouse, while a button is pressed. - * This is annoying during debugging, when OpenTTD is suspended while the button was pressed. - */ - if (!SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0")) return SDL_GetError(); - } + /* By default SDL captures the mouse, while a button is pressed. + * This is annoying during debugging, when OpenTTD is suspended while the button was pressed. + */ + SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0"); #endif #ifdef SDL_HINT_APP_NAME diff --git a/src/video/sdl2_v.h b/src/video/sdl2_v.h index 45c064d0bc..bbd3cadb49 100644 --- a/src/video/sdl2_v.h +++ b/src/video/sdl2_v.h @@ -35,6 +35,8 @@ public: bool ClaimMousePointer() override; + void FixMousePointer(bool fix_at) override; + void EditBoxGainedFocus() override; void EditBoxLostFocus() override;