From: Luca Bacci Date: Fri, 9 Jul 2021 13:17:17 +0000 (+0200) Subject: Handle WinPointer input X-Git-Tag: archive/raspbian/4.4.1+ds1-2+rpi1^2~18^2~1^2~6^2~6 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=68db945e477a95d63edf2047217edb49dad669ae;p=gtk4.git Handle WinPointer input --- 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 @@ -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