[gtk/gtk-3-24: 1/2] Handle Wintab cursors that are recognized after GDK app init




commit 4c10134295ddbf3812b015cb203855e2c7a2fe4f
Author: Steven Calwas <calwas2 hotmail com>
Date:   Thu Aug 20 22:54:36 2020 -0700

    Handle Wintab cursors that are recognized after GDK app init
    
    Previously, a GDK application handled the Wintab cursors (stylus,
    eraser, etc.) only during app initialization. If new cursors were
    recognized by Wintab during app execution, the app would not know
    about them.
    
    This fix still handles Wintab cursors known during app initialization.
    In addition, when Wintab recognizes new cursors and notifies the app
    via a WT_CSRCHANGE message, the app handles the new cursors, creating
    new Wintab device objects for them.
    
    Closes #1549

 gdk/win32/gdkdevicemanager-win32.c | 359 ++++++++++++++++++++++---------------
 1 file changed, 218 insertions(+), 141 deletions(-)
---
diff --git a/gdk/win32/gdkdevicemanager-win32.c b/gdk/win32/gdkdevicemanager-win32.c
index 830f5131c6..abd1931d8a 100644
--- a/gdk/win32/gdkdevicemanager-win32.c
+++ b/gdk/win32/gdkdevicemanager-win32.c
@@ -70,6 +70,10 @@ static gboolean default_display_opened = FALSE;
 
 G_DEFINE_TYPE (GdkDeviceManagerWin32, gdk_device_manager_win32, GDK_TYPE_DEVICE_MANAGER)
 
+static GdkDeviceWintab *gdk_device_manager_find_wintab_device (GdkDeviceManagerWin32 *, HCTX, UINT);
+UINT _wintab_recognize_new_cursors (GdkDeviceManagerWin32 *, HCTX);
+int _gdk_find_wintab_device_index (HCTX);
+
 static GdkDevice *
 create_pointer (GdkDeviceManager *device_manager,
                GType g_type,
@@ -355,18 +359,15 @@ wintab_init_check (GdkDeviceManagerWin32 *device_manager)
   GdkDisplay *display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
   GdkWindow *root = gdk_screen_get_root_window (gdk_display_get_default_screen (display));
   static gboolean wintab_initialized = FALSE;
-  GdkDeviceWintab *device;
   GdkWindowAttr wa;
   WORD specversion;
   HCTX *hctx;
-  UINT ndevices, ncursors, ncsrtypes, firstcsr, hardware;
-  BOOL active;
-  DWORD physid;
-  AXIS axis_x, axis_y, axis_npressure, axis_or[3];
-  UINT devix, cursorix;
-  int i, num_axes = 0;
-  wchar_t devname[100], csrname[100];
-  gchar *devname_utf8, *csrname_utf8, *device_name;
+  UINT ndevices, ncursors;
+  UINT devix;
+  AXIS axis_x, axis_y;
+  int i;
+  wchar_t devname[100];
+  gchar *devname_utf8;
   BOOL defcontext_done;
   HMODULE wintab32;
   char *wintab32_dll_path;
@@ -465,13 +466,8 @@ wintab_init_check (GdkDeviceManagerWin32 *device_manager)
 #ifdef DEBUG_WINTAB
       GDK_NOTE (INPUT, (g_print("Device %u: %s\n", devix, devname_utf8)));
 #endif
-      (*p_WTInfoA) (WTI_DEVICES + devix, DVC_NCSRTYPES, &ncsrtypes);
-      (*p_WTInfoA) (WTI_DEVICES + devix, DVC_FIRSTCSR, &firstcsr);
-      (*p_WTInfoA) (WTI_DEVICES + devix, DVC_HARDWARE, &hardware);
       (*p_WTInfoA) (WTI_DEVICES + devix, DVC_X, &axis_x);
       (*p_WTInfoA) (WTI_DEVICES + devix, DVC_Y, &axis_y);
-      (*p_WTInfoA) (WTI_DEVICES + devix, DVC_NPRESSURE, &axis_npressure);
-      (*p_WTInfoA) (WTI_DEVICES + devix, DVC_ORIENTATION, axis_or);
 
       defcontext_done = FALSE;
       if (HIBYTE (specversion) > 1 || LOBYTE (specversion) >= 1)
@@ -544,137 +540,183 @@ wintab_init_check (GdkDeviceManagerWin32 *device_manager)
         }
       if (!i)
         GDK_NOTE (INPUT, g_print("Whoops, no queue size could be set\n"));
-      for (cursorix = firstcsr; cursorix < firstcsr + ncsrtypes; cursorix++)
-        {
+
+      /* Get the cursors that Wintab is currently aware of */
+      _wintab_recognize_new_cursors(device_manager, *hctx);
+    }
+}
+
+UINT
+_wintab_recognize_new_cursors (GdkDeviceManagerWin32 *device_manager,
+                               HCTX                  hctx)
+{
+  GdkDisplay *display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
+  int devix;
+  wchar_t devname[100], csrname[100];
+  gchar *devname_utf8, *csrname_utf8, *device_name;
+  UINT ncsrtypes, firstcsr, cursorix;
+  BOOL active;
+  DWORD physid;
+  AXIS axis_x, axis_y, axis_npressure, axis_or[3];
+  GdkDeviceWintab *device;
+  LOGCONTEXT lc;
+  int num_axes;
+  UINT num_new_cursors = 0;
+
+  devix = _gdk_find_wintab_device_index(hctx);
+  if (devix == -1)
+    return num_new_cursors;
+    
+  (*p_WTInfoW) (WTI_DEVICES + devix, DVC_NAME, devname);
+  devname_utf8 = g_utf16_to_utf8 (devname, -1, NULL, NULL, NULL);
 #ifdef DEBUG_WINTAB
-          GDK_NOTE (INPUT, (g_print("Cursor %u:\n", cursorix), print_cursor (cursorix)));
+  GDK_NOTE (INPUT, (g_print("Finding cursors for device %u: %s\n", devix, devname_utf8)));
 #endif
-          active = FALSE;
-          (*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_ACTIVE, &active);
-          if (!active)
-            continue;
-
-          /* Wacom tablets seem to report cursors corresponding to
-           * nonexistent pens or pucks. At least my ArtPad II reports
-           * six cursors: a puck, pressure stylus and eraser stylus,
-           * and then the same three again. I only have a
-           * pressure-sensitive pen. The puck instances, and the
-           * second instances of the styluses report physid zero. So
-           * at least for Wacom, skip cursors with physid zero.
-           */
-          (*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_PHYSID, &physid);
-          if (wcscmp (devname, L"WACOM Tablet") == 0 && physid == 0)
-            continue;
-
-          (*p_WTInfoW) (WTI_CURSORS + cursorix, CSR_NAME, csrname);
-          csrname_utf8 = g_utf16_to_utf8 (csrname, -1, NULL, NULL, NULL);
-          device_name = g_strconcat (devname_utf8, " ", csrname_utf8, NULL);
-
-          device = g_object_new (GDK_TYPE_DEVICE_WINTAB,
-                                 "name", device_name,
-                                 "type", GDK_DEVICE_TYPE_FLOATING,
-                                 "input-source", GDK_SOURCE_PEN,
-                                 "input-mode", GDK_MODE_SCREEN,
-                                 "has-cursor", lc.lcOptions & CXO_SYSTEM,
-                                 "display", display,
-                                 "device-manager", device_manager,
-                                 NULL);
-
-         device->sends_core = lc.lcOptions & CXO_SYSTEM;
-         if (device->sends_core)
-           {
-             _gdk_device_set_associated_device (device_manager->system_pointer, GDK_DEVICE (device));
-             _gdk_device_add_slave (device_manager->core_pointer, GDK_DEVICE (device));
-           }
 
-          g_free (csrname_utf8);
+  (*p_WTInfoA) (WTI_DEVICES + devix, DVC_FIRSTCSR, &firstcsr);
+  (*p_WTInfoA) (WTI_DEVICES + devix, DVC_NCSRTYPES, &ncsrtypes);
+  for (cursorix = firstcsr; cursorix < firstcsr + ncsrtypes; cursorix++)
+    {
+#ifdef DEBUG_WINTAB
+      GDK_NOTE (INPUT, (g_print("Cursor %u:\n", cursorix), print_cursor (cursorix)));
+#endif
+      /* Skip cursors that are already known to us */
+      if (gdk_device_manager_find_wintab_device(device_manager, hctx, cursorix) != NULL)
+        continue;
+        
+      active = FALSE;
+      (*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_ACTIVE, &active);
+      if (!active)
+        continue;
+
+      /* Wacom tablets iterate through all possible cursors,
+       * even if the cursor's presence has not been recognized.
+       * Unrecognized cursors have a physid of zero and are ignored. 
+       * Recognized cursors have a non-zero physid and we create a 
+       * Wintab device object for each of them.
+       */
+      (*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_PHYSID, &physid);
+      if (wcscmp (devname, L"WACOM Tablet") == 0 && physid == 0)
+        continue;
 
-          device->hctx = *hctx;
-          device->cursor = cursorix;
-          (*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_PKTDATA, &device->pktdata);
+      if (!(*p_WTGetA) (hctx, &lc))
+        {
+          g_warning ("wintab_recognize_new_cursors: Failed to retrieve device LOGCONTEXT");
+          continue;
+        }
 
-          if (device->pktdata & PK_X)
-            {
-              _gdk_device_add_axis (GDK_DEVICE (device),
-                                    GDK_NONE,
-                                    GDK_AXIS_X,
-                                    axis_x.axMin,
-                                    axis_x.axMax,
-                                    axis_x.axResolution / 65535);
-              num_axes++;
-            }
+      /* Create a Wintab device for this cursor */
+      (*p_WTInfoA) (WTI_DEVICES + devix, DVC_X, &axis_x);
+      (*p_WTInfoA) (WTI_DEVICES + devix, DVC_Y, &axis_y);
+      (*p_WTInfoA) (WTI_DEVICES + devix, DVC_NPRESSURE, &axis_npressure);
+      (*p_WTInfoA) (WTI_DEVICES + devix, DVC_ORIENTATION, axis_or);
+      (*p_WTInfoW) (WTI_CURSORS + cursorix, CSR_NAME, csrname);
+      csrname_utf8 = g_utf16_to_utf8 (csrname, -1, NULL, NULL, NULL);
+      device_name = g_strconcat (devname_utf8, " ", csrname_utf8, NULL);
+      g_free (csrname_utf8);
+
+      device = g_object_new (GDK_TYPE_DEVICE_WINTAB,
+                              "name", device_name,
+                              "type", GDK_DEVICE_TYPE_FLOATING,
+                              "input-source", GDK_SOURCE_PEN,
+                              "input-mode", GDK_MODE_SCREEN,
+                              "has-cursor", lc.lcOptions & CXO_SYSTEM,
+                              "display", display,
+                              "device-manager", device_manager,
+                              NULL);
+
+      device->sends_core = lc.lcOptions & CXO_SYSTEM;
+      if (device->sends_core)
+        {
+          _gdk_device_set_associated_device (device_manager->system_pointer, GDK_DEVICE (device));
+          _gdk_device_add_slave (device_manager->core_pointer, GDK_DEVICE (device));
+        }
 
-          if (device->pktdata & PK_Y)
-            {
-              _gdk_device_add_axis (GDK_DEVICE (device),
-                                    GDK_NONE,
-                                    GDK_AXIS_Y,
-                                    axis_y.axMin,
-                                    axis_y.axMax,
-                                    axis_y.axResolution / 65535);
-              num_axes++;
-            }
+      device->hctx = hctx;
+      device->cursor = cursorix;
+      (*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_PKTDATA, &device->pktdata);
+      num_axes = 0;
 
+      if (device->pktdata & PK_X)
+        {
+          _gdk_device_add_axis (GDK_DEVICE (device),
+                                GDK_NONE,
+                                GDK_AXIS_X,
+                                axis_x.axMin,
+                                axis_x.axMax,
+                                axis_x.axResolution / 65535);
+          num_axes++;
+        }
 
-          if (device->pktdata & PK_NORMAL_PRESSURE)
-            {
-              _gdk_device_add_axis (GDK_DEVICE (device),
-                                    GDK_NONE,
-                                    GDK_AXIS_PRESSURE,
-                                    axis_npressure.axMin,
-                                    axis_npressure.axMax,
-                                    axis_npressure.axResolution / 65535);
-              num_axes++;
-            }
+      if (device->pktdata & PK_Y)
+        {
+          _gdk_device_add_axis (GDK_DEVICE (device),
+                                GDK_NONE,
+                                GDK_AXIS_Y,
+                                axis_y.axMin,
+                                axis_y.axMax,
+                                axis_y.axResolution / 65535);
+          num_axes++;
+        }
 
-          if (device->pktdata & PK_ORIENTATION)
-            {
-              device->orientation_axes[0] = axis_or[0];
-              device->orientation_axes[1] = axis_or[1];
-
-              /* Wintab gives us azimuth and altitude, which
-               * we convert to x and y tilt in the -1000..1000 range
-               */
-              _gdk_device_add_axis (GDK_DEVICE (device),
-                                    GDK_NONE,
-                                    GDK_AXIS_XTILT,
-                                    -1000,
-                                    1000,
-                                    1000);
-
-              _gdk_device_add_axis (GDK_DEVICE (device),
-                                    GDK_NONE,
-                                    GDK_AXIS_YTILT,
-                                    -1000,
-                                    1000,
-                                    1000);
-              num_axes += 2;
-            }
+      if (device->pktdata & PK_NORMAL_PRESSURE)
+        {
+          _gdk_device_add_axis (GDK_DEVICE (device),
+                                GDK_NONE,
+                                GDK_AXIS_PRESSURE,
+                                axis_npressure.axMin,
+                                axis_npressure.axMax,
+                                axis_npressure.axResolution / 65535);
+          num_axes++;
+        }
 
-          device->last_axis_data = g_new (gint, num_axes);
+      if (device->pktdata & PK_ORIENTATION)
+        {
+          device->orientation_axes[0] = axis_or[0];
+          device->orientation_axes[1] = axis_or[1];
 
-          GDK_NOTE (INPUT, g_print ("device: (%u) %s axes: %d\n",
-                                    cursorix,
-                                    device_name,
-                                    num_axes));
+          /* Wintab gives us azimuth and altitude, which
+           * we convert to x and y tilt in the -1000..1000 range
+           */
+          _gdk_device_add_axis (GDK_DEVICE (device),
+                                GDK_NONE,
+                                GDK_AXIS_XTILT,
+                                -1000,
+                                1000,
+                                1000);
+
+          _gdk_device_add_axis (GDK_DEVICE (device),
+                                GDK_NONE,
+                                GDK_AXIS_YTILT,
+                                -1000,
+                                1000,
+                                1000);
+          num_axes += 2;
+        }
 
-#if 0
-          for (i = 0; i < gdkdev->info.num_axes; i++)
-            GDK_NOTE (INPUT, g_print ("... axis %d: %d--%d@%d\n",
-                                      i,
-                                      gdkdev->axes[i].min_value,
-                                      gdkdev->axes[i].max_value,
-                                      gdkdev->axes[i].resolution));
-#endif
+      device->last_axis_data = g_new (gint, num_axes);
 
-          device_manager->wintab_devices = g_list_append (device_manager->wintab_devices,
-                                                          device);
+      GDK_NOTE (INPUT, g_print ("device: (%u) %s axes: %d\n",
+                                cursorix,
+                                device_name,
+                                num_axes));
 
-          g_free (device_name);
-        }
+#if 0
+      for (i = 0; i < gdkdev->info.num_axes; i++)
+        GDK_NOTE (INPUT, g_print ("... axis %d: %d--%d@%d\n",
+                                  i,
+                                  gdkdev->axes[i].min_value,
+                                  gdkdev->axes[i].max_value,
+                                  gdkdev->axes[i].resolution));
+#endif
 
-      g_free (devname_utf8);
+      device_manager->wintab_devices = g_list_append (device_manager->wintab_devices,
+                                                      device);
+      num_new_cursors++;
+      g_free (device_name);
     }
+  g_free (devname_utf8);
+  return num_new_cursors;
 }
 
 /* Only initialize Wintab after the default display is set for
@@ -918,6 +960,31 @@ get_modifier_key_state (void)
   return state;
 }
 
+int
+_gdk_find_wintab_device_index (HCTX hctx)
+{
+  GList *tmp_list;
+  int devix;
+
+  /* Find the index of the Wintab driver's input device (probably zero) */
+  if (!wintab_contexts)
+    return -1; /* No tablet devices found or Wintab not initialized yet */
+  
+  tmp_list = wintab_contexts;
+  devix = 0;
+  while (tmp_list)
+    {
+      if ((*(HCTX *) (tmp_list->data)) == hctx)
+        return devix;
+      else
+        {
+          devix++;
+          tmp_list = tmp_list->next;
+        }
+    }
+  return -1;
+}
+
 static GdkDeviceWintab *
 gdk_device_manager_find_wintab_device (GdkDeviceManagerWin32 *device_manager,
                                        HCTX                   hctx,
@@ -1221,21 +1288,31 @@ G_GNUC_END_IGNORE_DEPRECATIONS;
 
     case WT_CSRCHANGE:
       if (device_manager->dev_entered_proximity > 0)
-       device_manager->dev_entered_proximity -= 1;
+        device_manager->dev_entered_proximity -= 1;
 
-      if ((source_device = gdk_device_manager_find_wintab_device (device_manager,
-                                                                 (HCTX) msg->lParam,
-                                                                 packet.pkCursor)) == NULL)
-       return FALSE;
+      if ((source_device = 
+        gdk_device_manager_find_wintab_device (device_manager,
+                                                                                               (HCTX) 
msg->lParam,
+                                                                                               
packet.pkCursor)) == NULL)
+        {
+          /* Check for new cursors and try again */
+          if (_wintab_recognize_new_cursors(device_manager,
+                                            (HCTX) msg->lParam) == 0)
+              return FALSE;
+          if ((source_device =
+            gdk_device_manager_find_wintab_device (device_manager,
+                                                    (HCTX) msg->lParam,
+                                                    packet.pkCursor)) == NULL)
+            return FALSE;
+        }
 
       if (source_device->sends_core &&
-         gdk_device_get_mode (GDK_DEVICE (source_device)) != GDK_MODE_DISABLED)
-       {
-         _gdk_device_virtual_set_active (device_manager->core_pointer,
-                                         GDK_DEVICE (source_device));
-         _gdk_input_ignore_core += 1;
-       }
-
+               gdk_device_get_mode (GDK_DEVICE (source_device)) != GDK_MODE_DISABLED)
+             {
+               _gdk_device_virtual_set_active (device_manager->core_pointer,
+                                                                       GDK_DEVICE (source_device));
+               _gdk_input_ignore_core += 1;
+             }
       return FALSE;
 
     case WT_PROXIMITY:


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]