Fix Unicode injection: ydotoold + xclip fallback + input logging
- Start ydotoold automatically so ydotool can handle Vietnamese chars - Fix xclip clipboard to run as SUDO_USER when daemon is root - Add detailed input logging for easier debugging
This commit is contained in:
parent
96c8006070
commit
0f1f08e79f
2 changed files with 64 additions and 16 deletions
|
|
@ -130,6 +130,7 @@ impl Daemon {
|
|||
let mut commands = Vec::new();
|
||||
|
||||
if let Some(event) = self.engine.process_key(ch) {
|
||||
eprintln!("[vietc] key='{}' buf='{}' -> {:?}", ch, self.engine.buffer(), event);
|
||||
match event {
|
||||
EngineEvent::Flush(text) => {
|
||||
commands.push(OutputCommand::Type(text));
|
||||
|
|
@ -151,6 +152,8 @@ impl Daemon {
|
|||
commands.push(OutputCommand::Type(restored));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
eprintln!("[vietc] key='{}' -> (no event, buf='{}')", ch, self.engine.buffer());
|
||||
}
|
||||
|
||||
commands
|
||||
|
|
@ -576,20 +579,19 @@ fn execute_commands(injector: &dyn vietc_protocol::KeyInjector, commands: &[Outp
|
|||
for cmd in commands {
|
||||
match cmd {
|
||||
OutputCommand::Backspace(count) => {
|
||||
// The engine adds +1 to account for the current character key.
|
||||
// With grabbing that key was never forwarded to the app, so
|
||||
// we subtract 1. Without grab, the key WAS forwarded, so we
|
||||
// use the full count.
|
||||
let adjusted = if grabbed { count.saturating_sub(1) } else { *count };
|
||||
eprintln!("[vietc] cmd: Backspace({}) -> adjusted={}", count, adjusted);
|
||||
pending_backspaces += adjusted;
|
||||
}
|
||||
OutputCommand::Type(text) => {
|
||||
eprintln!("[vietc] cmd: Type(\"{}\")", text);
|
||||
pending_text.push_str(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if pending_backspaces > 0 || !pending_text.is_empty() {
|
||||
eprintln!("[vietc] inject: BS={} text=\"{}\"", pending_backspaces, pending_text);
|
||||
injector.inject_replacement(pending_backspaces, &pending_text);
|
||||
}
|
||||
injector.flush();
|
||||
|
|
|
|||
|
|
@ -24,7 +24,23 @@ unsafe impl Send for UinputInjector {}
|
|||
unsafe impl Sync for UinputInjector {}
|
||||
|
||||
impl UinputInjector {
|
||||
fn start_ydotoold() {
|
||||
// ydotoold must be running for ydotool to handle Unicode characters.
|
||||
// ydotool in direct mode crashes with "no matching keycode" for
|
||||
// non-ASCII chars. Start it once; ignore failure (daemon may already
|
||||
// exist).
|
||||
let _ = std::process::Command::new("ydotoold")
|
||||
.arg("--fork")
|
||||
.stdout(std::process::Stdio::null())
|
||||
.stderr(std::process::Stdio::null())
|
||||
.spawn();
|
||||
// Give it a moment to start
|
||||
std::thread::sleep(std::time::Duration::from_millis(200));
|
||||
}
|
||||
|
||||
pub fn new(name: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
Self::start_ydotoold();
|
||||
|
||||
let file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
|
|
@ -332,18 +348,48 @@ impl UinputInjector {
|
|||
{
|
||||
return true;
|
||||
}
|
||||
// Try xclip (X11)
|
||||
std::process::Command::new("xclip")
|
||||
.args(["-selection", "clipboard"])
|
||||
.stdin(std::process::Stdio::piped())
|
||||
.spawn()
|
||||
.and_then(|mut child| {
|
||||
use std::io::Write;
|
||||
child.stdin.take().unwrap().write_all(s.as_bytes())?;
|
||||
child.wait()
|
||||
})
|
||||
.map(|status| status.success())
|
||||
.unwrap_or(false)
|
||||
// Try xclip (X11). When root, run as SUDO_USER so it can connect to X.
|
||||
let xclip_result = if is_root {
|
||||
if let Ok(sudo_user) = std::env::var("SUDO_USER") {
|
||||
let display = std::env::var("DISPLAY").unwrap_or_default();
|
||||
let mut cmd = std::process::Command::new("sudo");
|
||||
cmd.args(["-u", &sudo_user, "env"]);
|
||||
if !display.is_empty() {
|
||||
cmd.arg(format!("DISPLAY={}", display));
|
||||
}
|
||||
cmd.arg("xclip");
|
||||
cmd.args(["-selection", "clipboard"]);
|
||||
cmd.stdin(std::process::Stdio::piped())
|
||||
.spawn()
|
||||
.and_then(|mut child| {
|
||||
use std::io::Write;
|
||||
child.stdin.take().unwrap().write_all(s.as_bytes())?;
|
||||
child.wait()
|
||||
})
|
||||
.map(|status| status.success())
|
||||
.unwrap_or(false)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
std::process::Command::new("xclip")
|
||||
.args(["-selection", "clipboard"])
|
||||
.stdin(std::process::Stdio::piped())
|
||||
.spawn()
|
||||
.and_then(|mut child| {
|
||||
use std::io::Write;
|
||||
child.stdin.take().unwrap().write_all(s.as_bytes())?;
|
||||
child.wait()
|
||||
})
|
||||
.map(|status| status.success())
|
||||
.unwrap_or(false)
|
||||
};
|
||||
|
||||
if xclip_result {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Send Ctrl+V through our uinput device.
|
||||
|
|
|
|||
Loading…
Reference in a new issue