]> git.eshelyaron.com Git - emacs.git/commitdiff
Make libraries works with xterm-mouse-mode.
authorJared Finder <jared@finder.org>
Sat, 2 Jan 2021 22:10:17 +0000 (14:10 -0800)
committerEli Zaretskii <eliz@gnu.org>
Fri, 15 Jan 2021 11:50:07 +0000 (13:50 +0200)
Change calls from 'read-event' to 'read-key' in libraries expecting
mouse events.  Do this only when 'xterm-mouse-mode' is enabled.  That
way those libraries read decoded mouse events instead of the
underlying escape sequence.  Add a parameter to 'read-key' that avoids
running any of the unbound fallbacks in 'read-key-sequence' so the
libraries can read mouse button-down events.

For backward compatibility purposes, the above logic is contained in a
new internal-only function: 'read--potential-mouse-event'.

* doc/lispref/commands.texi (Reading One Event): Document new
parameter to 'read-key'.  Mention that non-character events on
terminals need 'read-key'.
* lisp/subr.el (read-key-full-map): Add new keymap used by 'read-key'.
(read-key): Add new parameter 'fallbacks-disabled' to prevent running
any of the unbound fallbacks normally run by 'read-key-sequence'.
(read--potential-mouse-event): Add new function that calls 'read-key'
or 'read-event' depending on if 'xterm-mouse-mode' is set.
* lisp/foldout.el (foldout-mouse-swallow-events):
* lisp/isearch.el (isearch-pre-command-hook):
* lisp/mouse-drag.el (mouse-drag-throw, mouse-drag-drag):
* lisp/mouse.el (mouse-drag-secondary):
* lisp/ruler-mode.el (ruler-mode-mouse-grab-any-column)
(ruler-mode-mouse-drag-any-column-iteration):
* lisp/strokes.el (strokes-read-stroke, strokes-read-complex-stroke):
* lisp/textmodes/artist.el (artist-mouse-draw-continously)
(artist-mouse-draw-poly, artist-mouse-draw-2points):
* lisp/vc/ediff-wind.el (ediff-get-window-by-clicking):
* lisp/wid-edit.el (widget-button--check-and-call-button)
(widget-button-click): Call 'read--potential-mouse-event' instead of
'read-event'.
* lisp/wid-edit.el (widget-key-sequence-read-event): Call 'read-key'
with 'fallbacks-disabled' set instead of 'read-event'.  Unlike above
changes, this is unconditionally applied so it works for function
keys too.  Apply 'local-function-key-map' instead of
'function-key-map' as that contains the full terminal translations.
* lisp/vc/ediff.el (ediff-windows): Use 'display-mouse-p' to check if
a mouse is available.
* src/lread.c (Fread_event): Recommend 'read-key' in docstring for
'read-event' for non-character events.

13 files changed:
doc/lispref/commands.texi
lisp/foldout.el
lisp/isearch.el
lisp/mouse-drag.el
lisp/mouse.el
lisp/ruler-mode.el
lisp/strokes.el
lisp/subr.el
lisp/textmodes/artist.el
lisp/vc/ediff-wind.el
lisp/vc/ediff.el
lisp/wid-edit.el
src/lread.c

index 6c68f70482a03640a76d16c78d75915934aef296..3a2c7d019ef094222517fe2d89927ec34cf1177c 100644 (file)
@@ -2696,9 +2696,11 @@ from the terminal---not counting those generated by keyboard macros.
 @code{read-event}, @code{read-char}, and @code{read-char-exclusive} do
 not perform the translations described in @ref{Translation Keymaps}.
 If you wish to read a single key taking these translations into
-account, use the function @code{read-key}:
+account (for example, to read @ref{Function Keys} in a terminal or
+@ref{Mouse Events} from @code{xterm-mouse-mode}), use the function
+@code{read-key}:
 
-@defun read-key &optional prompt
+@defun read-key &optional prompt disable-fallbacks
 This function reads a single key.  It is intermediate between
 @code{read-key-sequence} and @code{read-event}.  Unlike the former, it
 reads a single key, not a key sequence.  Unlike the latter, it does
@@ -2708,6 +2710,14 @@ and @code{key-translation-map} (@pxref{Translation Keymaps}).
 
 The argument @var{prompt} is either a string to be displayed in the
 echo area as a prompt, or @code{nil}, meaning not to display a prompt.
+
+If argument @var{disable-fallbacks} is non-@code{nil} then the usual
+fallback logic for unbound keys in @code{read-key-sequence} is not
+applied.  This means that mouse button-down and multi-click events
+will not be discarded and @code{local-function-key-map} and
+@code{key-translation-map} will not get applied.  If @code{nil} or
+unspecified, the only fallback disabled is downcasing of the last
+event.
 @end defun
 
 @defun read-char-choice prompt chars &optional inhibit-quit
index 771b81e5be5372691766cfeb9d7278a7bf9627c4..4c479d68e9a63570abe68143ecd4780863bb5b32 100644 (file)
@@ -487,7 +487,7 @@ What happens depends on the number of mouse clicks:-
 Signal an error if the final event isn't the same type as the first one."
   (let ((initial-event-type (event-basic-type event)))
     (while (null (sit-for (/ double-click-time 1000.0) 'nodisplay))
-      (setq event (read-event)))
+      (setq event (read--potential-mouse-event)))
     (or (eq initial-event-type (event-basic-type event))
        (error "")))
   event)
index d8d3a731a4b209d6a7404a8a02956874873176ad..c6f7fe7bd4aff847c683ec178e146ae17cf010e4 100644 (file)
@@ -3002,7 +3002,7 @@ See more for options in `search-exit-option'."
      ((and (eq (car-safe main-event) 'down-mouse-1)
           (window-minibuffer-p (posn-window (event-start main-event))))
       ;; Swallow the up-event.
-      (read-event)
+      (read--potential-mouse-event)
       (setq this-command 'isearch-edit-string))
      ;; Don't terminate the search for motion commands.
      ((and isearch-yank-on-move
index f6612600bdd2dcb32fba86a402b397ec4c10034e..907ef0615941f9e46b077c8eb1d238884ce3d8a5 100644 (file)
@@ -225,7 +225,7 @@ To test this function, evaluate:
       ;; Don't change the mouse pointer shape while we drag.
       (setq track-mouse 'dragging)
       (while (progn
-              (setq event (read-event)
+              (setq event (read--potential-mouse-event)
                     end (event-end event)
                     row (cdr (posn-col-row end))
                     col (car (posn-col-row end)))
@@ -286,7 +286,7 @@ To test this function, evaluate:
          window-last-col (- (window-width) 2))
     (track-mouse
       (while (progn
-              (setq event (read-event)
+              (setq event (read--potential-mouse-event)
                     end (event-end event)
                     row (cdr (posn-col-row end))
                     col (car (posn-col-row end)))
index 0da82882fc107b209ffc76cf1ab2d914ba99cab7..8732fb8086666d06266ec36ef9e9041b19f4a073 100644 (file)
@@ -1792,7 +1792,7 @@ The function returns a non-nil value if it creates a secondary selection."
       (let (event end end-point)
        (track-mouse
          (while (progn
-                  (setq event (read-event))
+                  (setq event (read--potential-mouse-event))
                   (or (mouse-movement-p event)
                       (memq (car-safe event) '(switch-frame select-window))))
 
index 7cda6c96affd821e084ace1bab15d1504349baf6..1e819044194bde1531a408a01442c1a9cd23ad02 100644 (file)
@@ -429,7 +429,7 @@ dragging.  See also the variable `ruler-mode-dragged-symbol'."
          ;; `ding' flushes the next messages about setting goal
          ;; column.  So here I force fetch the event(mouse-2) and
          ;; throw away.
-         (read-event)
+         (read--potential-mouse-event)
          ;; Ding BEFORE `message' is OK.
          (when ruler-mode-set-goal-column-ding-flag
            (ding))
@@ -460,7 +460,7 @@ the mouse has been clicked."
     (track-mouse
       ;; Signal the display engine to freeze the mouse pointer shape.
       (setq track-mouse 'dragging)
-      (while (mouse-movement-p (setq event (read-event)))
+      (while (mouse-movement-p (setq event (read--potential-mouse-event)))
         (setq drags (1+ drags))
         (when (eq window (posn-window (event-end event)))
           (ruler-mode-mouse-drag-any-column event)
index b0ab4f990f601dbd45280025c552587bbcae74bf..55f2ae8cc477248ad49e70c6d676a606fb18b7ed 100644 (file)
@@ -756,12 +756,12 @@ Optional EVENT is acceptable as the starting event of the stroke."
              (strokes-fill-current-buffer-with-whitespace))
            (when prompt
              (message "%s" prompt)
-             (setq event (read-event))
+             (setq event (read--potential-mouse-event))
              (or (strokes-button-press-event-p event)
                  (error "You must draw with the mouse")))
            (unwind-protect
                (track-mouse
-                 (or event (setq event (read-event)
+                 (or event (setq event (read--potential-mouse-event)
                                  safe-to-draw-p t))
                  (while (not (strokes-button-release-event-p event))
                    (if (strokes-mouse-event-p event)
@@ -776,7 +776,7 @@ Optional EVENT is acceptable as the starting event of the stroke."
                            (setq safe-to-draw-p t))
                          (push (cdr (mouse-pixel-position))
                                pix-locs)))
-                   (setq event (read-event)))))
+                   (setq event (read--potential-mouse-event)))))
            ;; protected
            ;; clean up strokes buffer and then bury it.
            (when (equal (buffer-name) strokes-buffer-name)
@@ -787,16 +787,16 @@ Optional EVENT is acceptable as the starting event of the stroke."
       ;; Otherwise, don't use strokes buffer and read stroke silently
       (when prompt
        (message "%s" prompt)
-       (setq event (read-event))
+       (setq event (read--potential-mouse-event))
        (or (strokes-button-press-event-p event)
            (error "You must draw with the mouse")))
       (track-mouse
-       (or event (setq event (read-event)))
+       (or event (setq event (read--potential-mouse-event)))
        (while (not (strokes-button-release-event-p event))
          (if (strokes-mouse-event-p event)
              (push (cdr (mouse-pixel-position))
                    pix-locs))
-         (setq event (read-event))))
+         (setq event (read--potential-mouse-event))))
       (setq grid-locs (strokes-renormalize-to-grid (nreverse pix-locs)))
       (strokes-fill-stroke
        (strokes-eliminate-consecutive-redundancies grid-locs)))))
@@ -817,10 +817,10 @@ Optional EVENT is acceptable as the starting event of the stroke."
        (if prompt
            (while (not (strokes-button-press-event-p event))
              (message "%s" prompt)
-             (setq event (read-event))))
+             (setq event (read--potential-mouse-event))))
        (unwind-protect
            (track-mouse
-             (or event (setq event (read-event)))
+             (or event (setq event (read--potential-mouse-event)))
              (while (not (and (strokes-button-press-event-p event)
                               (eq 'mouse-3
                                   (car (get (car event)
@@ -834,14 +834,15 @@ Optional EVENT is acceptable as the starting event of the stroke."
                                                ?\s strokes-character))
                        (push (cdr (mouse-pixel-position))
                              pix-locs)))
-                 (setq event (read-event)))
+                 (setq event (read--potential-mouse-event)))
                (push strokes-lift pix-locs)
                (while (not (strokes-button-press-event-p event))
-                 (setq event (read-event))))
+                 (setq event (read--potential-mouse-event))))
              ;; ### KLUDGE! ### sit and wait
              ;; for some useless event to
              ;; happen to fix the minibuffer bug.
-             (while (not (strokes-button-release-event-p (read-event))))
+             (while (not (strokes-button-release-event-p
+                           (read--potential-mouse-event))))
              (setq pix-locs (nreverse (cdr pix-locs))
                    grid-locs (strokes-renormalize-to-grid pix-locs))
              (strokes-fill-stroke
index 9b89e49370265d84ef2aae1da759e6058bdc5a0c..f249ec3578cec6baa8ad9ca26ed3c68608edb82a 100644 (file)
@@ -2569,23 +2569,52 @@ It can be retrieved with `(process-get PROCESS PROPNAME)'."
 \f
 ;;;; Input and display facilities.
 
-(defconst read-key-empty-map (make-sparse-keymap))
+;; The following maps are used by `read-key' to remove all key
+;; bindings while calling `read-key-sequence'.  This way the keys
+;; returned are independent of the key binding state.
+
+(defconst read-key-empty-map (make-sparse-keymap)
+  "Used internally by `read-key'.")
+
+(defconst read-key-full-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map [t] 'dummy)
+
+    ;; ESC needs to be unbound so that escape sequences in
+    ;; `input-decode-map' are still processed by `read-key-sequence'.
+    (define-key map [?\e] nil)
+    map)
+  "Used internally by `read-key'.")
 
 (defvar read-key-delay 0.01) ;Fast enough for 100Hz repeat rate, hopefully.
 
-(defun read-key (&optional prompt)
+(defun read-key (&optional prompt disable-fallbacks)
   "Read a key from the keyboard.
 Contrary to `read-event' this will not return a raw event but instead will
 obey the input decoding and translations usually done by `read-key-sequence'.
 So escape sequences and keyboard encoding are taken into account.
 When there's an ambiguity because the key looks like the prefix of
-some sort of escape sequence, the ambiguity is resolved via `read-key-delay'."
+some sort of escape sequence, the ambiguity is resolved via `read-key-delay'.
+
+If the optional argument PROMPT is non-nil, display that as a
+prompt.
+
+If the optional argument DISABLE-FALLBACKS is non-nil, all
+unbound fallbacks usually done by `read-key-sequence' are
+disabled such as discarding mouse down events.  This is generally
+what you want as `read-key' temporarily removes all bindings
+while calling `read-key-sequence'.  If nil or unspecified, the
+only unbound fallback disabled is downcasing of the last event."
   ;; This overriding-terminal-local-map binding also happens to
   ;; disable quail's input methods, so although read-key-sequence
   ;; always inherits the input method, in practice read-key does not
   ;; inherit the input method (at least not if it's based on quail).
   (let ((overriding-terminal-local-map nil)
-       (overriding-local-map read-key-empty-map)
+       (overriding-local-map
+         ;; FIXME: Audit existing uses of `read-key' to see if they
+         ;; should always specify disable-fallbacks to be more in line
+         ;; with `read-event'.
+         (if disable-fallbacks read-key-full-map read-key-empty-map))
         (echo-keystrokes 0)
        (old-global-map (current-global-map))
         (timer (run-with-idle-timer
@@ -2639,6 +2668,23 @@ some sort of escape sequence, the ambiguity is resolved via `read-key-delay'."
       (message nil)
       (use-global-map old-global-map))))
 
+;; FIXME: Once there's a safe way to transition away from read-event,
+;; callers to this function should be updated to that way and this
+;; function should be deleted.
+(defun read--potential-mouse-event ()
+    "Read an event that might be a mouse event.
+
+This function exists for backward compatibility in code packaged
+with Emacs.  Do not call it directly in your own packages."
+    ;; `xterm-mouse-mode' events must go through `read-key' as they
+    ;; are decoded via `input-decode-map'.
+    (if xterm-mouse-mode
+        (read-key nil
+                  ;; Normally `read-key' discards all mouse button
+                  ;; down events.  However, we want them here.
+                  t)
+      (read-event)))
+
 (defvar read-passwd-map
   ;; BEWARE: `defconst' would purecopy it, breaking the sharing with
   ;; minibuffer-local-map along the way!
index ce620821d65fc99f6f7d1ec09003d96a77143318..50c00c95320577c7a221efb4bae4633b80089e5d 100644 (file)
@@ -5004,7 +5004,7 @@ The event, EV, is the mouse event."
                   (setq timer (run-at-time interval interval draw-fn x1 y1))))
 
             ;; Read next event
-            (setq ev (read-event))))
+            (setq ev (read--potential-mouse-event))))
       ;; Cleanup: get rid of any active timer.
       (if timer
           (cancel-timer timer)))
@@ -5212,7 +5212,7 @@ The event, EV, is the mouse event."
 
        ;; Read next event (only if we should not stop)
        (if (not done)
-           (setq ev (read-event)))))
+           (setq ev (read--potential-mouse-event)))))
 
     ;; Reverse point-list (last points are cond'ed first)
     (setq point-list (reverse point-list))
@@ -5339,7 +5339,7 @@ The event, EV, is the mouse event."
 
 
        ;; Read next event
-       (setq ev (read-event))))
+       (setq ev (read--potential-mouse-event))))
 
     ;; If we are not rubber-banding (that is, we were moving around the `2')
     ;; draw the shape
index 72b345874f9dec601e52f4ba6fce5b0e3b216826..47ef37a19ee41acd3ae73c28d90219ba77033e3b 100644 (file)
@@ -262,11 +262,12 @@ keyboard input to go into icons."
   (let (event)
     (message
      "Select windows by clicking.  Please click on Window %d " wind-number)
-    (while (not (ediff-mouse-event-p (setq event (read-event))))
+    (while (not (ediff-mouse-event-p (setq event
+                                           (read--potential-mouse-event))))
       (if (sit-for 1) ; if sequence of events, wait till the final word
          (beep 1))
       (message "Please click on Window %d " wind-number))
-    (read-event) ; discard event
+    (read--potential-mouse-event) ; discard event
     (posn-window (event-start event))))
 
 
index e3612dd8e3431956f20f098337ca829041085f41..ed375738b475206e8540135ebc56df8bae056eaa 100644 (file)
@@ -939,7 +939,7 @@ arguments after setting up the Ediff buffers."
 ;; If WIND-A is nil, use selected window.
 ;; If WIND-B is nil, use window next to WIND-A.
 (defun ediff-windows (dumb-mode wind-A wind-B startup-hooks job-name word-mode)
-  (if (or dumb-mode (not (ediff-window-display-p)))
+  (if (or dumb-mode (not (display-mouse-p)))
       (setq wind-A (ediff-get-next-window wind-A nil)
            wind-B (ediff-get-next-window wind-B wind-A))
     (setq wind-A (ediff-get-window-by-clicking wind-A nil 1)
index 8b10d71dcb318883061c25d5be0e6d897fb07e4a..7dda04eda21eb0a2b0c67fa2cca370aadb97bff5 100644 (file)
@@ -1104,7 +1104,7 @@ If nothing was called, return non-nil."
                  (unless (widget-apply button :mouse-down-action event)
                    (let ((track-mouse t))
                      (while (not (widget-button-release-event-p event))
-                       (setq event (read-event))
+                        (setq event (read--potential-mouse-event))
                        (when (and mouse-1 (mouse-movement-p event))
                          (push event unread-command-events)
                          (setq event oevent)
@@ -1169,7 +1169,7 @@ If nothing was called, return non-nil."
            (when up
              ;; Don't execute up events twice.
              (while (not (widget-button-release-event-p event))
-               (setq event (read-event))))
+               (setq event (read--potential-mouse-event))))
            (when command
              (call-interactively command)))))
     (message "You clicked somewhere weird.")))
@@ -3486,14 +3486,16 @@ It reads a directory name from an editable text field."
   :help-echo "C-q: insert KEY, EVENT, or CODE; RET: enter value"
   :tag "Key sequence")
 
+;; FIXME: Consider combining this with help--read-key-sequence which
+;; can also read double and triple mouse events.
 (defun widget-key-sequence-read-event (ev)
   (interactive (list
                (let ((inhibit-quit t) quit-flag)
-                 (read-event "Insert KEY, EVENT, or CODE: "))))
+                 (read-key "Insert KEY, EVENT, or CODE: " t))))
   (let ((ev2 (and (memq 'down (event-modifiers ev))
-                 (read-event)))
-       (tr (and (keymapp function-key-map)
-                (lookup-key function-key-map (vector ev)))))
+                 (read-key nil t)))
+       (tr (and (keymapp local-function-key-map)
+                (lookup-key local-function-key-map (vector ev)))))
     (when (and (integerp ev)
               (or (and (<= ?0 ev) (< ev (+ ?0 (min 10 read-quoted-char-radix))))
                   (and (<= ?a (downcase ev))
index 4b168fb84bd99ea898df6342a76b22db4a04ba63..72b68df6631f74eb29630314c16cef48df78a6b1 100644 (file)
@@ -787,6 +787,12 @@ If `inhibit-interaction' is non-nil, this function will signal an
 
 DEFUN ("read-event", Fread_event, Sread_event, 0, 3, 0,
        doc: /* Read an event object from the input stream.
+
+If you want to read non-character events, consider calling `read-key'
+instead.  `read-key' will decode events via `input-decode-map' that
+`read-event' will not.  On a terminal this includes function keys such
+as <F7> and <RIGHT>, or mouse events generated by `xterm-mouse-mode'.
+
 If the optional argument PROMPT is non-nil, display that as a prompt.
 If PROMPT is nil or the string \"\", the key sequence/events that led
 to the current command is used as the prompt.