^[control-codes live in libghostty-vt

Escape sequences

XTGETTCAP Request Termcap/Terminfo String

Ask the terminal what a key sends, or for one of a few of its capabilities, by its terminfo or termcap name.

DCS + q Pt ST
xterm
Device-Control functions

DCS + q Pt ST asks for one or more capabilities by name, so that a program can learn about the terminal it is actually talking to rather than trusting $TERM’s terminfo entry, which may be wrong or on another machine. Pt is the names, each in hexadecimal and separated by ;: kcuu1 is 6B63757531. The answer is DCS 1 + r name=value ST, with the name as it was sent and the value in hexadecimal too, or DCS 0 + r ST if the first name is not one the terminal knows.

It is xterm’s, and what a default xterm knows is a fixed table, not a terminfo entry (xtermcap.c):

  • the keys: arrows, editing keys, function keys and the keypad, each by its terminfo name (kcuu1, khome, kf1) or its termcap name (ku, kh, k1), and shifted ones such as kRIT;
  • Co or colors, the number of colors, 256;
  • RGB, the bits per color it can show directly, 8 on a 24-bit display;
  • TN or name, the terminal name it set $TERM to, xterm unless the termName resource says otherwise.

A key is answered by pretending to press it, so the answer is what the key sends now: kcuu1 is CSI A, until DECCKM makes it SS3 A (XTGETTCAP, xtermcapKeycode, cursor keys). Several names in one request get one answer, with the name=value pairs separated by ;; it stops at the first name it does not know, after writing the ;.

libghostty-vt answers from Ghostty’s own terminfo entry instead. Its key strings are fixed, the ones that entry gives, which assume DECCKM is set; it knows terminfo names only; it answers many capabilities xterm does not, such as Smulx and setrgbf, giving those as their terminfo source text; it gives each name its own DCS … ST, writes the names back in upper case, and says nothing about a name it does not know. It does not answer TN. The cases follow a default xterm, and the cases that touch those differences are known differences.

The names in the cases are sent in upper-case hexadecimal, which both write back unchanged, so that a case shows one difference at a time.

Validation

XTGETTCAP-1: Number of colors

\eP+q436F\e\\  # Co
\eP+q636F6C6F7273\e\\  # colors
|______|
reply \eP1+r436F=323536\e\\\eP1+r636F6C6F7273=323536\e\\

XTGETTCAP-2: Direct color

\eP+q524742\e\\  # RGB
|______|
reply \eP1+r524742=38\e\\

XTGETTCAP-3: F1

\eP+q6B6631\e\\  # kf1
|______|
reply \eP1+r6B6631=1B4F50\e\\

XTGETTCAP-4: Up arrow, as it is now

\eP+q6B63757531\e\\  # kcuu1: CSI A
|______|
reply \eP1+r6B63757531=1B5B41\e\\

XTGETTCAP-5: Up arrow, after DECCKM

\e[?1h
\eP+q6B63757531\e\\  # kcuu1: SS3 A
|______|
reply \eP1+r6B63757531=1B4F41\e\\

XTGETTCAP-6: Home

\eP+q6B686F6D65\e\\  # khome: CSI H
\e[?1h
\eP+q6B686F6D65\e\\  # khome: SS3 H
|______|
reply \eP1+r6B686F6D65=1B5B48\e\\\eP1+r6B686F6D65=1B4F48\e\\

XTGETTCAP-7: Shift and right arrow

\eP+q6B524954\e\\  # kRIT: CSI 1 ; 2 C
|______|
reply \eP1+r6B524954=1B5B313B3243\e\\

XTGETTCAP-8: By termcap name

\eP+q6B75\e\\  # ku
|______|
reply \eP1+r6B75=1B5B41\e\\

XTGETTCAP-9: The terminal’s name

\eP+q544E\e\\  # TN
|______|
reply \eP1+r544E=787465726D\e\\

XTGETTCAP-10: Two at once

\eP+q436F;524742\e\\  # Co;RGB
|______|
reply \eP1+r436F=323536;524742=38\e\\

XTGETTCAP-11: A name it does not know

\eP+q536D756C78\e\\  # Smulx
|______|
reply \eP0+r\e\\

XTGETTCAP-12: The name comes back as it was sent

\eP+q436f\e\\  # Co, in lower case
|______|
reply \eP1+r436f=323536\e\\