unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Jared Finder via "Emacs development discussions." <emacs-devel@gnu.org>
To: Eli Zaretskii <eliz@gnu.org>
Cc: monnier@iro.umontreal.ca, emacs-devel@gnu.org
Subject: Re: Additional cleanup around xterm-mouse
Date: Sat, 26 Dec 2020 15:49:19 -0800	[thread overview]
Message-ID: <f06e43436fefcad5fd9e7371b84cad98@finder.org> (raw)

[-- Attachment #1: Type: text/plain, Size: 1716 bytes --]

On 2020-12-24 10:43 am, Eli Zaretskii wrote:
>> Date: Wed, 23 Dec 2020 09:21:10 -0800
>> From: Jared Finder <jared@finder.org>
>> Cc: monnier@iro.umontreal.ca, emacs-devel@gnu.org
>> 
>> The additional thing to keep in mind is that read-key is implemented 
>> on
>> top of read-key-sequence.  read-key currently will never return down
>> mouse events due to them being discarded in the (C function)
>> read_key_sequence.
> 
> And xterm-mouse-mode does need these down-mouse events?  For what
> purpose?

Libraries need those events.  For example, artist mode relies on reading 
both down mouse events when drawing a polyline.

>> 1. [Stefan's preference] Change the behavior of the dont-downcase-last
>> parameter to this more extensive meaning. Update global-set-key (the
>> only other caller who sets dont-downcase-last in Emacs' code) to take
>> this new behavior into account.
>> 
>> 2. Make the dont-downcase-last parameter have the new behavior only if
>> it is passed some new value (for example: 'all-fallbacks). Leave the
>> existing behavior for any other value, especially 'nil and 't.
>> 
>> 3. [My preference] Like 2, but with a deprecation message on values
>> other than 'nil, 'all-fallbacks, or 't (or maybe 'downcase-last if we
>> want full explicitness). This allows maximal ability to define new
>> behaviors in the future.
> 
> I prefer 3 or 2.  1 sounds too radical to me.  It's true that in core
> there's only one caller, but we have no idea what happens outside of
> the core.

Great, I've coded behavior #3.  Updated patch attached.  The remaining 
work to do is just documentation, but I was hoping to defer that until 
the code otherwise looks good.  Let me know what you think.

   -- MJF

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-WIP-version-making-libraries-work-with-xterm-mouse-m.patch --]
[-- Type: text/x-diff; name=0001-WIP-version-making-libraries-work-with-xterm-mouse-m.patch, Size: 30656 bytes --]

From 4bd9ed204049195a69c71d9430267aab38c4fe4e Mon Sep 17 00:00:00 2001
From: Jared Finder <jared@finder.org>
Date: Tue, 1 Dec 2020 22:23:43 -0800
Subject: [PATCH] WIP version making libraries work with xterm-mouse-mode.

Still todo:
* Finalize comment.
* Update manual.
* Update release notes (changing read-key-sequence is a BIG DEAL).

WIP comment (this needs to be updated):

Make libraries work with xterm-mouse-mode.

Change read-event calls in libraries expecting mouse events to read-key
when xterm-mouse-mode is enabled.  Add an option that tells
read-key-sequence (which read-key is built on top of) to return mouse
button down events.

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

* src/lread.c (Fread_event): Update docstring for read-event to
recommend read-key.
* lisp/subr.el (read-key): Add new parameter, all-mouse-events to
prevent discarding mouse events normally discarded by
read-key-sequence.
* doc/lispref/commands.texi (Reading One Event): Document new
parameter.
* src/keyboard.c (read_key_sequence): Implement new behavior for
read-key.
(inhibit--unbound-mouse-fallback): New variable to enable new
behavior.
(read-potential-mouse-event): 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 it.
* lisp/wid-edit.el (widget-key-sequence-read-event): Call read-key,
delete manual application of function-key-map.
* lisp/vc/ediff.el (ediff-windows): Use display-mouse-p to check if a
mouse is available.

WIP
---
 doc/lispref/commands.texi |  12 ++++-
 lisp/foldout.el           |   2 +-
 lisp/isearch.el           |   2 +-
 lisp/mouse-drag.el        |   4 +-
 lisp/mouse.el             |   2 +-
 lisp/ruler-mode.el        |   4 +-
 lisp/strokes.el           |  23 ++++-----
 lisp/subr.el              |  48 ++++++++++++++++--
 lisp/textmodes/artist.el  |   6 +--
 lisp/vc/ediff-wind.el     |   5 +-
 lisp/vc/ediff.el          |   2 +-
 lisp/wid-edit.el          |  12 ++---
 src/keyboard.c            | 101 ++++++++++++++++++++++++++++----------
 src/lread.c               |   6 +++
 14 files changed, 166 insertions(+), 63 deletions(-)

diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index 15d7e4e3a7..ae41053d6e 100644
--- a/doc/lispref/commands.texi
+++ b/doc/lispref/commands.texi
@@ -2434,6 +2434,8 @@ Key Sequence Input
 with a mouse event is read using the keymaps of the buffer in the
 window that the mouse was in, not the current buffer.)
 
+TODO: update docs here.
+
 If the events are all characters and all can fit in a string, then
 @code{read-key-sequence} returns a string (@pxref{Strings of Events}).
 Otherwise, it returns a vector, since a vector can hold all kinds of
@@ -2486,7 +2488,7 @@ Key Sequence Input
 and does not set @code{quit-flag}.  @xref{Quitting}.
 @end defun
 
-@defun read-key-sequence-vector prompt &optional continue-echo dont-downcase-last switch-frame-ok command-loop
+@defun read-key-sequence-vector prompt &optional continue-echo fallbacks-disabled can-return-switch-frame command-loop
 This is like @code{read-key-sequence} except that it always
 returns the key sequence as a vector, never as a string.
 @xref{Strings of Events}.
@@ -2698,7 +2700,7 @@ Reading One Event
 If you wish to read a single key taking these translations into
 account, use the function @code{read-key}:
 
-@defun read-key &optional prompt
+@defun read-key &optional prompt all-fallbacks-disabled
 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
@@ -2706,8 +2708,14 @@ Reading One Event
 according to @code{input-decode-map}, @code{local-function-key-map},
 and @code{key-translation-map} (@pxref{Translation Keymaps}).
 
+TODO: update docs here.
+
 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{all-mouse-events} is non-@code{nil} then button-down
+and multi-click events will get returned.  Otherwise, these are
+ignored as in @code{read-key-sequence}.
 @end defun
 
 @defun read-char-choice prompt chars &optional inhibit-quit
diff --git a/lisp/foldout.el b/lisp/foldout.el
index 58455c28b1..ca7776f97a 100644
--- a/lisp/foldout.el
+++ b/lisp/foldout.el
@@ -487,7 +487,7 @@ foldout-mouse-swallow-events
 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)
diff --git a/lisp/isearch.el b/lisp/isearch.el
index 13173a2857..815906fee5 100644
--- a/lisp/isearch.el
+++ b/lisp/isearch.el
@@ -2968,7 +2968,7 @@ isearch-pre-command-hook
      ((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
diff --git a/lisp/mouse-drag.el b/lisp/mouse-drag.el
index e80ebba28d..ed26e6f072 100644
--- a/lisp/mouse-drag.el
+++ b/lisp/mouse-drag.el
@@ -225,7 +225,7 @@ mouse-drag-throw
       ;; 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 @@ mouse-drag-drag
 	  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)))
diff --git a/lisp/mouse.el b/lisp/mouse.el
index 9d4492f1bd..7433f6404f 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1792,7 +1792,7 @@ mouse-drag-secondary
       (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))))
 
diff --git a/lisp/ruler-mode.el b/lisp/ruler-mode.el
index d97abca9ee..8a81e213cb 100644
--- a/lisp/ruler-mode.el
+++ b/lisp/ruler-mode.el
@@ -429,7 +429,7 @@ ruler-mode-mouse-grab-any-column
          ;; `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 @@ ruler-mode-mouse-drag-any-column-iteration
     (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)
diff --git a/lisp/strokes.el b/lisp/strokes.el
index 044872068f..0264c9b1e2 100644
--- a/lisp/strokes.el
+++ b/lisp/strokes.el
@@ -756,12 +756,12 @@ strokes-read-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 @@ strokes-read-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 @@ strokes-read-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 @@ strokes-read-complex-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 @@ strokes-read-complex-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
diff --git a/lisp/subr.el b/lisp/subr.el
index 725722cbee..36eb27312d 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -1123,7 +1123,16 @@ global-set-key
 that you make with this function."
   (interactive
    (let* ((menu-prompting nil)
-          (key (read-key-sequence "Set key globally: " nil t)))
+          (key (read-key-sequence
+                "Set key globally: " nil
+                ;; FIXME: It'd be nicer if this was set to
+                ;; 'all-fallbacks, however that would not apply the
+                ;; transformations applied by local-function-key-map,
+                ;; for example control modified function keys.
+                ;; `widget-key-sequence-read-event' queries the user
+                ;; which key they want in this case, perhaps do the
+                ;; same here?
+                'downcase-last)))
      (list key
            (read-command (format "Set key %s to command: "
                                  (key-description key))))))
@@ -2456,13 +2465,24 @@ read-key-empty-map
 
 (defvar read-key-delay 0.01) ;Fast enough for 100Hz repeat rate, hopefully.
 
-(defun read-key (&optional prompt)
+(defun read-key (&optional prompt all-fallbacks-disabled)
   "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 ALL-FALLBACKS-DISABLED 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.
+Otherwise, only downcasing of the last event is disabled.  See
+the parameter FALLBACKS-DISABLED to `read-key-sequence' for more
+details."
   ;; 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
@@ -2508,7 +2528,11 @@ read-key
 		   (lookup-key global-map [tool-bar])))
              map))
           (let* ((keys
-                  (catch 'read-key (read-key-sequence-vector prompt nil t)))
+                  (catch 'read-key
+                    (read-key-sequence-vector prompt nil
+                                              (if all-fallbacks-disabled
+                                                  'all-fallbacks
+                                                'downcase-last))))
                  (key (aref keys 0)))
             (if (and (> (length keys) 1)
                      (memq key '(mode-line header-line
@@ -2522,6 +2546,22 @@ read-key
       (message nil)
       (use-global-map old-global-map))))
 
+;; FIXME: Once there's a safe way to transition away from read-event,
+;; 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!
diff --git a/lisp/textmodes/artist.el b/lisp/textmodes/artist.el
index cc2eaf1e4e..1f663aea75 100644
--- a/lisp/textmodes/artist.el
+++ b/lisp/textmodes/artist.el
@@ -5004,7 +5004,7 @@ artist-mouse-draw-continously
                   (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 @@ artist-mouse-draw-poly
 
 	;; 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 @@ artist-mouse-draw-2points
 
 
 	;; 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
diff --git a/lisp/vc/ediff-wind.el b/lisp/vc/ediff-wind.el
index 3d90ccb1cb..ecc25137c2 100644
--- a/lisp/vc/ediff-wind.el
+++ b/lisp/vc/ediff-wind.el
@@ -262,11 +262,12 @@ ediff-get-window-by-clicking
   (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))))
 
 
diff --git a/lisp/vc/ediff.el b/lisp/vc/ediff.el
index ae2f8ad6c1..bf35cd2bd1 100644
--- a/lisp/vc/ediff.el
+++ b/lisp/vc/ediff.el
@@ -939,7 +939,7 @@ ediff-windows-linewise
 ;; 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)
diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el
index 8250316bcc..6be64218b3 100644
--- a/lisp/wid-edit.el
+++ b/lisp/wid-edit.el
@@ -1104,7 +1104,7 @@ widget-button--check-and-call-button
 		  (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 @@ widget-button-click
 	    (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.")))
@@ -3490,11 +3490,11 @@ 'key-sequence
 (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))
diff --git a/src/keyboard.c b/src/keyboard.c
index 54232aaea1..60c8fb2619 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -1230,8 +1230,8 @@ some_mouse_moved (void)
    sans error-handling encapsulation.  */
 
 enum { READ_KEY_ELTS = 30 };
-static int read_key_sequence (Lisp_Object *, Lisp_Object,
-                              bool, bool, bool, bool);
+static int read_key_sequence (Lisp_Object *, Lisp_Object, Lisp_Object, bool,
+                              bool, bool);
 static void adjust_point_for_property (ptrdiff_t, bool);
 
 Lisp_Object
@@ -1350,7 +1350,7 @@ command_loop_1 (void)
       /* Read next key sequence; i gets its length.  */
       raw_keybuf_count = 0;
       Lisp_Object keybuf[READ_KEY_ELTS];
-      int i = read_key_sequence (keybuf, Qnil, false, true, true, false);
+      int i = read_key_sequence (keybuf, Qnil, Qnil, true, true, false);
 
       /* A filter may have run while we were reading the input.  */
       if (! FRAME_LIVE_P (XFRAME (selected_frame)))
@@ -1597,7 +1597,7 @@ read_menu_command (void)
   specbind (Qecho_keystrokes, make_fixnum (0));
 
   Lisp_Object keybuf[READ_KEY_ELTS];
-  int i = read_key_sequence (keybuf, Qnil, false, true, true, true);
+  int i = read_key_sequence (keybuf, Qnil, Qnil, true, true, true);
 
   unbind_to (count, Qnil);
 
@@ -9203,15 +9203,28 @@ test_undefined (Lisp_Object binding)
    These include any minor mode keymaps active in the current buffer,
    the current buffer's local map, and the global map.
 
-   If a key sequence has no other bindings, we check Vfunction_key_map
-   to see if some trailing subsequence might be the beginning of a
-   function key's sequence.  If so, we try to read the whole function
-   key, and substitute its symbolic name into the key sequence.
+   There are a handful of fallbacks that apply only if a key sequence
+   has no other bindings.  These apply conditionally based on the
+   value of FALLBACKS_DISABLED:
 
-   We ignore unbound `down-' mouse clicks.  We turn unbound `drag-' and
-   `double-' events into similar click events, if that would make them
-   bound.  We try to turn `triple-' events first into `double-' events,
-   then into clicks.
+   * If a key sequence is unbound, we check Vfunction_key_map to see
+   if some trailing subsequence might be the beginning of a function
+   key's sequence.  If so, we try to read the whole function key, and
+   substitute its symbolic name into the key sequence.
+
+   * If a `down-' mouse click event is unbound, it is discarded.
+
+   * If a `drag-' or `double-' event is unbound, it is turned into
+   similar click events if that would make them bound.  We try to turn
+   `triple-' events first into `double-' events, then into clicks.
+
+   * If a capital letter is unbound, it is turned into a lower case
+   letter if that would make it bound.
+
+   If FALLBACKS_DISABLED is Qnil, all of the above fallbacks are
+   applied.  If it is Qall_fallbacks, then none of the fallbacks are
+   applied.  If it is Qdowncase_last, the capital letter fallback is
+   not applied, but all other ones are applied.
 
    If we get a mouse click in a mode line, vertical divider, or other
    non-text area, we treat the click as if it were prefixed by the
@@ -9230,8 +9243,9 @@ test_undefined (Lisp_Object binding)
 
 static int
 read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
-		   bool dont_downcase_last, bool can_return_switch_frame,
-		   bool fix_current_buffer, bool prevent_redisplay)
+		   Lisp_Object fallbacks_disabled,
+                   bool can_return_switch_frame, bool fix_current_buffer,
+                   bool prevent_redisplay)
 {
   ptrdiff_t count = SPECPDL_INDEX ();
 
@@ -9774,7 +9788,7 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
       new_binding = follow_key (current_binding, key);
 
       /* If KEY wasn't bound, we'll try some fallbacks.  */
-      if (!NILP (new_binding))
+      if (!NILP (new_binding) || EQ (fallbacks_disabled, Qall_fallbacks))
 	/* This is needed for the following scenario:
 	   event 0: a down-event that gets dropped by calling replay_key.
 	   event 1: some normal prefix like C-h.
@@ -9986,7 +10000,8 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
 				     first_binding >= nmaps) we don't want
 				     to apply this function-key-mapping.  */
 				  (fkey.end + 1 == t
-				   && test_undefined (current_binding)),
+				   && test_undefined (current_binding)
+                                   && !EQ (fallbacks_disabled, Qall_fallbacks)),
 				  &diff, prompt);
 	    if (done)
 	      {
@@ -10007,7 +10022,8 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
 	  int diff;
 
 	  done = keyremap_step (keybuf, &keytran, max (t, mock_input),
-				true, &diff, prompt);
+                                !EQ (fallbacks_disabled, Qall_fallbacks),
+                                &diff, prompt);
 	  if (done)
 	    {
 	      mock_input = diff + max (t, mock_input);
@@ -10027,7 +10043,8 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
 	 use the corresponding lower-case letter instead.  */
       if (NILP (current_binding)
 	  && /* indec.start >= t && fkey.start >= t && */ keytran.start >= t
-	  && FIXNUMP (key))
+	  && FIXNUMP (key)
+          && !EQ (fallbacks_disabled, Qall_fallbacks))
 	{
 	  Lisp_Object new_key;
 	  EMACS_INT k = XFIXNUM (key);
@@ -10073,7 +10090,8 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
 	 and is a shifted function key,
 	 use the corresponding unshifted function key instead.  */
       if (NILP (current_binding)
-	  && /* indec.start >= t && fkey.start >= t && */ keytran.start >= t)
+	  && /* indec.start >= t && fkey.start >= t && */ keytran.start >= t
+          && !EQ (fallbacks_disabled, Qall_fallbacks))
 	{
 	  Lisp_Object breakdown = parse_modifiers (key);
 	  int modifiers
@@ -10127,7 +10145,9 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
 
   /* Don't downcase the last character if the caller says don't.
      Don't downcase it if the result is undefined, either.  */
-  if ((dont_downcase_last || NILP (current_binding))
+  if ((EQ (fallbacks_disabled, Qdowncase_last)
+       || EQ (fallbacks_disabled, Qall_fallbacks)
+       || NILP (current_binding))
       && t > 0
       && t - 1 == original_uppercase_position)
     {
@@ -10156,7 +10176,7 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
 
 static Lisp_Object
 read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo,
-		      Lisp_Object dont_downcase_last,
+		      Lisp_Object fallbacks_disabled,
 		      Lisp_Object can_return_switch_frame,
 		      Lisp_Object cmd_loop, bool allow_string)
 {
@@ -10166,6 +10186,29 @@ read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo,
     CHECK_STRING (prompt);
   maybe_quit ();
 
+  if (!EQ (fallbacks_disabled, Qnil)
+      && !EQ (fallbacks_disabled, Qall_fallbacks)
+      && !EQ (fallbacks_disabled, Qdowncase_last))
+    {
+      /* Prior to Emacs 28, fallbacks-disabled was named
+         dont-downcase-last and choose between two behaviors:
+
+         1. no fallbacks disabled (nil)
+         2. disable downcase of last event (any other value)
+
+         Warn for any code that has not yet made an explicit choice in
+         behavior.  */
+      fallbacks_disabled = Qdowncase_last;
+      Vdelayed_warnings_list
+        = Fcons
+        (list2 (Qemacs, build_string
+                ("Deprecated value for fallbacks-disabled passed to "
+                "`read-key-sequence'.\n"
+                "Prior to Emacs 28, this parameter was called "
+                "dont-downcase-last.")),
+         Vdelayed_warnings_list);
+    }
+
   specbind (Qinput_method_exit_on_first_char,
 	    (NILP (cmd_loop) ? Qt : Qnil));
   specbind (Qinput_method_use_echo_area,
@@ -10184,7 +10227,7 @@ read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo,
 
   raw_keybuf_count = 0;
   Lisp_Object keybuf[READ_KEY_ELTS];
-  int i = read_key_sequence (keybuf, prompt, ! NILP (dont_downcase_last),
+  int i = read_key_sequence (keybuf, prompt, fallbacks_disabled,
 			     ! NILP (can_return_switch_frame), false, false);
 
 #if 0  /* The following is fine for code reading a key sequence and
@@ -10216,6 +10259,8 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
 Second (optional) arg CONTINUE-ECHO, if non-nil, means this key echos
 as a continuation of the previous key.
 
+TODO: update docs here.
+
 The third (optional) arg DONT-DOWNCASE-LAST, if non-nil, means do not
 convert the last event to lower case.  (Normally any upper case event
 is converted to lower case if the original event is undefined and the lower
@@ -10254,19 +10299,19 @@ Second (optional) arg CONTINUE-ECHO, if non-nil, means this key echos
 that this key sequence is being read by something that will
 read commands one after another.  It should be nil if the caller
 will read just one key sequence.  */)
-  (Lisp_Object prompt, Lisp_Object continue_echo, Lisp_Object dont_downcase_last, Lisp_Object can_return_switch_frame, Lisp_Object cmd_loop)
+  (Lisp_Object prompt, Lisp_Object continue_echo, Lisp_Object fallbacks_disabled, Lisp_Object can_return_switch_frame, Lisp_Object cmd_loop)
 {
-  return read_key_sequence_vs (prompt, continue_echo, dont_downcase_last,
+  return read_key_sequence_vs (prompt, continue_echo, fallbacks_disabled,
 			       can_return_switch_frame, cmd_loop, true);
 }
 
 DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
        Sread_key_sequence_vector, 1, 5, 0,
        doc: /* Like `read-key-sequence' but always return a vector.  */)
-  (Lisp_Object prompt, Lisp_Object continue_echo, Lisp_Object dont_downcase_last, Lisp_Object can_return_switch_frame, Lisp_Object cmd_loop)
+  (Lisp_Object prompt, Lisp_Object continue_echo, Lisp_Object fallbacks_disabled, Lisp_Object can_return_switch_frame, Lisp_Object cmd_loop)
 {
-  return read_key_sequence_vs (prompt, continue_echo, dont_downcase_last,
-			       can_return_switch_frame, cmd_loop, false);
+  return read_key_sequence_vs (prompt, continue_echo, fallbacks_disabled,
+                               can_return_switch_frame, cmd_loop, false);
 }
 \f
 /* Return true if input events are pending.  */
@@ -11687,6 +11732,8 @@ syms_of_keyboard (void)
 
   DEFSYM (Qcommand_execute, "command-execute");
   DEFSYM (Qinternal_echo_keystrokes_prefix, "internal-echo-keystrokes-prefix");
+  DEFSYM (Qall_fallbacks, "all-fallbacks");
+  DEFSYM (Qdowncase_last, "downcase-last");
 
   accent_key_syms = Qnil;
   staticpro (&accent_key_syms);
diff --git a/src/lread.c b/src/lread.c
index 3ef874039a..74ed474944 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -782,6 +782,12 @@ DEFUN ("read-char", Fread_char, Sread_char, 0, 3, 0,
 
 DEFUN ("read-event", Fread_event, Sread_event, 0, 3, 0,
        doc: /* Read an event object from the input stream.
+
+If you want to read mouse events (for example, to discard an expected
+button up event inside a button down command), call `read-key' which
+can return events via `input-decode-map' such as all 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.
-- 
2.20.1


             reply	other threads:[~2020-12-26 23:49 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-26 23:49 Jared Finder via Emacs development discussions. [this message]
2020-12-27 15:36 ` Additional cleanup around xterm-mouse Stefan Monnier
2020-12-27 16:30   ` Jared Finder via Emacs development discussions.
2020-12-27 17:10     ` Stefan Monnier
2020-12-28  0:22       ` Jared Finder via Emacs development discussions.
2021-01-02  8:17 ` Eli Zaretskii
2021-01-02 22:20   ` Jared Finder via Emacs development discussions.
2021-01-09 12:27     ` Eli Zaretskii
2021-01-09 23:01       ` Jared Finder via Emacs development discussions.
2021-01-15 11:54         ` Eli Zaretskii
  -- strict thread matches above, loose matches on Subject: below --
2020-11-16  6:29 Jared Finder via Emacs development discussions.
2020-11-16 17:30 ` Jared Finder via Emacs development discussions.
2020-11-18 17:40 ` Eli Zaretskii
2020-11-19  8:03   ` Jared Finder via Emacs development discussions.
2020-11-21  9:31     ` Eli Zaretskii
2020-11-22 23:56       ` Jared Finder via Emacs development discussions.
2020-11-28 16:36         ` Eli Zaretskii
2020-12-01  7:36           ` Jared Finder via Emacs development discussions.
2020-12-01 15:21             ` Stefan Monnier
2020-12-01 18:23             ` Eli Zaretskii
2020-12-02  6:45               ` Jared Finder via Emacs development discussions.
2020-12-02 16:53                 ` Stefan Monnier
2020-12-03  5:46                   ` Jared Finder via Emacs development discussions.
2020-12-03 14:45                     ` Stefan Monnier
2020-12-03 17:31                       ` Jared Finder via Emacs development discussions.
2020-12-14  0:54                         ` Jared Finder via Emacs development discussions.
2020-12-14 15:32                           ` Eli Zaretskii
2020-12-16  5:30                             ` Jared Finder via Emacs development discussions.
2020-12-19 18:32                               ` Eli Zaretskii
2020-12-19 22:50                                 ` Stefan Monnier
2020-12-20  7:26                                   ` Jared Finder via Emacs development discussions.
2020-12-20 14:07                                     ` Stefan Monnier
2020-12-20 23:27                                       ` Jared Finder via Emacs development discussions.
2020-12-23 16:52                                         ` Eli Zaretskii
2020-12-23 17:21                                           ` Jared Finder via Emacs development discussions.
2020-12-24 18:43                                             ` Eli Zaretskii
2020-12-14  0:36               ` Jared Finder via Emacs development discussions.
2020-11-21 17:00     ` Stefan Monnier
2020-11-21  8:23   ` Eli Zaretskii
2020-11-15  8:49 Jared Finder via Emacs development discussions.
2020-11-15 18:11 ` Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=f06e43436fefcad5fd9e7371b84cad98@finder.org \
    --to=emacs-devel@gnu.org \
    --cc=eliz@gnu.org \
    --cc=jared@finder.org \
    --cc=monnier@iro.umontreal.ca \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).