Appearance
Control Characters
The 33 bytes that aren't text — C0 control codes and ASCII
Before escape sequences existed, terminals had control characters — special bytes in the 0x00–0x1F range (plus 0x7F) that tell the terminal to do something instead of displaying something. They occupy the first 32 positions of ASCII plus DEL. Most are relics of teletypes and paper tape, but a few — ESC, BS, TAB, LF, CR, BEL — remain fundamental to how every terminal works today.
What C0 Controls Are
ASCII (American Standard Code for Information Interchange, 1963) defines 128 characters. The first 32 (0x00–0x1F) and the last one (0x7F, DEL) are control characters — they don't represent printable glyphs. Instead, they're instructions: ring the bell, move the carriage back, start a new line, escape from the normal character stream.
These 33 characters are called C0 controls (the "C" stands for "control," the "0" distinguishes them from the C1 control range at 0x80–0x9F). They were designed for electromechanical teletypes in the 1960s. Most have no effect in modern terminals, but the ones that do are essential.
The Complete C0 Table
| Hex | Dec | Ctrl | Caret | Name | Terminal Behavior |
|---|---|---|---|---|---|
00 | 0 | Ctrl+@ | ^@ | NUL | Ignored by most terminals. Padding character in legacy systems. |
01 | 1 | Ctrl+A | ^A | SOH | No terminal effect. Used by tmux as the default prefix key. |
02 | 2 | Ctrl+B | ^B | STX | No terminal effect. Used by screen as the default prefix key. |
03 | 3 | Ctrl+C | ^C | ETX | No terminal effect. The kernel TTY driver sends SIGINT to the foreground process group. |
04 | 4 | Ctrl+D | ^D | EOT | No terminal effect. Interpreted by the TTY driver as end-of-file in canonical mode. |
05 | 5 | Ctrl+E | ^E | ENQ | Some terminals respond with an answerback string (configurable). |
06 | 6 | Ctrl+F | ^F | ACK | No terminal effect. |
07 | 7 | Ctrl+G | ^G | BEL | Plays a sound, flashes the title bar, or triggers a notification. Also used as an alternative string terminator for OSC sequences. |
08 | 8 | Ctrl+H | ^H | BS | Move cursor back one column (backspace). Does not delete the character. |
09 | 9 | Ctrl+I | ^I | HT | Horizontal tab — advance cursor to the next tab stop (default: every 8 columns). |
0A | 10 | Ctrl+J | ^J | LF | Line feed — move cursor down one line. In most terminals, also performs a carriage return (newline behavior). |
0B | 11 | Ctrl+K | ^K | VT | Vertical tab — treated as LF by most terminals. |
0C | 12 | Ctrl+L | ^L | FF | Form feed — treated as LF by most terminals. Shells often interpret it as "clear screen." |
0D | 13 | Ctrl+M | ^M | CR | Carriage return — move cursor to column 1 of the current line. |
0E | 14 | Ctrl+N | ^N | SO | Shift Out — switch to G1 character set (DEC Special Graphics on VT100). |
0F | 15 | Ctrl+O | ^O | SI | Shift In — switch back to G0 character set (ASCII). |
10 | 16 | Ctrl+P | ^P | DLE | No terminal effect. |
11 | 17 | Ctrl+Q | ^Q | DC1/XON | Resume transmission (software flow control). See stty ixon. |
12 | 18 | Ctrl+R | ^R | DC2 | No terminal effect. |
13 | 19 | Ctrl+S | ^S | DC3/XOFF | Pause transmission (software flow control). See stty ixon. |
14 | 20 | Ctrl+T | ^T | DC4 | No terminal effect. |
15 | 21 | Ctrl+U | ^U | NAK | No terminal effect. The TTY driver uses it to kill the current line in canonical mode. |
16 | 22 | Ctrl+V | ^V | SYN | No terminal effect. |
17 | 23 | Ctrl+W | ^W | ETB | No terminal effect. The TTY driver uses it to delete the previous word in canonical mode. |
18 | 24 | Ctrl+X | ^X | CAN | Cancel/abort the current escape sequence. The terminal discards the incomplete sequence. |
19 | 25 | Ctrl+Y | ^Y | EM | No terminal effect. |
1A | 26 | Ctrl+Z | ^Z | SUB | Treated as CAN (abort escape sequence) by most terminals. The TTY driver generates SIGTSTP (suspend). |
1B | 27 | Ctrl+[ | ^[ | ESC | Start of escape sequence — the most important control character. Everything on this site starts with this byte. |
1C | 28 | Ctrl+\ | ^\ | FS | No terminal effect. The TTY driver sends SIGQUIT. |
1D | 29 | Ctrl+] | ^] | GS | No terminal effect. Used by telnet as the escape character. |
1E | 30 | Ctrl+^ | ^^ | RS | No terminal effect. |
1F | 31 | Ctrl+_ | ^_ | US | No terminal effect. |
7F | 127 | Ctrl+? | ^? | DEL | Delete character. Historically: rubout on paper tape. Modern terminals often treat it the same as BS. |
Highlighted rows are the control characters that have meaningful effects in modern terminal emulators.
How Ctrl+Key Maps to Control Characters
The mapping is elegant and mathematical: Ctrl+key produces the byte value of the key minus 64 (or equivalently, the key's ASCII value with bits 5 and 6 cleared).
- Ctrl+A = 0x41 (
A) - 0x40 = 0x01 (SOH) - Ctrl+C = 0x43 (
C) - 0x40 = 0x03 (ETX) - Ctrl+M = 0x4D (
M) - 0x40 = 0x0D (CR, carriage return) - Ctrl+[ = 0x5B (
[) - 0x40 = 0x1B (ESC)
This is a hardware-level mapping — it happens in the terminal emulator before the byte reaches any software. This is also why Ctrl+I and Tab are the same byte (0x09): the terminal has no way to distinguish them. It's not a bug; it's the fundamental design of ASCII.
Ctrl+I and Tab are the same byte (0x09)
This is why you can't bind Ctrl+I and Tab to different actions in traditional terminals — they produce identical input. The Kitty keyboard protocol solves this by reporting keys as symbolic events with modifiers, not as raw bytes. With the Kitty protocol, Ctrl+I and Tab are distinct events, and key-release events are reportable for the first time.
The Characters That Still Matter
Of the 33 control characters, only a handful have meaningful effects in modern terminals:
ESC (0x1B) — The gateway to everything else on this site. ESC followed by [ starts a CSI (Control Sequence Introducer) sequence. ESC followed by ] starts an OSC (Operating System Command). ESC alone with a letter is a simple escape command (like ESC 7 for DECSC cursor save). Every color change, cursor movement, and mode switch begins with this one byte.
LF (0x0A) — Line feed. Combined with CR, this is the newline operation. In most terminal configurations, LF alone performs both line-feed and carriage-return (controlled by the onlcr stty setting).
CR (0x0D) — Carriage return. Moves the cursor to column 1. In the raw output of \r\n, CR does the horizontal movement and LF does the vertical movement. Many terminal applications use CR alone to overwrite the current line (progress bars, spinners).
BS (0x08) — Backspace. Moves the cursor left one column but does not erase anything. To visually delete a character, applications send BS, Space, BS (move back, overwrite with space, move back again).
HT (0x09) — Horizontal tab. Advances to the next tab stop. Default tab stops are at columns 9, 17, 25, 33, ... (every 8 columns). Applications can set custom tab stops with the HTS escape sequence.
BEL (0x07) — The bell character. Originally rang a physical bell on teletypes. In modern terminals, it may play a system sound, flash the title bar ("visual bell"), or trigger a desktop notification. BEL also serves double duty as a string terminator in OSC sequences (as an alternative to the formal ST terminator, ESC \).
DEL (0x7F) — The delete character. It's not in the 0x00–0x1F range — it's 0x7F, the last ASCII value. On paper tape, DEL was a character with all holes punched, used to "rub out" a mistake. In terminals, it's often mapped to the same function as BS.
Ctrl+C doesn't kill processes via the terminal
When you press Ctrl+C, the terminal emulator sends byte 0x03 (ETX) to the PTY. But the terminal doesn't interpret it — the kernel TTY line discipline intercepts it and sends SIGINT to the foreground process group. This is why Ctrl+C works even when the application isn't listening for input. It's also why it doesn't work in raw mode — raw mode disables the line discipline's signal generation. See stty & Line Discipline for details.
Relationship to ASCII
ASCII defines 128 characters in 7 bits (0x00–0x7F):
| Range | Count | What |
|---|---|---|
| 0x00–0x1F | 32 | C0 control characters |
| 0x20 | 1 | Space (technically a "graphic" character) |
| 0x21–0x7E | 94 | Printable characters (letters, digits, punctuation) |
| 0x7F | 1 | DEL (control character) |
The C1 control range (0x80–0x9F) was defined later by ECMA-48 for 8-bit character sets. It includes single-byte equivalents for common escape sequences — 0x9B is CSI (equivalent to ESC [), 0x9D is OSC (equivalent to ESC ]). In practice, C1 controls are almost never used because they conflict with UTF-8 encoding, where bytes 0x80–0xBF are continuation bytes. The 7-bit ESC-prefixed forms are universal.
Why ESC is special
ESC (0x1B) isn't just another control character — it's the meta-character that extends the entire control vocabulary. One byte gives you 33 control functions. ESC followed by one or more bytes gives you thousands. The entire ECMA-48 escape sequence grammar, all DEC private modes, OSC commands, and modern protocol extensions are built on this one byte as the entry point. See ECMA-48 features for the grammar ESC unlocks.