Function: read-key

read-key is a byte-compiled function defined in subr.el.gz.

Signature

(read-key &optional PROMPT DISABLE-FALLBACKS)

Documentation

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.

If the optional argument PROMPT is non-nil, display that as a prompt.

If the optional argument DISABLE-FALLBACKS is non-nil, all unbound fallbacks usually done by read-key-sequence are disabled such as discarding mouse down events. This is generally what you want as read-key temporarily removes all bindings while calling read-key-sequence. If nil or unspecified, the only unbound fallback disabled is downcasing of the last event.

View in manual

Probably introduced at or before Emacs version 23.2.

Source Code

;; Defined in /usr/src/emacs/lisp/subr.el.gz
(defvar read-key-delay 0.01) ;Fast enough for 100Hz repeat rate, hopefully.

(defun read-key (&optional prompt disable-fallbacks)
  "Read a key from the keyboard.
Contrary to `read-event' this will not return a raw event but instead will
obey the input decoding and translations usually done by `read-key-sequence'.
So escape sequences and keyboard encoding are taken into account.
When there's an ambiguity because the key looks like the prefix of
some sort of escape sequence, the ambiguity is resolved via `read-key-delay'.

If the optional argument PROMPT is non-nil, display that as a
prompt.

If the optional argument DISABLE-FALLBACKS is non-nil, all
unbound fallbacks usually done by `read-key-sequence' are
disabled such as discarding mouse down events.  This is generally
what you want as `read-key' temporarily removes all bindings
while calling `read-key-sequence'.  If nil or unspecified, the
only unbound fallback disabled is downcasing of the last event."
  ;; This overriding-terminal-local-map binding also happens to
  ;; disable quail's input methods, so although read-key-sequence
  ;; always inherits the input method, in practice read-key does not
  ;; inherit the input method (at least not if it's based on quail).
  (let ((overriding-terminal-local-map nil)
	(overriding-local-map
         ;; FIXME: Audit existing uses of `read-key' to see if they
         ;; should always specify disable-fallbacks to be more in line
         ;; with `read-event'.
         (if disable-fallbacks read-key-full-map read-key-empty-map))
        (echo-keystrokes 0)
	(old-global-map (current-global-map))
        (timer (run-with-idle-timer
                ;; Wait long enough that Emacs has the time to receive and
                ;; process all the raw events associated with the single-key.
                ;; But don't wait too long, or the user may find the delay
                ;; annoying (or keep hitting more keys, which may then get
                ;; lost or misinterpreted).
                ;; This is relevant only for keys that Emacs perceives as
                ;; "prefixes", such as C-x (because of the C-x 8 map in
                ;; key-translate-table and the C-x @ map in function-key-map)
                ;; or ESC (because of terminal escape sequences in
                ;; input-decode-map).
                read-key-delay t
                (lambda ()
                  (let ((keys (this-command-keys-vector)))
                    (unless (zerop (length keys))
                      ;; `keys' is non-empty, so the user has hit at least
                      ;; one key; there's no point waiting any longer, even
                      ;; though read-key-sequence thinks we should wait
                      ;; for more input to decide how to interpret the
                      ;; current input.
                      (throw 'read-key keys)))))))
    (unwind-protect
        (progn
	  (use-global-map
           (let ((map (make-sparse-keymap)))
             ;; Don't hide the menu-bar, tab-bar and tool-bar entries.
             (define-key map [menu-bar] (lookup-key global-map [menu-bar]))
             (define-key map [tab-bar]
	       ;; This hack avoids evaluating the :filter (Bug#9922).
	       (or (cdr (assq 'tab-bar global-map))
		   (lookup-key global-map [tab-bar])))
             (define-key map [tool-bar]
	       ;; This hack avoids evaluating the :filter (Bug#9922).
	       (or (cdr (assq 'tool-bar global-map))
		   (lookup-key global-map [tool-bar])))
             map))
          (let* ((keys
                  (catch 'read-key (read-key-sequence-vector prompt nil t)))
                 (key (aref keys 0)))
            (if (and (> (length keys) 1)
                     (memq key '(mode-line header-line
                                 left-fringe right-fringe)))
                (aref keys 1)
              key)))
      (cancel-timer timer)
      ;; For some reason, `read-key(-sequence)' leaves the prompt in the echo
      ;; area, whereas `read-event' seems to empty it just before returning
      ;; (bug#22714).  So, let's mimic the behavior of `read-event'.
      (message nil)
      (use-global-map old-global-map))))