From c88d3701366d1681b02f33264760b59b02f4d8b6 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Thu, 31 Oct 2024 02:02:09 +0100 Subject: [PATCH] Implement Windows multitouch support --- libs/tk/ydk/win32/gdkevents-win32.c | 111 ++++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 13 deletions(-) diff --git a/libs/tk/ydk/win32/gdkevents-win32.c b/libs/tk/ydk/win32/gdkevents-win32.c index 9903418511..8dbbfecf99 100644 --- a/libs/tk/ydk/win32/gdkevents-win32.c +++ b/libs/tk/ydk/win32/gdkevents-win32.c @@ -168,6 +168,11 @@ static gboolean gdk_event_dispatch (GSource *source, static GList *client_filters; /* Filters for client messages */ +static GList *touch_mapper = NULL; + +static int last_touch_x[32]; +static int last_touch_y[32]; + static HCURSOR p_grab_cursor; static GSourceFuncs event_funcs = { @@ -231,6 +236,40 @@ track_mouse_event (DWORD dwFlags, GDK_NOTE (EVENTS, g_print(" (cancel TrackMouseEvent %p)", hwnd)); } +static int +touch_idx_lookup (DWORD id) +{ + GList* g = g_list_find (touch_mapper, GUINT_TO_POINTER(id)); + if (!g) { + return -1; + } + return g_list_position (touch_mapper, g); +} + +static int +touch_idx_map (DWORD id) +{ + GList* g = g_list_find (touch_mapper, GUINT_TO_POINTER(G_MAXUINT)); + if (!g) { + touch_mapper = g_list_append (touch_mapper, GUINT_TO_POINTER(id)); + } else { + g->data = GUINT_TO_POINTER(id); + } + return touch_idx_lookup (id); +} + +static int +touch_idx_unmap (DWORD id) +{ + GList* g = g_list_find (touch_mapper, GUINT_TO_POINTER(id)); + if (!g) { + return -1; + } + int rv = g_list_position (touch_mapper, g); + g->data = GUINT_TO_POINTER(G_MAXULONG); + return rv; +} + gulong _gdk_win32_get_next_tick (gulong suggested_tick) { @@ -2021,24 +2060,75 @@ handle_wm_pointer (GdkEventType type, GdkWindow* window, MSG* msg) POINTER_TOUCH_INFO touch_info; if (!getPointerTouchInfo (GET_POINTERID_WPARAM (msg->wParam), &touch_info)) { - printf ("getPointerTouchInfo failed to translate event\n"); + printf ("getPointerTouchInfo failed to translate event\n"); return FALSE; } + /* Touch positions are in screen coordinates, convert + * them to Window coordidates + */ + POINT point; + point.x = GET_X_LPARAM (msg->lParam); + point.y = GET_Y_LPARAM (msg->lParam); + + int touch_sequence = 0; + switch (type) + { + case GDK_TOUCH_BEGIN: + touch_sequence = touch_idx_map (GET_POINTERID_WPARAM (msg->wParam)); + break; + case GDK_TOUCH_END: + touch_sequence = touch_idx_unmap (GET_POINTERID_WPARAM (msg->wParam)); + break; + case GDK_TOUCH_UPDATE: + touch_sequence = touch_idx_lookup (GET_POINTERID_WPARAM (msg->wParam)); + break; + default: + return FALSE; + } + + // printf ("TOUCH %d SEQ %d %x | %d = %d | %d = %d\n", type, touch_sequence, GET_POINTERID_WPARAM (msg->wParam), (int)point.x, last_touch_x[touch_sequence], (int)point.y, last_touch_y[touch_sequence]); + + /* Dear Aliens, we're sorry to limit multitouch to 30 fingers */ + if (touch_sequence < 0 || touch_sequence > 31) + { + return FALSE; + } + + + /* Windows periodically sends WM_POINTERUPDATE updates. + * If a finger has not moved, do not create a GDK event. + */ + if (type == GDK_TOUCH_UPDATE + && (int)point.x == last_touch_x[touch_sequence] + && (int)point.y == last_touch_y[touch_sequence]) + { + return FALSE; + } + + last_touch_x[touch_sequence] = (int)point.x; + last_touch_y[touch_sequence] = (int)point.y; + + /* first single touch is already handled by Windows as mouse event */ + if (touch_sequence == 0) { + return TRUE; + } + + ScreenToClient (msg->hwnd, &point); GdkEvent *event = gdk_event_new (type); event->touch.window = window; event->touch.time = _gdk_win32_get_next_tick (msg->time); - event->touch.x = (gint16) GET_X_LPARAM (msg->lParam); - event->touch.y = (gint16) GET_Y_LPARAM (msg->lParam); + event->touch.x = (gint16) point.x; + event->touch.y = (gint16) point.y; event->touch.x_root = msg->pt.x + _gdk_offset_x; event->touch.y_root = msg->pt.y + _gdk_offset_y; event->touch.state = 0; - event->touch.sequence = GET_POINTERID_WPARAM (msg->wParam); // XXX ? - event->touch.flags = 0; // XXX - event->touch.deviceid = 0; // XXX + event->touch.sequence = GET_POINTERID_WPARAM (msg->wParam); // or touch_sequence + 1 + event->touch.flags = 0; // touch_sequence == 0 ? 0x20000 : 0; + event->touch.deviceid = 0; - printf ("getPointerTouchInfo at: %.1fx%.1f root: %1.fx%1.f\n", event->touch.x, event->touch.y, event->touch.x_root, event->touch.y_root); + printf ("getPointerTouchInfo type = %d at: %.1fx%.1f root: %1.fx%1.f seq=%d\n", type, event->touch.x, event->touch.y, event->touch.x_root, event->touch.y_root, touch_sequence); _gdk_win32_append_event (event); } @@ -2810,17 +2900,12 @@ gdk_event_translate (MSG *msg, break; case 0x0246 /* WM_POINTERDOWN */: - printf ("Event WM_POINTERDOWN\n"); - if (!handle_wm_pointer (GDK_TOUCH_BEGIN, window, msg)) { - // XXX -> generate_button_event ? - } + handle_wm_pointer (GDK_TOUCH_BEGIN, window, msg); break; case 0x0247 /* WM_POINTERUP */: - printf ("Event WM_POINTERUP\n"); handle_wm_pointer (GDK_TOUCH_END, window, msg); break; case 0x0245 /* WM_POINTERUPDATE */: - printf ("Event WM_POINTERUPDATE\n"); handle_wm_pointer (GDK_TOUCH_UPDATE, window, msg); break;