all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* Re: Additional cleanup around xterm-mouse
@ 2020-12-26 23:49 Jared Finder via Emacs development discussions.
  2020-12-27 15:36 ` Stefan Monnier
  2021-01-02  8:17 ` Eli Zaretskii
  0 siblings, 2 replies; 41+ messages in thread
From: Jared Finder via Emacs development discussions. @ 2020-12-26 23:49 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: monnier, emacs-devel

[-- 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread
* Re: Additional cleanup around xterm-mouse
@ 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
  0 siblings, 2 replies; 41+ messages in thread
From: Jared Finder via Emacs development discussions. @ 2020-11-16  6:29 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

On 2020-11-15 10:11 am, Eli Zaretskii wrote:
>> Date: Sun, 15 Nov 2020 00:49:03 -0800
>> From: Jared Finder via "Emacs development discussions." 
>> <emacs-devel@gnu.org>
>> 
>> The first patch is very straightforward and should be trivial to 
>> review
>> and merge.
> 
> Agreed.

Great. It's completely independent of the other change, feel free to 
merge at any time.

>> I have a question about the right way to proceed with the second 
>> patch.
>> [...]
> 
> Ouch, this is scary.  We have a lot of gray hair from replacing input
> functions by seemingly-similar other input functions.  And on top of
> that, you need changes to read-key.  These changes will affect every
> "native" mouse subsystem out there, with the benefit being a single
> niche mouse subsystem that is an emulator.  This sounds like not the
> best way, as the risk will be shared by many important configurations
> and the benefits by only one not very important one.
> 
> Can you think about a way of doing this that will affect only
> xterm-mouse?  I'm okay with, for example, replacing read-event in
> those cases with some new function that will call a special
> xterm-mouse API when xterm-mouse is in effect, and will call
> read-event otherwise.  Is something like this feasible?

I was a little nervous about changing read-key's default behavior too.  
Happy to explore other options. :)

Creating such an alternative function doesn't appear too bad if you're 
okay with having the same run-with-idle-timer pattern that read-key 
uses.  I do not think it can be xterm specific as it needs to apply all 
of input-decode-map to be able to return function keys such as [f1] on a 
native Linux term or an xterm.  (This is important for 
widget-key-sequence-read-event.)  However, it can avoid the rest of the 
complexity of read-key-sequence.  I'm imagining something like this 
(untested code follows, just wanted to give a flavor of it):

(defun read-decoded-key ()  ; I'd love a better name here.
   ;; Start of code like read-key's code.
   (let ((keys '())
         (timer (run-with-idle-timer
                 read-key-delay t
                 (lambda ()
                   (unless (null keys)
                     (throw 'read-key nil))))))
     (unwind-protect
         (while t (push (read-event) keys))
       (cancel-timer timer))

     ;; Start of new stuff: Apply transformations from input-decode-map.
     (do-stuff)

     (vconcat (nreverse keys))))

As you can see, this avoids all the complexity around managing the 
different keymaps that read-key currently has since it calls 
read-key-sequence.


An alternative is to just use read-key as is in most cases and make my 
change a parameter / special variable.  Most of my patch's changes work 
fine with the existing behavior of read-key.  Only the following changes 
do not:

* lisp/vc/ediff-wind.el (ediff-get-window-by-clicking)
==> As coded, expects the first mouse event returned by read-event to be 
a down-mouse-X event, which it then follows by another call to 
read-event to get the mouse-X event.  It could be easily changed to only 
look for the up event.

* lisp/strokes.el (strokes-read-stroke, strokes-read-complex-stroke)
* lisp/textmodes/artist.el (artist-mode-draw-poly)
==> These both expect to detect a mix of down-mouse-X and mouse-X 
events.

* lisp/wid-edit.el (widget-key-sequence-read-event)
==> This w/o changes to read-key, but with a behavior change.  With no 
changes to read-key it returns just a single up event.  Currently on 
other environments you get both a down and up event (e.g. <down-mouse-1> 
<mouse-1>).

   -- MJF



^ permalink raw reply	[flat|nested] 41+ messages in thread
* Additional cleanup around xterm-mouse
@ 2020-11-15  8:49 Jared Finder via Emacs development discussions.
  2020-11-15 18:11 ` Eli Zaretskii
  0 siblings, 1 reply; 41+ messages in thread
From: Jared Finder via Emacs development discussions. @ 2020-11-15  8:49 UTC (permalink / raw)
  To: emacs-devel

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

Two more patches doing misc cleanup around xterm-mouse.

The first patch is very straightforward and should be trivial to review 
and merge.

I have a question about the right way to proceed with the second patch.  
Redirecting to read-key seems like the right solution here as it is 
"read-event but also take input-decode-map into account".  I needed to 
make a change to read-key's implementation to make it also return button 
down events and I saw two ways to do that.  I would like advice on which 
way is preferred.  In the patch you can see the two options commented in 
subr.el with Option 1 enabled by default.

Let me know what you think.

   -- MJF

[-- Attachment #2: 0001-Migrate-usage-of-GPM_CLICK_EVENT-to-MOUSE_CLICK_EVEN.patch --]
[-- Type: text/x-diff, Size: 3555 bytes --]

From d9ac1bb6cdb270c1ab3b3b660837590b535a68a5 Mon Sep 17 00:00:00 2001
From: Jared Finder <jared@finder.org>
Date: Sat, 14 Nov 2020 23:44:26 -0800
Subject: [PATCH 1/2] Migrate usage of GPM_CLICK_EVENT to MOUSE_CLICK_EVENT.

* src/termhooks.h (enum event_kind):
* src/term.c (term_mouse_click, handle_one_term_event):
* src/keyboard.c (discard_mouse_events, make_lispy_event): Migrate
usage of GPM_CLICK_EVENT to MOUSE_CLICK_EVENT.
---
 src/keyboard.c  | 12 +-----------
 src/term.c      |  8 ++++----
 src/termhooks.h |  4 ----
 3 files changed, 5 insertions(+), 19 deletions(-)

diff --git a/src/keyboard.c b/src/keyboard.c
index 49a0a8bd23..45e9abc229 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -3736,9 +3736,6 @@ discard_mouse_events (void)
       if (sp->kind == MOUSE_CLICK_EVENT
 	  || sp->kind == WHEEL_EVENT
           || sp->kind == HORIZ_WHEEL_EVENT
-#ifdef HAVE_GPM
-	  || sp->kind == GPM_CLICK_EVENT
-#endif
 	  || sp->kind == SCROLL_BAR_CLICK_EVENT
 	  || sp->kind == HORIZONTAL_SCROLL_BAR_CLICK_EVENT)
 	{
@@ -5542,9 +5539,6 @@ make_lispy_event (struct input_event *event)
       /* A mouse click.  Figure out where it is, decide whether it's
          a press, click or drag, and build the appropriate structure.  */
     case MOUSE_CLICK_EVENT:
-#ifdef HAVE_GPM
-    case GPM_CLICK_EVENT:
-#endif
 #ifndef USE_TOOLKIT_SCROLL_BARS
     case SCROLL_BAR_CLICK_EVENT:
     case HORIZONTAL_SCROLL_BAR_CLICK_EVENT:
@@ -5559,11 +5553,7 @@ make_lispy_event (struct input_event *event)
 	position = Qnil;
 
 	/* Build the position as appropriate for this mouse click.  */
-	if (event->kind == MOUSE_CLICK_EVENT
-#ifdef HAVE_GPM
-	    || event->kind == GPM_CLICK_EVENT
-#endif
-	    )
+	if (event->kind == MOUSE_CLICK_EVENT)
 	  {
 	    struct frame *f = XFRAME (event->frame_or_window);
 	    int row, column;
diff --git a/src/term.c b/src/term.c
index a0738594bf..fee3b55575 100644
--- a/src/term.c
+++ b/src/term.c
@@ -2481,7 +2481,7 @@ term_mouse_click (struct input_event *result, Gpm_Event *event,
 {
   int i, j;
 
-  result->kind = GPM_CLICK_EVENT;
+  result->kind = MOUSE_CLICK_EVENT;
   for (i = 0, j = GPM_B_LEFT; i < 3; i++, j >>= 1 )
     {
       if (event->buttons & j) {
@@ -2567,11 +2567,11 @@ handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event)
     {
       f->mouse_moved = 0;
       term_mouse_click (&ie, event, f);
-      /* eassert (ie.kind == GPM_CLICK_EVENT); */
+      /* eassert (ie.kind == MOUSE_CLICK_EVENT); */
       if (tty_handle_tab_bar_click (f, event->x, event->y,
                                     (ie.modifiers & down_modifier) != 0, &ie))
         {
-          /* eassert (ie.kind == GPM_CLICK_EVENT
+          /* eassert (ie.kind == MOUSE_CLICK_EVENT
            *          || ie.kind == TAB_BAR_EVENT); */
           /* tty_handle_tab_bar_click stores 2 events in the event
              queue, so we are done here.  */
@@ -2581,7 +2581,7 @@ handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event)
           count += 2;
           return count;
         }
-      /* eassert (ie.kind == GPM_CLICK_EVENT); */
+      /* eassert (ie.kind == MOUSE_CLICK_EVENT); */
       kbd_buffer_store_event (&ie);
       count++;
     }
diff --git a/src/termhooks.h b/src/termhooks.h
index 6ab06ceff9..44ab14225f 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -220,10 +220,6 @@ #define EMACS_TERMHOOKS_H
      save yourself before shutdown. */
   SAVE_SESSION_EVENT
 
-#ifdef HAVE_GPM
-  , GPM_CLICK_EVENT
-#endif
-
 #ifdef HAVE_DBUS
   , DBUS_EVENT
 #endif
-- 
2.20.1


[-- Attachment #3: 0002-Options-for-making-libraries-work-with-xt-mouse.patch --]
[-- Type: text/x-diff, Size: 14729 bytes --]

From 8a2cc39ab17a1e2e6f8ea0294b538a8971146a68 Mon Sep 17 00:00:00 2001
From: Jared Finder <jared@finder.org>
Date: Sat, 14 Nov 2020 21:42:34 -0800
Subject: [PATCH 2/2] Options for making libraries work with xt-mouse.

Libraries changed by making them call `read-key' instead of
`read-event'.
---
 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          | 22 +++++++++++-----------
 lisp/subr.el             | 23 +++++++++++++++++++++++
 lisp/textmodes/artist.el |  6 +++---
 lisp/vc/ediff-wind.el    |  4 ++--
 lisp/vc/ediff.el         |  2 +-
 lisp/wid-edit.el         |  9 ++++++---
 src/keyboard.c           | 10 +++++++++-
 src/lread.c              |  6 ++++++
 13 files changed, 68 insertions(+), 28 deletions(-)

diff --git a/lisp/foldout.el b/lisp/foldout.el
index 0d7a7a88a6..0a33099daf 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-key)))
     (or (eq initial-event-type (event-basic-type event))
 	(error "")))
   event)
diff --git a/lisp/isearch.el b/lisp/isearch.el
index 4fba4370d9..aa623652b3 100644
--- a/lisp/isearch.el
+++ b/lisp/isearch.el
@@ -2967,7 +2967,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-key)
       (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..dcffbf0875 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-key)
 		     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-key)
 		     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..d0cd2f7769 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-key))
 		   (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 82e6178da1..29afa44323 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-key)
          ;; 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-key)))
         (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 c2f03cac0f..788930c105 100644
--- a/lisp/strokes.el
+++ b/lisp/strokes.el
@@ -757,12 +757,12 @@ strokes-read-stroke
 	      (strokes-fill-current-buffer-with-whitespace))
 	    (when prompt
 	      (message "%s" prompt)
-	      (setq event (read-event))
+	      (setq event (read-key))
 	      (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-key)
 				  safe-to-draw-p t))
 		  (while (not (strokes-button-release-event-p event))
 		    (if (strokes-mouse-event-p event)
@@ -777,7 +777,7 @@ strokes-read-stroke
 			    (setq safe-to-draw-p t))
 			  (push (cdr (mouse-pixel-position))
 				pix-locs)))
-		    (setq event (read-event)))))
+		    (setq event (read-key)))))
 	    ;; protected
 	    ;; clean up strokes buffer and then bury it.
 	    (when (equal (buffer-name) strokes-buffer-name)
@@ -788,16 +788,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-key))
 	(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-key)))
 	(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-key))))
       (setq grid-locs (strokes-renormalize-to-grid (nreverse pix-locs)))
       (strokes-fill-stroke
        (strokes-eliminate-consecutive-redundancies grid-locs)))))
@@ -818,10 +818,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-key))))
 	(unwind-protect
 	    (track-mouse
-	      (or event (setq event (read-event)))
+	      (or event (setq event (read-key)))
 	      (while (not (and (strokes-button-press-event-p event)
 			       (eq 'mouse-3
 				   (car (get (car event)
@@ -835,14 +835,14 @@ strokes-read-complex-stroke
 						?\s strokes-character))
 			(push (cdr (mouse-pixel-position))
 			      pix-locs)))
-		  (setq event (read-event)))
+		  (setq event (read-key)))
 		(push strokes-lift pix-locs)
 		(while (not (strokes-button-press-event-p event))
-		  (setq event (read-event))))
+		  (setq event (read-key))))
 	      ;; ### 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-key))))
 	      (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 6e9f66fe97..36381dc4e6 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -2446,6 +2446,9 @@ read-key
 	(overriding-local-map read-key-empty-map)
         (echo-keystrokes 0)
 	(old-global-map (current-global-map))
+        ;; Option 1: New variable that prevents mouse events from
+        ;; being transformed or discarded.
+        (inhibit--unbound-mouse-fallback t)
         (timer (run-with-idle-timer
                 ;; Wait long enough that Emacs has the time to receive and
                 ;; process all the raw events associated with the single-key.
@@ -2481,6 +2484,26 @@ read-key
 	       ;; This hack avoids evaluating the :filter (Bug#9922).
 	       (or (cdr (assq 'tool-bar global-map))
 		   (lookup-key global-map [tool-bar])))
+             ;; Option 2: Bind all the mouse events to prevent
+             ;; dropping / transformation.
+             ;;
+             ;; Note: this is not an exhaustive list.  To fully work,
+             ;; this should bind all possible prefix combinations (the
+             ;; power set of A-, C-, H-, S-, s-) for all possible
+             ;; mouse events.  For example, this currently does not
+             ;; bind C-S-down-mouse-1.
+             ;; (define-key map [down-mouse-1] 'ignore)
+             ;; (define-key map [C-down-mouse-1] 'ignore)
+             ;; (define-key map [M-down-mouse-1] 'ignore)
+             ;; (define-key map [C-M-down-mouse-1] 'ignore)
+             ;; (define-key map [down-mouse-2] 'ignore)
+             ;; (define-key map [C-down-mouse-2] 'ignore)
+             ;; (define-key map [M-down-mouse-2] 'ignore)
+             ;; (define-key map [C-M-down-mouse-3] 'ignore)
+             ;; (define-key map [down-mouse-3] 'ignore)
+             ;; (define-key map [C-down-mouse-3] 'ignore)
+             ;; (define-key map [M-down-mouse-3] 'ignore)
+             ;; (define-key map [C-M-down-mouse-3] 'ignore)
              map))
           (let* ((keys
                   (catch 'read-key (read-key-sequence-vector prompt nil t)))
diff --git a/lisp/textmodes/artist.el b/lisp/textmodes/artist.el
index 5ce9a90ea6..5155d4100c 100644
--- a/lisp/textmodes/artist.el
+++ b/lisp/textmodes/artist.el
@@ -5016,7 +5016,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-key))))
       ;; Cleanup: get rid of any active timer.
       (if timer
           (cancel-timer timer)))
@@ -5224,7 +5224,7 @@ artist-mouse-draw-poly
 
 	;; Read next event (only if we should not stop)
 	(if (not done)
-	    (setq ev (read-event)))))
+	    (setq ev (read-key)))))
 
     ;; Reverse point-list (last points are cond'ed first)
     (setq point-list (reverse point-list))
@@ -5351,7 +5351,7 @@ artist-mouse-draw-2points
 
 
 	;; Read next event
-	(setq ev (read-event))))
+	(setq ev (read-key))))
 
     ;; 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 a23d72070a..9843669e78 100644
--- a/lisp/vc/ediff-wind.el
+++ b/lisp/vc/ediff-wind.el
@@ -269,11 +269,11 @@ 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-key))))
       (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-key) ; 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 4e2cf7416d..bdcf8255a1 100644
--- a/lisp/wid-edit.el
+++ b/lisp/wid-edit.el
@@ -1088,7 +1088,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-key))
 		        (when (and mouse-1 (mouse-movement-p event))
 			  (push event unread-command-events)
 			  (setq event oevent)
@@ -1153,6 +1153,9 @@ widget-button-click
 	    (when up
 	      ;; Don't execute up events twice.
 	      (while (not (widget-button-release-event-p event))
+                ;; FIXME: This should probably be read-key to get
+                ;; mouse events through xterm-mouse-mode, but it is
+                ;; unclear how to trigger this code path normally.
 		(setq event (read-event))))
 	    (when command
 	      (call-interactively command)))))
@@ -3465,9 +3468,9 @@ '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: "))))
   (let ((ev2 (and (memq 'down (event-modifiers ev))
-		  (read-event)))
+		  (read-key)))
 	(tr (and (keymapp function-key-map)
 		 (lookup-key function-key-map (vector ev)))))
     (when (and (integerp ev)
diff --git a/src/keyboard.c b/src/keyboard.c
index 45e9abc229..483af75158 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -9827,7 +9827,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) || inhibit_unbound_mouse_fallback)
 	/* 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.
@@ -12393,6 +12393,14 @@ syms_of_keyboard (void)
 macros, dribble file, and `recent-keys'.
 Internal use only.  */);
 
+  DEFVAR_BOOL ("inhibit--unbound-mouse-fallback",
+               inhibit_unbound_mouse_fallback,
+               doc: /* If non-nil, `read-key-sequence' does not
+transform any unbound mouse events.
+This prevents the usual behavior in `read-key-sequence' where unbound
+button-down events, drag events, and multiple-click events get
+transformed or dropped.  Internal use only.  */);
+
   pdumper_do_now_and_after_load (syms_of_keyboard_for_pdumper);
 }
 
diff --git a/src/lread.c b/src/lread.c
index a3d5fd7bb8..e811de47c1 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


^ permalink raw reply related	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2021-01-15 11:54 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-12-26 23:49 Additional cleanup around xterm-mouse Jared Finder via Emacs development discussions.
2020-12-27 15:36 ` 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

Code repositories for project(s) associated with this external index

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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.