I am writing simple terminal so I am trying to understand some basic things about control symbols, escape sequences and how all that is related to terminfo and termios.
What I find awkward is that according to the input I have from tty and according to tput
left key is mapped to Backspace code (ASCII code 8)
tput cub1 | od -tx1
0000000 08
0000001
while I would expect it to be \033[D
because
$ tput cuf1 | od -tx1
0000000 1b 5b 43
0000003
which is \033[C
code that is right key indeed according to various documents about terminal codes.
So the absence of symmetry here is quite confusing to me. Is there a specific reason behind it?
The second question: is there way to change it?
I have created example of raw terminal which demonstrates this behaviour: RawTerminal.
The cub1
capability is not left arrow, but instead a cursor movement capability. Referring to terminfo(5), you may find
cursor_left cub1 le move left one space
which is named similarly to the key marked "left-arrow":
key_left kcub1 kl left-arrow key
The cursor-movement capabilities do just that: move the cursor around on the screen. In some cases, the similarly-named cursor-movement and cursor-keys have the same string, just because (long ago) it was useful to have keys which one could setup to echo locally (rather than send to a host application).
In this particular case, the two are different because the main use of these terminal descriptions is for curses applications, which minimize the number of characters sent to the screen (as well as minimizing the time spent sending the characters). Making cub1
send an ASCII backspace is fewer characters than the escape sequence.
While there is no requirement, longstanding convention tells you that terminfo capabilities which begin with "k" are probably for the keyboard.
bash uses readline for reading keys and updating the line which you are typing on. Checking its source-code, e.g., from bash-4.2 I am looking at lib/readline/terminal.c, it has a table of the termcap strings that it may use:
static const struct _tc_string tc_strings[] =
{
{ "@7", &_rl_term_at7 },
{ "DC", &_rl_term_DC },
{ "IC", &_rl_term_IC },
{ "ce", &_rl_term_clreol },
{ "cl", &_rl_term_clrpag },
{ "cr", &_rl_term_cr },
{ "dc", &_rl_term_dc },
{ "ei", &_rl_term_ei },
{ "ic", &_rl_term_ic },
{ "im", &_rl_term_im },
{ "kD", &_rl_term_kD }, /* delete */
{ "kH", &_rl_term_kH }, /* home down ?? */
{ "kI", &_rl_term_kI }, /* insert */
{ "kd", &_rl_term_kd },
{ "ke", &_rl_term_ke }, /* end keypad mode */
{ "kh", &_rl_term_kh }, /* home */
{ "kl", &_rl_term_kl },
{ "kr", &_rl_term_kr },
{ "ks", &_rl_term_ks }, /* start keypad mode */
{ "ku", &_rl_term_ku },
{ "le", &_rl_term_backspace },
{ "mm", &_rl_term_mm },
{ "mo", &_rl_term_mo },
{ "nd", &_rl_term_forward_char },
{ "pc", &_rl_term_pc },
{ "up", &_rl_term_up },
{ "vb", &_rl_visible_bell },
{ "vs", &_rl_term_vs },
{ "ve", &_rl_term_ve },
};
Using "infocmp -Cr xterm", I can see this:
xterm|xterm terminal emulator (X Window System):\
:am:bs:km:mi:msn:\
:co#80:it#8:li#24:\
:AL=\E[%dLC=\E[%dPL=\E[%dMO=\E[%dB:IC=\E[%d@:\
:K2=\EOE:LE=\E[%dD:RI=\E[%dC:SF=\E[%dS:SR=\E[%dT:\
:UP=\E[%dA:ae=\E(B:al=\E[L:as=\E(0:bl=^G:bt=\E[Z:cd=\E[J:\
:ce=\E[K:cl=\E[H\E[2J:cm=\E[%i%d;%dH:cr=^M:\
:cs=\E[%i%d;%dr:ct=\E[3gc=\E[Pl=\E[Mo=^J:ec=\E[%dX:\
:ei=\E[4l:ho=\E[H:im=\E[4h:is=\E[!p\E[?3;4l\E[4l\E>:\
:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:k5=\E[15~:k6=\E[17~:\
:k7=\E[18~:k8=\E[19~:k9=\E[20~:kD=\E[3~:kI=\E[2~:kN=\E[6~:\
:kP=\E[5~:kb=\177:kd=\EOB:ke=\E[?1l\E>:kh=\EOH:kl=\EOD:\
:kr=\EOC:ks=\E[?1h\E=:ku=\EOA:le=^H:mb=\E[5m:md=\E[1m:\
:me=\E[0m:mh=\E[2m:mm=\E[?1034h:mo=\E[?1034l:mr=\E[7m:\
:nd=\E[C:rc=\E8:sc=\E7:se=\E[27m:sf=^J:so=\E[7m:sr=\EM:\
:st=\EH:ta=^I:te=\E[?1049l:ti=\E[?1049h:ue=\E[24m:up=\E[A:\
:us=\E[4m:vb=\E[?5h\E[?5l:ve=\E[?12l\E[?25h:vi=\E[?25l:\
:vs=\E[?12;25h:
or with "infocmp -Cr nsterm":
nsterm|Apple_Terminal|AppKit Terminal.app:\
:am:hs:mi:msno:\
:co#80:it#8:li#24:ws#50:\
:AL=\E[%dLC=\E[%dPL=\E[%dMO=\E[%dB:IC=\E[%d@:\
:K1=\EOq:K2=\EOr:K3=\EOs:K4=\EOp:K5=\EOn:LE=\E[%dD:\
:RI=\E[%dC:UP=\E[%dA:ae=^O:al=\E[L:as=^N:bl=^G:cd=\E[J:\
:ce=\E[K:cl=\E[H\E[J:cm=\E[%i%d;%dH:cr=^M:cs=\E[%i%d;%dr:\
:ct=\E[3gc=\E[Pl=\E[Mo=^Js=\E]2;\007:ei=\E[4l:\
:fs=^G:ho=\E[H:ic=\E[@:im=\E[4h:k1=\EOP:k2=\EOQ:k3=\EOR:\
:k4=\EOS:k5=\E[15~:k6=\E[17~:k7=\E[18~:k8=\E[19~:\
:k9=\E[20~:kD=\E[3~:kN=\E[6~:kP=\E[5~:kb=\177:kd=\EOB:\
:ke=\E[?1l\E>:kh=\EOH:kl=\EOD:kr=\EOC:ks=\E[?1h\E=:\
:ku=\EOA:le=^H:mb=\E[5m:md=\E[1m:me=\E[0m:mh=\E[2m:\
:mr=\E[7m:nd=\E[C:rc=\E8:\
:rs=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:sc=\E7:se=\E[m:\
:sf=^J:so=\E[7m:sr=\EM:st=\EH:ta=^I:te=\E[2J\E[?47l\E8:\
:ti=\E7\E[?47h:ts=\E]2;:ue=\E[m:up=\E[A:us=\E[4m:\
:vb=\E[?5h\E[?5l:ve=\E[?25h:vi=\E[?25l:
The ":le=^H:" part is what you are seeing.
From (ncurses) terminfo(5):
cursor_left cub1 le move left one space
if you made a termcap (for "xterm") setting that to \e[D, then bash should
echo back \e[D
rather than ^H
. But ncurses uses ^H
to reduce the number of
characters from from 3 (\e[D
) to 1 (^H
)
Rather than modify the terminal description, you should modify your program, e.g., to read the termcap strings and handle those.