Single Shift / Locking Shift family — SS2 / SS3 / LS2 / LS3 / LS1R / LS2R / LS3R
ISO 2022 character-set switching: invoke G2 / G3 once (SS2 / SS3), or lock GL / GR to a different G-set (LS2 / LS3 / LS1R / LS2R / LS3R). Pairs with `\x1b(` / `\x1b)` / `\x1b*` / `\x1b+` G-set designators.
Byte forms
Every common string-literal form so you can paste-and-search either direction.
\x1bN SS2 \x1bO SS3 \x1bn LS2 \x1bo LS3 \x1b~ LS1R \x1b} LS2R \x1b| LS3R\033N / \033O / \033n / \033o / \033~ / \033} / \033|\eN / \eO / \en / \eo / \e~ / \e} / \e|ESC N / ESC O / ESC n / ESC o / ESC ~ / ESC } / ESC |1b 4e / 1b 4f / 1b 6e / 1b 6f / 1b 7e / 1b 7d / 1b 7cDescription
The ISO 2022 / ECMA-35 character-set machinery uses four registers (G0, G1, G2, G3) each pointing at a designated character set, with two 'pointers' (GL = invoked for 0x20–0x7F, GR = invoked for 0xA0–0xFF) selecting which G-set is currently active for which byte range. The single-shift and locking-shift families switch the active mapping. **Designators** (set what each G-register points at — covered separately, listed here for context): - `\x1b(<final>` — designate G0 (e.g. `\x1b(0` = G0 → DEC Special Graphics, the line-drawing set) - `\x1b)<final>` — designate G1 - `\x1b*<final>` — designate G2 - `\x1b+<final>` — designate G3 **Invokers** (switch GL / GR to point at a different G-register — this entry): - **SS2** `\x1bN` (`ESC N`) — *Single Shift 2* — the **next single 7-bit byte** is interpreted via G2, then GL reverts. Useful for inserting a single character from a designated set without locking. - **SS3** `\x1bO` (`ESC O`) — *Single Shift 3* — same as SS2 but uses G3. Note: `ESC O` is also the SS3 prefix in many keypad / function key codes (`\x1bOA` = up-arrow in application mode — see `keymap`), which is the same SS3 in spirit. - **LS2** `\x1bn` (`ESC n`) — *Locking Shift 2* — point GL at G2 until a subsequent shift. All subsequent 7-bit bytes go through G2. - **LS3** `\x1bo` (`ESC o`) — *Locking Shift 3* — point GL at G3. - **LS1R** `\x1b~` (`ESC ~`) — *Locking Shift 1 Right* — point GR at G1 (8-bit byte range 0xA0–0xFF flows through G1). - **LS2R** `\x1b}` (`ESC }`) — *Locking Shift 2 Right* — point GR at G2. - **LS3R** `\x1b|` (`ESC |`) — *Locking Shift 3 Right* — point GR at G3. - (LS0 = `\x0F` SI and LS1 = `\x0E` SO are C0 single-byte controls — see `c0-controls`.) **Why you'd see these in the wild**: 1. DEC line drawing — `\x1b(0` designates G0 → DEC Special Graphics, then code 0x6C (`l`) renders as `┌`. Frequently used by `ncurses` for box-drawing on non-UTF-8 terminals. 2. Legacy mainframe / serial-line apps that ship 7-bit binary 'paths' through GR-mapped G-sets to avoid 8-bit MSB-stripping middleware. 3. NRCS (National Replacement Character Sets) — e.g. `\x1b)A` designates G1 → UK NRCS (substitutes `£` for `#`). 4. Telnet/SSH options for 7-bit data paths. **Modern UTF-8 era reality**: ISO 2022 is largely vestigial. Terminals that announce UTF-8 (`\x1b%G` / `\x1b%@` is the UTF-8 designate / leave-UTF-8 pair) typically interpret incoming bytes as UTF-8 and **ignore** SS2/SS3/LS2/LS3 entirely. The exception is DEC Special Graphics — kept alive because `ncurses` still emits `\x1b(0` for line drawing on terminals that don't have full Unicode box glyphs. **Coverage**: **xterm** = full (reference). **kitty** / **WezTerm** / **iTerm2** / **Ghostty** / **Konsole**: support `\x1b(0` line-drawing path; SS2/SS3/LS2/LS3/LS{1,2,3}R variously implemented but the practical use case is line drawing. **gnome-terminal** = full. **Alacritty** = partial (DEC Special Graphics + UTF-8 only). **Linux console** = partial (`\x1b(0` works, more exotic invokers are no-ops). **Windows Terminal / cmd / ConPTY**: line-drawing via `\x1b(0` partial; locking-shift right (`\x1b~`/`\x1b}`/`\x1b|`) no-op. **macOS Terminal** = partial. Don't rely on anything beyond DEC Special Graphics + designators unless you've specifically probed.
Spec citation: ISO 2022 / ECMA-35 / xterm-ctlseqs (Single Shift + Locking Shift family)
Examples
# DEC line-drawing top-left corner: designate G0 -> SpecGraphics, emit 'l', restore.\nprintf '\\033(0l\\033(B' # 'l' renders as ┌; \\033(B restores G0 -> US-ASCII# Box from DEC special graphics: ┌──┐ / │ │ / └──┘\nimport sys\nsys.stdout.write('\\x1b(0lqqk\\nx x\\nmqqj\\x1b(B\\n')\nsys.stdout.flush()// Single-shift: print one G2 char without locking.\n// (G2 designated to DEC special graphics first.)\nfmt.Print(\"\\x1b*0\") // designate G2 -> SpecGraphics\nfmt.Print(\"\\x1bNl\") // SS2 then 'l' -> single ┌\nfmt.Print(\"X\") // back to GL=G0 (US-ASCII) -> literal 'X'// Lock GR to G2 for an 8-bit data path. Reset with LS0 (SI = \\x0f).\nprocess.stdout.write('\\x1b*A\\x1b}'); // G2 -> UK NRCS, LS2R\n// ... write 8-bit bytes; £ now lives at 0xA3 via G2\nprocess.stdout.write('\\x1b~'); // LS1R back to G1 default/* ncurses-style box-drawing entry; designate G0 to SpecGraphics. */\nprintf(\"\\x1b(0\");\nputs(\"lqqk\"); /* ┌──┐ */\nputs(\"x x\"); /* │ │ */\nputs(\"mqqj\"); /* └──┘ */\nprintf(\"\\x1b(B\"); /* restore G0 to US-ASCII */Terminal support
- xterm
- yes
- Linux console (fbcon)
- partial
- macOS Terminal.app
- partial
- iTerm2
- partial
- Windows Terminal
- partial
- cmd.exe / ConPTY
- partial
- kitty
- partial
- alacritty
- partial
- WezTerm
- partial
- Ghostty
- partial
- GNOME Terminal
- yes
- Konsole
- partial
- tmux
- no
- GNU screen
- no
| xterm | Linux console (fbcon) | macOS Terminal.app | iTerm2 | Windows Terminal | cmd.exe / ConPTY | kitty | alacritty | WezTerm | Ghostty | GNOME Terminal | Konsole | tmux | GNU screen |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| yes | partial | partial | partial | partial | partial | partial | partial | partial | partial | yes | partial | no | no |
Related sequences
In the family cookbook
ESC cookbook · 5. Locking shifts + the 8-bit C1 bridge — `\x1bn` / `\x1bo` / `\x1b|` and `\x80-\x9F`