diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 2dfdcf7bcec..8bbe446616d 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -812,9 +812,9 @@ GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 //Quartz Display Services uses the old coordinates (top left origin) yf = [[NSScreen mainScreen] frame].size.height -yf; - CGAssociateMouseAndMouseCursorPosition(false); + //CGAssociateMouseAndMouseCursorPosition(false); CGWarpMouseCursorPosition(CGPointMake(xf, yf)); - CGAssociateMouseAndMouseCursorPosition(true); + //CGAssociateMouseAndMouseCursorPosition(true); return GHOST_kSuccess; } @@ -1151,7 +1151,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) window->getCursorWarpAccum(x_accum, y_accum); x_accum += [event deltaX]; - y_accum += [event deltaY]; + y_accum += -[event deltaY]; //Strange Apple implementation (inverted coordinates for the deltaY) ... window->setCursorWarpAccum(x_accum, y_accum); pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, x_warp+x_accum, y_warp+y_accum)); @@ -1159,6 +1159,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) else { //Normal cursor operation: send mouse position in window NSPoint mousePos = [event locationInWindow]; pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, mousePos.x, mousePos.y)); + window->setCursorWarpAccum(0, 0); //Mouse motion occured between two cursor warps, so we can reset the delta counter } break; } diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h index 7a39d9ab54a..bc0dd9db13d 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.h +++ b/intern/ghost/intern/GHOST_WindowCocoa.h @@ -236,6 +236,11 @@ protected: */ virtual GHOST_TSuccess setWindowCursorVisibility(bool visible); + /** + * Sets the cursor warp accumulator. Overriden for workaround due to Cocoa next event after cursor set giving delta values non zero + */ + inline virtual bool setCursorWarpAccum(GHOST_TInt32 x, GHOST_TInt32 y); + /** * Sets the cursor grab on the window using * native window system calls. diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index 1d604553cc1..205c18e29ba 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -712,18 +712,33 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible) return GHOST_kSuccess; } + +//Override this method to provide set feature even if not in warp +inline bool GHOST_WindowCocoa::setCursorWarpAccum(GHOST_TInt32 x, GHOST_TInt32 y) +{ + m_cursorWarpAccumPos[0]= x; + m_cursorWarpAccumPos[1]= y; + + return GHOST_kSuccess; +} + + GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(bool grab, bool warp, bool restore) { + printf("\ncursor grab %i",grab); if (grab) { + //No need to perform grab without warp as it is always on in OS X if(warp) { - m_systemCocoa->getCursorPosition(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]); - - setCursorWarpAccum(0, 0); - setWindowCursorVisibility(false); + GHOST_TInt32 x_old,y_old; + m_cursorWarp= true; + m_systemCocoa->getCursorPosition(x_old,y_old); + screenToClient(x_old, y_old, m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]); + //Warp position is stored in client (window base) coordinates + setWindowCursorVisibility(false); + return CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; } - return CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; } else { if(m_cursorWarp) @@ -732,34 +747,37 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(bool grab, bool warp, bool /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */ if(restore) { GHOST_Rect bounds; - GHOST_TInt32 x_new, y_new, x_rel, y_rel; + GHOST_TInt32 x_new, y_new, x_cur, y_cur; getClientBounds(bounds); - printf("\ncursor ungrab with restore"); x_new= m_cursorWarpInitPos[0]+m_cursorWarpAccumPos[0]; y_new= m_cursorWarpInitPos[1]+m_cursorWarpAccumPos[1]; - screenToClient(x_new, y_new, x_rel, y_rel); + if(x_new < 0) x_new = 0; + if(y_new < 0) y_new = 0; + if(x_new > bounds.getWidth()) x_new = bounds.getWidth(); + if(y_new > bounds.getHeight()) y_new = bounds.getHeight(); - if(x_rel < 0) x_new = (x_new-x_rel) + 2; - if(y_rel < 0) y_new = (y_new-y_rel) + 2; - if(x_rel > bounds.getWidth()) x_new -= (x_rel-bounds.getWidth()) + 2; - if(y_rel > bounds.getHeight()) y_new -= (y_rel-bounds.getHeight()) + 2; - - clientToScreen(x_new, y_new, x_rel, y_rel); - m_systemCocoa->setCursorPosition(x_rel, y_rel); + //get/set cursor position works in screen coordinates + clientToScreen(x_new, y_new, x_cur, y_cur); + m_systemCocoa->setCursorPosition(x_cur, y_cur); + //As Cocoa will give as first deltaX,deltaY this change in cursor position, we need to compensate for it + //Issue appearing in case of two transform operations conducted w/o mouse motion in between + x_new=m_cursorWarpAccumPos[0]; + y_new=m_cursorWarpAccumPos[1]; + setCursorWarpAccum(-x_new, -y_new); } else { m_systemCocoa->setCursorPosition(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]); + setCursorWarpAccum(0, 0); } - setCursorWarpAccum(0, 0); m_cursorWarp= false; + return CGAssociateMouseAndMouseCursorPosition(true) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; } - return CGAssociateMouseAndMouseCursorPosition(true) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; } - + return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape)