How Windows Terminal Handles Operating System Commands (OSC): VT Parser Deep Dive
Windows Terminal processes Operating System Commands (OSC) through a dedicated VT parser state machine that detects ESC] sequences, accumulates numeric parameters and string payloads until a BEL or ESC\ terminator, then dispatches the parsed data to IAdaptDispatch methods for execution.
Operating System Commands (OSC) are escape sequences that allow applications to interact with the terminal environment, from setting window titles to manipulating the clipboard. In the microsoft/terminal repository, OSC handling is implemented through a sophisticated state machine architecture in src/terminal/parser/stateMachine.cpp that parses incoming byte streams and converts them into concrete terminal actions via the OutputStateMachineEngine and AdaptDispatch layers.
OSC Sequence Structure and Detection
An OSC sequence follows the format ESC ] <parameter> ; <string> <terminator>, where the terminator can be either BEL (\x07 or \a) or the two-character string terminator ESC \ (ST). The parser uses specific helper functions to identify these components:
_isOscIndicatorinstateMachine.cpp(lines 272-275) recognizes the]character that follows anESCto start an OSC sequence._isOscDelimiter(lines 85-88) identifies the semicolon that separates the numeric parameter from the string payload._isOscTerminator(lines 10-13) detects theBELcharacter as a primary termination signal._isStringTerminatorIndicator(defined inascii.hpp) handles theESC \sequence for standards-compliant termination.
When the parser is in the Escape state and encounters ], it transitions to the OscParam state via _EnterOscParam to begin collecting the OSC action number.
The State Machine Architecture for OSC Parsing
Windows Terminal implements OSC parsing through three distinct states managed by the StateMachine class: OscParam, OscString, and OscTermination. Each state handles specific transitions based on incoming characters.
Parsing the OSC Parameter
In the OscParam state, defined in stateMachine.cpp (lines 49-73), the parser accumulates numeric characters into the _oscParameter buffer:
void StateMachine::_EventOscParam(const wchar_t wch) {
if (_isOscTerminator(wch)) { _ActionOscDispatch(); _EnterGround(); }
else if (_isEscape(wch)) { _EnterOscTermination(); }
else if (_isNumericParamValue(wch)) { _ActionOscParam(wch); }
else if (_isOscDelimiter(wch)) { _EnterOscString(); }
else { _ActionIgnore(); }
}
Numeric values build the action code (e.g., 0 for window title, 52 for clipboard). When the parser encounters the delimiter ;, it transitions to OscString via _EnterOscString. If it encounters BEL, it immediately dispatches the action, while ESC triggers a transition to OscTermination to handle the ST sequence.
Collecting the String Payload
Once in the OscString state (lines 87-105), the parser accumulates all subsequent characters into the _oscString buffer:
void StateMachine::_EventOscString(const wchar_t wch) {
if (_isOscTerminator(wch)) { _ActionOscDispatch(); _EnterGround(); }
else if (_isEscape(wch)) { _EnterOscTermination(); }
else if (_isOscInvalid(wch)) { _ActionIgnore(); }
else { _ActionOscPut(wch); } // store the character in _oscString
}
The _ActionOscPut method appends valid characters to the string buffer until a terminator is encountered. Invalid C0 control characters are ignored to prevent parser corruption.
Handling String Terminators
The OscTermination state (lines 119-129) manages the standards-compliant ESC \ string terminator:
void StateMachine::_EventOscTermination(const wchar_t wch) {
if (_isStringTerminatorIndicator(wch)) {
_ActionOscDispatch(); _EnterGround();
} else {
_EnterEscape(); _EventEscape(wch);
}
}
If the character following ESC is \, the sequence is considered complete and _ActionOscDispatch is invoked. Otherwise, the parser treats the ESC as the start of a new escape sequence and transitions accordingly.
Dispatching OSC Actions to the Terminal Engine
Once parsing is complete, _ActionOscDispatch (lines 696-702) forwards the accumulated parameter and string to the active engine:
void StateMachine::_ActionOscDispatch() {
_trace.TraceOnAction(L"OscDispatch");
_trace.DispatchSequenceTrace(_SafeExecute([=]() {
return _engine->ActionOscDispatch(_oscParameter, _oscString);
}));
}
The OutputStateMachineEngine::ActionOscDispatch method in OutputStateMachineEngine.cpp (lines 750-998) implements a comprehensive switch statement that maps OSC codes to specific terminal operations:
bool OutputStateMachineEngine::ActionOscDispatch(const size_t parameter,
const std::wstring_view string) {
switch (parameter) {
case OscActionCodes::SetWindowTitle:
case OscActionCodes::SetIconAndWindowTitle:
case OscActionCodes::DECSWT_SetWindowTitle:
_dispatch->SetWindowTitle(string); break;
case OscActionCodes::SetClipboard:
std::wstring text; bool query;
if (_GetOscSetClipboard(string, text, query) && !query)
_dispatch->SetClipboard(text);
break;
case OscActionCodes::Hyperlink:
// parse "params;URI" and call _dispatch->AddHyperlink() or EndHyperlink()
break;
// Additional cases for SetColor, ConEmuAction, ITerm2Action, VsCodeAction, etc.
}
return true;
}
Concrete OSC Implementations in Windows Terminal
The actual side effects are implemented in src/terminal/adapter/adaptDispatch.cpp. When SetWindowTitle is invoked (lines 82-89), it updates the terminal UI:
void AdaptDispatch::SetWindowTitle(std::wstring_view title) {
_api.SetWindowTitle(title); // Calls the console API to rename the window.
}
Supported OSC codes include:
- OSC 0, 1, 2: Window title manipulation via
SetWindowTitle. - OSC 4, 10, 11: Color palette queries and modifications using
SetColorTableEntryandSetXtermColorResource. - OSC 8: Hyperlink creation through
AddHyperlinkandEndHyperlink, enabling clickable terminal text. - OSC 52: Clipboard integration allowing applications to copy text to the system clipboard via
SetClipboard. - OSC 1337, 133, etc.: Extended actions for ConEmu, iTerm2, and VS Code integration protocols.
Practical Examples: Sending OSC Sequences
Setting Window Titles with OSC 0
From PowerShell, applications can update the window title using:
# ESC ] 0 ; My Awesome Terminal BEL
$osc = "`e]0;My Awesome Terminal`a"
[Console]::Write($osc)
The parser extracts parameter = 0 and string = "My Awesome Terminal", then invokes AdaptDispatch::SetWindowTitle to update the title bar.
Clipboard Manipulation via OSC 52
Applications can copy text to the clipboard by sending base64-encoded data:
# ESC ] 52 ; c ; <base64-payload> BEL
printf '\e]52;c;$(echo -n "Hello, World!" | base64)\a'
Windows Terminal decodes the payload and calls SetClipboard to place the content on the system clipboard. Note that clipboard reading via OSC 52 is restricted for security reasons.
Creating Clickable Hyperlinks with OSC 8
Terminal hyperlinks follow the format ESC ] 8 ; params ; URI BEL:
# Open a clickable link to the repository
printf '\e]8;;https://github.com/microsoft/terminal\aClick Here\e]8;;\a\n'
The parser interprets parameter = 8, extracts the URI from the string payload, and AdaptDispatch creates a clickable region in the terminal buffer that opens the URL when activated.
Summary
- OSC Detection: The
StateMachineclass identifiesESC]sequences using_isOscIndicatorand transitions through dedicated parsing states. - Parameter Extraction: The OscParam state accumulates numeric action codes, while OscString collects the text payload until a terminator is detected.
- Dual Termination Support: Windows Terminal accepts both
BEL(\a) andESC\(ST) as valid sequence terminators. - Engine Dispatch: Parsed data flows through
OutputStateMachineEngine::ActionOscDispatchto map codes to terminal operations. - Concrete Actions: The
IAdaptDispatchinterface inadaptDispatch.cppimplements side effects including window titles, clipboard access, color tables, and hyperlinks.
Frequently Asked Questions
What is the difference between OSC and other VT sequences?
OSC sequences start with ESC] and are used for high-level terminal-environment interactions like setting titles or clipboard contents, whereas CSI sequences (Control Sequence Introducer, ESC[) control cursor movement and text formatting, and DCS sequences (Device Control String) handle device-specific configurations. The parser uses distinct states for each introducer type.
How does Windows Terminal handle malformed OSC sequences?
Malformed sequences are handled gracefully through the _ActionIgnore mechanism in the state machine. If the parser encounters invalid C0 control characters in the OscString state, or if termination occurs without proper payload completion, the sequence is discarded without crashing the parser, allowing subsequent valid sequences to process normally.
Which OSC codes are supported by Windows Terminal?
Windows Terminal supports standard XTerm codes including OSC 0-2 (window titles), OSC 4 (color palette), OSC 8 (hyperlinks), OSC 10-11 (foreground/background colors), OSC 52 (clipboard), and extended protocols like OSC 133 (shell integration), OSC 1337 (iTerm2 extensions), and OSC 9 (ConEmu progress notifications). The full dispatch table is implemented in OutputStateMachineEngine.cpp.
Can OSC sequences be used to read clipboard contents?
While the OSC 52 specification supports clipboard querying via specific parameter flags, Windows Terminal restricts this capability for security reasons. The ActionOscDispatch implementation checks the query flag in _GetOscSetClipboard and only allows write operations to the clipboard, preventing malicious applications from exfiltrating sensitive data without user consent.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →