[Bf-blender-cvs] [6f158f834dc] master: Refactor of Wintab to use Wintab supplied mouse movement once verified against system input.

Nicholas Rishel noreply at git.blender.org
Mon Jun 21 23:40:09 CEST 2021


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. @@



More information about the Bf-blender-cvs mailing list