Fix CursorLockMode.Locked not working

This commit is contained in:
2025-03-31 21:42:38 +03:00
parent a8f93beeb8
commit d355f9eff5
5 changed files with 64 additions and 52 deletions

View File

@@ -357,9 +357,9 @@ public:
class SDLMouse : public Mouse
{
private:
Float2 oldPosition = Float2::Zero;
Window* relativeModeWindow = nullptr;
const SDL_Rect* oldScreenRect = nullptr;
Float2 _oldPosition = Float2::Zero;
Window* _relativeModeWindow = nullptr;
const SDL_Rect* _oldScreenRect = nullptr;
public:
/// <summary>
@@ -377,8 +377,8 @@ public:
/// </summary>
Float2 GetOldMousePosition() const
{
ASSERT(relativeModeWindow != nullptr);
return relativeModeWindow->ClientToScreen(oldPosition);
ASSERT(_relativeModeWindow != nullptr);
return _relativeModeWindow->ClientToScreen(_oldPosition);
}
// [Mouse]
@@ -405,27 +405,27 @@ public:
auto windowHandle = static_cast<SDLWindow*>(window)->_window;
if (relativeMode)
{
relativeModeWindow = window;
SDL_GetMouseState(&oldPosition.X, &oldPosition.Y);
_relativeModeWindow = window;
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 };
oldScreenRect = SDL_GetWindowMouseRect(windowHandle);
SDL_Rect clipRect = { (int)_oldPosition.X, (int)_oldPosition.Y, 1, 1 };
_oldScreenRect = SDL_GetWindowMouseRect(windowHandle);
SDL_SetWindowMouseRect(windowHandle, &clipRect);
}
}
else
{
if (relativeModeWindow != window)
if (_relativeModeWindow != window)
{
// FIXME: When floating game window is focused and editor viewport activated, the relative mode gets stuck
return;
}
SDL_SetWindowMouseRect(windowHandle, nullptr);//oldScreenRect);
SDL_WarpMouseInWindow(windowHandle, oldPosition.X, oldPosition.Y);
oldScreenRect = nullptr;
relativeModeWindow = nullptr;
SDL_WarpMouseInWindow(windowHandle, _oldPosition.X, _oldPosition.Y);
_oldScreenRect = nullptr;
_relativeModeWindow = nullptr;
}
Mouse::SetRelativeMode(relativeMode, window);

View File

@@ -70,7 +70,7 @@ bool SDLPlatform::Init()
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_MODE_CENTER, "0"); //
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, "0"); // Relative mode can be active when cursor is shown and clipped
SDL_SetHint(SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS, "8"); // Reduce the default mouse double-click radius
//SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1"); // Disables raw mouse input
@@ -118,6 +118,7 @@ bool SDLPlatform::Init()
}
SDLInput::Init();
SDLWindow::Init();
SystemDpi = (int)(SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()) * DefaultDPI);

View File

@@ -73,6 +73,10 @@ void* GetNativeWindowPointer(SDL_Window* window)
return windowPtr;
}
void SDLWindow::Init()
{
}
SDLWindow::SDLWindow(const CreateWindowSettings& settings)
: WindowBase(settings)
, _handle(nullptr)
@@ -420,26 +424,29 @@ void SDLWindow::HandleEvent(SDL_Event& event)
case SDL_EVENT_WINDOW_FOCUS_GAINED:
{
OnGotFocus();
if (IsPopupWindow(_settings.Type))
_window = _window;
if (_settings.AllowInput && !SDLPlatform::UsesX11())
SDL_StartTextInput(_window);
const SDL_Rect* currentClippingRect = SDL_GetWindowMouseRect(_window);
if (_isClippingCursor && currentClippingRect == nullptr)
if (_isClippingCursor)
{
// The relative mode needs to be disabled for clipping to take effect
bool inRelativeMode = Input::Mouse->IsRelative(this) || _restoreRelativeMode;
if (inRelativeMode)
Input::Mouse->SetRelativeMode(false, this);
// Restore previous clipping region
SDL_Rect rect{ (int)_clipCursorRect.GetX(), (int)_clipCursorRect.GetY(), (int)_clipCursorRect.GetWidth(), (int)_clipCursorRect.GetHeight() };
SDL_SetWindowMouseRect(_window, &rect);
if (inRelativeMode)
Input::Mouse->SetRelativeMode(true, this);
}
return;
}
case SDL_EVENT_WINDOW_FOCUS_LOST:
{
if (IsPopupWindow(_settings.Type))
_window = _window;
if (_settings.AllowInput && !SDLPlatform::UsesX11())
SDL_StopTextInput(_window);
const SDL_Rect* currentClippingRect = SDL_GetWindowMouseRect(_window);
if (currentClippingRect != nullptr)
if (_isClippingCursor)
SDL_SetWindowMouseRect(_window, nullptr);
OnLostFocus();
return;
@@ -802,9 +809,23 @@ void SDLWindow::StartClippingCursor(const Rectangle& bounds)
if (!IsFocused())
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);
}
#endif
_isClippingCursor = true;
SDL_Rect rect{ (int)bounds.GetX(), (int)bounds.GetY(), (int)bounds.GetWidth(), (int)bounds.GetHeight() };
SDL_SetWindowMouseRect(_window, &rect);
_clipCursorRect = bounds;
}
void SDLWindow::EndClippingCursor()

View File

@@ -40,6 +40,9 @@ private:
Rectangle _clipCursorRect;
Rectangle _cachedClientRectangle;
public:
static void Init();
public:
/// <summary>
/// Initializes a new instance of the <see cref="SDLWindow"/> class.