From 68c0ac0ffcb8df27e16006b89a2930a64302fbdd Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Wed, 2 Apr 2025 21:37:14 +0300 Subject: [PATCH] Fix cursor locking bounds calculation --- Source/Engine/Engine/Screen.cpp | 42 +++++++++++------------- Source/Engine/Platform/Base/WindowBase.h | 21 ++++++------ Source/Engine/Platform/SDL/SDLInput.cpp | 1 + Source/Engine/Platform/SDL/SDLWindow.cpp | 23 +++++++------ Source/Engine/Platform/SDL/SDLWindow.h | 1 + 5 files changed, 46 insertions(+), 42 deletions(-) diff --git a/Source/Engine/Engine/Screen.cpp b/Source/Engine/Engine/Screen.cpp index d9d3a8f8f..d2fb7db3d 100644 --- a/Source/Engine/Engine/Screen.cpp +++ b/Source/Engine/Engine/Screen.cpp @@ -123,34 +123,32 @@ void Screen::SetCursorLock(CursorLockMode mode) #if USE_EDITOR const auto win = Editor::Managed->GetGameWindow(true); Rectangle bounds(Editor::Managed->GameViewportToScreen(Float2::Zero), Editor::Managed->GetGameWindowSize()); + if (win) + bounds = Rectangle(win->ScreenToClient(bounds.GetTopLeft()), bounds.Size); #else const auto win = Engine::MainWindow; Rectangle bounds = win != nullptr ? win->GetClientBounds() : Rectangle(); #endif - bool inRelativeMode = Input::Mouse->IsRelative(); - if (win && mode == CursorLockMode::Clipped) - win->StartClippingCursor(bounds); - else if (win && mode == CursorLockMode::Locked) + if (win) { - // Use mouse clip region to restrict the cursor in one spot - Rectangle centerBounds; - auto mousePosition = win->GetMousePosition(); - if (bounds.Contains(mousePosition)) - centerBounds = Rectangle(mousePosition, Float2(1, 1)); - else - centerBounds = Rectangle(bounds.GetCenter(), Float2(1, 1)); - win->StartClippingCursor(centerBounds); - } - else if (win && (CursorLock == CursorLockMode::Locked || CursorLock == CursorLockMode::Clipped)) - win->EndClippingCursor(); - CursorLock = mode; + bool inRelativeMode = Input::Mouse->IsRelative(); + if (mode == CursorLockMode::Clipped) + win->StartClippingCursor(bounds); + else if (mode == CursorLockMode::Locked) + { + // Use mouse clip region to restrict the cursor in one spot + win->StartClippingCursor(Rectangle(bounds.GetCenter(), Float2(1, 1))); + } + else if (CursorLock == CursorLockMode::Locked || CursorLock == CursorLockMode::Clipped) + win->EndClippingCursor(); - // Enable relative mode when cursor is restricted - bool focused = win && Engine::HasGameViewportFocus(); - if (win && CursorLock != CursorLockMode::None) - Input::Mouse->SetRelativeMode(true, win); - else if (win && CursorLock == CursorLockMode::None && inRelativeMode) - Input::Mouse->SetRelativeMode(false, win); + // Enable relative mode when cursor is restricted + if (mode != CursorLockMode::None) + Input::Mouse->SetRelativeMode(true, win); + else if (mode == CursorLockMode::None && inRelativeMode) + Input::Mouse->SetRelativeMode(false, win); + } + CursorLock = mode; } GameWindowMode Screen::GetGameWindowMode() diff --git a/Source/Engine/Platform/Base/WindowBase.h b/Source/Engine/Platform/Base/WindowBase.h index d53292ef4..9cf1cc771 100644 --- a/Source/Engine/Platform/Base/WindowBase.h +++ b/Source/Engine/Platform/Base/WindowBase.h @@ -521,6 +521,17 @@ public: { } + /// + /// Gets the mouse position in window coordinates. + /// + API_PROPERTY() virtual Float2 GetMousePosition() const; + + /// + /// Sets the mouse position in window coordinates. + /// + /// Mouse position to set on + API_PROPERTY() virtual void SetMousePosition(const Float2& position) const; + /// /// Gets the mouse cursor. /// @@ -717,16 +728,6 @@ public: API_FUNCTION() bool GetKeyUp(KeyboardKeys key) const; public: - /// - /// Gets the mouse position in window coordinates. - /// - API_PROPERTY() Float2 GetMousePosition() const; - - /// - /// Sets the mouse position in window coordinates. - /// - /// Mouse position to set on - API_PROPERTY() void SetMousePosition(const Float2& position) const; /// /// Gets the mouse position change during the last frame. diff --git a/Source/Engine/Platform/SDL/SDLInput.cpp b/Source/Engine/Platform/SDL/SDLInput.cpp index 40c3e3b9d..0ef8c2211 100644 --- a/Source/Engine/Platform/SDL/SDLInput.cpp +++ b/Source/Engine/Platform/SDL/SDLInput.cpp @@ -399,6 +399,7 @@ public: void SetRelativeMode(bool relativeMode, Window* window) final override { + ASSERT(window != nullptr); if (relativeMode == _relativeMode) return; diff --git a/Source/Engine/Platform/SDL/SDLWindow.cpp b/Source/Engine/Platform/SDL/SDLWindow.cpp index 8c1fb8a3f..68e652d85 100644 --- a/Source/Engine/Platform/SDL/SDLWindow.cpp +++ b/Source/Engine/Platform/SDL/SDLWindow.cpp @@ -820,16 +820,8 @@ void SDLWindow::StartClippingCursor(const Rectangle& bounds) return; #if PLATFORM_LINUX - { - auto oldValue = SDL_GetHint(SDL_HINT_MOUSE_RELATIVE_WARP_MOTION); - SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_WARP_MOTION, "1"); - - // The cursor is not fully constrained when positioned outside of the clip region... - Float2 center = bounds.GetCenter(); - SDL_WarpMouseInWindow(_window, center.X, center.Y); - - SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_WARP_MOTION, oldValue); - } + // The cursor is not fully constrained when positioned outside the clip region + SetMousePosition(bounds.GetCenter()); #endif _isClippingCursor = true; @@ -847,6 +839,17 @@ void SDLWindow::EndClippingCursor() SDL_SetWindowMouseRect(_window, nullptr); } +void SDLWindow::SetMousePosition(const Float2& position) const +{ + if (!_settings.AllowInput || !_focused) + return; + + SDL_WarpMouseInWindow(_window, position.X, position.Y); + + Float2 screenPosition = ClientToScreen(position); + Input::Mouse->OnMouseMoved(screenPosition); +} + void SDLWindow::SetCursor(CursorType type) { CursorType oldCursor = _cursor; diff --git a/Source/Engine/Platform/SDL/SDLWindow.h b/Source/Engine/Platform/SDL/SDLWindow.h index d9bfd4de3..8e00cd950 100644 --- a/Source/Engine/Platform/SDL/SDLWindow.h +++ b/Source/Engine/Platform/SDL/SDLWindow.h @@ -113,6 +113,7 @@ public: void EndTrackingMouse() override; void StartClippingCursor(const Rectangle& bounds) override; void EndClippingCursor() override; + void SetMousePosition(const Float2& position) const override; void SetCursor(CursorType type) override; #if USE_EDITOR && PLATFORM_WINDOWS