mirror of https://github.com/k0kubun/xremap
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 fmtpull/203/head
parent
763b1b8746
commit
d02446a040
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
@ -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…
Reference in New Issue