^[control-codes live in libghostty-vt

Private modes

?12 Cursor Blink

Start or stop the cursor blinking.

CSI ? 12 h
xterm
Functions using CSI

CSI ? 12 h makes the cursor blink and CSI ? 12 l makes it steady. xterm names it after the AT&T 610 terminal it took the number from; DEC’s own use of mode 12 is something else, and DECSCUSR is the way to set the blink and the shape together.

The cases follow xterm, where this mode and DECSCUSR set the same flag (dpmodes, CASE_DECSCUSR, do_dec_rqm):

  • it is off to begin with, unless the cursorBlink resource says otherwise;
  • a blinking DECSCUSR style sets it, and a steady one resets it, so DECRQM for mode 12 tells which DECSCUSR chose last;
  • DECSTR and RIS both reset it (ReallyReset).

If the cursorBlink resource is set to always or never, neither this mode nor DECSCUSR can change it.

libghostty-vt keeps the mode and DECSCUSR in step as xterm does, but DECSTR leaves the mode set, which is a known difference.

Validation

BLINK-1: Steady to begin with

\e[?12$p
|____|
reply \e[?12;2$y

BLINK-2: Set and reset

\e[?12h
\e[?12$p
\e[?12l
\e[?12$p
|____|
reply \e[?12;1$y\e[?12;2$y

BLINK-3: DECSCUSR sets it too

\e[1\sq   # blinking block
\e[?12$p
\e[2\sq   # steady block
\e[?12$p
|____|
reply \e[?12;1$y\e[?12;2$y

BLINK-4: DECSTR resets it

\e[?12h
\e[!p
\e[?12$p
|____|
reply \e[?12;2$y

BLINK-5: So does RIS

\e[?12h
\ec
\e[?12$p
|____|
reply \e[?12;2$y