Fix mouse resetting issues after ending relative mode

This commit is contained in:
2025-01-19 21:56:40 +02:00
parent c842e131bb
commit 6f289f7bb2
2 changed files with 42 additions and 14 deletions

View File

@@ -10,6 +10,12 @@
#include "Engine/Input/Mouse.h" #include "Engine/Input/Mouse.h"
#include "Engine/Input/Keyboard.h" #include "Engine/Input/Keyboard.h"
#include "Engine/Input/Gamepad.h" #include "Engine/Input/Gamepad.h"
#include "Engine/Engine/Engine.h"
#include "Engine/Engine/Screen.h"
#if USE_EDITOR
#include "Editor/Editor.h"
#include "Editor/Managed/ManagedEditor.h"
#endif
#include <SDL3/SDL_events.h> #include <SDL3/SDL_events.h>
@@ -351,7 +357,9 @@ public:
class SDLMouse : public Mouse class SDLMouse : public Mouse
{ {
private: private:
Float2 oldPosition; Float2 oldPosition = Float2::Zero;
Window* relativeModeWindow = nullptr;
const SDL_Rect* oldScreenRect = nullptr;
public: public:
/// <summary> /// <summary>
@@ -369,14 +377,24 @@ public:
/// </summary> /// </summary>
Float2 GetOldMousePosition() const Float2 GetOldMousePosition() const
{ {
return oldPosition; ASSERT(relativeModeWindow != nullptr);
return relativeModeWindow->ClientToScreen(oldPosition);
} }
// [Mouse] // [Mouse]
void SetMousePosition(const Float2& newPosition) final override void SetMousePosition(const Float2& screenPosition) final override
{ {
SDL_WarpMouseGlobal(newPosition.X, newPosition.Y); #if USE_EDITOR
OnMouseMoved(newPosition); auto window = Editor::Managed->GetGameWindow();
if (window == nullptr)
window = Engine::MainWindow;
#else
auto window = Engine::MainWindow;
#endif
Float2 position = window->ScreenToClient(screenPosition);
SDL_WarpMouseInWindow(static_cast<SDLWindow*>(window)->_window, position.X, position.Y);
OnMouseMoved(position);
} }
void SetRelativeMode(bool relativeMode, Window* window) final override void SetRelativeMode(bool relativeMode, Window* window) final override
@@ -384,19 +402,29 @@ public:
if (relativeMode == _relativeMode) if (relativeMode == _relativeMode)
return; return;
auto sdlWindow = static_cast<SDLWindow*>(window)->GetSDLWindow(); auto windowHandle = static_cast<SDLWindow*>(window)->_window;
if (relativeMode) if (relativeMode)
{
oldScreenRect = SDL_GetWindowMouseRect(windowHandle);
relativeModeWindow = window;
SDL_GetMouseState(&oldPosition.X, &oldPosition.Y); SDL_GetMouseState(&oldPosition.X, &oldPosition.Y);
if (!SDL_CursorVisible())
{
// Trap the cursor in current location
SDL_Rect clipRect = { (int)oldPosition.X, (int)oldPosition.Y, 1, 1 };
SDL_SetWindowMouseRect(windowHandle, &clipRect);
}
}
else
{
SDL_SetWindowMouseRect(windowHandle, oldScreenRect);
oldScreenRect = nullptr;
relativeModeWindow = nullptr;
}
Mouse::SetRelativeMode(relativeMode, window); Mouse::SetRelativeMode(relativeMode, window);
if (!SDL_SetWindowRelativeMouseMode(sdlWindow, relativeMode)) if (!SDL_SetWindowRelativeMouseMode(windowHandle, relativeMode))
LOG(Error, "Failed to set mouse relative mode: {0}", String(SDL_GetError())); LOG(Error, "Failed to set mouse relative mode: {0}", String(SDL_GetError()));
if (!relativeMode)
{
SDL_WarpMouseInWindow(sdlWindow, oldPosition.X, oldPosition.Y);
OnMouseMoved(oldPosition);
}
} }
}; };

View File

@@ -68,7 +68,7 @@ bool SDLPlatform::Init()
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_WARP_MOTION, "0"); SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_WARP_MOTION, "0");
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE, "1"); // Needed for tracking mode SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE, "1"); // Needed for tracking mode
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, "1"); // Is this needed? SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, "0"); //
//SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1"); // Disables raw mouse input //SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1"); // Disables raw mouse input
SDL_SetHint(SDL_HINT_WINDOWS_RAW_KEYBOARD, "1"); SDL_SetHint(SDL_HINT_WINDOWS_RAW_KEYBOARD, "1");