From 50741bc7bba58c9808a5fd7a9b3681e0f1bda2fd Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Tue, 29 Jun 2021 23:14:43 +0200 Subject: [PATCH] Rework `InputBackend` abstractions to track individual devices Removes the notion of Seats from `InputBackend` and replaces it with `DeviceAdded` and `DeviceRemoved` events allowing compositors to descriminate between single devices. A new abstraction to model multiple seats on a single input backend may be be added separately at a later time. --- anvil/src/winit.rs | 2 +- src/backend/input.rs | 209 +++++--------- src/backend/{libinput/mod.rs => libinput.rs} | 257 ++++++++++------- src/backend/libinput/helpers.rs | 279 ------------------- src/backend/winit.rs | 150 +++++----- 5 files changed, 313 insertions(+), 584 deletions(-) rename src/backend/{libinput/mod.rs => libinput.rs} (60%) delete mode 100644 src/backend/libinput/helpers.rs diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index 16cfeb9..b4ec500 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -109,7 +109,7 @@ pub fn run_winit( while state.running.load(Ordering::SeqCst) { if input - .dispatch_new_events(|event, _| state.process_input_event(event)) + .dispatch_new_events(|event| state.process_input_event(event)) .is_err() { state.running.store(false, Ordering::SeqCst); diff --git a/src/backend/input.rs b/src/backend/input.rs index 7817fba..91091ac 100644 --- a/src/backend/input.rs +++ b/src/backend/input.rs @@ -2,78 +2,33 @@ use std::error::Error; -/// A seat describes a group of input devices and at least one -/// graphics device belonging together. -/// -/// By default only one seat exists for most systems and smithay backends -/// however multiseat configurations are possible and should be treated as -/// separated users, all with their own focus, input and cursor available. -/// -/// Seats referring to the same internal id will always be equal and result in the same -/// hash, but capabilities of cloned and copied [`Seat`]s will not be updated by smithay. -/// Always refer to the [`Seat`] given by a callback for up-to-date information. You may -/// use this to calculate the differences since the last callback. -#[derive(Debug, Clone, Eq)] -pub struct Seat { - id: u64, - name: String, - capabilities: SeatCapabilities, +/// Trait for generic functions every input device does provide +pub trait Device: PartialEq + Eq + std::hash::Hash { + /// Unique id of a single device at a point in time. + /// + /// Note: This means ids may be re-used by the backend for later devices. + fn id(&self) -> String; + /// Human-readable name of the device + fn name(&self) -> String; + /// Test if this device has a specific capability + fn has_capability(&self, capability: DeviceCapability) -> bool; } -impl Seat { - #[cfg(any(feature = "backend_winit", feature = "backend_libinput"))] - pub(crate) fn new(id: u64, name: S, capabilities: SeatCapabilities) -> Seat { - Seat { - id, - name: name.to_string(), - capabilities, - } - } - - #[cfg(feature = "backend_libinput")] - pub(crate) fn capabilities_mut(&mut self) -> &mut SeatCapabilities { - &mut self.capabilities - } - - /// Get the currently capabilities of this [`Seat`] - pub fn capabilities(&self) -> &SeatCapabilities { - &self.capabilities - } - - /// Get the name of this [`Seat`] - pub fn name(&self) -> &str { - &*self.name - } -} - -impl ::std::cmp::PartialEq for Seat { - fn eq(&self, other: &Seat) -> bool { - self.id == other.id - } -} - -impl ::std::hash::Hash for Seat { - fn hash(&self, state: &mut H) - where - H: ::std::hash::Hasher, - { - self.id.hash(state); - } -} - -/// Describes capabilities a [`Seat`] has. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct SeatCapabilities { - /// [`Seat`] has a pointer - pub pointer: bool, - /// [`Seat`] has a keyboard - pub keyboard: bool, - /// [`Seat`] has a touchscreen - pub touch: bool, +/// Set of input types a device may provide +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[allow(missing_docs)] // self explainatory +pub enum DeviceCapability { + Keyboard, + Pointer, + Touch, + TabletTool, + TabletPad, + Gesture, + Switch, } /// Trait for generic functions every input event does provide -pub trait Event { +pub trait Event { /// Returns an upward counting variable useful for event ordering. /// /// Makes no guarantees about actual time passed between events. @@ -81,6 +36,8 @@ pub trait Event { // - check if events can even arrive out of order. // - Make stronger time guarantees, if possible fn time(&self) -> u32; + /// Returns the device, that generated this event + fn device(&self) -> B::Device; } /// Used to mark events never emitted by an [`InputBackend`] implementation. @@ -92,10 +49,14 @@ pub trait Event { #[derive(Debug)] pub enum UnusedEvent {} -impl Event for UnusedEvent { +impl Event for UnusedEvent { fn time(&self) -> u32 { match *self {} } + + fn device(&self) -> B::Device { + match *self {} + } } /// State of key on a keyboard. Either pressed or released @@ -108,7 +69,7 @@ pub enum KeyState { } /// Trait for keyboard event -pub trait KeyboardKeyEvent: Event { +pub trait KeyboardKeyEvent: Event { /// Code of the pressed key. See `linux/input-event-codes.h` fn key_code(&self) -> u32; /// State of the key @@ -117,7 +78,7 @@ pub trait KeyboardKeyEvent: Event { fn count(&self) -> u32; } -impl KeyboardKeyEvent for UnusedEvent { +impl KeyboardKeyEvent for UnusedEvent { fn key_code(&self) -> u32 { match *self {} } @@ -154,14 +115,14 @@ pub enum MouseButtonState { } /// Common methods pointer event generated by pressed buttons do implement -pub trait PointerButtonEvent: Event { +pub trait PointerButtonEvent: Event { /// Pressed button of the event fn button(&self) -> MouseButton; /// State of the button fn state(&self) -> MouseButtonState; } -impl PointerButtonEvent for UnusedEvent { +impl PointerButtonEvent for UnusedEvent { fn button(&self) -> MouseButton { match *self {} } @@ -214,7 +175,7 @@ pub enum AxisSource { } /// Trait for pointer events generated by scrolling on an axis. -pub trait PointerAxisEvent: Event { +pub trait PointerAxisEvent: Event { /// Amount of scrolling in pixels on the given [`Axis`]. /// /// Guaranteed to be `Some` when source returns either [`AxisSource::Finger`] or [`AxisSource::Continuous`]. @@ -229,7 +190,7 @@ pub trait PointerAxisEvent: Event { fn source(&self) -> AxisSource; } -impl PointerAxisEvent for UnusedEvent { +impl PointerAxisEvent for UnusedEvent { fn amount(&self, _axis: Axis) -> Option { match *self {} } @@ -244,7 +205,7 @@ impl PointerAxisEvent for UnusedEvent { } /// Trait for pointer events generated by relative device movement. -pub trait PointerMotionEvent: Event { +pub trait PointerMotionEvent: Event { /// Delta between the last and new pointer device position interpreted as pixel movement fn delta(&self) -> (f64, f64) { (self.delta_x(), self.delta_y()) @@ -256,7 +217,7 @@ pub trait PointerMotionEvent: Event { fn delta_y(&self) -> f64; } -impl PointerMotionEvent for UnusedEvent { +impl PointerMotionEvent for UnusedEvent { fn delta_x(&self) -> f64 { match *self {} } @@ -267,7 +228,7 @@ impl PointerMotionEvent for UnusedEvent { } /// Trait for pointer events generated by absolute device positioning. -pub trait PointerMotionAbsoluteEvent: Event { +pub trait PointerMotionAbsoluteEvent: Event { /// Device position in it's original coordinate space. /// /// The format is defined by the backend implementation. @@ -303,7 +264,7 @@ pub trait PointerMotionAbsoluteEvent: Event { fn y_transformed(&self, height: u32) -> f64; } -impl PointerMotionAbsoluteEvent for UnusedEvent { +impl PointerMotionAbsoluteEvent for UnusedEvent { fn x(&self) -> f64 { match *self {} } @@ -339,7 +300,7 @@ impl TouchSlot { } /// Trait for touch events starting at a given position. -pub trait TouchDownEvent: Event { +pub trait TouchDownEvent: Event { /// [`TouchSlot`], if the device has multi-touch capabilities fn slot(&self) -> Option; @@ -378,7 +339,7 @@ pub trait TouchDownEvent: Event { fn y_transformed(&self, height: u32) -> f64; } -impl TouchDownEvent for UnusedEvent { +impl TouchDownEvent for UnusedEvent { fn slot(&self) -> Option { match *self {} } @@ -401,7 +362,7 @@ impl TouchDownEvent for UnusedEvent { } /// Trait for touch events regarding movement on the screen -pub trait TouchMotionEvent: Event { +pub trait TouchMotionEvent: Event { /// [`TouchSlot`], if the device has multi-touch capabilities fn slot(&self) -> Option; @@ -440,7 +401,7 @@ pub trait TouchMotionEvent: Event { fn y_transformed(&self, height: u32) -> f64; } -impl TouchMotionEvent for UnusedEvent { +impl TouchMotionEvent for UnusedEvent { fn slot(&self) -> Option { match *self {} } @@ -463,33 +424,33 @@ impl TouchMotionEvent for UnusedEvent { } /// Trait for touch events finishing. -pub trait TouchUpEvent: Event { +pub trait TouchUpEvent: Event { /// [`TouchSlot`], if the device has multi-touch capabilities fn slot(&self) -> Option; } -impl TouchUpEvent for UnusedEvent { +impl TouchUpEvent for UnusedEvent { fn slot(&self) -> Option { match *self {} } } /// Trait for touch events cancelling the chain -pub trait TouchCancelEvent: Event { +pub trait TouchCancelEvent: Event { /// [`TouchSlot`], if the device has multi-touch capabilities fn slot(&self) -> Option; } -impl TouchCancelEvent for UnusedEvent { +impl TouchCancelEvent for UnusedEvent { fn slot(&self) -> Option { match *self {} } } /// Trait for touch frame events -pub trait TouchFrameEvent: Event {} +pub trait TouchFrameEvent: Event {} -impl TouchFrameEvent for UnusedEvent {} +impl TouchFrameEvent for UnusedEvent {} /// Trait that describes objects providing a source of input events. All input backends /// need to implement this and provide the same base guarantees about the precision of @@ -498,117 +459,93 @@ pub trait InputBackend: Sized { /// Type representing errors that may be returned when processing events type EventError: Error; + /// Type representing input devices + type Device: Device; /// Type representing keyboard events - type KeyboardKeyEvent: KeyboardKeyEvent; + type KeyboardKeyEvent: KeyboardKeyEvent; /// Type representing axis events on pointer devices - type PointerAxisEvent: PointerAxisEvent; + type PointerAxisEvent: PointerAxisEvent; /// Type representing button events on pointer devices - type PointerButtonEvent: PointerButtonEvent; + type PointerButtonEvent: PointerButtonEvent; /// Type representing motion events of pointer devices - type PointerMotionEvent: PointerMotionEvent; + type PointerMotionEvent: PointerMotionEvent; /// Type representing motion events of pointer devices - type PointerMotionAbsoluteEvent: PointerMotionAbsoluteEvent; + type PointerMotionAbsoluteEvent: PointerMotionAbsoluteEvent; /// Type representing touch events starting - type TouchDownEvent: TouchDownEvent; + type TouchDownEvent: TouchDownEvent; /// Type representing touch events ending - type TouchUpEvent: TouchUpEvent; + type TouchUpEvent: TouchUpEvent; /// Type representing touch events from moving - type TouchMotionEvent: TouchMotionEvent; + type TouchMotionEvent: TouchMotionEvent; /// Type representing cancelling of touch events - type TouchCancelEvent: TouchCancelEvent; + type TouchCancelEvent: TouchCancelEvent; /// Type representing touch frame events - type TouchFrameEvent: TouchFrameEvent; + type TouchFrameEvent: TouchFrameEvent; /// Special events that are custom to this backend type SpecialEvent; - /// Backend-specific type allowing you to configure it - type InputConfig: ?Sized; - - /// Get the list of currently known Seats - fn seats(&self) -> Vec; - - /// Access the input configuration interface - fn input_config(&mut self) -> &mut Self::InputConfig; - /// Processes new events and calls the provided callback. - /// - /// The callback can only assume its second argument to be usable if the event is - /// `InputEvent::ConfigChanged`. fn dispatch_new_events(&mut self, callback: F) -> Result<(), Self::EventError> where - F: FnMut(InputEvent, &mut Self::InputConfig); + F: FnMut(InputEvent); } /// Different events that can be generated by an input backend #[derive(Debug)] pub enum InputEvent { - /// A new seat has been created - NewSeat(Seat), - /// A seat has changed - SeatChanged(Seat), - /// A seat has been removed - SeatRemoved(Seat), + /// An input device was connected + DeviceAdded { + /// The added device + device: B::Device, + }, + /// An input device was disconnected + DeviceRemoved { + /// The removed device + device: B::Device, + }, /// A keyboard event occured Keyboard { - /// Seat that generated the event - seat: Seat, /// The keyboard event event: B::KeyboardKeyEvent, }, /// A relative pointer motion occured PointerMotion { - /// Seat that generated the event - seat: Seat, /// The pointer motion event event: B::PointerMotionEvent, }, /// An absolute pointer motion occures PointerMotionAbsolute { - /// Seat that generated the event - seat: Seat, /// The absolute pointer motion event event: B::PointerMotionAbsoluteEvent, }, /// A pointer button was pressed or released PointerButton { - /// Seat that generated the event - seat: Seat, /// The pointer button event event: B::PointerButtonEvent, }, /// A pointer axis was actionned PointerAxis { - /// Seat that generated the event - seat: Seat, /// The pointer axis event event: B::PointerAxisEvent, }, /// A new touchpoint appeared TouchDown { - /// Seat that generated the event - seat: Seat, /// The touch down event event: B::TouchDownEvent, }, /// A touchpoint moved TouchMotion { - /// Seat that generated the event - seat: Seat, /// The touch motion event event: B::TouchMotionEvent, }, /// A touchpoint was removed TouchUp { - /// Seat that generated the event - seat: Seat, /// The touch up event event: B::TouchUpEvent, }, /// A touch sequence was cancelled TouchCancel { - /// Seat that generated the event - seat: Seat, /// The touch cancel event event: B::TouchCancelEvent, }, @@ -617,8 +554,6 @@ pub enum InputEvent { /// A set of two events received on the same seat between two frames should /// be interpreted as an atomic event. TouchFrame { - /// Seat that generated the event - seat: Seat, /// The touch frame event event: B::TouchFrameEvent, }, diff --git a/src/backend/libinput/mod.rs b/src/backend/libinput.rs similarity index 60% rename from src/backend/libinput/mod.rs rename to src/backend/libinput.rs index a637d4c..13b8e14 100644 --- a/src/backend/libinput/mod.rs +++ b/src/backend/libinput.rs @@ -1,8 +1,5 @@ //! Implementation of input backend trait for types provided by `libinput` -mod helpers; -use helpers::{on_device_event, on_keyboard_event, on_pointer_event, on_touch_event}; - use crate::backend::input::{self as backend, Axis, InputBackend, InputEvent}; #[cfg(feature = "backend_session")] use crate::{ @@ -15,7 +12,6 @@ use input::event; #[cfg(feature = "backend_session")] use std::path::Path; use std::{ - collections::hash_map::HashMap, io::Error as IoError, os::unix::io::{AsRawFd, RawFd}, }; @@ -37,8 +33,6 @@ const INPUT_MAJOR: u32 = 13; #[derive(Debug)] pub struct LibinputInputBackend { context: libinput::Libinput, - config: LibinputConfig, - seats: HashMap, #[cfg(feature = "backend_session")] links: Vec, logger: ::slog::Logger, @@ -55,8 +49,6 @@ impl LibinputInputBackend { info!(log, "Initializing a libinput backend"); LibinputInputBackend { context, - config: LibinputConfig { devices: Vec::new() }, - seats: HashMap::new(), #[cfg(feature = "backend_session")] links: Vec::new(), logger: log, @@ -87,13 +79,45 @@ impl Linkable for LibinputInputBackend { } } -impl backend::Event for event::keyboard::KeyboardKeyEvent { - fn time(&self) -> u32 { - event::keyboard::KeyboardEventTrait::time(self) +impl backend::Device for libinput::Device { + fn id(&self) -> String { + self.sysname().into() + } + + fn name(&self) -> String { + self.name().into() + } + + fn has_capability(&self, capability: backend::DeviceCapability) -> bool { + libinput::Device::has_capability(self, capability.into()) } } -impl backend::KeyboardKeyEvent for event::keyboard::KeyboardKeyEvent { +impl From for libinput::DeviceCapability { + fn from(other: backend::DeviceCapability) -> libinput::DeviceCapability { + match other { + backend::DeviceCapability::Gesture => libinput::DeviceCapability::Gesture, + backend::DeviceCapability::Keyboard => libinput::DeviceCapability::Keyboard, + backend::DeviceCapability::Pointer => libinput::DeviceCapability::Pointer, + backend::DeviceCapability::Switch => libinput::DeviceCapability::Switch, + backend::DeviceCapability::TabletPad => libinput::DeviceCapability::TabletPad, + backend::DeviceCapability::TabletTool => libinput::DeviceCapability::TabletTool, + backend::DeviceCapability::Touch => libinput::DeviceCapability::Touch, + } + } +} + +impl backend::Event for event::keyboard::KeyboardKeyEvent { + fn time(&self) -> u32 { + event::keyboard::KeyboardEventTrait::time(self) + } + + fn device(&self) -> libinput::Device { + event::EventTrait::device(self) + } +} + +impl backend::KeyboardKeyEvent for event::keyboard::KeyboardKeyEvent { fn key_code(&self) -> u32 { use input::event::keyboard::KeyboardEventTrait; self.key() @@ -109,13 +133,17 @@ impl backend::KeyboardKeyEvent for event::keyboard::KeyboardKeyEvent { } } -impl<'a> backend::Event for event::pointer::PointerAxisEvent { +impl<'a> backend::Event for event::pointer::PointerAxisEvent { fn time(&self) -> u32 { event::pointer::PointerEventTrait::time(self) } + + fn device(&self) -> libinput::Device { + event::EventTrait::device(self) + } } -impl backend::PointerAxisEvent for event::pointer::PointerAxisEvent { +impl backend::PointerAxisEvent for event::pointer::PointerAxisEvent { fn amount(&self, axis: Axis) -> Option { Some(self.axis_value(axis.into())) } @@ -129,13 +157,17 @@ impl backend::PointerAxisEvent for event::pointer::PointerAxisEvent { } } -impl backend::Event for event::pointer::PointerButtonEvent { +impl backend::Event for event::pointer::PointerButtonEvent { fn time(&self) -> u32 { event::pointer::PointerEventTrait::time(self) } + + fn device(&self) -> libinput::Device { + event::EventTrait::device(self) + } } -impl backend::PointerButtonEvent for event::pointer::PointerButtonEvent { +impl backend::PointerButtonEvent for event::pointer::PointerButtonEvent { fn button(&self) -> backend::MouseButton { match self.button() { 0x110 => backend::MouseButton::Left, @@ -150,13 +182,17 @@ impl backend::PointerButtonEvent for event::pointer::PointerButtonEvent { } } -impl backend::Event for event::pointer::PointerMotionEvent { +impl backend::Event for event::pointer::PointerMotionEvent { fn time(&self) -> u32 { event::pointer::PointerEventTrait::time(self) } + + fn device(&self) -> libinput::Device { + event::EventTrait::device(self) + } } -impl backend::PointerMotionEvent for event::pointer::PointerMotionEvent { +impl backend::PointerMotionEvent for event::pointer::PointerMotionEvent { fn delta_x(&self) -> f64 { self.dx() } @@ -165,13 +201,19 @@ impl backend::PointerMotionEvent for event::pointer::PointerMotionEvent { } } -impl backend::Event for event::pointer::PointerMotionAbsoluteEvent { +impl backend::Event for event::pointer::PointerMotionAbsoluteEvent { fn time(&self) -> u32 { event::pointer::PointerEventTrait::time(self) } + + fn device(&self) -> libinput::Device { + event::EventTrait::device(self) + } } -impl backend::PointerMotionAbsoluteEvent for event::pointer::PointerMotionAbsoluteEvent { +impl backend::PointerMotionAbsoluteEvent + for event::pointer::PointerMotionAbsoluteEvent +{ fn x(&self) -> f64 { self.absolute_x() } @@ -189,13 +231,17 @@ impl backend::PointerMotionAbsoluteEvent for event::pointer::PointerMotionAbsolu } } -impl backend::Event for event::touch::TouchDownEvent { +impl backend::Event for event::touch::TouchDownEvent { fn time(&self) -> u32 { event::touch::TouchEventTrait::time(self) } + + fn device(&self) -> libinput::Device { + event::EventTrait::device(self) + } } -impl backend::TouchDownEvent for event::touch::TouchDownEvent { +impl backend::TouchDownEvent for event::touch::TouchDownEvent { fn slot(&self) -> Option { event::touch::TouchEventSlot::slot(self).map(|x| backend::TouchSlot::new(x as u64)) } @@ -217,13 +263,17 @@ impl backend::TouchDownEvent for event::touch::TouchDownEvent { } } -impl backend::Event for event::touch::TouchMotionEvent { +impl backend::Event for event::touch::TouchMotionEvent { fn time(&self) -> u32 { event::touch::TouchEventTrait::time(self) } + + fn device(&self) -> libinput::Device { + event::EventTrait::device(self) + } } -impl backend::TouchMotionEvent for event::touch::TouchMotionEvent { +impl backend::TouchMotionEvent for event::touch::TouchMotionEvent { fn slot(&self) -> Option { event::touch::TouchEventSlot::slot(self).map(|x| backend::TouchSlot::new(x as u64)) } @@ -245,66 +295,54 @@ impl backend::TouchMotionEvent for event::touch::TouchMotionEvent { } } -impl backend::Event for event::touch::TouchUpEvent { +impl backend::Event for event::touch::TouchUpEvent { fn time(&self) -> u32 { event::touch::TouchEventTrait::time(self) } + + fn device(&self) -> libinput::Device { + event::EventTrait::device(self) + } } -impl backend::TouchUpEvent for event::touch::TouchUpEvent { +impl backend::TouchUpEvent for event::touch::TouchUpEvent { fn slot(&self) -> Option { event::touch::TouchEventSlot::slot(self).map(|x| backend::TouchSlot::new(x as u64)) } } -impl backend::Event for event::touch::TouchCancelEvent { +impl backend::Event for event::touch::TouchCancelEvent { fn time(&self) -> u32 { event::touch::TouchEventTrait::time(self) } + + fn device(&self) -> libinput::Device { + event::EventTrait::device(self) + } } -impl backend::TouchCancelEvent for event::touch::TouchCancelEvent { +impl backend::TouchCancelEvent for event::touch::TouchCancelEvent { fn slot(&self) -> Option { event::touch::TouchEventSlot::slot(self).map(|x| backend::TouchSlot::new(x as u64)) } } -impl backend::Event for event::touch::TouchFrameEvent { +impl backend::Event for event::touch::TouchFrameEvent { fn time(&self) -> u32 { event::touch::TouchEventTrait::time(self) } -} -impl backend::TouchFrameEvent for event::touch::TouchFrameEvent {} - -/// Special events generated by Libinput -#[derive(Debug)] -pub enum LibinputEvent { - /// A new device was plugged in - NewDevice(libinput::Device), - /// A device was plugged out - RemovedDevice(libinput::Device), -} - -/// Configuration handle for libinput -/// -/// This type allows you to access the list of know devices to configure them -/// if relevant -#[derive(Debug)] -pub struct LibinputConfig { - devices: Vec, -} - -impl LibinputConfig { - /// Access the list of current devices - pub fn devices(&mut self) -> &mut [libinput::Device] { - &mut self.devices + fn device(&self) -> libinput::Device { + event::EventTrait::device(self) } } +impl backend::TouchFrameEvent for event::touch::TouchFrameEvent {} + impl InputBackend for LibinputInputBackend { type EventError = IoError; + type Device = libinput::Device; type KeyboardKeyEvent = event::keyboard::KeyboardKeyEvent; type PointerAxisEvent = event::pointer::PointerAxisEvent; type PointerButtonEvent = event::pointer::PointerButtonEvent; @@ -316,61 +354,70 @@ impl InputBackend for LibinputInputBackend { type TouchCancelEvent = event::touch::TouchCancelEvent; type TouchFrameEvent = event::touch::TouchFrameEvent; - type SpecialEvent = LibinputEvent; - type InputConfig = LibinputConfig; - - fn seats(&self) -> Vec { - self.seats.values().cloned().collect() - } - - fn input_config(&mut self) -> &mut Self::InputConfig { - &mut self.config - } + type SpecialEvent = backend::UnusedEvent; fn dispatch_new_events(&mut self, mut callback: F) -> Result<(), IoError> where - F: FnMut(InputEvent, &mut LibinputConfig), + F: FnMut(InputEvent), { self.context.dispatch()?; for event in &mut self.context { match event { - libinput::Event::Device(device_event) => { - on_device_event( - &mut callback, - &mut self.seats, - &mut self.config, - device_event, - &self.logger, - ); - } - libinput::Event::Touch(touch_event) => { - on_touch_event( - &mut callback, - &self.seats, - &mut self.config, - touch_event, - &self.logger, - ); - } - libinput::Event::Keyboard(keyboard_event) => { - on_keyboard_event( - &mut callback, - &self.seats, - &mut self.config, - keyboard_event, - &self.logger, - ); - } - libinput::Event::Pointer(pointer_event) => { - on_pointer_event( - &mut callback, - &self.seats, - &mut self.config, - pointer_event, - &self.logger, - ); - } + libinput::Event::Device(device_event) => match device_event { + event::DeviceEvent::Added(device_added_event) => { + let added = event::EventTrait::device(&device_added_event); + + info!(self.logger, "New device {:?}", added.sysname(),); + + callback(InputEvent::DeviceAdded { device: added }); + } + event::DeviceEvent::Removed(device_removed_event) => { + let removed = event::EventTrait::device(&device_removed_event); + + info!(self.logger, "Removed device {:?}", removed.sysname(),); + + callback(InputEvent::DeviceRemoved { device: removed }); + } + }, + libinput::Event::Touch(touch_event) => match touch_event { + event::TouchEvent::Down(down_event) => { + callback(InputEvent::TouchDown { event: down_event }); + } + event::TouchEvent::Motion(motion_event) => { + callback(InputEvent::TouchMotion { event: motion_event }); + } + event::TouchEvent::Up(up_event) => { + callback(InputEvent::TouchUp { event: up_event }); + } + event::TouchEvent::Cancel(cancel_event) => { + callback(InputEvent::TouchCancel { event: cancel_event }); + } + event::TouchEvent::Frame(frame_event) => { + callback(InputEvent::TouchFrame { event: frame_event }); + } + }, + libinput::Event::Keyboard(keyboard_event) => match keyboard_event { + event::KeyboardEvent::Key(key_event) => { + callback(InputEvent::Keyboard { event: key_event }); + } + }, + libinput::Event::Pointer(pointer_event) => match pointer_event { + event::PointerEvent::Motion(motion_event) => { + callback(InputEvent::PointerMotion { event: motion_event }); + } + event::PointerEvent::MotionAbsolute(motion_abs_event) => { + callback(InputEvent::PointerMotionAbsolute { + event: motion_abs_event, + }); + } + event::PointerEvent::Axis(axis_event) => { + callback(InputEvent::PointerAxis { event: axis_event }); + } + event::PointerEvent::Button(button_event) => { + callback(InputEvent::PointerButton { event: button_event }); + } + }, _ => {} //FIXME: What to do with the rest. } } @@ -460,14 +507,14 @@ impl AsRawFd for LibinputInputBackend { impl EventSource for LibinputInputBackend { type Event = InputEvent; - type Metadata = LibinputConfig; + type Metadata = (); type Ret = (); - fn process_events(&mut self, _: Readiness, _: Token, callback: F) -> std::io::Result<()> + fn process_events(&mut self, _: Readiness, _: Token, mut callback: F) -> std::io::Result<()> where - F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret, + F: FnMut(Self::Event, &mut ()) -> Self::Ret, { - self.dispatch_new_events(callback) + self.dispatch_new_events(|event| callback(event, &mut ())) } fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { diff --git a/src/backend/libinput/helpers.rs b/src/backend/libinput/helpers.rs deleted file mode 100644 index 337c093..0000000 --- a/src/backend/libinput/helpers.rs +++ /dev/null @@ -1,279 +0,0 @@ -use crate::backend::input::{self as backend, InputEvent}; -use input as libinput; -use input::event::{ - device::DeviceEvent, keyboard::KeyboardEvent, pointer::PointerEvent, touch::TouchEvent, EventTrait, -}; -use slog::Logger; - -use super::{LibinputConfig, LibinputEvent, LibinputInputBackend}; -use std::{ - collections::hash_map::{DefaultHasher, Entry, HashMap}, - hash::{Hash, Hasher}, -}; - -use slog::{info, warn}; - -#[inline(always)] -pub fn on_device_event( - callback: &mut F, - seats: &mut HashMap, - config: &mut LibinputConfig, - event: DeviceEvent, - logger: &Logger, -) where - F: FnMut(InputEvent, &mut LibinputConfig), -{ - match event { - DeviceEvent::Added(device_added_event) => { - let added = device_added_event.device(); - - let new_caps = backend::SeatCapabilities { - pointer: added.has_capability(libinput::DeviceCapability::Pointer), - keyboard: added.has_capability(libinput::DeviceCapability::Keyboard), - touch: added.has_capability(libinput::DeviceCapability::Touch), - }; - - let device_seat = added.seat(); - info!( - logger, - "New device {:?} on seat {:?}", - added.sysname(), - device_seat.logical_name() - ); - config.devices.push(added.clone()); - - match seats.entry(device_seat.clone()) { - Entry::Occupied(mut seat_entry) => { - let old_seat = seat_entry.get_mut(); - { - 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; - } - callback(InputEvent::SeatChanged(old_seat.clone()), config); - } - Entry::Vacant(seat_entry) => { - let mut hasher = DefaultHasher::default(); - seat_entry.key().hash(&mut hasher); - let seat = seat_entry.insert(backend::Seat::new( - hasher.finish(), - format!("{}:{}", device_seat.physical_name(), device_seat.logical_name()), - new_caps, - )); - callback(InputEvent::NewSeat(seat.clone()), config); - } - } - - callback(InputEvent::Special(LibinputEvent::NewDevice(added)), config); - } - DeviceEvent::Removed(device_removed_event) => { - let removed = device_removed_event.device(); - - // remove device - config.devices.retain(|dev| *dev != removed); - - let device_seat = removed.seat(); - info!( - logger, - "Removed device {:?} on seat {:?}", - removed.sysname(), - device_seat.logical_name() - ); - - // update capabilities, so they appear correctly on `on_seat_changed` and `on_seat_destroyed`. - if let Some(seat) = seats.get_mut(&device_seat) { - let caps = seat.capabilities_mut(); - caps.pointer = config - .devices - .iter() - .filter(|x| x.seat() == device_seat) - .any(|x| x.has_capability(libinput::DeviceCapability::Pointer)); - caps.keyboard = config - .devices - .iter() - .filter(|x| x.seat() == device_seat) - .any(|x| x.has_capability(libinput::DeviceCapability::Keyboard)); - caps.touch = config - .devices - .iter() - .filter(|x| x.seat() == device_seat) - .any(|x| x.has_capability(libinput::DeviceCapability::Touch)); - } else { - warn!(logger, "Seat changed that was never created"); - return; - } - - // check if the seat has any other devices - if !config.devices.iter().any(|x| x.seat() == device_seat) { - // it has not, lets destroy it - if let Some(seat) = seats.remove(&device_seat) { - info!( - logger, - "Removing seat {} which no longer has any device", - device_seat.logical_name() - ); - callback(InputEvent::SeatRemoved(seat), config); - } else { - warn!(logger, "Seat destroyed that was never created"); - return; - } - // it has, notify about updates - } else if let Some(seat) = seats.get(&device_seat) { - callback(InputEvent::SeatChanged(seat.clone()), config); - } else { - warn!(logger, "Seat changed that was never created"); - return; - } - - callback(InputEvent::Special(LibinputEvent::RemovedDevice(removed)), config); - } - } -} - -#[inline(always)] -pub fn on_touch_event( - callback: &mut F, - seats: &HashMap, - config: &mut LibinputConfig, - event: TouchEvent, - logger: &Logger, -) where - F: FnMut(InputEvent, &mut LibinputConfig), -{ - let device_seat = event.device().seat(); - if let Some(seat) = seats.get(&device_seat).cloned() { - match event { - TouchEvent::Down(down_event) => { - callback( - InputEvent::TouchDown { - seat, - event: down_event, - }, - config, - ); - } - TouchEvent::Motion(motion_event) => { - callback( - InputEvent::TouchMotion { - seat, - event: motion_event, - }, - config, - ); - } - TouchEvent::Up(up_event) => { - callback( - InputEvent::TouchUp { - seat, - event: up_event, - }, - config, - ); - } - TouchEvent::Cancel(cancel_event) => { - callback( - InputEvent::TouchCancel { - seat, - event: cancel_event, - }, - config, - ); - } - TouchEvent::Frame(frame_event) => { - callback( - InputEvent::TouchFrame { - seat, - event: frame_event, - }, - config, - ); - } - } - } else { - warn!(logger, "Received touch event of non existing Seat"); - } -} - -#[inline(always)] -pub fn on_keyboard_event( - callback: &mut F, - seats: &HashMap, - config: &mut LibinputConfig, - event: KeyboardEvent, - logger: &Logger, -) where - F: FnMut(InputEvent, &mut LibinputConfig), -{ - match event { - KeyboardEvent::Key(key_event) => { - let device_seat = key_event.device().seat(); - if let Some(seat) = seats.get(&device_seat).cloned() { - callback( - InputEvent::Keyboard { - seat, - event: key_event, - }, - config, - ); - } else { - warn!(logger, "Received key event of non existing Seat"); - } - } - } -} - -#[inline(always)] -pub fn on_pointer_event( - callback: &mut F, - seats: &HashMap, - config: &mut LibinputConfig, - event: PointerEvent, - logger: &Logger, -) where - F: FnMut(InputEvent, &mut LibinputConfig), -{ - let device_seat = event.device().seat(); - if let Some(seat) = seats.get(&device_seat).cloned() { - match event { - PointerEvent::Motion(motion_event) => { - callback( - InputEvent::PointerMotion { - seat, - event: motion_event, - }, - config, - ); - } - PointerEvent::MotionAbsolute(motion_abs_event) => { - callback( - InputEvent::PointerMotionAbsolute { - seat, - event: motion_abs_event, - }, - config, - ); - } - PointerEvent::Axis(axis_event) => { - callback( - InputEvent::PointerAxis { - seat, - event: axis_event, - }, - config, - ); - } - PointerEvent::Button(button_event) => { - callback( - InputEvent::PointerButton { - seat, - event: button_event, - }, - config, - ); - } - } - } else { - warn!(logger, "Received pointer event of non existing Seat"); - } -} diff --git a/src/backend/winit.rs b/src/backend/winit.rs index 0230445..170f46f 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -4,10 +4,10 @@ use crate::backend::egl::display::EGLDisplay; use crate::backend::{ egl::{context::GlAttributes, native, EGLContext, EGLSurface, Error as EGLError}, input::{ - Axis, AxisSource, Event as BackendEvent, InputBackend, InputEvent, KeyState, KeyboardKeyEvent, - MouseButton, MouseButtonState, PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent, - Seat, SeatCapabilities, TouchCancelEvent, TouchDownEvent, TouchMotionEvent, TouchSlot, TouchUpEvent, - UnusedEvent, + Axis, AxisSource, Device, DeviceCapability, Event as BackendEvent, InputBackend, InputEvent, + KeyState, KeyboardKeyEvent, MouseButton, MouseButtonState, PointerAxisEvent, PointerButtonEvent, + PointerMotionAbsoluteEvent, TouchCancelEvent, TouchDownEvent, TouchMotionEvent, TouchSlot, + TouchUpEvent, UnusedEvent, }, renderer::{ gles2::{Gles2Error, Gles2Frame, Gles2Renderer}, @@ -77,8 +77,8 @@ pub struct WinitInputBackend { events_loop: EventLoop<()>, time: Instant, key_counter: u32, - seat: Seat, logger: ::slog::Logger, + initialized: bool, size: Rc>, } @@ -200,15 +200,7 @@ where egl, time: Instant::now(), key_counter: 0, - seat: Seat::new( - 0, - "winit", - SeatCapabilities { - pointer: true, - keyboard: true, - touch: true, - }, - ), + initialized: false, logger: log.new(o!("smithay_winit_component" => "input")), size, }, @@ -268,6 +260,27 @@ impl WinitGraphicsBackend { } } +/// Virtual input device used by the backend to associate input events +#[derive(PartialEq, Eq, Hash)] +pub struct WinitVirtualDevice; + +impl Device for WinitVirtualDevice { + fn id(&self) -> String { + String::from("winit") + } + + fn name(&self) -> String { + String::from("winit virtual input") + } + + fn has_capability(&self, capability: DeviceCapability) -> bool { + matches!( + capability, + DeviceCapability::Keyboard | DeviceCapability::Pointer | DeviceCapability::Touch + ) + } +} + /// Errors that may happen when driving the event loop of [`WinitInputBackend`] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)] pub enum WinitInputError { @@ -287,13 +300,17 @@ pub struct WinitKeyboardInputEvent { state: ElementState, } -impl BackendEvent for WinitKeyboardInputEvent { +impl BackendEvent for WinitKeyboardInputEvent { fn time(&self) -> u32 { self.time } + + fn device(&self) -> WinitVirtualDevice { + WinitVirtualDevice + } } -impl KeyboardKeyEvent for WinitKeyboardInputEvent { +impl KeyboardKeyEvent for WinitKeyboardInputEvent { fn key_code(&self) -> u32 { self.key } @@ -315,13 +332,17 @@ pub struct WinitMouseMovedEvent { logical_position: LogicalPosition, } -impl BackendEvent for WinitMouseMovedEvent { +impl BackendEvent for WinitMouseMovedEvent { fn time(&self) -> u32 { self.time } + + fn device(&self) -> WinitVirtualDevice { + WinitVirtualDevice + } } -impl PointerMotionAbsoluteEvent for WinitMouseMovedEvent { +impl PointerMotionAbsoluteEvent for WinitMouseMovedEvent { // TODO: maybe use {Logical, Physical}Position from winit? fn x(&self) -> f64 { let wsize = self.size.borrow(); @@ -353,13 +374,17 @@ pub struct WinitMouseWheelEvent { delta: MouseScrollDelta, } -impl BackendEvent for WinitMouseWheelEvent { +impl BackendEvent for WinitMouseWheelEvent { fn time(&self) -> u32 { self.time } + + fn device(&self) -> WinitVirtualDevice { + WinitVirtualDevice + } } -impl PointerAxisEvent for WinitMouseWheelEvent { +impl PointerAxisEvent for WinitMouseWheelEvent { fn source(&self) -> AxisSource { match self.delta { MouseScrollDelta::LineDelta(_, _) => AxisSource::Wheel, @@ -392,13 +417,17 @@ pub struct WinitMouseInputEvent { state: ElementState, } -impl BackendEvent for WinitMouseInputEvent { +impl BackendEvent for WinitMouseInputEvent { fn time(&self) -> u32 { self.time } + + fn device(&self) -> WinitVirtualDevice { + WinitVirtualDevice + } } -impl PointerButtonEvent for WinitMouseInputEvent { +impl PointerButtonEvent for WinitMouseInputEvent { fn button(&self) -> MouseButton { self.button.into() } @@ -417,13 +446,17 @@ pub struct WinitTouchStartedEvent { id: u64, } -impl BackendEvent for WinitTouchStartedEvent { +impl BackendEvent for WinitTouchStartedEvent { fn time(&self) -> u32 { self.time } + + fn device(&self) -> WinitVirtualDevice { + WinitVirtualDevice + } } -impl TouchDownEvent for WinitTouchStartedEvent { +impl TouchDownEvent for WinitTouchStartedEvent { fn slot(&self) -> Option { Some(TouchSlot::new(self.id)) } @@ -460,13 +493,17 @@ pub struct WinitTouchMovedEvent { id: u64, } -impl BackendEvent for WinitTouchMovedEvent { +impl BackendEvent for WinitTouchMovedEvent { fn time(&self) -> u32 { self.time } + + fn device(&self) -> WinitVirtualDevice { + WinitVirtualDevice + } } -impl TouchMotionEvent for WinitTouchMovedEvent { +impl TouchMotionEvent for WinitTouchMovedEvent { fn slot(&self) -> Option { Some(TouchSlot::new(self.id)) } @@ -501,13 +538,17 @@ pub struct WinitTouchEndedEvent { id: u64, } -impl BackendEvent for WinitTouchEndedEvent { +impl BackendEvent for WinitTouchEndedEvent { fn time(&self) -> u32 { self.time } + + fn device(&self) -> WinitVirtualDevice { + WinitVirtualDevice + } } -impl TouchUpEvent for WinitTouchEndedEvent { +impl TouchUpEvent for WinitTouchEndedEvent { fn slot(&self) -> Option { Some(TouchSlot::new(self.id)) } @@ -520,27 +561,26 @@ pub struct WinitTouchCancelledEvent { id: u64, } -impl BackendEvent for WinitTouchCancelledEvent { +impl BackendEvent for WinitTouchCancelledEvent { fn time(&self) -> u32 { self.time } + + fn device(&self) -> WinitVirtualDevice { + WinitVirtualDevice + } } -impl TouchCancelEvent for WinitTouchCancelledEvent { +impl TouchCancelEvent for WinitTouchCancelledEvent { fn slot(&self) -> Option { Some(TouchSlot::new(self.id)) } } -/// Input config for Winit -/// -/// This backend does not allow any input configuration, so this type does nothing. -#[derive(Debug)] -pub struct WinitInputConfig; - impl InputBackend for WinitInputBackend { type EventError = WinitInputError; + type Device = WinitVirtualDevice; type KeyboardKeyEvent = WinitKeyboardInputEvent; type PointerAxisEvent = WinitMouseWheelEvent; type PointerButtonEvent = WinitMouseInputEvent; @@ -553,17 +593,6 @@ impl InputBackend for WinitInputBackend { type TouchFrameEvent = UnusedEvent; type SpecialEvent = WinitEvent; - type InputConfig = WinitInputConfig; - - fn seats(&self) -> Vec { - vec![self.seat.clone()] - } - - fn input_config(&mut self) -> &mut Self::InputConfig { - /// So much effort to return a useless singleton! - static mut CONFIG: WinitInputConfig = WinitInputConfig; - unsafe { &mut CONFIG } - } /// Processes new events of the underlying event loop and calls the provided callback. /// @@ -578,7 +607,7 @@ impl InputBackend for WinitInputBackend { /// not be used anymore as well. fn dispatch_new_events(&mut self, mut callback: F) -> ::std::result::Result<(), WinitInputError> where - F: FnMut(InputEvent, &mut WinitInputConfig), + F: FnMut(InputEvent), { let mut closed = false; @@ -591,12 +620,17 @@ impl InputBackend for WinitInputBackend { let closed_ptr = &mut closed; let key_counter = &mut self.key_counter; let time = &self.time; - let seat = &self.seat; let window = &self.window; let egl = &self.egl; let logger = &self.logger; let window_size = &self.size; - let mut callback = move |event| callback(event, &mut WinitInputConfig); + + if !self.initialized { + callback(InputEvent::DeviceAdded { + device: WinitVirtualDevice, + }); + self.initialized = true; + } self.events_loop .run_return(move |event, _target, control_flow| match event { @@ -651,7 +685,6 @@ impl InputBackend for WinitInputBackend { } }; callback(InputEvent::Keyboard { - seat: seat.clone(), event: WinitKeyboardInputEvent { time, key: scancode, @@ -663,7 +696,6 @@ impl InputBackend for WinitInputBackend { WindowEvent::CursorMoved { position, .. } => { let lpos = position.to_logical(window_size.borrow().scale_factor); callback(InputEvent::PointerMotionAbsolute { - seat: seat.clone(), event: WinitMouseMovedEvent { size: window_size.clone(), time, @@ -673,14 +705,10 @@ impl InputBackend for WinitInputBackend { } WindowEvent::MouseWheel { delta, .. } => { let event = WinitMouseWheelEvent { time, delta }; - callback(InputEvent::PointerAxis { - seat: seat.clone(), - event, - }); + callback(InputEvent::PointerAxis { event }); } WindowEvent::MouseInput { state, button, .. } => { callback(InputEvent::PointerButton { - seat: seat.clone(), event: WinitMouseInputEvent { time, button, state }, }); } @@ -692,7 +720,6 @@ impl InputBackend for WinitInputBackend { .. }) => { callback(InputEvent::TouchDown { - seat: seat.clone(), event: WinitTouchStartedEvent { size: window_size.clone(), time, @@ -708,7 +735,6 @@ impl InputBackend for WinitInputBackend { .. }) => { callback(InputEvent::TouchMotion { - seat: seat.clone(), event: WinitTouchMovedEvent { size: window_size.clone(), time, @@ -725,7 +751,6 @@ impl InputBackend for WinitInputBackend { .. }) => { callback(InputEvent::TouchMotion { - seat: seat.clone(), event: WinitTouchMovedEvent { size: window_size.clone(), time, @@ -734,7 +759,6 @@ impl InputBackend for WinitInputBackend { }, }); callback(InputEvent::TouchUp { - seat: seat.clone(), event: WinitTouchEndedEvent { time, id }, }) } @@ -745,11 +769,13 @@ impl InputBackend for WinitInputBackend { .. }) => { callback(InputEvent::TouchCancel { - seat: seat.clone(), event: WinitTouchCancelledEvent { time, id }, }); } WindowEvent::CloseRequested | WindowEvent::Destroyed => { + callback(InputEvent::DeviceRemoved { + device: WinitVirtualDevice, + }); warn!(logger, "Window closed"); *closed_ptr = true; }