From a807a2d02bf2ce2f45dfffa2380ff8bc416474f4 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sun, 9 Jun 2024 20:40:17 +0800 Subject: [PATCH] Amend last change * lisp/loadup.el: Load touch-screen.el on MS-Windows. * src/w32fns.c (Emacs_GESTURECONFIG): New structure. (SetGestureConfig_fn): New variable. (w32_createwindow): Disable emulated mouse and gesture events for the frame's window. (w32_wnd_proc) : Ignore mouse events which are marked as emulated pointer events. (globals_of_w32fns): Load SetGestureConfig from user32.dll. * src/w32term.c (w32_read_socket): Correct utilization of GetTouchInputInfo, coordinate spaces, &c. (cherry picked from commit 588a8439e0919b0b9fede908a55200bb790e6de3) --- lisp/loadup.el | 3 +- src/w32fns.c | 47 +++++++++++++++++++++++++- src/w32term.c | 90 +++++++++++++++++++++++++++++++++++++------------- 3 files changed, 115 insertions(+), 25 deletions(-) diff --git a/lisp/loadup.el b/lisp/loadup.el index eea87d4b940..229956571fe 100644 --- a/lisp/loadup.el +++ b/lisp/loadup.el @@ -344,7 +344,8 @@ (when (eq system-type 'windows-nt) (load "w32-fns") (load "ls-lisp") - (load "dos-w32")))) + (load "dos-w32")) + (load "touch-screen"))) (if (eq system-type 'ms-dos) (progn (load "dos-w32") diff --git a/src/w32fns.c b/src/w32fns.c index 4437c1fb2b5..062ed0f5ef2 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -218,6 +218,19 @@ typedef BOOL (WINAPI * WTSUnRegisterSessionNotification_Proc) (HWND hwnd); typedef BOOL (WINAPI * RegisterTouchWindow_proc) (HWND, ULONG); +/* Types for gesture recognition are documented by Microsoft but appear + not to be defined anywhere in MinGW's includes. */ + +typedef struct Emacs_GESTURECONFIG +{ + DWORD dwID; + DWORD dwWant; + DWORD dwBlock; +} Emacs_GESTURECONFIG, *Emacs_PGESTURECONFIG; + +typedef BOOL (WINAPI * SetGestureConfig_proc) (HWND, DWORD, UINT, + Emacs_PGESTURECONFIG, UINT); + TrackMouseEvent_Proc track_mouse_event_fn = NULL; ImmGetCompositionString_Proc get_composition_string_fn = NULL; ImmGetContext_Proc get_ime_context_fn = NULL; @@ -237,6 +250,7 @@ DwmSetWindowAttribute_Proc DwmSetWindowAttribute_fn = NULL; WTSUnRegisterSessionNotification_Proc WTSUnRegisterSessionNotification_fn = NULL; WTSRegisterSessionNotification_Proc WTSRegisterSessionNotification_fn = NULL; RegisterTouchWindow_proc RegisterTouchWindow_fn = NULL; +SetGestureConfig_proc SetGestureConfig_fn = NULL; extern AppendMenuW_Proc unicode_append_menu; @@ -2553,7 +2567,20 @@ w32_createwindow (struct frame *f, int *coords) /* Enable touch-screen input. */ if (RegisterTouchWindow_fn) - (*RegisterTouchWindow_fn) (hwnd, 0); + { + Emacs_GESTURECONFIG cfg; + + (*RegisterTouchWindow_fn) (hwnd, 0); + + /* Disable Window's emulation of mouse events. */ + cfg.dwID = 0; + cfg.dwWant = 0; +#ifndef GC_ALLGESTURES +#define GC_ALLGESTURES 0x00000001 +#endif /* GC_ALLGESTURES */ + cfg.dwBlock = GC_ALLGESTURES; + (*SetGestureConfig_fn) (hwnd, 0, 1, &cfg, sizeof cfg); + } /* Reset F's touch point array. */ for (i = 0; i < ARRAYELTS (f->output_data.w32->touch_ids); ++i) @@ -4803,6 +4830,14 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) are used together, but only if user has two button mouse. */ case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: + + /* Ignore mouse events produced by a touch screen. */ +#ifndef MOUSEEVENTF_FROMTOUCH +#define MOUSEEVENTF_FROMTOUCH 0xFF515700 +#endif /* MOUSEEVENTF_FROMTOUCH */ + if (GetMessageExtraInfo () & MOUSEEVENTF_FROMTOUCH) + goto dflt; + if (w32_num_mouse_buttons > 2) goto handle_plain_button; @@ -4868,6 +4903,13 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_LBUTTONUP: case WM_RBUTTONUP: + /* Ignore mouse events produced by a touch screen. */ +#ifndef MOUSEEVENTF_FROMTOUCH +#define MOUSEEVENTF_FROMTOUCH 0xFF515700 +#endif /* MOUSEEVENTF_FROMTOUCH */ + if (GetMessageExtraInfo () & MOUSEEVENTF_FROMTOUCH) + goto dflt; + if (w32_num_mouse_buttons > 2) goto handle_plain_button; @@ -11441,6 +11483,9 @@ globals_of_w32fns (void) RegisterTouchWindow_fn = (RegisterTouchWindow_proc) get_proc_addr (user32_lib, "RegisterTouchWindow"); + SetGestureConfig_fn + = (SetGestureConfig_proc) get_proc_addr (user32_lib, + "SetGestureConfig"); { HMODULE imm32_lib = GetModuleHandle ("imm32.dll"); diff --git a/src/w32term.c b/src/w32term.c index 45f94ab76bd..74d73af727a 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -6114,11 +6114,13 @@ w32_read_socket (struct terminal *terminal, if (f) { - TOUCHINPUT points[MAX_TOUCH_POINTS]; - int i, x; + TOUCHINPUT *points; + int i, x, px, py; + POINT pt; + points = alloca (sizeof *points * LOWORD (msg.msg.wParam)); if ((*pfnGetTouchInputInfo) ((HANDLE) msg.msg.lParam, - MAX_TOUCH_POINTS, + LOWORD (msg.msg.wParam), points, sizeof (TOUCHINPUT))) { bool movement_p = false; @@ -6128,7 +6130,7 @@ w32_read_socket (struct terminal *terminal, structure, and for each, enter or remove information into and from F->touch_ids, and generate events correspondingly. */ - for (i = 0; i < MAX_TOUCH_POINTS; ++i) + for (i = 0; i < LOWORD (msg.msg.wParam); ++i) { if (!points[i].dwID) continue; @@ -6137,14 +6139,34 @@ w32_read_socket (struct terminal *terminal, empty or matches dwID. */ for (x = 0; x < MAX_TOUCH_POINTS; x++) { - if (FRAME_OUTPUT_DATA (f)->touch_ids[x] == -1 - || (FRAME_OUTPUT_DATA (f)->touch_ids[x] - == points[i].dwID)) + if (FRAME_OUTPUT_DATA (f)->touch_ids[x] + == points[i].dwID) break; } + + if (x < MAX_TOUCH_POINTS) + goto touch_located; + + for (x = 0; x < MAX_TOUCH_POINTS; x++) + { + if (FRAME_OUTPUT_DATA (f)->touch_ids[x] == -1) + break; + } + if (x == MAX_TOUCH_POINTS) continue; + touch_located: + /* X and Y are fractional values. */ + pt.x = points[i].x / 100; + pt.y = points[i].y / 100; + + /* Convert them from screen values to client + values. */ + ScreenToClient (msg.msg.hwnd, &pt); + px = pt.x; + py = pt.y; + if (points[i].dwFlags & TOUCHEVENTF_UP) { /* Clear the entry in touch_ids and report the @@ -6157,22 +6179,25 @@ w32_read_socket (struct terminal *terminal, inev.kind = TOUCHSCREEN_END_EVENT; inev.timestamp = msg.msg.time; XSETFRAME (inev.frame_or_window, f); - XSETINT (inev.x, points[i].x); - XSETINT (inev.y, points[i].y); + XSETINT (inev.x, px); + XSETINT (inev.y, py); XSETINT (inev.arg, x + base); kbd_buffer_store_event (&inev); EVENT_INIT (inev); } else if (points[i].dwFlags & TOUCHEVENTF_DOWN) { - bool recorded_p + bool recorded_p; + + touchscreen_down: + recorded_p = FRAME_OUTPUT_DATA (f)->touch_ids[x] != -1; /* Report and record (if not already recorded) the addition. */ FRAME_OUTPUT_DATA (f)->touch_ids[x] = points[i].dwID; - FRAME_OUTPUT_DATA (f)->touch_x[x] = points[i].x; - FRAME_OUTPUT_DATA (f)->touch_y[x] = points[i].y; + FRAME_OUTPUT_DATA (f)->touch_x[x] = px; + FRAME_OUTPUT_DATA (f)->touch_y[x] = py; if (recorded_p) movement_p = true; @@ -6181,8 +6206,8 @@ w32_read_socket (struct terminal *terminal, inev.kind = TOUCHSCREEN_BEGIN_EVENT; inev.timestamp = msg.msg.time; XSETFRAME (inev.frame_or_window, f); - XSETINT (inev.x, points[i].x); - XSETINT (inev.y, points[i].y); + XSETINT (inev.x, px); + XSETINT (inev.y, py); XSETINT (inev.arg, x + base); kbd_buffer_store_event (&inev); EVENT_INIT (inev); @@ -6190,10 +6215,20 @@ w32_read_socket (struct terminal *terminal, } else { - FRAME_OUTPUT_DATA (f)->touch_ids[x] = points[i].dwID; - FRAME_OUTPUT_DATA (f)->touch_x[x] = points[i].x; - FRAME_OUTPUT_DATA (f)->touch_y[x] = points[i].y; - movement_p = true; + bool recorded_p + = FRAME_OUTPUT_DATA (f)->touch_ids[x] != -1; + if (!recorded_p) + goto touchscreen_down; + + if (FRAME_OUTPUT_DATA (f)->touch_x[x] != px + || FRAME_OUTPUT_DATA (f)->touch_y[x] != py) + { + movement_p = true; + FRAME_OUTPUT_DATA (f)->touch_ids[x] + = points[i].dwID; + FRAME_OUTPUT_DATA (f)->touch_x[x] = px; + FRAME_OUTPUT_DATA (f)->touch_y[x] = py; + } } } @@ -6209,13 +6244,22 @@ w32_read_socket (struct terminal *terminal, arg = Qnil; for (i = 0; i < MAX_TOUCH_POINTS; ++i) - arg - = Fcons (list3i (FRAME_OUTPUT_DATA (f)->touch_x[i], - FRAME_OUTPUT_DATA (f)->touch_y[i], - i + base), - arg); + { + if (FRAME_OUTPUT_DATA (f)->touch_ids[i] == -1) + continue; + + arg + = Fcons (list3i (FRAME_OUTPUT_DATA (f)->touch_x[i], + FRAME_OUTPUT_DATA (f)->touch_y[i], + i + base), + arg); + } inev.arg = arg; + + /* Don't generate events if they would be empty. */ + if (NILP (arg)) + EVENT_INIT (inev); } } } -- 2.39.2