diff --git a/src/openttd.cpp b/src/openttd.cpp index 82943ac624..7b2691efb5 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -332,7 +332,7 @@ static void LoadIntroGame(bool load_newgrfs = true) FixTitleGameZoom(); _pause_mode = PM_UNPAUSED; - _cursor.fix_at = false; + VideoDriver::GetInstance()->FixMousePointer(false); CheckForMissingGlyphs(); diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index eb2d551dd4..8afe0349c4 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -9,6 +9,7 @@ #include "stdafx.h" #include "core/backup_type.hpp" +#include "video/video_driver.hpp" #include "clear_map.h" #include "industry.h" #include "station_map.h" @@ -1866,7 +1867,9 @@ public: void OnScroll(Point delta) override { - if (_settings_client.gui.scroll_mode == VSM_VIEWPORT_RMB_FIXED || _settings_client.gui.scroll_mode == VSM_MAP_RMB_FIXED) _cursor.fix_at = true; + if (_settings_client.gui.scroll_mode == VSM_VIEWPORT_RMB_FIXED || _settings_client.gui.scroll_mode == VSM_MAP_RMB_FIXED) { + VideoDriver::GetInstance()->FixMousePointer(true); + } /* While tile is at (delta.x, delta.y)? */ int sub; diff --git a/src/video/cocoa/cocoa_v.h b/src/video/cocoa/cocoa_v.h index edfa39646d..deaf4a31ae 100644 --- a/src/video/cocoa/cocoa_v.h +++ b/src/video/cocoa/cocoa_v.h @@ -49,6 +49,7 @@ public: void ClearSystemSprites() override; void PopulateSystemSprites() override; + void FixMousePointer(bool fix_at) override; void EditBoxLostFocus() override; std::vector GetListOfMonitorRefreshRates() override; diff --git a/src/video/cocoa/cocoa_v.mm b/src/video/cocoa/cocoa_v.mm index ab425e2125..fe3e6eed8f 100644 --- a/src/video/cocoa/cocoa_v.mm +++ b/src/video/cocoa/cocoa_v.mm @@ -240,6 +240,15 @@ bool VideoDriver_Cocoa::AfterBlitterChange() return true; } +void VideoDriver_Cocoa::FixMousePointer(bool fix_at) +{ + if (_cursor.fix_at == fix_at) return; + + this->VideoDriver::FixMousePointer(fix_at); + + CGAssociateMouseAndMouseCursorPosition(!_cursor.fix_at); +} + /** * An edit box lost the input focus. Abort character compositing if necessary. */ diff --git a/src/video/cocoa/cocoa_wnd.mm b/src/video/cocoa/cocoa_wnd.mm index 38e7b720ed..c8bec4e1a3 100644 --- a/src/video/cocoa/cocoa_wnd.mm +++ b/src/video/cocoa/cocoa_wnd.mm @@ -674,15 +674,6 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel HandleMouseEvents(); } -- (void)internalMouseButtonEvent -{ - bool cur_fix = _cursor.fix_at; - HandleMouseEvents(); - - /* Cursor fix mode was changed, synchronize with OS. */ - if (cur_fix != _cursor.fix_at) CGAssociateMouseAndMouseCursorPosition(!_cursor.fix_at); -} - - (BOOL)emulateRightButton:(NSEvent *)event { uint32_t keymask = 0; @@ -708,7 +699,7 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel [ self rightMouseDown:event ]; } else { _left_button_down = true; - [ self internalMouseButtonEvent ]; + HandleMouseEvents(); } } - (void)mouseUp:(NSEvent *)event @@ -719,7 +710,7 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel } else { _left_button_down = false; _left_button_clicked = false; - [ self internalMouseButtonEvent ]; + HandleMouseEvents(); } } @@ -731,12 +722,12 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel { _right_button_down = true; _right_button_clicked = true; - [ self internalMouseButtonEvent ]; + HandleMouseEvents(); } - (void)rightMouseUp:(NSEvent *)event { _right_button_down = false; - [ self internalMouseButtonEvent ]; + HandleMouseEvents(); } - (void)scrollWheel:(NSEvent *)event 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; diff --git a/src/video/video_driver.hpp b/src/video/video_driver.hpp index 72731f0113..76de0b280e 100644 --- a/src/video/video_driver.hpp +++ b/src/video/video_driver.hpp @@ -87,6 +87,11 @@ public: return true; } + /** + * Fix the mouse position position. + */ + virtual void FixMousePointer(bool fix_at) { _cursor.fix_at = fix_at; } + /** * Get whether the mouse cursor is drawn by the video driver. * @return True if cursor drawing is done by the video driver. diff --git a/src/window.cpp b/src/window.cpp index 6fce13f1d7..2639043c65 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -2363,7 +2363,7 @@ static EventState HandleViewportScroll() if (_last_scroll_window == nullptr) _last_scroll_window = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); if (_last_scroll_window == nullptr || !((_settings_client.gui.scroll_mode != VSM_MAP_LMB && _right_button_down) || scrollwheel_scrolling || (_settings_client.gui.scroll_mode == VSM_MAP_LMB && _left_button_down))) { - _cursor.fix_at = false; + VideoDriver::GetInstance()->FixMousePointer(false); _scrolling_viewport = false; _last_scroll_window = nullptr; return ES_NOT_HANDLED; @@ -2818,7 +2818,7 @@ static void MouseLoop(MouseClick click, int mousewheel) if (vp != nullptr) { if (scrollwheel_scrolling && !w->flags.Test(WindowFlag::DisableVpScroll)) { _scrolling_viewport = true; - _cursor.fix_at = true; + VideoDriver::GetInstance()->FixMousePointer(true); return; } @@ -2829,7 +2829,7 @@ static void MouseLoop(MouseClick click, int mousewheel) if (!w->flags.Test(WindowFlag::DisableVpScroll) && _settings_client.gui.scroll_mode == VSM_MAP_LMB) { _scrolling_viewport = true; - _cursor.fix_at = false; + VideoDriver::GetInstance()->FixMousePointer(false); return; } break; @@ -2838,8 +2838,7 @@ static void MouseLoop(MouseClick click, int mousewheel) if (!w->flags.Test(WindowFlag::DisableVpScroll) && _settings_client.gui.scroll_mode != VSM_MAP_LMB) { _scrolling_viewport = true; - _cursor.fix_at = (_settings_client.gui.scroll_mode == VSM_VIEWPORT_RMB_FIXED || - _settings_client.gui.scroll_mode == VSM_MAP_RMB_FIXED); + VideoDriver::GetInstance()->FixMousePointer(_settings_client.gui.scroll_mode == VSM_VIEWPORT_RMB_FIXED || _settings_client.gui.scroll_mode == VSM_MAP_RMB_FIXED); DispatchRightClickEvent(w, x - w->left, y - w->top); return; }