3

If I run cat under terminal (xterm-256color), and then press the up arrow button, I see ^[[A as output.

But if I press <ctrl-v> <up> in vim insert mode, I see ^[OA as output.

So i wonder why the byte sequence ^[[A will become ^[OA, is there any internal key code translation in vim?

6

You can paste Vim's builtin termcap database in the current buffer with the following command:

put =execute('set termcap')

In it, you should find the text t_ku <Up> ^[OA, which means that when you press Up, the terminal will send Esc O A. Or you could just execute :echo &t_ku, to get the value of the terminal option 't_ku' (see :h t_ku). It should display ^[OA.

I don't know all the details about why there's a difference between $ cat and Vim, but you may be interested in these links:

Here's an excerpt from the first link:

VTxxx (VT100 and up) terminals may send different escape sequences for the cursor (arrow) keys depending on how they are set up. The choices are referred to as the normal and application modes. Initially, the terminal is in normal mode.

VTxxx terminals are usually set up so that full-screen applications will use the cursor application mode strings. This is good for full-screen applications, including legacy applications which may have hard-coded behavior, but bad for interactive shells (e.g., ksh, tcsh, bash) which use arrow keys to scroll through a history of command strings.

To see the difference between normal/application modes, consider this example:

  • In normal (non-application) mode, the terminal transmits a down-arrow as \E[C, which happens to echo as a down-arrow.
  • In application mode the terminal transmits \EOC, which echoes as C. That is because the \EO is the SS3 control, which says to use the character from the G3 character set for the next cell.

And here's a table from the second one:

The cursor keys transmit the following escape sequences depending on the
mode specified via the DECCKM escape sequence.

              Key            Normal     Application
              -------------+----------+-------------
              Cursor Up    | CSI A    | SS3 A
              Cursor Down  | CSI B    | SS3 B
              Cursor Right | CSI C    | SS3 C
              Cursor Left  | CSI D    | SS3 D
              -------------+----------+-------------

Basically, it seems that the terminal is in “normal mode” when you are in the shell, and in “application mode” when you are in a full-screen application such as Vim.

When you press Up, the terminal sends the sequence:

  • (if it's in normal mode) CSI A, where CSI means Control Sequence Introducer and is produced by ESC [; in caret notation, the whole sequence is displayed as ^[[A
  • (if it's in application mode) SS3 A, where SS3 is described as Single Shift Select of G3 Character Set here, and is produced by ESC O; in caret notation, the whole sequence is displayed as ^[OA

You can also probably find these 2 sequences, Esc [ A and Esc O A, in the xterm-256color entry of your terminfo database:

$ infocmp -x xterm-256color | vim -R -

Inside this buffer, if you look for the capabilities cuu1 and kcuu1, you should find:

cuu1=\E[A
kcuu1=\EOA

In man terminfo, these capabilities are described as follows:

   cursor_up              cuu1                    up               up one line
   key_up                 kcuu1                   ku               up-arrow key

As rightly pointed out by @Rich, in the shell, you can make the terminal enter the application mode by sending the sequence stored in the smkx capability. To do so, you may execute $ tput smkx. And to make it re-enter the normal mode, you may execute $ tput rmkx.

So, you could temporarily make the Up key produce Esc O A like in Vim, if you executed:

$ tput smkx
$ cat
  Up
  C-c
$ tput rmkx

The smkx and rmkx capabilities are also described in man terminfo:

keypad_xmit         smkx        ks        enter 'keyboard_transmit' mode
keypad_local        rmkx        ke        leave 'keyboard_transmit' mode

For some reason, here, the application mode is called keyboard_transmit mode. In Vim, it's called keypad transmit mode (see :h t_ks).

  • 1
    Nice answer! An extra detail is that Vim switches between the two modes by sending the escape sequences specified in its t_ks and t_ke settings, which correspond to terminfo's smkx and rmkx capabilities. You can try out switching modes outside of Vim by running the command tput smkx in your shell, after which the Ctrl-V Up sequence will report the same in the shell as it does in Vim. tput rmkx will then revert to the normal mode. – Rich Feb 23 '18 at 10:23
  • Cool, really helpful answer. Thx very much ! – jayven Feb 23 '18 at 13:59

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.