From d9e0258750e6c8b943bd91e8bc8f65ce58d8055e Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Tue, 28 Nov 2023 12:56:20 +0000 Subject: [PATCH] Simplify some sequences that seem unique to rxvt Almost(?) all other terminals I've tested, shifted numeric keypad keys just yield the unshifted version of that key. rxvt seems to have sequences for those keys. Much like #3737 and #3739 we *could* add support for these sequences to the ANSI sequence list, but this is a bit different. Whereas in those other PRs we've been adding the alternate sequences that rxvt seems to have for well known and well-supported keys, here it would be the other way round: it would be adding bindable keys that are only available on a small subset of environments. Ideally, at least for the moment, we want to encourage people to bind keys that are well-supported; so here we turn the shifted keypad keys into their unshifted counterparts, thus matching many other environments. See #3741 --- src/textual/_ansi_sequences.py | 19 ++++++++++++++++++- src/textual/_xterm_parser.py | 14 ++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/textual/_ansi_sequences.py b/src/textual/_ansi_sequences.py index 13280943a9..38508b479c 100644 --- a/src/textual/_ansi_sequences.py +++ b/src/textual/_ansi_sequences.py @@ -1,9 +1,11 @@ +from __future__ import annotations + from typing import Mapping, Tuple from .keys import Keys # Mapping of vt100 escape codes to Keys. -ANSI_SEQUENCES_KEYS: Mapping[str, Tuple[Keys, ...]] = { +ANSI_SEQUENCES_KEYS: Mapping[str, Tuple[Keys, ...] | str] = { # Control keys. " ": (Keys.Space,), "\r": (Keys.Enter,), @@ -326,6 +328,21 @@ "\x1b[1;8w": (Keys.Escape, Keys.ControlShift7), "\x1b[1;8x": (Keys.Escape, Keys.ControlShift8), "\x1b[1;8y": (Keys.Escape, Keys.ControlShift9), + # Simplify some sequences that appear to be unique to rxvt; see + # https://github.com/Textualize/textual/issues/3741 for context. + "\x1bOj": "*", + "\x1bOk": "+", + "\x1bOm": "-", + "\x1bOo": "/", + "\x1bOq": "1", + "\x1bOr": "2", + "\x1bOs": "3", + "\x1bOt": "4", + "\x1bOu": "5", + "\x1bOv": "6", + "\x1bOw": "7", + "\x1bOx": "8", + "\x1bOy": "9", } # https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036 diff --git a/src/textual/_xterm_parser.py b/src/textual/_xterm_parser.py index d3653dc3d5..1b2b47a64f 100644 --- a/src/textual/_xterm_parser.py +++ b/src/textual/_xterm_parser.py @@ -243,10 +243,20 @@ def _sequence_to_key_events( Keys """ keys = ANSI_SEQUENCES_KEYS.get(sequence) - if keys is not None: + if isinstance(keys, tuple): + # If the sequence mapped to a tuple, then it's values from the + # `Keys` enum. Raise key events from what we find in the tuple. for key in keys: yield events.Key(key.value, sequence if len(sequence) == 1 else None) - elif len(sequence) == 1: + return + # If keys is a string, the intention is that it's a mapping to a + # character, which should really be treated as the sequence for the + # purposes of the next step... + if isinstance(keys, str): + sequence = keys + # If the sequence is a single character, attempt to process it as a + # key. + if len(sequence) == 1: try: if not sequence.isalnum(): name = _character_to_key(sequence)