Browse Source

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 10 years ago
parent
commit
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
 \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.
 - 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.
   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.
 - 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).
   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
 \section InputJoystick Joystick input
 
 

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

@@ -284,7 +284,7 @@ void Input::Update()
     {
     {
 #ifdef REQUIRE_CLICK_TO_FOCUS
 #ifdef REQUIRE_CLICK_TO_FOCUS
         // When using the "click to focus" mechanism, only focus automatically in fullscreen or non-hidden mouse mode
         // 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
 #else
         if (!inputFocus_ && (flags & SDL_WINDOW_INPUT_FOCUS))
         if (!inputFocus_ && (flags & SDL_WINDOW_INPUT_FOCUS))
 #endif
 #endif
@@ -361,7 +361,7 @@ void Input::Update()
     // Check for relative mode mouse move
     // Check for relative mode mouse move
     // Note that Emscripten will use SDL mouse move events for relative mode instead
     // Note that Emscripten will use SDL mouse move events for relative mode instead
 #ifndef EMSCRIPTEN
 #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
 #else
     if (!touchEmulation_ && mouseMode_ != MM_RELATIVE && (graphics_->GetExternalWindow() || (!mouseVisible_ && inputFocus_ && (flags & SDL_WINDOW_MOUSE_FOCUS))))
     if (!touchEmulation_ && mouseMode_ != MM_RELATIVE && (graphics_->GetExternalWindow() || (!mouseVisible_ && inputFocus_ && (flags & SDL_WINDOW_MOUSE_FOCUS))))
 #endif
 #endif
@@ -444,11 +444,14 @@ void Input::SetMouseVisible(bool enable, bool suppressEvent)
             {
             {
                 SDL_ShowCursor(SDL_FALSE);
                 SDL_ShowCursor(SDL_FALSE);
 #ifndef EMSCRIPTEN
 #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
 #else
                 lastVisibleMousePosition_ = GetMousePosition();
                 lastVisibleMousePosition_ = GetMousePosition();
                 lastMousePosition_ = lastVisibleMousePosition_;
                 lastMousePosition_ = lastVisibleMousePosition_;
@@ -557,7 +560,7 @@ void Input::SetMouseMode(MouseMode mode)
 #endif
 #endif
 
 
         // Handle changing to new mode
         // Handle changing to new mode
-        if (mode == MM_ABSOLUTE)
+        if (mode == MM_ABSOLUTE || mode == MM_FREE)
         {
         {
 #ifndef EMSCRIPTEN
 #ifndef EMSCRIPTEN
             SetMouseGrabbed(false);
             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
         // Emscripten will use SDL mouse move events for relative mode, as repositioning the mouse and
         // measuring distance from window center is not supported
         // measuring distance from window center is not supported
 #ifndef EMSCRIPTEN
 #ifndef EMSCRIPTEN
-        if (mouseVisible_ && !touchEmulation_)
+        if ((mouseVisible_ || mouseMode_ == MM_FREE) && !touchEmulation_)
 #else
 #else
-        if ((mouseVisible_ || mouseMode_ == MM_RELATIVE) && !touchEmulation_)
+        if ((mouseVisible_ || mouseMode_ == MM_RELATIVE || mouseMode_ == MM_FREE) && !touchEmulation_)
 #endif
 #endif
         {
         {
             mouseMove_.x_ += evt.motion.xrel;
             mouseMove_.x_ += evt.motion.xrel;
@@ -1997,7 +2000,7 @@ void Input::HandleScreenMode(StringHash eventType, VariantMap& eventData)
     windowID_ = SDL_GetWindowID(window);
     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 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);
         IntVector2 center(graphics_->GetWidth() / 2, graphics_->GetHeight() / 2);
         SetMousePosition(center);
         SetMousePosition(center);

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

@@ -37,7 +37,8 @@ enum MouseMode
 {
 {
     MM_ABSOLUTE = 0,
     MM_ABSOLUTE = 0,
     MM_RELATIVE,
     MM_RELATIVE,
-    MM_WRAP
+    MM_WRAP,
+    MM_FREE
 };
 };
 
 
 class Deserializer;
 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.
      *  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).
      *  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);
     void SetMouseMode(MouseMode mode);
     /// Add screen joystick.
     /// Add screen joystick.

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

@@ -5,7 +5,8 @@ enum MouseMode
 {
 {
     MM_ABSOLUTE = 0,
     MM_ABSOLUTE = 0,
     MM_RELATIVE,
     MM_RELATIVE,
-    MM_WRAP
+    MM_WRAP,
+    MM_FREE
 };
 };
 
 
 struct TouchState
 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_ABSOLUTE", MM_ABSOLUTE);
     engine->RegisterEnumValue("MouseMode", "MM_RELATIVE", MM_RELATIVE);
     engine->RegisterEnumValue("MouseMode", "MM_RELATIVE", MM_RELATIVE);
     engine->RegisterEnumValue("MouseMode", "MM_WRAP", MM_WRAP);
     engine->RegisterEnumValue("MouseMode", "MM_WRAP", MM_WRAP);
+    engine->RegisterEnumValue("MouseMode", "MM_FREE", MM_FREE);
 
 
     engine->RegisterObjectType("TouchState", 0, asOBJ_REF);
     engine->RegisterObjectType("TouchState", 0, asOBJ_REF);
     engine->RegisterObjectBehaviour("TouchState", asBEHAVE_ADDREF, "void f()", asFUNCTION(FakeAddRef), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("TouchState", asBEHAVE_ADDREF, "void f()", asFUNCTION(FakeAddRef), asCALL_CDECL_OBJLAST);