diff --git a/daemon/src/main.rs b/daemon/src/main.rs index 65f1212..fd640d9 100644 --- a/daemon/src/main.rs +++ b/daemon/src/main.rs @@ -1205,35 +1205,27 @@ fn run_with_evdev( } if !grabbed { - // Legacy mode: only forward to engine on press events. - // Raw keystrokes reach the application BEFORE the daemon - // can correct them, so VNI/Telex control keys (1-9, f,s,r,...) - // appear on screen as literal characters. We must account - // for this by adding one extra backspace for control keys. - if value != 1 { - continue; - } - if is_modifier_pressed(&key_state) { - continue; - } - if let Some(ch) = key_to_char(key) { - let mut commands = daemon.process_key(ch); - // In non-grabbing mode, VNI/Telex control keys (1-9, f,s,r,x,j) - // reach the application as literal characters before the daemon - // can inject corrections. Add one extra backspace to remove - // the control character from the screen. - if !commands.is_empty() - && is_vn_control_key(&daemon.config.input_method, ch) - { - // Find and increment the first Backspace command - for cmd in &mut commands { - if let OutputCommand::Backspace(ref mut n) = cmd { - *n += 1; - break; - } + // Non-grabbing mode: raw keystrokes reach the application + // directly. Use Event Sourcing (replay_and_inject) which + // tracks what's actually on screen and computes corrections + // based on the screen state — not the engine's internal + // buffer. This avoids race conditions where a correction + // backspace removes the wrong characters because the user + // typed more while the clipboard paste was in flight. + if value == 1 { + if is_modifier_pressed(&key_state) { + continue; + } + if let Some(ch) = key_to_char(key) { + if ch == '\x08' { + // Backspace: let the raw key through, but also + // update the event sourcing state. + daemon.replay_backspace(); + } else { + let commands = daemon.replay_and_inject(ch); + execute_commands(&*injector, &commands, false); } } - execute_commands(&*injector, &commands, false); } } else { // Grabbing mode: all output goes through uinput only.