[gtk: 12/19] Handle WinPointer input




commit 68db945e477a95d63edf2047217edb49dad669ae
Author: Luca Bacci <luca bacci982 gmail com>
Date:   Fri Jul 9 15:17:17 2021 +0200

    Handle WinPointer input

 gdk/win32/gdkevents-win32.c     | 229 ++++++++++++++---
 gdk/win32/gdkinput-winpointer.c | 541 ++++++++++++++++++++++++++++++++++++++++
 gdk/win32/gdkinput-winpointer.h |  15 ++
 gdk/win32/gdkprivate-win32.h    |   2 +
 4 files changed, 749 insertions(+), 38 deletions(-)
---
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index 44a6792169..c49c0ed2fd 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -1253,6 +1253,26 @@ synthesize_crossing_events (GdkDisplay                 *display,
     }
 }
 
+static void
+make_crossing_event (GdkDevice *physical_device,
+                     GdkSurface *surface,
+                     POINT *screen_pt,
+                     guint32 time_)
+{
+  GDK_NOTE (EVENTS, g_print (" mouse_window %p -> %p",
+                             mouse_window ? GDK_SURFACE_HWND (mouse_window) : NULL,
+                             surface ? GDK_SURFACE_HWND (surface) : NULL));
+  synthesize_crossing_events (_gdk_display,
+                              physical_device,
+                              mouse_window, surface,
+                              GDK_CROSSING_NORMAL,
+                              screen_pt,
+                              0, /* TODO: Set right mask */
+                              time_,
+                              FALSE);
+  g_set_object (&mouse_window, surface);
+}
+
 /* Acquires actual client area size of the underlying native window.
  * Rectangle is in GDK screen coordinates (_gdk_offset_* is added).
  * Returns FALSE if configure events should be inhibited,
@@ -1771,6 +1791,8 @@ gdk_event_translate (MSG *msg,
   GdkDeviceGrabInfo *pointer_grab = NULL;
   GdkSurface *grab_window = NULL;
 
+  crossing_cb_t crossing_cb = NULL;
+
   int button;
 
   char buf[256];
@@ -2434,6 +2456,165 @@ gdk_event_translate (MSG *msg,
       return_val = TRUE;
       break;
 
+    case WM_POINTERDOWN:
+      if (_gdk_win32_tablet_input_api != GDK_WIN32_TABLET_INPUT_API_WINPOINTER ||
+          gdk_winpointer_should_forward_message (msg))
+        {
+          return_val = FALSE;
+          break;
+        }
+
+      if (pointer_grab != NULL &&
+          !pointer_grab->implicit &&
+          !pointer_grab->owner_events)
+        g_set_object (&window, pointer_grab->surface);
+
+      if (IS_POINTER_PRIMARY_WPARAM (msg->wParam) && mouse_window != window)
+        crossing_cb = make_crossing_event;
+
+      gdk_winpointer_input_events (window, crossing_cb, msg);
+
+      *ret_valp = 0;
+      return_val = TRUE;
+      break;
+
+    case WM_POINTERUP:
+      if (_gdk_win32_tablet_input_api != GDK_WIN32_TABLET_INPUT_API_WINPOINTER ||
+          gdk_winpointer_should_forward_message (msg))
+        {
+          return_val = FALSE;
+          break;
+        }
+
+      if (pointer_grab != NULL &&
+          !pointer_grab->implicit &&
+          !pointer_grab->owner_events)
+        g_set_object (&window, pointer_grab->surface);
+
+      gdk_winpointer_input_events (window, NULL, msg);
+
+      impl = GDK_WIN32_SURFACE (window);
+      if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
+        {
+          gdk_win32_surface_end_move_resize_drag (window);
+        }
+
+      *ret_valp = 0;
+      return_val = TRUE;
+      break;
+
+    case WM_POINTERUPDATE:
+      if (_gdk_win32_tablet_input_api != GDK_WIN32_TABLET_INPUT_API_WINPOINTER ||
+          gdk_winpointer_should_forward_message (msg))
+        {
+          return_val = FALSE;
+          break;
+        }
+
+      if (pointer_grab != NULL &&
+          !pointer_grab->implicit &&
+          !pointer_grab->owner_events)
+        g_set_object (&window, pointer_grab->surface);
+
+      if (IS_POINTER_PRIMARY_WPARAM (msg->wParam) && mouse_window != window)
+        crossing_cb = make_crossing_event;
+
+      impl = GDK_WIN32_SURFACE (window);
+
+      if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
+        {
+          gdk_win32_surface_do_move_resize_drag (window, current_root_x, current_root_y);
+        }
+      else
+        {
+          gdk_winpointer_input_events (window, crossing_cb, msg);
+        }
+
+      *ret_valp = 0;
+      return_val = TRUE;
+      break;
+
+    case WM_NCPOINTERUPDATE:
+      if (_gdk_win32_tablet_input_api != GDK_WIN32_TABLET_INPUT_API_WINPOINTER ||
+          gdk_winpointer_should_forward_message (msg))
+        {
+          return_val = FALSE;
+          break;
+        }
+
+      if (IS_POINTER_PRIMARY_WPARAM (msg->wParam) &&
+          !IS_POINTER_INCONTACT_WPARAM (msg->wParam) &&
+          mouse_window != NULL)
+        {
+          GdkDevice *event_device = NULL;
+          guint32 event_time = 0;
+
+          if (gdk_winpointer_get_message_info (msg, &event_device, &event_time))
+            {
+              make_crossing_event(event_device,
+                                  NULL,
+                                  &msg->pt,
+                                  event_time);
+            }
+        }
+
+      return_val = FALSE; /* forward to DefWindowProc */
+      break;
+
+    case WM_POINTERENTER:
+      if (_gdk_win32_tablet_input_api != GDK_WIN32_TABLET_INPUT_API_WINPOINTER ||
+          gdk_winpointer_should_forward_message (msg))
+        {
+          return_val = FALSE;
+          break;
+        }
+
+      if (pointer_grab != NULL &&
+          !pointer_grab->implicit &&
+          !pointer_grab->owner_events)
+        g_set_object (&window, pointer_grab->surface);
+
+      if (IS_POINTER_NEW_WPARAM (msg->wParam))
+        {
+          gdk_winpointer_input_events (window, NULL, msg);
+        }
+
+      *ret_valp = 0;
+      return_val = TRUE;
+      break;
+
+    case WM_POINTERLEAVE:
+      if (_gdk_win32_tablet_input_api != GDK_WIN32_TABLET_INPUT_API_WINPOINTER ||
+          gdk_winpointer_should_forward_message (msg))
+        {
+          return_val = FALSE;
+          break;
+        }
+
+      if (!IS_POINTER_INRANGE_WPARAM (msg->wParam))
+        {
+          gdk_winpointer_input_events (window, NULL, msg);
+        }
+      else if (IS_POINTER_PRIMARY_WPARAM (msg->wParam) && mouse_window != NULL)
+        {
+          GdkDevice *event_device = NULL;
+          guint32 event_time = 0;
+
+          if (gdk_winpointer_get_message_info (msg, &event_device, &event_time))
+            {
+              make_crossing_event(event_device,
+                                  NULL,
+                                  &msg->pt,
+                                  event_time);
+            }
+        }
+
+      gdk_winpointer_interaction_ended (msg);
+
+      *ret_valp = 0;
+      return_val = TRUE;
+      break;
+
     case WM_MOUSEWHEEL:
     case WM_MOUSEHWHEEL:
       GDK_NOTE (EVENTS, g_print (" %d", (short) HIWORD (msg->wParam)));
@@ -2532,44 +2713,6 @@ gdk_event_translate (MSG *msg,
       return_val = TRUE;
       break;
 
-    case WM_HSCROLL:
-      /* Just print more debugging information, don't actually handle it. */
-      GDK_NOTE (EVENTS,
-               (g_print (" %s",
-                         (LOWORD (msg->wParam) == SB_ENDSCROLL ? "ENDSCROLL" :
-                          (LOWORD (msg->wParam) == SB_LEFT ? "LEFT" :
-                           (LOWORD (msg->wParam) == SB_RIGHT ? "RIGHT" :
-                            (LOWORD (msg->wParam) == SB_LINELEFT ? "LINELEFT" :
-                             (LOWORD (msg->wParam) == SB_LINERIGHT ? "LINERIGHT" :
-                              (LOWORD (msg->wParam) == SB_PAGELEFT ? "PAGELEFT" :
-                               (LOWORD (msg->wParam) == SB_PAGERIGHT ? "PAGERIGHT" :
-                                (LOWORD (msg->wParam) == SB_THUMBPOSITION ? "THUMBPOSITION" :
-                                 (LOWORD (msg->wParam) == SB_THUMBTRACK ? "THUMBTRACK" :
-                                  "???")))))))))),
-                (LOWORD (msg->wParam) == SB_THUMBPOSITION ||
-                 LOWORD (msg->wParam) == SB_THUMBTRACK) ?
-                (g_print (" %d", HIWORD (msg->wParam)), 0) : 0));
-      break;
-
-    case WM_VSCROLL:
-      /* Just print more debugging information, don't actually handle it. */
-      GDK_NOTE (EVENTS,
-               (g_print (" %s",
-                         (LOWORD (msg->wParam) == SB_ENDSCROLL ? "ENDSCROLL" :
-                          (LOWORD (msg->wParam) == SB_BOTTOM ? "BOTTOM" :
-                           (LOWORD (msg->wParam) == SB_TOP ? "TOP" :
-                            (LOWORD (msg->wParam) == SB_LINEDOWN ? "LINDOWN" :
-                             (LOWORD (msg->wParam) == SB_LINEUP ? "LINEUP" :
-                              (LOWORD (msg->wParam) == SB_PAGEDOWN ? "PAGEDOWN" :
-                               (LOWORD (msg->wParam) == SB_PAGEUP ? "PAGEUP" :
-                                (LOWORD (msg->wParam) == SB_THUMBPOSITION ? "THUMBPOSITION" :
-                                 (LOWORD (msg->wParam) == SB_THUMBTRACK ? "THUMBTRACK" :
-                                  "???")))))))))),
-                (LOWORD (msg->wParam) == SB_THUMBPOSITION ||
-                 LOWORD (msg->wParam) == SB_THUMBTRACK) ?
-                (g_print (" %d", HIWORD (msg->wParam)), 0) : 0));
-      break;
-
      case WM_MOUSEACTIVATE:
        {
         if (GDK_IS_DRAG_SURFACE (window))
@@ -2587,6 +2730,16 @@ gdk_event_translate (MSG *msg,
 
        break;
 
+    case WM_POINTERACTIVATE:
+      if (GDK_IS_DRAG_SURFACE (window) ||
+          _gdk_modal_blocked (window))
+        {
+          *ret_valp = PA_NOACTIVATE;
+          return_val = TRUE;
+        }
+
+      break;
+
     case WM_KILLFOCUS:
       if (keyboard_grab != NULL &&
          !GDK_SURFACE_DESTROYED (keyboard_grab->surface) &&
diff --git a/gdk/win32/gdkinput-winpointer.c b/gdk/win32/gdkinput-winpointer.c
index 5628cb5df9..61668ca685 100644
--- a/gdk/win32/gdkinput-winpointer.c
+++ b/gdk/win32/gdkinput-winpointer.c
@@ -21,11 +21,13 @@
 #include "gdkwin32.h"
 #include "gdkprivate-win32.h"
 #include "gdkdevicemanager-win32.h"
+#include "gdkdevice-virtual.h"
 #include "gdkdevice-winpointer.h"
 #include "gdkdeviceprivate.h"
 #include "gdkdisplayprivate.h"
 #include "gdkseatdefaultprivate.h"
 #include "gdkdevicetoolprivate.h"
+#include "gdkinput-winpointer.h"
 
 #include <windows.h>
 
@@ -49,6 +51,10 @@ typedef BOOL
 typedef BOOL
 (WINAPI *getPointerCursorId_t)(UINT32 pointerId, UINT32 *cursorId);
 typedef BOOL
+(WINAPI *getPointerPenInfo_t)(UINT32 pointerId, POINTER_PEN_INFO *penInfo);
+typedef BOOL
+(WINAPI *getPointerTouchInfo_t)(UINT32 pointerId, POINTER_TOUCH_INFO *touchInfo);
+typedef BOOL
 (WINAPI *getPointerPenInfoHistory_t)(UINT32 pointerId, UINT32 *entriesCount, POINTER_PEN_INFO *penInfo);
 typedef BOOL
 (WINAPI *getPointerTouchInfoHistory_t)(UINT32 pointerId, UINT32 *entriesCount, POINTER_TOUCH_INFO 
*touchInfo);
@@ -61,6 +67,8 @@ static getPointerDeviceCursors_t getPointerDeviceCursors;
 static getPointerDeviceRects_t getPointerDeviceRects;
 static getPointerType_t getPointerType;
 static getPointerCursorId_t getPointerCursorId;
+static getPointerPenInfo_t getPointerPenInfo;
+static getPointerTouchInfo_t getPointerTouchInfo;
 static getPointerPenInfoHistory_t getPointerPenInfoHistory;
 static getPointerTouchInfoHistory_t getPointerTouchInfoHistory;
 static setGestureConfig_t setGestureConfig;
@@ -68,6 +76,531 @@ static setGestureConfig_t setGestureConfig;
 static ATOM notifications_window_class;
 static HWND notifications_window_handle;
 
+static GPtrArray *ignored_interactions;
+
+static inline void
+winpointer_ignore_interaction (UINT32 pointer_id)
+{
+  g_ptr_array_add (ignored_interactions, GUINT_TO_POINTER (pointer_id));
+}
+
+static inline void
+winpointer_remove_ignored_interaction (UINT32 pointer_id)
+{
+  g_ptr_array_remove_fast (ignored_interactions, GUINT_TO_POINTER (pointer_id));
+}
+
+static inline gboolean
+winpointer_should_ignore_interaction (UINT32 pointer_id)
+{
+  return g_ptr_array_find (ignored_interactions, GUINT_TO_POINTER (pointer_id), NULL);
+}
+
+static inline guint32
+winpointer_get_time (MSG *msg,
+                     POINTER_INFO *info)
+{
+  return info->dwTime != 0 ? info->dwTime : msg->time;
+}
+
+static inline gboolean
+winpointer_is_eraser (POINTER_PEN_INFO *pen_info)
+{
+  return (pen_info->penFlags & (PEN_FLAG_INVERTED | PEN_FLAG_ERASER)) != 0;
+}
+
+static inline gboolean
+winpointer_should_filter_message (MSG *msg,
+                                  POINTER_INPUT_TYPE type)
+{
+  switch (type)
+    {
+    case PT_TOUCH:
+      return msg->message == WM_POINTERENTER ||
+             msg->message == WM_POINTERLEAVE;
+    break;
+    }
+
+  return FALSE;
+}
+
+static inline double*
+copy_axes (double *axes)
+{
+  return g_memdup2 (axes, sizeof (double) * GDK_AXIS_LAST);
+}
+
+static GdkDeviceWinpointer*
+winpointer_find_device_with_source (HANDLE device_handle,
+                                    UINT32 cursor_id,
+                                    GdkInputSource input_source)
+{
+  for (GList *l = _gdk_device_manager->winpointer_devices; l != NULL; l = l->next)
+    {
+      GdkDeviceWinpointer *device = (GdkDeviceWinpointer*) l->data;
+
+      if (device->device_handle == device_handle &&
+          device->start_cursor_id <= cursor_id &&
+          device->end_cursor_id >= cursor_id &&
+          gdk_device_get_source ((GdkDevice*) device) == input_source)
+        {
+          return device;
+        }
+    }
+
+  return NULL;
+}
+
+static gboolean
+winpointer_get_event_type (MSG *msg,
+                           POINTER_INFO *info,
+                           GdkEventType *evt_type)
+{
+  switch (info->pointerType)
+    {
+    case PT_PEN:
+      switch (msg->message)
+        {
+        case WM_POINTERENTER:
+          g_return_val_if_fail (IS_POINTER_NEW_WPARAM (msg->wParam), FALSE);
+          *evt_type = GDK_PROXIMITY_IN;
+        return TRUE;
+        case WM_POINTERLEAVE:
+          g_return_val_if_fail (!IS_POINTER_INRANGE_WPARAM (msg->wParam), FALSE);
+          *evt_type = GDK_PROXIMITY_OUT;
+        return TRUE;
+        case WM_POINTERDOWN:
+          *evt_type = GDK_BUTTON_PRESS;
+        return TRUE;
+        case WM_POINTERUP:
+          *evt_type = GDK_BUTTON_RELEASE;
+        return TRUE;
+        case WM_POINTERUPDATE:
+          *evt_type = GDK_MOTION_NOTIFY;
+        return TRUE;
+        }
+    break;
+    case PT_TOUCH:
+      if (IS_POINTER_CANCELED_WPARAM (msg->wParam) ||
+          !HAS_POINTER_CONFIDENCE_WPARAM (msg->wParam))
+        {
+          winpointer_ignore_interaction (GET_POINTERID_WPARAM (msg->wParam));
+
+          if (((info->pointerFlags & POINTER_FLAG_INCONTACT) &&
+               (info->pointerFlags & POINTER_FLAG_UPDATE)) ||
+              (info->pointerFlags & POINTER_FLAG_UP))
+            {
+              *evt_type = GDK_TOUCH_CANCEL;
+              return TRUE;
+            }
+          else
+            return FALSE;
+        }
+
+      g_return_val_if_fail (msg->message != WM_POINTERENTER &&
+                            msg->message != WM_POINTERLEAVE, FALSE);
+
+      switch (msg->message)
+        {
+          case WM_POINTERDOWN:
+            *evt_type = GDK_TOUCH_BEGIN;
+          return TRUE;
+          case WM_POINTERUP:
+            *evt_type = GDK_TOUCH_END;
+          return TRUE;
+          case WM_POINTERUPDATE:
+            if (!IS_POINTER_INCONTACT_WPARAM (msg->wParam))
+              return FALSE;
+            *evt_type = GDK_TOUCH_UPDATE;
+          return TRUE;
+        }
+    break;
+    }
+
+  g_warn_if_reached ();
+
+  return FALSE;
+}
+
+static void
+winpointer_make_event (GdkDeviceWinpointer *device,
+                       GdkDeviceTool *tool,
+                       GdkSurface *surface,
+                       MSG *msg,
+                       POINTER_INFO *info)
+{
+  guint32 time = 0;
+  double screen_x = 0.0;
+  double screen_y = 0.0;
+  double x = 0.0;
+  double y = 0.0;
+  unsigned int state = 0;
+  unsigned int button = 0;
+  double axes[GDK_AXIS_LAST];
+  GdkEventSequence *sequence = NULL;
+  gboolean emulating_pointer = FALSE;
+  POINT client_area_coordinates;
+  GdkWin32Surface *impl = NULL;
+  GdkEventType evt_type;
+  GdkEvent *evt = NULL;
+  GdkDevice *core_device = NULL;
+
+  core_device = _gdk_device_manager->core_pointer;
+
+  if (!winpointer_get_event_type (msg, info, &evt_type))
+    return;
+
+  time = winpointer_get_time (msg, info);
+
+  screen_x = device->origin_x + info->ptHimetricLocation.x * device->scale_x;
+  screen_y = device->origin_y + info->ptHimetricLocation.y * device->scale_y;
+
+  client_area_coordinates.x = 0;
+  client_area_coordinates.y = 0;
+  ClientToScreen (GDK_SURFACE_HWND (surface), &client_area_coordinates);
+  x = screen_x - client_area_coordinates.x;
+  y = screen_y - client_area_coordinates.y;
+
+  impl = GDK_WIN32_SURFACE (surface);
+  x /= impl->surface_scale;
+  y /= impl->surface_scale;
+
+  state = 0;
+  if (info->dwKeyStates & POINTER_MOD_CTRL)
+    state |= GDK_CONTROL_MASK;
+  if (info->dwKeyStates & POINTER_MOD_SHIFT)
+    state |= GDK_SHIFT_MASK;
+  if (GetKeyState (VK_MENU) < 0)
+    state |= GDK_ALT_MASK;
+  if (GetKeyState (VK_CAPITAL) & 0x1)
+    state |= GDK_LOCK_MASK;
+
+  device->last_button_mask = 0;
+  if (((info->pointerFlags & POINTER_FLAG_FIRSTBUTTON) &&
+       (info->ButtonChangeType != POINTER_CHANGE_FIRSTBUTTON_DOWN))
+      || info->ButtonChangeType == POINTER_CHANGE_FIRSTBUTTON_UP)
+    device->last_button_mask |= GDK_BUTTON1_MASK;
+  if (((info->pointerFlags & POINTER_FLAG_SECONDBUTTON) &&
+       (info->ButtonChangeType != POINTER_CHANGE_SECONDBUTTON_DOWN))
+      || info->ButtonChangeType == POINTER_CHANGE_SECONDBUTTON_UP)
+    device->last_button_mask |= GDK_BUTTON3_MASK;
+  state |= device->last_button_mask;
+
+  memset (axes, 0, sizeof (axes));
+  switch (info->pointerType)
+    {
+    case PT_PEN:
+      {
+        POINTER_PEN_INFO *pen_info = (POINTER_PEN_INFO*) info;
+
+        axes[GDK_AXIS_PRESSURE] = (pen_info->penMask & PEN_MASK_PRESSURE) ?
+                                   pen_info->pressure / 1024.0 :
+                                  (pen_info->pointerInfo.pointerFlags & POINTER_FLAG_INCONTACT) ?
+                                   1.0 : 0.0;
+        axes[GDK_AXIS_XTILT] = (pen_info->penMask & PEN_MASK_TILT_X) ?
+                                pen_info->tiltX / 90.0 : 0.0;
+        axes[GDK_AXIS_YTILT] = (pen_info->penMask & PEN_MASK_TILT_Y) ?
+                                pen_info->tiltY / 90.0 : 0.0;
+        axes[GDK_AXIS_ROTATION] = (pen_info->penMask & PEN_MASK_ROTATION) ?
+                                   pen_info->rotation / 360.0 : 0.0;
+      }
+    break;
+    case PT_TOUCH:
+      {
+        POINTER_TOUCH_INFO *touch_info = (POINTER_TOUCH_INFO*) info;
+
+        axes[GDK_AXIS_PRESSURE] = (touch_info->touchMask & TOUCH_MASK_PRESSURE) ?
+                                   touch_info->pressure / 1024.0 :
+                                  (touch_info->pointerInfo.pointerFlags & POINTER_FLAG_INCONTACT) ?
+                                   1.0 : 0.0;
+      }
+    break;
+    }
+
+  sequence = (GdkEventSequence*) GUINT_TO_POINTER (info->pointerId);
+  emulating_pointer = (info->pointerFlags & POINTER_FLAG_PRIMARY) != 0;
+  button = (info->pointerFlags & POINTER_FLAG_FIRSTBUTTON) ||
+           (info->ButtonChangeType == POINTER_CHANGE_FIRSTBUTTON_UP) ? 1 : 3;
+
+  switch (evt_type)
+    {
+    case GDK_PROXIMITY_IN:
+    case GDK_PROXIMITY_OUT:
+      evt = gdk_proximity_event_new (evt_type,
+                                     surface,
+                                     core_device,
+                                     tool,
+                                     time);
+    break;
+    case GDK_BUTTON_PRESS:
+    case GDK_BUTTON_RELEASE:
+      evt = gdk_button_event_new (evt_type,
+                                  surface,
+                                  core_device,
+                                  tool,
+                                  time,
+                                  state,
+                                  button,
+                                  x,
+                                  y,
+                                  copy_axes (axes));
+    break;
+    case GDK_MOTION_NOTIFY:
+      evt = gdk_motion_event_new (surface,
+                                  core_device,
+                                  tool,
+                                  time,
+                                  state,
+                                  x,
+                                  y,
+                                  copy_axes (axes));
+    break;
+    case GDK_TOUCH_BEGIN:
+    case GDK_TOUCH_UPDATE:
+    case GDK_TOUCH_CANCEL:
+    case GDK_TOUCH_END:
+      evt = gdk_touch_event_new (evt_type,
+                                 sequence,
+                                 surface,
+                                 core_device,
+                                 time,
+                                 state,
+                                 x,
+                                 y,
+                                 copy_axes (axes),
+                                 emulating_pointer);
+    break;
+    default:
+      g_warn_if_reached ();
+    break;
+    }
+
+  if (evt_type == GDK_PROXIMITY_OUT)
+    gdk_device_update_tool ((GdkDevice*) device, NULL);
+
+  if (G_LIKELY (evt))
+    {
+      _gdk_device_virtual_set_active (core_device, (GdkDevice*) device);
+      _gdk_win32_append_event (evt);
+    }
+}
+
+void
+gdk_winpointer_input_events (GdkSurface *surface,
+                             crossing_cb_t crossing_cb,
+                             MSG *msg)
+{
+  UINT32 pointer_id = GET_POINTERID_WPARAM (msg->wParam);
+  POINTER_INPUT_TYPE type = PT_POINTER;
+  UINT32 cursor_id = 0;
+
+  if (!getPointerType (pointer_id, &type))
+    {
+      WIN32_API_FAILED_LOG_ONCE ("GetPointerType");
+      return;
+    }
+
+  if (!getPointerCursorId (pointer_id, &cursor_id))
+    {
+      WIN32_API_FAILED_LOG_ONCE ("GetPointerCursorId");
+      return;
+    }
+
+  if (winpointer_should_filter_message (msg, type))
+    return;
+
+  if (winpointer_should_ignore_interaction (pointer_id))
+    return;
+
+  switch (type)
+    {
+    case PT_PEN:
+      {
+        POINTER_PEN_INFO *infos = NULL;
+        UINT32 history_count = 0;
+        GdkDeviceWinpointer *device = NULL;
+        GdkDeviceTool *tool = NULL;
+        UINT32 h = 0;
+
+        do
+          {
+            infos = g_new0 (POINTER_PEN_INFO, history_count);
+            if (!getPointerPenInfoHistory (pointer_id, &history_count, infos))
+              {
+                WIN32_API_FAILED_LOG_ONCE ("GetPointerPenInfoHistory");
+                g_free (infos);
+                return;
+              }
+          }
+        while (!infos && history_count > 0);
+
+        if (G_UNLIKELY (history_count == 0))
+          return;
+
+        device = winpointer_find_device_with_source (infos->pointerInfo.sourceDevice, cursor_id, 
GDK_SOURCE_PEN);
+        if (G_UNLIKELY (!device))
+          {
+            g_free (infos);
+            return;
+          }
+
+        if (!winpointer_is_eraser (infos))
+          tool = device->tool_pen;
+        else
+          tool = device->tool_eraser;
+
+        gdk_device_update_tool ((GdkDevice*) device, tool);
+
+        h = history_count - 1;
+
+        if (crossing_cb)
+          {
+            POINT screen_pt = infos[h].pointerInfo.ptPixelLocation;
+            guint32 event_time = winpointer_get_time (msg, &infos[h].pointerInfo);
+
+            crossing_cb(GDK_DEVICE (device), surface, &screen_pt, event_time);
+          }
+
+        do
+          winpointer_make_event (device, tool, surface, msg, (POINTER_INFO*) &infos[h]);
+        while (h-- > 0);
+
+        g_free (infos);
+      }
+    break;
+    case PT_TOUCH:
+      {
+        POINTER_TOUCH_INFO *infos = NULL;
+        UINT32 history_count = 0;
+        GdkDeviceWinpointer *device = NULL;
+        UINT32 h = 0;
+
+        do
+          {
+            infos = g_new0 (POINTER_TOUCH_INFO, history_count);
+            if (!getPointerTouchInfoHistory (pointer_id, &history_count, infos))
+              {
+                WIN32_API_FAILED_LOG_ONCE ("GetPointerTouchInfoHistory");
+                g_free (infos);
+                return;
+              }
+          }
+        while (!infos && history_count > 0);
+
+        if (G_UNLIKELY (history_count == 0))
+          return;
+
+        device = winpointer_find_device_with_source (infos->pointerInfo.sourceDevice, cursor_id, 
GDK_SOURCE_TOUCHSCREEN);
+        if (G_UNLIKELY (!device))
+          {
+            g_free (infos);
+            return;
+          }
+
+        h = history_count - 1;
+
+        if (crossing_cb)
+          {
+            POINT screen_pt = infos[h].pointerInfo.ptPixelLocation;
+            guint32 event_time = winpointer_get_time (msg, &infos[h].pointerInfo);
+
+            crossing_cb(GDK_DEVICE (device), surface, &screen_pt, event_time);
+          }
+
+        do
+          winpointer_make_event (device, NULL, surface, msg, (POINTER_INFO*) &infos[h]);
+        while (h-- > 0);
+
+        g_free (infos);
+      }
+    break;
+    }
+}
+
+gboolean
+gdk_winpointer_get_message_info (MSG *msg,
+                                 GdkDevice **device,
+                                 guint32 *time)
+{
+  UINT32 pointer_id = GET_POINTERID_WPARAM (msg->wParam);
+  POINTER_INPUT_TYPE type = PT_POINTER;
+  UINT32 cursor_id = 0;
+
+  if (!getPointerType (pointer_id, &type))
+    {
+      WIN32_API_FAILED_LOG_ONCE ("GetPointerType");
+      return FALSE;
+    }
+
+  if (!getPointerCursorId (pointer_id, &cursor_id))
+    {
+      WIN32_API_FAILED_LOG_ONCE ("GetPointerCursorId");
+      return FALSE;
+    }
+
+  switch (type)
+    {
+    case PT_PEN:
+      {
+        POINTER_PEN_INFO pen_info;
+
+        if (!getPointerPenInfo (pointer_id, &pen_info))
+          {
+            WIN32_API_FAILED_LOG_ONCE ("GetPointerPenInfo");
+            return FALSE;
+          }
+
+        *device = (GdkDevice*) winpointer_find_device_with_source (pen_info.pointerInfo.sourceDevice, 
cursor_id, GDK_SOURCE_PEN);
+        *time = winpointer_get_time (msg, &pen_info.pointerInfo);
+      }
+    break;
+    case PT_TOUCH:
+      {
+        POINTER_TOUCH_INFO touch_info;
+
+        if (!getPointerTouchInfo (pointer_id, &touch_info))
+            {
+              WIN32_API_FAILED_LOG_ONCE ("GetPointerTouchInfo");
+              return FALSE;
+            }
+
+        *device = GDK_DEVICE (winpointer_find_device_with_source (touch_info.pointerInfo.sourceDevice,
+                                                                  cursor_id,
+                                                                  GDK_SOURCE_TOUCHSCREEN));
+
+        *time = winpointer_get_time (msg, &touch_info.pointerInfo);
+      }
+    break;
+    default:
+      g_warn_if_reached ();
+      return FALSE;
+    break;
+    }
+
+  return *device ? TRUE : FALSE;
+}
+
+gboolean
+gdk_winpointer_should_forward_message (MSG *msg)
+{
+  UINT32 pointer_id = GET_POINTERID_WPARAM (msg->wParam);
+  POINTER_INPUT_TYPE type = PT_POINTER;
+
+  if (!getPointerType (pointer_id, &type))
+    {
+      WIN32_API_FAILED_LOG_ONCE ("GetPointerType");
+      return TRUE;
+    }
+
+  return !(type == PT_PEN || type == PT_TOUCH);
+}
+
+void
+gdk_winpointer_interaction_ended (MSG *msg)
+{
+  winpointer_remove_ignored_interaction (GET_POINTERID_WPARAM (msg->wParam));
+}
+
 static inline double
 utils_rect_width (RECT *rect)
 {
@@ -516,6 +1049,10 @@ winpointer_ensure_procedures (void)
         GetProcAddress (user32_dll, "GetPointerType");
       getPointerCursorId = (getPointerCursorId_t)
         GetProcAddress (user32_dll, "GetPointerCursorId");
+      getPointerPenInfo = (getPointerPenInfo_t)
+        GetProcAddress (user32_dll, "GetPointerPenInfo");
+      getPointerTouchInfo = (getPointerTouchInfo_t)
+        GetProcAddress (user32_dll, "GetPointerTouchInfo");
       getPointerPenInfoHistory = (getPointerPenInfoHistory_t)
         GetProcAddress (user32_dll, "GetPointerPenInfoHistory");
       getPointerTouchInfoHistory = (getPointerTouchInfoHistory_t)
@@ -530,6 +1067,8 @@ winpointer_ensure_procedures (void)
          getPointerDeviceRects &&
          getPointerType &&
          getPointerCursorId &&
+         getPointerPenInfo &&
+         getPointerTouchInfo &&
          getPointerPenInfoHistory &&
          getPointerTouchInfoHistory &&
          setGestureConfig;
@@ -550,6 +1089,8 @@ gdk_winpointer_initialize (void)
       return FALSE;
     }
 
+  ignored_interactions = g_ptr_array_new ();
+
   winpointer_enumerate_devices ();
 
   return TRUE;
diff --git a/gdk/win32/gdkinput-winpointer.h b/gdk/win32/gdkinput-winpointer.h
index d8a55c8f07..36c1a39f0d 100644
--- a/gdk/win32/gdkinput-winpointer.h
+++ b/gdk/win32/gdkinput-winpointer.h
@@ -25,4 +25,19 @@ gboolean gdk_winpointer_initialize (void);
 void gdk_winpointer_initialize_surface (GdkSurface *surface);
 void gdk_winpointer_finalize_surface (GdkSurface *surface);
 
+typedef void
+(*crossing_cb_t)(GdkDevice *physical_device,
+                 GdkSurface *surface,
+                 POINT *screen_pt,
+                 guint32 time_);
+
+gboolean gdk_winpointer_should_forward_message (MSG *msg);
+void     gdk_winpointer_input_events (GdkSurface *surface,
+                                      crossing_cb_t crossing_cb,
+                                      MSG *msg);
+gboolean gdk_winpointer_get_message_info (MSG *msg,
+                                          GdkDevice **device,
+                                          guint32 *time_);
+void     gdk_winpointer_interaction_ended (MSG *msg);
+
 #endif /* __GDK_INPUT_WINPOINTER_H__ */
diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h
index 0f0062db29..58714024eb 100644
--- a/gdk/win32/gdkprivate-win32.h
+++ b/gdk/win32/gdkprivate-win32.h
@@ -246,6 +246,8 @@ void    _gdk_other_api_failed        (const char *where,
 #define WIN32_GDI_FAILED(api) WIN32_API_FAILED (api)
 #define OTHER_API_FAILED(api) _gdk_other_api_failed (G_STRLOC, api)
 
+#define WIN32_API_FAILED_LOG_ONCE(api) G_STMT_START { static gboolean logged = 0; if (!logged) { 
_gdk_win32_api_failed (G_STRLOC , api); logged = 1; }} G_STMT_END
+
 /* These two macros call a GDI or other Win32 API and if the return
  * value is zero or NULL, print a warning message. The majority of GDI
  * calls return zero or NULL on failure. The value of the macros is nonzero


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