daemon: fall back to X11 capture when evdev produces no events

When evdev's EVIOCGRAB works (returns success) but no keyboard events
arrive (common in VMs where input bypasses the grabbed device), the
daemon previously exited silently after the 30-second safety timeout.
Now it falls through to X11 XRecord capture as a fallback, which works
reliably in VMs by intercepting keystrokes at the X11 protocol level
rather than the evdev level.

- run_with_evdev no longer uses 'return', so main() continues to X11
  capture after evdev exits (timeout or error)
This commit is contained in:
Khoa Vo 2026-07-02 13:33:41 +07:00
parent 41ecc48b0a
commit 24f9bc8c7e

View file

@ -855,20 +855,33 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}); });
} }
// Try evdev first (more reliable than X11 XRecord) // Try evdev first (more reliable than X11 XRecord in most environments).
// If the evdev device opens but produces no events (common in VMs where
// keyboard input bypasses the evdev grab), run_with_evdev will exit via
// the 30-second safety timeout — we fall through to X11 capture.
match open_keyboard_device() { match open_keyboard_device() {
Ok((device, path)) => { Ok((device, path)) => {
log_info(&format!("[vietc] Keyboard device: {}", path)); log_info(&format!("[vietc] Keyboard device: {}", path));
return run_with_evdev( match run_with_evdev(
device, device,
&mut daemon, &mut daemon,
shared_active_window, shared_active_window.clone(),
shared_window_class, shared_window_class.clone(),
config_changed, config_changed.clone(),
status_changed, status_changed.clone(),
engine_enabled, engine_enabled.clone(),
display, display,
); ) {
Ok(()) => {
log_info("[vietc] evdev returned, trying X11 capture as fallback");
}
Err(e) => {
log_info(&format!(
"[vietc] evdev exited with error: {} — trying X11 capture",
e
));
}
}
} }
Err(e) => { Err(e) => {
log_info(&format!("[vietc] evdev not available: {}", e)); log_info(&format!("[vietc] evdev not available: {}", e));
@ -882,10 +895,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
return run_with_x11( return run_with_x11(
capture, capture,
&mut daemon, &mut daemon,
shared_active_window.clone(), shared_active_window,
config_changed.clone(), config_changed,
status_changed.clone(), status_changed,
engine_enabled.clone(), engine_enabled,
); );
} else { } else {
log_info("[vietc] X11 not available, falling back"); log_info("[vietc] X11 not available, falling back");