I've seen many different ways of specifying key combinations for setting or unsetting key bindings in emacs. Some are quoted, others are bracketed, some are escaped, others are not. Do they all work in all contexts? Is there a best practice?

Some examples from my init file which may or may not work:

(define-key org-mode-map (kbd "<M-S-right>") nil)
(define-key evil-normal-state-map (kbd "C-k") (foo))
(define-key global-map (kbd "RET") 'newline-and-indent)
(global-set-key [(C-f4)] 'bury-buffer)
(global-set-key [(f6)] 'emms-playlist-mode-go)
(define-key c-mode-map  [(tab)] 'company-complete)
(define-key ggtags-mode-map (kbd "C-c g s") 'ggtags-find-other-symbol)
(setq helm-gtags-prefix-key "\C-cg")
(define-key evil-normal-state-map [escape] 'keyboard-quit)
(bind-key "<escape>" 'isearch-cancel isearch-mode-map)
(global-unset-key "\M-:")

Is there a canonical way to define key combinations? If so, where can I read about it, especially for a list of special and modifier keys (tab, escape, return, meta, ctrl, shift, super, Fn, delete)?

edit: This question and the answers below go a lot deeper than the similar question asked here.

  • For additional examples, have a look at the built-in source code located at .../lisp/bindings.el and .../lisp/term/ns-win.el (for OSX).
    – lawlist
    May 28 '16 at 22:51
  • 3
  • 1
    All I can tell you is that [(C-f4)] is the obsolete way or as the sources put it, "Lucid-style event type list". Personally, I'd always use the kbd syntax unless there's something you can't easily represent with it, then you can go for either strings or vectors.
    – wasamasa
    May 29 '16 at 13:23

The internal representation of a key sequence is as a vector of events. The internal representation is anything that the built-in primitives define-key and lookup-key recognize, and all the other functions based on them.

An individual event can be a character (for characters, possibly with modifiers), a symbol (for any event, possibly with modifiers) or a list (containing modifiers and a base event). There can be more than one representation of an event, e.g. (meta ?a) and ?\M-a are the same event. I don't think that there is one representation of events that is officially declared canonical.

If you want to compare events (but you probably don't, because input processing is complicated — let the keymap code handle that), you can call event-modifiers and event-basic-type to decompose an event, or contrariwise event-convert-list to pack the event into a single symbol.

The kbd function turns a “human-friendly” key sequence representation into an internal event representation.

When defining a keymap, use whatever syntax you prefer.

There are some events that are normally mapped to the same binding, via translation keymaps. If you're defining a package, you should steer away from those translation keymaps; these are to some extent terminal-dependent and to some extent a user preference. Here a few things to be aware of:

  • Some function keys are mapped to a control character:

    • [escape](kbd "ESC") = ?\e = ?\C-\[
    • [return](kbd "RET") = ?\r = ?\C-m (and [linefeed] to ?\C-j but few keyboards have that)
    • [tab](kbd "TAB") = ?\t = ?\C-i
    • [backspace](kbd "DEL") = ?\C-? (with additional complications relating to ?\C-h that I won't go into)

    Don't define bindings for those function keys, define bindings for the corresponding character instead.

  • ESC is very special. ESC key is normally equivalent to (meta key). On text terminals, most function keys are mapped to character sequences that start with ESC. So never define a binding for ESC.
  • A mouse click has the mouse button going down, then up, with the mouse possibly moving in between. This generates a flurry of different events. In addition rapid repeated clicks (double click, etc.) are recognized as such. See Mouse Events and subsequent sections in the manual.
  • "never define a binding for ESC" seems incompatible with evil-mode, whose rising popularity can't be ignored. Notice my binding (global-unset-key "\M-:") is to prevent the fast sequence ESC : w RET from trying to interpret w as lisp instead of saving the buffer. May 29 '16 at 12:38
  • 1
    Evil uses elaborate hacks with great care to allow doing this without messing with keybindings involving meta. Point is if you naïvely define a binding to ESC, this breaks meta.
    – wasamasa
    May 29 '16 at 13:24
  • @AlejandroErickson I meant that for “ordinary” modes and “normal” users. Evil isn't an ordinary mode, it essentially takes over the whole interface. May 29 '16 at 22:33
  • ok thanks. I was just clarifying, not accusing :) May 29 '16 at 23:47
  1. There is no "canonical" representation.

  2. If you want an external, i.e., source-code representation that is applicable generally and easy to read, then use kbd. The manual and C-h k will tell you the external representation for a given key, and you can pass that to kbd in a string. The value returned is an internal representation of the key sequence. Similarly, you can use function key-description as an approximate inverse of kbd.

    For example, in the example you gave of using [(C-f4)] you could just as easily used the external representation C-<f4>, wrapping that as a string with kbd: (kbd "C-<f4") -- that returns [C-f4] which is equivalent to [(C-f4)].

  3. To see how a given key binding might be represented internally, you can also examine a keymap where it is bound (using, for example, C-h v with a keymap variable, such as ctl-x-map).

The doc for kbd tells you:

This function converts the text KEYSEQ-TEXT (a string constant) into a key sequence (a string or vector constant). The contents of KEYSEQ-TEXT should use the same syntax as in the buffer invoked by the C-x C-k <RET> (kmacro-edit-macro) command; in particular, you must surround function key names with <…>. See (emacs)Edit Keyboard Macro.

See the Emacs manual, node Key Bindings and its subnodes, and the Elisp manual, node Keymaps and its subnodes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.