diff --git a/src/backend/libinput.rs b/src/backend/libinput.rs new file mode 100644 index 0000000..b3938c7 --- /dev/null +++ b/src/backend/libinput.rs @@ -0,0 +1,147 @@ +//! Implementation of input backend trait for types provided by `libinput` + +use backend::SeatInternal; +use backend::input::{InputBackend, InputHandler, Seat, SeatCapabilities}; +use input::{Libinput, Device, Seat as LibinputSeat, DeviceCapability}; +use input::event::*; + +use std::io::Error as IoError; +use std::collections::hash_map::{DefaultHasher, HashMap}; +use std::hash::{Hash, Hasher}; + +pub struct LibinputInputBackend { + context: Libinput, + devices: Vec, + seats: HashMap, + handler: Option + 'static>>, +} + +impl InputBackend for LibinputInputBackend { + type InputConfig = [Device]; + type EventError = IoError; + + fn set_handler + 'static>(&mut self, mut handler: H) { + if self.handler.is_some() { + self.clear_handler(); + } + for seat in self.seats.values() { + handler.on_seat_created(&seat); + } + self.handler = Some(Box::new(handler)); + } + + fn get_handler(&mut self) -> Option<&mut InputHandler> { + self.handler + .as_mut() + .map(|handler| handler as &mut InputHandler) + } + + fn clear_handler(&mut self) { + if let Some(mut handler) = self.handler.take() { + for seat in self.seats.values() { + handler.on_seat_destroyed(&seat); + } + } + } + + fn input_config(&mut self) -> &mut Self::InputConfig { + &mut self.devices + } + + fn set_cursor_position(&mut self, _x: u32, _y: u32) -> Result<(), ()> { + // FIXME later. + // This will be doable with the hardware cursor api and probably some more cases + Err(()) + } + + fn dispatch_new_events(&mut self) -> Result<(), IoError> { + self.context.dispatch()?; + for event in &mut self.context { + match event { + Event::Device(device_event) => { + use input::event::device::*; + match device_event { + DeviceEvent::Added(device_added_event) => { + let added = device_added_event.into_event().device(); + + let new_caps = SeatCapabilities { + pointer: added.has_capability(DeviceCapability::Pointer), + keyboard: added.has_capability(DeviceCapability::Keyboard), + touch: added.has_capability(DeviceCapability::Touch), + }; + + let device_seat = added.seat(); + self.devices.push(added); + + let contains = self.seats.contains_key(&device_seat); + if contains { + let old_seat = self.seats.get_mut(&device_seat).unwrap(); + { + let caps = old_seat.capabilities_mut(); + caps.pointer = new_caps.pointer || caps.pointer; + caps.keyboard = new_caps.keyboard || caps.keyboard; + caps.touch = new_caps.touch || caps.touch; + } + if let Some(ref mut handler) = self.handler { + handler.on_seat_changed(old_seat); + } + } else { + let mut hasher = DefaultHasher::default(); + device_seat.hash(&mut hasher); + self.seats.insert(device_seat.clone(), Seat::new(hasher.finish(), new_caps)); + if let Some(ref mut handler) = self.handler { + handler.on_seat_created(self.seats.get(&device_seat).unwrap()); + } + } + }, + DeviceEvent::Removed(device_removed_event) => { + let removed = device_removed_event.into_event().device(); + + // remove device + self.devices.retain(|dev| *dev == removed); + + let device_seat = removed.seat(); + + // update capabilities, so they appear correctly on `on_seat_changed` and `on_seat_destroyed`. + if let Some(seat) = self.seats.get_mut(&device_seat) { + let caps = seat.capabilities_mut(); + caps.pointer = self.devices.iter().any(|x| x.has_capability(DeviceCapability::Pointer)); + caps.keyboard = self.devices.iter().any(|x| x.has_capability(DeviceCapability::Keyboard)); + caps.touch = self.devices.iter().any(|x| x.has_capability(DeviceCapability::Touch)); + } else { + //TODO is this the best we can do? + panic!("Seat changed that was never created") + } + + // check if the seat has any other devices + if !self.devices.iter().any(|x| x.seat() == device_seat) { + // it has not, lets destroy it + if let Some(seat) = self.seats.remove(&device_seat) { + if let Some(ref mut handler) = self.handler { + handler.on_seat_destroyed(&seat); + } + } else { + //TODO is this the best we can do? + panic!("Seat destroyed that was never created"); + } + } else { + // it has, notify about updates + if let Some(ref mut handler) = self.handler { + handler.on_seat_changed(self.seats.get(&device_seat).unwrap()); + } + } + }, + } + if let Some(ref mut handler) = self.handler { + handler.on_input_config_changed(&mut self.devices); + } + }, + Event::Touch(touch_event) => {}, + Event::Keyboard(keyboard_event) => {}, + Event::Pointer(pointer_event) => {}, + _ => {}, //FIXME: What to do with the rest. + } + }; + Ok(()) + } +}