[Bf-blender-cvs] [8b2785bda5b] master: Fix T49498: continuous grab issues on macOS, particularly with gaming mouses.

Brecht Van Lommel noreply at git.blender.org
Tue Jul 18 16:13:53 CEST 2017


Commit: 8b2785bda5bd077548044acb307e17b376649051
Author: Brecht Van Lommel
Date:   Tue Jul 18 16:00:07 2017 +0200
Branches: master
https://developer.blender.org/rB8b2785bda5bd077548044acb307e17b376649051

Fix T49498: continuous grab issues on macOS, particularly with gaming mouses.

Change the implementation so it no longer takes over the mouse cursor motion
from the OS, instead only move it when warping, similar to Windows and X11.
Probably the reason it was not done this way originally is that you then get
a 500ms delay after warping, but we can use a trick to avoid that and get much
smoother mouse motion than before.

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

M	intern/ghost/intern/GHOST_SystemCocoa.h
M	intern/ghost/intern/GHOST_SystemCocoa.mm
M	intern/ghost/intern/GHOST_WindowCocoa.mm

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

diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h
index b142c2f7194..6802ad42c7b 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.h
+++ b/intern/ghost/intern/GHOST_SystemCocoa.h
@@ -292,11 +292,6 @@ protected:
 	/** Ignores window size messages (when window is dragged). */
 	bool m_ignoreWindowSizedMessages;
 	
-	/** Stores the mouse cursor delta due to setting a new cursor position
-	 * Needed because cocoa event delta cursor move takes setCursorPosition changes too.
-	 */
-	GHOST_TInt32 m_cursorDelta_x, m_cursorDelta_y;
-	
 	/** Temporarily ignore momentum scroll events */
 	bool m_ignoreMomentumScroll;
 	/** Is the scroll wheel event generated by a multitouch trackpad or mouse? */
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index 173f59c9c8f..4582dfb2a49 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -366,8 +366,6 @@ GHOST_SystemCocoa::GHOST_SystemCocoa()
 	char *rstring = NULL;
 
 	m_modifierMask =0;
-	m_cursorDelta_x=0;
-	m_cursorDelta_y=0;
 	m_outsideLoopEventProcessed = false;
 	m_needDelayedApplicationBecomeActiveEventProcessing = false;
 	m_displayManager = new GHOST_DisplayManagerCocoa ();
@@ -644,6 +642,13 @@ GHOST_TSuccess GHOST_SystemCocoa::setMouseCursorPosition(GHOST_TInt32 x, GHOST_T
 
 	CGDisplayMoveCursorToPoint((CGDirectDisplayID)[[[windowScreen deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue], CGPointMake(xf, yf));
 
+	// See https://stackoverflow.com/a/17559012. By default, hardware events
+	// will be suppressed for 500ms after a synthetic mouse event. For unknown
+	// reasons CGEventSourceSetLocalEventsSuppressionInterval does not work,
+	// however calling CGAssociateMouseAndMouseCursorPosition also removes the
+	// delay, even if this is undocumented.
+	CGAssociateMouseAndMouseCursorPosition(true);
+
 	[pool drain];
 	return GHOST_kSuccess;
 }
@@ -1354,9 +1359,8 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
 					case GHOST_kGrabWrap: //Wrap cursor at area/window boundaries
 					{
 						NSPoint mousePos = [cocoawindow mouseLocationOutsideOfEventStream];
-						GHOST_TInt32 x_mouse= mousePos.x;
-						GHOST_TInt32 y_mouse= mousePos.y;
-						GHOST_TInt32 x_accum, y_accum, x_cur, y_cur, x, y;
+						GHOST_TInt32 x_mouse = mousePos.x;
+						GHOST_TInt32 y_mouse = mousePos.y;
 						GHOST_Rect bounds, windowBounds, correctedBounds;
 
 						/* fallback to window bounds */
@@ -1370,29 +1374,26 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
 						correctedBounds.m_b = (windowBounds.m_b - windowBounds.m_t) - correctedBounds.m_b;
 						correctedBounds.m_t = (windowBounds.m_b - windowBounds.m_t) - correctedBounds.m_t;
 
-						//Update accumulation counts
+						//Get accumulation from previous mouse warps
+						GHOST_TInt32 x_accum, y_accum;
 						window->getCursorGrabAccum(x_accum, y_accum);
-						x_accum += [event deltaX]-m_cursorDelta_x;
-						y_accum += -[event deltaY]-m_cursorDelta_y; //Strange Apple implementation (inverted coordinates for the deltaY) ...
-						window->setCursorGrabAccum(x_accum, y_accum);
 
 						//Warp mouse cursor if needed
-						x_mouse += [event deltaX]-m_cursorDelta_x;
-						y_mouse += -[event deltaY]-m_cursorDelta_y;
-						correctedBounds.wrapPoint(x_mouse, y_mouse, 2);
-
-						//Compensate for mouse moved event taking cursor position set into account
-						m_cursorDelta_x = x_mouse-mousePos.x;
-						m_cursorDelta_y = y_mouse-mousePos.y;
+						GHOST_TInt32 warped_x_mouse = x_mouse;
+						GHOST_TInt32 warped_y_mouse = y_mouse;
+						correctedBounds.wrapPoint(warped_x_mouse, warped_y_mouse, 4);
 
 						//Set new cursor position
-						window->clientToScreenIntern(x_mouse, y_mouse, x_cur, y_cur);
-						setMouseCursorPosition(x_cur, y_cur); /* wrap */
+						if (x_mouse != warped_x_mouse || y_mouse != warped_y_mouse) {
+							GHOST_TInt32 warped_x, warped_y;
+							window->clientToScreenIntern(warped_x_mouse, warped_y_mouse, warped_x, warped_y);
+							setMouseCursorPosition(warped_x, warped_y); /* wrap */
+							window->setCursorGrabAccum(x_accum + (x_mouse - warped_x_mouse), y_accum + (y_mouse - warped_y_mouse));
+						}
 
-						//Post event
-						window->getCursorGrabInitPos(x_cur, y_cur);
-						window->screenToClientIntern(x_cur, y_cur, x_cur, y_cur);
-						window->clientToScreenIntern(x_cur + x_accum, y_cur + y_accum, x, y);
+						//Generate event
+						GHOST_TInt32 x, y;
+						window->clientToScreenIntern(x_mouse + x_accum, y_mouse + y_accum, x, y);
 						pushEvent(new GHOST_EventCursor([event timestamp] * 1000, GHOST_kEventCursorMove, window, x, y));
 						break;
 					}
@@ -1404,9 +1405,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
 
 						window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
 						pushEvent(new GHOST_EventCursor([event timestamp] * 1000, GHOST_kEventCursorMove, window, x, y));
-
-						m_cursorDelta_x=0;
-						m_cursorDelta_y=0; //Mouse motion occurred between two cursor warps, so we can reset the delta counter
 						break;
 					}
 				}
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index 97615dcea96..73c89f9d68d 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -1370,9 +1370,6 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode
 			//Make window key if it wasn't to get the mouse move events
 			[m_window makeKeyWindow];
 			
-			//Dissociate cursor position even for warp mode, to allow mouse acceleration to work even when warping the cursor
-			err = CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure;
-			
 			[pool drain];
 		}
 	}
@@ -1382,7 +1379,6 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode
 			setWindowCursorVisibility(true);
 		}
 		
-		err = CGAssociateMouseAndMouseCursorPosition(true) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure;
 		/* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */
 		setCursorGrabAccum(0, 0);
 		m_cursorGrabBounds.m_l= m_cursorGrabBounds.m_r= -1; /* disable */




More information about the Bf-blender-cvs mailing list