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:
- 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
- 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.
Summary
The kitty keyboard protocol asks a terminal to, for the lock keys (Caps/Num/Scroll):
caps_lock=64,num_lock=128), andCSI 57358 ufor 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)
wl_keyboard.modifiers— winit surfaces this asModifiersChanged, never aWindowEvent::KeyboardInput. So freminal never observes the transition: neither (a) the state nor (b) the event is obtainable. winit also does not expose themods_lockedbitmask from that event.GetKeyState(VK_CAPITAL/VK_NUMLOCK/VK_SCROLL)/CGEventSourceFlagsStateare 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).evdev/dev/inputLED 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 KKPCSI upath. Those are ordinary stateless keys that deliver correctly on all platforms.Upstream tracking
ModifiersStateexposes no caps/num/scroll lock bits)What would unblock us
Any of:
Keyvariants and reports their press/release transitions (egui#3653), plus lock modifier state inegui::Modifiers(egui#2041); ormods_lockedonModifiersChanged/ lock bits onModifiersState, winit#1426) and delivers the lock keys asKeyboardInputon Wayland — then freminal's existing raw-winit intercept + a small state read finishes the job with no platform divergence.Freminal-side notes
KKP_CAPS_LOCK_CODEPOINT/KKP_NUM_LOCK_CODEPOINT/KKP_SCROLL_LOCK_CODEPOINTconstants remain defined infreminal-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.Documents/ESCAPE_SEQUENCE_GAPS.md,ESCAPE_SEQUENCE_COVERAGE.md,KITTY_PROTOCOL_REFERENCE.mdmark these as not-implemented gaps;PLAN_VERSION_110.mdsubtask 114.11 records the revert rationale.