Drafter.Terminal.KittyKeyboard (drafter v0.4.0)

Copy Markdown View Source

The kitty keyboard protocol: the sequences that switch it on and off, and the parsing of the key reports a terminal sends while it is on.

push/0 asks for disambiguated escape codes, press/repeat/release event types, every key as an escape code, and the text a key produces. pop/0 restores the mode that was in force before. query/0 asks for the current flags; a terminal that speaks the protocol answers CSI ? flags u, one that does not stays silent.

parse/1 turns one report into events for Drafter.Terminal.ANSI:

  • a press yields the same {:key, ...} or {:char, ...} event the legacy encoding would have produced, followed by {:key_down, key, modifiers}
  • a repeat yields the legacy event only
  • a release yields {:key_up, key, modifiers}
  • the reply to query/0 yields {:key_release_support, true} when the flags in force include event types, so releases will be reported, and {:key_release_support, false} when they do not — a terminal that speaks the protocol but took only some of what push/0 asked for

key in :key_down and :key_up is the unshifted key: :a for both a and A, :"1" for both 1 and !, a name such as :left_shift or :kp_5 for a key with no glyph, and an integer codepoint for a glyph outside ASCII. modifiers is the [:ctrl, :alt, :shift] subset held, in that order, and may be empty. Caps lock and num lock are not modifiers. Keys with no glyph produce no legacy event unless the terminal reported text for them.

Summary

Functions

The {:key_down, key, modifiers} event matching a legacy key press.

Parse one report at the head of buffer.

The sequence that turns it off again.

The sequence that turns the protocol on for the running program.

The sequence that asks the terminal whether it speaks the protocol.

Types

event()

@type event() ::
  Drafter.Terminal.ANSI.event()
  | {:key_down, key(), Drafter.Terminal.ANSI.modifiers()}
  | {:key_up, key(), Drafter.Terminal.ANSI.modifiers()}
  | {:key_release_support, boolean()}

key()

@type key() :: atom() | non_neg_integer()

Functions

key_down(arg)

@spec key_down({:key, atom()} | {:key, atom(), Drafter.Terminal.ANSI.modifiers()}) ::
  {:key_down, key(), Drafter.Terminal.ANSI.modifiers()}

The {:key_down, key, modifiers} event matching a legacy key press.

Used while the protocol is on for the keys a terminal still reports in their legacy encoding, so every press has a :key_down whichever encoding it arrived in.

parse(buffer, key_release \\ false)

@spec parse(binary(), boolean()) :: {[event()], binary()} | :no_match

Parse one report at the head of buffer.

Returns the events it produced and the bytes after it, or :no_match when the buffer does not begin with a report this module reads. A report whose final byte has not arrived is :no_match as well; Drafter.Terminal.ANSI holds those back before asking.

With key_release false, only reports the legacy encodings cannot produce are read: a u final, or an event type or alternate key after a colon. With it true every CSI key report is read, including the legacy forms, each press gaining its :key_down.

pop()

@spec pop() :: String.t()

The sequence that turns it off again.

push()

@spec push() :: String.t()

The sequence that turns the protocol on for the running program.

query()

@spec query() :: String.t()

The sequence that asks the terminal whether it speaks the protocol.