From 5ff31bf36cf00f9d5a378ce139fd5c2ae8d3f25e Mon Sep 17 00:00:00 2001 From: Po Lu Date: Tue, 18 Jul 2023 10:12:40 +0800 Subject: [PATCH] Update Android port * doc/lispref/commands.texi (Touchscreen Events): Describe treatment of canceled touch sequences during touch event translation. * java/org/gnu/emacs/EmacsNative.java (EmacsNative): Update JNI prototypes. * java/org/gnu/emacs/EmacsWindow.java (motionEvent): Set cancelation flag in events sent where appropriate. * lisp/touch-screen.el (touch-screen-handle-point-update): Improve treatment of horizontal scrolling near window edges. (touch-screen-handle-touch): Don't handle point up if the touch sequence has been canceled. * src/android.c (sendTouchDown, sendTouchUp, sendTouchMove): New argument `flags'. * src/androidgui.h (enum android_touch_event_flags): New enum. (struct android_touch_event): New field `flags'. * src/androidterm.c (handle_one_android_event): Report cancelation in TOUCHSCREEN_END_EVENTs. * src/keyboard.c (make_lispy_event): Fix botched merge. --- doc/lispref/commands.texi | 23 ++++--- java/org/gnu/emacs/EmacsNative.java | 9 ++- java/org/gnu/emacs/EmacsWindow.java | 19 +++-- lisp/touch-screen.el | 27 ++++++-- src/android.c | 12 +++- src/androidgui.h | 10 +++ src/androidterm.c | 5 ++ src/keyboard.c | 103 ++++++++++++++++++++-------- 8 files changed, 152 insertions(+), 56 deletions(-) diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi index ffb01254fc9..55fecdce2d7 100644 --- a/doc/lispref/commands.texi +++ b/doc/lispref/commands.texi @@ -2061,9 +2061,11 @@ keymaps that are active at the location of the of a single @code{down-mouse-1} event, with subsequent @code{touchscreen-update} events translated to mouse motion events (@pxref{Motion Events}), and a final @code{touchscreen-end} event -translated to a @code{mouse-1} or @code{drag-mouse-1} event. This is -referred to ``simple translation'', and produces a simple -correspondence between touchpoint motion and mouse motion. +translated to a @code{mouse-1} or @code{drag-mouse-1} event (unless +the @code{touchscreen-end} event indicates that the touch sequence has +been intercepted by another program.) This is referred to ``simple +translation'', and produces a simple correspondence between touchpoint +motion and mouse motion. @cindex @code{ignored-mouse-command}, a symbol property However, some commands bound to @@ -2078,13 +2080,14 @@ takes place: here, Emacs processes touch screen gestures (@pxref{Touchscreens,,, emacs, The GNU Emacs Manual}) first, and finally attempts to translate touch screen events into mouse events if no gesture was detected prior to a closing @code{touchscreen-end} -event and a command is bound to @code{mouse-1} at the location of that -event. Before generating the @code{mouse-1} event, point is also set -to the location of the @code{touchscreen-end} event, and the window -containing the position of that event is selected, as a compromise for -packages which assume @code{mouse-drag-region} has already set point -to the location of any mouse click and selected the window where it -took place. +event (with its @var{canceled} parameter @code{nil}, as with simple +translation) and a command is bound to @code{mouse-1} at the location +of that event. Before generating the @code{mouse-1} event, point is +also set to the location of the @code{touchscreen-end} event, and the +window containing the position of that event is selected, as a +compromise for packages which assume @code{mouse-drag-region} has +already set point to the location of any mouse click and selected the +window where it took place. To prevent unwanted @code{mouse-1} events arriving after a mouse menu is dismissed (@pxref{Mouse Menus}), Emacs also avoids simple diff --git a/java/org/gnu/emacs/EmacsNative.java b/java/org/gnu/emacs/EmacsNative.java index 1331539879a..d4d502ede5a 100644 --- a/java/org/gnu/emacs/EmacsNative.java +++ b/java/org/gnu/emacs/EmacsNative.java @@ -142,15 +142,18 @@ public final class EmacsNative /* Send an ANDROID_TOUCH_DOWN event. */ public static native long sendTouchDown (short window, int x, int y, - long time, int pointerID); + long time, int pointerID, + int flags); /* Send an ANDROID_TOUCH_UP event. */ public static native long sendTouchUp (short window, int x, int y, - long time, int pointerID); + long time, int pointerID, + int flags); /* Send an ANDROID_TOUCH_MOVE event. */ public static native long sendTouchMove (short window, int x, int y, - long time, int pointerID); + long time, int pointerID, + int flags); /* Send an ANDROID_WHEEL event. */ public static native long sendWheel (short window, int x, int y, diff --git a/java/org/gnu/emacs/EmacsWindow.java b/java/org/gnu/emacs/EmacsWindow.java index 0e96a8382d0..8118479319e 100644 --- a/java/org/gnu/emacs/EmacsWindow.java +++ b/java/org/gnu/emacs/EmacsWindow.java @@ -1025,23 +1025,30 @@ public final class EmacsWindow extends EmacsHandleObject /* Touch down event. */ EmacsNative.sendTouchDown (this.handle, coordinate.x, coordinate.y, time, - coordinate.id); + coordinate.id, 0); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: + /* Touch up event. */ + EmacsNative.sendTouchUp (this.handle, coordinate.x, + coordinate.y, time, + coordinate.id, 0); + break; + case MotionEvent.ACTION_CANCEL: - /* Touch up event. Android documentation says ACTION_CANCEL - should be treated as more or less equivalent to ACTION_UP, - so that is what is done here. */ + /* Touch sequence cancellation event. */ EmacsNative.sendTouchUp (this.handle, coordinate.x, - coordinate.y, time, coordinate.id); + coordinate.y, time, + coordinate.id, + 1 /* ANDROID_TOUCH_SEQUENCE_CANCELED */); break; case MotionEvent.ACTION_MOVE: /* Pointer motion event. */ EmacsNative.sendTouchMove (this.handle, coordinate.x, - coordinate.y, time, coordinate.id); + coordinate.y, time, + coordinate.id, 0); break; } } diff --git a/lisp/touch-screen.el b/lisp/touch-screen.el index 1ef66d0043f..8f10bc3e794 100644 --- a/lisp/touch-screen.el +++ b/lisp/touch-screen.el @@ -548,11 +548,26 @@ then move point to the position of POINT." ;; WINDOW. (relative-xy (touch-screen-relative-xy posn window)) + (col (and (eq (posn-area posn) 'text-area) + (car (posn-col-row posn + (posn-window posn))))) + ;; Don't start horizontal scrolling if the touch + ;; point originated within two columns of the window + ;; edges, as systems like Android use those two + ;; columns to implement gesture navigation. + (diff-x-eligible + (and col (> (car col) 2) + (< (car col) (- (window-width window) 2)))) (diff-x (- (car last-posn) (car relative-xy))) (diff-y (- (cdr last-posn) (cdr relative-xy)))) - ;; Decide whether or not to start scrolling. - (when (or (> diff-y 10) (> diff-x 10) - (< diff-y -10) (< diff-x -10)) + ;; Decide whether or not to start scrolling. Make the + ;; hscrolling threshold slightly larger than the vertical + ;; scrolling threshold, to compensate better for + ;; Android-style gesture navigation. + (when (or (> diff-y 10) (and diff-x-eligible + (> diff-x 20)) + (< diff-y -10) (and diff-x-eligible + (< diff-x -20))) (setcar (nthcdr 3 touch-screen-current-tool) 'scroll) (setcar (nthcdr 2 touch-screen-current-tool) @@ -852,7 +867,11 @@ the place of EVENT within the key sequence being translated, or (cancel-timer touch-screen-current-timer) (setq touch-screen-current-timer nil)) (unwind-protect - (touch-screen-handle-point-up (cadr event) prefix) + ;; Don't perform any actions associated with releasing the + ;; tool if the touch sequence was intercepted by another + ;; program. + (unless (caddr event) + (touch-screen-handle-point-up (cadr event) prefix)) ;; Make sure the tool list is cleared even if ;; `touch-screen-handle-point-up' throws. (setq touch-screen-current-tool nil))) diff --git a/src/android.c b/src/android.c index 90288737c77..f2e5e75d35e 100644 --- a/src/android.c +++ b/src/android.c @@ -2870,7 +2870,8 @@ NATIVE_NAME (sendButtonRelease) (JNIEnv *env, jobject object, JNIEXPORT jlong JNICALL NATIVE_NAME (sendTouchDown) (JNIEnv *env, jobject object, jshort window, jint x, jint y, - jlong time, jint pointer_id) + jlong time, jint pointer_id, + jint flags) { JNI_STACK_ALIGNMENT_PROLOGUE; @@ -2883,6 +2884,7 @@ NATIVE_NAME (sendTouchDown) (JNIEnv *env, jobject object, event.touch.y = y; event.touch.time = time; event.touch.pointer_id = pointer_id; + event.touch.flags = flags; android_write_event (&event); return event_serial; @@ -2891,7 +2893,8 @@ NATIVE_NAME (sendTouchDown) (JNIEnv *env, jobject object, JNIEXPORT jlong JNICALL NATIVE_NAME (sendTouchUp) (JNIEnv *env, jobject object, jshort window, jint x, jint y, - jlong time, jint pointer_id) + jlong time, jint pointer_id, + jint flags) { JNI_STACK_ALIGNMENT_PROLOGUE; @@ -2904,6 +2907,7 @@ NATIVE_NAME (sendTouchUp) (JNIEnv *env, jobject object, event.touch.y = y; event.touch.time = time; event.touch.pointer_id = pointer_id; + event.touch.flags = flags; android_write_event (&event); return event_serial; @@ -2912,7 +2916,8 @@ NATIVE_NAME (sendTouchUp) (JNIEnv *env, jobject object, JNIEXPORT jlong JNICALL NATIVE_NAME (sendTouchMove) (JNIEnv *env, jobject object, jshort window, jint x, jint y, - jlong time, jint pointer_id) + jlong time, jint pointer_id, + jint flags) { JNI_STACK_ALIGNMENT_PROLOGUE; @@ -2925,6 +2930,7 @@ NATIVE_NAME (sendTouchMove) (JNIEnv *env, jobject object, event.touch.y = y; event.touch.time = time; event.touch.pointer_id = pointer_id; + event.touch.flags = flags; android_write_event (&event); return event_serial; diff --git a/src/androidgui.h b/src/androidgui.h index 9e604cdcb8c..265ec29b678 100644 --- a/src/androidgui.h +++ b/src/androidgui.h @@ -365,6 +365,13 @@ struct android_expose_event int width, height; }; +enum android_touch_event_flags + { + /* This touch sequence has been intercepted by the WM (probably + for back gesture navigation or some such.) */ + ANDROID_TOUCH_SEQUENCE_CANCELED = 1, + }; + struct android_touch_event { /* Type of the event. */ @@ -384,6 +391,9 @@ struct android_touch_event /* Index of the pointer being tracked. */ unsigned int pointer_id; + + /* Flags associated with this event. */ + int flags; }; struct android_wheel_event diff --git a/src/androidterm.c b/src/androidterm.c index 27800a61864..bcb6cd6db45 100644 --- a/src/androidterm.c +++ b/src/androidterm.c @@ -1511,6 +1511,11 @@ handle_one_android_event (struct android_display_info *dpyinfo, inev.ie.kind = TOUCHSCREEN_END_EVENT; inev.ie.timestamp = event->touch.time; + /* Report whether the sequence has been canceled. */ + + if (event->touch.flags & ANDROID_TOUCH_SEQUENCE_CANCELED) + inev.ie.modifiers = 1; + XSETFRAME (inev.ie.frame_or_window, any); XSETINT (inev.ie.x, event->touch.x); XSETINT (inev.ie.y, event->touch.y); diff --git a/src/keyboard.c b/src/keyboard.c index bd7433e584a..73c4e3f2593 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -6560,11 +6560,10 @@ make_lispy_event (struct input_event *event) { Lisp_Object x, y, id, position; struct frame *f; +#ifdef HAVE_WINDOW_SYSTEM int tab_bar_item; bool close; -#if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR - int column, row, dummy; -#endif /* defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR */ +#endif /* HAVE_WINDOW_SYSTEM */ f = XFRAME (event->frame_or_window); id = event->arg; @@ -6572,16 +6571,82 @@ make_lispy_event (struct input_event *event) y = event->y; #if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR - if (event->kind == TOUCHSCREEN_BEGIN_EVENT - && coords_in_menu_bar_window (f, XFIXNUM (x), XFIXNUM (y))) + if (coords_in_menu_bar_window (f, XFIXNUM (x), XFIXNUM (y))) { /* If the tap began in the menu bar window, then save the id. */ menu_bar_touch_id = id; return Qnil; } - else if (event->kind == TOUCHSCREEN_END_EVENT - && EQ (menu_bar_touch_id, id)) +#endif /* defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR */ + + position = make_lispy_position (f, x, y, event->timestamp); + +#ifdef HAVE_WINDOW_SYSTEM + + /* Now check if POSITION lies on the tab bar. If so, look up + the corresponding tab bar item's propertized string as the + OBJECT. */ + + if (coords_in_tab_bar_window (f, XFIXNUM (event->x), + XFIXNUM (event->y)) + /* `get_tab_bar_item_kbd' returns 0 if the item was + previously highlighted, 1 otherwise, and -1 if there is + no tab bar item. */ + && get_tab_bar_item_kbd (f, XFIXNUM (event->x), + XFIXNUM (event->y), &tab_bar_item, + &close) >= 0) + { + /* First, obtain the propertized string. */ + x = Fcopy_sequence (AREF (f->tab_bar_items, + (tab_bar_item + + TAB_BAR_ITEM_CAPTION))); + + /* Next, add the key binding. */ + AUTO_LIST2 (y, Qmenu_item, list3 (AREF (f->tab_bar_items, + (tab_bar_item + + TAB_BAR_ITEM_KEY)), + AREF (f->tab_bar_items, + (tab_bar_item + + TAB_BAR_ITEM_BINDING)), + close ? Qt : Qnil)); + + /* And add the new properties to the propertized string. */ + Fadd_text_properties (make_fixnum (0), + make_fixnum (SCHARS (x)), + y, x); + + /* Set the position to 0. */ + x = Fcons (x, make_fixnum (0)); + + /* Finally, add the OBJECT. */ + position = nconc2 (position, Fcons (x, Qnil)); + } + +#endif /* HAVE_WINDOW_SYSTEM */ + + return list2 (Qtouchscreen_begin, + Fcons (id, position)); + } + + case TOUCHSCREEN_END_EVENT: + { + Lisp_Object x, y, id, position; + struct frame *f = XFRAME (event->frame_or_window); +#if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR + int column, row, dummy; +#endif /* defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR */ +#ifdef HAVE_WINDOW_SYSTEM + int tab_bar_item; + bool close; +#endif /* HAVE_WINDOW_SYSTEM */ + + id = event->arg; + x = event->x; + y = event->y; + +#if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR + if (EQ (menu_bar_touch_id, id)) { /* This touch should activate the menu bar. Generate the menu bar event. */ @@ -6631,8 +6696,6 @@ make_lispy_event (struct input_event *event) } #endif /* defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR */ - position = make_lispy_position (f, x, y, event->timestamp); - #ifdef HAVE_WINDOW_SYSTEM /* Now check if POSITION lies on the tab bar. If so, look up @@ -6676,29 +6739,9 @@ make_lispy_event (struct input_event *event) #endif /* HAVE_WINDOW_SYSTEM */ - return list2 (((event->kind - == TOUCHSCREEN_BEGIN_EVENT) - ? Qtouchscreen_begin - : Qtouchscreen_end), - Fcons (id, position)); - } - - case TOUCHSCREEN_END_EVENT: - { - Lisp_Object x, y, id, position; - struct frame *f = XFRAME (event->frame_or_window); - - id = event->arg; - x = event->x; - y = event->y; - position = make_lispy_position (f, x, y, event->timestamp); - return list3 (((event->kind - == TOUCHSCREEN_BEGIN_EVENT) - ? Qtouchscreen_begin - : Qtouchscreen_end), - Fcons (id, position), + return list3 (Qtouchscreen_end, Fcons (id, position), event->modifiers ? Qt : Qnil); } -- 2.39.2