input

package
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package input turns the bytes a terminal sends into events.

A terminal reports input as a stream that mixes plain text with escape sequences, and it splits that stream wherever the read happens to land: half a sequence in one read and half in the next is normal, not an error. Parser is therefore incremental — it is fed whatever arrived and returns whatever is now unambiguous.

Nothing here touches a terminal. The parser is a function of its bytes, which is what lets every sequence this package claims to understand be stated as a test.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Button

type Button uint8

Button identifies which mouse button an action belongs to.

const (
	// ButtonNone is the zero value, which is right for a bare move and for a
	// wheel: neither belongs to a button.
	ButtonNone Button = iota
	ButtonLeft
	ButtonMiddle
	ButtonRight
)

type Code

type Code int

Code identifies which key was pressed. Character means the key produced text, carried in Key.Rune.

const (
	// Character is the zero value, so a Key literal with only a rune in it is a
	// character press — which is what most of them are.
	Character Code = iota
	Enter
	Esc
	Backspace
	Tab
	Backtab
	Up
	Down
	Left
	Right
	Home
	End
	PageUp
	PageDown
	Delete
	Insert
	F1
	F2
	F3
	F4
	F5
	F6
	F7
	F8
	F9
	F10
	F11
	F12
)

func (Code) String

func (c Code) String() string

String names the key the way a help line would print it.

type Event

type Event interface {
	// contains filtered or unexported methods
}

Event is one thing the terminal reported. The set is closed by the unexported method: a consumer's switch over events is exhaustive by construction.

type FocusIn

type FocusIn struct{}

FocusIn reports that the terminal window took focus.

type FocusOut

type FocusOut struct{}

FocusOut reports that the terminal window lost focus.

type Handler

type Handler interface {
	Handle(ev Event) bool
}

Handler is anything that answers an event, reporting whether it consumed it.

It lives here for the same reason [grid.Drawer] lives with the view: the word belongs to the layer that owns the thing being handled. Everything further up that answers input says so by embedding this, so "consumed" means one thing across the whole repository rather than one thing per layer that happens to line up.

An unconsumed event carries on to whatever else might want it, which is how a key can mean one thing inside a text field and another outside it without either side knowing about the other.

type Key

type Key struct {
	Code Code
	Rune rune
	Mods Mods
	// Transition is Press unless the terminal speaks the Kitty keyboard protocol,
	// which is the only way repeats and releases are ever reported.
	Transition Transition
	// Text is what the key produced, when the terminal was able to say. It can
	// hold more than one code point, and is empty on terminals that do not report
	// it — Rune is the fallback and the common case.
	Text string
}

Key is a keyboard event.

A character key arrives as Character with the rune in Rune. Ctrl held with a letter also arrives as a character — the letter, lowercased, with Ctrl in Mods — because that is what the terminal actually sends and inventing a separate representation for it would mean two ways to ask the same question.

func (Key) Down

func (k Key) Down() bool

Down reports whether the key is going down — pressed or auto-repeating. Most handlers want this rather than Press alone, or holding a key stops working on terminals that report repeats.

func (Key) Is

func (k Key) Is(code Code, mods Mods) bool

Is reports whether the key is code with exactly mods held.

Exactly, not at least: a binding on Ctrl+C that also fired for Ctrl+Shift+C would swallow a keystroke its owner never claimed.

func (Key) IsRune

func (k Key) IsRune(r rune, mods Mods) bool

IsRune reports whether the key is the character r with exactly mods held.

func (Key) String

func (k Key) String() string

String names the keystroke the way a help line or a keybinding file writes it.

type Mods

type Mods uint8

Mods is the set of modifier keys held during an event.

const (
	Shift Mods = 1 << iota
	Alt
	Ctrl
	// Super is the platform's own modifier — Command on macOS, the Windows key
	// elsewhere. Only terminals speaking the Kitty keyboard protocol report it.
	Super
)

func (Mods) Has

func (m Mods) Has(want Mods) bool

Has reports whether every modifier in want is held.

func (Mods) String

func (m Mods) String() string

String names the modifiers in the order a keybinding is conventionally written.

type Mouse

type Mouse struct {
	Pos    image.Point
	Action MouseAction
	Button Button
	Mods   Mods
}

Mouse is a mouse event, positioned in cells with the origin at the top left.

type MouseAction

type MouseAction uint8

MouseAction is what the mouse did.

const (
	MouseDown MouseAction = iota
	MouseUp
	MouseDrag
	MouseMove
	WheelUp
	WheelDown
)

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

Parser decodes terminal bytes into events, incrementally.

Bytes are handed to Parser.Feed exactly as they arrived, at whatever boundaries the read produced. Anything not yet unambiguous stays buffered: escape sequences and multi-byte characters routinely arrive in pieces, and a decoder that assumed otherwise would drop keys under load.

One case cannot be resolved by waiting. A lone escape byte is either the Escape key or the start of a sequence whose remainder has not arrived, and only time tells the difference. Parser.Pending reports that something is waiting, and Parser.Flush declares the wait over.

Not safe for concurrent use: it belongs to whichever goroutine reads the terminal.

func (*Parser) Feed

func (p *Parser) Feed(b []byte) []Event

Feed adds bytes and returns everything now decodable.

func (*Parser) Flush

func (p *Parser) Flush() []Event

Flush resolves what only time could resolve and returns the result.

A buffered escape becomes the Escape key, and anything after it is re-read as ordinary input. A half-arrived character is dropped, since the rest is never coming. A paste in progress is left alone: it is incomplete rather than ambiguous, and cutting it short would corrupt the text.

func (*Parser) Pending

func (p *Parser) Pending() bool

Pending reports whether anything is waiting for more input to make sense of it: bytes that might yet become a sequence, or a runaway one still being dropped. It is what tells a loop to arm the timer that will call Parser.Flush, and the runaway counts because the state has to end somewhere — otherwise the next keystroke that happened to be a parameter byte would vanish into it.

type Paste

type Paste struct{ Text string }

Paste is a block of text the terminal delivered as a paste rather than as keystrokes, so it can be inserted whole instead of being interpreted a character at a time.

type Resize

type Resize struct{ Width, Height int }

Resize reports the terminal's new size in cells.

type Transition

type Transition uint8

Transition is what happened to a key.

const (
	// Press is the zero value: an ordinary terminal only ever reports presses,
	// and a Key literal that says nothing about its transition means one.
	Press Transition = iota
	Repeat
	Release
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL