Documentation
¶
Overview ¶
Package input decodes raw terminal bytes into structured key events, including multi-byte ANSI escape sequences (arrows, function keys, etc.) and UTF-8 runes, without any external terminfo/termcap dependency.
Index ¶
- Constants
- type BackgroundColorEvent
- type BackgroundUnknownMsg
- type ChordDef
- type ChordMatcher
- type ChordMsg
- type ChordResult
- type Event
- type FocusEvent
- type Key
- type KeyAction
- type KeyType
- type Mod
- type MouseAction
- type MouseButton
- type MouseEvent
- type PaletteColorEvent
- type PasteEvent
- type Reader
- type ReplyEvent
Examples ¶
Constants ¶
const ( // PasteIdleTimeout is how long a paste may go without a new byte before // the Reader gives up on its end marker and delivers what it has. PasteIdleTimeout = 250 * time.Millisecond // MaxPasteBytes is the most paste text one PasteEvent holds. MaxPasteBytes = 16 << 20 )
const DefaultChordTimeout = 500 * time.Millisecond
DefaultChordTimeout is how long ChordMatcher waits for the next key of a still-possible chord before giving up on it. Vim-style multi-key sequences (g g, d d) and Emacs-style prefix bindings (ctrl+x ctrl+s) both use a window in roughly this range.
const DefaultEscTimeout = 30 * time.Millisecond
DefaultEscTimeout is how long a lone ESC waits for the rest of an escape sequence before it is reported as the Escape key.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type BackgroundColorEvent ¶
type BackgroundColorEvent struct {
R, G, B uint8
}
BackgroundColorEvent is the terminal's answer to an OSC 11 background query (ansi.QueryBackgroundColor), with each channel scaled to 8 bits.
func (BackgroundColorEvent) BackgroundRGB ¶
func (e BackgroundColorEvent) BackgroundRGB() (r, g, b uint8)
BackgroundRGB returns the colour; theme.Detect looks for this method.
type BackgroundUnknownMsg ¶
type BackgroundUnknownMsg struct{}
BackgroundUnknownMsg is sent once, to Update, when background detection is on and the terminal did not answer the background-colour query within the timeout. tui.BackgroundUnknownMsg is an alias of it. It lives here, below the root package, so theme.Detect can recognise it (through BackgroundUnknown) without importing either.
func (BackgroundUnknownMsg) BackgroundUnknown ¶
func (BackgroundUnknownMsg) BackgroundUnknown()
BackgroundUnknown marks m as the "no answer" message; theme.Detect looks for this method.
type ChordDef ¶
ChordDef configures one multi-key chord ChordMatcher recognizes. Keys is the ordered sequence of Key.String() forms (e.g. "g", "ctrl+x") that must arrive one after another for the chord to fire.
type ChordMatcher ¶
type ChordMatcher struct {
// Timeout overrides DefaultChordTimeout; the zero value (before any
// Feed call sets it) means DefaultChordTimeout.
Timeout time.Duration
// contains filtered or unexported fields
}
ChordMatcher accumulates Key events against a set of configured ChordDefs. It has no framework dependency: an application feeds it every Key event from tui.Update and acts on the returned ChordResult, so it works the same whether or not the caller happens to be a tui.Program.
ChordMatcher is not goroutine-safe; use it from a single Update-driven call site, the same assumption every other stateful piece of this library makes.
func NewChordMatcher ¶
func NewChordMatcher(defs ...ChordDef) *ChordMatcher
NewChordMatcher returns a ChordMatcher recognizing defs, using DefaultChordTimeout.
func (*ChordMatcher) Expire ¶
func (c *ChordMatcher) Expire(now time.Time) []Key
Expire flushes a pending prefix that has timed out even though no further key has arrived to trigger Feed's own expiry check — e.g. driven by an application's own idle/tick timer. It returns nil if nothing is pending or the pending prefix hasn't timed out yet.
func (*ChordMatcher) Feed ¶
func (c *ChordMatcher) Feed(k Key, now time.Time) ChordResult
Feed advances the matcher by one Key, arriving at time now. now is a parameter (rather than time.Now()) so callers, and this package's own tests, can drive it deterministically.
type ChordMsg ¶
type ChordMsg struct{ Name string }
ChordMsg is delivered by ChordMatcher.Feed when a configured chord completes: Name is whichever ChordDef.Name matched.
type ChordResult ¶
type ChordResult struct {
// Msg is non-nil when k completed a configured chord.
Msg *ChordMsg
// Pending is true when k extends a still-possible chord prefix: the
// caller should wait rather than act on k directly. If the chord never
// completes, a later Feed or Expire call returns the buffered keys via
// Flush.
Pending bool
// Flush holds keys that are NOT part of any completed chord — a
// previously buffered prefix that turned out to be a dead end, or (when
// no chord could ever match) k itself — in the order they should be
// delivered to the application, as if chord matching had never seen
// them.
Flush []Key
}
ChordResult is Feed's outcome for one Key.
type Event ¶
type Event = any
Event is whatever ReadEvent decodes next: a Key, a MouseEvent, or a PasteEvent. There's no exported interface to implement — a type switch on the concrete type is the intended way to handle it, the same way tui.Msg is handled in a Model's Update.
type FocusEvent ¶
type FocusEvent struct {
Focused bool
}
FocusEvent reports the terminal window gaining (Focused true, ESC[I) or losing (Focused false, ESC[O) focus. Terminals only send it after focus reporting is enabled (DECSET 1004).
type Key ¶
type Key struct {
Type KeyType
// Text is what a KeyRunes or KeySpace key typed: one character, or the
// whole text when the terminal reports a key with associated text (a
// grapheme cluster, a composed character). It is empty for every other
// type. A Text of one ASCII character shares a table, so decoding it
// allocates nothing.
Text string
// Code is the first rune of Text for a KeyRunes or KeySpace key, and the
// letter (or space, \\, ], ^, _) of a KeyCtrl key; 0 for every other type.
Code rune
Mod Mod
// Action is KeyPress (the zero value) unless the Reader was asked to
// report kitty event types, when it can also be KeyRepeat or KeyRelease.
Action KeyAction
// Keypad is true when the key came from the numeric keypad, as reported
// by the kitty protocol (always with flag 8, KeyboardReportAll, and
// usually with flag 1). Keypad Enter is {Type: KeyEnter, Keypad: true};
// keypad digits and operators are KeyRunes with the character in Text;
// keypad arrows, Home/End, PgUp/PgDn, Insert and Delete use the
// matching Type. Legacy terminals cannot tell keypad keys apart.
Keypad bool
}
Key is a single decoded key event.
type KeyAction ¶
type KeyAction uint8
KeyAction is the kind of a Key event.
The key actions. Only KeyPress is ever delivered unless release/repeat reporting is on (Reader.SetReportEvents, tui.WithKeyboard with KeyboardReportEvents).
type KeyType ¶
type KeyType int
KeyType identifies which key a Key event represents.
const ( KeyRunes KeyType = iota // printable input; see Key.Text KeyUp KeyDown KeyLeft KeyRight KeyEnter KeyEsc KeyTab KeyBackspace KeyDelete KeySpace KeyHome KeyEnd KeyPgUp KeyPgDown KeyF1 KeyF2 KeyF3 KeyF4 KeyCtrlC KeyCtrl // generic ctrl+letter; the letter is in Key.Code KeyUnknown // Appended after KeyUnknown so existing values are unchanged. KeyF5..KeyF24 // are contiguous. KeyF5 KeyF6 KeyF7 KeyF8 KeyF9 KeyF10 KeyF11 KeyF12 KeyF13 KeyF14 KeyF15 KeyF16 KeyF17 KeyF18 KeyF19 KeyF20 KeyF21 KeyF22 KeyF23 KeyF24 KeyInsert // Kitty media keys (private-use codepoints 57428-57440), decoded by // the kitty CSI-u path. They carry no runes. KeyMediaPlay KeyMediaPause KeyMediaPlayPause KeyMediaReverse KeyMediaStop KeyMediaFastForward KeyMediaRewind KeyMediaTrackNext KeyMediaTrackPrevious KeyMediaRecord KeyMediaVolumeDown KeyMediaVolumeUp KeyMediaMute )
The key types. KeyRunes carries printable input in Key.Text; the navigation, editing and function keys carry no runes. KeyCtrl is a generic ctrl+letter with the letter in Key.Code, and Ctrl+C is reported separately as KeyCtrlC. KeyUnknown is an escape sequence the reader consumed but does not recognise.
type Mod ¶
type Mod uint8
Mod is a bitmask of modifier keys held down alongside a Key.
Plain Ctrl+letter arrives from the terminal as its own control byte (e.g. Ctrl+A is literally byte 0x01) and is represented by KeyCtrl, not Mod — Mod exists for the keys that have no such direct byte encoding and are only distinguishable via an xterm CSI modifier parameter, chiefly Ctrl/Shift/Alt combined with arrows, Home/End, PgUp/PgDn, and Alt+rune.
const ( ModShift Mod = 1 << iota ModAlt ModCtrl // ModSuper is only ever set by the kitty keyboard protocol (see // parseCSIu) — no legacy xterm CSI-modifier sequence distinguishes it. ModSuper )
The modifier bits of a Mod, combined with |. ModSuper below is set only by the kitty keyboard protocol.
const ModNone Mod = 0
ModNone is the zero Mod: no modifier held.
type MouseAction ¶
type MouseAction int
MouseAction is what happened to MouseButton.
const ( MouseActionPress MouseAction = iota MouseActionRelease MouseActionMotion )
The mouse actions: a button pressed or released, or the pointer moved (a drag while a button is held, or free movement, depending on the tracking mode the Program enabled).
type MouseButton ¶
type MouseButton int
MouseButton identifies which mouse button (or wheel direction) a MouseEvent refers to.
const ( MouseButtonNone MouseButton = iota MouseButtonLeft MouseButtonMiddle MouseButtonRight MouseButtonWheelUp MouseButtonWheelDown MouseButtonWheelLeft MouseButtonWheelRight MouseButtonBack // SGR button 8 (Cb 128) MouseButtonForward // SGR button 9 (Cb 129) MouseButton10 // SGR button 10 (Cb 130) MouseButton11 // SGR button 11 (Cb 131) )
The mouse buttons. The wheel is reported as four buttons, one per direction, with MouseActionPress. Back, Forward, MouseButton10 and MouseButton11 are the extra buttons of SGR buttons 8-11.
type MouseEvent ¶
type MouseEvent struct {
X, Y int
Button MouseButton
Action MouseAction
Mod Mod
}
MouseEvent is a decoded SGR mouse report. X and Y are 0-indexed terminal cell coordinates.
type PaletteColorEvent ¶
PaletteColorEvent is the terminal's answer to an OSC 4 palette query (ansi.QueryPalette) for one colour, with each channel scaled to 8 bits.
func (PaletteColorEvent) PaletteColor ¶
func (e PaletteColorEvent) PaletteColor() (index, r, g, b uint8)
PaletteColor returns the slot and colour; theme.Palette.Observe looks for this method.
type PasteEvent ¶
type PasteEvent struct {
Text string
// Incomplete is true when the end marker never arrived: the stream went
// idle for PasteIdleTimeout or ended. Text is what was received.
Incomplete bool
// Truncated is true when the paste was longer than MaxPasteBytes. Text
// holds the first MaxPasteBytes bytes (never a partial character) and the
// rest, up to the end marker, was discarded.
Truncated bool
}
PasteEvent carries the full text of a bracketed paste (ESC[200~...ESC[201~), delivered as one event rather than as individual key presses.
type Reader ¶
type Reader struct {
// contains filtered or unexported fields
}
Reader decodes a raw byte stream (a terminal in raw mode) into Events.
Example ¶
A Reader turns the raw bytes of a terminal in raw mode into events. It is a pure decoder over an io.Reader, so it needs no TTY.
package main
import (
"fmt"
"strings"
"github.com/ows4444/tui/input"
)
func main() {
rd := input.NewReader(strings.NewReader("a\x1b[A\x1b[1;5C"))
for {
ev, err := rd.ReadEvent()
if err != nil {
break
}
fmt.Println(ev.(input.Key))
}
}
Output: a up ctrl+right
func NewReader ¶
NewReader wraps r, buffering reads for decoding. If r supports SetReadDeadline (an *os.File, net.Conn) the ESC timeout uses it; otherwise a single background peek is used, so any io.Reader works.
func (*Reader) EscTimeout ¶
EscTimeout reports the current ESC timeout.
func (*Reader) SetEscTimeout ¶
SetEscTimeout sets how long a lone ESC waits for a following byte. Zero or negative disables waiting (a bare ESC with nothing buffered is Escape).
Example ¶
package main
import (
"fmt"
"strings"
"github.com/ows4444/tui/input"
)
func main() {
rd := input.NewReader(strings.NewReader("\x1b"))
rd.SetEscTimeout(0) // a bare ESC with nothing buffered is Escape, with no wait
ev, _ := rd.ReadEvent()
fmt.Println(ev.(input.Key))
}
Output: esc
func (*Reader) SetReportCSIReplies ¶
SetReportCSIReplies chooses how a CSI reply to a terminal query (DA1 "ESC[?62;22c", DECRPM "ESC[?2026;1$y", a kitty keyboard flags answer "ESC[?0u", ...) is decoded. Off (the default) it is consumed as KeyUnknown. On it is a ReplyEvent with Kind '[' and Data the bytes between "ESC[" and the final byte inclusive (e.g. "?2026;1$y"). The capability probe turns it on; ordinary keys are unaffected either way.
func (*Reader) SetReportEvents ¶
SetReportEvents chooses how a kitty-protocol key event type is decoded. Off (the default), a key release decodes as KeyUnknown and a repeat as a plain press, exactly as before the option existed. On, they decode as the key itself with Key.Action set to KeyRelease or KeyRepeat.
type ReplyEvent ¶
ReplyEvent is a terminal string-sequence reply that is not otherwise decoded (a DCS XTGETTCAP answer, an APC kitty graphics answer, a non-11 OSC reply, ...). Kind is the introducer's final byte: ']' OSC, 'P' DCS, 'X' SOS, '^' PM, '_' APC. Data is the payload without introducer or terminator, truncated to 64 KiB.