How do I create CTRL key bindings in vim when using tmux?

Solution 1:

The recommended TERM setting for tmux is screen-256color and the snippet you added to your vimrc works only for a TERM that starts with screen so you can be sure that code block will never be executed if your TERM is xterm.

I've been successfully using that very snippet in the past on this machine, without set-window-option -g xterm-keys on, but for whatever reason it doesn't seem to work anymore for me (I didn't use tmux in the last three months). I wonder what's going on. An iTerm upgrade? A tmux upgrade?

Adding set-window-option -g xterm-keys on to my ~/.tmux.conf fixes the problem.

Anyway, you could directly map the raw sequences produced by <C-Left> and <C-Right> as a temporary workaround.

nnoremap <C-v><C-Left> :tabprevious<CR>

should give you something like:

nnoremap ^[[D :tabprevious<CR>

Solution 2:

Unless you see the code (e.g. <C-Left>) you're using in the section "Terminal keys" of :set termcap, you can't use it right away.

The docs lists 3 ways to map a special key. First in Insert or Cmdline mode press Ctrl-K, then the key sequence you want to map (e.g. Ctrl-K Ctrl-Left). If it prints <...>, you can use that for the left-hand side of your mapping. Or else, prepend it with <Esc> (Ctrl-V Esc), or use Ctrl-V Ctrl-Left. For example, under tmux I get [1;5D for Ctrl-Left, and <Left> for Left. Which means that for Left I can use <Left>, and for Ctrl-Left I need ^[[1;5D (^[ should be one character, Ctrl-V Esc, and do note the trailing <CR>):

nnoremap ^[[1;5D <Cmd>tabprevious<CR>

Or (:h :set-termcap):

set <C-Left>=^[[1;5D
nnoremap <C-Left> <Cmd>tabprevious<CR>

If you work under different terminals you probably want the second approach:

if &term =~ '^screen'
    set <C-Left>=...
elseif &term =~ '^tmux'
    set <C-Left>=...
endif
nnoremap <C-Left> <Cmd>tabprevious<CR>

Some keys work with some terminals, but doesn't work with others (when they have no field in the corresponding terminfo entry). Let's take <S-Left>, for example. From :set termcap not under tmux (TERM=rxvt-unicode-256color) I can see that it resides in the t_#4 termcap field:

t_#4 <S-Left>    ^[[d

man terminfo says:

key_sleft                   kLFT      #4     shifted left-arrow
                                             key

Which means that the terminfo name is kLFT. Now let's see the value of this field for TERM=rxvt-unicode-256color (not under tmux), TERM=screen (under tmux) and TERM=tmux (which we might need later):

$ infocmp rxvt-unicode-256color | grep kLFT
    kLFT=\E[d, kNXT=\E[6$, kPRV=\E[5$, kRIT=\E[c, ka1=\EOw,

$ infocmp screen | grep kLFT

$ infocmp tmux | grep kLFT
    kHOM=\E[1;2H, kIC=\E[2;2~, kLFT=\E[1;2D, kNXT=\E[6;2~,

It's missing in the screen terminfo entry. To resolve this:

if &term =~ '^screen'
    set <S-Left>=...
endif
nnoremap <S-Left> <Cmd>tabprevious<CR>

Or (with vim we must use termcap names):

if &term =~ '^screen'
    set t_#4=...
endif
nnoremap <S-Left> <Cmd>tabprevious<CR>

Alternatively, you can tell tmux to use its own terminfo entry:

set -g default-terminal tmux

On a side note, avoid using the <Esc> character if possible in your config (or generally in a text file). It's one character that looks like 2. If you e.g. copy it with a mouse, ^[ becomes 2 characters and this way it doesn't work. Particularly in the documentation you can find examples where ^[ is 2 characters, that you can't just copy. This sort of thing is easy to overlook.

And by the way, xterm-keys is not available since 2.4.

If it still doesn't work, tell me what you press and the escape sequence it produces (use Ctrl-V).