keyboard.py

Sub-module providing ‘keyboard awareness’.

class Keystroke(ucs: str = '', code: int | None = None, name: str | None = None, mode: int | None = None, match: Any = None)[source]

A unicode-derived class for describing a single “keystroke”.

A class instance describes a single keystroke received on input, which may contain multiple characters as a multibyte sequence, which is indicated by properties is_sequence returning True. Note that keystrokes may also represent mouse input, bracketed paste, or focus in/out events depending on enabled terminal modes.

The string name of the sequence is used to identify in code logic, such as 'KEY_LEFT' to represent a common and human-readable form of the Keystroke this class instance represents.

Class constructor.

_name: str | None = None
_code: int | None = None
_mode: int | None = None
_match: Any = None
_modifiers: int = 1
static __new__(cls: Type[_T], ucs: str = '', code: int | None = None, name: str | None = None, mode: int | None = None, match: Any = None) _T[source]

Class constructor.

static _infer_modifiers(ucs: str, mode: int | None, match: Any) int[source]

Infer modifiers from keystroke data.

Returns modifiers in standard format: 1 + bitwise OR of modifier flags.

property is_sequence: bool

Whether the value represents a multibyte sequence (bool).

_get_modified_keycode_name() str | None[source]

Get base name for modern/legacy CSI sequence with modifiers.

Returns name like ‘KEY_CTRL_ALT_F1’ or ‘KEY_SHIFT_UP’ without event-type suffix. The suffix is applied by name.

_get_kitty_protocol_name() str | None[source]

Get base name for Kitty keyboard protocol letter/digit/symbol.

Returns name like ‘KEY_CTRL_ALT_A’, ‘KEY_ALT_SHIFT_5’, ‘KEY_LEFT_SQUARE_BRACKET’ without event-type suffix. The suffix is applied by name.

_get_control_char_name() str | None[source]

Get name for single-character control sequences.

Returns name like ‘KEY_CTRL_A’ or ‘KEY_CTRL_SPACE’.

_get_control_symbol(char_code: int) str[source]

Get control symbol for a character code.

Returns symbol like ‘A’ for Ctrl+A, ‘SPACE’ for Ctrl+Space, ‘BACKSPACE’ for Ctrl+H, etc.

_get_alt_only_control_name(char_code: int) str | None[source]

Get name for Alt-only special control characters.

Returns names like ‘KEY_ALT_ESCAPE’, ‘KEY_ALT_BACKSPACE’, etc.

_get_meta_escape_name() str | None[source]

Get name for metaSendsEscape sequences (ESC + char).

Returns name like ‘KEY_ALT_A’, ‘KEY_ALT_SHIFT_Z’, ‘KEY_CTRL_ALT_C’, or ‘KEY_ALT_ESCAPE’.

_get_mouse_event_name() str | None[source]

Get name for mouse events.

Returns name like ‘MOUSE_LEFT’, ‘MOUSE_CTRL_LEFT’, ‘MOUSE_SCROLL_UP’, ‘MOUSE_LEFT_RELEASED’, ‘MOUSE_MOTION’, ‘MOUSE_RIGHT_MOTION’, etc.

_get_focus_event_name() str | None[source]

Get name for focus events.

Returns ‘FOCUS_IN’ or ‘FOCUS_OUT’.

_get_bracketed_paste_name() str | None[source]

Get name for bracketed paste events.

Returns ‘BRACKETED_PASTE’.

_resolve_name() str | None[source]

Resolve key name without event-type suffix.

Shared by name and key_name. The two keyboard protocol helpers (_get_modified_keycode_name, _get_kitty_protocol_name) return the base name only; name appends the suffix.

property name: str | None

Special application key name.

This is the best equality attribute to use for special keys, as raw string value of the ‘F1’ key can be received in many different values.

The ‘name’ property will return a reliable constant, eg. 'KEY_F1'.

The name supports “modifiers”, such as 'KEY_CTRL_F1', 'KEY_CTRL_ALT_F1', 'KEY_CTRL_ALT_SHIFT_F1'

When using a keyboard protocol with event reporting, names include an event-type suffix: 'KEY_CTRL_J_REPEATED' for repeat and 'KEY_CTRL_J_RELEASED' for release events. Press events have no suffix. See key_name for the same name without the suffix.

For mouse events, the name includes the 'MOUSE_' prefix followed by the button/action name, such as 'MOUSE_LEFT', 'MOUSE_MOTION', 'MOUSE_RIGHT_MOTION', 'MOUSE_LEFT_RELEASED'.

For other DEC events:

  • Focus events: ‘FOCUS_IN’ or ‘FOCUS_OUT’

  • Bracketed paste: ‘BRACKETED_PASTE’

  • Resize events: ‘RESIZE_EVENT’

For terminal query responses:

  • Cursor position report: ‘CPR_RESPONSE’ (row >= 2 only; row 1 is ambiguous with F3+modifier)

When non-None, all phrases begin with either ‘KEY’, ‘MOUSE’, ‘FOCUS_IN’, ‘FOCUS_OUT’, ‘BRACKETED_PASTE’, or ‘RESIZE_EVENT’, with one exception: ‘CSI’ is returned for ‘\x1b[’ in legacy (non-kitty-protocol) mode to indicate the beginning of a presumed unsupported input sequence. In kitty keyboard protocol mode, the ‘[’ key uses the name ‘KEY_LEFT_SQUARE_BRACKET’ (with modifier and event-type suffixes as appropriate).

If this value is None, then it can probably be assumed that the value is an unsurprising textual character without any modifiers, like the letter 'a'.

property key_name: str | None

Key identity without event-type suffix.

Like name, but without _RELEASED and _REPEATED suffixes, so that press, repeat, and release events for the same key all return the same value. Useful for key-map lookups when tracking press/release pairs.

Return type:

str or None

property code: int | None

Legacy curses-alike keycode value (int).

property modifiers: int

Modifier flags in standard keyboard protocol format.

Return type:

int

Returns:

Standard-style modifiers value (1 means no modifiers)

The value is 1 + bitwise OR of modifier flags:

  • shift: 0b1 (1)

  • alt: 0b10 (2)

  • ctrl: 0b100 (4)

  • super: 0b1000 (8)

  • hyper: 0b10000 (16)

  • meta: 0b100000 (32)

  • caps_lock: 0b1000000 (64)

  • num_lock: 0b10000000 (128)

property modifiers_bits: int

Raw modifier bit flags without the +1 offset.

Return type:

int

Returns:

Raw bitwise OR of modifier flags (0 means no modifiers)

property _shift: bool

Whether the shift modifier is active.

property _alt: bool

Whether the alt modifier is active.

property _ctrl: bool

Whether the ctrl modifier is active.

property _super: bool

Whether the super (Windows/Cmd) modifier is active.

property _hyper: bool

Whether the hyper modifier is active.

property _meta: bool

Whether the meta modifier is active.

property _caps_lock: bool

Whether caps lock was known to be active during this sequence.

property _num_lock: bool

Whether num lock was known to be active during this sequence.

property uses_keyboard_protocol: bool

Whether this keystroke uses a special keyboard protocol mode.

Returns True for Kitty, ModifyOtherKeys, or LegacyCSIModifier protocols, which use negative mode values (SpecialInternalKitty=-1, SpecialInternalModifyOtherKeys=-2, SpecialInternalLegacyCSIModifier=-3).

Return type:

bool

Returns:

True if using special keyboard protocol mode

property pressed: bool

Whether this is a key press event.

Return type:

bool

Returns:

True if this is a key press event (event_type=1 or not specified), False for repeat or release events

property repeated: bool

Whether this is a key repeat event.

Return type:

bool

Returns:

True if this is a key repeat event (event_type=2), False otherwise

property released: bool

Whether this is a key release event.

Return type:

bool

Returns:

True if this is a key release event (event_type=3), False otherwise

_is_escape_sequence(length: int = 2) bool[source]

Check if keystroke is an escape sequence of given length.

Parameters:

length (int) – Expected length of escape sequence (default 2)

Return type:

bool

Returns:

True if keystroke matches ESC + (length-1) chars pattern

static _make_expected_bits(tokens_modifiers: List[str]) int[source]

Build expected modifier bits from token list.

_make_effective_bits() int[source]

Returns modifier bits stripped of caps_lock and num_lock.

static _get_keycode_by_name(key_name: str) int | None[source]

Get keycode value for a given key name.

_build_appkeys_predicate(tokens_modifiers: List[str], key_name: str, event_type: str | None = None) Callable[[str | None, bool], bool][source]

Build a predicate function for application keys.

_build_alphanum_predicate(tokens_modifiers: List[str]) Callable[[str | None, bool], bool][source]

Build a predicate function for modifier checking of alphanumeric input.

_get_plain_char_value() str | None[source]

Get value for plain printable characters.

Returns the character as-is if it’s a single printable character.

_get_escape_sequence_value() str | None[source]

Get value for ESC+char sequences (Alt, Ctrl+Alt combinations).

Handles Alt+printable, Alt-only special keys, and Ctrl+Alt sequences. Returns the base character or empty string for application keys.

_get_ctrl_sequence_value() str | None[source]

Get value for Ctrl+char sequences.

Maps control characters back to their base characters.

_get_protocol_value() str | None[source]

Get value for Kitty or ModifyOtherKeys protocol sequences.

Extracts the character from modern keyboard protocols.

_get_ascii_value() str | None[source]

Get value for keys matched by curses-imitated keycodes.

property value: str

The textual character represented by this keystroke.

Return type:

str

Returns:

For text keys, returns the base character (ignoring modifiers). For application keys and sequences, returns empty string ‘’. For release events, always returns empty string.

Some Examples,

  • Plain text: ‘a’, ‘A’, ‘1’, ‘;’, ‘ ‘, ‘Ω’, emoji with ZWJ sequences

  • Alt+printable: Alt+a -> ‘a’, Alt+A -> ‘A’

  • Ctrl+letter: Ctrl+A -> ‘a’, Ctrl+Z -> ‘z’

  • Ctrl+symbol: Ctrl+@ -> ‘@’, Ctrl+? -> ‘?’, Ctrl+[ → ‘[’

  • Control chars: ‘t’, ‘n’, ‘x08’, ‘x1b’ (for Enter/Tab/Backspace/Escape keycodes)

  • Application keys: KEY_UP, KEY_F1, etc. → ‘’

  • Release events: always -> ‘’

property key_value: str

Character for this key, even for release events.

Like value, but does not suppress the character for release events. For press and repeat events, identical to value.

Return type:

str

property mode: DecPrivateMode | None

DEC Private Mode associated with this keystroke, if any.

Return type:

blessed.dec_modes.DecPrivateMode or None

Returns:

The DecPrivateMode enum value associated with this keystroke, or None if this is not a DEC mode event.

Note

Mode names beginning SpecialInternal with negative values (-1, -2, -3) are used to track how some kinds of application keys are matched.

property mouse_yx: Tuple[int, int]

Mouse position as (y, x) tuple for mouse events.

This is particularly useful with terminal movement functions: term.move_yx(*keystroke.mouse_yx)

Return type:

tuple of (int, int)

Returns:

(y, x) coordinate tuple (0-indexed) for mouse events, or (-1, -1) if not a mouse event

property mouse_xy: Tuple[int, int]

Mouse position as (x, y) tuple for mouse events.

Return type:

tuple of (int, int)

Returns:

(x, y) coordinate tuple (0-indexed) for mouse events, or (-1, -1) if not a mouse event

property cpr_yx: Tuple[int, int]

Cursor position as (y, x) tuple for Cursor Position Report.

Return type:

tuple of (int, int)

Returns:

(y, x) coordinate tuple (0-indexed) for cursor position report, or (-1, -1) if not a CPR_RESPONSE

property cpr_xy: Tuple[int, int]

Cursor position as (x, y) tuple for Cursor Position Report.

Return type:

tuple of (int, int)

Returns:

(x, y) coordinate tuple (0-indexed) for cursor position report, or (-1, -1) if not a CPR_RESPONSE

property text: str | None

Pasted text for bracketed paste events.

Return type:

str or None

Returns:

The pasted text for BRACKETED_PASTE events, or None if not a bracketed paste event

property _mode_values: BracketedPasteEvent | MouseEvent | FocusEvent | ResizeEvent | None

Return structured data for DEC private mode events (private API).

Returns a namedtuple with parsed event data for supported DecPrivateMode modes:

  • BRACKETED_PASTE: BracketedPasteEvent with text field

  • MOUSE_EXTENDED_SGR, MOUSE_ALL_MOTION, MOUSE_REPORT_DRAG, and MOUSE_REPORT_CLICK events: MouseEvent with button, coordinates, and modifier flags

  • FOCUS_IN_OUT_EVENTS: FocusEvent with gained boolean field

  • IN_BAND_WINDOW_RESIZE: ResizeEvent with dimension fields

Return type:

namedtuple or None

Returns:

Structured event data for this DEC mode event, or None if this keystroke is not a DEC mode event or the mode is not supported

_parse_focus() FocusEvent[source]

Parse focus event from stored regex match.

_parse_bracketed_paste() BracketedPasteEvent[source]

Parse bracketed paste event from stored regex match.

_parse_resize() ResizeEvent[source]

Parse resize event from stored regex match.

get_keyboard_codes() Dict[int, str][source]

Return mapping of keycode integer values paired by their curses key name.

Return type:

dict

Returns:

Dictionary of (code, name) pairs for curses keyboard constant values and their mnemonic name. Such as key 260, with the value of its identity, 'KEY_LEFT'.

These keys are derived from the attributes by the same of the curses(jinxed) module, with the following exceptions:

  • KEY_DELETE in place of KEY_DC

  • KEY_INSERT in place of KEY_IC

  • KEY_PGUP in place of KEY_PPAGE

  • KEY_PGDOWN in place of KEY_NPAGE

  • KEY_ESCAPE in place of KEY_EXIT

  • KEY_SUP in place of KEY_SR

  • KEY_SDOWN in place of KEY_SF

This function is the inverse of get_curses_keycodes(). With the given override “mixins” listed above, the keycode for the delete key will map to our imaginary KEY_DELETE mnemonic, effectively erasing the phrase KEY_DC from our code vocabulary for anyone that wishes to use the return value to determine the key-name by keycode.

get_keyboard_sequences(term: Terminal) OrderedDict[str, int][source]

Return mapping of keyboard sequences paired by keycodes.

Parameters:

term (blessed.Terminal) – Terminal instance.

Returns:

mapping of keyboard unicode sequences paired by keycodes as integer. This is used as the argument mapper to the supporting function resolve_sequence().

Return type:

OrderedDict

Initialize and return a keyboard map and sequence lookup table, (sequence, keycode) from Terminal instance term, where sequence is a multibyte input sequence of unicode characters, such as '\x1b[D', and keycode is an integer value, matching curses constant such as term.KEY_LEFT.

The return value is an OrderedDict instance, with their keys sorted longest-first.

class KittyKeyEvent(unicode_key, shifted_key, base_key, modifiers, event_type, int_codepoints)

Create new instance of KittyKeyEvent(unicode_key, shifted_key, base_key, modifiers, event_type, int_codepoints)

static __new__(_cls, unicode_key, shifted_key, base_key, modifiers, event_type, int_codepoints)

Create new instance of KittyKeyEvent(unicode_key, shifted_key, base_key, modifiers, event_type, int_codepoints)

_asdict()

Return a new dict which maps field names to their values.

_field_defaults = {}
_fields = ('unicode_key', 'shifted_key', 'base_key', 'modifiers', 'event_type', 'int_codepoints')
classmethod _make(iterable)

Make a new KittyKeyEvent object from a sequence or iterable

_replace(**kwds)

Return a new KittyKeyEvent object replacing specified fields with new values

base_key

Alias for field number 2

event_type

Alias for field number 4

int_codepoints

Alias for field number 5

modifiers

Alias for field number 3

shifted_key

Alias for field number 1

unicode_key

Alias for field number 0

class ModifyOtherKeysEvent(key, modifiers)

Create new instance of ModifyOtherKeysEvent(key, modifiers)

static __new__(_cls, key, modifiers)

Create new instance of ModifyOtherKeysEvent(key, modifiers)

_asdict()

Return a new dict which maps field names to their values.

_field_defaults = {}
_fields = ('key', 'modifiers')
classmethod _make(iterable)

Make a new ModifyOtherKeysEvent object from a sequence or iterable

_replace(**kwds)

Return a new ModifyOtherKeysEvent object replacing specified fields with new values

key

Alias for field number 0

modifiers

Alias for field number 1

class LegacyCSIKeyEvent(kind, key_id, modifiers, event_type)

Create new instance of LegacyCSIKeyEvent(kind, key_id, modifiers, event_type)

static __new__(_cls, kind, key_id, modifiers, event_type)

Create new instance of LegacyCSIKeyEvent(kind, key_id, modifiers, event_type)

_asdict()

Return a new dict which maps field names to their values.

_field_defaults = {}
_fields = ('kind', 'key_id', 'modifiers', 'event_type')
classmethod _make(iterable)

Make a new LegacyCSIKeyEvent object from a sequence or iterable

_replace(**kwds)

Return a new LegacyCSIKeyEvent object replacing specified fields with new values

event_type

Alias for field number 3

key_id

Alias for field number 1

kind

Alias for field number 0

modifiers

Alias for field number 2

class KittyKeyboardProtocol(value: int)[source]

Represents Kitty keyboard protocol flags.

Encapsulates the integer flag value returned by Kitty keyboard protocol queries and provides properties for individual flag bits and a method to convert back to enable_kitty_keyboard() arguments.

Initialize with raw integer flag value.

Parameters:

value (int) – Raw integer flags value from Kitty keyboard protocol query

property disambiguate: bool

Whether disambiguated escape codes are enabled (bit 1).

property report_events: bool

Whether key repeat and release events are reported (bit 2).

property report_alternates: bool

Whether shifted and base layout keys are reported for shortcuts (bit 4).

property report_all_keys: bool

Whether all keys are reported as escape codes (bit 8).

property report_text: bool

Whether associated text is reported with key events (bit 16).

make_arguments() Dict[str, bool][source]

Return dictionary of arguments suitable for enable_kitty_keyboard().

Return type:

dict

Returns:

Dictionary with boolean flags suitable for passing as keyword arguments to enable_kitty_keyboard()

class DeviceAttribute(raw: str, service_class: int, extensions: List[int] | None)[source]

Represents a terminal’s Device Attributes (DA1) response.

Device Attributes queries allow discovering terminal capabilities and type. The primary DA1 query sends CSI c and expects a response like:

CSI ? Psc ; Ps1 ; Ps2 ; ... ; Psn c

Where Psc is the service class (architectural class) and Ps1…Psn are supported extensions/capabilities.

Initialize DeviceAttribute instance.

Parameters:
  • raw (str) – Original response string from terminal

  • service_class (int) – Service class number (first parameter)

  • extensions (list) – List of extension numbers (remaining parameters)

RE_RESPONSE = re.compile('\\x1b\\[\\?([0-9]+)((?:;[0-9]+)*)c')
property supports_sixel: bool

Whether the terminal supports sixel graphics.

Return type:

bool

Returns:

True if extension 4 (sixel) is present in device attributes

property supports_osc52: bool

Whether the terminal advertises OSC 52 clipboard support.

Extension 52 in DA1 indicates the terminal supports writing to the system clipboard via the OSC 52 protocol.

Return type:

bool

Returns:

True if extension 52 is present in device attributes

classmethod from_match(match: Match[str]) DeviceAttribute[source]

Create DeviceAttribute from regex match object.

Parameters:

match (re.Match) – Regex match object with groups for service_class and extensions

Return type:

DeviceAttribute

Returns:

DeviceAttribute instance parsed from match

class SoftwareVersion(raw: str, name: str, version: str)[source]

Represents a terminal’s software name and version from XTVERSION response.

Initialize SoftwareVersion instance.

Parameters:
  • raw (str) – Original response string from terminal

  • name (str) – Software name (e.g., “kitty”, “XTerm”)

  • version (str) – Version string (e.g., “0.24.2”, “367”) or empty string if no version

RE_RESPONSE = re.compile('\\x1bP>\\|(.+?)\\x1b\\\\')
classmethod from_match(match: Match[str]) SoftwareVersion[source]

Create SoftwareVersion from regex match object.

Parameters:

match (re.Match) – Regex match object with group for software text

Return type:

SoftwareVersion

Returns:

SoftwareVersion instance parsed from match

static _parse_text(text: str) Tuple[str, str][source]

Parse software name and version from text.

Parsing logic (in order): 1. Check for space-separated format: “tmux 3.2a” or “X.Org 7.7.0(370)” 2. Check for parentheses format: “kitty(0.24.2)” 3. Name-only format: “software” (version is empty string)

Parameters:

text (str) – Text from XTVERSION response

Return type:

tuple

Returns:

Tuple of (name, version) where both are strings

class BracketedPasteEvent(text)

Create new instance of BracketedPasteEvent(text,)

static __new__(_cls, text)

Create new instance of BracketedPasteEvent(text,)

_asdict()

Return a new dict which maps field names to their values.

_field_defaults = {}
_fields = ('text',)
classmethod _make(iterable)

Make a new BracketedPasteEvent object from a sequence or iterable

_replace(**kwds)

Return a new BracketedPasteEvent object replacing specified fields with new values

text

Alias for field number 0

class FocusEvent(gained)

Create new instance of FocusEvent(gained,)

static __new__(_cls, gained)

Create new instance of FocusEvent(gained,)

_asdict()

Return a new dict which maps field names to their values.

_field_defaults = {}
_fields = ('gained',)
classmethod _make(iterable)

Make a new FocusEvent object from a sequence or iterable

_replace(**kwds)

Return a new FocusEvent object replacing specified fields with new values

gained

Alias for field number 0

class SyncEvent(begin)

Create new instance of SyncEvent(begin,)

static __new__(_cls, begin)

Create new instance of SyncEvent(begin,)

_asdict()

Return a new dict which maps field names to their values.

_field_defaults = {}
_fields = ('begin',)
classmethod _make(iterable)

Make a new SyncEvent object from a sequence or iterable

_replace(**kwds)

Return a new SyncEvent object replacing specified fields with new values

begin

Alias for field number 0

DEFAULT_SEQUENCE_MIXIN = (('\n', 343), ('\r', 343), ('\x08', 263), ('\t', 512), ('\x1b', 361), ('\x7f', 263), ('\x1b[A', 259), ('\x1b[B', 258), ('\x1b[C', 261), ('\x1b[D', 260), ('\x1b[E', 350), ('\x1b[1;2A', 337), ('\x1b[1;2B', 336), ('\x1b[1;2C', 402), ('\x1b[1;2D', 393), ('\x1b[F', 360), ('\x1b[H', 262), ('\x1b[K', 360), ('\x1b[U', 338), ('\x1b[V', 339), ('\x1bOM', 343), ('\x1bOj', 513), ('\x1bOk', 514), ('\x1bOl', 515), ('\x1bOm', 516), ('\x1bOn', 517), ('\x1bOo', 518), ('\x1bOX', 519), ('\x1bOp', 520), ('\x1bOq', 521), ('\x1bOr', 522), ('\x1bOs', 523), ('\x1bOt', 524), ('\x1bOu', 525), ('\x1bOv', 526), ('\x1bOw', 527), ('\x1bOx', 528), ('\x1bOy', 529), ('\x1b[1~', 262), ('\x1b[2~', 331), ('\x1b[3~', 330), ('\x1b[4~', 360), ('\x1b[5~', 339), ('\x1b[6~', 338), ('\x1b[7~', 262), ('\x1b[8~', 360), ('\x1b[OA', 259), ('\x1b[OB', 258), ('\x1b[OC', 261), ('\x1b[OD', 260), ('\x1b[OF', 360), ('\x1b[OH', 262), ('\x1bOP', 265), ('\x1bOQ', 266), ('\x1bOR', 267), ('\x1bOS', 268), ('\x1b[P', 265), ('\x1b[Q', 266), ('\x1b[13~', 267), ('\x1b[S', 268))

In a perfect world, terminal emulators would always send exactly what the terminfo(5) capability database plans for them, accordingly by the value of the TERM name they declare.

But this isn’t a perfect world. Many vt220-derived terminals, such as those declaring ‘xterm’, will continue to send vt220 codes instead of their native-declared codes, for backwards-compatibility.

This goes for many: rxvt, putty, iTerm.

These “mixins” are used for all terminals, regardless of their type.

Furthermore, curses does not provide sequences sent by the keypad, at least, it does not provide a way to distinguish between keypad 0 and numeric 0.

CURSES_KEYCODE_OVERRIDE_MIXIN = (('KEY_DELETE', 330), ('KEY_INSERT', 331), ('KEY_PGUP', 339), ('KEY_PGDOWN', 338), ('KEY_ESCAPE', 361), ('KEY_SUP', 337), ('KEY_SDOWN', 336), ('KEY_UP_LEFT', 348), ('KEY_UP_RIGHT', 349), ('KEY_CENTER', 350), ('KEY_BEGIN', 354), ('KEY_DOWN_LEFT', 351), ('KEY_DOWN_RIGHT', 352))

Override mixins for a few curses constants with easier mnemonics: there may only be a 1:1 mapping when only a keycode (int) is given, where these phrases are preferred.