Commit: a3a9459050a96e75138b3441c069898f211f179c Author: Germano Cavalcante Date: Wed Dec 14 15:37:49 2022 -0300 Branches: master https://developer.blender.org/rBa3a9459050a96e75138b3441c069898f211f179c
Fix erratic mouse wrapping movement on Windows (2) This is a solution in response to the issues mentioned in comments on rBe4f1d719080a and T103088. Apparently the workaround of checking if the mouse is already inside the area on the next event doesn't work for some tablets. Perhaps the order of events or some very small jitter is causing this issue on tablets. (Couldn't confirm). Whatever the cause, the solution of checking the timestamp of the event and thus ignoring the outdated ones is theoretically safer. It is the same solution seen in MacOS. Also calling `SendInput` 3 times every warp ensures that at least one event is dispatched. =================================================================== M intern/ghost/intern/GHOST_SystemWin32.cpp =================================================================== diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 75a4cc8389a..8cb007a756a 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -1061,11 +1061,16 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind int32_t x_screen = screen_co[0], y_screen = screen_co[1]; if (window->getCursorGrabModeIsWarp()) { - /* WORKAROUND: - * Sometimes Windows ignores `SetCursorPos()` or `SendInput()` calls or the mouse event is - * outdated. 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; + static uint64_t last_warp_time = 0; + { + /* WORKAROUND: Check the mouse event timestamp so we can ignore mousemove events that were + * already in the queue before we changed the cursor position. */ + MOUSEMOVEPOINT mp = {x_screen, y_screen}; + ::GetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &mp, &mp, 1, GMMP_USE_DISPLAY_POINTS); + if (mp.time <= last_warp_time) { + return NULL; + } + } int32_t x_new = x_screen; int32_t y_new = y_screen; @@ -1112,31 +1117,35 @@ 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); - } - } + /* WORKAROUND: Store the current time so that we ignore outdated mousemove events. */ + last_warp_time = ::GetTickCount64(); + + /* For more control over which timestamp to store in the event, we use `SendInput` instead of + * `SetCursorPos` here. + * It is quite unlikely to happen, but still possible that some event between + * `last_warp_time` and `GHOST_SystemWin32::setCursorPosition` is sent. */ + INPUT input[3] = {0}; + input[0].type = INPUT_MOUSE; + input[0].mi.dx = (LONG)(x_new * (65535.0f / GetSystemMetrics(SM_CXSCREEN))); + input[0].mi.dy = (LONG)(y_new * (65535.0f / GetSystemMetrics(SM_CYSCREEN))); + input[0].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; + input[0].mi.time = last_warp_time; + + /* Send 3 events with a jitter to make sure Windows does not occasionally and + * inexplicably ignore `SetCursorPos` or `SendInput`. */ + input[2] = input[1] = input[0]; + input[1].mi.dx += 1; + ::SendInput(3, input, sizeof(INPUT)); + + x_accum += (x_screen - x_new); + 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. */ + /* When wrapping we don't need to add an event because the `SendInput` call will cause new + * events after. */ return NULL; } - is_warping_x = false; - is_warping_y = false; x_screen += x_accum; y_screen += y_accum; } _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs