diff options
Diffstat (limited to 'intern')
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWin32.cpp | 138 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWin32.h | 18 |
2 files changed, 127 insertions, 29 deletions
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 5de97199fd8..ca4912ff2c5 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -225,6 +225,9 @@ GHOST_SystemWin32::GHOST_SystemWin32() #ifdef WITH_INPUT_NDOF m_ndofManager = new GHOST_NDOFManagerWin32(*this); #endif + + getCursorPosition(m_mousePosX, m_mousePosY); + m_mouseTimestamp = ::GetTickCount(); } GHOST_SystemWin32::~GHOST_SystemWin32() @@ -533,7 +536,20 @@ GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 { if (!::GetActiveWindow()) return GHOST_kFailure; - return ::SetCursorPos(x, y) == TRUE ? GHOST_kSuccess : GHOST_kFailure; + + INPUT input; + input.type = INPUT_MOUSE; + input.mi.mouseData = 0; + input.mi.time = ::GetTickCount(); + /* Map from virtual screen to 0-65536. */ + input.mi.dx = (x - GetSystemMetrics(SM_XVIRTUALSCREEN)) * 65536 / + GetSystemMetrics(SM_CXVIRTUALSCREEN); + input.mi.dy = (y - GetSystemMetrics(SM_YVIRTUALSCREEN)) * 65536 / + GetSystemMetrics(SM_CYVIRTUALSCREEN); + input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK; + SendInput(1, &input, sizeof(input)); + + return GHOST_kSuccess; } GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys &keys) const @@ -942,8 +958,18 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, GHOST_TabletData td = window->m_tabletInRange ? window->getLastTabletData() : GHOST_TABLET_DATA_NONE; - /* Ensure button click occurs at its intended position. */ - processCursorEvent(window); + /* Move mouse to button event position. */ + if (!window->m_tabletInRange) { + processCursorEvent(window); + } + else { + /* Tablet should be hadling inbetween mouse moves, only move to event position. */ + DWORD msgPos = ::GetMessagePos(); + int msgPosX = GET_X_LPARAM(msgPos); + int msgPosY = GET_Y_LPARAM(msgPos); + system->pushEvent(new GHOST_EventCursor( + ::GetMessageTime(), GHOST_kEventCursorMove, window, msgPosX, msgPosY, td)); + } window->updateMouseCapture(type == GHOST_kEventButtonDown ? MousePressed : MouseReleased); return new GHOST_EventButton(system->getMilliSeconds(), type, window, mask, td); @@ -1101,18 +1127,79 @@ void GHOST_SystemWin32::processPointerEvent( system->setCursorPosition(pointerInfo[0].pixelLocation.x, pointerInfo[0].pixelLocation.y); } -GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window) +void GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window) { + /* Cursor moves handled by tablets while active. */ + if (window->m_tabletInRange) { + return; + } + GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); DWORD msgPos = ::GetMessagePos(); - GHOST_TInt32 x_screen = GET_X_LPARAM(msgPos); - GHOST_TInt32 y_screen = GET_Y_LPARAM(msgPos); + LONG msgTime = ::GetMessageTime(); + + /* GetMessagePointsEx processes points as 16 bit integers and can fail or return erroneous values + * if negative input is not truncated. */ + int msgPosX = GET_X_LPARAM(msgPos) & 0x0000FFFF; + int msgPosY = GET_Y_LPARAM(msgPos) & 0x0000FFFF; + + const int maxPoints = 64; + MOUSEMOVEPOINT currentPoint = {msgPosX, msgPosY, (DWORD)msgTime, 0}; + MOUSEMOVEPOINT points[maxPoints] = {0}; + /* GetMouseMovePointsEx returns the number of points returned that are less than or equal to the + * requested point. If the requested point is the most recent, this returns up to 64 requested + * points. */ + int numPoints = ::GetMouseMovePointsEx( + sizeof(MOUSEMOVEPOINT), ¤tPoint, points, maxPoints, GMMP_USE_DISPLAY_POINTS); + + if (numPoints == -1) { + /* Points at edge of screen are often not in the queue, use the message's point instead. */ + numPoints = 1; + points[0] = currentPoint; + } + GHOST_TInt32 x_accum = 0, y_accum = 0; + window->getCursorGrabAccum(x_accum, y_accum); + + /* Points are in reverse chronological order. Find least recent, unprocessed mouse move. */ + int i; + for (i = 0; i < numPoints; i++) { + if (points[i].time < system->m_mouseTimestamp) { + break; + } - if (window->getCursorGrabModeIsWarp() && !window->m_tabletInRange) { - GHOST_TInt32 x_new = x_screen; - GHOST_TInt32 y_new = y_screen; + /* GetMouseMovePointsEx returns 16 bit number as 32 bit. If negative, we need to sign extend. + */ + points[i].x = points[i].x > 32767 ? points[i].x | 0xFFFF0000 : points[i].x; + points[i].y = points[i].y > 32767 ? points[i].y | 0xFFFF0000 : points[i].y; + + if (points[i].time == system->m_mouseTimestamp && points[i].x == system->m_mousePosX && + points[i].y == system->m_mousePosY) { + break; + } + } + while (--i >= 0) { + system->pushEvent(new GHOST_EventCursor(system->getMilliSeconds(), + GHOST_kEventCursorMove, + window, + points[i].x + x_accum, + points[i].y + y_accum, + GHOST_TABLET_DATA_NONE)); + } + + DWORD lastTimestamp = points[0].time; + + /* Check if we need to wrap the cursor. */ + if (window->getCursorGrabModeIsWarp()) { + /* Wrap based on current cursor position in case Win32 mouse move queue is out of order due to + * prior wrap. */ + POINT point; + ::GetCursorPos(&point); + GHOST_TInt32 x_current = point.x; + GHOST_TInt32 y_current = point.y; + GHOST_TInt32 x_wrap = point.x; + GHOST_TInt32 y_wrap = point.y; GHOST_Rect bounds; /* Fallback to window bounds. */ @@ -1122,23 +1209,24 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind /* Could also clamp to screen bounds wrap with a window outside the view will fail atm. * Use offset of 8 in case the window is at screen bounds. */ - bounds.wrapPoint(x_new, y_new, 2, window->getCursorGrabAxis()); + bounds.wrapPoint(x_wrap, y_wrap, 2, window->getCursorGrabAxis()); + + if (x_wrap != x_current || y_wrap != y_current) { + system->setCursorPosition(x_wrap, y_wrap); + window->setCursorGrabAccum(x_accum + (x_current - x_wrap), y_accum + (y_current - y_wrap)); - window->getCursorGrabAccum(x_accum, y_accum); - if (x_new != x_screen || y_new != y_screen) { - system->setCursorPosition(x_new, y_new); /* wrap */ - window->setCursorGrabAccum(x_accum + (x_screen - x_new), y_accum + (y_screen - y_new)); + /* First message after SendInput wrap is invalid for unknown reasons, skip events until one + * tick after SendInput event time. */ + lastTimestamp = ::GetTickCount() + 1; } } - GHOST_TabletData td = window->m_tabletInRange ? window->getLastTabletData() : - GHOST_TABLET_DATA_NONE; - return new GHOST_EventCursor(system->getMilliSeconds(), - GHOST_kEventCursorMove, - window, - x_screen + x_accum, - y_screen + y_accum, - td); + system->m_mousePosX = points[0].x; + system->m_mousePosY = points[0].y; + /* Use latest time, checking for overflow. */ + if (lastTimestamp > system->m_mouseTimestamp || ::GetTickCount() < system->m_mouseTimestamp) { + system->m_mouseTimestamp = lastTimestamp; + } } void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam) @@ -1631,7 +1719,8 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, } if (!window->m_tabletInRange) { - event = processCursorEvent(window); + processCursorEvent(window); + eventHandled = true; } break; case WM_MOUSEWHEEL: { @@ -1677,6 +1766,9 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, case WM_MOUSELEAVE: window->m_mousePresent = false; window->setWintabOverlap(false); + if (!window->m_tabletInRange) { + processCursorEvent(window); + } break; //////////////////////////////////////////////////////////////////////// // Mouse events, ignored diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index ca227278fa7..8ae0b0927c3 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -340,9 +340,8 @@ class GHOST_SystemWin32 : public GHOST_System { /** * Creates cursor event. * \param window: The window receiving the event (the active window). - * \return The event created. */ - static GHOST_EventCursor *processCursorEvent(GHOST_WindowWin32 *window); + static void processCursorEvent(GHOST_WindowWin32 *window); /** * Handles a mouse wheel event. @@ -463,16 +462,23 @@ class GHOST_SystemWin32 : public GHOST_System { __int64 m_lfstart; /** AltGr on current keyboard layout. */ bool m_hasAltGr; - /** language identifier. */ + /** Language identifier. */ WORD m_langId; - /** stores keyboard layout. */ + /** Stores keyboard layout. */ HKL m_keylayout; - /** Console status */ + /** Console status. */ int m_consoleStatus; - /** Wheel delta accumulator */ + /** Wheel delta accumulator. */ int m_wheelDeltaAccum; + + /** Last mouse x position. */ + int m_mousePosX; + /** Last mouse y position. */ + int m_mousePosY; + /** Last mouse timestamp. */ + DWORD m_mouseTimestamp; }; inline void GHOST_SystemWin32::retrieveModifierKeys(GHOST_ModifierKeys &keys) const |