diff -ur gtk+-3.22.5.orig/gdk/win32/gdkdevicemanager-win32.c gtk+-3.22.5.windows_multitouch/gdk/win32/gdkdevicemanager-win32.c --- gtk+-3.22.5.orig/gdk/win32/gdkdevicemanager-win32.c 2016-11-23 16:02:35.000000000 -0800 +++ gtk+-3.22.5.windows_multitouch/gdk/win32/gdkdevicemanager-win32.c 2016-12-28 19:44:39.819131975 -0800 @@ -88,6 +88,43 @@ } static GdkDevice * +create_touchscreen(GdkDeviceManagerWin32 *device_manager, + GType g_type, + const char *name, + GdkDeviceType type) +{ + GdkDevice *device; + device = g_object_new (g_type, + "name", name, + "type", type, + "input-source", GDK_SOURCE_TOUCHSCREEN, + "input-mode", GDK_MODE_DISABLED, + "has-cursor", FALSE, + "display", gdk_device_manager_get_display (device_manager), + "device-manager", device_manager, + "num-touches", 10, + NULL); + // todo: find a way to query Windows touchscreen specs - these are captured from the Wacom Linux driver + _gdk_device_add_axis (GDK_DEVICE (device), + GDK_NONE, + GDK_AXIS_X, + 0, + 12372, + 40000); + _gdk_device_add_axis (GDK_DEVICE (device), + GDK_NONE, + GDK_AXIS_Y, + 0, + 6960, + 40000); + + _gdk_device_set_associated_device (device, device_manager->core_pointer); + _gdk_device_add_slave (device_manager->core_pointer, device); + + return device; +} + +static GdkDevice * create_keyboard (GdkDeviceManager *device_manager, GType g_type, const char *name, @@ -572,7 +609,7 @@ device = g_object_new (GDK_TYPE_DEVICE_WINTAB, "name", device_name, - "type", GDK_DEVICE_TYPE_FLOATING, + "type", GDK_DEVICE_TYPE_SLAVE, "input-source", GDK_SOURCE_PEN, "input-mode", GDK_MODE_SCREEN, "has-cursor", lc.lcOptions & CXO_SYSTEM, @@ -583,8 +620,11 @@ device->sends_core = lc.lcOptions & CXO_SYSTEM; if (device->sends_core) { - _gdk_device_set_associated_device (device_manager->system_pointer, GDK_DEVICE (device)); + _gdk_device_set_associated_device(GDK_DEVICE(device), device_manager->core_pointer); _gdk_device_add_slave (device_manager->core_pointer, GDK_DEVICE (device)); + GdkSeat *seat = gdk_display_get_default_seat(display); + gdk_seat_default_add_slave(GDK_SEAT_DEFAULT(seat), GDK_DEVICE(device)); + } g_free (csrname_utf8); @@ -725,6 +765,12 @@ GDK_TYPE_DEVICE_WIN32, "System Aggregated Pointer", GDK_DEVICE_TYPE_SLAVE); + + device_manager->touchscreen = create_touchscreen(device_manager, + GDK_TYPE_DEVICE_WIN32, + "touchscreen", + GDK_DEVICE_TYPE_SLAVE); + _gdk_device_virtual_set_active (device_manager->core_pointer, device_manager->system_pointer); _gdk_device_set_associated_device (device_manager->system_pointer, device_manager->core_pointer); @@ -753,6 +799,8 @@ gdk_display_add_seat (gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object)), seat); gdk_seat_default_add_slave (GDK_SEAT_DEFAULT (seat), device_manager->system_pointer); gdk_seat_default_add_slave (GDK_SEAT_DEFAULT (seat), device_manager->system_keyboard); + gdk_seat_default_add_slave (GDK_SEAT_DEFAULT (seat), device_manager->touchscreen); + g_object_unref (seat); /* Only call Wintab init stuff after the default display diff -ur gtk+-3.22.5.orig/gdk/win32/gdkdevicemanager-win32.h gtk+-3.22.5.windows_multitouch/gdk/win32/gdkdevicemanager-win32.h --- gtk+-3.22.5.orig/gdk/win32/gdkdevicemanager-win32.h 2016-10-21 21:14:45.000000000 -0700 +++ gtk+-3.22.5.windows_multitouch/gdk/win32/gdkdevicemanager-win32.h 2016-12-28 17:33:36.153202049 -0800 @@ -41,6 +41,7 @@ /* Fake slave devices */ GdkDevice *system_pointer; GdkDevice *system_keyboard; + GdkDevice *touchscreen; GList *wintab_devices; }; diff -ur gtk+-3.22.5.orig/gdk/win32/gdkevents-win32.c gtk+-3.22.5.windows_multitouch/gdk/win32/gdkevents-win32.c --- gtk+-3.22.5.orig/gdk/win32/gdkevents-win32.c 2016-11-28 11:41:14.000000000 -0800 +++ gtk+-3.22.5.windows_multitouch/gdk/win32/gdkevents-win32.c 2016-12-28 19:21:37.362071638 -0800 @@ -2068,6 +2068,87 @@ return TRUE; } +#define MOUSEEVENTF_FROMTOUCH 0xff515700 + +gboolean +gdk_input_touch_event (GdkDisplay *display, + MSG *msg, + GdkWindow *window) +{ + GdkDeviceManagerWin32 *device_manager; + device_manager = GDK_DEVICE_MANAGER_WIN32 (gdk_display_get_device_manager (display)); + + const int MAX_TOUCH_INPUTS = 16; + TOUCHINPUT points[MAX_TOUCH_INPUTS]; + int pointCount = MIN(msg->wParam, MAX_TOUCH_INPUTS); + if (GetTouchInputInfo(msg->lParam, pointCount, points, sizeof(TOUCHINPUT))) + { + for (int i = 0; i < pointCount; ++i) + { + TOUCHINPUT *p = &points[i]; + if (p->dwFlags & (TOUCHEVENTF_PEN | TOUCHEVENTF_PALM)) + continue; + + GdkEventType type; + // can there ever be a combined UP & DOWN event? + if (p->dwFlags & TOUCHEVENTF_DOWN) + type = GDK_TOUCH_BEGIN; + else if (p->dwFlags & TOUCHEVENTF_UP) + type = GDK_TOUCH_END; + else + type = GDK_TOUCH_UPDATE; + + GdkEvent *event = gdk_event_new(type); + GdkEventTouch *_event = &event->touch; + + static int activeTouches; + static unsigned emulationSequence; + if (_event->type == GDK_TOUCH_BEGIN) + { + if (activeTouches == 0) + emulationSequence = p->dwID; + ++activeTouches; + } + else if (_event->type == GDK_TOUCH_END) + { + --activeTouches; + } + _event->time = p->dwTime; + _event->window = window; + _event->state = _event->type == GDK_TOUCH_END ? 0 : GDK_BUTTON1_MASK; + + _event->send_event = FALSE; + GdkDevice *device = device_manager->core_pointer; + gdk_event_set_source_device(event, device_manager->touchscreen); + gdk_event_set_device(event, device); + + gdk_event_set_seat(event, gdk_device_get_seat (device)); + + _event->x_root = p->x * 0.01; + _event->y_root = p->y * 0.01; + + POINT temp = {lrint(_event->x_root), lrint(_event->y_root)}; + ScreenToClient(msg->hwnd, &temp); + + _event->x = temp.x; + _event->y = temp.y; + + _event->axes = g_new0(gdouble, 2); + _event->axes[0] = temp.x; // screen relative + _event->axes[1] = temp.y; + + _event->sequence = GUINT_TO_POINTER(p->dwID); + + _event->emulating_pointer = emulationSequence == p->dwID; + if (_event->emulating_pointer) + gdk_event_set_pointer_emulated(event, TRUE); + _gdk_win32_append_event(event); + } + } + CloseTouchInputHandle(msg->lParam); + return TRUE; +} + #define GDK_ANY_BUTTON_MASK (GDK_BUTTON1_MASK | \ GDK_BUTTON2_MASK | \ GDK_BUTTON3_MASK | \ @@ -2638,6 +2719,9 @@ button = 5; buttondown0: + // ignore emulated touch events - GTK handles this in gtk_widget_real_touch_event() + if ((GetMessageExtraInfo() & 0xffffff00) == MOUSEEVENTF_FROMTOUCH) + break; GDK_NOTE (EVENTS, g_print (" (%d,%d)", GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam))); @@ -2677,6 +2761,9 @@ button = 5; buttonup0: + // ignore emulated touch events - GTK handles this in gtk_widget_real_touch_event() + if ((GetMessageExtraInfo() & 0xffffff00) == MOUSEEVENTF_FROMTOUCH) + break; GDK_NOTE (EVENTS, g_print (" (%d,%d)", GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam))); @@ -2732,6 +2819,9 @@ break; case WM_MOUSEMOVE: + // ignore emulated touch events - GTK handles this in gtk_widget_real_touch_event() + if ((GetMessageExtraInfo() & 0xffffff00) == MOUSEEVENTF_FROMTOUCH) + break; GDK_NOTE (EVENTS, g_print (" %p (%d,%d)", (gpointer) msg->wParam, @@ -3725,6 +3815,9 @@ gdk_event_free (event); break; + case WM_TOUCH: + gdk_input_touch_event(display, msg, window); + break; } done: diff -ur gtk+-3.22.5.orig/gdk/win32/gdkprivate-win32.h gtk+-3.22.5.windows_multitouch/gdk/win32/gdkprivate-win32.h --- gtk+-3.22.5.orig/gdk/win32/gdkprivate-win32.h 2016-11-23 16:02:35.000000000 -0800 +++ gtk+-3.22.5.windows_multitouch/gdk/win32/gdkprivate-win32.h 2016-12-28 17:33:36.185201573 -0800 @@ -27,7 +27,7 @@ #ifndef WINVER /* Vista or newer */ -#define WINVER 0x0600 +#define WINVER 0x0601 #endif #ifndef _WIN32_WINNT diff -ur gtk+-3.22.5.orig/gdk/win32/gdkwindow-win32.c gtk+-3.22.5.windows_multitouch/gdk/win32/gdkwindow-win32.c --- gtk+-3.22.5.orig/gdk/win32/gdkwindow-win32.c 2016-11-23 16:02:35.000000000 -0800 +++ gtk+-3.22.5.windows_multitouch/gdk/win32/gdkwindow-win32.c 2016-12-28 19:23:44.339867825 -0800 @@ -960,6 +960,11 @@ if (attributes_mask & GDK_WA_CURSOR) gdk_window_set_cursor (window, attributes->cursor); + if (event_mask & GDK_TOUCH_MASK) + { + gboolean pass = RegisterTouchWindow(hwndNew, 0); + g_return_if_fail(pass); + } _gdk_win32_window_enable_transparency (window); } diff -ur gtk+-3.22.5.orig/tests/testinput.c gtk+-3.22.5.windows_multitouch/tests/testinput.c --- gtk+-3.22.5.orig/tests/testinput.c 2016-11-23 16:02:36.000000000 -0800 +++ gtk+-3.22.5.windows_multitouch/tests/testinput.c 2016-12-28 18:10:27.367194333 -0800 @@ -23,6 +23,7 @@ */ #include "config.h" +#include #include #include "gtk/gtk.h" #include @@ -265,6 +266,14 @@ return TRUE; } +static gint +touch_event (GtkWidget *widget, GdkEventTouch *event) +{ + // Microsoft printf doesn't recognize %z for sequence, so cast to ll + g_printf("touch type=%d seq=%llu ev=(%f %f) axes=(%f %f) state=%x emu=%d\n", event->type, (uint64_t)event->sequence, event->x, event->y, event->axes[0], event->axes[1], event->state, event->emulating_pointer); + return FALSE; // return false so that default handler, gtk_widget_real_touch_event() is called. If not called, then touch events won't get translated to emulated mouse events +} + /* We track the next two events to know when we need to draw a cursor */ @@ -345,13 +354,16 @@ G_CALLBACK (leave_notify_event), NULL); g_signal_connect (drawing_area, "proximity_out_event", G_CALLBACK (proximity_out_event), NULL); + g_signal_connect (drawing_area, "touch_event", + G_CALLBACK(touch_event), NULL); event_mask = GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK | GDK_POINTER_MOTION_MASK | - GDK_PROXIMITY_OUT_MASK; + GDK_PROXIMITY_OUT_MASK | + GDK_TOUCH_MASK; gtk_widget_set_events (drawing_area, event_mask);