- UI Concept
- Process Model Diagram
- Architecture Overview
- Runtime modes
- I/O modes
- Desktop structure
- Quickstart
- Desktop Live Panel
- Desktop objects and built-in applications
HybridTUI (HTUI), or Hybrid Textual User Interface, is a class of software within a single executable file where the entire user interface is represented by a mosaic of text cells forming a TUI matrix directly rendered either into its own GUI window or into a compatible text console providing a unified user experience regardless of the execution environment.
The key technology for HTUI is VT2D (Unicode Character Geometry Modifiers), which allows scaling and transforming individual characters and their parts at the cell level and ensures perfect visual uniformity of the user interface.
| Advantage | Over TUI | Over GUI |
|---|---|---|
| Unified UX | Provides full graphical rendering (e.g., fonts, shadows, alpha blending) when launched in graphical environment. | Retains full functionality and look when launched in a remote SSH session or existing terminal. |
| Single Binary | Does not require compiling different versions or maintaining separate executables for different modes. | Avoids the need to maintain two entirely separate codebases (terminal and graphical). |
| Flexible Launch | The user chooses how to launch the app - from the console or with a double-click - without losing functionality. | Offers the lightweight and minimalist nature of TUI apps with the capabilities of a windowed mode. |
- Environment check:
- If an explicit CLI flag is specified to use TUI or GUI mode, the application will attempt to activate the specified mode.
- If no explicit mode is specified, the application will attempt to launch in GUI mode, which provides a full range of capabilities.
- If the GUI mode is unavailable (for example, the application is running in Session 0), the application starts in TUI mode.
- Unified Interface:
- In both modes, the same internal rendering logic is utilized, based on projecting a virtual TUI matrix onto a canvas of the graphic window or terminal, ensuring an identical visual appearance.
- In GUI mode, the application renders by leveraging the full potential of VT2D and uses the native API for user input (keyboard, mouse, system events), ensuring maximum performance and capabilities.
- In TUI mode, the application adapts to the limited input/output capabilities of the host terminal.
The main goal of the vtm project is to form the foundation of the HybridTUI Application concept, empowering this class of applications with a reactive UI driven by DynamicXML+Lua (similar to WPF with XAML+CLR or web apps with HTML+JS), and to create an environment that reveals their potential.
graph TB
subgraph GUI[Native GUI Window]
subgraph TUI[TUI Matrix]
subgraph DESK[Desktop]
direction LR
subgraph APP1[Application]
direction LR
App1[Application UI]
end
subgraph APP2[Application]
direction LR
App2[Application UI]
end
end
end
end
subgraph GUI2[Generic Text Console]
subgraph TUI2[TUI Matrix]
subgraph DESK2[Desktop]
direction LR
subgraph APP21[Application]
direction LR
App21[Application UI]
end
subgraph APP22[Application]
direction LR
App22[Application UI]
end
end
end
end
subgraph GUI3[Native GUI Window]
subgraph TUI3[TUI Matrix]
subgraph APP33[Application]
direction LR
App33[Application UI]
end
end
end
graph TB
subgraph IE10[Generic Text Console 1]
subgraph IE1[Input]
direction LR
C1[keybd, mouse, focus<br>winsize, clipboard,<br>os signals]
end
subgraph OU1[Output]
TC1[scrollback<br>buffer]
end
subgraph CS1[Desktop Client 1]
VTM1[vtm<br>process 1]
end
C1 --> CS1
TC1 --- CS1
end
subgraph IE20[Generic Text Console 2]
subgraph IE2[Input]
direction LR
C2[keybd, mouse, focus<br>winsize, clipboard,<br>os signals]
end
subgraph OU2[Output]
TC2[scrollback<br>buffer]
end
subgraph CS2[Desktop Client 2]
VTM2[vtm<br>process 2]
end
C2 --> CS2
TC2 --- CS2
end
subgraph IE30[Generic Text Console 3]
subgraph IE3[Input]
direction LR
C3[keybd, mouse, focus<br>winsize, clipboard,<br>os signals]
end
subgraph OU3[Output]
TC3[scrollback<br>buffer]
end
subgraph CS3[DirectVT Gateway]
VTM3[vtm<br>process 3]
end
C3 --> CS3
TC3 --- CS3
end
subgraph APP0x[Standalone DirectVT-aware Application]
APP01[DirectVT App4<br>app: process 9]
end
CS3 <-->|DirectVT I/O<br>send: Events<br>recv: Render| APP01
subgraph NP[Connection Point]
TS["system-wide<br>named pipe"]
end
subgraph SS[Desktop Server]
VTMs[vtm<br>process 0]
subgraph SE[Desktop Session]
subgraph APPx[running application windows]
subgraph APP1[DirectVT Gateway]
eAPP1[DirectVT App1<br>app: process 4]
end
subgraph APP2[DirectVT Gateway]
eAPP2["App2 (Teletype+App2)<br>vtm: process 5<br>app: process 6"]
end
subgraph APP3[DirectVT Gateway]
eAPP3["App3 (Terminal+App3)<br>vtm: process 7<br>app: process 8"]
end
end
subgraph APPu[connected users]
USR1["Desktop Client 1<br>Viewport<br>Taskbar"]
USR2["Desktop Client 2<br>Viewport<br>Taskbar"]
end
USR1 --->|keyboard focus| APP1
USR2 --->|keyboard focus| APP2
USR2 --->|keyboard focus| APP3
end
VTMs === SE
end
CS1 <-->|DirectVT I/O<br>send: Events<br>recv: Render| TS
CS2 <-->|DirectVT I/O<br>send: Events<br>recv: Render| TS
TS === VTMs
- Vtm is a text-based application that comes with a single executable and has a number of runtime modes for running multiple instances in parallel to form the desktop environment.
- A vtm process running in
Desktop Servermode creates a desktop session. - Desktop users connect to an existing desktop session through an additional vtm process running in
Desktop Clientmode. The desktop is presented to the user as a borderless workspace that allows panning in all directions (infinite desktop). - The desktop session has a unique ID, coined from the platform-specific creator UID, unless explicitly specified otherwise.
- Sessions with different IDs can coexist independently.
- Only the session creator or an elevated user can access the session.
- The "regular" user and the "elevated" user are different independent users despite having the same username.
- The session allows multiple access in real time.
- Multiple connected users can share a focused application, while each user can have multiple applications focused.
- Users can lock windows, restricting access for other users. Users who was focused on the locked window at the time of locking becomes its sole owner. The restrictions set prevent the desktop session from terminating.
- Users can disconnect from the session and reconnect later.
- The first user connected to the desktop session becomes a full administrator with full access to any locked windows and the ability to unconditionally shut down the server. When disconnected, administrators lose all privileges.
- To maximize rendering efficiency and minimize cross-platform issues, along with the character-oriented xterm-compatible I/O mode called
Classic VT, vtm supports an additional message-based binary I/O mode calledDirectVT. - Using
DirectVTmode (when vtm is running as aDesktop ClientorDirectVT Gateway), vtm has the ability to fully binary deserialize/serialize its state through arbitrary channels (like socat over SSH reverse tunnel) and does not require a running SSH server on the remote side. - Vtm employs a HybridTUI (HTUI) approach: it can render itself into both GUI windows and terminals (
vtm --guiandvtm --tuiflags). Currently, rendering into a native GUI window is only available on the Windows platform. - In GUI mode, vtm replicates its unique TUI-mode style and windowing mechanics, including keyboard multifocus (activated by
Ctrl+LeftClick). - On Windows, any user can launch an SSH-accessible desktop session in Session 0, running under their own security context and is independent of any active graphical session (requires the vtm service installed via
vtm --installfrom an elevated console). - When running in the Linux in-kernel VGA Console or KMSCON environment, vtm can directly use any kernel pointer devices (
/dev/input/eventX) (requires persistent access configured usingsudo vtm --mouse 1). - A typical console application integrates into the desktop using the
DirectVT Gatewaywindow as the DirectVT connection endpoint.- A DirectVT-aware application directly connected to the environment can seamlessly send and receive the entire set of desktop events, as well as render itself in a binary form, avoiding expensive
Classic VTparsing. - To run a non-DirectVT application, an additional vtm host process is launched in
Desktop Appletmode with theTeletype ConsoleorTerminal Consoleapplet as a DirectVT bridge to the desktop environment.
- A DirectVT-aware application directly connected to the environment can seamlessly send and receive the entire set of desktop events, as well as render itself in a binary form, avoiding expensive
- The desktop has a built-in Tiling Window Manager for organizing desktop space into non-overlapping panels with Drag and Drop support for moving panels (like in web browsers).
- The user interface supports Lua scripting, allowing scripts to be bound to various internal events via configuration settings, as well as executed directly from child processes via APC sequences.
- The desktop server can receive and execute Lua scripts relayed from other vtm processes (running on behalf of the session creator) via a redirected standard input, or interactively executed from the attached log monitor (
vtm --monitor). - In terminal emulator mode (
Teletype ConsoleorTerminal Consolelaunched viavtm --run vttyorvtm --run term), vtm also supports the following features:- Simultaneous output of wrapped and non-wrapped text lines of arbitrary length with horizontal scrolling.
- An in-process Win32 Console Server implementation, which is independent of the standard system
conhost.exeand compatible with Windows 8.1 and Windows Server 2012 Core (including GUI mode with true-color Unicode rendering). - Mouse reports with floating point coordinates, where the cursor position inside a cell is normalized from 0 to 1.
- Special (Exclusive) keyboard mode for the terminal window to transfer all keyboard events to the terminal as is.
- A configurable scrollback buffer size (100k lines by default, limited by max_int32 and system RAM).
- Text lookup in the scrollback buffer.
- Unicode Character Geometry Modifiers VT2D with the ability to output text characters of arbitrary size and in parts (up to 16x4 cells).
- Stdin/stdout logging.
- Vtm supports the creation of advanced keyboard bindings (generic:
Ctrl+Enter, literal:Ctrl+'\n', specific:LeftCtrl+KeyEnter, scancodes:0x1D+0x1C), allowing for the configuration of complex behavior, like a tmux-style prefix key for modality (e.g., toggling window movement with arrow keys). - The entire user interface can be localized to any language, including those with complex scripts, via a configuration file (rendering is powered by VT2D in GUI mode).
- Vtm has a built-in logging subsystem; the log output is available via the
vtm --monitorcommand. - Used non-standard technologies:
- DirectVT (binary input and output)
- VT2D (Unicode Character Geometry Modifiers)
- DynamicXML (settings configuration)
- Lua scripting (reactive UI)
- TUI Shadows (SGR attribute)
- VT Input Mode (floating point mouse reporting)
- HybridTUI (HTUI)
- In-process Windows Console Server (Windows 8.1 and later compatibility)
- Terminal with horizontal scrolling support (wrapped and un-wrapped text lines simultaneously)
| Runtime mode | I/O mode | Environment role |
|---|---|---|
| Desktop Applet | auto detected | A desktop applet of an arbitrary type running in its own process that accepts user input and renders itself. Used to place a heavy (complex) desktop object in a separate process to optimize desktop resource consumption. |
| Desktop Client | auto detected | A desktop client running in its own process that forwards user input to the desktop and renders the corresponding desktop region with a taskbar overlay. |
| Desktop Server | n/a command line only |
The desktop environment core that manages connected users, runs desktop applications, routes user input, and forwards render output to desktop clients. |
| Desktop Monitor | n/a command line only |
A desktop log monitor which outputs desktop session logs and relays script commands to the desktop server via standard input redirection. |
The runtime mode can be selected using command-line options. By default, Desktop Client mode will be used, and Desktop Server will be started in parallel if it is not already running.
The desktop applet type can be specified using the vtm [-r [<type>]][<args...>] command-line option. By default, vtty will be used if <args...> is specified without any <type>.
| Desktop applet | Type | Host for |
|---|---|---|
| Teletype Console (default) | vtty |
CUI applications. |
| Terminal Console | term |
CUI applications. |
| DirectVT Gateway | dtvt |
DirectVT-aware applications. |
| DirectVT Gateway with TTY | dtty |
CUI applications that redirect the DirectVT flow to standard I/O streams and require user input via the platform's TTY. |
A vtm process instance running in Desktop Client or Desktop Applet mode can operate in one of two I/O modes: either Classic VT mode or DirectVT (dtvt) mode.
In DirectVT mode, vtm process multiplexes the following events:
- Keyboard
- Mouse
- Focus
- Window size
- Clipboard
- Rendering
- Process lifetime control
The DirectVT stream can be wrapped in any transport layer protocol suitable for stdin/stdout transfer, such as SSH.
In Classic VT mode, a vtm process parses input from multiple standard sources and forwards it to the desktop server using the DirectVT transport. The set of input sources varies by platform.
- STDIN
- Bracketed paste marks
\x1b[200~/\x1b[201~are treated as the boundaries of a binary, immutable block pasted from the clipboard. This immutable block is handled independently of keyboard input and forwarded to the clipboard event channel. - SGR mouse reporting sequences
\x1b[<s;x;yM/mare redirected to the mouse event channel. - Terminal window focus reporting sequences
\x1b[I/\x1b[Oare redirected to the focus event channel. - Line style reporting sequences
\x1b[33:STYLEpare redirected to the style event channel (current/selected line wrapping on/off, left/right/center alignment). - All incoming text flow that does not fall into the above categories is clusterized, forming a key-pressed stream forwarded to the keyboard event channel.
- Bracketed paste marks
- Operating system signals
- SIGWINCH events are forwarded to the window size event channel.
- SIGINT events are forwarded to the process lifetime control channel to perform a graceful exit.
- SIGHUP events are forwarded to the process lifetime control channel to perform a graceful exit.
- SIGTERM events are forwarded to the process lifetime control channel to perform a graceful exit.
- PS/2 Mouse device (Linux VGA Console (in-kernel console) only)
/dev/input/eventX: Received pointing device events are decoded and forwarded to the mouse event channel.
- ReadConsoleInput events (Win32 Console API)
- The KEY_EVENT stream is clusterized, forming a key-pressed stream forwarded to the keyboard event channel (excluding repeat modifier keys).
- The MOUSE_EVENT stream is forwarded to the mouse event channel (excluding double clicks and idle events).
- The FOCUS_EVENT stream is forwarded to the focus event channel.
- The WINDOW_BUFFER_SIZE_EVENT stream is forwarded to the window size event channel.
- The MENU_EVENT stream is interpreted using the Event.MenuEvent.dwCommandId value:
- 0x8000: The subsequent MENU_EVENT record is forwarded to the style event channel.
- 0x8001: Clipboard-paste block start (INPUT_RECORD Begin Mark). Subsequent KEY_EVENT records are read until the INPUT_RECORD End Mark appears, and then a whole block of chars is forwarded to the clipboard event channel.
- 0x8002: Clipboard-paste block end (INPUT_RECORD End Mark).
- Window system-defined messages
- WM_CREATE event is forwarded to the clipboard event channel.
- WM_CLIPBOARDUPDATE events are forwarded to the clipboard event channel.
- WM_ENDSESSION event is interpreted using its sub-parameter's value:
- ENDSESSION_CLOSEAPP: Registers the CTRL_CLOSE_EVENT signal.
- ENDSESSION_LOGOFF: Registers the CTRL_LOGOFF_EVENT signal.
- Any other non-zero value: Registers the CTRL_SHUTDOWN_EVENT signal.
- Operating system signals
- CTRL_C_EVENT events form the
Ctrl+Ckey-pressed event stream forwarded to the keyboard event channel. - CTRL_BREAK_EVENT events form the
Ctrl+Breakkey-pressed event stream forwarded to the keyboard event channel. - CTRL_CLOSE_EVENT event is forwarded to the process lifetime control channel to perform a graceful exit.
- CTRL_LOGOFF_EVENT event is forwarded to the process lifetime control channel to perform a graceful exit.
- CTRL_SHUTDOWN_EVENT event is forwarded to the process lifetime control channel to perform a graceful exit.
- CTRL_C_EVENT events form the
CUI applications running as external processes are instantly rendered into their host DirectVT Gateways windows, which run directly in the desktop server's address space.
The desktop server receives and caches window bitmaps, sending incremental changes to desktop clients every tick of an internal timer.
The binary render stream received from the desktop server is converted by the desktop client into the format suitable for the console being used for output. The console type is detected at desktop client startup and can be one of the following:
- XTerm-compatible terminal with truecolor support
- XTerm-compatible terminal with 256-color support (Apple Terminal)
- XTerm-compatible terminal with 16-color support (Linux VGA Console, 16-color terminals)
- Win32 Console with 16-color support (Command Prompt on platforms from Windows 8.1 up to Windows 2019 Server)
The desktop client outputs the received render to the hosting console only when the console is ready to accept the next frame.
| Term | Description |
|---|---|
colored character |
A character depicted with rendition attributes such as background and foreground colors. |
text console |
A cellular, rectangular surface designed to display colored, monospaced characters in cells. |
text cell |
A text console cell containing a colored, monospaced character or its fragment. |
bitmap |
A rectangular block of text cells. |
canvas |
A rectangular buffer for bitmap output. |
Internally, the desktop is represented by a parent-child object tree with a single root object that maintains a desktop-wide configuration, a list of connected users, and a list of running windows. The root object broadcasts a fixed number of ticks every second to update the tree state and to perform other synchronized actions.
Users and windows are associated with the rectangular regions where they are currently placed. For the connected user, it is the viewport of the terminal used to connect to the desktop. For the application window, it is the window rectangle itself.
The desktop has no bounds, and users can navigate the desktop in any direction. For every window located outside the user's viewport, a navigation string appears from the viewport center towards the window's location.
Each desktop window has a canvas for the hosted object's bitmap, sizing grips around the canvas, a window title at the top, and a window footer at the bottom.
The desktop window can host an object instance of an arbitrary type. The hosted object controls all of the hosting window's properties.
| Desktop object | Description |
|---|---|
Teletype Consoleteletype |
A solid, rectangular, truecolor text canvas depicting a freely scrollable buffer of text runs generated by an xterm-compatible parser from the standard output of an attached CUI application. It can be a very heavy object due to maintaining a scrollback buffer of arbitrary length. Not used directly in the desktop process's address space. |
Terminal Consoleterminal |
A derivative of Teletype Console with additional UI controls. |
DirectVT Gatewaydtvt |
A lightweight truecolor text canvas depicting content received from an external dtvt-aware process. |
Teletype Console dtvt‑bridgevtty |
A DirectVT Gateway hosting an external, standalone Teletype Console applet. It is designed to run heavy Teletype Console objects as external processes to optimize desktop resource consumption. |
Terminal Console dtvt‑bridgeterm |
A DirectVT Gateway hosting an external, standalone Terminal Console applet. It is designed to run heavy Terminal Console objects as external processes to optimize desktop resource consumption. |
DirectVT Gateway with TTYdtty |
A derivative of DirectVT Gateway stacked with an additional, limited Teletype Console as a controlling terminal. It is used for CUI applications that redirect the DirectVT stream to standard output and require user input via the platform's TTY. Depending on activity, the corresponding console becomes active for the user. |
Tiling Window Managertile |
A window container with an organization of the hosting window area into mutually non-overlapping panes for nested windows. |
Desktop Region Markersite |
A transparent, resizable frame for marking the specific desktop region for quick navigation across the borderless workspace. |
Notes:
vtty/dttyas hosts for heavy objects:- These heavy objects are typically terminal emulator instances that maintain a scrollback buffer of arbitrary size. By default, this buffer is set to 100,000 lines but can accommodate millions of lines if sufficient memory is available (limited only by
int32_maxcount). - While a terminal instance starts lightweight, the scrollback buffer (internally a circular buffer) grows over time as application output fills it. This resource consumption is the primary reason for running these specific object types as external processes (
Desktop Appletmode).
- These heavy objects are typically terminal emulator instances that maintain a scrollback buffer of arbitrary size. By default, this buffer is set to 100,000 lines but can accommodate millions of lines if sufficient memory is available (limited only by
- Do not confuse the
Desktop Appletnames with the desktop object names, even though they are literally the same, e.g.vttyandterm. Desktop objects of the same name as Desktop Applets are wrappers for heavy desktop objects that should be launched in parallel vtm processes.
Vtm can function perfectly well without explicit installation. However, for ease of launch, vtm can be installed (copied) to %SystemRoot% (usually C:\Windows) or /usr/local/bin, depending on the platform.
sudo vtm --installNotes:
- Mouse support in the Linux VGA Console (in-kernel console) requires direct access to mouse devices. The command
sudo vtm --mousegrants access to pointing devices for all users. - On Windows, the
vtm --installcommand will also install a system service (vtmText-based desktop environment.), which makes it possible to run the vtm desktop in Session 0 for connections to it from outside via ssh.
# run desktop in background ┌─ run desktop client
# ─┴────────── ─┴─
# ┌─ expanded to `vtm --daemon; vtm`
# ─┴─
vtmNote: You can explicitly specify running vtm inside the terminal (run vtm --tui) or in its own GUI window (run vtm --gui). GUI mode is only available on Windows for now.
# ┌─ Classic VT console (Teletype, vtty) for any command or TUI App
# ─┴──
# ┌─ expanded to `vtm --run vtty <any_command_or_tui_app>`
# ─────┴────────────────────
vtm any_command_or_tui_app# ┌─ use Terminal Console to run any_command_or_tui_app or user default shell
# ─┴──
# ┌─ expanded to `vtm --run term <any_command_or_tui_app or user_default_shell (if empty)>`
# ─────┴──────────────────────────────
vtm -r term [any_command_or_tui_app]- In general, the local and remote platforms may be different.
- When the DirectVT mode is used, all keyboard, mouse, and other input events are transmitted between hosts in a binary form.
- The following examples assume that vtm is accessible via PATH on both the local and remote sides.
Note: vtm (as a desktop client or standalone terminal) can be run in an existing interactive SSH session as a regular TUI application in Classic VT mode.
In the Classic VT console (Teletype, Terminal), vtm always runs in Classic VT mode:
# ┌─ Classic VT console (Teletype, vtty) for any command or TUI App
# ─┴──
# ┌ ssh/ssh.exe ┌─ expanded to `vtm --run vtty [any_remote_command_or_tui_app]`
# ─┴─ ───┴───────────────────────────────
ssh user@server vtm [any_remote_command_or_tui_app]
# ┬┬─ ─────────────┬───────────────
# <─ Classic VT <─┘└<─ Classic VT <─┘DirectVT mode will be automatically enabled if vtm is started inside the DirectVT console (DirectVT Gateway):
# DirectVT Gateway with TTY (DirectVT console) for DirectVT content received from an external dtvt-aware process
# ─┴──
# ┌─ expanded to `vtm --run dtty ssh`
# │ ┌─ expanded to `vtm --run vtty <any_remote_command_or_tui_app>`
# ───┴─── ───┴───────────────────────────────
vtm ssh user@server vtm <any_remote_command_or_tui_app>
# ─┬─ ┬┬ ─────────────┬───────────────
# └ binary DirectVT ─┘└<─ Classic VT <─┘...or with verbose syntax, allowing the use of any dtvt-aware source, not just ssh:
# DirectVT ─┐ ┌ any ssh/ssh.exe command ┌─ Classic VT console (Teletype, vtty) for TUI App
# console ─┴── ─┴───────────── ─┴──
vtm --run dtty ssh user@server vtm --run vtty <any_remote_command_or_tui_app>
# ─┬──────────── ─┬┬ ──────────────┬──────────────
# └─── binary DirectVT stream ───┘└<─── Classic VT stream <───┘Short command to access remote vtm desktop over SSH:
# ┌─ expanded to `vtm --run dtty ssh`
# │ ┌─ expanded to `vtm --daemon; vtm`
# ───┴─── ─┴─
vtm ssh user@server vtm
# ─┬─ ─┬─
# └ binary DirectVT ──┘- Remote side
ncat -l tcp_port -k -e vtm # ─┬───────── ─┬ ─┬──── # │ │ └ run vtm for every connected client # │ └ keep connection open for multiple clients # └ specifies tcp port to listen
- Local side
# ┌─ DirectVT Gateway (dtvt) for content received from ncat # ─┴── vtm -r dtvt ncat remote_ip remote_tcp_port
- Remote side
- Install
inetd. - Add the following line to the
/etc/inetd.conf:tcp_port stream tcp nowait user_name /remote/side/path/to/vtm vtm # ──────┬─ ─┬─────── # │ └ user login name # └ tcp port to listen
- Launch
inetd:inetd
- Install
- Local side
# ┌─ DirectVT Gateway (dtvt) for content received from ncat # ─┴── vtm -r dtvt ncat remote_ip remote_tcp_port
- Host side
mkfifo in && mkfifo out vtm >out <in - User side
# ┌─ DirectVT Gateway (dtvt) for content received from socat # ─┴── vtm -r dtvt socat open:out\!\!open:in stdin\!\!stdout
The remote and local sides may differ in platform.
- Local side with ip=1.2.3.4 (waiting for a connection from a remote on 1122tcp - a random available TCP port)
# ┌> relay dtvt-stream ┐ # ─────┴───────── ──────────┴──── vtm -r dtvt socat tcp-listen:1122 stdin\!\!stdout # ─┬───────── ───┬─────────── # └< binary DirectVT <────────────────┘
- Remote side - run vtm desktop and forward its stdio to the side with ip=1.2.3.4
socat tcp:1.2.3.4:1122 exec:"vtm" # ─┬────────────── ─┬─ # └< relay dtvt-stream <─┘
The client and server roles can be swapped:
- Local side (connect to 1.2.3.4:1122tcp)
vtm -r dtvt socat tcp:1.2.3.4:1122 stdin\!\!stdout - Remote side with ip=1.2.3.4 (vtm desktop waits for a connection on 1122tcp from a remote)
socat tcp-listen:1122 exec:"vtm"
-
Install
winsocatwinget install winsocat -
Local side with ip=1.2.3.4 (waiting for a connection from a remote on 1122tcp - a random available TCP port)
vtm -r dtvt winsocat tcp-listen:1122 stdio
-
Remote side - run vtm desktop and forward its stdio to the side with ip=1.2.3.4
winsocat tcp:1.2.3.4:1122 exec:"vtm"
Notes:
- The remote and local platforms may differ.
- Using the localhost name may cause connection issues with the IP address family (IPv4:
127.0.0.1vs. IPv6:[::1]) between remote systems. Use an explicit IP address to avoid this.
- Remote side
# Run reverse tunnel for 1122tcp in background # ┌─ relay all traffic passed through 127.0.0.1:1122tcp to the remote host # ─────────┴──── ssh -N -R 1122:127.0.0.1:1122 user@1.2.3.4 & # ─┬ ─┬───── ─┬────────── ┬ # │ └─ listen on remote │ └─ run in background # │ └─ remote host # └─ do nothing on remote just listen 1122tcp # # Save the background process' PID ssh_tunnel_pid=$! # # Run vtm and forward its stdio (in dtvt format) streams to 127.0.0.1:1122. # ┌──────< relay dtvt-stream <─────┐ ┌─ kill the ssh reverse tunnel after vtm exits # ─────┴──────────────────────── ─┴─ ──┴───────────────── socat tcp-listen:1122,bind=127.0.0.1 exec:"vtm"; kill $ssh_tunnel_pid # ─────┬──────────────────────── # └─ wait for forwarded connections on 127.0.0.1:1122tcp # or reversed # socat exec:"vtm" tcp-listen:1122,bind=127.0.0.1; kill $ssh_tunnel_pid
- Local side with ip=1.2.3.4 (connect to the remote vtm desktop via 127.0.0.1:1122tcp)
# ┌──────────< binary DirectVT <─────────────┐ # ───┴─────── ─────────┴───── vtm -r dtvt socat tcp:127.0.0.1:1122 stdin\!\!stdout # ────┬───────────── ─────────┬───── # └─> relay dtvt-stream >─┘
- Install
winsocatwinget install winsocat - Remote side
# Run reverse tunnel for 1122tcp in background. $process = Start-Process "ssh" "-N -R 1122:127.0.0.1:1122 user@1.2.3.4" -PassThru -WindowStyle Minimized # Run vtm and forward its stdio streams to 127.0.0.1:1122. # ┌──────< relay dtvt-stream <─────┐ ┌─ kill the ssh reverse tunnel after vtm exits # ─────┴──────────────────────── ─┴─ ──┴───────────────────────── winsocat tcp-listen:1122,bind=127.0.0.1 exec:"vtm"; Stop-Process -Id $process.Id # ─────┬──────────────────────── # └─ wait for forwarded connections on 127.0.0.1:1122tcp # or # winsocat exec:"vtm" tcp-listen:1122,bind=127.0.0.1; Stop-Process -Id $process.Id
- Local side with ip=1.2.3.4 (connect to the remote vtm desktop via 127.0.0.1:1122tcp)
# ┌───────< binary DirectVT <─────────────┐ # ───┴─────── ───┴─ vtm -r dtvt winsocat tcp:127.0.0.1:1122 stdio # ┬───────────────── ───┬─ # └> relay dtvt-stream >┘
It is possible to visualize standard input/output streams of running CUI applications. Launched in the Log Monitor mode (vtm -m), vtm will log the event stream of each terminal window where the Logs switch is enabled.
Important: Avoid enabling the Logs switch in the terminal window hosting the Log Monitor process itself, as this may lead to recursive event logging with unpredictable results.
The taskbar menu can be configured using a settings file ~/.config/vtm/settings.xml (%USERPROFILE%\.config\vtm\settings.xml on Windows):
<config>
<desktop>
<taskbar>
<!-- <item*/> --> <!-- Uncomment to clear the default item list. -->
<item splitter label="Remote Access"/>
<item id="Run remote vtm desktop in DirectVT mode over SSH" type="dtty" cmd="ssh user@server vtm"/>
<item id="Run console app in remote terminal over SSH" type="dtty" cmd="ssh user@server vtm -r term </path/to/console/app...>"/>
<item id="Run console app remotely over SSH w/o extra UI" type="dtty" cmd="ssh user@server vtm </path/to/console/app...>"/>
<item splitter label="More Examples"/>
<item id="Far Manager" type="vtty" cmd="far"/>
<item id="Far Manager in terminal" type="dtvt" cmd="$0 -r term far"/>
<item id="Midnight Commander" type="vtty" cmd="mc"/>
<item id="Midnight Commander in terminal" type="dtvt" cmd="$0 -r term mc"/>
<item id="Remote cmd in terminal over SSH" type="dtty" cmd="ssh user@server vtm -r term cmd"/>
<item id="Remote cmd over SSH" type="dtty" cmd="ssh user@server vtm cmd"/>
<item id="Remote Far Manager over SSH" type="dtty" cmd="ssh user@server vtm far"/>
<item id="Remote wsl over SSH" type="dtty" cmd="ssh user@server vtm wsl"/>
<item id="Remote mc over SSH" type="dtty" cmd="ssh user@server vtm mc"/>
<item id="Remote wsl mc over SSH" type="dtty" cmd="ssh user@server vtm wsl mc"/>
</taskbar>
</desktop>
</config>It is possible to emulate the tmux-like keyboard prefix approach by using a global variable in the Lua scripting runspace. As an example, the following configuration adds the keyboard shortcut Ctrl+B as a toggle for an additional keyboard mode (coupled with a user-defined variable named kbmodifier - a table of Boolean values unique to each connected user: kbmodifier[vtm.gate]) that allows windows to be moved directly using the arrow keys:
~/.config/vtm/settings.xml:<config> <events> <gate> <script="if kbmodifier == nil then kbmodifier = {}; end;" on="release: e2::form::upon::started"/> <!-- Initialize `kbmodifier` table if it is not initialized. --> <script="kbmodifier[vtm.gate] = nil;" on="release: e2::form::upon::stopped"/> <!-- Remove user specific kbmodifier state on user disconnect. --> </gate> <desktop> <SetMark="vtm.gate.SetOverlay(0, kbmodifier[vtm.gate] and '\\n\\x1b[11:2p\\x1b[41mB' or ''); vtm.gate.Deface();"/> <!-- `SetMark` macro. If the kbmodifier is active, draw a visual red "B" mark near the right side of the viewport. --> <script="kbmodifier[vtm.gate] = not kbmodifier[vtm.gate];" | SetMark on="Ctrl+B"/> <!-- Emulate tmux-like prefix key. Store the mode state value in the `kbmodifier` table using a unique vtm.gate (user's console) value for each user. --> <script="" on="Alt+Z" /> <!-- Unbind existing FocusTaskbar binding. --> <script="" on="Ctrl+PageUp" /> <!-- Unbind existing FocusPrevWindow binding. --> <script="" on="Ctrl+PageDown"/> <!-- Unbind existing FocusNextWindow binding. --> </desktop> <applet> <!-- Key bindings for the application window. --> <KeyFilter=prerun prerun="if (not kbmodifier[vtm.gate] and vtm.gear.Bypass()) then return; end; "/> <!-- `KeyFilter` macro. Do nothing if `kbmodifier[vtm.gate]` is false. Calling vtm.gear.Bypass() always returns true. --> <script=KeyFilter | MoveAppletLeft on="LeftArrow" /> <!-- The ` | ` operator concatenates script fragments/macros. If for some reason the keyboard event is not processed by anyone, it will then return and fire on this object, so the KeyFilter's script is also reused at the beginning of the `script="..."`. --> <script=KeyFilter | MoveAppletRight on="RightArrow" /> <!-- The `prerun` attribute (inherited from KeyFilter) contains a Lua script that will be executed during pre-polling to filter out key events. --> <script=KeyFilter | MoveAppletUp on="UpArrow" /> <!-- When `kbmodifier[vtm.gate]` is true, you can move windows using the arrow keys. --> <script=KeyFilter | MoveAppletDown on="DownArrow" /> <!-- Macros like `MoveApplet...` are defined in the default configuration. You can list them with `vtm -l`. --> <script=KeyFilter | MoveAppletTopLeft on="LeftArrow+UpArrow | UpArrow+LeftArrow" /> <!-- Simultaneous key presses should also be processed if supported. --> <script=KeyFilter | MoveAppletBottomLeft on="LeftArrow+DownArrow | DownArrow+LeftArrow" /> <!-- It is convenient to specify multiple keyboard shortcuts in one definition separated by `|`. --> <script=KeyFilter | MoveAppletTopRight on="RightArrow+UpArrow | UpArrow+RightArrow" /> <script=KeyFilter | MoveAppletBottomRight on="RightArrow+DownArrow | DownArrow+RightArrow"/> <script=KeyFilter | IncreaseAppletWidth on="Ctrl+RightArrow" /> <script=KeyFilter | DecreaseAppletWidth on="Ctrl+LeftArrow" /> <script=KeyFilter | IncreaseAppletHeight on="Ctrl+DownArrow" /> <script=KeyFilter | DecreaseAppletHeight on="Ctrl+UpArrow" /> <script=KeyFilter | FocusPrevWindow on="PageUp" /> <script=KeyFilter | FocusNextWindow on="PageDown" /> <script=KeyFilter | FocusTaskbar on="preview: -Esc" /> <!-- Focus taskbar on Esc unpress. The `on="Esc"` combination is busy in bindings like `"Esc+..."`. --> </applet> </events> </config>
Additionally, the taskbar menu of the running desktop can be configured using shell piped redirection by sending script commands to the running vtm desktop:
# Delete existing menu items
echo "vtm.taskbar.Del()" | vtm
# Add new menu items
echo "vtm.taskbar.Set({ id='Term', label='Terminal', type='dtvt', cmd='vtm -r term' })" | vtm
echo "vtm.taskbar.Set({ id='White', label='White Terminal', type='dtvt', cmd='vtm -r term', cfg='<config><terminal><colors><default fgc=0xFF000000 bgc=0xFFffffff/></colors></terminal></config>' })" | vtm
echo "vtm.taskbar.Set({ id='Huge', label='Huge Terminal', type='dtvt', cmd='vtm -r term', cfg='<config><terminal><scrollback size=500000/></terminal></config>' })" | vtm
echo "vtm.taskbar.Set({ id='Tile', label='Three Terminals', type='tile', cmd='v(h(Term, White), Huge)' })" | vtm
echo "vtm.taskbar.Set({ id='cmd', label='Remote cmd over SSH', type='dtty', cmd='ssh user@server vtm cmd' })" | vtm
# Set default menu item
echo "vtm.taskbar.Selected('Term')" | vtm
# Run window with terminals
echo "vtm.desktop.Run({ id='Tile' })" | vtm