struct

TermBuf::Input::Key

Inherits Struct < Value < Object

One key press.

A key is a value: it says which key, which modifiers, and for an ordinary character which character. What the terminal sent to say so is on the Events::Key that carries it, since two terminals can send different bytes for the same key and an application should not have to care.

Modifiers are only as good as the terminal's encoding. Ctrl with a letter arrives as one control byte, so Ctrl+I and Tab are the same key press and nothing downstream can separate them. Terminals implementing the kitty keyboard protocol can, which is why that protocol exists.

Constructors

character(char : Char, modifiers : Modifiers = Modifiers::None) : Key

An ordinary character key.

Source
from_control(byte : UInt8) : Key

The key a C0 control byte is.

There is one table and this is it: Decoder reads a control byte by asking here, so what a binding table is written against and what an application is handed cannot drift apart.

Several of these bytes are two keys wearing one byte. Ctrl+I and Tab are both 0x09, Ctrl+M and Enter are both 0x0D, and no amount of care here separates them: it takes a terminal speaking the kitty keyboard protocol, which reports the key and the modifier apart.

Source
named(name : Name, modifiers : Modifiers = Modifiers::None) : Key

A named key.

Source
new(name : Name, char : Char = '\0', modifiers : Modifiers = Modifiers::None)
Source
parse_one(text : String) : Key

One key description, as .parse reads them.

Ctrl with a character is a single C0 control byte on the wire, and several of those bytes are a named key: no terminal can tell Ctrl+I from Tab, so both have to become the key the decoder emits for 0x09. That gives Ctrl+I => Tab, Ctrl+M and Ctrl+J => Enter, and Ctrl+[ => Escape, each keeping whatever else was held down.

Ctrl+H is the one that keeps its modifier. 0x08 reaches the decoder as Ctrl+Backspace and 0x7F as a bare Backspace, because a keyboard with both keys sends the two bytes and an application is entitled to bind them apart; stripping the Ctrl would fold the two together.

The same rule settles case, since Ctrl+A and Ctrl+a are one byte and the decoder calls it lower case.

Source

Class methods

parse(text : String) : Array(Key)

Reads back what #to_s writes: a space separated sequence of key descriptions.

Each description is zero or more of the prefixes Ctrl+, Alt+, Shift+ and Super+, in any order and any case, followed by a Name label, the Space or Nul label, or a single character. A space is an unambiguous separator because the space key is written Space, so "Ctrl+X s" is two keys and "Ctrl+Space" is one.

Descriptions are normalised to what Decoder emits for the same key press, so a binding table built from text matches the keys an application is handed. See .parse_one.

A string of nothing but whitespace is an empty sequence; an empty description is an ArgumentError, as is an unknown name, a trailing modifier, and anything longer than one character that is not a name.

Source

Instance methods

alt?

Whether alt was held.

Source
char

The character pressed, for a Character key. '\0' for anything else.

Source
character?

Whether this is an ordinary character rather than a named key.

Source
ctrl?

Whether control was held.

Source
is?(char : Char) : Bool

Whether this is char with no modifiers but shift, which is what asking "did they type a q" means.

Source
is?(name : Name) : Bool

Whether this is the named key, whatever was held down with it.

Source
modifiers

What was held down with it.

Source
name

Which key, with Name::Character meaning the one in #char.

Source
shift?

Whether shift was held.

Source
super?

Whether the windows, command, or meta key was held.

Source
to_s(io : IO) : Nil

A form suited to a key binding table: Ctrl+C, Alt+Up, Shift+F5.

Source

Nested types