Implement relative mouse mode (raw input) for SDL platform

This commit is contained in:
2024-07-25 21:29:38 +03:00
parent 09331b601b
commit c2a588f738
18 changed files with 293 additions and 30 deletions

View File

@@ -93,6 +93,7 @@ Delegate<const Float2&, MouseButton> Input::MouseUp;
Delegate<const Float2&, MouseButton> Input::MouseDoubleClick;
Delegate<const Float2&, float> Input::MouseWheel;
Delegate<const Float2&> Input::MouseMove;
Delegate<const Float2&> Input::MouseMoveRelative;
Action Input::MouseLeave;
Delegate<const Float2&, int32> Input::TouchDown;
Delegate<const Float2&, int32> Input::TouchMove;
@@ -221,6 +222,14 @@ void Mouse::OnMouseMove(const Float2& position, Window* target)
e.MouseData.Position = position;
}
void Mouse::OnMouseMoveRelative(const Float2& positionRelative, Window* target)
{
Event& e = _queue.AddOne();
e.Type = EventType::MouseMoveRelative;
e.Target = target;
e.MouseMovementData.PositionRelative = positionRelative;
}
void Mouse::OnMouseLeave(Window* target)
{
Event& e = _queue.AddOne();
@@ -286,6 +295,11 @@ bool Mouse::Update(EventQueue& queue)
_state.MousePosition = e.MouseData.Position;
break;
}
case EventType::MouseMoveRelative:
{
_state.MousePosition += e.MouseMovementData.PositionRelative;
break;
}
case EventType::MouseLeave:
{
break;
@@ -710,11 +724,16 @@ void InputService::Update()
// Send input events for the focused window
WindowsManager::WindowsLocker.Lock();
bool mouseRelativeMode = Input::Mouse->IsRelative();
for (const auto& e : InputEvents)
{
auto window = e.Target ? e.Target : defaultWindow;
if (!window || !WindowsManager::Windows.Contains(window))
continue;
bool handleRelativeModeInputOnly = mouseRelativeMode;
if (handleRelativeModeInputOnly && window->GetCursor() == CursorType::Hidden && window->IsMouseTracking())
handleRelativeModeInputOnly = false;
switch (e.Type)
{
// Keyboard events
@@ -729,32 +748,43 @@ void InputService::Update()
break;
// Mouse events
case InputDevice::EventType::MouseDown:
window->OnMouseDown(window->ScreenToClient(e.MouseData.Position), e.MouseData.Button);
if (!handleRelativeModeInputOnly)
window->OnMouseDown(window->ScreenToClient(e.MouseData.Position), e.MouseData.Button);
break;
case InputDevice::EventType::MouseUp:
window->OnMouseUp(window->ScreenToClient(e.MouseData.Position), e.MouseData.Button);
if (!handleRelativeModeInputOnly)
window->OnMouseUp(window->ScreenToClient(e.MouseData.Position), e.MouseData.Button);
break;
case InputDevice::EventType::MouseDoubleClick:
window->OnMouseDoubleClick(window->ScreenToClient(e.MouseData.Position), e.MouseData.Button);
if (!handleRelativeModeInputOnly)
window->OnMouseDoubleClick(window->ScreenToClient(e.MouseData.Position), e.MouseData.Button);
break;
case InputDevice::EventType::MouseWheel:
window->OnMouseWheel(window->ScreenToClient(e.MouseWheelData.Position), e.MouseWheelData.WheelDelta);
if (!handleRelativeModeInputOnly)
window->OnMouseWheel(window->ScreenToClient(e.MouseWheelData.Position), e.MouseWheelData.WheelDelta);
break;
case InputDevice::EventType::MouseMove:
window->OnMouseMove(window->ScreenToClient(e.MouseData.Position));
if (!handleRelativeModeInputOnly)
window->OnMouseMove(window->ScreenToClient(e.MouseData.Position));
break;
case InputDevice::EventType::MouseMoveRelative:
window->OnMouseMoveRelative(e.MouseMovementData.PositionRelative);
break;
case InputDevice::EventType::MouseLeave:
window->OnMouseLeave();
break;
// Touch events
case InputDevice::EventType::TouchDown:
window->OnTouchDown(window->ScreenToClient(e.TouchData.Position), e.TouchData.PointerId);
if (!handleRelativeModeInputOnly)
window->OnTouchDown(window->ScreenToClient(e.TouchData.Position), e.TouchData.PointerId);
break;
case InputDevice::EventType::TouchMove:
window->OnTouchMove(window->ScreenToClient(e.TouchData.Position), e.TouchData.PointerId);
if (!handleRelativeModeInputOnly)
window->OnTouchMove(window->ScreenToClient(e.TouchData.Position), e.TouchData.PointerId);
break;
case InputDevice::EventType::TouchUp:
window->OnTouchUp(window->ScreenToClient(e.TouchData.Position), e.TouchData.PointerId);
if (!handleRelativeModeInputOnly)
window->OnTouchUp(window->ScreenToClient(e.TouchData.Position), e.TouchData.PointerId);
break;
}
}
@@ -799,6 +829,9 @@ void InputService::Update()
case InputDevice::EventType::MouseMove:
Input::MouseMove(e.MouseData.Position);
break;
case InputDevice::EventType::MouseMoveRelative:
Input::MouseMoveRelative(e.MouseMovementData.PositionRelative);
break;
case InputDevice::EventType::MouseLeave:
Input::MouseLeave();
break;
@@ -1011,12 +1044,14 @@ void InputService::Update()
}
}
#if !PLATFORM_SDL
// Lock mouse if need to
const auto lockMode = Screen::GetCursorLock();
if (lockMode == CursorLockMode::Locked)
{
Input::SetMousePosition(Screen::GetSize() * 0.5f);
}
#endif
// Send events for the active actions and axes (send events only in play mode)
if (!Time::GetGamePaused())