From ca28b969829e17b33a9d87c0e16dbf2ea3c68c3f Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Thu, 16 Nov 2017 00:13:46 -0500 Subject: [PATCH] All threads now send input to a single mapping/output device --- src/error.rs | 14 +++++ src/main.rs | 166 ++++++++++++++++++++++++++------------------------- 2 files changed, 98 insertions(+), 82 deletions(-) diff --git a/src/error.rs b/src/error.rs index ca15cfc..a5d2727 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,11 +2,14 @@ use std::fmt; use std::error; use std::ffi; use std::io; +use std::sync::mpsc; use nix; #[cfg(feature = "udev")] use udev; +use libc; + /// UInput error. #[derive(Debug)] pub enum Error { @@ -22,6 +25,8 @@ pub enum Error { Io(io::Error), + Send(mpsc::SendError), + /// The uinput file could not be found. NotFound, @@ -54,6 +59,12 @@ impl From for Error { } } +impl From> for Error { + fn from(value: mpsc::SendError) -> Self { + Error::Send(value) + } +} + impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.write_str(error::Error::description(self)) @@ -76,6 +87,9 @@ impl error::Error for Error { &Error::Io(ref err) => err.description(), + &Error::Send(ref err) => + err.description(), + &Error::NotFound => "Device not found.", diff --git a/src/main.rs b/src/main.rs index 1a9226e..85192c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,8 +20,8 @@ use std::fs::File; use std::io::Read; use std::{env, mem}; use std::thread; -use std::sync::{Arc, mpsc}; -use std::collections::HashMap; +use std::sync::mpsc; +use std::sync::mpsc::Sender; use std::os::unix::io::AsRawFd; @@ -50,88 +50,16 @@ impl Config { } fn main() { + main_res().ok(); +} + +fn main_res() -> Result<()> { let config = parse_args(); //println!("Config: {:?}", config); - let key_map = Arc::new(KeyMaps::key_map()); + let key_map = KeyMaps::key_map(); //println!("key_map: {:?}", key_map); - if config.device_files.len() > 0 { - // we only want to operate on device files sent in then quit - let (tx, rx) = mpsc::channel(); - - for device_file in config.device_files.iter() { - let device_file = device_file.clone(); - let config_file = config.config_file.clone(); - let tx = tx.clone(); - let key_map = Arc::clone(&key_map); - thread::spawn(move || { - let ret = spawn_map_thread(key_map, &device_file, &config_file); - if let Err(e) = ret { - println!("mapping for {} ended due to error: {}", device_file, e); - } - tx.send(1).ok(); - }); - } - // wait for all threads to finish - let mut num_threads = config.device_files.len(); - for received in rx { - num_threads -= received; - if num_threads == 0 { - break; - } - } - } else { - // we want to wait forever starting new threads for any new keyboard devices - let mut inotify = Inotify::init().expect("Failed to initialize inotify"); - - inotify.add_watch("/dev/input/", WatchMask::CREATE).expect("Failed to add inotify watch"); - - let device_files = get_keyboard_device_filenames(); - println!("Detected devices: {:?}", device_files); - for device_file in device_files.iter() { - inotify_spawn_thread(&key_map, device_file, config.config_file.clone()); - } - - let mut buffer = [0u8; 4096]; - loop { - let events = inotify.read_events_blocking(&mut buffer); - - if let Ok(events) = events { - for event in events { - if !event.mask.contains(EventMask::ISDIR) { - if let Some(device_file) = event.name.and_then(|name|name.to_str()) { - // check if this is an eligible keyboard device - let device_files = get_keyboard_device_filenames(); - if !device_files.contains(&device_file.to_string()) { - continue; - } - println!("starting mapping thread for: {}", device_file); - inotify_spawn_thread(&key_map, device_file.clone(), config.config_file.clone()); - } - } - } - } - } - } -} - -fn inotify_spawn_thread(key_map: &Arc>, device_file: &str, config_file: String) { - let mut filename = "/dev/input/".to_string(); - filename.push_str(&device_file); - let key_map = Arc::clone(&key_map); - thread::spawn(move || { - let ret = spawn_map_thread(key_map, &filename, &config_file); - if let Err(e) = ret { - println!("mapping for {} ended due to error: {}", filename, e); - } - }); -} - -fn spawn_map_thread(key_map: Arc>, device_file: &str, config_file: &str) -> Result<()> { - let mut input_device = InputDevice::open(device_file)?; - input_device.grab()?; - let device = rusty_keys::open("/dev/uinput") .or_else(|_| rusty_keys::open("/dev/input/uinput")) .or_else(|_| rusty_keys::default())? @@ -139,17 +67,91 @@ fn spawn_map_thread(key_map: Arc>, device_file: &st .event(key_map.values())? .create()?; - let mut key_map = KeyMaps::from_cfg(&key_map, config_file); + let mut key_map = KeyMaps::from_cfg(&key_map, &config.config_file); //println!("keymaps: {:?}", keymaps); - loop { - let mut event = input_device.read_event()?; + let (tx, rx) = mpsc::channel(); + + if config.device_files.len() > 0 { + // we only want to operate on device files sent in then quit + for device_file in config.device_files.iter() { + let device_file = device_file.clone(); + let tx = tx.clone(); + thread::spawn(move || { + let ret = spawn_map_thread(tx, &device_file); + if let Err(e) = ret { + println!("mapping for {} ended due to error: {}", device_file, e); + } + }); + } + } else { + let tx = tx.clone(); + thread::spawn(move || { + // we want to wait forever starting new threads for any new keyboard devices + let mut inotify = Inotify::init().expect("Failed to initialize inotify"); + + inotify.add_watch("/dev/input/", WatchMask::CREATE).expect("Failed to add inotify watch"); + + let device_files = get_keyboard_device_filenames(); + println!("Detected devices: {:?}", device_files); + for device_file in device_files.iter() { + inotify_spawn_thread(&tx, device_file); + } + + let mut buffer = [0u8; 4096]; + loop { + let events = inotify.read_events_blocking(&mut buffer); + + if let Ok(events) = events { + for event in events { + if !event.mask.contains(EventMask::ISDIR) { + if let Some(device_file) = event.name.and_then(|name|name.to_str()) { + // check if this is an eligible keyboard device + let device_files = get_keyboard_device_filenames(); + if !device_files.contains(&device_file.to_string()) { + continue; + } + println!("starting mapping thread for: {}", device_file); + inotify_spawn_thread(&tx, device_file.clone()); + } + } + } + } + } + }); + } + drop(tx); // drop our last one, so when the threads finish, everything stops + // process all events + for mut event in rx { if event.type_ == EV_KEY_U16 { key_map.send_event(&mut event, &device)? } else { device.write_event(&mut event)? } } + Ok(()) +} + +fn inotify_spawn_thread(tx: &Sender, device_file: &str) { + let mut filename = "/dev/input/".to_string(); + filename.push_str(&device_file); + let tx = tx.clone(); + thread::spawn(move || { + let ret = spawn_map_thread(tx, &filename); + if let Err(e) = ret { + println!("mapping for {} ended due to error: {}", filename, e); + } + }); +} + +fn spawn_map_thread(tx: Sender, device_file: &str) -> Result<()> { + let mut input_device = InputDevice::open(device_file)?; + input_device.grab()?; + + loop { + let event = input_device.read_event()?; + tx.send(event)? + } } fn parse_args() -> Config {