Split ActionDispatcher from EventHandler (#200)

* Introduce Event enum

* Rename KeyAction/Action to ModmapAction/KeymapAction

* Introduce Action enum and ActionDispatcher

* Convert OverrideTimeout to an event

* thread::sleep should also be an Action

* Command should also be an Action

* Make InputEvent an Action

* Start writing tests for EventHandler

* cargo fmt
pull/203/head
Takashi Kokubun 2 years ago committed by GitHub
parent 763b1b8746
commit d02446a040
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,19 @@
use std::time::Duration;
use evdev::InputEvent;
use crate::event::KeyEvent;
// Input to ActionDispatcher. This should only contain things that are easily testable.
#[derive(Debug)]
pub enum Action {
// InputEvent (EventType::KEY) sent to evdev
KeyEvent(KeyEvent),
// InputEvent of any event types. It's discouraged to use this for testing because
// we don't have full control over timeval and it's not pattern-matching friendly.
InputEvent(InputEvent),
// Run a command
Command(Vec<String>),
// keypress_delay_ms
Delay(Duration),
}

@ -0,0 +1,72 @@
use std::thread;
use evdev::{uinput::VirtualDevice, EventType, InputEvent, Key};
use log::debug;
use log::error;
use nix::sys::signal;
use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet};
use std::process::{Command, Stdio};
use crate::{action::Action, event::KeyEvent};
pub struct ActionDispatcher {
// Device to emit events
device: VirtualDevice,
// Whether we've called a sigaction for spawing commands or not
sigaction_set: bool,
}
impl ActionDispatcher {
pub fn new(device: VirtualDevice) -> ActionDispatcher {
ActionDispatcher {
device,
sigaction_set: false,
}
}
// Execute Actions created by EventHandler. This should be the only public method of ActionDispatcher.
pub fn on_action(&mut self, action: Action) -> anyhow::Result<()> {
match action {
Action::KeyEvent(key_event) => self.on_key_event(key_event)?,
Action::InputEvent(event) => self.send_event(event)?,
Action::Command(command) => self.run_command(command),
Action::Delay(duration) => thread::sleep(duration),
}
Ok(())
}
fn on_key_event(&mut self, event: KeyEvent) -> std::io::Result<()> {
let event = InputEvent::new_now(EventType::KEY, event.code(), event.value());
self.send_event(event)
}
fn send_event(&mut self, event: InputEvent) -> std::io::Result<()> {
if event.event_type() == EventType::KEY {
debug!("{}: {:?}", event.value(), Key::new(event.code()))
}
self.device.emit(&[event])
}
fn run_command(&mut self, command: Vec<String>) {
if !self.sigaction_set {
// Avoid defunct processes
let sig_action = SigAction::new(SigHandler::SigDfl, SaFlags::SA_NOCLDWAIT, SigSet::empty());
unsafe {
sigaction(signal::SIGCHLD, &sig_action).expect("Failed to register SIGCHLD handler");
}
self.sigaction_set = true;
}
debug!("Running command: {:?}", command);
match Command::new(&command[0])
.args(&command[1..])
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
{
Ok(child) => debug!("Process spawned: {:?}, pid {}", command, child.id()),
Err(e) => error!("Error running command: {:?}", e),
}
}
}

@ -1,7 +1,7 @@
use crate::config::action::{Action, Actions};
use crate::config::application::deserialize_string_or_vec;
use crate::config::application::Application;
use crate::config::key_press::KeyPress;
use crate::config::keymap_action::{Actions, KeymapAction};
use evdev::Key;
use serde::{Deserialize, Deserializer};
use std::collections::HashMap;
@ -15,13 +15,13 @@ pub struct Keymap {
#[serde(default = "String::new")]
pub name: String,
#[serde(deserialize_with = "deserialize_remap")]
pub remap: HashMap<KeyPress, Vec<Action>>,
pub remap: HashMap<KeyPress, Vec<KeymapAction>>,
pub application: Option<Application>,
#[serde(default, deserialize_with = "deserialize_string_or_vec")]
pub mode: Option<Vec<String>>,
}
fn deserialize_remap<'de, D>(deserializer: D) -> Result<HashMap<KeyPress, Vec<Action>>, D::Error>
fn deserialize_remap<'de, D>(deserializer: D) -> Result<HashMap<KeyPress, Vec<KeymapAction>>, D::Error>
where
D: Deserializer<'de>,
{
@ -35,7 +35,7 @@ where
// Internals for efficient keymap lookup
#[derive(Clone, Debug)]
pub struct KeymapEntry {
pub actions: Vec<Action>,
pub actions: Vec<KeymapAction>,
pub modifiers: Vec<Modifier>,
pub application: Option<Application>,
pub mode: Option<Vec<String>>,
@ -70,12 +70,12 @@ pub fn build_keymap_table(keymaps: &Vec<Keymap>) -> HashMap<Key, Vec<KeymapEntry
// Subset of KeymapEntry for override_remap
#[derive(Clone)]
pub struct OverrideEntry {
pub actions: Vec<Action>,
pub actions: Vec<KeymapAction>,
pub modifiers: Vec<Modifier>,
}
// This is executed on runtime unlike build_keymap_table, but hopefully not called so often.
pub fn build_override_table(remap: &HashMap<KeyPress, Vec<Action>>) -> HashMap<Key, Vec<OverrideEntry>> {
pub fn build_override_table(remap: &HashMap<KeyPress, Vec<KeymapAction>>) -> HashMap<Key, Vec<OverrideEntry>> {
let mut table: HashMap<Key, Vec<OverrideEntry>> = HashMap::new();
for (key_press, actions) in remap.iter() {
let mut entries: Vec<OverrideEntry> = match table.get(&key_press.key) {

@ -14,7 +14,7 @@ use super::remap::RemapActions;
// Values in `keymap.remap`
#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum Action {
pub enum KeymapAction {
// Config interface
KeyPress(KeyPress),
#[serde(deserialize_with = "deserialize_remap")]
@ -123,12 +123,12 @@ where
#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum Actions {
Action(Action),
Actions(Vec<Action>),
Action(KeymapAction),
Actions(Vec<KeymapAction>),
}
impl Actions {
pub fn into_vec(self) -> Vec<Action> {
pub fn into_vec(self) -> Vec<KeymapAction> {
match self {
Actions::Action(action) => vec![action],
Actions::Actions(actions) => actions,

@ -1,10 +1,10 @@
pub mod action;
pub mod application;
mod key;
pub mod key_action;
pub mod key_press;
pub mod keymap;
pub mod keymap_action;
mod modmap;
pub mod modmap_action;
pub mod remap;
#[cfg(test)]

@ -1,6 +1,6 @@
use crate::config::application::Application;
use crate::config::key::deserialize_key;
use crate::config::key_action::KeyAction;
use crate::config::modmap_action::ModmapAction;
use evdev::Key;
use serde::{Deserialize, Deserializer};
use std::collections::HashMap;
@ -11,17 +11,17 @@ pub struct Modmap {
#[serde(default = "String::new")]
pub name: String,
#[serde(deserialize_with = "deserialize_remap")]
pub remap: HashMap<Key, KeyAction>,
pub remap: HashMap<Key, ModmapAction>,
pub application: Option<Application>,
}
fn deserialize_remap<'de, D>(deserializer: D) -> Result<HashMap<Key, KeyAction>, D::Error>
fn deserialize_remap<'de, D>(deserializer: D) -> Result<HashMap<Key, ModmapAction>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize, Eq, Hash, PartialEq)]
struct KeyWrapper(#[serde(deserialize_with = "deserialize_key")] Key);
let v = HashMap::<KeyWrapper, KeyAction>::deserialize(deserializer)?;
let v = HashMap::<KeyWrapper, ModmapAction>::deserialize(deserializer)?;
Ok(v.into_iter().map(|(KeyWrapper(k), v)| (k, v)).collect())
}

@ -4,12 +4,12 @@ use serde::{Deserialize, Deserializer};
use serde_with::{serde_as, DurationMilliSeconds};
use std::time::Duration;
use super::action::{Action, Actions};
use super::keymap_action::{Actions, KeymapAction};
// Values in `modmap.remap`
#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum KeyAction {
pub enum ModmapAction {
#[serde(deserialize_with = "deserialize_key")]
Key(Key),
MultiPurposeKey(MultiPurposeKey),
@ -31,12 +31,12 @@ pub struct MultiPurposeKey {
#[derive(Clone, Debug, Deserialize)]
pub struct PressReleaseKey {
#[serde(deserialize_with = "deserialize_actions")]
pub press: Vec<Action>,
pub press: Vec<KeymapAction>,
#[serde(deserialize_with = "deserialize_actions")]
pub release: Vec<Action>,
pub release: Vec<KeymapAction>,
}
pub fn deserialize_actions<'de, D>(deserializer: D) -> Result<Vec<Action>, D::Error>
pub fn deserialize_actions<'de, D>(deserializer: D) -> Result<Vec<KeymapAction>, D::Error>
where
D: Deserializer<'de>,
{

@ -1,16 +1,16 @@
use evdev::Key;
use serde::Deserialize;
use crate::config::action::Action;
use crate::config::key_press::KeyPress;
use crate::config::keymap_action::KeymapAction;
use std::collections::HashMap;
use std::time::Duration;
use super::action::Actions;
use super::keymap_action::Actions;
#[derive(Clone, Debug)]
pub struct Remap {
pub remap: HashMap<KeyPress, Vec<Action>>,
pub remap: HashMap<KeyPress, Vec<KeymapAction>>,
pub timeout: Option<Duration>,
pub timeout_key: Option<Key>,
}

@ -0,0 +1,76 @@
use evdev::{EventType, InputEvent, Key};
// Input to EventHandler. This should only contain things that are easily testable.
#[derive(Debug)]
pub enum Event {
// InputEvent (EventType::KEY) sent from evdev
KeyEvent(KeyEvent),
// Timer for nested override reached its timeout
OverrideTimeout,
}
#[derive(Debug)]
pub struct KeyEvent {
key: Key,
value: KeyValue,
}
#[derive(Debug)]
pub enum KeyValue {
Press,
Release,
Repeat,
}
impl Event {
// Convert evdev's raw InputEvent to xremap's internal Event
pub fn new(event: InputEvent) -> Option<Event> {
let event = match event.event_type() {
EventType::KEY => Event::KeyEvent(KeyEvent::new_with(event.code(), event.value())),
_ => return None,
};
Some(event)
}
}
impl KeyEvent {
// Constructor with newer interface
pub fn new(key: Key, value: KeyValue) -> KeyEvent {
KeyEvent { key, value }
}
// Constructor with legacy interface
pub fn new_with(code: u16, value: i32) -> KeyEvent {
let key = Key::new(code);
let value = KeyValue::new(value).unwrap();
KeyEvent::new(key, value)
}
pub fn code(&self) -> u16 {
self.key.code()
}
pub fn value(&self) -> i32 {
self.value.value()
}
}
impl KeyValue {
fn new(value: i32) -> Option<KeyValue> {
let event_value = match value {
0 => KeyValue::Release,
1 => KeyValue::Press,
2 => KeyValue::Repeat,
_ => return None,
};
Some(event_value)
}
fn value(&self) -> i32 {
match self {
KeyValue::Release => 0,
KeyValue::Press => 1,
KeyValue::Repeat => 2,
}
}
}

@ -1,28 +1,23 @@
use crate::action::Action;
use crate::client::{build_client, WMClient};
use crate::config::action::Action;
use crate::config::application::Application;
use crate::config::key_action::{KeyAction, MultiPurposeKey, PressReleaseKey};
use crate::config::key_press::{KeyPress, Modifier};
use crate::config::keymap::{build_override_table, OverrideEntry};
use crate::config::keymap_action::KeymapAction;
use crate::config::modmap_action::{ModmapAction, MultiPurposeKey, PressReleaseKey};
use crate::config::remap::Remap;
use crate::event::{Event, KeyEvent};
use crate::Config;
use evdev::uinput::VirtualDevice;
use evdev::{EventType, InputEvent, Key};
use evdev::Key;
use lazy_static::lazy_static;
use log::{debug, error};
use nix::sys::signal;
use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet};
use log::debug;
use nix::sys::time::TimeSpec;
use nix::sys::timerfd::{Expiration, TimerFd, TimerSetTimeFlags};
use std::collections::{HashMap, HashSet};
use std::error::Error;
use std::process::{Command, Stdio};
use std::thread;
use std::time::{Duration, Instant};
pub struct EventHandler {
// Device to emit events
device: VirtualDevice,
// Currently pressed modifier keys
modifiers: HashSet<Key>,
// Modifiers that are currently pressed but not in the source KeyPress
@ -40,21 +35,21 @@ pub struct EventHandler {
override_timeout_key: Option<Key>,
// Trigger a timeout of nested remaps through select(2)
override_timer: TimerFd,
// Whether we've called a sigaction for spawing commands or not
sigaction_set: bool,
// { set_mode: String }
mode: String,
// { set_mark: true }
mark_set: bool,
// { escape_next_key: true }
escape_next_key: bool,
// keypress_delay_ms
keypress_delay: Duration,
// Buffered actions to be dispatched. TODO: Just return actions from each function instead of using this.
actions: Vec<Action>,
}
impl EventHandler {
pub fn new(device: VirtualDevice, timer: TimerFd, mode: &str, keypress_delay: Duration) -> EventHandler {
pub fn new(timer: TimerFd, mode: &str, keypress_delay: Duration) -> EventHandler {
EventHandler {
device,
modifiers: HashSet::new(),
extra_modifiers: HashSet::new(),
pressed_keys: HashMap::new(),
@ -64,16 +59,25 @@ impl EventHandler {
override_remap: None,
override_timeout_key: None,
override_timer: timer,
sigaction_set: false,
mode: mode.to_string(),
mark_set: false,
escape_next_key: false,
keypress_delay,
actions: vec![],
}
}
// Handle an Event and return Actions. This should be the only public method of EventHandler.
pub fn on_event(&mut self, event: &Event, config: &Config) -> Result<Vec<Action>, Box<dyn Error>> {
match event {
Event::KeyEvent(key_event) => self.on_key_event(key_event, config),
Event::OverrideTimeout => self.timeout_override(),
}?;
Ok(self.actions.drain(..).collect())
}
// Handle EventType::KEY
pub fn on_event(&mut self, event: InputEvent, config: &Config) -> Result<(), Box<dyn Error>> {
fn on_key_event(&mut self, event: &KeyEvent, config: &Config) -> Result<(), Box<dyn Error>> {
self.application_cache = None; // expire cache
let key = Key::new(event.code());
debug!("=> {}: {:?}", event.value(), &key);
@ -104,22 +108,15 @@ impl EventHandler {
continue;
}
}
self.send_key(&key, value)?;
self.send_key(&key, value);
}
Ok(())
}
pub fn send_event(&mut self, event: InputEvent) -> std::io::Result<()> {
if event.event_type() == EventType::KEY {
debug!("{}: {:?}", event.value(), Key::new(event.code()))
}
self.device.emit(&[event])
}
pub fn timeout_override(&mut self) -> Result<(), Box<dyn Error>> {
fn timeout_override(&mut self) -> Result<(), Box<dyn Error>> {
if let Some(key) = self.override_timeout_key {
self.send_key(&key, PRESS)?;
self.send_key(&key, RELEASE)?;
self.send_key(&key, PRESS);
self.send_key(&key, RELEASE);
}
self.remove_override()
}
@ -131,16 +128,20 @@ impl EventHandler {
Ok(())
}
fn send_keys(&mut self, keys: &Vec<Key>, value: i32) -> std::io::Result<()> {
fn send_keys(&mut self, keys: &Vec<Key>, value: i32) {
for key in keys {
self.send_key(key, value)?;
self.send_key(key, value);
}
Ok(())
}
fn send_key(&mut self, key: &Key, value: i32) -> std::io::Result<()> {
let event = InputEvent::new(EventType::KEY, key.code(), value);
self.send_event(event)
fn send_key(&mut self, key: &Key, value: i32) {
//let event = InputEvent::new(EventType::KEY, key.code(), value);
let event = KeyEvent::new_with(key.code(), value);
self.send_action(Action::KeyEvent(event));
}
fn send_action(&mut self, action: Action) {
self.actions.push(action);
}
// Repeat/Release what's originally pressed even if remapping changes while holding it
@ -165,13 +166,13 @@ impl EventHandler {
fn dispatch_keys(
&mut self,
key_action: KeyAction,
key_action: ModmapAction,
key: Key,
value: i32,
) -> Result<Vec<(Key, i32)>, Box<dyn Error>> {
let keys = match key_action {
KeyAction::Key(modmap_key) => vec![(modmap_key, value)],
KeyAction::MultiPurposeKey(MultiPurposeKey {
ModmapAction::Key(modmap_key) => vec![(modmap_key, value)],
ModmapAction::MultiPurposeKey(MultiPurposeKey {
held,
alone,
alone_timeout,
@ -200,7 +201,7 @@ impl EventHandler {
// fallthrough on state discrepancy
vec![(key, value)]
}
KeyAction::PressReleaseKey(PressReleaseKey { press, release }) => {
ModmapAction::PressReleaseKey(PressReleaseKey { press, release }) => {
// Just hook actions, and then emit the original event. We might want to
// support reordering the key event and dispatched actions later.
if value == PRESS {
@ -237,7 +238,7 @@ impl EventHandler {
}
}
fn find_modmap(&mut self, config: &Config, key: &Key) -> Option<KeyAction> {
fn find_modmap(&mut self, config: &Config, key: &Key) -> Option<ModmapAction> {
for modmap in &config.modmap {
if let Some(key_action) = modmap.remap.get(key) {
if let Some(application_matcher) = &modmap.application {
@ -251,7 +252,7 @@ impl EventHandler {
None
}
fn find_keymap(&mut self, config: &Config, key: &Key) -> Result<Option<Vec<Action>>, Box<dyn Error>> {
fn find_keymap(&mut self, config: &Config, key: &Key) -> Result<Option<Vec<KeymapAction>>, Box<dyn Error>> {
if let Some(override_remap) = &self.override_remap {
if let Some(entries) = override_remap.clone().get(key) {
self.remove_override()?;
@ -292,17 +293,17 @@ impl EventHandler {
Ok(None)
}
fn dispatch_actions(&mut self, actions: &Vec<Action>, key: &Key) -> Result<(), Box<dyn Error>> {
fn dispatch_actions(&mut self, actions: &Vec<KeymapAction>, key: &Key) -> Result<(), Box<dyn Error>> {
for action in actions {
self.dispatch_action(action, key)?;
}
Ok(())
}
fn dispatch_action(&mut self, action: &Action, key: &Key) -> Result<(), Box<dyn Error>> {
fn dispatch_action(&mut self, action: &KeymapAction, key: &Key) -> Result<(), Box<dyn Error>> {
match action {
Action::KeyPress(key_press) => self.send_key_press(key_press)?,
Action::Remap(Remap {
KeymapAction::KeyPress(key_press) => self.send_key_press(key_press),
KeymapAction::Remap(Remap {
remap,
timeout,
timeout_key,
@ -310,20 +311,21 @@ impl EventHandler {
self.override_remap = Some(build_override_table(remap));
if let Some(timeout) = timeout {
let expiration = Expiration::OneShot(TimeSpec::from_duration(*timeout));
// TODO: Consider handling the timer in ActionDispatcher
self.override_timer.unset()?;
self.override_timer.set(expiration, TimerSetTimeFlags::empty())?;
self.override_timeout_key = timeout_key.or_else(|| Some(*key));
}
}
Action::Launch(command) => self.run_command(command.clone()),
Action::SetMode(mode) => {
KeymapAction::Launch(command) => self.run_command(command.clone()),
KeymapAction::SetMode(mode) => {
self.mode = mode.clone();
println!("mode: {}", mode);
}
Action::SetMark(set) => self.mark_set = *set,
Action::WithMark(key_press) => self.send_key_press(&self.with_mark(key_press))?,
Action::EscapeNextKey(escape_next_key) => self.escape_next_key = *escape_next_key,
Action::SetExtraModifiers(keys) => {
KeymapAction::SetMark(set) => self.mark_set = *set,
KeymapAction::WithMark(key_press) => self.send_key_press(&self.with_mark(key_press)),
KeymapAction::EscapeNextKey(escape_next_key) => self.escape_next_key = *escape_next_key,
KeymapAction::SetExtraModifiers(keys) => {
self.extra_modifiers.clear();
for key in keys {
self.extra_modifiers.insert(*key);
@ -333,7 +335,7 @@ impl EventHandler {
Ok(())
}
fn send_key_press(&mut self, key_press: &KeyPress) -> Result<(), Box<dyn Error>> {
fn send_key_press(&mut self, key_press: &KeyPress) {
// Build extra or missing modifiers. Note that only MODIFIER_KEYS are handled
// because logical modifiers shouldn't make an impact outside xremap.
let (mut extra_modifiers, mut missing_modifiers) = self.diff_modifiers(&key_press.modifiers);
@ -341,20 +343,18 @@ impl EventHandler {
missing_modifiers.retain(|key| MODIFIER_KEYS.contains(&key));
// Emulate the modifiers of KeyPress
self.send_keys(&extra_modifiers, RELEASE)?;
self.send_keys(&missing_modifiers, PRESS)?;
self.send_keys(&extra_modifiers, RELEASE);
self.send_keys(&missing_modifiers, PRESS);
// Press the main key
self.send_key(&key_press.key, PRESS)?;
self.send_key(&key_press.key, RELEASE)?;
self.send_key(&key_press.key, PRESS);
self.send_key(&key_press.key, RELEASE);
thread::sleep(self.keypress_delay);
self.send_action(Action::Delay(self.keypress_delay));
// Resurrect the original modifiers
self.send_keys(&missing_modifiers, RELEASE)?;
self.send_keys(&extra_modifiers, PRESS)?;
Ok(())
self.send_keys(&missing_modifiers, RELEASE);
self.send_keys(&extra_modifiers, PRESS);
}
fn with_mark(&self, key_press: &KeyPress) -> KeyPress {
@ -371,26 +371,7 @@ impl EventHandler {
}
fn run_command(&mut self, command: Vec<String>) {
if !self.sigaction_set {
// Avoid defunct processes
let sig_action = SigAction::new(SigHandler::SigDfl, SaFlags::SA_NOCLDWAIT, SigSet::empty());
unsafe {
sigaction(signal::SIGCHLD, &sig_action).expect("Failed to register SIGCHLD handler");
}
self.sigaction_set = true;
}
debug!("Running command: {:?}", command);
match Command::new(&command[0])
.args(&command[1..])
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
{
Ok(child) => debug!("Process spawned: {:?}, pid {}", command, child.id()),
Err(e) => error!("Error running command: {:?}", e),
}
self.send_action(Action::Command(command));
}
// Return (extra_modifiers, missing_modifiers)
@ -465,16 +446,16 @@ impl EventHandler {
}
}
fn with_extra_modifiers(actions: &Vec<Action>, extra_modifiers: &Vec<Key>) -> Vec<Action> {
let mut result: Vec<Action> = vec![];
fn with_extra_modifiers(actions: &Vec<KeymapAction>, extra_modifiers: &Vec<Key>) -> Vec<KeymapAction> {
let mut result: Vec<KeymapAction> = vec![];
if extra_modifiers.len() > 0 {
// Virtually release extra modifiers so that they won't be physically released on KeyPress
result.push(Action::SetExtraModifiers(extra_modifiers.clone()));
result.push(KeymapAction::SetExtraModifiers(extra_modifiers.clone()));
}
result.extend(actions.clone());
if extra_modifiers.len() > 0 {
// Resurrect the modifier status
result.push(Action::SetExtraModifiers(vec![]));
result.push(KeymapAction::SetExtraModifiers(vec![]));
}
return result;
}

@ -1,12 +1,14 @@
use crate::config::Config;
use crate::device::{device_watcher, get_input_devices, output_device};
use crate::event_handler::EventHandler;
use action::Action;
use action_dispatcher::ActionDispatcher;
use anyhow::{anyhow, bail, Context};
use clap::{AppSettings, ArgEnum, IntoApp, Parser};
use clap_complete::Shell;
use config::{config_watcher, load_config};
use device::InputDevice;
use evdev::EventType;
use event::Event;
use nix::libc::ENODEV;
use nix::sys::inotify::{AddWatchFlags, Inotify, InotifyEvent};
use nix::sys::select::select;
@ -18,10 +20,15 @@ use std::os::unix::io::{AsRawFd, RawFd};
use std::path::{Path, PathBuf};
use std::time::Duration;
mod action;
mod action_dispatcher;
mod client;
mod config;
mod device;
mod event;
mod event_handler;
#[cfg(test)]
mod tests;
#[derive(Parser, Debug)]
#[clap(version, global_setting(AppSettings::DeriveDisplayOrder))]
@ -48,7 +55,7 @@ struct Opts {
default_missing_value = "device",
verbatim_doc_comment,
hide_possible_values = true,
// Separating the help like this is necessary due to
// Separating the help like this is necessary due to
// https://github.com/clap-rs/clap/issues/3312
help = "Targets to watch [possible values: device, config]"
)]
@ -73,7 +80,8 @@ enum WatchTargets {
Config,
}
enum Event {
// TODO: Unify this with Event
enum ReloadEvent {
ReloadConfig,
ReloadDevices,
}
@ -115,28 +123,31 @@ fn main() -> anyhow::Result<()> {
let device_watcher = device_watcher(watch_devices).context("Setting up device watcher")?;
let config_watcher = config_watcher(watch_config, &config_path).context("Setting up config watcher")?;
let watchers: Vec<_> = device_watcher.iter().chain(config_watcher.iter()).collect();
let mut handler = EventHandler::new(timer, &config.default_mode, delay);
let output_device = match output_device(input_devices.values().next().map(InputDevice::bus_type)) {
Ok(output_device) => output_device,
Err(e) => bail!("Failed to prepare an output device: {}", e),
};
let mut handler = EventHandler::new(output_device, timer, &config.default_mode, delay);
let mut dispatcher = ActionDispatcher::new(output_device);
// Main loop
loop {
match 'event_loop: loop {
let readable_fds = select_readable(input_devices.values(), &watchers, timer_fd)?;
if readable_fds.contains(timer_fd) {
if let Err(error) = handler.timeout_override() {
if let Err(error) = handle_event(&mut handler, &mut dispatcher, &mut config, Event::OverrideTimeout) {
println!("Error on remap timeout: {error}")
}
}
for input_device in input_devices.values_mut() {
if readable_fds.contains(input_device.as_raw_fd())
&& !handle_input_events(input_device, &mut handler, &mut config)?
{
if !readable_fds.contains(input_device.as_raw_fd()) {
continue;
}
if !handle_input_events(input_device, &mut handler, &mut dispatcher, &mut config)? {
println!("Found a removed device. Reselecting devices.");
break 'event_loop Event::ReloadDevices;
break 'event_loop ReloadEvent::ReloadDevices;
}
}
@ -155,12 +166,12 @@ fn main() -> anyhow::Result<()> {
mouse,
&config_path,
)? {
break 'event_loop Event::ReloadConfig;
break 'event_loop ReloadEvent::ReloadConfig;
}
}
}
} {
Event::ReloadDevices => {
ReloadEvent::ReloadDevices => {
for input_device in input_devices.values_mut() {
input_device.ungrab();
}
@ -169,15 +180,17 @@ fn main() -> anyhow::Result<()> {
Err(e) => bail!("Failed to prepare input devices: {}", e),
};
}
Event::ReloadConfig => match (config.modify_time, config_path.metadata().and_then(|m| m.modified())) {
(Some(last_mtime), Ok(current_mtim)) if last_mtime == current_mtim => continue,
_ => {
if let Ok(c) = load_config(&config_path) {
println!("Reloading Config");
config = c;
ReloadEvent::ReloadConfig => {
match (config.modify_time, config_path.metadata().and_then(|m| m.modified())) {
(Some(last_mtime), Ok(current_mtim)) if last_mtime == current_mtim => continue,
_ => {
if let Ok(c) = load_config(&config_path) {
println!("Reloading Config");
config = c;
}
}
}
},
}
}
}
}
@ -199,9 +212,11 @@ fn select_readable<'a>(
Ok(read_fds)
}
// Return false when a removed device is found.
fn handle_input_events(
input_device: &mut InputDevice,
handler: &mut EventHandler,
dispatcher: &mut ActionDispatcher,
config: &mut Config,
) -> anyhow::Result<bool> {
match input_device.fetch_events().map_err(|e| (e.raw_os_error(), e)) {
@ -209,12 +224,10 @@ fn handle_input_events(
Err((_, error)) => Err(error).context("Error fetching input events"),
Ok(events) => {
for event in events {
if event.event_type() == EventType::KEY {
handler
.on_event(event, config)
.map_err(|e| anyhow!("Failed handling {event:?}:\n {e:?}"))?;
if let Some(event) = Event::new(event) {
handle_event(handler, dispatcher, config, event)?;
} else {
handler.send_event(event)?;
dispatcher.on_action(Action::InputEvent(event))?;
}
}
Ok(true)
@ -222,6 +235,22 @@ fn handle_input_events(
}
}
// Handle an Event with EventHandler, and dispatch Actions with ActionDispatcher
fn handle_event(
handler: &mut EventHandler,
dispatcher: &mut ActionDispatcher,
config: &mut Config,
event: Event,
) -> anyhow::Result<()> {
let actions = handler
.on_event(&event, config)
.map_err(|e| anyhow!("Failed handling {event:?}:\n {e:?}"))?;
for action in actions {
dispatcher.on_action(action)?;
}
Ok(())
}
fn handle_device_changes(
events: Vec<InotifyEvent>,
input_devices: &mut HashMap<PathBuf, InputDevice>,

@ -0,0 +1,35 @@
use evdev::Key;
use indoc::indoc;
use nix::sys::timerfd::{ClockId, TimerFd, TimerFlags};
use std::time::Duration;
use crate::{
action::Action,
config::Config,
event::{Event, KeyEvent, KeyValue},
event_handler::EventHandler,
};
#[test]
fn test_basic_modmap() {
assert_actions(
indoc! {"
modmap:
- remap:
a: b
"},
vec![Event::KeyEvent(KeyEvent::new(Key::KEY_A, KeyValue::Press))],
vec![Action::KeyEvent(KeyEvent::new(Key::KEY_B, KeyValue::Press))],
)
}
fn assert_actions(config_yaml: &str, events: Vec<Event>, actions: Vec<Action>) {
let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap();
let config: Config = serde_yaml::from_str(config_yaml).unwrap();
let mut event_handler = EventHandler::new(timer, "default", Duration::from_micros(0));
let mut actual: Vec<Action> = vec![];
for event in &events {
actual.append(&mut event_handler.on_event(event, &config).unwrap());
}
assert_eq!(format!("{:?}", actions), format!("{:?}", actual));
}
Loading…
Cancel
Save