Refactor module boundaries

This commit is contained in:
Takashi Kokubun 2021-12-27 21:49:14 -08:00
parent 94e91d9f6a
commit 9f69ef8bb6
No known key found for this signature in database
GPG Key ID: 6FFC433B12EE23DD
4 changed files with 95 additions and 94 deletions

View File

@ -1,44 +1,56 @@
extern crate evdev;
extern crate nix;
use crate::event_handler::EventHandler;
use crate::output::build_device;
use crate::Config;
use evdev::{Device, EventType, Key};
use nix::sys::select::select;
use nix::sys::select::FdSet;
use evdev::uinput::{VirtualDevice, VirtualDeviceBuilder};
use evdev::{AttributeSet, Device, Key, RelativeAxisType};
use std::collections::HashMap;
use std::error::Error;
use std::fs::read_dir;
use std::os::unix::ffi::OsStrExt;
use std::os::unix::io::AsRawFd;
pub fn event_loop(mut input_devices: Vec<Device>, config: &Config) -> Result<(), Box<dyn Error>> {
for device in &mut input_devices {
device
.grab()
.map_err(|e| format!("Failed to grab device '{}': {}", device_name(device), e))?;
}
let output_device = build_device().map_err(|e| format!("Failed to build an output device: {}", e))?;
static MOUSE_BTNS: [&str; 13] = [
"BTN_0",
"BTN_1",
"BTN_2",
"BTN_3",
"BTN_4",
"BTN_5",
"BTN_6",
"BTN_7",
"BTN_8",
"BTN_9",
"BTN_LEFT",
"BTN_MIDDLE",
"BTN_RIGHT",
];
let mut handler = EventHandler::new(output_device);
loop {
let readable_fds = select_readable(&input_devices)?;
for input_device in &mut input_devices {
if readable_fds.contains(input_device.as_raw_fd()) {
for event in input_device.fetch_events()? {
if event.event_type() == EventType::KEY {
handler.on_event(event, config)?;
} else {
handler.send_event(event)?;
}
}
}
// Credit: https://github.com/mooz/xkeysnail/blob/master/xkeysnail/output.py#L10-L32
pub fn output_device() -> Result<VirtualDevice, Box<dyn Error>> {
let mut keys: AttributeSet<Key> = AttributeSet::new();
for code in Key::KEY_RESERVED.code()..Key::BTN_TRIGGER_HAPPY40.code() {
let key = Key::new(code);
let name = format!("{:?}", key);
if name.starts_with("KEY_") || MOUSE_BTNS.contains(&&**&name) {
keys.insert(key);
}
}
let mut relative_axes: AttributeSet<RelativeAxisType> = AttributeSet::new();
relative_axes.insert(RelativeAxisType::REL_X);
relative_axes.insert(RelativeAxisType::REL_Y);
relative_axes.insert(RelativeAxisType::REL_HWHEEL);
relative_axes.insert(RelativeAxisType::REL_WHEEL);
relative_axes.insert(RelativeAxisType::REL_MISC);
let device = VirtualDeviceBuilder::new()?
.name("xremap")
.with_keys(&keys)?
.with_relative_axes(&relative_axes)?
.build()?;
Ok(device)
}
pub fn select_device(device_opts: &Vec<String>) -> Result<Vec<Device>, Box<dyn Error>> {
pub fn input_devices(device_opts: &Vec<String>) -> Result<Vec<Device>, Box<dyn Error>> {
let mut path_devices = list_devices()?;
let mut paths: Vec<String> = path_devices.keys().map(|e| e.clone()).collect();
paths.sort_by(|a, b| device_index(a).partial_cmp(&device_index(b)).unwrap());
@ -76,16 +88,13 @@ pub fn select_device(device_opts: &Vec<String>) -> Result<Vec<Device>, Box<dyn E
}
println!("{}", SEPARATOR);
return Ok(path_devices.into_values().collect());
}
fn select_readable(devices: &Vec<Device>) -> Result<FdSet, Box<dyn Error>> {
let mut read_fds = FdSet::new();
for device in devices {
read_fds.insert(device.as_raw_fd());
let mut devices: Vec<Device> = path_devices.into_values().collect();
for device in devices.iter_mut() {
device
.grab()
.map_err(|e| format!("Failed to grab device '{}': {}", device_name(device), e))?;
}
select(None, &mut read_fds, None, None, None)?;
return Ok(read_fds);
return Ok(devices);
}
// We can't know the device path from evdev::enumerate(). So we re-implement it.

View File

@ -5,14 +5,48 @@ use crate::config::key_action::KeyAction;
use crate::config::key_press::{KeyPress, Modifier};
use crate::Config;
use evdev::uinput::VirtualDevice;
use evdev::{EventType, InputEvent, Key};
use evdev::{Device, EventType, InputEvent, Key};
use lazy_static::lazy_static;
use log::debug;
use nix::sys::select::select;
use nix::sys::select::FdSet;
use std::collections::HashMap;
use std::error::Error;
use std::os::unix::io::AsRawFd;
use std::time::Instant;
pub struct EventHandler {
pub fn event_loop(
mut input_devices: Vec<Device>,
output_device: VirtualDevice,
config: &Config,
) -> Result<(), Box<dyn Error>> {
let mut handler = EventHandler::new(output_device);
loop {
let readable_fds = select_readable(&input_devices)?;
for input_device in &mut input_devices {
if readable_fds.contains(input_device.as_raw_fd()) {
for event in input_device.fetch_events()? {
if event.event_type() == EventType::KEY {
handler.on_event(event, config)?;
} else {
handler.send_event(event)?;
}
}
}
}
}
}
fn select_readable(devices: &Vec<Device>) -> Result<FdSet, Box<dyn Error>> {
let mut read_fds = FdSet::new();
for device in devices {
read_fds.insert(device.as_raw_fd());
}
select(None, &mut read_fds, None, None, None)?;
return Ok(read_fds);
}
struct EventHandler {
device: VirtualDevice,
wm_client: WMClient,
multi_purpose_keys: HashMap<Key, MultiPurposeKeyState>,
@ -25,7 +59,7 @@ pub struct EventHandler {
}
impl EventHandler {
pub fn new(device: VirtualDevice) -> EventHandler {
fn new(device: VirtualDevice) -> EventHandler {
EventHandler {
device,
wm_client: build_client(),
@ -40,7 +74,7 @@ impl EventHandler {
}
// Handle EventType::KEY
pub fn on_event(&mut self, event: InputEvent, config: &Config) -> Result<(), Box<dyn Error>> {
fn on_event(&mut self, event: InputEvent, config: &Config) -> Result<(), Box<dyn Error>> {
self.application_cache = None; // expire cache
let key = Key::new(event.code());
debug!("=> {}: {:?}", event.value(), &key);
@ -70,7 +104,7 @@ impl EventHandler {
Ok(())
}
pub fn send_event(&mut self, event: InputEvent) -> std::io::Result<()> {
fn send_event(&mut self, event: InputEvent) -> std::io::Result<()> {
if event.event_type() == EventType::KEY {
debug!("{}: {:?}", event.value(), Key::new(event.code()))
}

View File

@ -1,5 +1,6 @@
use crate::config::Config;
use crate::input::{event_loop, select_device};
use crate::device::{input_devices, output_device};
use crate::event_handler::event_loop;
use getopts::Options;
use std::env;
use std::process::exit;
@ -8,9 +9,8 @@ extern crate getopts;
mod client;
mod config;
mod device;
mod event_handler;
mod input;
mod output;
fn usage(program: &str, opts: Options) -> String {
let brief = format!("Usage: {} CONFIG [options]", program);
@ -49,13 +49,16 @@ fn main() {
Err(e) => abort(&format!("Failed to load config '{}': {}", filename, e)),
};
let devices = args.opt_strs("device");
let input_devices = match select_device(&devices) {
let input_devices = match input_devices(&args.opt_strs("device")) {
Ok(input_devices) => input_devices,
Err(e) => abort(&format!("Failed to select devices: {}", e)),
Err(e) => abort(&format!("Failed to prepare input devices: {}", e)),
};
let output_device = match output_device() {
Ok(output_device) => output_device,
Err(e) => abort(&format!("Failed to prepare an output device: {}", e)),
};
if let Err(e) = event_loop(input_devices, &config) {
if let Err(e) = event_loop(input_devices, output_device, &config) {
abort(&format!("Error: {}", e));
}
}

View File

@ -1,45 +0,0 @@
use evdev::uinput::{VirtualDevice, VirtualDeviceBuilder};
use evdev::{AttributeSet, Key, RelativeAxisType};
use std::error::Error;
static MOUSE_BTNS: [&str; 13] = [
"BTN_0",
"BTN_1",
"BTN_2",
"BTN_3",
"BTN_4",
"BTN_5",
"BTN_6",
"BTN_7",
"BTN_8",
"BTN_9",
"BTN_LEFT",
"BTN_MIDDLE",
"BTN_RIGHT",
];
// Credit: https://github.com/mooz/xkeysnail/blob/master/xkeysnail/output.py#L10-L32
pub fn build_device() -> Result<VirtualDevice, Box<dyn Error>> {
let mut keys: AttributeSet<Key> = AttributeSet::new();
for code in Key::KEY_RESERVED.code()..Key::BTN_TRIGGER_HAPPY40.code() {
let key = Key::new(code);
let name = format!("{:?}", key);
if name.starts_with("KEY_") || MOUSE_BTNS.contains(&&**&name) {
keys.insert(key);
}
}
let mut relative_axes: AttributeSet<RelativeAxisType> = AttributeSet::new();
relative_axes.insert(RelativeAxisType::REL_X);
relative_axes.insert(RelativeAxisType::REL_Y);
relative_axes.insert(RelativeAxisType::REL_HWHEEL);
relative_axes.insert(RelativeAxisType::REL_WHEEL);
relative_axes.insert(RelativeAxisType::REL_MISC);
let device = VirtualDeviceBuilder::new()?
.name("xremap")
.with_keys(&keys)?
.with_relative_axes(&relative_axes)?
.build()?;
Ok(device)
}