mirror of https://github.com/helix-editor/helix
fix: listen events from ungrabbed keyboard evdev devices
parent
4c6b0ff447
commit
0567bae0f3
|
@ -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"] }
|
||||||
|
|
|
@ -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()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue