fix: listen events from ungrabbed keyboard evdev devices

pull/10977/head
Evgeniy Tatarkin 2025-02-10 20:24:22 +03:00
parent 4c6b0ff447
commit 0567bae0f3
2 changed files with 51 additions and 35 deletions

View File

@ -57,7 +57,7 @@ thiserror.workspace = true
kstring = "2.0" kstring = "2.0"
keyboard_query = { version = "0.1.0", optional = true } keyboard_query = { version = "0.1.0", optional = true }
evdev = { version = "0.13", optional = true } evdev = { version = "0.13", features = ["tokio"], optional = true }
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
clipboard-win = { version = "5.4", features = ["std"] } clipboard-win = { version = "5.4", features = ["std"] }

View File

@ -62,9 +62,14 @@ mod keyboard_state {
use std::sync::atomic::{AtomicU16, Ordering}; use std::sync::atomic::{AtomicU16, Ordering};
use std::sync::Arc; use std::sync::Arc;
struct DeviceHandle {
_path: std::path::PathBuf,
_handle: tokio::task::JoinHandle<()>,
}
pub struct KeyboardState { pub struct KeyboardState {
codes: [Arc<AtomicU16>; 2], codes: [Arc<AtomicU16>; 2],
_handle: std::thread::JoinHandle<()>, _handle: Vec<DeviceHandle>,
} }
fn is_keyboard(device: &Device) -> bool { fn is_keyboard(device: &Device) -> bool {
@ -78,37 +83,40 @@ mod keyboard_state {
let key1 = Arc::new(AtomicU16::new(0)); let key1 = Arc::new(AtomicU16::new(0));
let key2 = Arc::new(AtomicU16::new(0)); let key2 = Arc::new(AtomicU16::new(0));
let k1 = Arc::clone(&key1); // find keyboards
let k2 = Arc::clone(&key2); let keyboards = evdev::enumerate()
.filter(|(_, dev)| is_keyboard(dev))
.collect::<Vec<_>>();
let _handle = std::thread::spawn(move || { let mut handles = Vec::new();
// Try to find last keyboard input device
// TODO how to find actual system input device?
// TODO get input device path from config
let now = std::time::Instant::now();
let Some((device_path, mut device)) = evdev::enumerate()
.filter(|(_, dev)| is_keyboard(dev))
.last()
else {
log::warn!("No keyboard devices found");
return;
};
log::info!(
"Listen last keyboard input device '{}' (spend {}ms): {}",
device_path.display(),
now.elapsed().as_millis(),
device.name().unwrap_or_default()
);
// evdev constants // evdev constant
const KEY_STATE_RELEASE: i32 = 0; const KEY_STATE_RELEASE: i32 = 0;
let mut codes: [u16; 2] = [0, 0];
loop { for (path, mut item) in keyboards {
let Ok(stream) = device.fetch_events() else { // skip already grabbed keyboards
log::error!("Failed to fetch devices events"); let is_grabbed = item.grab().is_err();
continue; if !is_grabbed {
if let Err(e) = item.ungrab() {
log::error!("Failed to ungrab input: {e}");
}
}
if is_grabbed {
continue;
}
let k1 = Arc::clone(&key1);
let k2 = Arc::clone(&key2);
let mut codes = [0, 0];
let device_path = path.to_str().unwrap_or_default().to_owned();
let handle = tokio::task::spawn(async move {
let device_name = item.name().unwrap_or_default().to_owned();
log::info!("Start listen events from: {device_name} ({device_path})");
let Ok(mut events) = item.into_event_stream() else {
log::error!("Failed to stream events from: {device_name} ({device_path})");
return;
}; };
for event in stream {
while let Ok(event) = events.next_event().await {
if evdev::EventType::KEY != event.event_type() { if evdev::EventType::KEY != event.event_type() {
continue; continue;
}; };
@ -129,11 +137,16 @@ mod keyboard_state {
k1.store(codes[0], Ordering::Relaxed); k1.store(codes[0], Ordering::Relaxed);
k2.store(codes[1], Ordering::Relaxed); k2.store(codes[1], Ordering::Relaxed);
} }
} });
});
handles.push(DeviceHandle {
_path: path,
_handle: handle,
})
}
Self { Self {
_handle, _handle: handles,
codes: [key1, key2], codes: [key1, key2],
} }
} }
@ -287,8 +300,6 @@ where
.map_err(|e| <D::Error as Error>::custom(e))?, .map_err(|e| <D::Error as Error>::custom(e))?,
) )
} else { } else {
log::debug!("User defined scancode layout not found: {}", value.layout);
// lookup in hardcoded defaults // lookup in hardcoded defaults
let Some(map) = defaults::LAYOUTS.get(value.layout.as_str()) else { let Some(map) = defaults::LAYOUTS.get(value.layout.as_str()) else {
return Err(<D::Error as Error>::custom(format!( return Err(<D::Error as Error>::custom(format!(
@ -297,6 +308,11 @@ where
))); )));
}; };
log::debug!(
"User defined scancode layout not found: {}. Use default",
value.layout
);
map.to_owned() map.to_owned()
}; };