fix: remove space split — paste entire text via clipboard at once

- Splitting spaces into separate uinput events caused them to arrive
  after the user's next keystrokes, resulting in 'thịtrâm' (no space).
- Now paste entire text including spaces via clipboard in one operation.
- Trailing spaces may be trimmed by some apps — but this is rarer than
  the timing-induced space loss from split injection.
This commit is contained in:
Khoa Vo 2026-06-26 16:29:02 +07:00
parent eb7960cc77
commit 3ce274c9ae

View file

@ -350,59 +350,34 @@ impl UinputInjector {
/// clipboard for Unicode. /// clipboard for Unicode.
fn inject_replacement_atomic(&self, backspaces: usize, text: &str) -> InjectResult { fn inject_replacement_atomic(&self, backspaces: usize, text: &str) -> InjectResult {
// If all ASCII, send keycodes directly — fast and reliable // If all ASCII, send keycodes directly — fast and reliable
if text.chars().all(|c| char_to_linux_keycode(c).is_some()) { if text.chars().all(|c| char_to_linux_keycode(c).is_some() || c == '\n') {
if backspaces > 0 { if backspaces > 0 {
for _ in 0..backspaces { for _ in 0..backspaces {
let _ = self.send_backspace(); let _ = self.send_backspace();
} }
} }
for ch in text.chars() { for ch in text.chars() {
if ch == '\n' { if ch == '\n' { self.send_enter(); }
self.send_enter(); else { let _ = self.send_char(ch); }
} else {
let _ = self.send_char(ch);
}
} }
return InjectResult::Success; return InjectResult::Success;
} }
// Unicode text: split into Vietnamese portion (clipboard paste) and // Unicode text: paste entire text via clipboard (includes spaces).
// trailing ASCII whitespace/punctuation (uinput). Clipboard paste // Don't split — splitting causes space to arrive after next keystrokes.
// often trims trailing whitespace, so we send it separately. // Send backspaces first, then clipboard paste everything at once.
let mut split = text.len();
for (i, c) in text.char_indices().rev() {
if c.is_ascii() && (c.is_whitespace() || matches!(c, '.' | ',' | '!' | '?' | ';' | ':')) {
split = i;
} else {
break;
}
}
let (vn_text, ascii_tail) = text.split_at(split);
// Backspaces via uinput
if backspaces > 0 { if backspaces > 0 {
for _ in 0..backspaces { for _ in 0..backspaces {
let _ = self.send_backspace(); let _ = self.send_backspace();
} }
} }
// Clipboard paste for Vietnamese text if self.copy_to_clipboard(text) {
if !vn_text.is_empty() {
if self.copy_to_clipboard(vn_text) {
self.send_ctrl_v_x11(); self.send_ctrl_v_x11();
} } else {
} // Fallback: send base ASCII chars via uinput
for ch in text.chars() {
// Trailing ASCII via uinput (spaces, punctuation). let _ = self.send_char(ch);
// Small delay lets the clipboard paste finish before trailing chars arrive.
if !ascii_tail.is_empty() {
std::thread::sleep(std::time::Duration::from_millis(15));
for ch in ascii_tail.chars() {
if ch == '\n' {
self.send_enter();
} else if let Some(kc) = char_to_linux_keycode(ch) {
self.send_key_stroke(kc, false);
}
} }
} }