diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 391 |
1 files changed, 6 insertions, 385 deletions
diff --git a/src/main.rs b/src/main.rs index 78f9308..3473bf7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,12 @@ +use crate::mapping::*; +use crate::remapper::*; use anyhow::*; -use evdev_rs::enums::{EventCode, EV_KEY as KeyCode}; -use evdev_rs::{Device, GrabMode, InputEvent, ReadFlag, TimeVal, UInputDevice}; -use std::collections::{HashMap, HashSet}; -use std::path::Path; use std::time::Duration; use structopt::StructOpt; mod deviceinfo; +mod mapping; +mod remapper; #[derive(Debug, StructOpt)] #[structopt( @@ -22,368 +22,6 @@ struct Opt { list_devices: bool, } -#[derive(Debug, Clone, Eq, PartialEq)] -enum Mapping { - DualRole { - input: KeyCode, - hold: Vec<KeyCode>, - tap: Vec<KeyCode>, - }, - Remap { - input: HashSet<KeyCode>, - output: HashSet<KeyCode>, - }, -} - -#[derive(Clone, Copy, Debug)] -enum KeyEventType { - Release, - Press, - Repeat, - Unknown(i32), -} - -impl KeyEventType { - fn from_value(value: i32) -> Self { - match value { - 0 => KeyEventType::Release, - 1 => KeyEventType::Press, - 2 => KeyEventType::Repeat, - _ => KeyEventType::Unknown(value), - } - } - - fn value(&self) -> i32 { - match self { - Self::Release => 0, - Self::Press => 1, - Self::Repeat => 2, - Self::Unknown(n) => *n, - } - } -} - -fn timeval_diff(newer: &TimeVal, older: &TimeVal) -> Duration { - const MICROS_PER_SECOND: i64 = 1000000; - let secs = newer.tv_sec - older.tv_sec; - let usecs = newer.tv_usec - older.tv_usec; - - let (secs, usecs) = if usecs < 0 { - (secs - 1, usecs + MICROS_PER_SECOND) - } else { - (secs, usecs) - }; - - Duration::from_micros(((secs * MICROS_PER_SECOND) + usecs) as u64) -} - -struct InputMapper { - input: Device, - output: UInputDevice, - /// If present in this map, the key is down since the instant - /// of its associated value - input_state: HashMap<KeyCode, TimeVal>, - - mappings: Vec<Mapping>, - - /// The most recent candidate for a tap function is held here - tapping: Option<KeyCode>, - - output_keys: HashSet<KeyCode>, -} - -fn enable_key_code(input: &mut Device, key: KeyCode) -> Result<()> { - input - .enable(&EventCode::EV_KEY(key.clone())) - .context(format!("enable key {:?}", key))?; - Ok(()) -} - -impl InputMapper { - pub fn create_mapper<P: AsRef<Path>>(path: P, mappings: Vec<Mapping>) -> Result<Self> { - let path = path.as_ref(); - let f = std::fs::File::open(path).context(format!("opening {}", path.display()))?; - let mut input = Device::new().ok_or_else(|| anyhow!("failed to make new Device"))?; - input - .set_fd(f) - .context(format!("assigning fd for {} to Device", path.display()))?; - - input.set_name(&format!("evremap Virtual input for {}", path.display())); - - // Ensure that any remapped keys are supported by the generated output device - for map in &mappings { - match map { - Mapping::DualRole { tap, hold, .. } => { - for t in tap { - enable_key_code(&mut input, t.clone())?; - } - for h in hold { - enable_key_code(&mut input, h.clone())?; - } - } - Mapping::Remap { output, .. } => { - for o in output { - enable_key_code(&mut input, o.clone())?; - } - } - } - } - - let output = UInputDevice::create_from_device(&input) - .context(format!("creating UInputDevice from {}", path.display()))?; - - input - .grab(GrabMode::Grab) - .context(format!("grabbing exclusive access on {}", path.display()))?; - - Ok(Self { - input, - output, - input_state: HashMap::new(), - output_keys: HashSet::new(), - tapping: None, - mappings, - }) - } - - /// Compute the effective set of keys that are pressed - fn compute_keys(&self) -> HashSet<KeyCode> { - // Start with the input keys - let mut keys: HashSet<KeyCode> = self.input_state.keys().cloned().collect(); - - // First phase is to apply any DualRole mappings as they are likely to - // be used to produce modifiers when held. - for map in &self.mappings { - if let Mapping::DualRole { input, hold, .. } = map { - if keys.contains(input) { - keys.remove(input); - for h in hold { - keys.insert(h.clone()); - } - } - } - } - - // Second pass to apply Remap items - for map in &self.mappings { - if let Mapping::Remap { input, output } = map { - if input.is_subset(&keys) { - for i in input { - keys.remove(i); - } - for o in output { - keys.insert(o.clone()); - } - } - } - } - - keys - } - - fn compute_and_apply_keys(&mut self, time: &TimeVal) -> Result<()> { - let desired_keys = self.compute_keys(); - let to_release: Vec<KeyCode> = self - .output_keys - .difference(&desired_keys) - .cloned() - .collect(); - - let to_press: Vec<KeyCode> = desired_keys - .difference(&self.output_keys) - .cloned() - .collect(); - - if !to_release.is_empty() { - self.emit_keys(&to_release, time, KeyEventType::Release)?; - } - if !to_press.is_empty() { - self.emit_keys(&to_press, time, KeyEventType::Press)?; - } - Ok(()) - } - - fn lookup_dual_role_mapping(&self, code: KeyCode) -> Option<Mapping> { - for map in &self.mappings { - if let Mapping::DualRole { input, .. } = map { - if *input == code { - // A DualRole mapping has the highest precedence - // so we've found our match - return Some(map.clone()); - } - } - } - None - } - - fn lookup_mapping(&self, code: KeyCode) -> Option<Mapping> { - let mut candidates = vec![]; - - for map in &self.mappings { - match map { - Mapping::DualRole { input, .. } => { - if *input == code { - // A DualRole mapping has the highest precedence - // so we've found our match - return Some(map.clone()); - } - } - Mapping::Remap { input, .. } => { - // Look for a mapping that includes the current key. - // If part of a chord, all of its component keys must - // also be pressed. - let mut code_matched = false; - let mut all_matched = true; - for i in input { - if *i == code { - code_matched = true; - } else if !self.input_state.contains_key(i) { - all_matched = false; - break; - } - } - if code_matched && all_matched { - candidates.push(map); - } - } - } - } - - // Any matches must be Remap entries. We want the one - // with the most active keys - candidates.sort_by(|a, b| match (a, b) { - (Mapping::Remap { input: input_a, .. }, Mapping::Remap { input: input_b, .. }) => { - input_a.len().cmp(&input_b.len()).reverse() - } - _ => unreachable!(), - }); - - candidates.get(0).map(|&m| m.clone()) - } - - pub fn update_with_event(&mut self, event: &InputEvent, code: KeyCode) -> Result<()> { - let event_type = KeyEventType::from_value(event.value); - match event_type { - KeyEventType::Release => { - let pressed_at = match self.input_state.remove(&code) { - None => { - self.write_event_and_sync(event)?; - return Ok(()); - } - Some(p) => p, - }; - - self.compute_and_apply_keys(&event.time)?; - - if let Some(Mapping::DualRole { tap, .. }) = - self.lookup_dual_role_mapping(code.clone()) - { - // If released quickly enough, becomes a tap press. - if let Some(tapping) = self.tapping.take() { - if tapping == code - && timeval_diff(&event.time, &pressed_at) <= Duration::from_millis(200) - { - self.emit_keys(&tap, &event.time, KeyEventType::Press)?; - self.emit_keys(&tap, &event.time, KeyEventType::Release)?; - } - } - } - } - KeyEventType::Press => { - self.input_state.insert(code.clone(), event.time.clone()); - - match self.lookup_mapping(code.clone()) { - Some(_) => { - self.compute_and_apply_keys(&event.time)?; - self.tapping.replace(code); - } - None => { - // Just pass it through - self.cancel_pending_tap(); - self.compute_and_apply_keys(&event.time)?; - } - } - } - KeyEventType::Repeat => { - match self.lookup_mapping(code.clone()) { - Some(Mapping::DualRole { hold, .. }) => { - self.emit_keys(&hold, &event.time, KeyEventType::Repeat)?; - } - Some(Mapping::Remap { output, .. }) => { - let output: Vec<KeyCode> = output.iter().cloned().collect(); - self.emit_keys(&output, &event.time, KeyEventType::Repeat)?; - } - None => { - // Just pass it through - self.cancel_pending_tap(); - self.write_event_and_sync(event)?; - } - } - } - KeyEventType::Unknown(_) => { - self.write_event_and_sync(event)?; - } - } - - Ok(()) - } - - fn cancel_pending_tap(&mut self) { - self.tapping.take(); - } - - fn emit_keys( - &mut self, - key: &[KeyCode], - time: &TimeVal, - event_type: KeyEventType, - ) -> Result<()> { - for k in key { - let event = make_event(k.clone(), time, event_type); - self.write_event(&event)?; - } - self.generate_sync_event(time)?; - Ok(()) - } - - fn write_event_and_sync(&mut self, event: &InputEvent) -> Result<()> { - self.write_event(event)?; - self.generate_sync_event(&event.time)?; - Ok(()) - } - - fn write_event(&mut self, event: &InputEvent) -> Result<()> { - log::trace!("OUT: {:?}", event); - self.output.write_event(&event)?; - if let EventCode::EV_KEY(ref key) = event.event_code { - let event_type = KeyEventType::from_value(event.value); - match event_type { - KeyEventType::Press | KeyEventType::Repeat => { - self.output_keys.insert(key.clone()); - } - KeyEventType::Release => { - self.output_keys.remove(key); - } - _ => {} - } - } - Ok(()) - } - - fn generate_sync_event(&self, time: &TimeVal) -> Result<()> { - self.output.write_event(&InputEvent::new( - time, - &EventCode::EV_SYN(evdev_rs::enums::EV_SYN::SYN_REPORT), - 0, - ))?; - Ok(()) - } -} - -fn make_event(key: KeyCode, time: &TimeVal, event_type: KeyEventType) -> InputEvent { - InputEvent::new(time, &EventCode::EV_KEY(key), event_type.value()) -} - fn main() -> Result<()> { pretty_env_logger::init(); let opt = Opt::from_args(); @@ -422,23 +60,6 @@ fn main() -> Result<()> { let device_info = deviceinfo::DeviceInfo::with_name("AT Translated Set 2 keyboard")?; let mut mapper = InputMapper::create_mapper(device_info.path, mappings)?; - - log::error!("Going into read loop"); - loop { - let (status, event) = mapper - .input - .next_event(ReadFlag::NORMAL | ReadFlag::BLOCKING)?; - match status { - evdev_rs::ReadStatus::Success => { - if let EventCode::EV_KEY(ref key) = event.event_code { - log::trace!("IN {:?}", event); - mapper.update_with_event(&event, key.clone())?; - } else { - log::trace!("PASSTHRU {:?}", event); - mapper.output.write_event(&event)?; - } - } - evdev_rs::ReadStatus::Sync => bail!("ReadStatus::Sync!"), - } - } + mapper.run_mapper()?; + Ok(()) } |