daemon: legacy key encoding drops Ctrl from Space and Backspace and the case after Alt #157

Closed
opened 2026-10-18 12:41:50 +09:00 by natsukium · 0 comments
Owner

Reported on the GitHub mirror: https://github.com/felis-terminal/felis/issues/5

Problem

With no Kitty keyboard flag that turns on CSI u and modifyOtherKeys off, the legacy path in crates/felis-daemon/src/serve/key_encode.rs encode sends some modified keys differently from xterm and kitty:

Key felis xterm / kitty
Ctrl+Space 0x20 0x00
Ctrl+Backspace 0x7f 0x08
Alt+Shift+B (Key::Character("B")) ESC b ESC B
Ctrl+2 … Ctrl+8, Ctrl+/, Ctrl+? the plain text, or nothing 0x00, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x7f; / → 0x1f, ? → 0x7f

This is the GUI's own path, so felis users hit it: Emacs C-SPC (set-mark), readline M-B vs M-b, and a shell's Ctrl+Backspace word delete all receive a different key.

Cause

  • encode_named returns the bare byte for Space and Backspace without looking at Ctrl, and returns Some, so the Ctrl branch after it never runs.
  • The metaSendsEscape branch builds its body with single_ascii_lower, which exists for the Kitty keycode ("the lowercase ASCII codepoint of the key") and drops the case Shift produced.
  • ctrl_byte maps letters and @ [ \ ] ^ _ but no digits, / or ?.

Expected

The legacy path matches xterm for these, as it does for the rest:

  • Ctrl+Space → 0x00, Ctrl+Backspace → 0x08; Alt prefixes ESC as it does for the other named keys.
  • Alt+character keeps the character's case.
  • Ctrl+digit / punctuation follow xterm's table: 2 / @ / Space → 0x00, 3 / [ → 0x1b, 4 / \ → 0x1c, 5 / ] → 0x1d, 6 / ^ → 0x1e, 7 / _ / / → 0x1f, 8 / ? → 0x7f.

The modifyOtherKeys and Kitty paths already escape these keys and are unaffected. The legacy section of docs/reference/protocols/key-encoding.md should name the mapping once it is fixed.

Reported on the GitHub mirror: https://github.com/felis-terminal/felis/issues/5 ## Problem With no Kitty keyboard flag that turns on CSI u and modifyOtherKeys off, the legacy path in `crates/felis-daemon/src/serve/key_encode.rs` `encode` sends some modified keys differently from xterm and kitty: | Key | felis | xterm / kitty | | --- | --- | --- | | Ctrl+Space | `0x20` | `0x00` | | Ctrl+Backspace | `0x7f` | `0x08` | | Alt+Shift+B (`Key::Character("B")`) | `ESC b` | `ESC B` | | Ctrl+2 … Ctrl+8, Ctrl+/, Ctrl+? | the plain text, or nothing | `0x00`, `0x1b`, `0x1c`, `0x1d`, `0x1e`, `0x1f`, `0x7f`; `/` → `0x1f`, `?` → `0x7f` | This is the GUI's own path, so felis users hit it: Emacs `C-SPC` (set-mark), readline `M-B` vs `M-b`, and a shell's Ctrl+Backspace word delete all receive a different key. ## Cause - `encode_named` returns the bare byte for `Space` and `Backspace` without looking at Ctrl, and returns `Some`, so the Ctrl branch after it never runs. - The metaSendsEscape branch builds its body with `single_ascii_lower`, which exists for the Kitty keycode ("the lowercase ASCII codepoint of the key") and drops the case Shift produced. - `ctrl_byte` maps letters and `@ [ \ ] ^ _` but no digits, `/` or `?`. ## Expected The legacy path matches xterm for these, as it does for the rest: - Ctrl+Space → `0x00`, Ctrl+Backspace → `0x08`; Alt prefixes `ESC` as it does for the other named keys. - Alt+character keeps the character's case. - Ctrl+digit / punctuation follow xterm's table: `2` / `@` / Space → `0x00`, `3` / `[` → `0x1b`, `4` / `\` → `0x1c`, `5` / `]` → `0x1d`, `6` / `^` → `0x1e`, `7` / `_` / `/` → `0x1f`, `8` / `?` → `0x7f`. The modifyOtherKeys and Kitty paths already escape these keys and are unaffected. The legacy section of `docs/reference/protocols/key-encoding.md` should name the mapping once it is fixed.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
felis-terminal/felis#157
No description provided.