git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

commitec511f4f1b668ced2b0f1c97e52cb81ac37123b3
parentaa235e391e
authorLucas Galante <[email protected]>
date2026-07-13 15:11
fix(backend): ctrl+letter shortcuts get the keysym, not the control-transformed utf8

handle_key's Character fallback preferred event.utf8, which xkb runs
through the legacy control-character transformation while Ctrl is held
(ctrl+j = "\n", ctrl+a = 0x01, ...) — so app-side ctrl+<letter> matches
like settings' ctrl+j/k/i/u section nav could NEVER fire, from hardware
or injection alike. With Ctrl held the keysym (untransformed) is now
preferred; the utf8 path is unchanged otherwise, and KeyEvent.text still
carries the raw utf8.

Found by driving the newly modifier-capable ccectl key injection (cce
114ef89) on the nested rig: settings received Character("\n") ctrl=true.
After the fix, ctrl+j/k cycle the section highlight and ctrl+i/u
descend/ascend, verified by pixel diffs of the section borders.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fb2AGNKjfQZxfbxP43fVbC

 src/backend/window_runner.rs | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/backend/window_runner.rs b/src/backend/window_runner.rs
index 37c9b4a..f26037b 100644
--- a/src/backend/window_runner.rs
+++ b/src/backend/window_runner.rs
@@ -2615,7 +2615,19 @@ impl<A: Application> EngineState<A> {
             xkeysym::Keysym::Shift_L | xkeysym::Keysym::Shift_R => Key::Named(NamedKey::Shift),
             xkeysym::Keysym::F5 => Key::Named(NamedKey::F5),
             _ => {
-                if let Some(ref text) = event.utf8 {
+                // With Ctrl held, xkb's utf8 goes through the legacy control-character
+                // transformation (ctrl+j = "\n", ctrl+a = 0x01, ...); the keysym is
+                // untransformed, so prefer it there or ctrl+<letter> shortcuts can
+                // never match their letter.
+                if self.ctrl_pressed {
+                    if let Some(ch) = event.keysym.key_char() {
+                        Key::Character(ch.to_string())
+                    } else if let Some(ref text) = event.utf8 {
+                        Key::Character(text.clone())
+                    } else {
+                        return;
+                    }
+                } else if let Some(ref text) = event.utf8 {
                     Key::Character(text.clone())
                 } else if let Some(ch) = event.keysym.key_char() {
                     Key::Character(ch.to_string())