[Bf-blender-cvs] [1a484889466] fix-tablet-walk: Windows high frequency Wintab input.

Nicholas Rishel noreply at git.blender.org
Sat Jun 19 06:34:23 CEST 2021


Commit: 1a484889466650a4d3532437d94b9dfcb6126520
Author: Nicholas Rishel
Date:   Thu Mar 4 15:48:48 2021 -0800
Branches: fix-tablet-walk
https://developer.blender.org/rB1a484889466650a4d3532437d94b9dfcb6126520

Windows high frequency Wintab input.

Use Wintab supplied mouse movement once verified against system input,
checked by comparing Win32 and Wintab button down event positions.

Dynamically unload Wintab if Tablet API is WinPointer (Windows Ink),
load Wintab otherwise.

When Tablet API is Automatic, dynamically switch between Wintab and
WinPointer based on number of Wintab devices present. Previous
behavior was to use Wintab if wintab.dll was present on system.

Allow system handling of system cursor movement during WinPointer
events by leaving WM_POINTERUPDATE events unhandled.

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

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