Is there a way to prompt the user for a key sequence, like read-key-sequence
, but only including keys from a specified keymap? It seems like read-key-sequence
always reads from all active keymaps.

- 41
- 1
1 Answers
Best I've been able to figure out:
(defun read-key-sequence-in-keymap (keymap &rest arguments)
(let ((overriding-terminal-local-map nil)
(overriding-local-map keymap)
(saved-global-map (current-global-map)))
(unwind-protect
(progn
(use-global-map (make-sparse-keymap))
(apply 'read-key-sequence arguments))
(use-global-map saved-global-map))))
Usage Notes
Since read-key-sequence
doesn't distinguish if the key sequence reaches a non-prefix bound key or an unbound key, combine it with something like lookup-key
if you need to tell those cases apart (note the t
argument at the end of lookup-key
makes it respect default bindings the same way that read-key-sequence
does):
(let ((key-sequence (read-key-sequence-in-keymap my-keymap ...)))
(lookup-key my-keymap key-sequence t))
Explanation
The big picture: activate the keymap we're interested in, and disable all other keymaps. This limits read-key-sequence
to just our keymap.
The details:
Keymaps can come from many different variables, and even from text under point, but overriding-local-map
is uniquely special: it does not merely take precedence, it causes most other keymaps to not even get looked at.
The easiest way to see this is in the pseudo code in the Emacs documentation for how keymaps are searched (notice how most of the search is in the "else" branch of if overriding-local-map
):
(or (if overriding-terminal-local-map
(find-in overriding-terminal-local-map))
(if overriding-local-map
(find-in overriding-local-map)
(or (find-in (get-char-property (point) 'keymap))
(find-in-any emulation-mode-map-alists)
(find-in-any minor-mode-overriding-map-alist)
(find-in-any minor-mode-map-alist)
(if (get-char-property (point) 'local-map)
(find-in (get-char-property (point) 'local-map))
(find-in (current-local-map)))))
(find-in (current-global-map)))
So simply assigning the keymap we're interested in to overriding-local-map
is most of the solution, and we just have to clear overriding-terminal-local-map
and the global map. The first is trivial - just set it to nil. But the second requires a little extra fiddling:
- we have to use
use-global-map
to set it since it doesn't live in a global variable (there'sglobal-map
but that's just a reference to the default global map, not the current one); - Emacs won't let us set it to
nil
, so we have to create a new empty keymap (by the way, an empty sparse keymap is just'(keymap)
); and - we have to make sure we restore the global keymap when we're done.
Questions
Does this break input methods?
My own design intuition based on what I know would be to implement the entry into key-translating functions using something like key-translation-map
or a "special event" (aiui: binding that execute as soon as they're read, before the normal key sequence read and lookup is done), and that should be fully compatible with this.
(The Quail library that ships with Emacs uses overriding-terminal-local-map
in its implemention of such input methods, but glancing at the source, it seems to only do this temporarily in their own let
form, during their own code, with little to no opportunity for other code to run, so that part seems compatible with this.)
Bugs
When read-key-sequence-in-keymap
is ran inside a (with-temp-buffer ...)
, and input comes from a terminal (not GUI) Emacs frame, hitting the Escape key causes the read to wait for more input until I hit any other key.

- 346
- 2
- 13
read-key-sequence
doesn't pay attention to any keymaps. It reads a key sequence that Emacs can recognize - regardless of whether it is bound in any keymap. A key sequence need not be bound to any command. – Drew Aug 27 '21 at 06:25map-keymap
to get key descriptions of all keys in a keymap, and then use those descriptions as completion candidates withcompleting-read
. – Drew Aug 27 '21 at 06:27read-key-sequence
does pay attention to the currently active keymaps - if you pressC-x
after runningread-key-sequence
, it will wait for you to press more keys becauseC-x
is globally bound to a keymap, but if you press an unmapped key or key bound to a command, it will return the sequence. What I am looking for is a command to do the same thing but only taking into account a specific keymap. – Prismavoid Aug 28 '21 at 04:25C-x
. You can typeC-x 7
, even though that key sequence is unbound. – Drew Aug 28 '21 at 16:55C-x
, enough to know thatC-x 5
is yet another prefix and read one more key after that. Literally one of the first lines in the built-in help: "The sequence is sufficient to specify a non-prefix command in the current local and global maps." It stops atC-x 7
because7
is not bound in theC-x
map, so it has ruled out the prefix case. It doesn't stop atC-x 5
because it looked into theC-x
keymap and seen that5
is bound to yet another keymap, and it will look in there too to see if the next key is also a prefix, and so on. – mtraceur Sep 10 '23 at 16:11