29

I have the following line in init.el:

(global-set-key [(control \;)] 'comment-region)

It works very well in GUI window, but if emacs is invoked with the -nw option then C-; doesn't comment region, only inserts ; character. M-x comment-region RET works fine however.

I tried follow this answer on similar problem, but C-q C-; returns just ; and I obviously don't want to bind bare ;.

How to achieve desired effect?

  • 4
    It's possible that your terminal (what are you using, by the way?) does not recognize that command sequence. Try using the C-; combo and then use M-x view-lossage to see if it's even getting to Emacs. – Dan Oct 10 '14 at 13:02
  • I'm using gnome-terminal, and M-x view-lossage returns: ESC [ > 1 ; 2 8 0 2 ; 0 c ; ESC x v i e w - l o s s a g e RET – WeSenseASoulInSearchOfAnswers Oct 10 '14 at 13:07
  • 3
    Looks like a terminal issue: if that key combination were to reach Emacs, it would look like C-; rather than c ; (or, at least, I get C-;). – Dan Oct 10 '14 at 13:11
  • @Dan: Could you put that up as an answer? That would mark the question as answered and make it easier to see the solution, which is good for other people having the same problem. Thanks! – Tikhon Jelvis Oct 10 '14 at 19:40
  • Summarized and posted with an additional link for more reading. Also editing the question title to make it a bit more general. – Dan Oct 10 '14 at 19:55
16

First, the more general issue: terminal emulators are often limited in the control and escape sequences they can send. So: it may be the case that the terminal swallows your special characters before they reach Emacs. As a general diagnostic, you can hit C-h l (or M-x view-lossage) to see if your key combinations make it into Emacs.

For more discussion of this issue, have a look at this Stack Overflow thread and the links therein.

To summarize the back-and-forth in the comments, your specific problem suggests it's the terminal rather than Emacs that is the problem. When you tried C-; and then M-x view-lossage, you got blah blah blah c ; ESC v i e w - l o s s a g e RET. That looks like a terminal issue: if the key combination were reaching Emacs, the c ; part would look like C-;.

33

In Shift+Up isn't recognized by Emacs in a terminal I explain how terminals translate most function keys into escape sequences, because the interface between applications and terminals transmits characters (or rather bytes), not keys. Only a few modifier+character combinations have their own character:

  • Ctrl plus a letter or one of @[\]^_ turns into bytes 0–31 (ASCII control characters).
  • Often Ctrl+? turns into byte 127 and Ctrl+Space is equivalent to Ctrl+@ (byte 0).
  • Some function keys are equivalent to control characters: Tab = Ctrl+I, Return = Ctrl+M, Esc = Ctrl+[.
  • And Backspace = Ctrl+H or Ctrl+? depending on the configuration. Ctrl+? is more convenient for Emacs, since Ctrl+H is help.
  • Meta+character is sent as Esc followed by character.

So what about other combinations such as Ctrl+; or Ctrl+Shift+letter? Since there's no corresponding character, the terminal has to either reuse a character or send an escape sequence. Many terminals ignore modifiers when there's no corresponding character, so you end up with Ctrl+; sending ;, Ctrl+Shift+letter equivalent to Ctrl+letter, etc.

Terminal vendors kept doing the simple thing for a long time. There was no standard for escape sequences, which was self-perpetuating — terminal vendors don't implement it, applications don't support it, users don't expect it. Some terminal emulators can be configured to send arbitrary escape sequences, so if yours can, you can configure it and declare the escape sequences to Emacs (more on this later).

Lately, the situation is changing, because there have been two proposals to standardize on escape sequences. One is LeoNerd's libtermkey with the syntax ESC [ codepoint ; modifier u. Another is Thomas Dickey's xterm with the syntax ESC [ 2 7 ; modifier ; codepoint ~. Current versions of xterm (≥216) can be configured for either syntax by setting the formatOtherKeys resource; the feature must be activated by setting the modifyOtherKeys to a nonzero value.

If your terminal emulator doesn't support these syntaxes but can be configured, pick either.

Since Emacs 24.4, Emacs automatically turns on the modifyOtherKeys feature when it detects that the terminal is xterm version ≥216. Emacs's detection of escape sequences to encode keys works through the variable local-function-key-map. As of Emacs 24.4, not all escape sequences are supported. You can use the following code in your init file to complete the job.

;; xterm with the resource ?.VT100.modifyOtherKeys: 1
;; GNU Emacs >=24.4 sets xterm in this mode and define
;; some of the escape sequences but not all of them.
(defun character-apply-modifiers (c &rest modifiers)
  "Apply modifiers to the character C.
MODIFIERS must be a list of symbols amongst (meta control shift).
Return an event vector."
  (if (memq 'control modifiers) (setq c (if (or (and (<= ?@ c) (<= c ?_))
                                                (and (<= ?a c) (<= c ?z)))
                                            (logand c ?\x1f)
                                          (logior (lsh 1 26) c))))
  (if (memq 'meta modifiers) (setq c (logior (lsh 1 27) c)))
  (if (memq 'shift modifiers) (setq c (logior (lsh 1 25) c)))
  (vector c))
(defun my-eval-after-load-xterm ()
  (when (and (boundp 'xterm-extra-capabilities) (boundp 'xterm-function-map))
    (let ((c 32))
      (while (<= c 126)
        (mapc (lambda (x)
                (define-key xterm-function-map (format (car x) c)
                  (apply 'character-apply-modifiers c (cdr x))))
              '(;; with ?.VT100.formatOtherKeys: 0
                ("\e\[27;3;%d~" meta)
                ("\e\[27;5;%d~" control)
                ("\e\[27;6;%d~" control shift)
                ("\e\[27;7;%d~" control meta)
                ("\e\[27;8;%d~" control meta shift)
                ;; with ?.VT100.formatOtherKeys: 1
                ("\e\[%d;3u" meta)
                ("\e\[%d;5u" control)
                ("\e\[%d;6u" control shift)
                ("\e\[%d;7u" control meta)
                ("\e\[%d;8u" control meta shift)))
        (setq c (1+ c))))))
(eval-after-load "xterm" '(my-eval-after-load-xterm))

If the TERM environment variable isn't set to xterm or a variant such as xterm-256color, Emacs won't activate those sequences. If Emacs already has support for your value of TERM, you can add support by defining a function similar to the one above, to be executed after loading the Lisp file whose name is the value of TERM. If Emacs as no such support, you can add it by creating a subdirectory called term somewhere in your load-path, and creating a Lisp file called term/$TERM.el where $TERM is the value of TERM, defining a function called terminal-init-$TERM.

As I write, it seems that few terminal emulators other than xterm have adopted these escape sequences. On OSX, you can configure iTerm2 by selecting an escape sequence for each key combination, one by one.

  • 2
    Your answers on this subject are always superb, Gilles. Much appreciated. – phils Nov 12 '15 at 1:39
  • Great!. Though i have quite a hard time finding how to make urxvt sending those sequences. Could you give me a hand :) – Amos Aug 14 '17 at 1:25
  • @Amos I don't use rxvt. You should ask on Unix & Linux how to make urxvt send the same escape sequences as xterm with modifyOtherKeys. – Gilles Aug 14 '17 at 10:19
  • not works on macOS xterm-256color. M-C-% be recognized to ESC 5 – LoranceChen Dec 19 '17 at 3:29
  • @LoranceChen That's the expected behavior if the modifyOtherKeys feature is not active. Note that it is only supported in recent enough versions of xterm, and it is only activated automatically since Emacs 24.4. I don't know if OSX ships with recent versions. If it doesn't, and it isn't working for you, I suggest that you ask a new question. Mention the versions that you are using. – Gilles Dec 19 '17 at 13:36
2

Gilles' answer stated: On OSX, you can configure iTerm2 by selecting an escape sequence for each key combination, one by one. I had a little trouble getting there, so here a detailed explanation in case you are like me, confused.

If, when running Emacs in a terminal (e.g., Mac's default Terminal.app), C-x C-; does not run comment-line, and you would like that functionality, then you must switch to iTerm2 (Terminal.app does not have the capability) and create a Key Mapping under Profiles...Keys as follow:

^;     ^[[59;5u

This is accomplished by clicking on the + button, which brings up a little window called "Keyboard Shortcut"; this window has initially two fields; the top has a value of "Click to Set" and the bottom has a value of "Ignore." Click the top button and type C-;. This sets the key combination that will run the action and code. Click the bottom field, "Action", and find and click on "Send Escape Sequence", which is down a little more than half way. After you click that, a third field will appear, called "Esc+". Inside this field, type:

[59;5u

The 59 is comma's decimal ASCII code, and the 5 is the code for Ctrl. Then press "OK" to finish. The correct key combo to key sequence will now be included in iTerm2's preferences. When you start up Emacs in iTerm, you will now have access to C-x C-; functionality.

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.