Declaring terminals
Module Notty . Unescape

Input events

type special = [
| `Escape
| `Enter
| `Tab
| `Backspace
| `Insert
| `Delete
| `Home
| `End
| `Arrow of [ `Up | `Down | `Left | `Right ]
| `Page of [ `Up | `Down ]
| `Function of int

A selection of extra keys on the keyboard.

type button = [
| `Left
| `Middle
| `Right
| `Scroll of [ `Up | `Down ]

Mouse buttons.

type mods = [ `Meta | `Ctrl | `Shift ] list

Modifier state.

type key = [ special | `Uchar of Uchar.t | `ASCII of char ] * mods

Keypress event.

type mouse = [ `Press of button | `Drag | `Release ] * (int * int) * mods

Mouse event.

type paste = [
| `Start
| `End

Paste event.

type event = [
| `Key of key
| `Mouse of mouse
| `Paste of paste

Things that terminals say to applications.

  • `Key (k, mods) is keyboard input.

    k is a key, one of:

    `ASCII and `Uchar together represent the textual part of the input. These characters are guaranteed not to be control characters, and are safe to use when constructing images. ASCII is separated from the rest of Unicode for convenient pattern-matching.

    mods are the extra modifier keys.

  • `Mouse (event, (x, y), mods) is mouse input.

    event is the actual mouse event: button press, release, or motion of the mouse with buttons depressed.

    (x, y) are column and row position of the mouse. The origin is (0,0), the upper-left corner.

    Note Every `Press (`Left|`Middle|`Right) generates a corresponding `Release, but there is no portable way to detect which button was released. `Scroll (`Up|`Down) presses are not followed by releases.

  • `Paste (`Start|`End) are bracketed paste events, signalling the beginning and end of a sequence of events pasted into the terminal.

    Note This mechanism is useful, but not reliable. The pasted text could contain spurious start-of-paste or end-of-paste markers, or they could be entered by hand.

Terminal input protocols are historical cruft, and heavily overload the ASCII range. For instance:

  • It is impossible to distinguish lower- and upper-case ASCII characters if Ctrl is pressed;
  • several combinations of key-presses are aliased as special keys; and
  • in a UTF-8 encoded stream, there is no representation for non-ASCII characters with modifier keys.

This means that many values that inhabit the event type are impossible, while some reflect multiple different user actions. Limitations include:

  • `Shift is reported only with special keys, and not all of them.
  • `Meta and `Control are reported with mouse events, key events with special keys, and key events with values in the ranges 0x40-0x5f (@ to _) and 0x60-0x7e (` to ~). If Ctrl is pressed, the higher range is mapped into the lower range.
  • Terminals will variously under-report modifier key state.

Perform own experiments before relying on elaborate key combinations.

val uchar : [< `Uchar of Uchar.t | `ASCII of char ] -> Uchar.t

uchar x is the Uchar.t corresponding to x. This operations merges the ASCII and Unicode variants of key.

Decoding filter

Simple IO-less terminal input processor. It can be used for building custom terminal input abstractions.

type t

Input decoding filter.

The filter should be fed strings, which it first decodes from UTF-8, and then extracts the input events.

Malformed UTF-8 input bytes and unrecognized escape sequences are silently discarded.

val create : unit -> t

create () is a new, empty filter.

val input : t -> bytes -> int -> int -> unit

input t buffer i len feeds len bytes of string into t, starting from position len.

len = 0 signals the end of input.

buffer is immediately processed and can be reused after the call returns.

val next : t -> [ event | `Await | `End ]

next t is the next event in the filter's input stream:

  • #event, an input event.
  • `Await if the filter needs more input.
  • `End if the input had ended.
val pending : t -> bool

pending t is true if a call to next, without any intervening input, would not return `Await.

Low-level parsing

Warning The parsing interface is subject to change.

Implementation of small parts of ECMA-35 and ECMA-48, as needed by terminal emulators in common use.

val decode : Uchar.t list -> event list

decode us are the events encoded by us.

us are assumed to have been generated in a burst, and the end of the list is taken to mean a pause. Therefore, decode us1 @ decode us2 <> decode (us1 @ us2) if us1 ends with a partial escape sequence, including a lone \x1b.

Unsupported escape sequences are silently discarded.