A VT100/ANSI terminal emulator and telnet client written from scratch in C# — no terminal library, no telnet library. It implements the escape-sequence state machine, the telnet option-negotiation protocol, and the keyboard-to-terminal encoding by hand, then renders the screen with GDI+ on a WinForms panel.
It was built to match the behavior of the classic Windows telnet client byte-for-byte when talking to line-oriented hosts, which meant getting the protocol details exactly right rather than "close enough."
Platform: Windows (WinForms UI), .NET 9.
Three self-contained pieces, each interesting on its own:
A character-cell screen model (char[,] plus per-cell foreground/background color planes) driven by a byte-at-a-time state machine:
- Escape-sequence parser that buffers
ESC [ … <final>sequences and dispatches on the final byte, guarding against unterminated sequences. - Cursor control: absolute position (
H/f), relative moves (A/B/C/D), each with parameter parsing and clamping to screen bounds. - Erase operations: erase-display and erase-line (
J/K) in all three modes (to-cursor, from-cursor, whole). - SGR color (
m): the 30–37 / 40–47 foreground/background palette and reset. - Control characters: BEL, backspace, tab-to-8, CR, LF, with scroll-up when the cursor runs past the last row.
- Cursor visibility via
?25h/?25l. - A logical/physical split: the emulator always presents a logical 80×25 to the host (so server-side formatting stays correct) while the panel can be any physical size, with content re-flowed and re-centered on resize.
A stateless processor for the telnet command stream (RFC 854 and friends):
- Full IAC command handling —
WILL/WONT/DO/DONTwith correct accept/refuse responses per option. - Options supported: ECHO, Suppress-Go-Ahead, Terminal-Type, Window-Size (NAWS).
- Subnegotiation (
SB … SE): replies to a terminal-type request withVT100, and emits NAWS window-size updates encoded as high/low byte pairs. - Correct escaped-IAC handling (a doubled
0xFFis literal data, not a command) so binary bytes survive intact. - Sends a sensible initial negotiation on connect and exposes live window-size updates.
Turns high-level intents (CreateText, CreateKeyPress, CreateKeyCombination) into the exact byte sequences a VT100 host expects — including the ESC O P-style function-key encodings and ESC [ arrow/navigation keys — so sessions can be driven programmatically, not just typed.
TCP socket ──bytes──▶ TelnetNegotiation.ProcessTelnetData
│ (strips & answers IAC commands,
│ writes responses back to the stream)
▼
display bytes ──▶ VT100Terminal.ProcessData
│ (escape-sequence state machine,
│ updates the cell/color buffer)
▼
Panel.Paint ──▶ GDI+ render
keyboard / AutomationCommand ──encode──▶ socket
The two protocols share one inbound stream, so the design keeps them cleanly separated: telnet commands are consumed and answered first, and only the remaining display bytes reach the terminal emulator.
Requires the .NET 9 SDK on Windows.
git clone https://github.com/astralmaster/VT100Sharp.git
cd VT100Sharp
dotnet build -c Release
dotnet run -c ReleaseEnter a host and port, connect, and interact with the remote session in the terminal panel.
- Targets the VT100/ANSI subset needed for line-oriented and full-screen text hosts; it is not a full xterm (no 256-color, no mouse reporting, no alternate screen buffer).
- Rendering is intentionally simple GDI+
DrawStringper cell — clear over clever. A glyph atlas would be the obvious next step for very high-throughput screens. - The emulator reports a fixed logical 80×25 to the host by design; see the logical/physical split above.
MIT — see LICENSE.