From 3219978c3fe2db287cd4dd9aa3a4c67811ae80f2 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Tue, 31 Dec 2019 07:31:07 -0800 Subject: split into more modules --- src/main.rs | 391 +------------------------------------------------------- src/mapping.rs | 15 +++ src/remapper.rs | 376 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 397 insertions(+), 385 deletions(-) create mode 100644 src/mapping.rs create mode 100644 src/remapper.rs 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, - tap: Vec, - }, - Remap { - input: HashSet, - output: HashSet, - }, -} - -#[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, - - mappings: Vec, - - /// The most recent candidate for a tap function is held here - tapping: Option, - - output_keys: HashSet, -} - -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>(path: P, mappings: Vec) -> Result { - 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 { - // Start with the input keys - let mut keys: HashSet = 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 = self - .output_keys - .difference(&desired_keys) - .cloned() - .collect(); - - let to_press: Vec = 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 { - 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 { - 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 = 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(()) } diff --git a/src/mapping.rs b/src/mapping.rs new file mode 100644 index 0000000..6fa655e --- /dev/null +++ b/src/mapping.rs @@ -0,0 +1,15 @@ +pub use evdev_rs::enums::{EventCode, EV_KEY as KeyCode}; +use std::collections::HashSet; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum Mapping { + DualRole { + input: KeyCode, + hold: Vec, + tap: Vec, + }, + Remap { + input: HashSet, + output: HashSet, + }, +} diff --git a/src/remapper.rs b/src/remapper.rs new file mode 100644 index 0000000..b81f29b --- /dev/null +++ b/src/remapper.rs @@ -0,0 +1,376 @@ +use crate::mapping::*; +use anyhow::*; +use evdev_rs::{Device, GrabMode, InputEvent, ReadFlag, TimeVal, UInputDevice}; +use std::collections::{HashMap, HashSet}; +use std::path::Path; +use std::time::Duration; + +#[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) +} + +pub 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, + + mappings: Vec, + + /// The most recent candidate for a tap function is held here + tapping: Option, + + output_keys: HashSet, +} + +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>(path: P, mappings: Vec) -> Result { + 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, + }) + } + + pub fn run_mapper(&mut self) -> Result<()> { + log::error!("Going into read loop"); + loop { + let (status, event) = self + .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); + self.update_with_event(&event, key.clone())?; + } else { + log::trace!("PASSTHRU {:?}", event); + self.output.write_event(&event)?; + } + } + evdev_rs::ReadStatus::Sync => bail!("ReadStatus::Sync!"), + } + } + } + + /// Compute the effective set of keys that are pressed + fn compute_keys(&self) -> HashSet { + // Start with the input keys + let mut keys: HashSet = 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 = self + .output_keys + .difference(&desired_keys) + .cloned() + .collect(); + + let to_press: Vec = 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 { + 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 { + 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 = 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()) +} -- cgit v1.2.3