From a5c1ab99c330fe02d7e6e3ab77737dda19721606 Mon Sep 17 00:00:00 2001 From: vndangkhoa Date: Wed, 24 Jun 2026 20:57:40 +0700 Subject: [PATCH] Fix modifier key bypass (Ctrl, Alt, Meta) and raw key forwarding when no Vietnamese combination exists --- daemon/src/main.rs | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/daemon/src/main.rs b/daemon/src/main.rs index ac3f6a2..381e846 100644 --- a/daemon/src/main.rs +++ b/daemon/src/main.rs @@ -484,6 +484,7 @@ fn run_with_evdev( for event in events { if let evdev::InputEventKind::Key(key) = event.kind() { let value = event.value(); + let keycode = key.0; if value == 1 && is_toggle_combination_state(&key_state, &daemon.config.toggle_key) @@ -497,20 +498,24 @@ fn run_with_evdev( if value != 1 { continue; } + if is_modifier_pressed(&key_state) { + continue; + } if let Some(ch) = key_to_char(key) { let commands = daemon.process_key(ch); execute_commands(&*injector, &commands, false); } } else { // Grabbing mode: all output goes through uinput only. - // Physical evdev is grabbed — never forward through it, - // as separate channels have no ordering guarantee. - let keycode = key.0; + + // If Ctrl, Alt, or Meta/Super is pressed, bypass the engine completely and forward raw key events. + if is_modifier_pressed(&key_state) { + injector.send_key_event(keycode, value); + continue; + } // Backspace in grab mode: pop engine, inject via uinput. - // send_char('\x08') can't emit a keycode and falls through - // to paste_string, which is wrong. - if key == evdev::Key::KEY_BACKSPACE && grabbed { + if key == evdev::Key::KEY_BACKSPACE { if value == 1 || value == 2 { daemon.engine.process_key('\x08'); injector.send_key_event(14, 1); @@ -531,7 +536,7 @@ fn run_with_evdev( consumed_keys.insert(keycode); execute_commands(&*injector, &commands, true); } else { - injector.send_char(ch); + injector.send_key_event(keycode, 1); } } else { injector.send_key_event(keycode, 1); @@ -541,12 +546,7 @@ fn run_with_evdev( if consumed_keys.contains(&keycode) { continue; } - if let Some(ch) = key_to_char(key) { - injector.send_char(ch); - } else { - injector.send_key_event(keycode, 1); - injector.send_key_event(keycode, 0); - } + injector.send_key_event(keycode, 2); } else if value == 0 { // Release: skip if consumed, else forward if consumed_keys.contains(&keycode) { @@ -731,6 +731,20 @@ fn create_injector(display: display::DisplayServer) -> Result>) -> bool { + let key_state = match key_state { + Some(ks) => ks, + None => return false, + }; + + key_state.contains(evdev::Key::KEY_LEFTCTRL) + || key_state.contains(evdev::Key::KEY_RIGHTCTRL) + || key_state.contains(evdev::Key::KEY_LEFTALT) + || key_state.contains(evdev::Key::KEY_RIGHTALT) + || key_state.contains(evdev::Key::KEY_LEFTMETA) + || key_state.contains(evdev::Key::KEY_RIGHTMETA) +} + fn is_toggle_combination_state(key_state: &Option>, key: &str) -> bool { let key_state = match key_state { Some(ks) => ks,