Fix part of T74918: 3D Viewport: Jump, when mouse crosses a window corner.

We need a separate time stamp for each axis, and we have to add a few
milliseconds of padding to those, to ensure wrapping on both axes get
properly performed when it happens almost simultaneously, and avoid
extra wrapping caused by very close events sometimes.

This only addresses the Linux (X11 backend) case.

Differential Revision: https://developer.blender.org/D9209
This commit is contained in:
Bastien Montagne 2020-10-14 12:49:56 +02:00
parent f1aa55b6e9
commit d6fd03616e
Notes: blender-bot 2024-01-31 11:35:08 +01:00
Referenced by issue #82870, Continuous grab is broken 2.92.0 Alpha macOS
Referenced by issue #81704, Spline IK "Bone Original" Y-scale Causes Scaling
Referenced by issue #39144, Moving cursor quickly jumps it out of the window when translating objects
2 changed files with 20 additions and 11 deletions

View File

@ -175,7 +175,8 @@ GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(NULL), m_start_
#undef GHOST_INTERN_ATOM_IF_EXISTS
#undef GHOST_INTERN_ATOM
m_last_warp = 0;
m_last_warp_x = 0;
m_last_warp_y = 0;
m_last_release_keycode = 0;
m_last_release_time = 0;
@ -981,17 +982,24 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
window->getCursorGrabAccum(x_accum, y_accum);
if (x_new != xme.x_root || y_new != xme.y_root) {
if (xme.time > m_last_warp) {
/* when wrapping we don't need to add an event because the
* setCursorPosition call will cause a new event after */
setCursorPosition(x_new, y_new); /* wrap */
window->setCursorGrabAccum(x_accum + (xme.x_root - x_new),
y_accum + (xme.y_root - y_new));
m_last_warp = lastEventTime(xme.time);
/* Use time of last event to avoid wrapping several times on the 'same' actual wrap.
* Note that we need to deal with X and Y separately as those might wrap at the same time
* but still in two different events (corner case, see T74918).
* We also have to add a few extra milliseconds of 'padding', as sometimes we get two
* close events that will generate extra wrap on the same axis within those few
* milliseconds. */
if (x_new != xme.x_root && xme.time > m_last_warp_x) {
x_accum += (xme.x_root - x_new);
m_last_warp_x = lastEventTime(xme.time) + 25;
}
else {
setCursorPosition(x_new, y_new); /* wrap but don't accumulate */
if (y_new != xme.y_root && xme.time > m_last_warp_y) {
y_accum += (xme.y_root - y_new);
m_last_warp_y = lastEventTime(xme.time) + 25;
}
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. */
setCursorPosition(x_new, y_new); /* wrap */
}
else {
g_event = new GHOST_EventCursor(getMilliSeconds(),

View File

@ -361,7 +361,8 @@ class GHOST_SystemX11 : public GHOST_System {
* To prevent multiple warp, we store the time of the last warp event
* and stop accumulating all events generated before that.
*/
Time m_last_warp;
Time m_last_warp_x;
Time m_last_warp_y;
/* Detect auto-repeat glitch. */
unsigned int m_last_release_keycode;