use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use dharma::{EventHandlerId, event_kind};
use qualia::{Illusion, DeviceKind, EventHandling, InputConfig, InputForwarding, InputHandling};
use evdev_driver;
use udev::Udev;
use input_gateway::InputGateway;
use drivers::InputDriver;
use device_access::RestrictedOpener;
use virtual_terminal;
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
struct DeviceInfo {
pub devnode: PathBuf,
pub device_kind: DeviceKind,
}
impl DeviceInfo {
fn new(devnode: &Path, device_kind: DeviceKind) -> Self {
DeviceInfo {
devnode: devnode.to_owned(),
device_kind: device_kind,
}
}
}
pub struct InputCollector<C> where C: EventHandling {
coordinator: C,
input_config: InputConfig,
gateway: Arc<Mutex<InputForwarding>>,
restricted_opener: Rc<RefCell<RestrictedOpener>>,
current_devices: HashMap<DeviceInfo, EventHandlerId>,
}
impl<C> InputCollector<C> where C: EventHandling {
pub fn new(coordinator: C,
input_handler: Box<InputHandling>,
input_forwarder: Box<InputForwarding>,
input_config: InputConfig,
vt: Option<virtual_terminal::VirtualTerminal>,
restricted_opener: Rc<RefCell<RestrictedOpener>>)
-> Self {
InputCollector {
coordinator: coordinator,
input_config: input_config,
gateway: Arc::new(Mutex::new(InputGateway::new(input_handler, input_forwarder, vt))),
restricted_opener: restricted_opener,
current_devices: HashMap::new(),
}
}
pub fn scan_devices(&mut self, udev: &Udev) -> Result<(), Illusion> {
let old_devices = self.collect_current_devices();
let mut new_devices = HashSet::<DeviceInfo>::new();
udev.iterate_input_devices(|devnode, devkind, _| {
new_devices.insert(DeviceInfo::new(devnode, devkind));
});
for dev in new_devices.difference(&old_devices) {
self.handle_new_device(dev.clone());
}
for dev in old_devices.difference(&new_devices) {
self.handle_lost_device(dev);
}
Ok(())
}
}
impl<C> InputCollector<C> where C: EventHandling {
fn handle_new_device(&mut self, device: DeviceInfo) {
let r = evdev_driver::Evdev::initialize_device(&device.devnode,
device.device_kind,
self.input_config.clone(),
self.gateway.clone(),
&self.restricted_opener.borrow());
match r {
Ok(driver) => {
let id = self.coordinator.add_event_handler(driver, event_kind::READ);
self.current_devices.insert(device, id);
}
Err(err) => {
log_error!("Could not initialize input devices: {}", err);
}
}
}
fn handle_lost_device(&mut self, device: &DeviceInfo) {
log_info1!("Lost {:?}: {:?}", device.device_kind, device.devnode);
if let Some(id) = self.current_devices.remove(&device) {
self.coordinator.remove_event_handler(id);
} else {
log_warn2!("Lost input device which was never found: {:?}", device);
}
}
}
impl<C> InputCollector<C> where C: EventHandling {
fn collect_current_devices(&self) -> HashSet<DeviceInfo> {
let mut set = HashSet::new();
for key in self.current_devices.keys() {
set.insert(key.clone());
}
set
}
}