Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  gdkinput-winpointer.c

  Sprache: C
 

/* GDK - The GIMP Drawing Kit
 * Copyright (C) 2021 the GTK team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 */


#include "config.h"

#include <gdk/gdk.h>
#include "gdkwin32.h"
#include "gdkprivate-win32.h"
#include "gdkdevicemanager-win32.h"
#include "gdkdevice-virtual.h"
#include "gdkdevice-winpointer.h"
#include "gdkdeviceprivate.h"
#include "gdkdevicetoolprivate.h"
#include "gdkdisplay-win32.h"
#include "gdkeventsprivate.h"
#include "gdkseat-win32.h"

#include "gdkinput-winpointer.h"

#include <windows.h>

#include <tchar.h>
#include <tpcshrd.h>
#include <hidsdi.h>

#define HID_STRING_BYTES_LIMIT 200
#define VID_PID_CHARS 4

typedef BOOL
(WINAPI *registerPointerDeviceNotifications_t)(HWND window, BOOL notifyRange);
typedef BOOL
(WINAPI *getPointerDevices_t)(UINT32 *deviceCount, POINTER_DEVICE_INFO *pointerDevices);
typedef BOOL
(WINAPI *getPointerDeviceCursors_t)(HANDLE device, UINT32 *cursorCount, POINTER_DEVICE_CURSOR_INFO *deviceCursors);
typedef BOOL
(WINAPI *getPointerDeviceRects_t)(HANDLE device, RECT *pointerDeviceRect, RECT *displayRect);
typedef BOOL
(WINAPI *getPointerType_t)(UINT32 pointerId, POINTER_INPUT_TYPE *pointerType);
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);
typedef BOOL
(WINAPI *setGestureConfig_t)(HWND hwnd, DWORD dwReserved, UINT cIDs, PGESTURECONFIG pGestureConfig, UINT cbSize);
typedef BOOL
(WINAPI *setWindowFeedbackSetting_t)(HWND hwnd, FEEDBACK_TYPE feedback, DWORD dwFlags, UINT32 size, const VOID *configuration);

struct _GdkDeviceManagerWin32WinpointerFuncs
{
  registerPointerDeviceNotifications_t registerPointerDeviceNotifications;
  getPointerDevices_t getPointerDevices;
  getPointerDeviceCursors_t getPointerDeviceCursors;
  getPointerDeviceRects_t getPointerDeviceRects;
  getPointerType_t getPointerType;
  getPointerCursorId_t getPointerCursorId;
  getPointerPenInfo_t getPointerPenInfo;
  getPointerTouchInfo_t getPointerTouchInfo;
  getPointerPenInfoHistory_t getPointerPenInfoHistory;
  getPointerTouchInfoHistory_t getPointerTouchInfoHistory;
  setGestureConfig_t setGestureConfig;
  setWindowFeedbackSetting_t setWindowFeedbackSetting;
};
typedef struct _GdkDeviceManagerWin32WinpointerFuncs GdkDeviceManagerWin32WinpointerFuncs;

#define WINPOINTER_API(dm,f) ((GdkDeviceManagerWin32WinpointerFuncs *)dm->winpointer_funcs)->f

static inline void
winpointer_ignore_interaction (GdkDeviceManagerWin32 *device_manager,
                               UINT32                 pointer_id)
{
  g_ptr_array_add (device_manager->ignored_interactions, GUINT_TO_POINTER (pointer_id));
}

static inline void
winpointer_remove_ignored_interaction (GdkDeviceManagerWin32 *device_manager,
                                       UINT32                 pointer_id)
{
  g_ptr_array_remove_fast (device_manager->ignored_interactions, GUINT_TO_POINTER (pointer_id));
}

static inline gboolean
winpointer_should_ignore_interaction (GdkDeviceManagerWin32 *device_manager,
                                      UINT32                 pointer_id)
{
  return g_ptr_array_find (device_manager->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 (GdkDeviceManagerWin32 *device_manager,
                                    HANDLE                 device_handle,
                                    UINT32                 cursor_id,
                                    GdkInputSource         input_source)
{
  for (GList *l = 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 (GdkDeviceManagerWin32 *device_manager,
                           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 (device_manager, 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;
  GdkDeviceManagerWin32 *device_manager = GDK_WIN32_DISPLAY (gdk_surface_get_display (surface))->device_manager;

  core_device = device_manager->core_pointer;

  if (!winpointer_get_event_type (device_manager, 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;
  /* Note that info->dwKeyStates is not reliable, use GetKeyState() */
  if (GetKeyState (VK_CONTROL) < 0)
    state |= GDK_CONTROL_MASK;
  if (GetKeyState (VK_SHIFT) < 0)
    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, 0sizeof (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;
  GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_surface_get_display (surface));
  GdkDeviceManagerWin32 *device_manager = display_win32->device_manager;

  if (!WINPOINTER_API (device_manager, getPointerType) (pointer_id, &type))
    {
      WIN32_API_FAILED_LOG_ONCE ("GetPointerType");
      return;
    }

  if (!WINPOINTER_API (device_manager, 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 (device_manager, 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 (!WINPOINTER_API (device_manager, 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 (device_manager, 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 (!WINPOINTER_API (device_manager, 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 (device_manager, 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,
                                 GdkWin32Display  *display_win32,
                                 guint32          *time)
{
  UINT32 pointer_id = GET_POINTERID_WPARAM (msg->wParam);
  POINTER_INPUT_TYPE type = PT_POINTER;
  UINT32 cursor_id = 0;
  GdkDeviceManagerWin32 *device_manager = display_win32->device_manager;

  if (!WINPOINTER_API (device_manager, getPointerType) (pointer_id, &type))
    {
      WIN32_API_FAILED_LOG_ONCE ("GetPointerType");
      return FALSE;
    }

  if (!WINPOINTER_API (device_manager, getPointerCursorId) (pointer_id, &cursor_id))
    {
      WIN32_API_FAILED_LOG_ONCE ("GetPointerCursorId");
      return FALSE;
    }

  switch (type)
    {
    case PT_PEN:
      {
        POINTER_PEN_INFO pen_info;

        if (!WINPOINTER_API (device_manager, getPointerPenInfo) (pointer_id, &pen_info))
          {
            WIN32_API_FAILED_LOG_ONCE ("GetPointerPenInfo");
            return FALSE;
          }

        *device = (GdkDevice*) winpointer_find_device_with_source (device_manager, 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 (!WINPOINTER_API (device_manager, getPointerTouchInfo) (pointer_id, &touch_info))
            {
              WIN32_API_FAILED_LOG_ONCE ("GetPointerTouchInfo");
              return FALSE;
            }

        *device = GDK_DEVICE (winpointer_find_device_with_source (device_manager,
                                                                  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 (GdkDeviceManagerWin32 *device_manager,
                                       MSG                   *msg)
{
  UINT32 pointer_id = GET_POINTERID_WPARAM (msg->wParam);
  POINTER_INPUT_TYPE type = PT_POINTER;

  if (!WINPOINTER_API (device_manager, getPointerType) (pointer_id, &type))
    {
      WIN32_API_FAILED_LOG_ONCE ("GetPointerType");
      return TRUE;
    }

  return !(type == PT_PEN || type == PT_TOUCH);
}

void
gdk_winpointer_interaction_ended (GdkDeviceManagerWin32 *device_manager,
                                  MSG                   *msg)
{
  winpointer_remove_ignored_interaction (device_manager, GET_POINTERID_WPARAM (msg->wParam));
}

static inline double
utils_rect_width (RECT *rect)
{
  return rect->right - rect->left;
}

static inline double
utils_rect_height (RECT *rect)
{
  return rect->bottom - rect->top;
}

static inline gboolean
utils_rect_is_degenerate (RECT *rect)
{
  return utils_rect_width (rect) == 0 || utils_rect_height (rect) == 0;
}

static gboolean
winpointer_device_update_scale_factors (GdkDeviceWinpointer   *device,
                                        GdkDeviceManagerWin32 *device_manager)
{
  RECT device_rect;
  RECT display_rect;

  if (!WINPOINTER_API (device_manager, getPointerDeviceRects) (device->device_handle, &device_rect,&nbsp;&display_rect))
    {
      WIN32_API_FAILED ("GetPointerDeviceRects");
      return FALSE;
    }

  if (utils_rect_is_degenerate (&device_rect))
    {
      g_warning ("Invalid coordinates from GetPointerDeviceRects");
      return FALSE;
    }

  device->origin_x = display_rect.left;
  device->origin_y = display_rect.top;
  device->scale_x = utils_rect_width (&display_rect) / utils_rect_width (&device_rect);
  device->scale_y = utils_rect_height (&display_rect) / utils_rect_height (&device_rect);

  return TRUE;
}

static void
winpointer_get_device_details (HANDLE device,
                               char *vid,
                               char *pid,
                               char **manufacturer,
                               char **product)
{
  RID_DEVICE_INFO info;
  UINT wchars_count = 0;
  UINT size = 0;

  memset (&info, 0sizeof (info));

  info.cbSize = sizeof (info);
  size = sizeof (info);

  if (GetRawInputDeviceInfoW (device, RIDI_DEVICEINFO, &info, &size) > 0 &&
      info.dwType == RIM_TYPEHID &&
      info.hid.dwVendorId > 0 &&
      info.hid.dwProductId > 0)
    {
      const char *format_string = "%0" G_STRINGIFY (VID_PID_CHARS) "x";

      g_snprintf (vid, VID_PID_CHARS + 1, format_string, (unsigned) info.hid.dwVendorId);
      g_snprintf (pid, VID_PID_CHARS + 1, format_string, (unsigned) info.hid.dwProductId);
    }

  if (GetRawInputDeviceInfoW (device, RIDI_DEVICENAME, NULL, &wchars_count) == 0)
    {
      gunichar2 *device_path = g_new0 (gunichar2, wchars_count);

      if (GetRawInputDeviceInfoW (device, RIDI_DEVICENAME, device_path, &wchars_count) > 0)
        {
          HANDLE device_file = CreateFileW (device_path,
                                            0,
                                            FILE_SHARE_READ |
                                            FILE_SHARE_WRITE |
                                            FILE_SHARE_DELETE,
                                            NULL,
                                            OPEN_EXISTING,
                                            FILE_FLAG_SESSION_AWARE,
                                            NULL);

          if (device_file != INVALID_HANDLE_VALUE)
            {
              gunichar2 *buffer = g_malloc0 (HID_STRING_BYTES_LIMIT);

              if (HidD_GetManufacturerString (device_file, buffer, HID_STRING_BYTES_LIMIT))
                if (buffer[0])
                  *manufacturer = g_utf16_to_utf8 (buffer, -1, NULL, NULL, NULL);

              if (HidD_GetProductString (device_file, buffer, HID_STRING_BYTES_LIMIT))
                if (buffer[0])
                  *product = g_utf16_to_utf8 (buffer, -1, NULL, NULL, NULL);

              g_free (buffer);
              CloseHandle (device_file);
            }
        }

      g_free (device_path);
    }
}

static void
winpointer_create_device (GdkDeviceManagerWin32 *device_manager,
                          POINTER_DEVICE_INFO   *info,
                          GdkInputSource         source)
{
  GdkDeviceWinpointer *device = NULL;
  GdkSeat *seat = NULL;
  unsigned num_touches = 0;
  char vid[VID_PID_CHARS + 1];
  char pid[VID_PID_CHARS + 1];
  char *manufacturer = NULL;
  char *product = NULL;
  char *base_name = NULL;
  char *name = NULL;
  UINT32 num_cursors = 0;
  GdkAxisFlags axes_flags = 0;

  seat = gdk_display_get_default_seat (device_manager->display);

  memset (pid, 0, VID_PID_CHARS + 1);
  memset (vid, 0, VID_PID_CHARS + 1);

  if (!WINPOINTER_API (device_manager, getPointerDeviceCursors) (info->device, &num_cursors, NULL))
    {
      WIN32_API_FAILED ("GetPointerDeviceCursors");
      return;
    }

  if (num_cursors == 0)
    return;

  winpointer_get_device_details (info->device, vid, pid, &manufacturer, &product);

  /* build up the name */
  if (!manufacturer && vid[0])
    manufacturer = g_strdup (vid);

  if (!product && pid[0])
    product = g_strdup (pid);

  if (manufacturer && product)
    base_name = g_strconcat (manufacturer, " ", product, NULL);

  if (!base_name && info->productString[0])
    base_name = g_utf16_to_utf8 (info->productString, -1, NULL, NULL, NULL);

  if (!base_name)
    base_name = g_strdup ("Unnamed");

  switch (source)
    {
    case GDK_SOURCE_PEN:
      name = g_strconcat (base_name, " Pen", NULL);
    break;

    case GDK_SOURCE_TOUCHSCREEN:
      num_touches = info->maxActiveContacts;
      name = g_strconcat (base_name, " Finger touch", NULL);
    break;

    default:
      name = g_strdup (base_name);
    break;
    }

  device = g_object_new (GDK_TYPE_DEVICE_WINPOINTER,
                         "display", device_manager->display,
                         "seat", seat,
                         "has-cursor"TRUE,
                         "source", source,
                         "name", name,
                         "num-touches", num_touches,
                         "vendor-id", vid[0] ? vid : NULL,
                         "product-id", pid[0] ? pid : NULL,
                         NULL);

  switch (source)
    {
    case GDK_SOURCE_PEN:
      _gdk_device_add_axis (GDK_DEVICE (device), GDK_AXIS_PRESSURE, 0.01.01.0 / 1024.0);
      axes_flags |= GDK_AXIS_FLAG_PRESSURE;

      _gdk_device_add_axis (GDK_DEVICE (device), GDK_AXIS_XTILT, -1.01.01.0 / 90.0);
      axes_flags |= GDK_AXIS_FLAG_XTILT;

      _gdk_device_add_axis (GDK_DEVICE (device), GDK_AXIS_YTILT, -1.01.01.0 / 90.0);
      axes_flags |= GDK_AXIS_FLAG_YTILT;

      _gdk_device_add_axis (GDK_DEVICE (device), GDK_AXIS_ROTATION, 0.01.01.0 / 360.0);
      axes_flags |= GDK_AXIS_FLAG_ROTATION;
    break;

    case GDK_SOURCE_TOUCHSCREEN:
      _gdk_device_add_axis (GDK_DEVICE (device), GDK_AXIS_PRESSURE, 0.01.01.0 / 1024.0);
      axes_flags |= GDK_AXIS_FLAG_PRESSURE;
    break;

    default:
      g_warn_if_reached ();
    break;
    }

  device->device_handle = info->device;
  device->start_cursor_id = info->startingCursorId;
  device->end_cursor_id = info->startingCursorId + num_cursors - 1;

  if (!winpointer_device_update_scale_factors (device, device_manager))
    {
      g_set_object (&device, NULL);
      goto cleanup;
    }

  switch (source)
    {
    case GDK_SOURCE_PEN:
      {
        device->tool_pen = gdk_device_tool_new (00, GDK_DEVICE_TOOL_TYPE_PEN, axes_flags);
        gdk_win32_seat_add_tool (GDK_WIN32_SEAT (seat), device->tool_pen);

        device->tool_eraser = gdk_device_tool_new (00, GDK_DEVICE_TOOL_TYPE_ERASER, axes_flags);
        gdk_win32_seat_add_tool (GDK_WIN32_SEAT (seat), device->tool_eraser);
      }
    break;
    case GDK_SOURCE_TOUCHSCREEN:
    break;
    default:
      g_warn_if_reached ();
    break;
    }

  device_manager->winpointer_devices = g_list_append (device_manager->winpointer_devices, device);

  _gdk_device_set_associated_device (GDK_DEVICE (device), device_manager->core_pointer);
  _gdk_device_add_physical_device (device_manager->core_pointer, GDK_DEVICE (device));

  gdk_win32_seat_add_physical_device (GDK_WIN32_SEAT (seat), GDK_DEVICE (device));

cleanup:
  g_free (name);
  g_free (base_name);
  g_free (product);
  g_free (manufacturer);
}

static void
winpointer_create_devices (GdkDeviceManagerWin32 *device_manager,
                           POINTER_DEVICE_INFO   *info)
{
  switch (info->pointerDeviceType)
    {
    case POINTER_DEVICE_TYPE_INTEGRATED_PEN:
    case POINTER_DEVICE_TYPE_EXTERNAL_PEN:
      winpointer_create_device (device_manager, info, GDK_SOURCE_PEN);
    break;
    case POINTER_DEVICE_TYPE_TOUCH:
      winpointer_create_device (device_manager, info, GDK_SOURCE_TOUCHSCREEN);
    break;
    default:
      g_warn_if_reached ();
    break;
    }
}

static gboolean
winpointer_find_device_in_system_list (GdkDeviceWinpointer *device,
                                       POINTER_DEVICE_INFO *infos,
                                       UINT32 infos_count)
{
  for (UINT32 i = 0; i < infos_count; i++)
    {
      if (device->device_handle == infos[i].device &&
          device->start_cursor_id == infos[i].startingCursorId)
        {
          return TRUE;
        }
    }

  return FALSE;
}

static gboolean
winpointer_find_system_device_in_device_manager (GdkDeviceManagerWin32 *device_manager,
                                                 POINTER_DEVICE_INFO   *info)
{
  for (GList *l = device_manager->winpointer_devices; l != NULL; l = l->next)
    {
      GdkDeviceWinpointer *device = GDK_DEVICE_WINPOINTER (l->data);

      if (device->device_handle == info->device &&
          device->start_cursor_id == info->startingCursorId)
        {
          return TRUE;
        }
    }

  return FALSE;
}

static void
winpointer_enumerate_devices (GdkDeviceManagerWin32 *device_manager)
{
  POINTER_DEVICE_INFO *infos = NULL;
  UINT32 infos_count = 0;
  UINT32 i = 0;
  GList *current = NULL;

  do
    {
      infos = g_new0 (POINTER_DEVICE_INFO, infos_count);
      if (!WINPOINTER_API (device_manager, getPointerDevices) (&infos_count, infos))
        {
          WIN32_API_FAILED ("GetPointerDevices");
          g_free (infos);
          return;
        }
    }
  while (infos_count > 0 && !infos);

  current = device_manager->winpointer_devices;

  while (current != NULL)
    {
      GdkDeviceWinpointer *device = GDK_DEVICE_WINPOINTER (current->data);
      GList *next = current->next;

      if (!winpointer_find_device_in_system_list (device, infos, infos_count))
        {
          GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (device));

          device_manager->winpointer_devices = g_list_delete_link (device_manager->winpointer_devices,
                                                                        current);

          gdk_device_update_tool (GDK_DEVICE (device), NULL);

          if (device->tool_pen)
            gdk_win32_seat_remove_tool (GDK_WIN32_SEAT (seat), device->tool_pen);

          if (device->tool_eraser)
            gdk_win32_seat_remove_tool (GDK_WIN32_SEAT (seat), device->tool_eraser);

          _gdk_device_set_associated_device (GDK_DEVICE (device), NULL);
          _gdk_device_remove_physical_device (device_manager->core_pointer, GDK_DEVICE (device));

          gdk_win32_seat_remove_physical_device (GDK_WIN32_SEAT (seat), GDK_DEVICE (device));

          g_object_unref (device);
        }
      else
        {
          winpointer_device_update_scale_factors (device, device_manager);
        }

      current = next;
    }

  /* create new gdk devices */
  for (i = 0; i < infos_count; i++)
    {
      if (!winpointer_find_system_device_in_device_manager (device_manager, &infos[i]))
        {
          winpointer_create_devices (device_manager, &infos[i]);
        }
    }

  g_free (infos);
}

static LRESULT CALLBACK
winpointer_notifications_window_procedure (HWND hWnd,
                                           UINT uMsg,
                                           WPARAM wParam,
                                           LPARAM lParam)
{
  GdkDeviceManagerWin32 *device_manager;
  CREATESTRUCT *cs = NULL;

  switch (uMsg)
    {
    case WM_NCCREATE:
      cs = (CREATESTRUCT *)lParam;
      device_manager = cs->lpCreateParams;
      SetWindowLongPtr (hWnd, GWLP_USERDATA, (LONG_PTR)device_manager);
      return TRUE;
    case WM_POINTERDEVICECHANGE:
      device_manager = (GdkDeviceManagerWin32 *) GetWindowLongPtr (hWnd, GWLP_USERDATA);
      winpointer_enumerate_devices (device_manager);
      return 0;
    }

  return DefWindowProcW (hWnd, uMsg, wParam, lParam);
}

static HWND
winpointer_notif_window_create (GdkDeviceManagerWin32 *device_manager)
{
  WNDCLASSEXW wndclassex;
  ATOM notifications_window_class;
  HWND notification_window_hwnd = NULL;

  memset (&wndclassex, 0sizeof (wndclassex));
  wndclassex.cbSize = sizeof (wndclassex);
  wndclassex.lpszClassName = L"GdkWin32WinpointerNotificationsWindowClass";
  wndclassex.lpfnWndProc = winpointer_notifications_window_procedure;
  wndclassex.hInstance = this_module ();

  notifications_window_class = RegisterClassExW (&wndclassex);

  if (notifications_window_class != 0)
    {
      notification_window_hwnd = CreateWindowExW (0,
                                                  (LPCWSTR)(guintptr)notifications_window_class,
                                                  L"GdkWin32 Winpointer Notifications",
                                                  0,
                                                  0000,
                                                  HWND_MESSAGE,
                                                  NULL,
                                                  this_module (),
                                                  device_manager);

      if (notification_window_hwnd == NULL)
        WIN32_API_FAILED ("CreateWindowExW");
    }
  else
    WIN32_API_FAILED ("RegisterClassExW");

  return notification_window_hwnd;
}

static gboolean
winpointer_ensure_procedures (GdkDeviceManagerWin32 *device_manager)
{
  GdkDeviceManagerWin32WinpointerFuncs *funcs = NULL;
  static gsize user32_dll_checked = 0;

  if (g_once_init_enter (&user32_dll_checked))
    {
      HMODULE user32_dll = NULL;

      user32_dll = LoadLibraryW (L"user32.dll");
      if (user32_dll)
        {
          funcs = g_new0 (GdkDeviceManagerWin32WinpointerFuncs, 1);

          funcs->registerPointerDeviceNotifications = (registerPointerDeviceNotifications_t)
            GetProcAddress (user32_dll, "RegisterPointerDeviceNotifications");
          funcs->getPointerDevices = (getPointerDevices_t)
            GetProcAddress (user32_dll, "GetPointerDevices");
          funcs->getPointerDeviceCursors = (getPointerDeviceCursors_t)
            GetProcAddress (user32_dll, "GetPointerDeviceCursors");
          funcs->getPointerDeviceRects = (getPointerDeviceRects_t)
            GetProcAddress (user32_dll, "GetPointerDeviceRects");
          funcs->getPointerType = (getPointerType_t)
            GetProcAddress (user32_dll, "GetPointerType");
          funcs->getPointerCursorId = (getPointerCursorId_t)
            GetProcAddress (user32_dll, "GetPointerCursorId");
          funcs->getPointerPenInfo = (getPointerPenInfo_t)
            GetProcAddress (user32_dll, "GetPointerPenInfo");
          funcs->getPointerTouchInfo = (getPointerTouchInfo_t)
            GetProcAddress (user32_dll, "GetPointerTouchInfo");
          funcs->getPointerPenInfoHistory = (getPointerPenInfoHistory_t)
            GetProcAddress (user32_dll, "GetPointerPenInfoHistory");
          funcs->getPointerTouchInfoHistory = (getPointerTouchInfoHistory_t)
            GetProcAddress (user32_dll, "GetPointerTouchInfoHistory");
          funcs->setGestureConfig = (setGestureConfig_t)
            GetProcAddress (user32_dll, "SetGestureConfig");
          funcs->setWindowFeedbackSetting = (setWindowFeedbackSetting_t)
            GetProcAddress (user32_dll, "SetWindowFeedbackSetting");

          if (funcs->registerPointerDeviceNotifications &&
              funcs->getPointerDevices &&
              funcs->getPointerDeviceCursors &&
              funcs->getPointerDeviceRects &&
              funcs->getPointerType &&
              funcs->getPointerCursorId &&
              funcs->getPointerPenInfo &&
              funcs->getPointerTouchInfo &&
              funcs->getPointerPenInfoHistory &&
              funcs->getPointerTouchInfoHistory)
            device_manager->winpointer_funcs = funcs;
        }
      else
        WIN32_API_FAILED ("LoadLibraryW");

      g_once_init_leave (&user32_dll_checked, 1);
    }

  return (device_manager->winpointer_funcs != NULL);
}

gboolean
gdk_winpointer_initialize (GdkDeviceManagerWin32 *device_manager)
{
  HWND notification_hwnd = NULL;
  if (!winpointer_ensure_procedures (device_manager))
    return FALSE;

  notification_hwnd = winpointer_notif_window_create (device_manager);
  if (notification_hwnd == NULL)
    return FALSE;

  if (!WINPOINTER_API (device_manager, registerPointerDeviceNotifications) (notification_hwnd, FALSE))
    {
      WIN32_API_FAILED ("RegisterPointerDeviceNotifications");
      return FALSE;
    }

  device_manager->winpointer_notification_hwnd = notification_hwnd;
  device_manager->ignored_interactions = g_ptr_array_new ();

  winpointer_enumerate_devices (device_manager);

  return TRUE;
}

#ifndef MICROSOFT_TABLETPENSERVICE_PROPERTY
#define MICROSOFT_TABLETPENSERVICE_PROPERTY \
_T("MicrosoftTabletPenServiceProperty")
#endif

void
gdk_winpointer_initialize_surface (GdkSurface *surface)
{
  HWND hwnd = GDK_SURFACE_HWND (surface);
  ATOM key = 0;
  HANDLE val = (HANDLE)(TABLET_DISABLE_PRESSANDHOLD |
                        TABLET_DISABLE_PENTAPFEEDBACK |
                        TABLET_DISABLE_PENBARRELFEEDBACK |
                        TABLET_DISABLE_FLICKS |
                        TABLET_DISABLE_FLICKFALLBACKKEYS);

  GdkDeviceManagerWin32 *device_manager = GDK_WIN32_DISPLAY (gdk_surface_get_display (surface))->device_manager;
  winpointer_ensure_procedures (device_manager);

  key = GlobalAddAtom (MICROSOFT_TABLETPENSERVICE_PROPERTY);
  API_CALL (SetPropW, (hwnd, (LPCWSTR)(guintptr)key, val));
  GlobalDeleteAtom (key);

  if (WINPOINTER_API (device_manager, setGestureConfig) != NULL)
    {
      GESTURECONFIG gesture_config;
      memset (&gesture_config, 0sizeof (gesture_config));

      gesture_config.dwID = 0;
      gesture_config.dwWant = 0;
      gesture_config.dwBlock = GC_ALLGESTURES;

      API_CALL (WINPOINTER_API (device_manager,setGestureConfig), (hwnd, 01, &gesture_config, sizeof (gesture_config)));
    }

  if (WINPOINTER_API (device_manager, setWindowFeedbackSetting) != NULL)
    {
      FEEDBACK_TYPE feedbacks[] = {
        FEEDBACK_TOUCH_CONTACTVISUALIZATION,
        FEEDBACK_PEN_BARRELVISUALIZATION,
        FEEDBACK_PEN_TAP,
        FEEDBACK_PEN_DOUBLETAP,
        FEEDBACK_PEN_PRESSANDHOLD,
        FEEDBACK_PEN_RIGHTTAP,
        FEEDBACK_TOUCH_TAP,
        FEEDBACK_TOUCH_DOUBLETAP,
        FEEDBACK_TOUCH_PRESSANDHOLD,
        FEEDBACK_TOUCH_RIGHTTAP,
        FEEDBACK_GESTURE_PRESSANDTAP
      };
      gsize i = 0;

      for (i = 0; i < G_N_ELEMENTS (feedbacks); i++)
        {
          BOOL setting = FALSE;

          API_CALL (WINPOINTER_API (device_manager, setWindowFeedbackSetting), (hwnd, feedbacks[i], 0sizeof (BOOL), &setting));
        }
    }
}

void
gdk_winpointer_finalize_surface (GdkSurface *surface)
{
  HWND hwnd = GDK_SURFACE_HWND (surface);
  ATOM key = 0;

  key = GlobalAddAtom (MICROSOFT_TABLETPENSERVICE_PROPERTY);
  RemovePropW (hwnd, (LPCWSTR)(guintptr)key);
  GlobalDeleteAtom (key);
}

Messung V0.5 in Prozent
C=100 H=93 G=96

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet am  2026-07-03) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik