Explorar o código

Added MM_FREE mouse mode, which allows the cursor to move around and go out of the window also when hidden, and give accurate GetMousePosition() readings when inside the window. Closes #904.

Lasse Öörni %!s(int64=10) %!d(string=hai) anos
pai
achega
e55915502e

+ 4 - 1
Docs/Reference.dox

@@ -1658,7 +1658,7 @@ In AngelScript, the polling API is accessed via properties: input.keyDown[], inp
 
 \section InputMouseModes Mouse modes
 
-The operating system mouse cursor can be used in three modes which can be switched with \ref Input::SetMouseMode() "SetMouseMode()".
+The operating system mouse cursor can be used in four modes which can be switched with \ref Input::SetMouseMode() "SetMouseMode()".
 
 - MM_ABSOLUTE is the default behaviour, allowing the toggling of operating system cursor visibility and allowing the cursor to escape the window when visible.
   When the operating system cursor is invisible in absolute mouse mode, the mouse is confined to the window.
@@ -1672,6 +1672,9 @@ The operating system mouse cursor can be used in three modes which can be switch
 
 - MM_WRAP grabs the mouse from the operating system and confines the operating system cursor to the window, wrapping the cursor when it is near the edges.
   SetMouseMode(MM_WRAP) will call SetMouseGrabbed(true).
+  
+- MM_FREE does not grab/confine the mouse cursor even when it is hidden. This can be used for cases where the cursor should render using the operating system
+  outside the window, and perform custom rendering (with SetMouseVisible(false)) inside.
 
 \section InputJoystick Joystick input
 

+ 14 - 11
Source/Urho3D/Input/Input.cpp

@@ -284,7 +284,7 @@ void Input::Update()
     {
 #ifdef REQUIRE_CLICK_TO_FOCUS
         // When using the "click to focus" mechanism, only focus automatically in fullscreen or non-hidden mouse mode
-        if (!inputFocus_ && (mouseVisible_ || graphics_->GetFullscreen() || screenModeChanged_) && (flags & SDL_WINDOW_INPUT_FOCUS))
+        if (!inputFocus_ && ((mouseVisible_ || mouseMode_ == MM_FREE) || graphics_->GetFullscreen() || screenModeChanged_) && (flags & SDL_WINDOW_INPUT_FOCUS))
 #else
         if (!inputFocus_ && (flags & SDL_WINDOW_INPUT_FOCUS))
 #endif
@@ -361,7 +361,7 @@ void Input::Update()
     // Check for relative mode mouse move
     // Note that Emscripten will use SDL mouse move events for relative mode instead
 #ifndef EMSCRIPTEN
-    if (!touchEmulation_ && (graphics_->GetExternalWindow() || (!mouseVisible_ && inputFocus_ && (flags & SDL_WINDOW_MOUSE_FOCUS))))
+    if (!touchEmulation_ && (graphics_->GetExternalWindow() || ((!mouseVisible_ && mouseMode_ != MM_FREE) && inputFocus_ && (flags & SDL_WINDOW_MOUSE_FOCUS))))
 #else
     if (!touchEmulation_ && mouseMode_ != MM_RELATIVE && (graphics_->GetExternalWindow() || (!mouseVisible_ && inputFocus_ && (flags & SDL_WINDOW_MOUSE_FOCUS))))
 #endif
@@ -444,11 +444,14 @@ void Input::SetMouseVisible(bool enable, bool suppressEvent)
             {
                 SDL_ShowCursor(SDL_FALSE);
 #ifndef EMSCRIPTEN
-                // Recenter the mouse cursor manually when hiding it to avoid erratic mouse move for one frame
-                lastVisibleMousePosition_ = GetMousePosition();
-                IntVector2 center(graphics_->GetWidth() / 2, graphics_->GetHeight() / 2);
-                SetMousePosition(center);
-                lastMousePosition_ = center;
+                if (mouseMode_ != MM_FREE)
+                {
+                    // Recenter the mouse cursor manually when hiding it to avoid erratic mouse move for one frame
+                    lastVisibleMousePosition_ = GetMousePosition();
+                    IntVector2 center(graphics_->GetWidth() / 2, graphics_->GetHeight() / 2);
+                    SetMousePosition(center);
+                    lastMousePosition_ = center;
+                }
 #else
                 lastVisibleMousePosition_ = GetMousePosition();
                 lastMousePosition_ = lastVisibleMousePosition_;
@@ -557,7 +560,7 @@ void Input::SetMouseMode(MouseMode mode)
 #endif
 
         // Handle changing to new mode
-        if (mode == MM_ABSOLUTE)
+        if (mode == MM_ABSOLUTE || mode == MM_FREE)
         {
 #ifndef EMSCRIPTEN
             SetMouseGrabbed(false);
@@ -1565,9 +1568,9 @@ void Input::HandleSDLEvent(void* sdlEvent)
         // Emscripten will use SDL mouse move events for relative mode, as repositioning the mouse and
         // measuring distance from window center is not supported
 #ifndef EMSCRIPTEN
-        if (mouseVisible_ && !touchEmulation_)
+        if ((mouseVisible_ || mouseMode_ == MM_FREE) && !touchEmulation_)
 #else
-        if ((mouseVisible_ || mouseMode_ == MM_RELATIVE) && !touchEmulation_)
+        if ((mouseVisible_ || mouseMode_ == MM_RELATIVE || mouseMode_ == MM_FREE) && !touchEmulation_)
 #endif
         {
             mouseMove_.x_ += evt.motion.xrel;
@@ -1997,7 +2000,7 @@ void Input::HandleScreenMode(StringHash eventType, VariantMap& eventData)
     windowID_ = SDL_GetWindowID(window);
 
     // If screen mode happens due to mouse drag resize, do not recenter the mouse as that would lead to erratic window sizes
-    if (!mouseVisible_ && !inResize_)
+    if (!mouseVisible_ && mouseMode_ != MM_FREE && !inResize_)
     {
         IntVector2 center(graphics_->GetWidth() / 2, graphics_->GetHeight() / 2);
         SetMousePosition(center);

+ 5 - 1
Source/Urho3D/Input/Input.h

@@ -37,7 +37,8 @@ enum MouseMode
 {
     MM_ABSOLUTE = 0,
     MM_RELATIVE,
-    MM_WRAP
+    MM_WRAP,
+    MM_FREE
 };
 
 class Deserializer;
@@ -169,6 +170,9 @@ public:
      *
      *  MM_WRAP grabs the mouse from the operating system and confines the operating system cursor to the window, wrapping the cursor when it is near the edges.
      *  SetMouseMode(MM_WRAP) will call SetMouseGrabbed(true).
+     *
+     *  MM_FREE does not grab/confine the mouse cursor even when it is hidden. This can be used for cases where the cursor should render using the operating system
+     *  outside the window, and perform custom rendering (with SetMouseVisible(false)) inside.
     */
     void SetMouseMode(MouseMode mode);
     /// Add screen joystick.

+ 2 - 1
Source/Urho3D/LuaScript/pkgs/Input/Input.pkg

@@ -5,7 +5,8 @@ enum MouseMode
 {
     MM_ABSOLUTE = 0,
     MM_RELATIVE,
-    MM_WRAP
+    MM_WRAP,
+    MM_FREE
 };
 
 struct TouchState

+ 1 - 0
Source/Urho3D/Script/InputAPI.cpp

@@ -503,6 +503,7 @@ static void RegisterInput(asIScriptEngine* engine)
     engine->RegisterEnumValue("MouseMode", "MM_ABSOLUTE", MM_ABSOLUTE);
     engine->RegisterEnumValue("MouseMode", "MM_RELATIVE", MM_RELATIVE);
     engine->RegisterEnumValue("MouseMode", "MM_WRAP", MM_WRAP);
+    engine->RegisterEnumValue("MouseMode", "MM_FREE", MM_FREE);
 
     engine->RegisterObjectType("TouchState", 0, asOBJ_REF);
     engine->RegisterObjectBehaviour("TouchState", asBEHAVE_ADDREF, "void f()", asFUNCTION(FakeAddRef), asCALL_CDECL_OBJLAST);