From 4bd9ed204049195a69c71d9430267aab38c4fe4e Mon Sep 17 00:00:00 2001 From: Jared Finder 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); } /* 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