From 2d2b476643a246ca17f30cfcbb280e76bf6c281a Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Sun, 9 Jun 2024 06:20:56 -0700 Subject: Add --wait-for-device flag This is a simple approach for the case where the device isn't plugged in on startup. It works by polling the devices in a loop every few seconds. It is probably better and more robust to use udev rules for this purpose, but this approach will do for a quick and dirty ad-hoc user. closes: #35 closes: #46 closes: #60 --- src/main.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 5828a37..d578185 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +use crate::deviceinfo::DeviceInfo; use crate::mapping::*; use crate::remapper::*; use anyhow::{Context, Result}; @@ -40,6 +41,14 @@ enum Opt { /// Override the phys device specified by the config file #[arg(long)] phys: Option, + + /// If the device isn't found on startup, wait forever + /// until the device is plugged in. This works by polling + /// the set of devices every few seconds. It is not as + /// efficient as setting up a udev rule to spawn evremap, + /// but is simpler to setup ad-hoc. + #[arg(long)] + wait_for_device: bool, }, } @@ -68,6 +77,36 @@ fn setup_logger() { builder.init(); } +fn get_device( + device_name: &str, + phys: Option<&str>, + wait_for_device: bool, +) -> anyhow::Result { + match deviceinfo::DeviceInfo::with_name(device_name, phys) { + Ok(dev) => return Ok(dev), + Err(err) if !wait_for_device => return Err(err), + Err(err) => { + log::warn!("{err:#}. Will wait until it is attached."); + } + } + + const MAX_SLEEP: Duration = Duration::from_secs(10); + const ONE_SECOND: Duration = Duration::from_secs(1); + let mut sleep = ONE_SECOND; + + loop { + std::thread::sleep(sleep); + sleep = (sleep + ONE_SECOND).min(MAX_SLEEP); + + match deviceinfo::DeviceInfo::with_name(device_name, phys) { + Ok(dev) => return Ok(dev), + Err(err) => { + log::debug!("{err:#}"); + } + } + } +} + fn main() -> Result<()> { setup_logger(); let opt = Opt::parse(); @@ -80,6 +119,7 @@ fn main() -> Result<()> { delay, device_name, phys, + wait_for_device, } => { let mut mapping_config = MappingConfig::from_file(&config_file).context(format!( "loading MappingConfig from {}", @@ -104,8 +144,11 @@ fn main() -> Result<()> { log::warn!("Short delay: release any keys now!"); std::thread::sleep(Duration::from_secs_f64(delay)); - let device_info = - deviceinfo::DeviceInfo::with_name(device_name, mapping_config.phys.as_deref())?; + let device_info = get_device( + device_name, + mapping_config.phys.as_deref(), + wait_for_device, + )?; let mut mapper = InputMapper::create_mapper(device_info.path, mapping_config.mappings)?; mapper.run_mapper() -- cgit v1.2.3