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 static native long sendButtonRelease (short window, int x, int y, /* 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 @@ private static class Coordinate /* 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: - 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 up event. */ EmacsNative.sendTouchUp (this.handle, coordinate.x, - coordinate.y, time, coordinate.id); + coordinate.y, time, + coordinate.id, 0); + break; + + case MotionEvent.ACTION_CANCEL: + /* Touch sequence cancellation event. */ + EmacsNative.sendTouchUp (this.handle, coordinate.x, + 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,63 +6571,13 @@ 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)) - { - /* This touch should activate the menu bar. Generate the - menu bar event. */ - menu_bar_touch_id = Qnil; - - if (!NILP (f->menu_bar_window)) - { - x_y_to_hpos_vpos (XWINDOW (f->menu_bar_window), XFIXNUM (x), - XFIXNUM (y), &column, &row, NULL, NULL, - &dummy); - - if (row >= 0 && row < FRAME_MENU_BAR_LINES (f)) - { - Lisp_Object items, item; - - /* Find the menu bar item under `column'. */ - item = Qnil; - items = FRAME_MENU_BAR_ITEMS (f); - for (i = 0; i < ASIZE (items); i += 4) - { - Lisp_Object pos, string; - string = AREF (items, i + 1); - pos = AREF (items, i + 3); - if (NILP (string)) - break; - if (column >= XFIXNUM (pos) - && column < XFIXNUM (pos) + SCHARS (string)) - { - item = AREF (items, i); - break; - } - } - - /* ELisp manual 2.4b says (x y) are window - relative but code says they are - frame-relative. */ - position = list4 (event->frame_or_window, - Qmenu_bar, - Fcons (event->x, event->y), - INT_TO_INTEGER (event->timestamp)); - - return list2 (item, position); - } - } - - return Qnil; - } #endif /* defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR */ position = make_lispy_position (f, x, y, event->timestamp); @@ -6676,10 +6625,7 @@ make_lispy_event (struct input_event *event) #endif /* HAVE_WINDOW_SYSTEM */ - return list2 (((event->kind - == TOUCHSCREEN_BEGIN_EVENT) - ? Qtouchscreen_begin - : Qtouchscreen_end), + return list2 (Qtouchscreen_begin, Fcons (id, position)); } @@ -6687,18 +6633,115 @@ make_lispy_event (struct input_event *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. */ + menu_bar_touch_id = Qnil; + + if (!NILP (f->menu_bar_window)) + { + x_y_to_hpos_vpos (XWINDOW (f->menu_bar_window), XFIXNUM (x), + XFIXNUM (y), &column, &row, NULL, NULL, + &dummy); + + if (row >= 0 && row < FRAME_MENU_BAR_LINES (f)) + { + Lisp_Object items, item; + + /* Find the menu bar item under `column'. */ + item = Qnil; + items = FRAME_MENU_BAR_ITEMS (f); + for (i = 0; i < ASIZE (items); i += 4) + { + Lisp_Object pos, string; + string = AREF (items, i + 1); + pos = AREF (items, i + 3); + if (NILP (string)) + break; + if (column >= XFIXNUM (pos) + && column < XFIXNUM (pos) + SCHARS (string)) + { + item = AREF (items, i); + break; + } + } + + /* ELisp manual 2.4b says (x y) are window + relative but code says they are + frame-relative. */ + position = list4 (event->frame_or_window, + Qmenu_bar, + Fcons (event->x, event->y), + INT_TO_INTEGER (event->timestamp)); + + return list2 (item, position); + } + } + + return Qnil; + } +#endif /* defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR */ + +#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 */ + 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); }