diff options
| author | Po Lu | 2023-07-16 15:30:01 +0800 |
|---|---|---|
| committer | Po Lu | 2023-07-16 15:30:01 +0800 |
| commit | 7b346b92b4c30c634d094e6162b65a22a52b93bb (patch) | |
| tree | b6a81b1e8b27c007205280750ff6ebbcf9ac7209 | |
| parent | d78d7aa78391c84e3d5536514d245d844c08d43d (diff) | |
| download | emacs-7b346b92b4c30c634d094e6162b65a22a52b93bb.tar.gz emacs-7b346b92b4c30c634d094e6162b65a22a52b93bb.zip | |
Improve touch-screen support
* doc/emacs/emacs.texi (Top):
* doc/emacs/input.texi (Other Input Devices): Correctly
capitalize subsection name.
(Touchscreens): Document additional translation.
* doc/lispref/commands.texi (Touchscreen Events): Document that
`touchscreen-end' events now have prefix keys. Also, describe
mouse emulation and `touchscreen-scroll' events.
* doc/lispref/keymaps.texi (Translation Keymaps): Document
`current-key-remap-sequence'.
* lisp/touch-screen.el (touch-screen-translate-prompt): New
function.
(touch-screen-scroll): New command. Bind to
`touchscreen-scroll'.
(touch-screen-handle-point-update, touch-screen-handle-point-up)
(touch-screen-handle-touch): Refactor to actually translate
touch screen event sequences, as opposed to looking up commands
and executing them.
(touch-screen-translate-touch): New function. Bind in
function-key-map to all touch screen events.
(touch-screen-drag-mode-line-1, touch-screen-drag-mode-line)
(touch-screen-tap-header-line): Remove special commands for
dragging the mode line and clicking on the header line.
* lisp/wid-edit.el (widget-button-click): Adjust accordingly.
* src/keyboard.c (access_keymap_keyremap): Bind
`current-key-remap-sequence' to the key sequence being remapped.
(keyremap_step): Give fkey->start and fkey->end to
access_keymap_keyremap.
(head_table): Add imaginary prefix to touchscreen-end events as
well.
(syms_of_keyboard): New variable Vcurrent_key_remap_sequence.
| -rw-r--r-- | doc/emacs/emacs.texi | 2 | ||||
| -rw-r--r-- | doc/emacs/input.texi | 7 | ||||
| -rw-r--r-- | doc/lispref/commands.texi | 68 | ||||
| -rw-r--r-- | doc/lispref/keymaps.texi | 9 | ||||
| -rw-r--r-- | lisp/touch-screen.el | 657 | ||||
| -rw-r--r-- | lisp/wid-edit.el | 8 | ||||
| -rw-r--r-- | src/keyboard.c | 39 |
7 files changed, 518 insertions, 272 deletions
diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi index 92be9f9b9a9..b255e679d5f 100644 --- a/doc/emacs/emacs.texi +++ b/doc/emacs/emacs.texi | |||
| @@ -1273,7 +1273,7 @@ Emacs and Android | |||
| 1273 | * Android Troubleshooting:: Dealing with problems. | 1273 | * Android Troubleshooting:: Dealing with problems. |
| 1274 | * Android Software:: Getting extra software. | 1274 | * Android Software:: Getting extra software. |
| 1275 | 1275 | ||
| 1276 | Emacs and unconventional input devices | 1276 | Emacs and Unconventional Input Devices |
| 1277 | 1277 | ||
| 1278 | * Touchscreens:: Using Emacs on touchscreens. | 1278 | * Touchscreens:: Using Emacs on touchscreens. |
| 1279 | * On-Screen Keyboards:: Using Emacs with virtual keyboards. | 1279 | * On-Screen Keyboards:: Using Emacs with virtual keyboards. |
diff --git a/doc/emacs/input.texi b/doc/emacs/input.texi index 0df3162ce97..66554653def 100644 --- a/doc/emacs/input.texi +++ b/doc/emacs/input.texi | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | @c Copyright (C) 2023 Free Software Foundation, Inc. | 2 | @c Copyright (C) 2023 Free Software Foundation, Inc. |
| 3 | @c See file emacs.texi for copying conditions. | 3 | @c See file emacs.texi for copying conditions. |
| 4 | @node Other Input Devices | 4 | @node Other Input Devices |
| 5 | @appendix Emacs and unconventional input devices | 5 | @appendix Emacs and Unconventional Input Devices |
| 6 | @cindex other input devices | 6 | @cindex other input devices |
| 7 | 7 | ||
| 8 | Emacs was originally developed with the assumption that its users | 8 | Emacs was originally developed with the assumption that its users |
| @@ -21,7 +21,7 @@ which is detailed here. | |||
| 21 | 21 | ||
| 22 | @node Touchscreens | 22 | @node Touchscreens |
| 23 | @section Using Emacs on touchscreens | 23 | @section Using Emacs on touchscreens |
| 24 | @cindex touchscreens | 24 | @cindex touchscreen input |
| 25 | 25 | ||
| 26 | Touchscreen input works by pressing and moving tools (which include | 26 | Touchscreen input works by pressing and moving tools (which include |
| 27 | fingers and some pointing devices--styluses, for example) onto a frame | 27 | fingers and some pointing devices--styluses, for example) onto a frame |
| @@ -40,6 +40,9 @@ executing any command bound to @code{mouse-1} at that location in the | |||
| 40 | window. If the tap happened on top of a link (@pxref{Mouse | 40 | window. If the tap happened on top of a link (@pxref{Mouse |
| 41 | References}), then Emacs will follow the link instead. | 41 | References}), then Emacs will follow the link instead. |
| 42 | 42 | ||
| 43 | If a command bound to @code{down-mouse-1} is bound to the location | ||
| 44 | where the tap took place, Emacs will execute that command as well. | ||
| 45 | |||
| 43 | @item | 46 | @item |
| 44 | @cindex scrolling, touchscreens | 47 | @cindex scrolling, touchscreens |
| 45 | ``Scrolling'', meaning to place a tool on the display and move it up | 48 | ``Scrolling'', meaning to place a tool on the display and move it up |
diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi index 7a076406bed..725ca900165 100644 --- a/doc/lispref/commands.texi +++ b/doc/lispref/commands.texi | |||
| @@ -2013,10 +2013,7 @@ finger against the touchscreen. | |||
| 2013 | 2013 | ||
| 2014 | These events also have imaginary prefixes keys added by | 2014 | These events also have imaginary prefixes keys added by |
| 2015 | @code{read-key-sequence} when they originate on top of a special part | 2015 | @code{read-key-sequence} when they originate on top of a special part |
| 2016 | of a frame or window. @xref{Key Sequence Input}. The reason the | 2016 | of a frame or window. @xref{Key Sequence Input}. |
| 2017 | other touch screen events do not undergo this treatment is that they | ||
| 2018 | are rarely useful without being used in tandem from their | ||
| 2019 | corresponding @code{touchscreen-begin} events. | ||
| 2020 | 2017 | ||
| 2021 | @cindex @code{touchscreen-update} event | 2018 | @cindex @code{touchscreen-update} event |
| 2022 | @item (touchscreen-update @var{points}) | 2019 | @item (touchscreen-update @var{points}) |
| @@ -2029,12 +2026,73 @@ up-to-date positions of each touch point currently on the touchscreen. | |||
| 2029 | This event is sent when @var{point} is no longer present on the | 2026 | This event is sent when @var{point} is no longer present on the |
| 2030 | display, because another program took the grab, or because the user | 2027 | display, because another program took the grab, or because the user |
| 2031 | raised the finger from the touchscreen. | 2028 | raised the finger from the touchscreen. |
| 2029 | |||
| 2030 | These events also have imaginary prefixes keys added by | ||
| 2031 | @code{read-key-sequence} when they originate on top of a special part | ||
| 2032 | of a frame or window. | ||
| 2032 | @end table | 2033 | @end table |
| 2033 | 2034 | ||
| 2034 | If a touchpoint is pressed against the menu bar, then Emacs will not | 2035 | If a touchpoint is pressed against the menu bar, then Emacs will not |
| 2035 | generate any corresponding @code{touchscreen-begin} or | 2036 | generate any corresponding @code{touchscreen-begin} or |
| 2036 | @code{touchscreen-end} events; instead, the menu bar may be displayed | 2037 | @code{touchscreen-end} events; instead, the menu bar may be displayed |
| 2037 | when @code{touchscreen-end} should have been delivered. | 2038 | after @code{touchscreen-end} would have been delivered under other |
| 2039 | circumstances. | ||
| 2040 | |||
| 2041 | @cindex mouse emulation from touch screen events | ||
| 2042 | When no command is bound to @code{touchscreen-begin}, | ||
| 2043 | @code{touchscreen-end} or @code{touchscreen-update}, Emacs calls a | ||
| 2044 | ``key translation function'' (@pxref{Translation Keymaps}) to | ||
| 2045 | translate key sequences containing touch screen events into ordinary | ||
| 2046 | mouse events (@pxref{Mouse Events}.) Since Emacs doesn't support | ||
| 2047 | distinguishing events originating from separate mouse devices, it | ||
| 2048 | assumes that only one touchpoint is active while translation takes | ||
| 2049 | place; breaking this assumption may lead to unexpected behavior. | ||
| 2050 | |||
| 2051 | Emacs applies two different strategies for translating touch events | ||
| 2052 | into mouse events, contingent on factors such as the commands bound to | ||
| 2053 | keymaps that are active at the location of the | ||
| 2054 | @code{touchscreen-begin} event. If a command is bound to | ||
| 2055 | @code{down-mouse-1} at that location, the initial translation consists | ||
| 2056 | of a single @code{down-mouse-1} event, with subsequent | ||
| 2057 | @code{touchscreen-update} events translated to mouse motion events | ||
| 2058 | (@pxref{Motion Events}), and a final @code{touchscreen-end} event | ||
| 2059 | translated to a @code{mouse-1} or @code{drag-mouse-1} event. This is | ||
| 2060 | referred to ``simple translation'', and produces a simple | ||
| 2061 | correspondence between touchpoint motion and mouse motion. | ||
| 2062 | |||
| 2063 | @cindex @code{ignored-mouse-command}, a symbol property | ||
| 2064 | However, some commands bound to | ||
| 2065 | @code{down-mouse-1}--@code{mouse-drag-region}, for example--either | ||
| 2066 | conflict with defined touch screen gestures (such as ``long-press to | ||
| 2067 | drag''), or with user expectations for touch input, and shouldn't | ||
| 2068 | subject the touch sequence to simple translation. If a command whose | ||
| 2069 | name contains the property @code{ignored-mouse-command} is encountered | ||
| 2070 | or there is no command bound to @code{down-mouse-1}, a more irregular | ||
| 2071 | form of translation takes place: here, Emacs processes touch screen | ||
| 2072 | gestures (@pxref{Touchscreens,,, emacs, The GNU Emacs Manual}) first, | ||
| 2073 | and finally attempts to translate touch screen events into mouse | ||
| 2074 | events if no gesture was detected prior to a closing | ||
| 2075 | @code{touchscreen-end} event and a command is bound to @code{mouse-1} | ||
| 2076 | at the location of that event. Before generating the @code{mouse-1} | ||
| 2077 | event, point is also set to the location of the @code{touchscreen-end} | ||
| 2078 | event, and the window containing the position of that event is | ||
| 2079 | selected, as a compromise for packages which assume | ||
| 2080 | @code{mouse-drag-region} has already set point to the location of any | ||
| 2081 | mouse click and selected the window where it took place. | ||
| 2082 | |||
| 2083 | @cindex @code{touchscreen-scroll} event | ||
| 2084 | If a ``scrolling'' gesture is detected during the translation process, | ||
| 2085 | each subsequent @code{touchscreen-update} event is translated to a | ||
| 2086 | @code{touchscreen-scroll} event of the form: | ||
| 2087 | |||
| 2088 | @example | ||
| 2089 | @w{@code{(touchscreen-scroll @var{window} @var{dx} @var{dy})}} | ||
| 2090 | @end example | ||
| 2091 | |||
| 2092 | where @var{dx} and @var{dy} specify, in pixels, the relative motion of | ||
| 2093 | the tool from the position of the @code{touchscreen-begin} event that | ||
| 2094 | started the sequence or the last @code{touchscreen-scroll} event, | ||
| 2095 | whichever came later. | ||
| 2038 | 2096 | ||
| 2039 | @cindex handling touch screen events | 2097 | @cindex handling touch screen events |
| 2040 | @cindex tap and drag, touch screen gestures | 2098 | @cindex tap and drag, touch screen gestures |
diff --git a/doc/lispref/keymaps.texi b/doc/lispref/keymaps.texi index 05dc17eb03f..e41dbf9def8 100644 --- a/doc/lispref/keymaps.texi +++ b/doc/lispref/keymaps.texi | |||
| @@ -2044,6 +2044,15 @@ to turn the character that follows into a Hyper character: | |||
| 2044 | @end group | 2044 | @end group |
| 2045 | @end example | 2045 | @end example |
| 2046 | 2046 | ||
| 2047 | @cindex accessing events within a key translation function | ||
| 2048 | @vindex current-key-remap-sequence | ||
| 2049 | A key translation function might want to adjust its behavior based on | ||
| 2050 | parameters to events within a key sequence containing non-key events | ||
| 2051 | (@pxref{Input Events}.) This information is available from the | ||
| 2052 | variable @code{current-key-remap-sequence}, which is bound to the key | ||
| 2053 | sub-sequence being translated around calls to key translation | ||
| 2054 | functions. | ||
| 2055 | |||
| 2047 | @subsection Interaction with normal keymaps | 2056 | @subsection Interaction with normal keymaps |
| 2048 | 2057 | ||
| 2049 | The end of a key sequence is detected when that key sequence either is bound | 2058 | The end of a key sequence is detected when that key sequence either is bound |
diff --git a/lisp/touch-screen.el b/lisp/touch-screen.el index 242ea4fcd9b..0f584269931 100644 --- a/lisp/touch-screen.el +++ b/lisp/touch-screen.el | |||
| @@ -49,6 +49,11 @@ keyboard after a mouse command is executed in response to a | |||
| 49 | "Timer used to track long-presses. | 49 | "Timer used to track long-presses. |
| 50 | This is always cleared upon any significant state change.") | 50 | This is always cleared upon any significant state change.") |
| 51 | 51 | ||
| 52 | (defvar touch-screen-translate-prompt nil | ||
| 53 | "Prompt given to the touch screen translation function. | ||
| 54 | If non-nil, the touch screen key event translation machinery | ||
| 55 | is being called from `read-sequence' or some similar function.") | ||
| 56 | |||
| 52 | (defcustom touch-screen-display-keyboard nil | 57 | (defcustom touch-screen-display-keyboard nil |
| 53 | "If non-nil, always display the on screen keyboard. | 58 | "If non-nil, always display the on screen keyboard. |
| 54 | A buffer local value means to always display the on screen | 59 | A buffer local value means to always display the on screen |
| @@ -70,6 +75,14 @@ See `pixel-scroll-precision-mode' for more details." | |||
| 70 | :group 'mouse | 75 | :group 'mouse |
| 71 | :version "30.1") | 76 | :version "30.1") |
| 72 | 77 | ||
| 78 | |||
| 79 | |||
| 80 | ;; Touch screen event translation. The code here translates raw touch | ||
| 81 | ;; screen events into `touchscreen-scroll' events and mouse events in | ||
| 82 | ;; a ``DWIM'' fashion, consulting the keymaps at the position of the | ||
| 83 | ;; mouse event to determine the best course of action, while also | ||
| 84 | ;; recognizing drag-to-select and other gestures. | ||
| 85 | |||
| 73 | (defun touch-screen-relative-xy (posn window) | 86 | (defun touch-screen-relative-xy (posn window) |
| 74 | "Return the coordinates of POSN, a mouse position list. | 87 | "Return the coordinates of POSN, a mouse position list. |
| 75 | However, return the coordinates relative to WINDOW. | 88 | However, return the coordinates relative to WINDOW. |
| @@ -201,6 +214,26 @@ horizontal scrolling according to the movement in DX." | |||
| 201 | (setcar (nthcdr 8 touch-screen-current-tool) lines-hscrolled) | 214 | (setcar (nthcdr 8 touch-screen-current-tool) lines-hscrolled) |
| 202 | nil))))) | 215 | nil))))) |
| 203 | 216 | ||
| 217 | (defun touch-screen-scroll (event) | ||
| 218 | "Scroll the window within EVENT, a `touchscreen-scroll' event. | ||
| 219 | If `touch-screen-precision-scroll', scroll the window vertically | ||
| 220 | by the number of pixels specified within that event. Else, | ||
| 221 | scroll the window by one line for every | ||
| 222 | `window-default-line-height' pixels worth of movement. | ||
| 223 | |||
| 224 | If EVENT also specifies horizontal motion and no significant | ||
| 225 | amount of vertical scrolling has taken place, also scroll the | ||
| 226 | window horizontally in conjunction with the number of pixels in | ||
| 227 | the event." | ||
| 228 | (interactive "e") | ||
| 229 | (let ((window (nth 1 event)) | ||
| 230 | (dx (nth 2 event)) | ||
| 231 | (dy (nth 3 event))) | ||
| 232 | (with-selected-window window | ||
| 233 | (touch-screen-handle-scroll dx dy)))) | ||
| 234 | |||
| 235 | (global-set-key [touchscreen-scroll] #'touch-screen-scroll) | ||
| 236 | |||
| 204 | (defun touch-screen-handle-timeout (arg) | 237 | (defun touch-screen-handle-timeout (arg) |
| 205 | "Start the touch screen timeout or handle it depending on ARG. | 238 | "Start the touch screen timeout or handle it depending on ARG. |
| 206 | When ARG is nil, start the `touch-screen-current-timer' to go off | 239 | When ARG is nil, start the `touch-screen-current-timer' to go off |
| @@ -236,19 +269,30 @@ known position of the tool." | |||
| 236 | 269 | ||
| 237 | (defun touch-screen-handle-point-update (point) | 270 | (defun touch-screen-handle-point-update (point) |
| 238 | "Notice that the touch point POINT has changed position. | 271 | "Notice that the touch point POINT has changed position. |
| 272 | Perform the editing operations or throw to the input translation | ||
| 273 | function with an input event tied to any gesture that is | ||
| 274 | recognized. | ||
| 275 | |||
| 239 | POINT must be the touch point currently being tracked as | 276 | POINT must be the touch point currently being tracked as |
| 240 | `touch-screen-current-tool'. | 277 | `touch-screen-current-tool'. |
| 241 | 278 | ||
| 242 | If the fourth element of `touch-screen-current-tool' is nil, then | 279 | If the fourth element of `touch-screen-current-tool' is nil, then |
| 243 | the touch has just begun. Determine how much POINT has moved. | 280 | the touch has just begun. Determine how much POINT has moved. |
| 244 | If POINT has moved upwards or downwards by a significant amount, | 281 | If POINT has moved upwards or downwards by a significant amount, |
| 245 | then set the fourth element to `scroll'. Then, call | 282 | then set the fourth element to `scroll'. Then, generate a |
| 246 | `touch-screen-handle-scroll' to scroll the display by that | 283 | `touchscreen-scroll' event with the window that POINT was |
| 247 | amount. | 284 | initially placed upon, and pixel deltas describing how much point |
| 285 | has moved relative to its previous position in the X and Y axes. | ||
| 286 | |||
| 287 | If the fourth element of `touchscreen-current-tool' is `scroll', | ||
| 288 | then generate a `touchscreen-scroll' event with the window that | ||
| 289 | qPOINT was initially placed upon, and pixel deltas describing how | ||
| 290 | much point has moved relative to its previous position in the X | ||
| 291 | and Y axes. | ||
| 248 | 292 | ||
| 249 | If the fourth element of `touch-screen-current-tool' is `scroll', | 293 | If the fourth element of `touch-screen-current-tool' is |
| 250 | then scroll the display by how much POINT has moved in the Y | 294 | `mouse-drag' and `track-mouse' is non-nil, then generate a |
| 251 | axis. | 295 | `mouse-movement' event with the position of POINT. |
| 252 | 296 | ||
| 253 | If the fourth element of `touch-screen-current-tool' is `held', | 297 | If the fourth element of `touch-screen-current-tool' is `held', |
| 254 | then the touch has been held down for some time. If motion | 298 | then the touch has been held down for some time. If motion |
| @@ -275,8 +319,11 @@ then move point to the position of POINT." | |||
| 275 | 'scroll) | 319 | 'scroll) |
| 276 | (setcar (nthcdr 2 touch-screen-current-tool) | 320 | (setcar (nthcdr 2 touch-screen-current-tool) |
| 277 | relative-xy) | 321 | relative-xy) |
| 278 | (with-selected-window window | 322 | ;; Generate a `touchscreen-scroll' event with `diff-x' |
| 279 | (touch-screen-handle-scroll diff-x diff-y)) | 323 | ;; and `diff-y'. |
| 324 | (throw 'input-event | ||
| 325 | (list 'touchscreen-scroll | ||
| 326 | window diff-x diff-y)) | ||
| 280 | ;; Cancel the touch screen long-press timer, if it is | 327 | ;; Cancel the touch screen long-press timer, if it is |
| 281 | ;; still there by any chance. | 328 | ;; still there by any chance. |
| 282 | (when touch-screen-current-timer | 329 | (when touch-screen-current-timer |
| @@ -301,8 +348,18 @@ then move point to the position of POINT." | |||
| 301 | (setcar (nthcdr 2 touch-screen-current-tool) | 348 | (setcar (nthcdr 2 touch-screen-current-tool) |
| 302 | relative-xy) | 349 | relative-xy) |
| 303 | (unless (and (zerop diff-x) (zerop diff-y)) | 350 | (unless (and (zerop diff-x) (zerop diff-y)) |
| 304 | (with-selected-window window | 351 | (throw 'input-event |
| 305 | (touch-screen-handle-scroll diff-x diff-y))))) | 352 | ;; Generate a `touchscreen-scroll' event with |
| 353 | ;; `diff-x' and `diff-y'. | ||
| 354 | (list 'touchscreen-scroll | ||
| 355 | window diff-x diff-y))))) | ||
| 356 | ((eq what 'mouse-drag) | ||
| 357 | ;; There was a `down-mouse-1' event bound at the starting | ||
| 358 | ;; point of the event. Generate a mouse-motion event if | ||
| 359 | ;; mouse movement is being tracked. | ||
| 360 | (when track-mouse | ||
| 361 | (throw 'input-event (list 'mouse-movement | ||
| 362 | (cdr point))))) | ||
| 306 | ((eq what 'held) | 363 | ((eq what 'held) |
| 307 | (let* ((posn (cdr point)) | 364 | (let* ((posn (cdr point)) |
| 308 | (relative-xy | 365 | (relative-xy |
| @@ -319,7 +376,6 @@ then move point to the position of POINT." | |||
| 319 | ;; Activate the mark. It should have been set by the | 376 | ;; Activate the mark. It should have been set by the |
| 320 | ;; time `touch-screen-timeout' was called. | 377 | ;; time `touch-screen-timeout' was called. |
| 321 | (activate-mark) | 378 | (activate-mark) |
| 322 | |||
| 323 | ;; Figure out what character to go to. If this posn is | 379 | ;; Figure out what character to go to. If this posn is |
| 324 | ;; in the window, go to (posn-point posn). If not, | 380 | ;; in the window, go to (posn-point posn). If not, |
| 325 | ;; then go to the line before either window start or | 381 | ;; then go to the line before either window start or |
| @@ -385,127 +441,357 @@ in response to the minibuffer being closed." | |||
| 385 | (cancel-timer minibuffer-on-screen-keyboard-timer) | 441 | (cancel-timer minibuffer-on-screen-keyboard-timer) |
| 386 | (setq minibuffer-on-screen-keyboard-timer nil))))) | 442 | (setq minibuffer-on-screen-keyboard-timer nil))))) |
| 387 | 443 | ||
| 388 | (defun touch-screen-handle-point-up (point) | 444 | (defun touch-screen-handle-point-up (point prefix) |
| 389 | "Notice that POINT has been removed from the screen. | 445 | "Notice that POINT has been removed from the screen. |
| 390 | POINT should be the point currently tracked as | 446 | POINT should be the point currently tracked as |
| 391 | `touch-screen-current-tool'. | 447 | `touch-screen-current-tool'. |
| 448 | PREFIX should be a virtual function key used to look up key | ||
| 449 | bindings. | ||
| 450 | |||
| 451 | If the fourth element of `touch-screen-current-tool' is nil, move | ||
| 452 | point to the position of POINT, selecting the window under POINT | ||
| 453 | as well, and deactivate the mark; if there is a button or link at | ||
| 454 | POINT, call the command bound to `mouse-2' there. Otherwise, | ||
| 455 | call the command bound to `mouse-1'. | ||
| 392 | 456 | ||
| 393 | If the fourth argument of `touch-screen-current-tool' is nil, | 457 | If the fourth element of `touch-screen-current-tool' is |
| 394 | move point to the position of POINT, selecting the window under | 458 | `mouse-drag', then generate either a `mouse-1' or a |
| 395 | POINT as well, and deactivate the mark; if there is a button or | 459 | `drag-mouse-1' event depending on how far the position of POINT |
| 396 | link at POINT, call the command bound to `mouse-2' there. | 460 | is from the starting point of the touch. |
| 397 | Otherwise, call the command bound to `mouse-1'. | ||
| 398 | 461 | ||
| 399 | If the command being executed is listed in | 462 | If the command being executed is listed in |
| 400 | `touch-screen-set-point-commands' also display the on-screen | 463 | `touch-screen-set-point-commands' also display the on-screen |
| 401 | keyboard if the current buffer and the character at the new point | 464 | keyboard if the current buffer and the character at the new point |
| 402 | is not read-only." | 465 | is not read-only." |
| 403 | (let ((what (nth 3 touch-screen-current-tool))) | 466 | (let ((what (nth 3 touch-screen-current-tool)) |
| 467 | (posn (cdr point)) window point) | ||
| 404 | (cond ((null what) | 468 | (cond ((null what) |
| 405 | (when (windowp (posn-window (cdr point))) | 469 | (when (windowp (posn-window posn)) |
| 470 | (setq point (posn-point point) | ||
| 471 | window (posn-window posn)) | ||
| 406 | ;; Select the window that was tapped. | 472 | ;; Select the window that was tapped. |
| 407 | (select-window (posn-window (cdr point))) | 473 | (select-window window) |
| 408 | ;; Now simulate a mouse click there. If there is a link | 474 | ;; Now simulate a mouse click there. If there is a link |
| 409 | ;; or a button, use mouse-2 to push it. | 475 | ;; or a button, use mouse-2 to push it. |
| 410 | (let ((event (list (if (or (mouse-on-link-p (cdr point)) | 476 | (let* ((event (list (if (or (mouse-on-link-p posn) |
| 411 | (button-at (posn-point (cdr point)))) | 477 | (and point (button-at point))) |
| 412 | 'mouse-2 | 478 | 'mouse-2 |
| 413 | 'mouse-1) | 479 | 'mouse-1) |
| 414 | (cdr point))) | 480 | posn)) |
| 415 | ;; Look for an extra keymap to look in. | 481 | ;; Look for the command bound to this event. |
| 416 | (keymap (and (posn-object (cdr point)) | 482 | (command (key-binding (if prefix |
| 417 | (stringp | 483 | (vector prefix |
| 418 | (posn-object (cdr point))) | 484 | (car event)) |
| 419 | (get-text-property | 485 | (vector (car event))) |
| 420 | 0 'keymap | 486 | t nil posn))) |
| 421 | (posn-object (cdr point))))) | ||
| 422 | command) | ||
| 423 | (save-excursion | ||
| 424 | (when (posn-point (cdr point)) | ||
| 425 | (goto-char (posn-point (cdr point)))) | ||
| 426 | (if keymap | ||
| 427 | (setq keymap (cons keymap (current-active-maps t))) | ||
| 428 | (setq keymap (current-active-maps t))) | ||
| 429 | (setq command (lookup-key keymap (vector (car event))))) | ||
| 430 | (deactivate-mark) | 487 | (deactivate-mark) |
| 431 | ;; This is necessary for following links. | 488 | (when point |
| 432 | (goto-char (posn-point (cdr point))) | 489 | ;; This is necessary for following links. |
| 490 | (goto-char point)) | ||
| 433 | ;; Figure out if the on screen keyboard needs to be | 491 | ;; Figure out if the on screen keyboard needs to be |
| 434 | ;; displayed. | 492 | ;; displayed. |
| 435 | (when command | 493 | (when command |
| 436 | (call-interactively command nil | 494 | (if (memq command touch-screen-set-point-commands) |
| 437 | (vector event)) | 495 | (if touch-screen-translate-prompt |
| 438 | (when (memq command touch-screen-set-point-commands) | 496 | ;; When a `mouse-set-point' command is |
| 439 | (if (and (or (not buffer-read-only) | 497 | ;; encountered and |
| 440 | touch-screen-display-keyboard) | 498 | ;; `touch-screen-handle-touch' is being |
| 441 | ;; Detect the splash screen and avoid | 499 | ;; called from the keyboard command loop, |
| 442 | ;; displaying the on screen keyboard | 500 | ;; call it immediately so that point is set |
| 443 | ;; there. | 501 | ;; prior to the on screen keyboard being |
| 444 | (not (equal (buffer-name) "*GNU Emacs*"))) | 502 | ;; displayed. |
| 445 | ;; Once the on-screen keyboard has been opened, | 503 | (call-interactively command nil |
| 446 | ;; add `touch-screen-window-selection-changed' | 504 | (vector event)) |
| 447 | ;; as a window selection change function This | 505 | (if (and (or (not buffer-read-only) |
| 448 | ;; allows the on screen keyboard to be hidden | 506 | touch-screen-display-keyboard) |
| 449 | ;; if the selected window's point becomes read | 507 | ;; Detect the splash screen and avoid |
| 450 | ;; only at some point in the future. | 508 | ;; displaying the on screen keyboard |
| 451 | (progn | 509 | ;; there. |
| 452 | (add-hook 'window-selection-change-functions | 510 | (not (equal (buffer-name) "*GNU Emacs*"))) |
| 453 | #'touch-screen-window-selection-changed) | 511 | ;; Once the on-screen keyboard has been |
| 454 | (frame-toggle-on-screen-keyboard (selected-frame) nil)) | 512 | ;; opened, add |
| 455 | ;; Otherwise, hide the on screen keyboard now. | 513 | ;; `touch-screen-window-selection-changed' |
| 456 | (frame-toggle-on-screen-keyboard (selected-frame) t)))))))))) | 514 | ;; as a window selection change function |
| 457 | 515 | ;; This allows the on screen keyboard to be | |
| 458 | (defun touch-screen-handle-touch (event) | 516 | ;; hidden if the selected window's point |
| 517 | ;; becomes read only at some point in the | ||
| 518 | ;; future. | ||
| 519 | (progn | ||
| 520 | (add-hook 'window-selection-change-functions | ||
| 521 | #'touch-screen-window-selection-changed) | ||
| 522 | (frame-toggle-on-screen-keyboard (selected-frame) | ||
| 523 | nil)) | ||
| 524 | ;; Otherwise, hide the on screen keyboard | ||
| 525 | ;; now. | ||
| 526 | (frame-toggle-on-screen-keyboard (selected-frame) t)) | ||
| 527 | ;; But if it's being called from `describe-key' | ||
| 528 | ;; or some such, return it as a key sequence. | ||
| 529 | (throw 'input-event event))) | ||
| 530 | ;; If not, return the event. | ||
| 531 | (throw 'input-event event))))) | ||
| 532 | ((eq what 'mouse-drag) | ||
| 533 | ;; Generate a corresponding `mouse-1' event. | ||
| 534 | (let* ((new-window (posn-window posn)) | ||
| 535 | (new-point (posn-point posn)) | ||
| 536 | (old-posn (nth 4 touch-screen-current-tool)) | ||
| 537 | (old-window (posn-window posn)) | ||
| 538 | (old-point (posn-point posn))) | ||
| 539 | (throw 'input-event | ||
| 540 | ;; If the position of the touch point hasn't | ||
| 541 | ;; changed, or it doesn't start or end on a | ||
| 542 | ;; window... | ||
| 543 | (if (and (eq new-window old-window) | ||
| 544 | (eq new-point old-point) | ||
| 545 | (windowp new-window) | ||
| 546 | (windowp old-window)) | ||
| 547 | ;; ... generate a mouse-1 event... | ||
| 548 | (list 'mouse-1 posn) | ||
| 549 | ;; ... otherwise, generate a drag-mouse-1 event. | ||
| 550 | (list 'drag-mouse-1 (cons old-window | ||
| 551 | old-posn) | ||
| 552 | (cons new-window posn))))))))) | ||
| 553 | |||
| 554 | (defun touch-screen-handle-touch (event prefix &optional interactive) | ||
| 459 | "Handle a single touch EVENT, and perform associated actions. | 555 | "Handle a single touch EVENT, and perform associated actions. |
| 460 | EVENT can either be a touchscreen-begin, touchscreen-update or | 556 | EVENT can either be a `touchscreen-begin', `touchscreen-update' or |
| 461 | touchscreen-end event." | 557 | `touchscreen-end' event. |
| 462 | (interactive "e") | 558 | PREFIX is either nil, or a symbol specifying a virtual function |
| 463 | (cond | 559 | key to apply to EVENT. |
| 464 | ((eq (car event) 'touchscreen-begin) | 560 | |
| 465 | ;; A tool was just pressed against the screen. Figure out the | 561 | If INTERACTIVE, execute the command associated with any event |
| 466 | ;; window where it is and make it the tool being tracked on the | 562 | generated instead of throwing `input-event'. Otherwise, throw |
| 467 | ;; window. | 563 | `input-event' with a single input event if that event should take |
| 468 | (let ((touchpoint (caadr event)) | 564 | the place of EVENT within the key sequence being translated, or |
| 469 | (position (cdadr event))) | 565 | `nil' if all tools have been released." |
| 470 | ;; Cancel the touch screen timer, if it is still there by any | 566 | (interactive "e\ni\np") |
| 471 | ;; chance. | 567 | (if interactive |
| 472 | (when touch-screen-current-timer | 568 | ;; Called interactively (probably from wid-edit.el.) |
| 473 | (cancel-timer touch-screen-current-timer) | 569 | ;; Add any event generated to `unread-command-events'. |
| 474 | (setq touch-screen-current-timer nil)) | 570 | (let ((event (catch 'input-event |
| 475 | ;; Replace any previously ongoing gesture. If POSITION has no | 571 | (touch-screen-handle-touch event prefix) nil))) |
| 476 | ;; window or position, make it nil instead. | 572 | (when event |
| 477 | (setq touch-screen-current-tool (and (windowp (posn-window position)) | 573 | (setq unread-command-events |
| 478 | (posn-point position) | 574 | (nconc unread-command-events |
| 479 | (list touchpoint | 575 | (list event))))) |
| 480 | (posn-window position) | 576 | (cond |
| 481 | (posn-x-y position) | 577 | ((eq (car event) 'touchscreen-begin) |
| 482 | nil position nil nil | 578 | ;; A tool was just pressed against the screen. Figure out the |
| 483 | nil nil))) | 579 | ;; window where it is and make it the tool being tracked on the |
| 484 | ;; Start the long-press timer. | 580 | ;; window. |
| 485 | (touch-screen-handle-timeout nil))) | 581 | (let* ((touchpoint (caadr event)) |
| 486 | ((eq (car event) 'touchscreen-update) | 582 | (position (cdadr event)) |
| 487 | ;; The positions of tools currently pressed against the screen | 583 | (window (posn-window position)) |
| 488 | ;; have changed. If there is a tool being tracked as part of a | 584 | (point (posn-point position))) |
| 489 | ;; gesture, look it up in the list of tools. | 585 | ;; Cancel the touch screen timer, if it is still there by any |
| 490 | (let ((new-point (assq (car touch-screen-current-tool) | 586 | ;; chance. |
| 491 | (cadr event)))) | 587 | (when touch-screen-current-timer |
| 492 | (when new-point | 588 | (cancel-timer touch-screen-current-timer) |
| 493 | (touch-screen-handle-point-update new-point)))) | 589 | (setq touch-screen-current-timer nil)) |
| 494 | ((eq (car event) 'touchscreen-end) | 590 | ;; Replace any previously ongoing gesture. If POSITION has no |
| 495 | ;; A tool has been removed from the screen. If it is the tool | 591 | ;; window or position, make it nil instead. |
| 496 | ;; currently being tracked, clear `touch-screen-current-tool'. | 592 | (setq touch-screen-current-tool (and (windowp window) |
| 497 | (when (eq (caadr event) (car touch-screen-current-tool)) | 593 | (list touchpoint window |
| 498 | ;; Cancel the touch screen long-press timer, if it is still there | 594 | (posn-x-y position) |
| 499 | ;; by any chance. | 595 | nil position |
| 500 | (when touch-screen-current-timer | 596 | nil nil nil nil))) |
| 501 | (cancel-timer touch-screen-current-timer) | 597 | ;; Determine if there is a command bound to `down-mouse-1' at |
| 502 | (setq touch-screen-current-timer nil)) | 598 | ;; the position of the tap and that command is not a command |
| 503 | (touch-screen-handle-point-up (cadr event)) | 599 | ;; whose functionality is replaced by the long-press mechanism. |
| 504 | (setq touch-screen-current-tool nil))))) | 600 | ;; If so, set the fourth element of `touch-screen-current-tool' |
| 505 | 601 | ;; to `mouse-drag' and generate an emulated `mouse-1' event. | |
| 506 | (define-key global-map [touchscreen-begin] #'touch-screen-handle-touch) | 602 | (if (and touch-screen-current-tool |
| 507 | (define-key global-map [touchscreen-update] #'touch-screen-handle-touch) | 603 | (with-selected-window window |
| 508 | (define-key global-map [touchscreen-end] #'touch-screen-handle-touch) | 604 | (let ((binding (key-binding (if prefix |
| 605 | (vector prefix | ||
| 606 | 'down-mouse-1) | ||
| 607 | [down-mouse-1]) | ||
| 608 | t nil position))) | ||
| 609 | (and binding | ||
| 610 | (not (and (symbolp binding) | ||
| 611 | (get binding 'ignored-mouse-command))))))) | ||
| 612 | (progn (setcar (nthcdr 3 touch-screen-current-tool) | ||
| 613 | 'mouse-drag) | ||
| 614 | (throw 'input-event (list 'down-mouse-1 position))) | ||
| 615 | (and point | ||
| 616 | ;; Start the long-press timer. | ||
| 617 | (touch-screen-handle-timeout nil))))) | ||
| 618 | ((eq (car event) 'touchscreen-update) | ||
| 619 | ;; The positions of tools currently pressed against the screen | ||
| 620 | ;; have changed. If there is a tool being tracked as part of a | ||
| 621 | ;; gesture, look it up in the list of tools. | ||
| 622 | (let ((new-point (assq (car touch-screen-current-tool) | ||
| 623 | (cadr event)))) | ||
| 624 | (when new-point | ||
| 625 | (touch-screen-handle-point-update new-point)))) | ||
| 626 | ((eq (car event) 'touchscreen-end) | ||
| 627 | ;; A tool has been removed from the screen. If it is the tool | ||
| 628 | ;; currently being tracked, clear `touch-screen-current-tool'. | ||
| 629 | (when (eq (caadr event) (car touch-screen-current-tool)) | ||
| 630 | ;; Cancel the touch screen long-press timer, if it is still there | ||
| 631 | ;; by any chance. | ||
| 632 | (when touch-screen-current-timer | ||
| 633 | (cancel-timer touch-screen-current-timer) | ||
| 634 | (setq touch-screen-current-timer nil)) | ||
| 635 | (unwind-protect | ||
| 636 | (touch-screen-handle-point-up (cadr event) prefix) | ||
| 637 | ;; Make sure the tool list is cleared even if | ||
| 638 | ;; `touch-screen-handle-point-up' throws. | ||
| 639 | (setq touch-screen-current-tool nil))) | ||
| 640 | ;; Throw to the key translation function. | ||
| 641 | (throw 'input-event nil))))) | ||
| 642 | |||
| 643 | ;; Mark `mouse-drag-region' as ignored for the purposes of mouse click | ||
| 644 | ;; emulation. | ||
| 645 | |||
| 646 | (put 'mouse-drag-region 'ignored-mouse-command t) | ||
| 647 | |||
| 648 | (defun touch-screen-translate-touch (prompt) | ||
| 649 | "Translate touch screen events into a sequence of mouse events. | ||
| 650 | PROMPT is the prompt string given to `read-key-sequence', or nil | ||
| 651 | if this function is being called from the keyboard command loop. | ||
| 652 | Value is a new key sequence. | ||
| 653 | |||
| 654 | Read the touch screen event within `current-key-remap-sequence' | ||
| 655 | and give it to `touch-screen-handle-touch'. Return any key | ||
| 656 | sequence signaled. | ||
| 657 | |||
| 658 | If `touch-screen-handle-touch' does not signal for an event to be | ||
| 659 | returned after the last element of the key sequence is read, | ||
| 660 | continue reading touch screen events until | ||
| 661 | `touch-screen-handle-touch' signals. Return a sequence | ||
| 662 | consisting of the first event encountered that is not a touch | ||
| 663 | screen event. | ||
| 664 | |||
| 665 | In addition to non-touchscreen events read, key sequences | ||
| 666 | returned may contain any one of the following events: | ||
| 667 | |||
| 668 | (touchscreen-scroll WINDOW DX DY) | ||
| 669 | |||
| 670 | where WINDOW specifies a window to scroll, and DX and DY are | ||
| 671 | integers describing how many pixels to be scrolled horizontally | ||
| 672 | and vertically. | ||
| 673 | |||
| 674 | (down-mouse-1 POSN) | ||
| 675 | (drag-mouse-1 POSN) | ||
| 676 | |||
| 677 | where POSN is the position of the mouse button press or click. | ||
| 678 | |||
| 679 | (mouse-1 POSN) | ||
| 680 | (mouse-2 POSN) | ||
| 681 | |||
| 682 | where POSN is the position of the mouse click, either `mouse-2' | ||
| 683 | if POSN is on a link or a button, or `mouse-1' otherwise." | ||
| 684 | (if (> (length current-key-remap-sequence) 0) | ||
| 685 | ;; Save the virtual function key if this is a mode line event. | ||
| 686 | (let* ((prefix (and (> (length current-key-remap-sequence) 1) | ||
| 687 | (aref current-key-remap-sequence 0))) | ||
| 688 | (touch-screen-translate-prompt prompt) | ||
| 689 | (event (catch 'input-event | ||
| 690 | ;; First, process the one event already within | ||
| 691 | ;; `current-key-remap-sequence'. | ||
| 692 | (touch-screen-handle-touch | ||
| 693 | (aref current-key-remap-sequence | ||
| 694 | (if prefix 1 0)) | ||
| 695 | prefix) | ||
| 696 | ;; Next, continue reading input events. | ||
| 697 | (while t | ||
| 698 | (let ((event1 (read-event))) | ||
| 699 | ;; If event1 is a virtual function key, make | ||
| 700 | ;; it the new prefix. | ||
| 701 | (if (memq event1 '(mode-line tab-line | ||
| 702 | header-line tool-bar tab-bar | ||
| 703 | left-fringe right-fringe | ||
| 704 | left-margin right-margin | ||
| 705 | right-divider bottom-divider)) | ||
| 706 | (setq prefix event1) | ||
| 707 | ;; If event1 is not a touch screen event, return | ||
| 708 | ;; it. | ||
| 709 | (if (not (memq (car-safe event1) | ||
| 710 | '(touchscreen-begin | ||
| 711 | touchscreen-end | ||
| 712 | touchscreen-update))) | ||
| 713 | (throw 'input-event event1) | ||
| 714 | ;; Process this event as well. | ||
| 715 | (touch-screen-handle-touch event1 prefix)))))))) | ||
| 716 | ;; Return a key sequence consisting of event | ||
| 717 | ;; or an empty vector if it is nil, meaning that | ||
| 718 | ;; no key events have been translated. | ||
| 719 | (if event (or (and prefix (consp event) | ||
| 720 | ;; If this is a mode line event, then generate | ||
| 721 | ;; the appropriate function key. | ||
| 722 | (vector prefix event)) | ||
| 723 | (vector event)) | ||
| 724 | "")))) | ||
| 725 | |||
| 726 | (define-key function-key-map [touchscreen-begin] | ||
| 727 | #'touch-screen-translate-touch) | ||
| 728 | (define-key function-key-map [touchscreen-update] | ||
| 729 | #'touch-screen-translate-touch) | ||
| 730 | (define-key function-key-map [touchscreen-end] | ||
| 731 | #'touch-screen-translate-touch) | ||
| 732 | |||
| 733 | (define-key function-key-map [mode-line touchscreen-begin] | ||
| 734 | #'touch-screen-translate-touch) | ||
| 735 | (define-key function-key-map [mode-line touchscreen-update] | ||
| 736 | #'touch-screen-translate-touch) | ||
| 737 | (define-key function-key-map [mode-line touchscreen-end] | ||
| 738 | #'touch-screen-translate-touch) | ||
| 739 | |||
| 740 | (define-key function-key-map [header-line touchscreen-begin] | ||
| 741 | #'touch-screen-translate-touch) | ||
| 742 | (define-key function-key-map [header-line touchscreen-update] | ||
| 743 | #'touch-screen-translate-touch) | ||
| 744 | (define-key function-key-map [header-line touchscreen-end] | ||
| 745 | #'touch-screen-translate-touch) | ||
| 746 | |||
| 747 | (define-key function-key-map [bottom-divider touchscreen-begin] | ||
| 748 | #'touch-screen-translate-touch) | ||
| 749 | (define-key function-key-map [bottom-divider touchscreen-update] | ||
| 750 | #'touch-screen-translate-touch) | ||
| 751 | (define-key function-key-map [bottom-divider touchscreen-end] | ||
| 752 | #'touch-screen-translate-touch) | ||
| 753 | |||
| 754 | (define-key function-key-map [right-divider touchscreen-begin] | ||
| 755 | #'touch-screen-translate-touch) | ||
| 756 | (define-key function-key-map [right-divider touchscreen-update] | ||
| 757 | #'touch-screen-translate-touch) | ||
| 758 | (define-key function-key-map [right-divider touchscreen-end] | ||
| 759 | #'touch-screen-translate-touch) | ||
| 760 | |||
| 761 | (define-key function-key-map [right-divider touchscreen-begin] | ||
| 762 | #'touch-screen-translate-touch) | ||
| 763 | (define-key function-key-map [right-divider touchscreen-update] | ||
| 764 | #'touch-screen-translate-touch) | ||
| 765 | (define-key function-key-map [right-divider touchscreen-end] | ||
| 766 | #'touch-screen-translate-touch) | ||
| 767 | |||
| 768 | (define-key function-key-map [left-fringe touchscreen-begin] | ||
| 769 | #'touch-screen-translate-touch) | ||
| 770 | (define-key function-key-map [left-fringe touchscreen-update] | ||
| 771 | #'touch-screen-translate-touch) | ||
| 772 | (define-key function-key-map [left-fringe touchscreen-end] | ||
| 773 | #'touch-screen-translate-touch) | ||
| 774 | |||
| 775 | (define-key function-key-map [right-fringe touchscreen-begin] | ||
| 776 | #'touch-screen-translate-touch) | ||
| 777 | (define-key function-key-map [right-fringe touchscreen-update] | ||
| 778 | #'touch-screen-translate-touch) | ||
| 779 | (define-key function-key-map [right-fringe touchscreen-end] | ||
| 780 | #'touch-screen-translate-touch) | ||
| 781 | |||
| 782 | (define-key function-key-map [left-margin touchscreen-begin] | ||
| 783 | #'touch-screen-translate-touch) | ||
| 784 | (define-key function-key-map [left-margin touchscreen-update] | ||
| 785 | #'touch-screen-translate-touch) | ||
| 786 | (define-key function-key-map [left-margin touchscreen-end] | ||
| 787 | #'touch-screen-translate-touch) | ||
| 788 | |||
| 789 | (define-key function-key-map [right-margin touchscreen-begin] | ||
| 790 | #'touch-screen-translate-touch) | ||
| 791 | (define-key function-key-map [right-margin touchscreen-update] | ||
| 792 | #'touch-screen-translate-touch) | ||
| 793 | (define-key function-key-map [right-margin touchscreen-end] | ||
| 794 | #'touch-screen-translate-touch) | ||
| 509 | 795 | ||
| 510 | 796 | ||
| 511 | ;; Exports. These functions are intended for use externally. | 797 | ;; Exports. These functions are intended for use externally. |
| @@ -582,149 +868,6 @@ touch point in EVENT did not move significantly, and t otherwise." | |||
| 582 | 868 | ||
| 583 | 869 | ||
| 584 | 870 | ||
| 585 | ;; Modeline dragging. | ||
| 586 | |||
| 587 | (defun touch-screen-drag-mode-line-1 (event) | ||
| 588 | "Internal helper for `touch-screen-drag-mode-line'. | ||
| 589 | This is called when that function determines that no drag really | ||
| 590 | happened. EVENT is the same as in `touch-screen-drag-mode-line'." | ||
| 591 | ;; If there is an object at EVENT, then look either a keymap bound | ||
| 592 | ;; to [down-mouse-1] or a command bound to [mouse-1]. Then, if a | ||
| 593 | ;; keymap was found, pop it up as a menu. Otherwise, wait for a tap | ||
| 594 | ;; to complete and run the command found. | ||
| 595 | ;; Also, select the window in EVENT. | ||
| 596 | (select-window (posn-window (cdadr event))) | ||
| 597 | (let* ((object (posn-object (cdadr event))) | ||
| 598 | (object-keymap (and (consp object) | ||
| 599 | (stringp (car object)) | ||
| 600 | (or (get-text-property (cdr object) | ||
| 601 | 'keymap | ||
| 602 | (car object)) | ||
| 603 | (get-text-property (cdr object) | ||
| 604 | 'local-map | ||
| 605 | (car object))))) | ||
| 606 | (keymap (lookup-key object-keymap [mode-line down-mouse-1])) | ||
| 607 | (command (or (lookup-key object-keymap [mode-line mouse-1]) | ||
| 608 | keymap))) | ||
| 609 | (when (or (keymapp keymap) command) | ||
| 610 | (if (keymapp keymap) | ||
| 611 | (when-let* ((command (x-popup-menu event keymap)) | ||
| 612 | (tem (lookup-key keymap | ||
| 613 | (if (consp command) | ||
| 614 | (apply #'vector command) | ||
| 615 | (vector command)) | ||
| 616 | t))) | ||
| 617 | (call-interactively tem)) | ||
| 618 | (when (commandp command) | ||
| 619 | (call-interactively command nil | ||
| 620 | (vector (list 'mouse-1 (cdadr event))))))))) | ||
| 621 | |||
| 622 | (defun touch-screen-drag-mode-line (event) | ||
| 623 | "Begin dragging the mode line in response to a touch EVENT. | ||
| 624 | Change the height of the window based on where the touch point in | ||
| 625 | EVENT moves. | ||
| 626 | |||
| 627 | If it does not actually move anywhere and the touch point is | ||
| 628 | removed, and EVENT lies on top of text with a mouse command | ||
| 629 | bound, run that command instead." | ||
| 630 | (interactive "e") | ||
| 631 | ;; Find the window that should be dragged and the starting position. | ||
| 632 | (let* ((window (posn-window (cdadr event))) | ||
| 633 | (relative-xy (touch-screen-relative-xy (cdadr event) | ||
| 634 | 'frame)) | ||
| 635 | (last-position (cdr relative-xy))) | ||
| 636 | (when (window-resizable window 0) | ||
| 637 | (when (eq | ||
| 638 | (touch-screen-track-drag | ||
| 639 | event (lambda (new-event &optional _data) | ||
| 640 | ;; Find the position of the touchpoint in | ||
| 641 | ;; NEW-EVENT. | ||
| 642 | (let* ((touchpoint (assq (caadr event) | ||
| 643 | (cadr new-event))) | ||
| 644 | (new-relative-xy | ||
| 645 | (touch-screen-relative-xy (cdr touchpoint) 'frame)) | ||
| 646 | (position (cdr new-relative-xy)) | ||
| 647 | (window-resize-pixelwise t) | ||
| 648 | growth) | ||
| 649 | ;; Now set the new height of the window. If | ||
| 650 | ;; new-relative-y is above relative-xy, then | ||
| 651 | ;; make the window that much shorter. | ||
| 652 | ;; Otherwise, make it bigger. | ||
| 653 | (unless (or (zerop (setq growth | ||
| 654 | (- position last-position))) | ||
| 655 | (and (> growth 0) | ||
| 656 | (< position | ||
| 657 | (+ (window-pixel-top window) | ||
| 658 | (window-pixel-height window)))) | ||
| 659 | (and (< growth 0) | ||
| 660 | (> position | ||
| 661 | (+ (window-pixel-top window) | ||
| 662 | (window-pixel-height window))))) | ||
| 663 | (when (ignore-errors | ||
| 664 | (adjust-window-trailing-edge window growth nil t) t) | ||
| 665 | (setq last-position position)))))) | ||
| 666 | 'no-drag) | ||
| 667 | ;; Dragging did not actually happen, so try to run any command | ||
| 668 | ;; necessary. | ||
| 669 | (touch-screen-drag-mode-line-1 event))))) | ||
| 670 | |||
| 671 | (global-set-key [mode-line touchscreen-begin] | ||
| 672 | #'touch-screen-drag-mode-line) | ||
| 673 | (global-set-key [bottom-divider touchscreen-begin] | ||
| 674 | #'touch-screen-drag-mode-line) | ||
| 675 | |||
| 676 | |||
| 677 | |||
| 678 | ;; Header line tapping. | ||
| 679 | |||
| 680 | (defun touch-screen-tap-header-line (event) | ||
| 681 | "Handle a `touchscreen-begin' EVENT on the header line. | ||
| 682 | Wait for the tap to complete, then run any command bound to | ||
| 683 | `mouse-1' at the position of EVENT. | ||
| 684 | |||
| 685 | If another keymap is bound to `down-mouse-1', then display a menu | ||
| 686 | with its contents instead, and run the selected command." | ||
| 687 | (interactive "e") | ||
| 688 | (let* ((posn (cdadr event)) | ||
| 689 | (object (posn-object posn)) | ||
| 690 | ;; Look for the keymap defined by the object itself. | ||
| 691 | (object-keymap (and (consp object) | ||
| 692 | (stringp (car object)) | ||
| 693 | (or (get-text-property (cdr object) | ||
| 694 | 'keymap | ||
| 695 | (car object)) | ||
| 696 | (get-text-property (cdr object) | ||
| 697 | 'local-map | ||
| 698 | (car object))))) | ||
| 699 | command keymap) | ||
| 700 | ;; Now look for either a command bound to `mouse-1' or a keymap | ||
| 701 | ;; bound to `down-mouse-1'. | ||
| 702 | (with-selected-window (posn-window posn) | ||
| 703 | (setq command (lookup-key object-keymap | ||
| 704 | [header-line mouse-1] t) | ||
| 705 | keymap (lookup-key object-keymap | ||
| 706 | [header-line down-mouse-1] t)) | ||
| 707 | (unless (keymapp keymap) | ||
| 708 | (setq keymap nil))) | ||
| 709 | ;; Wait for the tap to complete. | ||
| 710 | (when (touch-screen-track-tap event) | ||
| 711 | ;; Select the window whose header line was clicked. | ||
| 712 | (with-selected-window (posn-window posn) | ||
| 713 | (if keymap | ||
| 714 | (when-let* ((command (x-popup-menu event keymap)) | ||
| 715 | (tem (lookup-key keymap | ||
| 716 | (if (consp command) | ||
| 717 | (apply #'vector command) | ||
| 718 | (vector command)) | ||
| 719 | t))) | ||
| 720 | (call-interactively tem)) | ||
| 721 | (when (commandp command) | ||
| 722 | (call-interactively command nil | ||
| 723 | (vector (list 'mouse-1 (cdadr event)))))))))) | ||
| 724 | |||
| 725 | (global-set-key [header-line touchscreen-begin] | ||
| 726 | #'touch-screen-tap-header-line) | ||
| 727 | |||
| 728 | (provide 'touch-screen) | 871 | (provide 'touch-screen) |
| 729 | 872 | ||
| 730 | ;;; touch-screen ends here | 873 | ;;; touch-screen ends here |
diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el index 4df1fb7ab08..fa801cab51b 100644 --- a/lisp/wid-edit.el +++ b/lisp/wid-edit.el | |||
| @@ -1193,8 +1193,7 @@ If nothing was called, return non-nil." | |||
| 1193 | ;; up event. | 1193 | ;; up event. |
| 1194 | (cond | 1194 | (cond |
| 1195 | ((eq (car event) 'touchscreen-begin) | 1195 | ((eq (car event) 'touchscreen-begin) |
| 1196 | (setq command (lookup-key widget-global-map | 1196 | (setq command 'touch-screen-handle-touch)) |
| 1197 | [touchscreen-begin]))) | ||
| 1198 | (mouse-1 (cond ((setq command ;down event | 1197 | (mouse-1 (cond ((setq command ;down event |
| 1199 | (lookup-key widget-global-map [down-mouse-1])) | 1198 | (lookup-key widget-global-map [down-mouse-1])) |
| 1200 | (setq up nil)) | 1199 | (setq up nil)) |
| @@ -1213,6 +1212,11 @@ If nothing was called, return non-nil." | |||
| 1213 | (call-interactively command))))) | 1212 | (call-interactively command))))) |
| 1214 | (message "You clicked somewhere weird."))) | 1213 | (message "You clicked somewhere weird."))) |
| 1215 | 1214 | ||
| 1215 | ;; Make sure `touch-screen-handle-touch' abstains from emulating | ||
| 1216 | ;; down-mouse-1 events for `widget-button-click'. | ||
| 1217 | |||
| 1218 | (put 'widget-button-click 'ignored-mouse-command t) | ||
| 1219 | |||
| 1216 | (defun widget-button-press (pos &optional event) | 1220 | (defun widget-button-press (pos &optional event) |
| 1217 | "Invoke button at POS." | 1221 | "Invoke button at POS." |
| 1218 | (interactive "@d") | 1222 | (interactive "@d") |
diff --git a/src/keyboard.c b/src/keyboard.c index ea07c538aa2..e10128def13 100644 --- a/src/keyboard.c +++ b/src/keyboard.c | |||
| @@ -9994,13 +9994,18 @@ typedef struct keyremap | |||
| 9994 | If the mapping is a function and DO_FUNCALL is true, | 9994 | If the mapping is a function and DO_FUNCALL is true, |
| 9995 | the function is called with PROMPT as parameter and its return | 9995 | the function is called with PROMPT as parameter and its return |
| 9996 | value is used as the return value of this function (after checking | 9996 | value is used as the return value of this function (after checking |
| 9997 | that it is indeed a vector). */ | 9997 | that it is indeed a vector). |
| 9998 | |||
| 9999 | START and END are the indices of the first and last key of the | ||
| 10000 | sequence being remapped within the keyboard buffer KEYBUF. */ | ||
| 9998 | 10001 | ||
| 9999 | static Lisp_Object | 10002 | static Lisp_Object |
| 10000 | access_keymap_keyremap (Lisp_Object map, Lisp_Object key, Lisp_Object prompt, | 10003 | access_keymap_keyremap (Lisp_Object map, Lisp_Object key, Lisp_Object prompt, |
| 10001 | bool do_funcall) | 10004 | bool do_funcall, ptrdiff_t start, ptrdiff_t end, |
| 10005 | Lisp_Object *keybuf) | ||
| 10002 | { | 10006 | { |
| 10003 | Lisp_Object next; | 10007 | Lisp_Object next; |
| 10008 | specpdl_ref count; | ||
| 10004 | 10009 | ||
| 10005 | next = access_keymap (map, key, 1, 0, 1); | 10010 | next = access_keymap (map, key, 1, 0, 1); |
| 10006 | 10011 | ||
| @@ -10016,10 +10021,18 @@ access_keymap_keyremap (Lisp_Object map, Lisp_Object key, Lisp_Object prompt, | |||
| 10016 | its value instead. */ | 10021 | its value instead. */ |
| 10017 | if (do_funcall && FUNCTIONP (next)) | 10022 | if (do_funcall && FUNCTIONP (next)) |
| 10018 | { | 10023 | { |
| 10019 | Lisp_Object tem; | 10024 | Lisp_Object tem, remap; |
| 10020 | tem = next; | 10025 | tem = next; |
| 10021 | 10026 | ||
| 10022 | next = call1 (next, prompt); | 10027 | /* Build Vcurrent_key_remap_sequence. */ |
| 10028 | remap = Fvector (end - start + 1, keybuf + start); | ||
| 10029 | |||
| 10030 | /* Bind `current-key-remap-sequence' to the key sequence being | ||
| 10031 | remapped. */ | ||
| 10032 | count = SPECPDL_INDEX (); | ||
| 10033 | specbind (Qcurrent_key_remap_sequence, remap); | ||
| 10034 | next = unbind_to (count, call1 (next, prompt)); | ||
| 10035 | |||
| 10023 | /* If the function returned something invalid, | 10036 | /* If the function returned something invalid, |
| 10024 | barf--don't ignore it. */ | 10037 | barf--don't ignore it. */ |
| 10025 | if (! (NILP (next) || VECTORP (next) || STRINGP (next))) | 10038 | if (! (NILP (next) || VECTORP (next) || STRINGP (next))) |
| @@ -10044,11 +10057,17 @@ keyremap_step (Lisp_Object *keybuf, volatile keyremap *fkey, | |||
| 10044 | int input, bool doit, int *diff, Lisp_Object prompt) | 10057 | int input, bool doit, int *diff, Lisp_Object prompt) |
| 10045 | { | 10058 | { |
| 10046 | Lisp_Object next, key; | 10059 | Lisp_Object next, key; |
| 10060 | ptrdiff_t buf_start, buf_end; | ||
| 10061 | |||
| 10062 | /* Save the key sequence being translated. */ | ||
| 10063 | buf_start = fkey->start; | ||
| 10064 | buf_end = fkey->end; | ||
| 10047 | 10065 | ||
| 10048 | key = keybuf[fkey->end++]; | 10066 | key = keybuf[fkey->end++]; |
| 10049 | 10067 | ||
| 10050 | if (KEYMAPP (fkey->parent)) | 10068 | if (KEYMAPP (fkey->parent)) |
| 10051 | next = access_keymap_keyremap (fkey->map, key, prompt, doit); | 10069 | next = access_keymap_keyremap (fkey->map, key, prompt, doit, |
| 10070 | buf_start, buf_end, keybuf); | ||
| 10052 | else | 10071 | else |
| 10053 | next = Qnil; | 10072 | next = Qnil; |
| 10054 | 10073 | ||
| @@ -12479,6 +12498,7 @@ static const struct event_head head_table[] = { | |||
| 12479 | {SYMBOL_INDEX (Qselect_window), SYMBOL_INDEX (Qswitch_frame)}, | 12498 | {SYMBOL_INDEX (Qselect_window), SYMBOL_INDEX (Qswitch_frame)}, |
| 12480 | /* Touchscreen events should be prefixed by the posn. */ | 12499 | /* Touchscreen events should be prefixed by the posn. */ |
| 12481 | {SYMBOL_INDEX (Qtouchscreen_begin), SYMBOL_INDEX (Qtouchscreen)}, | 12500 | {SYMBOL_INDEX (Qtouchscreen_begin), SYMBOL_INDEX (Qtouchscreen)}, |
| 12501 | {SYMBOL_INDEX (Qtouchscreen_end), SYMBOL_INDEX (Qtouchscreen)}, | ||
| 12482 | }; | 12502 | }; |
| 12483 | 12503 | ||
| 12484 | static Lisp_Object | 12504 | static Lisp_Object |
| @@ -13575,6 +13595,15 @@ If non-nil, text conversion will continue to happen after a prefix | |||
| 13575 | key has been read inside `read-key-sequence'. */); | 13595 | key has been read inside `read-key-sequence'. */); |
| 13576 | disable_inhibit_text_conversion = false; | 13596 | disable_inhibit_text_conversion = false; |
| 13577 | 13597 | ||
| 13598 | DEFVAR_LISP ("current-key-remap-sequence", | ||
| 13599 | Vcurrent_key_remap_sequence, | ||
| 13600 | doc: /* The key sequence currently being remap, or nil. | ||
| 13601 | Bound to a vector containing the sub-sequence matching a binding | ||
| 13602 | within `input-decode-map' or `local-function-key-map' when its bound | ||
| 13603 | function is called to remap that sequence. */); | ||
| 13604 | Vcurrent_key_remap_sequence = Qnil; | ||
| 13605 | DEFSYM (Qcurrent_key_remap_sequence, "current-key-remap-sequence"); | ||
| 13606 | |||
| 13578 | pdumper_do_now_and_after_load (syms_of_keyboard_for_pdumper); | 13607 | pdumper_do_now_and_after_load (syms_of_keyboard_for_pdumper); |
| 13579 | } | 13608 | } |
| 13580 | 13609 | ||