Emacs 25
As mentioned by @YoungFrog in the comments, starting with Emacs 25.1, the good-old C-h k
method of describing key-binds will also tell you which keymap the key was found in.
Before Emacs 25
There’s some code
here
on this, but it’s incomplete as it does not cover everything. Below is an improved version of it.
Keys can be bound in 9(!) ways. Thanks to @Drew for this link (also supplemented by this) with the full list. By order of precedence, they are:
- A terminal-specific set of keys,
overriding-terminal-local-map
. This is defined by the set-transient-map
function.
- A buffer-local override map,
overriding-local-map
. If this one is set, items 3–8 are skipped (probably why you don't see many of these).
- At point via the
keymap
text-propety (which could go on actual text or on overlays).
- A variable which essentially simulates different possible sets of enabled minor-modes,
emulation-mode-map-alists
.
- A variable where major-modes can override the keybinds of minor-modes,
minor-mode-overriding-map-alist
.
- The actual minor-modes, whose keybinds are stored in
minor-mode-map-alist
.
- At point (again), via the
local-map
text property. If this exists, item 8 is skipped.
- The standard buffer-local keymap (where major-mode or buffer-local keybinds go), returned by the function
current-local-map
.
- The global keymap, returned by
current-global-map
.
There's a also a semi-item 10. Whatever command was found through the above procedure might also have been remaped.
The following function queries some of these possibilities (the most likely ones), and returns or prints the result.
(defun locate-key-binding (key)
"Determine in which keymap KEY is defined."
(interactive "kPress key: ")
(let ((ret
(list
(key-binding-at-point key)
(minor-mode-key-binding key)
(local-key-binding key)
(global-key-binding key))))
(when (called-interactively-p 'any)
(message "At Point: %s\nMinor-mode: %s\nLocal: %s\nGlobal: %s"
(or (nth 0 ret) "")
(or (mapconcat (lambda (x) (format "%s: %s" (car x) (cdr x)))
(nth 1 ret) "\n ")
"")
(or (nth 2 ret) "")
(or (nth 3 ret) "")))
ret))
There are built-in functions for each of these except the first, so we
must create one (also an improved version of the code linked above).
(defun key-binding-at-point (key)
(mapcar (lambda (keymap) (when (keymapp keymap)
(lookup-key keymap key)))
(list
;; More likely
(get-text-property (point) 'keymap)
(mapcar (lambda (overlay)
(overlay-get overlay 'keymap))
(overlays-at (point)))
;; Less likely
(get-text-property (point) 'local-map)
(mapcar (lambda (overlay)
(overlay-get overlay 'local-map))
(overlays-at (point))))))
Since you’re saying the behaviour is active when point is on an
attachment, there’s a good chance this keybind takes place on an
overlay or text-property.
If that doesn't work, try the following command as well. Just place the cursor on the attachment, and do M-x
keymaps-at-point
.
(defun keymaps-at-point ()
"List entire keymaps present at point."
(interactive)
(let ((map-list
(list
(mapcar (lambda (overlay)
(overlay-get overlay 'keymap))
(overlays-at (point)))
(mapcar (lambda (overlay)
(overlay-get overlay 'local-map))
(overlays-at (point)))
(get-text-property (point) 'keymap)
(get-text-property (point) 'local-map))))
(apply #'message
(concat
"Overlay keymap: %s\n"
"Overlay local-map: %s\n"
"Text-property keymap: %s\n"
"Text-property local-map: %s")
map-list)))
Searching Keymaps
. See also nodesFunctions for Key Lookup
andActive Keymaps
.