[Bf-blender-cvs] [1a3ef53a78d] wintab-revised: Here lies a final attempt attempt at a sane Wintab implementation, smashed against the reality of broken and bad APIs. If only rawinput events mapped consistently, but for reasons unknown Wintab express buttons will map to the device when stylus is in range, and map to an emulated button when the pen is away. For this reason this commit must only exist for posterity, a totem of my naivety in believing Wintab and Win32 could be reasoned with.

Nicholas Rishel noreply at git.blender.org
Mon Dec 7 07:14:20 CET 2020


Commit: 1a3ef53a78d48439723f4be3d4fcaaf11f32cd60
Author: Nicholas Rishel
Date:   Sun Dec 6 00:20:27 2020 -0800
Branches: wintab-revised
https://developer.blender.org/rB1a3ef53a78d48439723f4be3d4fcaaf11f32cd60

Here lies a final attempt attempt at a sane Wintab implementation, smashed
against the reality of broken and bad APIs. If only rawinput events
mapped consistently, but for reasons unknown Wintab express buttons will
map to the device when stylus is in range, and map to an emulated button
when the pen is away. For this reason this commit must only exist for
posterity, a totem of my naivety in believing Wintab and Win32 could
be reasoned with.

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

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

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

diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 8178b9bdf1e..071ffae1092 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -30,12 +30,21 @@
 #endif
 
 #include <commctrl.h>
+#include <memory>
 #include <psapi.h>
 #include <shellapi.h>
 #include <shlobj.h>
 #include <tlhelp32.h>
 #include <windowsx.h>
 
+#include <cfgmgr32.h>
+#include <initguid.h>  // XXX must include before devpkey.h
+
+#include <devpkey.h>
+#pragma comment(lib, "Cfgmgr32.lib")
+
+#pragma comment(lib, "Rpcrt4.lib")
+
 #include "utf_winfunc.h"
 #include "utfconv.h"
 
@@ -57,6 +66,8 @@
 
 #ifdef WITH_INPUT_NDOF
 #  include "GHOST_NDOFManagerWin32.h"
+#  define NDOF_USAGE_PAGE 0x01
+#  define NDOF_USAGE 0x08
 #endif
 
 // Key code values not found in winuser.h
@@ -143,12 +154,17 @@
  */
 #define BROKEN_PEEK_TOUCHPAD
 
+#define GUID_FORMAT "%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX"
+#define GUID_ARG(guid) \
+  guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], \
+      guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]
+
 static void initRawInput()
 {
 #ifdef WITH_INPUT_NDOF
-#  define DEVICE_COUNT 2
+  const int DEVICE_COUNT = 3;
 #else
-#  define DEVICE_COUNT 1
+  const int DEVICE_COUNT = 2;
 #endif
 
   RAWINPUTDEVICE devices[DEVICE_COUNT];
@@ -159,18 +175,19 @@ static void initRawInput()
   devices[0].usUsagePage = 0x01;
   devices[0].usUsage = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */
 
+  // Initiates WM_INPUT messages from mouse
+  devices[1].usUsagePage = 0x01;
+  devices[1].usUsage = 0x02;
+
 #ifdef WITH_INPUT_NDOF
   // multi-axis mouse (SpaceNavigator, etc.)
-  devices[1].usUsagePage = 0x01;
-  devices[1].usUsage = 0x08;
+  devices[2].usUsagePage = NDOF_USAGE_PAGE;
+  devices[2].usUsage = NDOF_USAGE;
 #endif
 
-  if (RegisterRawInputDevices(devices, DEVICE_COUNT, sizeof(RAWINPUTDEVICE)))
-    ;  // yay!
-  else
+  if (!RegisterRawInputDevices(devices, DEVICE_COUNT, sizeof(RAWINPUTDEVICE))) {
     GHOST_PRINTF("could not register for RawInput: %d\n", (int)GetLastError());
-
-#undef DEVICE_COUNT
+  }
 }
 
 #ifndef DPI_ENUMS_DECLARED
@@ -566,17 +583,22 @@ GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons &buttons) const
 {
   /* Check for swapped buttons (left-handed mouse buttons)
    * GetAsyncKeyState() will give back the state of the physical mouse buttons.
+   *
+   * Tested Wacom tablet swapped physical buttons when the OS swapped logical mouse buttons such
+   * that behavior was unchanged. Physical buttons were swapped for both the stylus and pad
+   * buttons.
    */
   bool swapped = ::GetSystemMetrics(SM_SWAPBUTTON) == TRUE;
 
-  bool down = HIBYTE(::GetKeyState(VK_LBUTTON)) != 0;
+  bool down = HIBYTE(::GetAsyncKeyState(VK_LBUTTON)) != 0;
   buttons.set(swapped ? GHOST_kButtonMaskRight : GHOST_kButtonMaskLeft, down);
 
-  down = HIBYTE(::GetKeyState(VK_MBUTTON)) != 0;
+  down = HIBYTE(::GetAsyncKeyState(VK_MBUTTON)) != 0;
   buttons.set(GHOST_kButtonMaskMiddle, down);
 
-  down = HIBYTE(::GetKeyState(VK_RBUTTON)) != 0;
+  down = HIBYTE(::GetAsyncKeyState(VK_RBUTTON)) != 0;
   buttons.set(swapped ? GHOST_kButtonMaskLeft : GHOST_kButtonMaskRight, down);
+
   return GHOST_kSuccess;
 }
 
@@ -596,6 +618,50 @@ GHOST_TSuccess GHOST_SystemWin32::init()
   FreeLibrary(user32);
   initRawInput();
 
+  UINT nDevices;
+  if (GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)) == 0) {
+    std::vector<RAWINPUTDEVICELIST> devices(nDevices);
+    if (GetRawInputDeviceList(devices.data(), &nDevices, sizeof(RAWINPUTDEVICELIST)) != -1) {
+      for (auto device : devices) {
+        if (device.dwType != RIM_TYPEHID) {
+          continue;
+        }
+
+        RID_DEVICE_INFO deviceInfo;
+        deviceInfo.cbSize = sizeof(deviceInfo);
+        UINT deviceInfoSize = sizeof(deviceInfo);
+        if (GetRawInputDeviceInfo(device.hDevice, RIDI_DEVICEINFO, &deviceInfo, &deviceInfoSize) ==
+            -1) {
+          continue;
+        }
+        if (deviceInfo.dwType == RIM_TYPEHID && deviceInfo.hid.usUsagePage == 0x0D) {
+          if (deviceInfo.hid.usUsage == 0x01 || deviceInfo.hid.usUsage == 0x02) {
+            // get device
+            UINT nameLen;
+            GetRawInputDeviceInfoW(device.hDevice, RIDI_DEVICENAME, NULL, &nameLen);
+            std::basic_string<WCHAR> name;
+            name.resize(nameLen);
+            GetRawInputDeviceInfoW(device.hDevice, RIDI_DEVICENAME, name.data(), &nameLen);
+
+            DEVPROPTYPE type = DEVPROP_TYPE_GUID;
+            GUID containerId;
+            ULONG containerIdSize = sizeof(containerId);
+            if (CM_Get_Device_Interface_PropertyW(name.data(),
+                                                  &DEVPKEY_Device_ContainerId,
+                                                  &type,
+                                                  (PBYTE)&containerId,
+                                                  &containerIdSize,
+                                                  0) == CR_SUCCESS) {
+              RPC_STATUS status;
+              m_tabletHandles.insert(UuidHash((GUID *)&containerId, &status));
+              printf("{" GUID_FORMAT "}\n", GUID_ARG(((GUID *)&containerId)));
+            }
+          }
+        }
+      }
+    }
+  }
+
   m_lfstart = ::GetTickCount();
   // Determine whether this system has a high frequency performance counter. */
   m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER *)&m_freq) == TRUE;
@@ -946,126 +1012,38 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type,
     window->updateMouseCapture(MouseReleased);
   }
 
-  /* Check for active Wintab mouse emulation in addition to a tablet in range because a proximity
-   * leave event might have fired before the Windows mouse up event, thus there are still tablet
-   * events to grab. The described behavior was observed in a Wacom Bamboo CTE-450. */
-  if (window->useTabletAPI(GHOST_kTabletWintab) &&
-      (window->m_tabletInRange || window->wintabSysButPressed()) &&
-      processWintabEvent(type, window, mask, window->getMousePressed())) {
-    /* Wintab processing only handles in-contact events. */
-    return NULL;
-  }
-
   return new GHOST_EventButton(
       system->getMilliSeconds(), type, window, mask, GHOST_TABLET_DATA_NONE);
 }
 
-GHOST_TSuccess GHOST_SystemWin32::processWintabEvent(GHOST_TEventType type,
-                                                     GHOST_WindowWin32 *window,
-                                                     GHOST_TButtonMask mask,
-                                                     bool mousePressed)
+GHOST_TSuccess GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window)
 {
   GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
 
-  /* Only process Wintab packets if we can correlate them to a Window's mouse button event. When a
-   * button event associated to a mouse button by Wintab occurs outside of WM_*BUTTON events,
-   * there's no way to tell if other simultaneously pressed non-mouse mapped buttons are associated
-   * to a modifier key (shift, alt, ctrl) or a system event (scroll, etc.) and thus it is not
-   * possible to determine if a mouse click event should occur. */
-  if (!mousePressed && !window->wintabSysButPressed()) {
-    return GHOST_kFailure;
-  }
-
   std::vector<GHOST_WintabInfoWin32> wintabInfo;
   if (!window->getWintabInfo(wintabInfo)) {
     return GHOST_kFailure;
   }
 
-  auto wtiIter = wintabInfo.begin();
-
-  /* We only process events that correlate to a mouse button events, so there may exist Wintab
-   * button down events that were instead mapped to e.g. scroll still in the queue. We need to
-   * skip those and find the last button down mapped to mouse buttons. */
-  if (!window->wintabSysButPressed()) {
-    /* Assume there may be no button down event currently in the queue. */
-    wtiIter = wintabInfo.end();
-
-    for (auto it = wintabInfo.begin(); it != wintabInfo.end(); it++) {
-      if (it->type == GHOST_kEventButtonDown) {
-        wtiIter = it;
-      }
-    }
-  }
-
-  bool unhandledButton = type != GHOST_kEventCursorMove;
-
-  for (; wtiIter != wintabInfo.end(); wtiIter++) {
-    auto info = *wtiIter;
-
+  for (auto info : wintabInfo) {
     switch (info.type) {
-      case GHOST_kEventButtonDown: {
-        /* While changing windows with a tablet, Window's mouse button events normally occur before
-         * tablet proximity events, so a button up event can't be differentiated as occurring from
-         * a Wintab tablet or a normal mouse and a Ghost button event will always be generated.
-         *
-         * If we were called during a button down event create a ghost button down event, otherwise
-         * don't duplicate the prior button down as it interrupts drawing immediately after
-         * changing a window. */
-        system->pushEvent(new GHOST_EventCursor(
-            info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData));
-        if (type == GHOST_kEventButtonDown && mask == info.button) {
-          system->pushEvent(
-              new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData));
-          unhandledButton = false;
-        }
-        window->updateWintabSysBut(MousePressed);
-        break;
-      }
       case GHOST_kEventCursorMove:
         system->pushEvent(new GHOST_EventCursor(
             info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData));
         break;
+      case GHOST_kEventButtonDown:
+        system->pushEvent(
+            new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData));
+        break;
       case GHOST_kEventButtonUp:
         system->pushEvent(
             new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData));
-        if (type == GHOST_kEventButtonUp && mask == info.button) {
-          unhandledButton = false;
-        }
-        window->updateWintabSysBut(MouseReleased);
         break;
       default:
         break;
     }
   }

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list