I have an issue when I run emacs with -nw: all my C-M- bindings stop working, as C (control) doesn't register, and only the M- binding is executed.


  (global-set-key (kbd "C-M-.") 'vundo)

-- works in Emacs GUI, but with emacs -nw I get M-. executed. I have key chords start with C-M-<return>, in -nw mode I always get the message: M-RET is undefined.

The terminal emulator might be behind this? - I tried xterm, urxvt, alacritty and kitty, same everywhere.

My emacs config? I tried with emacs -Q -nw -> same issue.

What am I missing? Where is my Control going in terminal mode?


1 Answer 1


There are two issues at play here, both of which have to do with the terminal environment (tty):

  1. Your terminal emulator (usually*) gets first dibs over any key combos that you enter, which can be a problem for any chords that happen to match a shortcut. For example, in terminator, C-M-w renames a window even in emacs tty mode. (In my version of doom emacs gui, this appends from the kill ring.) In this case, you won't have much choice except to find which shortcut could be interferring. I do not believe that is the main issue for the specific problem you listed though because 2) is more likely in play.

  2. Terminal emulators sends characters not keystrokes. See this excellent discussion in the Unix SE for an overview. Also see further here that talks about making a terminal emulator to handle all key combos. But in summary: While it is possible to press a chord in emacs gui to enact some functionality and a different key for a different set of functionality, when we step into emacs tty, emacs could end up seeing the same characters on both keypresses. This is especially noticeable for chords involving any of the control keys**. In other words, the information that you pressed C is lost.

There are not any easy fixes to number 2 because there aren't standard escape code messages for all terminals and key combos as far as I can tell. You could approach the problem in a few ways:

In ~/.Xresources to define behaviours with C, S, and M:

 Term.VT100.translations:       #override \n\
     Ctrl ~Shift ~Meta <key>Return: string("\033[73;5~") \n\
     Ctrl Shift ~Meta <key>percent: string("\033[37;6~") 

Then in emacs, translate into mapping (the above uses number representation to send in ESC [ n1 ; n2 ~ where n2 is the number we get if we treat shift as 2, meta as 3, control as 5, control + meta as 7, or add 1 to the other number wherever we added shift to the combo.

(define-key local-function-key-map "\033[37;6~" [(control ?L)])
(define-key local-function-key-map "\033[37;6~" [(control ?L)])

*Not always though. Observe that you can enter C-d in emacs tty mode and not close your session. If you exit emacs and do the same on the terminal, you close the session. This also holds for other common chords like C-c and C-x.

**But you may find control keys and chords which are not affected. Note how C-M-q works in emacs tty for instance if you assign a chord to it.

  • 1
    Good answer, but before defining a million custom escape sequences, look into your terminal emulator’s preferences. XTerm, for example, has the option modifyOtherKeys which sends escape sequences that Emacs will already recognize for most if not all such combinations. Other terminal emulators will likely have something similar.
    – db48x
    Commented Jan 22, 2023 at 1:39
  • 1
    Ah, thank you! I meant to include a section about terminal specific solutions, because I learned while trying to remap capsLock to ctrl that you can use xkb to send modifiers to terminal. I edited the answer to point out what you mentioned here.
    – Malle Yeno
    Commented Jan 22, 2023 at 2:01
  • Thanks a lot for all the background!
    – parszab
    Commented Jan 22, 2023 at 16:57

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