diff --git a/src/hw_device.rs b/src/hw_device.rs index def4d30..810e6b9 100644 --- a/src/hw_device.rs +++ b/src/hw_device.rs @@ -1,20 +1,127 @@ +use std::thread; use std::fs::File; +use std::time::Duration; + +use evdev_rs::util::event_code_to_int; +use evdev_rs::enums::EventType::EV_REL; + +use crossbeam::crossbeam_channel::{unbounded, Select, Receiver, Sender}; + +use super::event::ThreadInputEvent; pub struct HwDevice { - pub device: evdev_rs::Device, - _file: File, + pub path: String, + // pub device: evdev_rs::Device, + pub event_channel: Receiver, + stop_channel: Sender, } impl HwDevice { - pub fn new(path: &str) -> Self { - let f = File::open(path).unwrap(); - let mut d = evdev_rs::Device::new().unwrap(); - d.set_fd(&f).unwrap(); + pub fn new(device_path: &str) -> Self { + // send out input events, receive stop command + let (send_event_channel, recv_event_channel) = unbounded(); + let (send_stop_channel, recv_stop_channel) = unbounded(); + + // thread safety and stuff + let path = String::from(device_path); + let return_device_path = path.clone(); + + thread::spawn(move || { + // open device + let fd = File::open(path).unwrap(); + let mut dev = evdev_rs::Device::new().unwrap(); + dev.set_fd(&fd).unwrap(); + // wait for device init + thread::sleep(Duration::from_secs(1)); + // don't deliver events elsewhere + dev.grab(evdev_rs::GrabMode::Grab).unwrap(); + // sleep for testing purposes + thread::sleep(Duration::from_secs(1)); + + // cache mouse movement before consuming all events + let mut mouse_move = vec![0, 0]; + loop { + if stop_requested(&recv_stop_channel) { + break; + } + + loop { + let mut event = dev.next_event(evdev_rs::NORMAL | evdev_rs::BLOCKING); + let mut first = true; + // pending events not required for first round + while first || dev.has_event_pending() { + first = false; + match event { + // send input event to event channel + Ok(e) => { + let e = ThreadInputEvent { + typ: e.1.event_type as u32, + code: event_code_to_int(&e.1.event_code).1, + value: e.1.value, + }; + // EV_REL, REL_X/REL_Y + if e.typ == 2 && e.code <= 1 { + mouse_move[e.code as usize] += e.value; + } else { + send_event_channel.send(e).unwrap(); + } + }, + Err(_) => (), + } + // read next input event + event = dev.next_event(evdev_rs::NORMAL | evdev_rs::BLOCKING); + } + // combined mouse event + send_combined_mouse_move(&mut mouse_move, &send_event_channel); + // save cpu by sleeping after consuming all events + thread::sleep(Duration::from_millis(5)); + } + } + }); HwDevice { - device: d, - // keep fd open - _file: f, + path: return_device_path, + event_channel: recv_event_channel, + stop_channel: send_stop_channel, + } + } + + pub fn stop(&mut self) { + self.stop_channel.send(true).unwrap(); + } +} + +fn stop_requested(chan: &Receiver) -> bool { + // check for stop requests + let mut sel = Select::new(); + // create stop channel receive operation + let oper1 = sel.recv(&chan); + // try to select from stop channel + let oper = sel.try_select(); + match oper { + // no stop requests + Err(_) => false, + // stop request received, break out of the loop + Ok(oper) => match oper.index() { + i if i == oper1 => { + oper.recv(&chan).unwrap() + }, + // shouldn't happen + _ => false, + }, + } +} + +fn send_combined_mouse_move(mouse_move: &mut Vec, chan: &Sender) { + // REL_X..=REL_Y + for code in 0..=1 { + if mouse_move[code] != 0 { + chan.send(ThreadInputEvent { + typ: EV_REL as u32, + code: code as u32, + value: mouse_move[code], + }).unwrap(); + mouse_move[code] = 0; } } } diff --git a/src/input_thread.rs b/src/input_thread.rs deleted file mode 100644 index eb02099..0000000 --- a/src/input_thread.rs +++ /dev/null @@ -1,108 +0,0 @@ -use std::thread; -use std::time::Duration; - -use evdev_rs::util::event_code_to_int; -use evdev_rs::enums::EventType::EV_REL; - -use crossbeam::crossbeam_channel::{unbounded, Select, Receiver, Sender}; - -use super::event::ThreadInputEvent; -use super::hw_device; - -pub fn create_evdev_thread(device_path: &str) -> (String, Receiver, Sender) { - // send out input events, receive stop command - let (send_event_channel, recv_event_channel) = unbounded(); - let (send_stop_channel, recv_stop_channel) = unbounded(); - - // thread safety and stuff - let device_path = String::from(device_path); - let return_device_path = device_path.clone(); - - thread::spawn(move || { - // open device - let mut dev = hw_device::HwDevice::new(&device_path); - // wait for device init - thread::sleep(Duration::from_secs(1)); - // don't deliver events elsewhere - dev.device.grab(evdev_rs::GrabMode::Grab).unwrap(); - // sleep for testing purposes - thread::sleep(Duration::from_secs(1)); - - // cache mouse movement before consuming all events - let mut mouse_move = vec![0, 0]; - loop { - if stop_requested(&recv_stop_channel) { - continue; - } - - loop { - // block before starting while loop again - let mut first = true; - let mut event = dev.device.next_event(evdev_rs::NORMAL | evdev_rs::BLOCKING); - // pending events not required for first round - while first || dev.device.has_event_pending() { - first = false; - match event { - // send input event to event channel - Ok(e) => { - let e = ThreadInputEvent { - typ: e.1.event_type as u32, - code: event_code_to_int(&e.1.event_code).1, - value: e.1.value, - }; - if e.typ == 2 && e.code <= 1 { - mouse_move[e.code as usize] += e.value; - } else { - send_event_channel.send(e).unwrap(); - } - }, - Err(_) => (), - } - // read next input event - event = dev.device.next_event(evdev_rs::NORMAL | evdev_rs::BLOCKING); - } - // combined mouse event - send_combined_mouse_move(&mut mouse_move, &send_event_channel); - // save cpu by sleeping after consuming all events - thread::sleep(Duration::from_millis(5)); - } - } - }); - - (return_device_path, recv_event_channel, send_stop_channel) -} - -fn stop_requested(chan: &Receiver) -> bool { - // check for stop requests - let mut sel = Select::new(); - // create stop channel receive operation - let oper1 = sel.recv(&chan); - // try to select from stop channel - let oper = sel.try_select(); - match oper { - // no stop requests - Err(_) => false, - // stop request received, break out of the loop - Ok(oper) => match oper.index() { - i if i == oper1 => { - oper.recv(&chan).unwrap() - }, - // shouldn't happen - _ => false, - }, - } -} - -fn send_combined_mouse_move(mouse_move: &mut Vec, chan: &Sender) { - // REL_X..=REL_Y - for code in 0..=1 { - if mouse_move[code] != 0 { - chan.send(ThreadInputEvent { - typ: EV_REL as u32, - code: code as u32, - value: mouse_move[code], - }).unwrap(); - mouse_move[code] = 0; - } - } -} diff --git a/src/main.rs b/src/main.rs index ffd3667..6941cef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,6 @@ extern crate crossbeam; use std::thread; use std::env::args; use std::time::Duration; -use std::collections::HashMap; use evdev_rs::enums::EventType::{EV_KEY, EV_REL}; @@ -15,9 +14,6 @@ mod virtual_mouse; mod virtual_kbd; mod hw_device; mod event; -mod input_thread; - -use self::input_thread::create_evdev_thread; fn main() { @@ -28,13 +24,17 @@ fn main() { // let mut disabled_devices = Vec::new(); for device_path in &args[1..] { - devices.push(create_evdev_thread(&device_path)); + devices.push(hw_device::HwDevice::new(&device_path)); } - // testing device removal + // // testing device removal // thread::sleep(Duration::from_secs(1)); - // devices[1].2.send(true).unwrap(); + // devices[1].stop(); // disabled_devices.push(devices.remove(1)); + // thread::sleep(Duration::from_secs(1)); + + // // add it again + // devices.push(hw_device::HwDevice::new(&args[1])); // init virtual devices let mut virt_kbd = virtual_kbd::VirtualKeyboard::new("test-kbd"); @@ -45,11 +45,9 @@ fn main() { // init select let mut sel = Select::new(); - // create device input event receive operations and map them to devices - let mut device_idx_by_oper = HashMap::new(); - for (i, (_, receiver, _)) in devices.iter().enumerate() { - let o = sel.recv(&receiver); - device_idx_by_oper.insert(o, i); + // add select operations + for d in &devices { + sel.recv(&d.event_channel); } // select from available device(s) @@ -57,7 +55,7 @@ fn main() { // read from selected device let index = oper.index(); - match oper.recv(&devices[device_idx_by_oper[&index]].1) { + match oper.recv(&devices[index].event_channel) { Ok(e) => { // mouse event if e.typ == EV_REL as u32 || (e.code >= 272 && e.code <= 276) {