6

This question is a follow-up to this answer (q.v.).

I understand that Emacs interprets esc as M- only when the keystroke that follows it corresponds to a "character" (e.g. A, 5, ;, etc.), as opposed to, e.g., , F5, home, etc.

What can I add to my .emacs file to extend the esc ⇒ M- interpretation to the case where the following key is a "non-character" key?


OK, the following snippet takes care of my immediate problem, but it's not an answer to my question (see below):

(add-hook 'org-mode-hook
    (lambda ()
        (define-key org-mode-map [27 S-down] 'org-shiftmetadown)
        (define-key org-mode-map [27 S-up] 'org-shiftmetaup)
        (define-key org-mode-map [27 S-right] 'org-shiftmetaright)
        (define-key org-mode-map [27 S-left] 'org-shiftmetaleft)
        (define-key org-mode-map [27 down] 'org-metadown)
        (define-key org-mode-map [27 up] 'org-metaup)
        (define-key org-mode-map [27 right] 'org-metaright)
        (define-key org-mode-map [27 left] 'org-metaleft)
        (define-key org-mode-map [27 return] 'org-meta-return)
        (define-key org-mode-map [27 S-return] 'org-insert-todo-heading)))

To find the bindings I needed to define, I got a listing of org-mode-map (with C-h v), and searched for M- to get all the bindings beginning with M-:

  (M-S-down . org-shiftmetadown)
  (M-S-up . org-shiftmetaup)
  (M-S-right . org-shiftmetaright)
  (M-S-left . org-shiftmetaleft)
  (M-down . org-metadown)
  (M-up . org-metaup)
  (M-right . org-metaright)
  (M-left . org-metaleft)
  (M-return . org-meta-return)
  (M-S-return . org-insert-todo-heading)

Each one of these lines is the basis for a corresponding define-key expression in the mode-hook shown above. The transformation should be pretty obvious. (The 27 in the define-key expressions is the code for esc.)

One would need to do this sort of thing for every single mode X that defines a key binding of the form M- followed by a non-character key sequence. Specifically, for every such binding, one would have to include a define-key expression in a mode-hook for mode X. Therefore, this approach is obviously a very laborious, fragile, and hard-to-maintain hack. It does not do what the question requests, but instead painstakingly simulates it for certain special cases. For this reason I did not post it as an answer, in the hopes that someone will post an actual answer to the original question.

6

Emacs already has a key binding for “apply meta to the next key”, but it's awkward to type: C-x @ m (alongside C-x @ c for “apply control to the next key”, etc.). It's implemented by a binding to event-apply-meta-modifier in function-key-map.

Binding escape to event-apply-meta-modifier in function-key-map won't work because bindings there are shadowed by bindings in the global map or in minor mode maps, and these do have bindings for escape. (You could remove the global binding for escape but that would leave you at the mercy of minor modes.) Instead, you can bind escape in input-decode-map.

(define-key input-decode-map [escape] 'event-apply-meta-modifier)
(define-key global-map [?\M-\e M-escape] 'keyboard-escape-quit)

The second command binds keyboard-escape-quit to four presses of the Escape key; it's normally bound to three presses but that binding won't be accessible any longer.

In a terminal, this won't work, because the Escape key sends the ?\e (ESC) character, not the escape key. Adding the same binding for "\e" would break all function keys that are encoded as escape sequences in a terminal.

If you want M-key bindings to take precedence over ESC key in a terminal, I can't think of a good way that doesn't require binding every key. You don't have to do it in every mode though: you can add a series of macros in the global map.

(require 'cl)
(dolist (key '(f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
               left right up down prior next home end))
  (dolist ((chord `((,key)
                    (shift ,key)
                    (control ,key)
                    (control shift ,key))))
    (global-set-key (vector ?\e chord) (vector (cons 'meta chord)))))

On Linux, I do find that Org mode bindings work when I press Escape followed by Left etc., so you shouldn't need the terminal part, only the input-decode-map binding for escape for GUI-based Emacs.

  • 1
    Good post. I learned something. – Drew Nov 30 '14 at 21:38

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.