If you’ve been using a terminal for a while, you’ve surely stumbled across the terminal’s legacy keyboard handling. Terminal escape codes were created in the 1970s and haven’t been updated much.
CTRL + J == newline CTRL + I == tab
These two examples are some of the least annoying, but the implications aren’t at first obvious. Normal terminal apps can’t tell whether you actually typed “ENTER” on your keyboard or “CTRL” + “I”. From the perspective of the app, it’s the same. Sadly, that’s just the tip of the iceberg for these limitations.
CTRL + … Sequences starting with CTRL+… are basically used up by the way the terminal represents common data (CTRL + D == EOF) with “CTRL CODES”, and CTRL+SHIFT+letter is the same as CTRL+letter
ALT + C might be encoded as 0xc3, which collides with UTF-8 for characters like: é.
SHIFT + … The terminal doesn’t know the difference between “Shift + s” and “S”…
Hyper +… Hardly any apps are cool enough to be able to work with the awesome hyper modifier… Without an enhanced way to process keycodes, this isn’t possible.
Many terminals rely on timing to distinguish codes like Alt+C from Esc + C… This generates lag and errors when typed too slow or too fast. vim-fixkey has a nice list of workarounds to get full access to keypresses in the terminal, though even in the best case scenario, it would be limited by a timeout, and not work for Cmd, Hyper or various CTRL+x keys…
Fortunately Leonerd, the author of libtermkey (now replaced by libtickit), wrote the “fixterms” specification and the author of Kitty has extended the fixterms spec to cover Super, Hyper and other modifier keys. iTerm 2 is also being extended to cover the new Kitty version of the fixterms spec.
Some of this is “worked around” with the XTerm
ModifyOtherKeys option that’s also supported in gnome-terminal and Konsole. Unfortunately ModifyOtherKeys is not complete.
There is discussion on the NeoVim github issues about adding fixterms support in neovim, but at this time (Nov 2021) it seems that no support is yet complete. It looks like
neovim/src/nvim/keymap.c probably holds most of the code that needs to change.
Fix ambigous terminal key strokes? https://github.com/neovim/neovim/issues/176
Someone may have worked on an actual code change for this, tracking at: https://github.com/neovim/neovim/issues/6279
TUI: enable/disable modifyOtherKeys automatically https://github.com/neovim/neovim/issues/15352
TUI: distinguish Tab, CTRL-i (S8C1T mode) https://github.com/neovim/neovim/issues/5916
CTRL-Alt-Space isn’t recognized even though terminal sends ^[^@, works in Vim https://github.com/neovim/neovim/issues/14836
Binding <M-S-Tab> https://github.com/neovim/neovim/issues/2379
TUI: S8C1T (8-bit) mode, v:termresponse https://github.com/neovim/neovim/issues/6279
See: “xterm-8-bit” Nvim does not use 8-bit sequence detection, and always uses 7-bit sequences (for now)
One day, hopefully Neovim will support these sequences by default, but in the mean time it’s possible to map these sequences manually in Kitty and Neovim, it’s possible to manually use a specific mapping by configuring Kitty’s
map ... send_text
# In Kitty.conf Example map ctrl+enter send_text normal,application \x1b[13;5u # In init.lua vimp = require('vimp') vimp.bind('n', '<C-cr>', ':echom "Hello C + R"<CR>')
Remember, the Kitty chart for progressive enhancement is:
|0b1 (1)||Disambiguate escape codes|
|0b10 (2)||Report event types|
|0b100 (4)||Report alternate keys|
|0b1000 (8)||Report all keys as escape codes|
|0b10000 (16)||Report associated text|
So \x1b = 11011… So it will turn on all options except “report alternate keys”.
Decimal 13 == Carriage Return
; 5u == modifier flags == “Ctrl” + 1.
shift 0b1 (1) alt 0b10 (2) ctrl 0b100 (4) super 0b1000 (8) hyper 0b10000 (16) meta 0b100000 (32) caps_lock 0b1000000 (64) num_lock 0b10000000 (128)
# In Kitty.conf Example map ctrl+tab send_text normal,application \x1b[9;5u map ctrl+shift+tab send_text normal,application \x1b[9;6u # In init.lua vimp = require('vimp') vimp.bind('n', '<C-tab>', ':echom "Hello Tab"<CR>') vimp.bind('n', '<C-S-tab>', ':echom "Hello Shift Tab"<CR>')
In this example, the relevant parts are:
\x 1b [ 9 ;5u \x 1b [ 9 ;6u ^ 1b = 11011binary == turn on Disambiguate Esc Codes, Report Event Types, Report All Keys as Escaped, Report Associated Text [ is just the end of our escape code 9 is the keycode for Tab 5u = 1 (constant) + 4 (0100) Control 6u = 1 (cont) + 5 4 = ctrl + 1 shift = 5
Let’s go through a few more examples. Let’s try:
CTRL + Super + Tab. Unfortunately, even though Kitty can send this one, until Neovim’s keyboard support is more complete, it doesn’t look like Neovim has any way to receive this keycode.
CTRL = 4 SUPER = 8 Constant = 1 Total =13 # Remember, Tab = 0x9 \x 1b [ 9; 13u
Sadly, I can’t get Super or Hyper based shortcut keys to work in Neovim or regular Vim yet, but I think it will be here soon…