daemon: use poll() with 100ms timeout for evdev reads instead of blocking fetch_events
The original fetch_events() call blocked indefinitely on the evdev device. In VM environments, the grabbed keyboard device may not deliver events after the initial batch, causing the 30-second safety timeout to trigger silently — the daemon exits, the grab is released, and subsequent keystrokes bypass the IME entirely. Replace with libc::poll() with a 100ms timeout so the event loop stays responsive. When poll returns 0 (timeout), the loop checks signals, the 30-second grab-safety timeout, and also polls for background window changes. This ensures the safety timeout actually fires as expected, and the daemon correctly detects and handles the no-event condition. Also check for background window class changes during idle periods (no keypress events) so app detection works consistently.
This commit is contained in:
parent
8f8b4abf6d
commit
41ecc48b0a
1 changed files with 34 additions and 0 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
@ -1169,6 +1170,39 @@ fn run_with_evdev(
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Poll evdev fd with 100ms timeout so the loop stays responsive
|
||||||
|
// even when no keyboard events arrive (e.g. VM doesn't route input
|
||||||
|
// through the grabbed device).
|
||||||
|
let mut pfd = libc::pollfd {
|
||||||
|
fd: device.as_raw_fd(),
|
||||||
|
events: libc::POLLIN,
|
||||||
|
revents: 0,
|
||||||
|
};
|
||||||
|
let poll_ret = unsafe { libc::poll(&mut pfd, 1, 100) };
|
||||||
|
if poll_ret < 0 {
|
||||||
|
let err = std::io::Error::last_os_error();
|
||||||
|
if err.kind() == std::io::ErrorKind::Interrupted {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
log_info(&format!(
|
||||||
|
"[vietc] poll error on evdev fd: {:?} — exiting",
|
||||||
|
err
|
||||||
|
));
|
||||||
|
return Err(err.into());
|
||||||
|
}
|
||||||
|
if poll_ret == 0 {
|
||||||
|
// No events available — check for background window changes even
|
||||||
|
// without a keypress (the background thread polls every 250ms).
|
||||||
|
if daemon.config.app_state.enabled {
|
||||||
|
let class = shared_window_class.lock().unwrap().clone();
|
||||||
|
if !class.is_empty() && class != last_window_class {
|
||||||
|
last_window_class = class.clone();
|
||||||
|
daemon.check_app_change_with(last_window_class.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let caps = is_caps_lock_on(&device);
|
let caps = is_caps_lock_on(&device);
|
||||||
let mut key_state = device
|
let mut key_state = device
|
||||||
.get_key_state()
|
.get_key_state()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue