The driver model is the mechanism by which Terminal.Gui supports multiple platforms. Windows, Mac, Linux, and unit test environments are all supported through a modular, component-based architecture.
Terminal.Gui v2 uses a sophisticated driver architecture that separates concerns and enables platform-specific optimizations while maintaining a consistent API. The architecture is based on the Component Factory pattern and uses multi-threading to ensure responsive input handling.
Terminal.Gui provides console driver implementations optimized for different platforms:
dotnet) - A cross-platform driver that uses the .NET System.Console API. Works on all platforms (Windows, macOS, Linux). Best for maximum compatibility.windows) - A Windows-optimized driver that uses native Windows Console APIs for enhanced performance and platform-specific features.unix) - A Unix/Linux/macOS-optimized driver that uses platform-specific APIs for better integration and performance.fake) - A mock driver designed for unit testing. Simulates console behavior without requiring a real terminal.The appropriate driver is automatically selected based on the platform when you call Application.Init():
WindowsDriverUnixDriverYou can explicitly specify a driver in three ways:
// Method 1: Set ForceDriver property before Init
Application.ForceDriver = "dotnet";
Application.Init();
// Method 2: Pass driver name to Init
Application.Init(driverName: "unix");
// Method 3: Pass a custom IConsoleDriver instance
var customDriver = new MyCustomDriver();
Application.Init(driver: customDriver);
Valid driver names: "dotnet", "windows", "unix", "fake"
The v2 driver architecture uses the Component Factory pattern to create platform-specific components. Each driver has a corresponding factory:
NetComponentFactory - Creates components for DotNetDriverWindowsComponentFactory - Creates components for WindowsDriverUnixComponentFactory - Creates components for UnixDriverFakeComponentFactory - Creates components for FakeDriverEach driver is composed of specialized components, each with a single responsibility:
Reads raw console input events from the terminal. The generic type T represents the platform-specific input type:
ConsoleKeyInfo for DotNetDriver and FakeDriverWindowsConsole.InputRecord for WindowsDriverchar for UnixDriverRuns on a dedicated input thread to avoid blocking the UI.
Renders the output buffer to the terminal. Handles:
Translates raw console input into Terminal.Gui events:
Key events (handles keyboard input)MouseEventArgs for mouse inputManages the screen buffer and drawing operations:
Contents array (what should be displayed)AddRune(), AddStr(), Move(), FillRect()Detects terminal size changes and raises SizeChanged events when the terminal is resized.
A unified facade that implements IConsoleDriver and coordinates all the components. This is what gets assigned to Application.Driver.
The driver architecture employs a multi-threaded design for optimal responsiveness:
┌─────────────────────────────────────────────┐
│ ApplicationImpl.Init() │
│ Creates MainLoopCoordinator<T> with │
│ ComponentFactory<T> │
└────────────────┬────────────────────────────┘
│
├──────────────────┬───────────────────┐
│ │ │
┌────────▼────────┐ ┌──────▼─────────┐ ┌──────▼──────────┐
│ Input Thread │ │ Main UI Thread│ │ ConsoleDriver │
│ │ │ │ │ Facade │
│ IConsoleInput │ │ ApplicationMain│ │ │
│ reads console │ │ Loop processes │ │ Coordinates all │
│ input async │ │ events, layout,│ │ components │
│ into queue │ │ and rendering │ │ │
└─────────────────┘ └────────────────┘ └─────────────────┘
Input Thread: Started by MainLoopCoordinator, runs IConsoleInput.Run() which continuously reads console input and queues it into a thread-safe ConcurrentQueue<T>.
Main UI Thread: Runs ApplicationMainLoop.Iteration() which:
IInputProcessorIConsoleOutputThis separation ensures that input is never lost and the UI remains responsive during intensive operations.
When you call Application.Init():
MainLoopCoordinator<T> with the appropriate ComponentFactory<T>IConsoleInput<T>IConsoleOutputConsoleDriverFacade<T> and assigns to Application.DriverWhen Application.Shutdown() is called:
IConsoleOutput is disposedThe main driver interface that applications interact with. Provides:
Screen, Cols, Rows, ContentsAddRune(), AddStr(), Move(), FillRect()SetCursorVisibility(), UpdateCursor()CurrentAttribute, SetAttribute(), MakeColor()Clip propertyKeyDown, KeyUp, MouseEvent, SizeChangedSupportsTrueColor, Force16Colors, ClipboardExtended interface for v2 drivers that exposes the internal components:
IInputProcessor InputProcessorIOutputBuffer OutputBufferIWindowSizeMonitor WindowSizeMonitorThis interface allows advanced scenarios and testing.
System.Console for all I/O operationsConsoleKeyInfo via Console.ReadKey()Console.Write() and ANSI escape sequencesInputRecord structs via ReadConsoleInputWhen running in Visual Studio's debug console (VSDebugConsole.exe), WindowsDriver detects the VSAPPIDNAME environment variable and automatically adjusts its behavior:
This ensures Terminal.Gui applications can be debugged directly in Visual Studio without rendering issues.
char data from terminalFakeConsole for all operationsApplication._forceFakeConsole is trueApplication.Init();
// Access the driver
IConsoleDriver driver = Application.Driver;
// Check if it's a v2 driver with facade
if (driver is IConsoleDriverFacade facade)
{
// Access individual components
IInputProcessor inputProcessor = facade.InputProcessor;
IOutputBuffer outputBuffer = facade.OutputBuffer;
IWindowSizeMonitor sizeMonitor = facade.WindowSizeMonitor;
// Use components for advanced scenarios
sizeMonitor.SizeChanging += (s, e) =>
{
Console.WriteLine($"Terminal resized to {e.Size}");
};
}
To create a custom driver, implement IComponentFactory<T>:
public class MyComponentFactory : ComponentFactory<MyInputType>
{
public override IConsoleInput<MyInputType> CreateInput()
{
return new MyConsoleInput();
}
public override IConsoleOutput CreateOutput()
{
return new MyConsoleOutput();
}
public override IInputProcessor CreateInputProcessor(
ConcurrentQueue<MyInputType> inputBuffer)
{
return new MyInputProcessor(inputBuffer);
}
}
Then use it:
ApplicationImpl.ChangeComponentFactory(new MyComponentFactory());
Application.Init();
Terminal.Gui v1 drivers that implement IConsoleDriver but not IConsoleDriverFacade are still supported through a legacy compatibility layer. However, they do not benefit from the v2 architecture improvements (multi-threading, component separation, etc.).