Skip to main content

Locking shifts

AI-Generated Content
This page was generated with the assistance of AI and may contain inaccuracies. It is intended as a placeholder for future human verification. If you spot issues ahead of its initial review, please report them on GitHub!
Standard

The locking shifts are escape sequences that invoke character sets G1, G2, or G3 into the GL (left) or GR (right) half of the code table. Unlike single shifts (SS2/SS3), locking shifts remain in effect until another shift is performed.

Syntax​

ESC n         LS2  — Locking-shift G2 into GL
ESC o LS3 — Locking-shift G3 into GL
ESC ~ LS1R — Locking-shift G1 into GR
ESC } LS2R — Locking-shift G2 into GR
ESC | LS3R — Locking-shift G3 into GR
Formal syntax
LS2  = 0x1b, "n" ;
LS3  = 0x1b, "o" ;
LS1R = 0x1b, "~" ;
LS2R = 0x1b, "}" ;
LS3R = 0x1b, "|" ;

The GL shifts LS0 and LS1 are the 8-bit equivalents of SI and SO respectively — see SO/SI.

Description​

Per ECMA-48 §8.3.75–§8.3.81, the locking shift functions are used for code extension purposes. Their detailed semantics are defined in ECMA-35.

In the VT100/VT220 character set architecture:

  • GL (Graphic Left, 0x20-0x7F) and GR (Graphic Right, 0xA0-0xFF) are the two active code areas for graphic characters.
  • Four character sets — G0, G1, G2, G3 — can be designated via escape sequences (e.g., ESC ( B for ASCII into G0).
  • The locking shifts control which of G0–G3 is invoked into GL or GR.
ShiftInvokesInto
LS0 / SIG0GL
LS1 / SOG1GL
LS2G2GL
LS3G3GL
LS1RG1GR
LS2RG2GR
LS3RG3GR

Practical relevance​

Locking shifts beyond LS0/LS1 (SI/SO) are rarely used in modern terminals. UTF-8 has largely supplanted the ISO 2022 character set switching mechanism. Most modern terminal emulators support these sequences for compatibility but they see little practical use outside of legacy applications.

Specifications​

SpecificationSection
ECMA-48§8.3.75–§8.3.81

Terminal support​

TerminalSupportVersionNotes
Terminal Emulators
Alacritty✗NoNo locking shift (LS2/LS3/LS1R/LS2R/LS3R) support found
Bobcat✓0.9.0Locking shift sequences, part of TerminalCtrl character set handling
contour✗NoLS2, LS3, LS1R, LS2R, LS3R not found; only LS0/LS1 (SI/SO) supported
foot~1.8.0LS2 and LS3 supported (vt.c:485-497), LS1R/LS2R/LS3R not implemented
Ghostty✓v1.0.0LS2, LS3 (ESC n, ESC o) and LS1R, LS2R, LS3R (ESC ~, ESC }, ESC |) handled in stream.zig:2269-2335
iTerm2✗NoLS2, LS3, LS1R, LS2R, LS3R not implemented
Kitty✗No
Konsole~YesLS2/LS3 via ESC n/o; LS1R/LS2R/LS3R not found
mintty✓YesLS2 at src/termout.c:2034, LS3 at src/termout.c:2037, LS1R at src/termout.c:2040, LS2R at src/termout.c:2043, LS3R at src/termout.c:2046
mlterm✓rel-0_2_1Delegated to mef library for ISO-2022 encodings
PuTTY~0.45Only LS0/LS1 (SO/SI) supported; LS2, LS3, LS1R, LS2R, LS3R not implemented
Rio✗NoLS2/LS3/LS1R/LS2R/LS3R not implemented
rxvt-unicode~rxvt-unicode-1.2Only LS2/LS3 (ESC n/o); LS1R/LS2R/LS3R not supported
st~0.6Only LS2/LS3 implemented, not LS1R/LS2R/LS3R
terminology✗NoNot implemented
VT100✗No
VTE~YesLS2, LS3, LS1R, LS2R, LS3R handlers exist but are mostly non-functional (code commented out)
WezTerm✗NoOnly SO/SI (shift out/in) supported; no evidence of LS2, LS3, LS1R, LS2R, LS3R
Windows Terminal✓YesLS2, LS3 (ESC n/o) and LS1R, LS2R, LS3R (ESC ~/-/_) dispatch LockingShift/LockingShiftRight in OutputStateMachineEngine.cpp:241-254
xterm✓YesImplemented in charproc.c:6167-6200. Requires ansi_level > 2
xterm.js✓3.5.0LS2, LS3, LS1R, LS2R, LS3R supported via setgLevel
Multiplexers
cy✗NoLS2/LS3/LS1R/LS2R/LS3R not found
GNU Screen✓v.4.2.0LS2/LS3/LS1R/LS2R/LS3R implemented in DoESC() at src/ansi.c:760-775
tmux✗NoLS2/LS3/LS1R/LS2R/LS3R not implemented
tuios✓v0.0.15
Zellij✗No

See also​