Skip to content

Kitty keyboard: caps_lock/num_lock + lock-key events blocked on upstream (egui/winit) #380

Description

@fredclausen

Summary

The kitty keyboard protocol asks a terminal to, for the lock keys (Caps/Num/Scroll):

  • (a) decorate every key report with the current lock-key state (modifier bits caps_lock=64, num_lock=128), and
  • (b) emit press/release transition events for the lock keys themselves under progressive-enhancement flag 8 (+ event types under flag 2), e.g. CSI 57358 u for CapsLock.

freminal cannot do either correctly and uniformly across platforms with the current windowing stack, so the Task 114 attempt was reverted (see PR reverting the lock-state half). This issue tracks the upstream support needed to do it right.

Why it's blocked (per platform)

  • Wayland: the compositor consumes CapsLock/NumLock to update its own modifier state and delivers only wl_keyboard.modifiers — winit surfaces this as ModifiersChanged, never a WindowEvent::KeyboardInput. So freminal never observes the transition: neither (a) the state nor (b) the event is obtainable. winit also does not expose the mods_locked bitmask from that event.
  • Windows / macOS: GetKeyState(VK_CAPITAL/VK_NUMLOCK/VK_SCROLL) / CGEventSourceFlagsState are level queries (current on/off), not edges. We can only sample them at cold-start and focus-gain, so (a) decoration is stale between focus changes (exactly when the user is typing), and (b) the transition event is never observable (the key event carries no lock semantics; the query is a level).
  • X11: both work — but shipping X11-only would make one platform behave fundamentally differently from every other target.
  • A Linux-only evdev /dev/input LED watcher would fix (a) on Linux only, still can't do (b) off X11, and adds a fragile out-of-band device-node dependency that deepens platform divergence.

Half-shipping this would violate freminal's truthful capability-advertisement rule (we would advertise flag-8 lock support / lock modifier bits we can't actually deliver), so we declined it rather than ship a broken/divergent implementation.

What IS implemented (unaffected)

Task 114 still delivers the other egui-dropped keys — keypad operators/digits, media keys, and PrintScreen/Pause/Menu — via a raw-winit intercept (App::on_raw_key_event) encoded through the existing KKP CSI u path. Those are ordinary stateless keys that deliver correctly on all platforms.

Upstream tracking

What would unblock us

Any of:

  1. egui exposes CapsLock/NumLock/ScrollLock as Key variants and reports their press/release transitions (egui#3653), plus lock modifier state in egui::Modifiers (egui#2041); or
  2. winit exposes lock-modifier state (e.g. mods_locked on ModifiersChanged / lock bits on ModifiersState, winit#1426) and delivers the lock keys as KeyboardInput on Wayland — then freminal's existing raw-winit intercept + a small state read finishes the job with no platform divergence.

Freminal-side notes

  • The KKP_CAPS_LOCK_CODEPOINT / KKP_NUM_LOCK_CODEPOINT / KKP_SCROLL_LOCK_CODEPOINT constants remain defined in freminal-terminal-emulator (full kitty codepoint table, unit-tested) — only the GUI delivery was removed, so re-enabling is mostly windowing-layer work once upstream lands.
  • Docs: Documents/ESCAPE_SEQUENCE_GAPS.md, ESCAPE_SEQUENCE_COVERAGE.md, KITTY_PROTOCOL_REFERENCE.md mark these as not-implemented gaps; PLAN_VERSION_110.md subtask 114.11 records the revert rationale.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions