Connection

The Connection interface represents a connection to a terminal (local, direct, or remote).

Creating Connections

Local Terminal Connection

import org.aesh.tty.terminal.TerminalConnection;

Connection connection = new TerminalConnection();

Opening Connections

Blocking Mode

connection.openBlocking();

Blocks the current thread until the connection is closed.

Non-Blocking Mode

connection.openNonBlocking();

Reads input in a separate thread, allowing the current thread to continue.

Checking Reading State

// Check if connection is actively reading
if (connection.reading()) {
    // Handler-based queries work (setStdinHandler)
} else {
    // Use synchronous methods like queryColorCapability()
}

The reading() method returns true after openBlocking() or openNonBlocking() is called and before close() is called. This is useful for determining which query methods to use:

  • When reading() is true: Handler-based methods like queryTerminal() work
  • When reading() is false: Use synchronous methods like queryColorCapability()

Handlers

Standard Input Handler

connection.setStdinHandler(input -> {
    for (int codePoint : input) {
        System.out.println("Char: " + (char) codePoint);
    }
});

Consumer<int[]> handler = connection.getStdinHandler();

Standard Output Handler

Consumer<int[]> outputHandler = connection.stdoutHandler();
outputHandler.accept("Output text\n".codePoints().toArray());

// Convenience method
connection.write("Hello, World!\n");

Size Handler

Called when terminal is resized:

connection.setSizeHandler(size -> {
    int width = size.getWidth();
    int height = size.getHeight();
    System.out.println("Terminal resized: " + width + "x" + height);
});

Consumer<Size> sizeHandler = connection.getSizeHandler();

Signal Handler

Called when terminal signals are received:

connection.setSignalHandler(signal -> {
    System.out.println("Signal: " + signal);
});

Consumer<Signal> signalHandler = connection.getSignalHandler();

Close Handler

Called when the connection is closed:

connection.setCloseHandler(ignored -> {
    System.out.println("Connection closed");
});

Consumer<Void> closeHandler = connection.getCloseHandler();

Terminal Properties

Device device = connection.device();
Size size = connection.size();

// Encoding
Charset inputEncoding = connection.inputEncoding();
Charset outputEncoding = connection.outputEncoding();

// ANSI support
boolean supportsAnsi = connection.supportsAnsi();

Attributes

Attributes attributes = connection.getAttributes();
connection.setAttributes(new Attributes);

Capabilities

Set terminal capabilities:

boolean success = connection.put(Capability.key_x, 1);

Closing Connections

connection.close();          // Close with default exit
connection.close(0);        // Close with specific exit code

Write Convenience

Connection connection = ...;

connection.write("Hello");
connection.write("Line 1\nLine 2\n");

Raw Mode

Enter raw mode for character-by-character input:

Attributes previous = connection.enterRawMode();
// ... work in raw mode ...
connection.setAttributes(previous);

Cursor Position

Get cursor position:

Point position = connection.getCursorPosition();
int row = position.getRow();
int col = position.getColumn();

OSC Queries

OSC (Operating System Command) queries allow you to interrogate the terminal for information like colors, clipboard content, and more.

Generic OSC Query

Send any OSC query with a custom response parser:

// Query palette color 4 with custom parser
String result = connection.queryOsc(4, "?", 500, input -> {
    // Custom parsing logic
    return parseColorResponse(input);
});

Color Queries

Query the terminal’s current colors:

// Query foreground color (OSC 10)
int[] fg = connection.queryForegroundColor(500);
if (fg != null) {
    System.out.println("Foreground: RGB(" + fg[0] + "," + fg[1] + "," + fg[2] + ")");
}

// Query background color (OSC 11)
int[] bg = connection.queryBackgroundColor(500);
if (bg != null) {
    System.out.println("Background: RGB(" + bg[0] + "," + bg[1] + "," + bg[2] + ")");
}

// Query cursor color (OSC 12)
int[] cursor = connection.queryCursorColor(500);

Palette Color Queries

Query colors from the 256-color palette using OSC 4:

// Query palette color by index (0-255)
int[] color = connection.queryPaletteColor(1, 500);
if (color != null) {
    System.out.println("Palette 1: RGB(" + color[0] + "," + color[1] + "," + color[2] + ")");

    // Convert to nearest 256-color index
    int index = ANSI.rgbTo256Color(color[0], color[1], color[2]);

    // Convert to basic ANSI code
    int ansiCode = ANSI.rgbToAnsiColor(color[0], color[1], color[2]);
}

Palette indices:

  • 0-7: Standard ANSI colors
  • 8-15: Bright ANSI colors
  • 16-231: 6x6x6 color cube
  • 232-255: Grayscale ramp

OSC Query with Index Parameter

For OSC codes that require an index (like OSC 4), use the indexed query method:

// Query OSC 4 with index parameter
int[] rgb = connection.queryOsc(4, 1, "?", 500,
        input -> ANSI.parseOscColorResponse(input, 4, 1));

OSC Support Detection

Not all terminals support all OSC queries. For example, JetBrains IDE terminals don’t support OSC 4 (palette queries). Use the Device enums to check terminal capabilities before querying:

import org.aesh.terminal.Device.TerminalType;
import org.aesh.terminal.Device.OscCode;

// Detect terminal type from environment
TerminalType termType = connection.getTerminalType();
System.out.println("Terminal: " + termType.getIdentifier());

// Check specific OSC support
if (connection.supportsPaletteQuery()) {
    int[] color = connection.queryPaletteColor(1, 500);
    // Use color...
}

// Or use the convenience method that checks support first
int[] color = connection.queryPaletteColorIfSupported(1, 500);
if (color != null) {
    // Terminal supports OSC 4 and returned a color
}

// Check for OSC 10/11 support
if (connection.supportsColorQuery()) {
    int[] fg = connection.queryForegroundColor(500);
    int[] bg = connection.queryBackgroundColor(500);
}

// Check if running in JetBrains IDE
Device device = connection.device();
if (device != null && device.isJetBrainsTerminal()) {
    // Use fallback approach for palette colors
}

// Check for any OSC code support
if (connection.supportsOscCode(OscCode.CLIPBOARD)) {
    // Terminal supports clipboard access via OSC 52
}

Known terminal limitations:

  • JetBrains IDEs: No OSC 4 (palette) support
  • Linux console: No OSC query support
  • Alacritty: No OSC 52 (clipboard) support

Batch OSC Queries

For better performance when querying multiple colors, use batch queries. This sends all queries at once and collects responses together, reducing latency from O(n × timeout) to O(timeout):

// Query foreground, background, and cursor colors in one operation
// Takes ~50-100ms instead of ~300-400ms for individual queries
Map<Integer, int[]> colors = connection.queryColors(500);

int[] fg = colors.get(ANSI.OSC_FOREGROUND);   // OSC 10
int[] bg = colors.get(ANSI.OSC_BACKGROUND);   // OSC 11
int[] cursor = colors.get(ANSI.OSC_CURSOR_COLOR);  // OSC 12

// Query multiple palette colors at once
Map<Integer, int[]> palette = connection.queryPaletteColors(500, 0, 1, 2, 3, 4, 5, 6, 7);

// Query all 16 ANSI colors
Map<Integer, int[]> ansi16 = connection.queryAnsi16Colors(500);

// Generic batch query for any OSC codes
Map<Integer, int[]> results = connection.queryBatchOsc(500, 10, 11, 12);

For higher-level access with automatic fallbacks, use TerminalColorDetector:

import org.aesh.terminal.tty.TerminalColorDetector;

// Query with automatic fallback to environment-based detection
Map<Integer, int[]> colors = TerminalColorDetector.queryColorsWithFallback(connection, 500);
// Always returns colors - actual if OSC works, estimated if not

Device Attributes (DA1/DA2)

Device Attributes queries allow you to detect terminal capabilities that cannot be determined from terminfo alone.

Primary Device Attributes (DA1)

Query the terminal’s conformance level and supported features:

DeviceAttributes da = connection.queryPrimaryDeviceAttributes(500);

if (da != null) {
    // Device class (1=VT100, 62=VT220, 64=VT420, etc.)
    int deviceClass = da.getDeviceClass();

    // Check specific features
    boolean hasSixel = da.supportsSixel();
    boolean hasAnsiColor = da.supportsAnsiColor();
    boolean hasMouse = da.supportsMouse();
    boolean has132Cols = da.supports132Columns();

    // Check any feature by enum
    if (da.hasFeature(DeviceAttributes.Feature.RECTANGULAR_EDITING)) {
        // Terminal supports rectangular editing operations
    }
}

Secondary Device Attributes (DA2)

Query terminal identification and version information:

DeviceAttributes da = connection.querySecondaryDeviceAttributes(500);

if (da != null) {
    // Terminal type (VT100, VT220, VT420, etc.)
    DeviceAttributes.TerminalType type = da.getTerminalType();

    // Firmware/version number
    int version = da.getFirmwareVersion();

    System.out.println("Terminal: " + type.getName() + " v" + version);
}

Combined Query

Query both DA1 and DA2 and merge the results:

DeviceAttributes da = connection.queryDeviceAttributes(500);

if (da != null) {
    // Has both DA1 and DA2 data
    System.out.println("Class: " + da.getDeviceClass());
    System.out.println("Type: " + da.getTerminalType().getName());
    System.out.println("Features: " + da.getFeatures());
}

Available Features

The DeviceAttributes.Feature enum includes:

FeatureCodeDescription
COLUMNS_1321132-column mode
PRINTER2Printer port
REGIS_GRAPHICS3ReGIS graphics
SIXEL4Sixel graphics
SELECTIVE_ERASE6Selective erase
DRCS7Soft character set
USER_DEFINED_KEYS8User-defined keys
NATIONAL_CHARSETS9National character sets
LOCATOR16DEC locator (mouse)
ANSI_COLOR22ANSI color support
RECTANGULAR_EDITING28Rectangular editing
ANSI_TEXT_LOCATOR29ANSI text locator (mouse)

Image Protocol Detection

Detect the terminal’s image protocol support using DA1 attributes:

// Query-based detection (most accurate)
ImageProtocol protocol = connection.queryImageProtocol(500);

switch (protocol) {
    case KITTY:
        // Use Kitty graphics protocol
        break;
    case ITERM2:
        // Use iTerm2 inline images
        break;
    case SIXEL:
        // Use Sixel graphics
        break;
    case NONE:
        // No image support detected
        break;
}

For faster (but less accurate) detection without querying:

Device device = connection.device();
ImageProtocol protocol = device.getImageProtocol();

Color Capabilities

Get terminal color information:

// Get color depth from terminfo or environment
ColorDepth depth = connection.getColorDepth();

if (depth.supportsTrueColor()) {
    // Use 24-bit RGB colors
} else if (depth.supports256Colors()) {
    // Use 256-color palette
}

// Query terminal for full color capability (uses synchronous I/O)
// This can be called BEFORE openBlocking/openNonBlocking
TerminalColorCapability cap = connection.queryColorCapability(500);
if (cap != null) {
    TerminalTheme theme = cap.getTheme();
    int[] fg = cap.getForegroundRGB();
    int[] bg = cap.getBackgroundRGB();
    int[] cursor = cap.getCursorRGB();
    Map<Integer, int[]> palette = cap.getPaletteColors();
}

// Or use TerminalColorDetector for comprehensive detection with fallbacks
TerminalColorCapability cap = TerminalColorDetector.detect(connection);