terminput

Crates.ioterminput
lib.rsterminput
version0.5.6
created_at2025-01-22 02:21:50.891934+00
updated_at2025-08-25 01:45:45.43436+00
descriptionTUI input parser/encoder and abstraction over input backends
homepagehttps://github.com/aschey/terminput
repositoryhttps://github.com/aschey/terminput
max_upload_size
id1526213
size205,760
Austin Schey (aschey)

documentation

README

terminput

crates.io docs.rs license CI codecov GitHub repo size Lines of Code

A library to abstract over various backends that provide input events, such as key presses and mouse clicks. This was mainly created as a common interface to the terminal backends that Ratatui supports.

Many TUI libraries with some kind of input handling mechanism want to support multiple backends, but mapping each backend's input structure into a common interface is tedious, and it can be difficult to keep up with all the new backends being added. This library aims to provide a uniform interface to these input types and prevent crates from having to manually add support for each backend.

Additionally, we supply methods for parsing and encoding ANSI escape sequences for events.

Feature Flags

  • std - Adds a dependency on the standard library, required for the encoder and parser modules (enabled by default).
  • serde - Adds serde serialization for event types (not enabled by default).

Usage

Use the conversion methods provided by the integration crates to convert to and from from terminput's event types.

use crossterm::event::read;
use std::io;
use terminput::Event;
use terminput_crossterm::{to_crossterm, to_terminput};

fn main() -> io::Result<()> {
    let crossterm_event = read()?;
    let event: Result<Event, _> = to_terminput(crossterm_event);
    println!("{event:?}");

    if let Ok(event) = event {
        // Conversions work both ways
        let event2: Result<crossterm::event::Event, _> = to_crossterm(event);
        println!("{event2:?}");
    }

    Ok(())
}

Event Matching

Some helpers for matching on events are included. See the match_event example.

Backends

The following backends are currently supported via separate integration crates. Different versions of each backend can be used by activating a feature flag that matches the desired version. For example, crossterm 0.28 can be activated using the crossterm_0_28 feature. The latest version of each backend will be enabled by default.

See the docs for each integration crate for more details.

backend integration crate supported versions
crossterm terminput-crossterm 0.28, 0.29
termion terminput-termion 4
termwiz terminput-termwiz 0.22, 0.23
egui terminput-egui 0.32
web-sys terminput-web-sys 0.3

The Event struct provided by this library is an attempt to create a superset of all supported backend functionality that TUI apps may be interested in.

The following table shows the matrix of supported features:

feature crossterm termion termwiz egui web-sys
key press
key release/repeat
mouse down
mouse up
mouse move
mouse drag
focus
paste
resize

Conversions for web-sys are only implemented in one direction (web-sys to terminput) because conversions in the other direction don't seem particularly useful. If you require this functionality, feel free to make a feature request.

Parsing

Use the Event::parse_from method to parse an ANSI-encoded sequence of bytes into an event struct. This can be helpful for usage with SSH or other situations where you need to read raw input from something other than a normal TTY device.

The input parser used here was extracted from crossterm's implementation.

use terminput::Event;

fn read_input(input: &[u8]) {
    let event = Event::parse_from(input);

    match event {
        Ok(Some(event)) => {
            println!("Successfully parsed input: {event:?}");
        }
        Ok(None) => {
            println!("More input required");
        }
        Err(e) => {
            println!("Unable to parse input: {e:?}");
        }
    }
}

Encoding

Input structs can also be encoded into ANSI escape sequences using Event::encode. This can be useful if you're controlling a child pty and need to send it some encoded input.

use terminput::{Encoding, Event, KeyCode, KeyEvent, KittyFlags};

let event = Event::Key(KeyEvent::new(KeyCode::Char('a')));
let mut buf = [0; 16];

// Legacy encoding
let written = event.encode(&mut buf, Encoding::Xterm);
if let Ok(written) = written {
    println!("Encoded: {:?}", &buf[..written]);
}

// Kitty encoding
let mut buf = [0; 16];
let written = event.encode(&mut buf, Encoding::Kitty(KittyFlags::all()));
if let Ok(written) = written {
    println!("Encoded: {:?}", &buf[..written]);
}

Supported Rust Versions

The MSRV is currently 1.85.0. Since Cargo's V3 resolver supports MSRV-aware dependencies, we do not treat an MSRV bump as a breaking change.

Commit count: 106

cargo fmt