From 035aeca9973f348f1a6aacdf24a61b1caa658dc9 Mon Sep 17 00:00:00 2001 From: Khoa Vo Date: Thu, 2 Jul 2026 15:35:53 +0700 Subject: [PATCH] fix: VNI/Telex control key flicker in non-grabbed mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a VNI/Telex control key (e.g. digit 6 for ô, w for â/ê/ô) is pressed, the engine absorbs it in-place without emitting an event. In non-grabbed mode the raw character already reached the terminal. Fix: capture buf_before, compare with buf_after, and synthesize Backspace(len+1) + Type(buf_after) when the buffer changed. --- daemon/src/main.rs | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/daemon/src/main.rs b/daemon/src/main.rs index 5f6b390..3ec09cd 100644 --- a/daemon/src/main.rs +++ b/daemon/src/main.rs @@ -310,8 +310,6 @@ impl Daemon { commands.push(OutputCommand::Type(text)); } } - } else { - // No event — key was consumed or ignored by engine } commands @@ -1269,15 +1267,17 @@ fn run_with_x11_keymap( // Use keymap lookup for character conversion if let Some(ch) = capture.lookup_keycode(keycode, mod_state) { + let buf_before = daemon.engine.buffer(); let mut commands = daemon.process_key(ch); - if !commands.is_empty() + if commands.is_empty() + && daemon.engine.is_enabled() && is_vn_control_key(daemon.app_state.effective_method(), ch) { - for cmd in &mut commands { - if let OutputCommand::Backspace(ref mut n) = cmd { - *n += 1; - break; - } + let buf_after = daemon.engine.buffer(); + if buf_after != buf_before && !buf_before.is_empty() { + let len = buf_before.chars().count(); + commands.push(OutputCommand::Backspace(len + 1)); + commands.push(OutputCommand::Type(buf_after)); } } execute_commands(&*injector, &commands, false); @@ -1499,15 +1499,17 @@ fn run_with_evdev( continue; } if let Some(ch) = key_to_char(key) { + let buf_before = daemon.engine.buffer(); let mut commands = daemon.process_key(ch); - if !commands.is_empty() + if commands.is_empty() + && daemon.engine.is_enabled() && is_vn_control_key(daemon.app_state.effective_method(), ch) { - for cmd in &mut commands { - if let OutputCommand::Backspace(ref mut n) = cmd { - *n += 1; - break; - } + let buf_after = daemon.engine.buffer(); + if buf_after != buf_before && !buf_before.is_empty() { + let len = buf_before.chars().count(); + commands.push(OutputCommand::Backspace(len + 1)); + commands.push(OutputCommand::Type(buf_after)); } } execute_commands(&*injector, &commands, false);