diff --git a/Source/Engine/Engine/Screen.cpp b/Source/Engine/Engine/Screen.cpp
index c9efb9e05..40bc0341b 100644
--- a/Source/Engine/Engine/Screen.cpp
+++ b/Source/Engine/Engine/Screen.cpp
@@ -116,6 +116,19 @@ CursorLockMode Screen::GetCursorLock()
void Screen::SetCursorLock(CursorLockMode mode)
{
+#if USE_EDITOR
+ const auto win = Editor::Managed->GetGameWindow();
+#else
+ const auto win = Engine::MainWindow;
+#endif
+ if (win && mode == CursorLockMode::Clipped)
+ {
+ win->StartClippingCursor(win->GetClientBounds());
+ }
+ else if (win && CursorLock == CursorLockMode::Clipped)
+ {
+ win->EndClippingCursor();
+ }
CursorLock = mode;
}
diff --git a/Source/Engine/Input/Enums.h b/Source/Engine/Input/Enums.h
index 9600cd2b8..6dc4b78b1 100644
--- a/Source/Engine/Input/Enums.h
+++ b/Source/Engine/Input/Enums.h
@@ -21,6 +21,11 @@ API_ENUM() enum class CursorLockMode
/// Cursor position is locked to the center of the game window.
///
Locked = 1,
+
+ ///
+ /// Cursor position is confined to the bounds of the game window.
+ ///
+ Clipped = 2,
};
///
diff --git a/Source/Engine/Platform/Base/WindowBase.cpp b/Source/Engine/Platform/Base/WindowBase.cpp
index 6394c6d60..b884db38a 100644
--- a/Source/Engine/Platform/Base/WindowBase.cpp
+++ b/Source/Engine/Platform/Base/WindowBase.cpp
@@ -104,6 +104,7 @@ WindowBase::WindowBase(const CreateWindowSettings& settings)
, _trackingMouseOffset(Float2::Zero)
, _isUsingMouseOffset(false)
, _isTrackingMouse(false)
+ , _isClippingCursor(false)
, RenderTask(nullptr)
{
// Update window location based on start location
diff --git a/Source/Engine/Platform/Base/WindowBase.h b/Source/Engine/Platform/Base/WindowBase.h
index 638a7e84a..25b72bc4e 100644
--- a/Source/Engine/Platform/Base/WindowBase.h
+++ b/Source/Engine/Platform/Base/WindowBase.h
@@ -288,6 +288,7 @@ protected:
bool _isUsingMouseOffset;
Rectangle _mouseOffsetScreenSize;
bool _isTrackingMouse;
+ bool _isClippingCursor;
explicit WindowBase(const CreateWindowSettings& settings);
virtual ~WindowBase();
@@ -694,6 +695,29 @@ public:
{
}
+ ///
+ /// Starts the cursor clipping.
+ ///
+ /// The bounds that the cursor will be confined to.
+ API_FUNCTION() virtual void StartClippingCursor(const Rectangle& bounds)
+ {
+ }
+
+ ///
+ /// Gets the value indicating whenever the cursor is being clipped.
+ ///
+ API_PROPERTY() bool IsCursorClipping() const
+ {
+ return _isClippingCursor;
+ }
+
+ ///
+ /// Ends the cursor clipping.
+ ///
+ API_FUNCTION() virtual void EndClippingCursor()
+ {
+ }
+
///
/// Gets the mouse cursor.
///
diff --git a/Source/Engine/Platform/Windows/WindowsWindow.cpp b/Source/Engine/Platform/Windows/WindowsWindow.cpp
index 724c86049..ce2affa44 100644
--- a/Source/Engine/Platform/Windows/WindowsWindow.cpp
+++ b/Source/Engine/Platform/Windows/WindowsWindow.cpp
@@ -564,6 +564,34 @@ void WindowsWindow::EndTrackingMouse()
}
}
+void WindowsWindow::StartClippingCursor(const Rectangle& bounds)
+{
+ ASSERT(HasHWND());
+
+ if (!_isClippingCursor)
+ {
+ _isClippingCursor = true;
+ }
+
+ const RECT lpRect = {
+ bounds.GetUpperLeft().X,
+ bounds.GetUpperLeft().Y,
+ bounds.GetBottomRight().X,
+ bounds.GetBottomRight().Y
+ };
+ ClipCursor(&lpRect);
+}
+
+void WindowsWindow::EndClippingCursor()
+{
+ if (_isClippingCursor)
+ {
+ _isClippingCursor = false;
+
+ ClipCursor(NULL);
+ }
+}
+
void WindowsWindow::SetCursor(CursorType type)
{
// Base
diff --git a/Source/Engine/Platform/Windows/WindowsWindow.h b/Source/Engine/Platform/Windows/WindowsWindow.h
index 82f1f9909..73ad56f39 100644
--- a/Source/Engine/Platform/Windows/WindowsWindow.h
+++ b/Source/Engine/Platform/Windows/WindowsWindow.h
@@ -120,6 +120,8 @@ public:
DragDropEffect DoDragDrop(const StringView& data) override;
void StartTrackingMouse(bool useMouseScreenOffset) override;
void EndTrackingMouse() override;
+ void StartClippingCursor(const Rectangle& bounds) override;
+ void EndClippingCursor() override;
void SetCursor(CursorType type) override;
#if USE_EDITOR