Skip to content

Commit

Permalink
[wip] udev support via tokio-udev to add/remove devices dynamically
Browse files Browse the repository at this point in the history
Support for listening asynchronously to udev DeviceRemoved/DeviceAdded events
with the `tokio-udev` crate.

For now, this only works with the latest commits on the tokio-udev repo.
  • Loading branch information
ajanon committed May 28, 2023
1 parent 82f9617 commit cdbb379
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `DESTDIR` variable for the `install` target in the `Makefile` to help
packaging and installation. To install in a subdirectory, just call `make
DESTDIR=subdir install`.
- Detection of added/removed devices (e.g., when plugging or unplugging a
keyboard). The devices are grabbed by `swhkd` if they match the `--device`
parameters if present or if they are recognized as keyboard devices otherwise.

### Changed

Expand Down
38 changes: 38 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions swhkd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ signal-hook-tokio = { version = "0.3.1", features = ["futures-v0_3"] }
sysinfo = "0.23.5"
tokio = { version = "1.17.0", features = ["full"] }
tokio-stream = "0.1.8"
tokio-udev = { git = "https://github.com/jeandudey/tokio-udev.git" }

[[bin]]
name = "swhkd"
Expand Down
52 changes: 52 additions & 0 deletions swhkd/src/daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use tokio::select;
use tokio::time::Duration;
use tokio::time::{sleep, Instant};
use tokio_stream::{StreamExt, StreamMap};
use tokio_udev::{AsyncMonitorSocket, EventType, MonitorBuilder};

mod config;
mod perms;
Expand Down Expand Up @@ -183,6 +184,9 @@ async fn main() -> Result<(), Box<dyn Error>> {
}
};

let mut udev =
AsyncMonitorSocket::new(MonitorBuilder::new()?.match_subsystem("input")?.listen()?)?;

let modifiers_map: HashMap<Key, config::Modifier> = HashMap::from([
(Key::KEY_LEFTMETA, config::Modifier::Super),
(Key::KEY_RIGHTMETA, config::Modifier::Super),
Expand Down Expand Up @@ -275,6 +279,54 @@ async fn main() -> Result<(), Box<dyn Error>> {
}
}

Some(Ok(event)) = udev.next() => {
if !event.is_initialized() {
log::warn!("Received udev event with uninitialized device.");
}
match event.event_type() {
EventType::Add => {
if let Some(devnode) = event.devnode() {
let mut device = match Device::open(devnode) {
Err(e) => {
log::error!("Could not open evdev device at {}: {}", devnode.to_string_lossy(), e);
continue;
},
Ok(device) => device
};
if arg_devices.contains(&device.name().unwrap_or("")) || check_device_is_keyboard(&device) {
log::info!("Device '{}' at '{}' added.", &device.name().unwrap_or(""), devnode.to_string_lossy());
let _ = device.grab();
keyboard_states.push(KeyboardState::new());
keyboard_stream_map.insert(keyboard_states.len() - 1, device.into_event_stream()?);
}
}
}
EventType::Remove => {
let udev_physical_path = event.property_value("PHYS")
.and_then(|os_str| os_str.to_str())
.map(|s| s.replace('\"', ""));
keyboard_stream_map
.iter()
.filter(|(_, stream)| stream.device().physical_path() == udev_physical_path.as_deref())
.map(|(key, _)| *key)
// Collect all to not remove values while iterating
.collect::<Vec<_>>()
.into_iter()
// Reverse to avoid dealing with changing indices for the keyboard_states vector
.rev()
.for_each(|key| {
keyboard_states.remove(key);
if let Some(stream) = keyboard_stream_map.remove(&key) {
log::info!("Device '{}' removed", stream.device().name().unwrap_or(""));
}
});
}
_ => {
log::trace!("Ignored udev event of type: {:?}", event.event_type());
}
}
}

Some((i, Ok(event))) = keyboard_stream_map.next() => {
let keyboard_state = &mut keyboard_states[i];

Expand Down

0 comments on commit cdbb379

Please sign in to comment.