Commit: 6f158f834dcfa638639391f37afcb2ca8457cb45 Author: Nicholas Rishel Date: Thu Mar 4 15:48:48 2021 -0800 Branches: master https://developer.blender.org/rB6f158f834dcfa638639391f37afcb2ca8457cb45
Refactor of Wintab to use Wintab supplied mouse movement once verified against system input. Reviewed By: brecht, LazyDodo Maniphest Tasks: T88852 Differential Revision: https://developer.blender.org/D11508 =================================================================== M intern/ghost/CMakeLists.txt M intern/ghost/GHOST_Types.h M intern/ghost/intern/GHOST_System.h M intern/ghost/intern/GHOST_SystemWin32.cpp M intern/ghost/intern/GHOST_SystemWin32.h M intern/ghost/intern/GHOST_WindowWin32.cpp M intern/ghost/intern/GHOST_WindowWin32.h A intern/ghost/intern/GHOST_Wintab.cpp A intern/ghost/intern/GHOST_Wintab.h M source/blender/windowmanager/intern/wm_window.c =================================================================== diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index 1b5cdb3cda0..40d78a22e6f 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -370,6 +370,7 @@ elseif(WIN32) intern/GHOST_DropTargetWin32.cpp intern/GHOST_SystemWin32.cpp intern/GHOST_WindowWin32.cpp + intern/GHOST_Wintab.cpp intern/GHOST_ContextD3D.h intern/GHOST_DisplayManagerWin32.h @@ -377,6 +378,7 @@ elseif(WIN32) intern/GHOST_SystemWin32.h intern/GHOST_TaskbarWin32.h intern/GHOST_WindowWin32.h + intern/GHOST_Wintab.h ) if(NOT WITH_GL_EGL) diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 3a8d0fbfecf..f18e6f03ede 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -105,7 +105,9 @@ typedef enum { typedef enum { GHOST_kTabletAutomatic = 0, - GHOST_kTabletNative, + /* Show as Windows Ink to users to match "Use Windows Ink" in tablet utilities, but we use the + dependent Windows Pointer API. */ + GHOST_kTabletWinPointer, GHOST_kTabletWintab, } GHOST_TTabletAPI; diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h index 2a7123b293e..9915520691f 100644 --- a/intern/ghost/intern/GHOST_System.h +++ b/intern/ghost/intern/GHOST_System.h @@ -239,7 +239,7 @@ class GHOST_System : public GHOST_ISystem { * Set which tablet API to use. Only affects Windows, other platforms have a single API. * \param api: Enum indicating which API to use. */ - void setTabletAPI(GHOST_TTabletAPI api); + virtual void setTabletAPI(GHOST_TTabletAPI api) override; GHOST_TTabletAPI getTabletAPI(void); #ifdef WITH_INPUT_NDOF diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 45b9e88f884..09cfa30eca5 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -866,15 +866,151 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, { GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); - if (type == GHOST_kEventButtonDown) { - window->updateMouseCapture(MousePressed); + GHOST_TabletData td = window->getTabletData(); + + /* Move mouse to button event position. */ + if (window->getTabletData().Active != GHOST_kTabletModeNone) { + /* Tablet should be handling 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)); } - else if (type == GHOST_kEventButtonUp) { - window->updateMouseCapture(MouseReleased); + + window->updateMouseCapture(type == GHOST_kEventButtonDown ? MousePressed : MouseReleased); + return new GHOST_EventButton(system->getMilliSeconds(), type, window, mask, td); +} + +void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window) +{ + GHOST_Wintab *wt = window->getWintab(); + if (!wt) { + return; + } + + GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); + + std::vector<GHOST_WintabInfoWin32> wintabInfo; + wt->getInput(wintabInfo); + + /* Wintab provided coordinates are untrusted until a Wintab and Win32 button down event match. + * This is checked on every button down event, and revoked if there is a mismatch. This can + * happen when Wintab incorrectly scales cursor position or is in mouse mode. + * + * If Wintab was never trusted while processing this Win32 event, a fallback Ghost cursor move + * event is created at the position of the Win32 WT_PACKET event. */ + bool mouseMoveHandled; + bool useWintabPos; + mouseMoveHandled = useWintabPos = wt->trustCoordinates(); + + for (GHOST_WintabInfoWin32 &info : wintabInfo) { + switch (info.type) { + case GHOST_kEventCursorMove: { + if (!useWintabPos) { + continue; + } + + wt->mapWintabToSysCoordinates(info.x, info.y, info.x, info.y); + system->pushEvent(new GHOST_EventCursor( + info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData)); + + break; + } + case GHOST_kEventButtonDown: { + UINT message; + switch (info.button) { + case GHOST_kButtonMaskLeft: + message = WM_LBUTTONDOWN; + break; + case GHOST_kButtonMaskRight: + message = WM_RBUTTONDOWN; + break; + case GHOST_kButtonMaskMiddle: + message = WM_MBUTTONDOWN; + break; + default: + continue; + } + + /* Wintab buttons are modal, but the API does not inform us what mode a pressed button is + * in. Only issue button events if we can steal an equivalent Win32 button event from the + * event queue. */ + MSG msg; + if (PeekMessage(&msg, window->getHWND(), message, message, PM_NOYIELD) && + msg.message != WM_QUIT) { + + /* Test for Win32/Wintab button down match. */ + useWintabPos = wt->testCoordinates(msg.pt.x, msg.pt.y, info.x, info.y); + if (!useWintabPos) { + continue; + } + + /* Steal the Win32 event which was previously peeked. */ + PeekMessage(&msg, window->getHWND(), message, message, PM_REMOVE | PM_NOYIELD); + + /* Move cursor to button location, to prevent incorrect cursor position when + * transitioning from unsynchronized Win32 to Wintab cursor control. */ + wt->mapWintabToSysCoordinates(info.x, info.y, info.x, info.y); + system->pushEvent(new GHOST_EventCursor( + info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData)); + + window->updateMouseCapture(MousePressed); + system->pushEvent( + new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData)); + + mouseMoveHandled = true; + break; + } + } + case GHOST_kEventButtonUp: { + if (!useWintabPos) { + continue; + } + + UINT message; + switch (info.button) { + case GHOST_kButtonMaskLeft: + message = WM_LBUTTONUP; + break; + case GHOST_kButtonMaskRight: + message = WM_RBUTTONUP; + break; + case GHOST_kButtonMaskMiddle: + message = WM_MBUTTONUP; + break; + default: + continue; + } + + /* Wintab buttons are modal, but the API does not inform us what mode a pressed button is + * in. Only issue button events if we can steal an equivalent Win32 button event from the + * event queue. */ + MSG msg; + if (PeekMessage(&msg, window->getHWND(), message, message, PM_REMOVE | PM_NOYIELD) && + msg.message != WM_QUIT) { + + window->updateMouseCapture(MouseReleased); + system->pushEvent( + new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData)); + } + break; + } + default: + break; + } } - return new GHOST_EventButton( - system->getMilliSeconds(), type, window, mask, window->getTabletData()); + /* Fallback cursor movement if Wintab position were never trusted while processing this event. */ + if (!mouseMoveHandled) { + DWORD pos = GetMessagePos(); + int x = GET_X_LPARAM(pos); + int y = GET_Y_LPARAM(pos); + + /* TODO supply tablet data */ + system->pushEvent(new GHOST_EventCursor( + system->getMilliSeconds(), GHOST_kEventCursorMove, window, x, y, GHOST_TABLET_DATA_NONE)); + } } void GHOST_SystemWin32::processPointerEvent( @@ -882,7 +1018,7 @@ void GHOST_SystemWin32::processPointerEvent( { /* Pointer events might fire when changing windows for a device which is set to use Wintab, even * when when Wintab is left enabled but set to the bottom of Wintab overlap order. */ - if (!window->useTabletAPI(GHOST_kTabletNative)) { + if (!window->usingTabletAPI(GHOST_kTabletWinPointer)) { return; } @@ -893,20 +1029,21 @@ void GHOST_SystemWin32::processPointerEvent( return; } - if (!pointerInfo[0].isPrimary) { - eventHandled = true; - return; // For multi-touch displays we ignore these events - } - switch (type) { - case WM_POINTERENTER: - window->m_tabletInRange = true; - system->pushEvent(new GHOST_EventCursor(pointerInfo[0].time, - GHOST_kEventCursorMove, - window, - pointerInfo[0].pixelLocation.x, - pointerInfo[0].pixelLocation.y, - pointerInfo[0].tabletData)); + case WM_POINTERUPDATE: + /* Coalesced pointer events are reverse chronological order, reorder chronologically. + * Only contiguous move events are coalesced. */ + for (GHOST_TUns32 i = pointerInfo.size(); i-- > 0;) { + system->pushEvent(new GHOST_EventCursor(pointerInfo[i].time, + GHOST_kEventCursorMove, + window, + pointerInfo[i].pixelLocation.x, + pointerInfo[i].pixelLocation.y, + pointerInfo[i].tabletData)); + } + + /* Leave event unhandled so that system cursor is moved. */ + break; case WM_POINTERDOWN: /* Move cursor to point of contact because GHOST_EventButton does not include position. */ @@ -922,18 +1059,10 @@ void GHOST_SystemWin32::processPointerEvent( pointerInfo[0].buttonMask, pointerInfo[0].tabletData)); window->updateMouseCapture(MousePressed); - break; - case WM_POINTERUPDATE: - /* Coalesced pointer events are reverse chronological order, reorder chronologically. - @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list [email protected] List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs
