6

(I ask this question after reading this one.)


The form

(global-set-key (kbd "M-e") "e")

is, as far as I can tell, equivalent to

(global-set-key (kbd "M-e") (lambda () (interactive) (insert "e")))

However, after evaluating

(global-set-key (kbd "M-e") "abcdeéfghij")

pressing M-e inserts

abcde   fghij

(3 spaces instead of é). Looking up the keybinding, it appears that M-e is not really bound to (insert ...), but rather to a keyboard macro inserting all these chars... except that the é became a M-i. With a ê it's a linefeed (M-j). With a à it enters some menu (M-backtick), and so on.

But there isn't any problem if I create a macro using the keys for these characters.


So, the question is simple: what is going on here?

2 Answers 2

4

What is going on is that string in Emacs have historically been used in this context for 2 different purposes:

  • sequence of characters.
  • sequence of events.

In your case, you're writing what you think as a sequence of characters, but it's used in a context where Emacs expects a sequence of events.

Since Emacs-19 added support for GUIs, events have become a lot more complex, so sequences of events can also be represented as vectors rather than as strings. And this is usually the better option since it avoids this whole issue. IOW I'd recommend you write:

(global-set-key (kbd "M-e") [?a ?b ?c ?d ?e ?é ?f ?g ?h ?i ?j])

or

(global-set-key (kbd "M-e") (kbd "abcdeéfghij"))

or even

(global-set-key [?\M-e] [?a ?b ?c ?d ?e ?é ?f ?g ?h ?i ?j])

Since kbd is a function that turns a "human readable" string representation of events into an actual vector of events.

You could also M-x report-emacs-bug arguing that Emacs should figure out that the é (character code 233 (which is 128 + 105 where 105 is the code of i and 128 is the 7th bit that's used as the meta modifier in some contexts)) is really just a character and not the \M-i event, but it's probably difficult to fix this case without breaking existing code, since a lot of code still (mis)uses strings to represent sequences of events as if GUIs didn't exist.

4
  • Thanks for the detailed explanation. Out of curiosity, I went to check the release date for emacs 19... apparently that's 1994 (first beta in 1992). It's not that often that I meet a bug that's almost as old as I am! :) One question though: it seems from what you say that kbd does basically the same job as this legacy code (converting a string to a sequence of events), but much better from a 2016 point of view. Wouldn't this behavior be "easily" fixed by replacing this legacy code with calls to kbd where applicable (e.g. when binding keys)?
    – T. Verron
    Commented Oct 14, 2016 at 16:31
  • Also, I think you mean that 128 is the 8th* bit.
    – T. Verron
    Commented Oct 14, 2016 at 16:33
  • Right, I guess 8th is a better way to describe it (I was thinking "bit 7" when counting from 0, but I wouldn't call bit 0 "the 0th bit", I'd call it "the first bit").
    – Stefan
    Commented Oct 14, 2016 at 17:28
  • @T.Verron: The existing string representation of a sequence of events can't be changed without breaking existing code, so we can't just call kbd for the user, because we can't know if the string uses the old format or the "kdb format". My favorite option would be to signal an error when using a string as a "sequence of events" (or at least emit a warning) so as to force authors to update their code and use a vector (which they can do via kbd if they want).
    – Stefan
    Commented Oct 14, 2016 at 17:32
5

global-set-key is just a thin wrapper around define-key, ignoring some error checking it is

(defun global-set-key (key def)
   (define-key (current-global-map) key def))

The documentation for define-key says that the "def" can be a number of things, including

a string (treated as a keyboard macro),

So then there is the question about what something like ê is stored as. This typically has a character code of 0xea or 0x80+0x6a. 0x6a is the character code for j. The meta modifier is typically encoded as setting the top bit (0x80), hence ê being the same as M-j, and as a keyboard macro running something like comment-indent-newline.

1
  • Okay, that makes sense. Remains the question of why é (single key on my keyboard) gets transformed to M-i in these "def" strings, but behaves correctly if I define the keyboard macro myself. It's the translation from string to kbd macro which doesn't handle extended ascii correctly?
    – T. Verron
    Commented Oct 14, 2016 at 15:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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