diff --git a/Source/Editor/GUI/Input/ValueBox.cs b/Source/Editor/GUI/Input/ValueBox.cs
index 674ee0697..13e8ef5ce 100644
--- a/Source/Editor/GUI/Input/ValueBox.cs
+++ b/Source/Editor/GUI/Input/ValueBox.cs
@@ -266,6 +266,7 @@ namespace FlaxEditor.GUI.Input
return base.OnMouseDown(location, button);
}
+#if !PLATFORM_SDL
///
public override void OnMouseMove(Float2 location)
{
@@ -292,6 +293,36 @@ namespace FlaxEditor.GUI.Input
base.OnMouseMove(location);
}
+#else
+
+ ///
+ public override void OnMouseMoveRelative(Float2 mouseMotion)
+ {
+ var location = Root.TrackingMouseOffset;
+ if (_isSliding)
+ {
+ // Update sliding
+ ApplySliding(Root.TrackingMouseOffset.X * _slideSpeed);
+ return;
+ }
+
+ // Update cursor type so user knows they can slide value
+ if (CanUseSliding && SlideRect.Contains(location) && !_isSliding)
+ {
+ Cursor = CursorType.SizeWE;
+ _cursorChanged = true;
+ }
+ else if (_cursorChanged && !_isSliding)
+ {
+ Cursor = CursorType.Default;
+ _cursorChanged = false;
+ }
+
+ base.OnMouseMoveRelative(mouseMotion);
+ }
+
+#endif
+
///
public override bool OnMouseUp(Float2 location, MouseButton button)
{
diff --git a/Source/Editor/Managed/ManagedEditor.Internal.cpp b/Source/Editor/Managed/ManagedEditor.Internal.cpp
index de7532921..9ae0b71e9 100644
--- a/Source/Editor/Managed/ManagedEditor.Internal.cpp
+++ b/Source/Editor/Managed/ManagedEditor.Internal.cpp
@@ -435,6 +435,9 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_RunVisualScriptBreakpointLoopTick(floa
case InputDevice::EventType::MouseMove:
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;
diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs
index eaf243726..0df9f8aa1 100644
--- a/Source/Editor/Viewport/EditorViewport.cs
+++ b/Source/Editor/Viewport/EditorViewport.cs
@@ -158,18 +158,22 @@ namespace FlaxEditor.Viewport
private float _movementSpeed;
private float _minMovementSpeed;
private float _maxMovementSpeed;
+#if !PLATFORM_SDL
private float _mouseAccelerationScale;
private bool _useMouseFiltering;
private bool _useMouseAcceleration;
+#endif
// Input
internal bool _disableInputUpdate;
private bool _isControllingMouse, _isViewportControllingMouse, _wasVirtualMouseRightDown, _isVirtualMouseRightDown;
- private int _deltaFilteringStep;
private Float2 _startPos;
+#if !PLATFORM_SDL
private Float2 _mouseDeltaLast;
+ private int _deltaFilteringStep;
private Float2[] _deltaFilteringBuffer = new Float2[FpsCameraFilteringFrames];
+#endif
///
/// The previous input (from the previous update).
@@ -522,10 +526,11 @@ namespace FlaxEditor.Viewport
: base(task)
{
_editor = Editor.Instance;
-
+#if !PLATFORM_SDL
_mouseAccelerationScale = 0.1f;
_useMouseFiltering = false;
_useMouseAcceleration = false;
+#endif
_camera = camera;
if (_camera != null)
_camera.Viewport = this;
@@ -1460,7 +1465,9 @@ namespace FlaxEditor.Viewport
// Hide cursor and start tracking mouse movement
win.StartTrackingMouse(false);
win.Cursor = CursorType.Hidden;
+ win.MouseMoveRelative += OnMouseMoveRelative;
+#if !PLATFORM_SDL
// Center mouse position if it's too close to the edge
var size = Size;
var center = Float2.Round(size * 0.5f);
@@ -1469,6 +1476,7 @@ namespace FlaxEditor.Viewport
_viewMousePos = center;
win.MousePosition = PointToWindow(_viewMousePos);
}
+#endif
}
///
@@ -1480,6 +1488,7 @@ namespace FlaxEditor.Viewport
// Restore cursor and stop tracking mouse movement
win.Cursor = CursorType.Default;
win.EndTrackingMouse();
+ win.MouseMoveRelative -= OnMouseMoveRelative;
}
///
@@ -1584,6 +1593,14 @@ namespace FlaxEditor.Viewport
else
EndMouseCapture();
}
+#if PLATFORM_SDL
+ bool useMouse = IsControllingMouse || true;
+ _prevInput = _input;
+ if (canUseInput && ContainsFocus)
+ _input.Gather(win.Window, useMouse, ref _prevInput);
+ else
+ _input.Clear();
+#else
bool useMouse = IsControllingMouse || (Mathf.IsInRange(_viewMousePos.X, 0, Width) && Mathf.IsInRange(_viewMousePos.Y, 0, Height));
_prevInput = _input;
var hit = GetChildAt(_viewMousePos, c => c.Visible && !(c is CanvasRootControl) && !(c is UIEditorRoot));
@@ -1591,6 +1608,7 @@ namespace FlaxEditor.Viewport
_input.Gather(win.Window, useMouse, ref _prevInput);
else
_input.Clear();
+#endif
// Track controlling mouse state change
bool wasControllingMouse = _prevInput.IsControllingMouse;
@@ -1699,6 +1717,10 @@ namespace FlaxEditor.Viewport
if (_input.IsControlDown)
moveDelta *= 0.3f;
+#if PLATFORM_SDL
+ var mouseDelta = _mouseDelta;
+ _mouseDelta = Float2.Zero;
+#else
// Calculate smooth mouse delta not dependant on viewport size
var offset = _viewMousePos - _startPos;
if (_input.IsZooming && !_input.IsMouseRightDown && !_input.IsMouseLeftDown && !_input.IsMouseMiddleDown && !_isOrtho && !rmbWheel && !_isVirtualMouseRightDown)
@@ -1740,6 +1762,7 @@ namespace FlaxEditor.Viewport
mouseDelta += _mouseDeltaLast * _mouseAccelerationScale;
_mouseDeltaLast = currentDelta;
}
+#endif
// Update
moveDelta *= dt * (60.0f * 4.0f);
@@ -1748,12 +1771,14 @@ namespace FlaxEditor.Viewport
mouseDelta *= new Float2(1, -1);
UpdateView(dt, ref moveDelta, ref mouseDelta, out var centerMouse);
+#if !PLATFORM_SDL
// Move mouse back to the root position
if (centerMouse && (_input.IsMouseRightDown || _input.IsMouseLeftDown || _input.IsMouseMiddleDown || _isVirtualMouseRightDown))
{
var center = PointToWindow(_startPos);
win.MousePosition = center;
}
+#endif
// Change Ortho size on mouse scroll
if (_isOrtho && !rmbWheel)
@@ -1765,6 +1790,8 @@ namespace FlaxEditor.Viewport
}
else
{
+#if PLATFORM_SDL
+#else
if (_input.IsMouseLeftDown || _input.IsMouseRightDown || _isVirtualMouseRightDown)
{
// Calculate smooth mouse delta not dependant on viewport size
@@ -1779,6 +1806,7 @@ namespace FlaxEditor.Viewport
_mouseDelta = Float2.Zero;
}
_mouseDeltaLast = Float2.Zero;
+#endif
if (ContainsFocus)
{
@@ -1828,6 +1856,12 @@ namespace FlaxEditor.Viewport
_input.MouseWheelDelta = 0;
}
+ ///
+ public void OnMouseMoveRelative(ref Float2 mouseMotion)
+ {
+ _mouseDelta += mouseMotion;
+ }
+
///
public override bool OnMouseDown(Float2 location, MouseButton button)
{
diff --git a/Source/Engine/Engine/Screen.cpp b/Source/Engine/Engine/Screen.cpp
index 703f89c87..4131e11b4 100644
--- a/Source/Engine/Engine/Screen.cpp
+++ b/Source/Engine/Engine/Screen.cpp
@@ -106,13 +106,25 @@ void Screen::SetCursorVisible(const bool value)
#else
const auto win = Engine::MainWindow;
#endif
+ bool focused = false;
if (win && Engine::HasGameViewportFocus())
{
win->SetCursor(value ? CursorType::Default : CursorType::Hidden);
+ focused = true;
}
else if (win)
win->SetCursor(CursorType::Default);
CursorVisible = value;
+
+ // Just enable relative mode when cursor is constrained and not visible
+ if (CursorLock != CursorLockMode::None && !CursorVisible && focused)
+ {
+ Input::Mouse->SetRelativeMode(true);
+ }
+ else if (CursorLock == CursorLockMode::None || CursorVisible || !focused)
+ {
+ Input::Mouse->SetRelativeMode(false);
+ }
}
CursorLockMode Screen::GetCursorLock()
@@ -141,6 +153,17 @@ void Screen::SetCursorLock(CursorLockMode mode)
win->EndClippingCursor();
}
CursorLock = mode;
+
+ // Just enable relative mode when cursor is constrained and not visible
+ bool focused = win && Engine::HasGameViewportFocus();
+ if (CursorLock != CursorLockMode::None && !CursorVisible && focused)
+ {
+ Input::Mouse->SetRelativeMode(true);
+ }
+ else if (CursorLock == CursorLockMode::None || CursorVisible || !focused)
+ {
+ Input::Mouse->SetRelativeMode(false);
+ }
}
GameWindowMode Screen::GetGameWindowMode()
diff --git a/Source/Engine/Input/Input.cpp b/Source/Engine/Input/Input.cpp
index 7a4d0592c..3cd69e490 100644
--- a/Source/Engine/Input/Input.cpp
+++ b/Source/Engine/Input/Input.cpp
@@ -78,6 +78,7 @@ Delegate Input::MouseUp;
Delegate Input::MouseDoubleClick;
Delegate Input::MouseWheel;
Delegate Input::MouseMove;
+Delegate Input::MouseMoveRelative;
Action Input::MouseLeave;
Delegate Input::TouchDown;
Delegate Input::TouchMove;
@@ -208,6 +209,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();
@@ -273,6 +282,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;
@@ -933,6 +947,9 @@ void InputService::Update()
case InputDevice::EventType::MouseMove:
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;
@@ -989,6 +1006,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;
@@ -1202,6 +1222,7 @@ void InputService::Update()
}
}
+#if !PLATFORM_SDL
// Lock mouse if need to
const auto lockMode = Screen::GetCursorLock();
if (lockMode == CursorLockMode::Locked)
@@ -1210,6 +1231,7 @@ void InputService::Update()
Screen::ScreenToGameViewport(Float2::Zero);
Input::SetMousePosition(pos);
}
+#endif
// Send events for the active actions and axes (send events only in play mode)
if (!Time::GetGamePaused())
diff --git a/Source/Engine/Input/Input.h b/Source/Engine/Input/Input.h
index 8cc1b2106..0021f99a5 100644
--- a/Source/Engine/Input/Input.h
+++ b/Source/Engine/Input/Input.h
@@ -108,6 +108,11 @@ public:
///
API_EVENT() static Delegate MouseMove;
+ ///
+ /// Event fired when mouse moves while in relative mode.
+ ///
+ API_EVENT() static Delegate MouseMoveRelative;
+
///
/// Event fired when mouse leaves window.
///
diff --git a/Source/Engine/Input/InputDevice.h b/Source/Engine/Input/InputDevice.h
index 5d2a383be..80f98fbdd 100644
--- a/Source/Engine/Input/InputDevice.h
+++ b/Source/Engine/Input/InputDevice.h
@@ -25,6 +25,7 @@ public:
MouseDoubleClick,
MouseWheel,
MouseMove,
+ MouseMoveRelative,
MouseLeave,
TouchDown,
TouchMove,
@@ -54,6 +55,11 @@ public:
Float2 Position;
} MouseData;
+ struct
+ {
+ Float2 PositionRelative;
+ } MouseMovementData;
+
struct
{
float WheelDelta;
diff --git a/Source/Engine/Input/Mouse.h b/Source/Engine/Input/Mouse.h
index e5e1b3639..44738f607 100644
--- a/Source/Engine/Input/Mouse.h
+++ b/Source/Engine/Input/Mouse.h
@@ -46,12 +46,14 @@ public:
protected:
State _state;
State _prevState;
+ bool _relativeMode;
explicit Mouse()
: InputDevice(SpawnParams(Guid::New(), TypeInitializer), TEXT("Mouse"))
{
_state.Clear();
_prevState.Clear();
+ _relativeMode = false;
}
public:
@@ -114,6 +116,14 @@ public:
return !_state.MouseButtons[static_cast(button)] && _prevState.MouseButtons[static_cast(button)];
}
+ ///
+ /// Gets the current state of mouse relative mode.
+ ///
+ API_FUNCTION() FORCE_INLINE bool IsRelative() const
+ {
+ return _relativeMode;
+ }
+
public:
///
/// Sets the mouse position.
@@ -121,6 +131,16 @@ public:
/// The new position.
virtual void SetMousePosition(const Float2& newPosition) = 0;
+ ///
+ /// Sets the mouse relative mode state. While enabled, the mouse movement tracking becomes more accurate.
+ /// The cursor will be hidden while in relative mode.
+ ///
+ /// The new relative mode state.
+ virtual void SetRelativeMode(bool relativeMode)
+ {
+ _relativeMode = relativeMode;
+ }
+
///
/// Called when mouse cursor gets moved by the application. Invalidates the previous cached mouse position to prevent mouse jitter when locking the cursor programmatically.
///
@@ -158,6 +178,13 @@ public:
/// The target window to receive this event, otherwise input system will pick the window automatically.
void OnMouseMove(const Float2& position, Window* target = nullptr);
+ ///
+ /// Called when mouse moves in relative mode.
+ ///
+ /// The mouse position change.
+ /// The target window to receive this event, otherwise input system will pick the window automatically.
+ void OnMouseMoveRelative(const Float2& positionRelative, Window* target = nullptr);
+
///
/// Called when mouse leaves the input source area.
///
diff --git a/Source/Engine/Platform/Base/WindowBase.cpp b/Source/Engine/Platform/Base/WindowBase.cpp
index 4d7a925d7..befe86246 100644
--- a/Source/Engine/Platform/Base/WindowBase.cpp
+++ b/Source/Engine/Platform/Base/WindowBase.cpp
@@ -257,6 +257,13 @@ void WindowBase::OnMouseMove(const Float2& mousePosition)
INVOKE_EVENT_PARAMS_1(OnMouseMove, (void*)&mousePosition);
}
+void WindowBase::OnMouseMoveRelative(const Float2& mousePositionRelative)
+{
+ PROFILE_CPU_NAMED("GUI.OnMouseMoveRelative");
+ MouseMoveRelative(mousePositionRelative);
+ INVOKE_EVENT_PARAMS_1(OnMouseMoveRelative, (void*)&mousePositionRelative);
+}
+
void WindowBase::OnMouseLeave()
{
PROFILE_CPU_NAMED("GUI.OnMouseLeave");
diff --git a/Source/Engine/Platform/Base/WindowBase.h b/Source/Engine/Platform/Base/WindowBase.h
index f92502c18..db9a83839 100644
--- a/Source/Engine/Platform/Base/WindowBase.h
+++ b/Source/Engine/Platform/Base/WindowBase.h
@@ -592,6 +592,12 @@ public:
MouseDelegate MouseMove;
void OnMouseMove(const Float2& mousePosition);
+ ///
+ /// Event fired when mouse moves in relative mode.
+ ///
+ MouseDelegate MouseMoveRelative;
+ void OnMouseMoveRelative(const Float2& mousePositionRelative);
+
///
/// Event fired when mouse leaves window.
///
diff --git a/Source/Engine/Platform/Linux/LinuxWindow.cpp b/Source/Engine/Platform/Linux/LinuxWindow.cpp
index 5761685c8..f50fbce7f 100644
--- a/Source/Engine/Platform/Linux/LinuxWindow.cpp
+++ b/Source/Engine/Platform/Linux/LinuxWindow.cpp
@@ -616,7 +616,7 @@ void LinuxWindow::OnButtonPress(void* event)
}
// Handle double-click
- if (buttonEvent->button == Button1)
+ if (buttonEvent->button == Button1 && !Input::Mouse->IsRelative())
{
if (
buttonEvent->time < (MouseLastButtonPressTime + MouseDoubleClickTime) &&
diff --git a/Source/Engine/Platform/Mac/MacWindow.cpp b/Source/Engine/Platform/Mac/MacWindow.cpp
index ebccb5709..49a30ab42 100644
--- a/Source/Engine/Platform/Mac/MacWindow.cpp
+++ b/Source/Engine/Platform/Mac/MacWindow.cpp
@@ -507,7 +507,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
Float2 mousePos = GetMousePosition(Window, event);
mousePos = Window->ClientToScreen(mousePos);
MouseButton mouseButton = MouseButton::Left;
- if ([event clickCount] == 2)
+ if ([event clickCount] == 2 && !Input::Mouse->IsRelative())
Input::Mouse->OnMouseDoubleClick(mousePos, mouseButton, Window);
else
Input::Mouse->OnMouseDown(mousePos, mouseButton, Window);
@@ -544,7 +544,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
if (IsWindowInvalid(Window)) return;
Float2 mousePos = GetMousePosition(Window, event);
MouseButton mouseButton = MouseButton::Right;
- if ([event clickCount] == 2)
+ if ([event clickCount] == 2 && !Input::Mouse->IsRelative())
Input::Mouse->OnMouseDoubleClick(Window->ClientToScreen(mousePos), mouseButton, Window);
else
Input::Mouse->OnMouseDown(Window->ClientToScreen(mousePos), mouseButton, Window);
@@ -582,7 +582,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
default:
return;
}
- if ([event clickCount] == 2)
+ if ([event clickCount] == 2 && !Input::Mouse->IsRelative())
Input::Mouse->OnMouseDoubleClick(Window->ClientToScreen(mousePos), mouseButton, Window);
else
Input::Mouse->OnMouseDown(Window->ClientToScreen(mousePos), mouseButton, Window);
diff --git a/Source/Engine/Platform/SDL/SDLInput.cpp b/Source/Engine/Platform/SDL/SDLInput.cpp
index 720da2875..d73d28c47 100644
--- a/Source/Engine/Platform/SDL/SDLInput.cpp
+++ b/Source/Engine/Platform/SDL/SDLInput.cpp
@@ -474,8 +474,16 @@ bool SDLInput::HandleEvent(SDLWindow* window, SDL_Event& event)
{
case SDL_EVENT_MOUSE_MOTION:
{
- const Float2 mousePos = window->ClientToScreen({ event.motion.x, event.motion.y });
- Input::Mouse->OnMouseMove(mousePos, window);
+ if (Input::Mouse->IsRelative())
+ {
+ const Float2 mouseDelta(event.motion.xrel, event.motion.yrel);
+ Input::Mouse->OnMouseMoveRelative(mouseDelta, window);
+ }
+ else
+ {
+ const Float2 mousePos = window->ClientToScreen({ event.motion.x, event.motion.y });
+ Input::Mouse->OnMouseMove(mousePos, window);
+ }
return true;
}
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
@@ -486,7 +494,7 @@ bool SDLInput::HandleEvent(SDLWindow* window, SDL_Event& event)
case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP:
{
- const Float2 mousePos = window->ClientToScreen({ event.button.x, event.button.y });
+ Float2 mousePos = window->ClientToScreen({ event.button.x, event.button.y });
MouseButton button = MouseButton::None;
if (event.button.button == SDL_BUTTON_LEFT)
button = MouseButton::Left;
@@ -499,9 +507,16 @@ bool SDLInput::HandleEvent(SDLWindow* window, SDL_Event& event)
else if (event.button.button == SDL_BUTTON_X2)
button = MouseButton::Extended2;
+ if (Input::Mouse->IsRelative())
+ {
+ // Use the previous visible mouse position here, the event or global
+ // mouse position would cause input to trigger in other editor windows.
+ mousePos = SDLInputImpl::Mouse->GetMousePosition();
+ }
+
if (event.button.state == SDL_RELEASED)
Input::Mouse->OnMouseUp(mousePos, button, window);
- // Prevent sending mouse down event when double-clicking
+ // Prevent sending multiple mouse down event when double-clicking UI elements
else if (event.button.clicks % 2 == 1)
Input::Mouse->OnMouseDown(mousePos, button, window);
else
@@ -511,9 +526,16 @@ bool SDLInput::HandleEvent(SDLWindow* window, SDL_Event& event)
}
case SDL_EVENT_MOUSE_WHEEL:
{
- const Float2 mousePos = window->ClientToScreen({ event.wheel.mouse_x, event.wheel.mouse_y });
+ Float2 mousePos = window->ClientToScreen({ event.wheel.mouse_x, event.wheel.mouse_y });
const float delta = event.wheel.y;
+ if (Input::Mouse->IsRelative())
+ {
+ // Use the previous visible mouse position here, the event or global
+ // mouse position would cause input to trigger in other editor windows.
+ mousePos = SDLInputImpl::Mouse->GetMousePosition();
+ }
+
Input::Mouse->OnMouseWheel(mousePos, delta, window);
return true;
}
diff --git a/Source/Engine/Platform/SDL/SDLWindow.cpp b/Source/Engine/Platform/SDL/SDLWindow.cpp
index ed540325e..600705398 100644
--- a/Source/Engine/Platform/SDL/SDLWindow.cpp
+++ b/Source/Engine/Platform/SDL/SDLWindow.cpp
@@ -957,6 +957,10 @@ void SDLWindow::StartTrackingMouse(bool useMouseScreenOffset)
{
if (SDL_CaptureMouse(SDL_TRUE) != 0)
LOG(Warning, "SDL_CaptureMouse: {0}", String(SDL_GetError()));
+
+ // For viewport camera mouse tracking we want to use relative mode for best precision
+ if (_cursor == CursorType::Hidden)
+ Input::Mouse->SetRelativeMode(true);
}
}
@@ -973,6 +977,7 @@ void SDLWindow::EndTrackingMouse()
LOG(Warning, "SDL_CaptureMouse: {0}", String(SDL_GetError()));
//SDL_SetWindowGrab(_window, SDL_FALSE);
+ Input::Mouse->SetRelativeMode(false);
}
void SDLWindow::StartClippingCursor(const Rectangle& bounds)
@@ -1038,9 +1043,14 @@ void SDLWindow::UpdateCursor() const
if (_cursor == CursorType::Hidden)
{
SDL_HideCursor();
+
+ if (_isTrackingMouse)
+ Input::Mouse->SetRelativeMode(true);
return;
}
SDL_ShowCursor();
+ //if (_isTrackingMouse)
+ // Input::Mouse->SetRelativeMode(false);
int32 index = SDL_SYSTEM_CURSOR_DEFAULT;
switch (_cursor)
diff --git a/Source/Engine/Platform/Window.cs b/Source/Engine/Platform/Window.cs
index 86b872513..06b02457a 100644
--- a/Source/Engine/Platform/Window.cs
+++ b/Source/Engine/Platform/Window.cs
@@ -17,31 +17,37 @@ namespace FlaxEngine
///
/// Perform window hit test delegate.
///
- /// The mouse position. The coordinate is relative to the upper-left corner of the screen. Use to convert position into client space coordinates.
+ /// The mouse position. The coordinate is relative to the upper-left corner of the screen. Use to convert position into client space coordinates.
/// Hit result.
- public delegate WindowHitCodes HitTestDelegate(ref Float2 mouse);
+ public delegate WindowHitCodes HitTestDelegate(ref Float2 mousePosition);
///
/// Perform mouse buttons action.
///
- /// The mouse position.
+ /// The mouse position.
/// The mouse buttons state.
/// The flag that indicated that event has been handled by the custom code and should not be passed further. By default it is set to false.
- public delegate void MouseButtonDelegate(ref Float2 mouse, MouseButton button, ref bool handled);
+ public delegate void MouseButtonDelegate(ref Float2 mousePosition, MouseButton button, ref bool handled);
///
/// Perform mouse move action.
///
- /// The mouse position.
- public delegate void MouseMoveDelegate(ref Float2 mouse);
+ /// The mouse position.
+ public delegate void MouseMoveDelegate(ref Float2 mousePosition);
+
+ ///
+ /// Perform mouse move action in relative mode.
+ ///
+ /// The relative mouse motion.
+ public delegate void MouseMoveRelativeDelegate(ref Float2 mouseMotion);
///
/// Perform mouse wheel action.
///
- /// The mouse position.
+ /// The mouse position.
/// The mouse wheel move delta (can be positive or negative; normalized to [-1;1] range).
/// The flag that indicated that event has been handled by the custom code and should not be passed further. By default it is set to false.
- public delegate void MouseWheelDelegate(ref Float2 mouse, float delta, ref bool handled);
+ public delegate void MouseWheelDelegate(ref Float2 mousePosition, float delta, ref bool handled);
///
/// Perform touch action.
@@ -99,9 +105,14 @@ namespace FlaxEngine
public event MouseWheelDelegate MouseWheel;
///
- /// Event fired when mouse moves
+ /// Event fired when mouse moves.
///
public event MouseMoveDelegate MouseMove;
+
+ ///
+ /// Event fired when mouse moves in relative mode.
+ ///
+ public event MouseMoveRelativeDelegate MouseMoveRelative;
///
/// Event fired when mouse leaves window.
@@ -273,6 +284,12 @@ namespace FlaxEngine
MouseMove?.Invoke(ref pos);
GUI.OnMouseMove(pos);
}
+
+ internal void Internal_OnMouseMoveRelative(ref Float2 mouseMotion)
+ {
+ MouseMoveRelative?.Invoke(ref mouseMotion);
+ GUI.OnMouseMoveRelative(mouseMotion);
+ }
internal void Internal_OnMouseLeave()
{
diff --git a/Source/Engine/Platform/Windows/WindowsInput.cpp b/Source/Engine/Platform/Windows/WindowsInput.cpp
index a772c4c33..64299b6a3 100644
--- a/Source/Engine/Platform/Windows/WindowsInput.cpp
+++ b/Source/Engine/Platform/Windows/WindowsInput.cpp
@@ -265,19 +265,38 @@ bool WindowsMouse::WndProc(Window* window, const UINT msg, WPARAM wParam, LPARAM
}
case WM_LBUTTONDBLCLK:
{
- OnMouseDoubleClick(mousePos, MouseButton::Left, window);
+ if (!Input::Mouse->IsRelative())
+ OnMouseDoubleClick(mousePos, MouseButton::Left, window);
+ else
+ OnMouseDown(mousePos, MouseButton::Left, window);
result = true;
break;
}
case WM_RBUTTONDBLCLK:
{
- OnMouseDoubleClick(mousePos, MouseButton::Right, window);
+ if (!Input::Mouse->IsRelative())
+ OnMouseDoubleClick(mousePos, MouseButton::Right, window);
+ else
+ OnMouseDown(mousePos, MouseButton::Right, window);
result = true;
break;
}
case WM_MBUTTONDBLCLK:
{
- OnMouseDoubleClick(mousePos, MouseButton::Middle, window);
+ if (!Input::Mouse->IsRelative())
+ OnMouseDoubleClick(mousePos, MouseButton::Middle, window);
+ else
+ OnMouseDown(mousePos, MouseButton::Middle, window);
+ result = true;
+ break;
+ }
+ case WM_XBUTTONDBLCLK:
+ {
+ const auto button = (HIWORD(wParam) & XBUTTON1) ? MouseButton::Extended1 : MouseButton::Extended2;
+ if (!Input::Mouse->IsRelative())
+ OnMouseDoubleClick(mousePos, button, window);
+ else
+ OnMouseDown(mousePos, button, window);
result = true;
break;
}
diff --git a/Source/Engine/UI/GUI/Control.cs b/Source/Engine/UI/GUI/Control.cs
index c96ee0643..ef3ee5f91 100644
--- a/Source/Engine/UI/GUI/Control.cs
+++ b/Source/Engine/UI/GUI/Control.cs
@@ -769,6 +769,15 @@ namespace FlaxEngine.GUI
Tooltip?.OnMouseLeaveControl(this);
}
}
+
+ ///
+ /// When mouse moves over control's area while mouse is in relative mode
+ ///
+ /// Mouse relative motion
+ [NoAnimate]
+ public virtual void OnMouseMoveRelative(Float2 mouseMotion)
+ {
+ }
///
/// When mouse leaves control's area
diff --git a/Source/Engine/UI/GUI/WindowRootControl.cs b/Source/Engine/UI/GUI/WindowRootControl.cs
index f39cf0346..20351e2df 100644
--- a/Source/Engine/UI/GUI/WindowRootControl.cs
+++ b/Source/Engine/UI/GUI/WindowRootControl.cs
@@ -338,5 +338,17 @@ namespace FlaxEngine.GUI
base.OnMouseMove(location);
}
+
+ ///
+ public override void OnMouseMoveRelative(Float2 mouseMotion)
+ {
+ if (_trackingControl != null)
+ {
+ _trackingControl.OnMouseMoveRelative(mouseMotion);
+ return;
+ }
+
+ base.OnMouseMoveRelative(mouseMotion);
+ }
}
}