Commit: e4f1d719080ab15f4a33034a1eccacace4600b04
Author: Germano Cavalcante
Date:   Thu Aug 18 09:32:49 2022 -0300
Branches: master
https://developer.blender.org/rBe4f1d719080ab15f4a33034a1eccacace4600b04

Fix T89399: Mouse wrapping causes erratic movement

As mentioned in T89399, "the source of this bug is that cursor wrap
moves the cursor, but when it later checks the mouse position it hasn't
yet been updated, so it re-wraps".

As far as I could see, this happens for two reasons:
1. During the first warp, there are already other mousemove events in the queue 
with an outdated position.
2. Sometimes Windows occasionally and inexplicably ignores `SetCursorPos()` or 
`SendInput()` events. (See [1])

The solution consists in checking if the cursor is inside the bounds right 
after wrapping.
If it's not inside, it indicates that the wrapping either didn't work or the 
event is out of date.
In these cases do not change the "accum" values.

1. 
https://github.com/libsdl-org/SDL/blob/f317d619ccd22e60cebf1b09d716d3985359c981/src/video/windows/SDL_windowsmouse.c#L255)

Maniphest Tasks: T89399

Differential Revision: https://developer.blender.org/D15707

===================================================================

M       intern/ghost/intern/GHOST_SystemWin32.cpp

===================================================================

diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp 
b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 07c86cd84f2..ddbe8b67742 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -1099,6 +1099,12 @@ GHOST_EventCursor 
*GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
   system->getCursorPosition(x_screen, y_screen);
 
   if (window->getCursorGrabModeIsWarp()) {
+    /* WORKAROUND:
+     * Sometimes Windows ignores `SetCursorPos()` or `SendInput()` calls or 
the mouse event is
+     * outdate. Identify these cases by checking if the cursor is not yet 
within bounds. */
+    static bool is_warping_x = false;
+    static bool is_warping_y = false;
+
     int32_t x_new = x_screen;
     int32_t y_new = y_screen;
     int32_t x_accum, y_accum;
@@ -1115,29 +1121,41 @@ GHOST_EventCursor 
*GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
 
     window->getCursorGrabAccum(x_accum, y_accum);
     if (x_new != x_screen || y_new != y_screen) {
+      system->setCursorPosition(x_new, y_new); /* wrap */
+
+      /* Do not update the accum values if we are an outdated or failed 
pos-warp event. */
+      if (!is_warping_x) {
+        is_warping_x = x_new != x_screen;
+        if (is_warping_x) {
+          x_accum += (x_screen - x_new);
+        }
+      }
+
+      if (!is_warping_y) {
+        is_warping_y = y_new != y_screen;
+        if (is_warping_y) {
+          y_accum += (y_screen - y_new);
+        }
+      }
+      window->setCursorGrabAccum(x_accum, y_accum);
+
       /* When wrapping we don't need to add an event because the 
setCursorPosition call will cause
        * a new event after. */
-      system->setCursorPosition(x_new, y_new); /* wrap */
-      window->setCursorGrabAccum(x_accum + (x_screen - x_new), y_accum + 
(y_screen - y_new));
-    }
-    else {
-      return new GHOST_EventCursor(system->getMilliSeconds(),
-                                   GHOST_kEventCursorMove,
-                                   window,
-                                   x_screen + x_accum,
-                                   y_screen + y_accum,
-                                   GHOST_TABLET_DATA_NONE);
+      return NULL;
     }
+
+    is_warping_x = false;
+    is_warping_y = false;
+    x_screen += x_accum;
+    y_screen += y_accum;
   }
-  else {
-    return new GHOST_EventCursor(system->getMilliSeconds(),
-                                 GHOST_kEventCursorMove,
-                                 window,
-                                 x_screen,
-                                 y_screen,
-                                 GHOST_TABLET_DATA_NONE);
-  }
-  return NULL;
+
+  return new GHOST_EventCursor(system->getMilliSeconds(),
+                               GHOST_kEventCursorMove,
+                               window,
+                               x_screen,
+                               y_screen,
+                               GHOST_TABLET_DATA_NONE);
 }
 
 void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, WPARAM 
wParam, LPARAM lParam)

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
List details, subscription details or unsubscribe:
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to