Merge pull request #318 from Smithay/refactor/input_backend

Rework `InputBackend` abstractions to track individual devices
This commit is contained in:
Victor Brekenfeld 2021-06-30 00:14:20 +02:00 committed by GitHub
commit 616bacdff2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 313 additions and 584 deletions

View File

@ -110,7 +110,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);

View File

@ -2,78 +2,33 @@
use std::error::Error;
/// A seat describes a group of input devices and at least one
/// graphics device belonging together.
/// 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.
///
/// 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,
/// 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<S: std::string::ToString>(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<H>(&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<B: InputBackend> {
/// 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<B: InputBackend> Event<B> 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<B: InputBackend>: Event<B> {
/// 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<B: InputBackend> KeyboardKeyEvent<B> 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<B: InputBackend>: Event<B> {
/// Pressed button of the event
fn button(&self) -> MouseButton;
/// State of the button
fn state(&self) -> MouseButtonState;
}
impl PointerButtonEvent for UnusedEvent {
impl<B: InputBackend> PointerButtonEvent<B> 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<B: InputBackend>: Event<B> {
/// 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<B: InputBackend> PointerAxisEvent<B> for UnusedEvent {
fn amount(&self, _axis: Axis) -> Option<f64> {
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<B: InputBackend>: Event<B> {
/// 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<B: InputBackend> PointerMotionEvent<B> 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<B: InputBackend>: Event<B> {
/// 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<B: InputBackend> PointerMotionAbsoluteEvent<B> 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<B: InputBackend>: Event<B> {
/// [`TouchSlot`], if the device has multi-touch capabilities
fn slot(&self) -> Option<TouchSlot>;
@ -378,7 +339,7 @@ pub trait TouchDownEvent: Event {
fn y_transformed(&self, height: u32) -> f64;
}
impl TouchDownEvent for UnusedEvent {
impl<B: InputBackend> TouchDownEvent<B> for UnusedEvent {
fn slot(&self) -> Option<TouchSlot> {
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<B: InputBackend>: Event<B> {
/// [`TouchSlot`], if the device has multi-touch capabilities
fn slot(&self) -> Option<TouchSlot>;
@ -440,7 +401,7 @@ pub trait TouchMotionEvent: Event {
fn y_transformed(&self, height: u32) -> f64;
}
impl TouchMotionEvent for UnusedEvent {
impl<B: InputBackend> TouchMotionEvent<B> for UnusedEvent {
fn slot(&self) -> Option<TouchSlot> {
match *self {}
}
@ -463,33 +424,33 @@ impl TouchMotionEvent for UnusedEvent {
}
/// Trait for touch events finishing.
pub trait TouchUpEvent: Event {
pub trait TouchUpEvent<B: InputBackend>: Event<B> {
/// [`TouchSlot`], if the device has multi-touch capabilities
fn slot(&self) -> Option<TouchSlot>;
}
impl TouchUpEvent for UnusedEvent {
impl<B: InputBackend> TouchUpEvent<B> for UnusedEvent {
fn slot(&self) -> Option<TouchSlot> {
match *self {}
}
}
/// Trait for touch events cancelling the chain
pub trait TouchCancelEvent: Event {
pub trait TouchCancelEvent<B: InputBackend>: Event<B> {
/// [`TouchSlot`], if the device has multi-touch capabilities
fn slot(&self) -> Option<TouchSlot>;
}
impl TouchCancelEvent for UnusedEvent {
impl<B: InputBackend> TouchCancelEvent<B> for UnusedEvent {
fn slot(&self) -> Option<TouchSlot> {
match *self {}
}
}
/// Trait for touch frame events
pub trait TouchFrameEvent: Event {}
pub trait TouchFrameEvent<B: InputBackend>: Event<B> {}
impl TouchFrameEvent for UnusedEvent {}
impl<B: InputBackend> TouchFrameEvent<B> 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<Self>;
/// Type representing axis events on pointer devices
type PointerAxisEvent: PointerAxisEvent;
type PointerAxisEvent: PointerAxisEvent<Self>;
/// Type representing button events on pointer devices
type PointerButtonEvent: PointerButtonEvent;
type PointerButtonEvent: PointerButtonEvent<Self>;
/// Type representing motion events of pointer devices
type PointerMotionEvent: PointerMotionEvent;
type PointerMotionEvent: PointerMotionEvent<Self>;
/// Type representing motion events of pointer devices
type PointerMotionAbsoluteEvent: PointerMotionAbsoluteEvent;
type PointerMotionAbsoluteEvent: PointerMotionAbsoluteEvent<Self>;
/// Type representing touch events starting
type TouchDownEvent: TouchDownEvent;
type TouchDownEvent: TouchDownEvent<Self>;
/// Type representing touch events ending
type TouchUpEvent: TouchUpEvent;
type TouchUpEvent: TouchUpEvent<Self>;
/// Type representing touch events from moving
type TouchMotionEvent: TouchMotionEvent;
type TouchMotionEvent: TouchMotionEvent<Self>;
/// Type representing cancelling of touch events
type TouchCancelEvent: TouchCancelEvent;
type TouchCancelEvent: TouchCancelEvent<Self>;
/// Type representing touch frame events
type TouchFrameEvent: TouchFrameEvent;
type TouchFrameEvent: TouchFrameEvent<Self>;
/// 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<Seat>;
/// 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<F>(&mut self, callback: F) -> Result<(), Self::EventError>
where
F: FnMut(InputEvent<Self>, &mut Self::InputConfig);
F: FnMut(InputEvent<Self>);
}
/// Different events that can be generated by an input backend
#[derive(Debug)]
pub enum InputEvent<B: InputBackend> {
/// 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<B: InputBackend> {
/// 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,
},

View File

@ -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<libinput::Seat, backend::Seat>,
#[cfg(feature = "backend_session")]
links: Vec<SignalToken>,
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<SessionSignal> 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<backend::DeviceCapability> 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<LibinputInputBackend> 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<LibinputInputBackend> 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<LibinputInputBackend> 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<LibinputInputBackend> for event::pointer::PointerAxisEvent {
fn amount(&self, axis: Axis) -> Option<f64> {
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<LibinputInputBackend> 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<LibinputInputBackend> 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<LibinputInputBackend> 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<LibinputInputBackend> 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<LibinputInputBackend> 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<LibinputInputBackend>
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<LibinputInputBackend> 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<LibinputInputBackend> for event::touch::TouchDownEvent {
fn slot(&self) -> Option<backend::TouchSlot> {
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<LibinputInputBackend> 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<LibinputInputBackend> for event::touch::TouchMotionEvent {
fn slot(&self) -> Option<backend::TouchSlot> {
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<LibinputInputBackend> 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<LibinputInputBackend> for event::touch::TouchUpEvent {
fn slot(&self) -> Option<backend::TouchSlot> {
event::touch::TouchEventSlot::slot(self).map(|x| backend::TouchSlot::new(x as u64))
}
}
impl backend::Event for event::touch::TouchCancelEvent {
impl backend::Event<LibinputInputBackend> 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<LibinputInputBackend> for event::touch::TouchCancelEvent {
fn slot(&self) -> Option<backend::TouchSlot> {
event::touch::TouchEventSlot::slot(self).map(|x| backend::TouchSlot::new(x as u64))
}
}
impl backend::Event for event::touch::TouchFrameEvent {
impl backend::Event<LibinputInputBackend> for event::touch::TouchFrameEvent {
fn time(&self) -> u32 {
event::touch::TouchEventTrait::time(self)
}
fn device(&self) -> libinput::Device {
event::EventTrait::device(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<libinput::Device>,
}
impl LibinputConfig {
/// Access the list of current devices
pub fn devices(&mut self) -> &mut [libinput::Device] {
&mut self.devices
}
}
impl backend::TouchFrameEvent<LibinputInputBackend> 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<backend::Seat> {
self.seats.values().cloned().collect()
}
fn input_config(&mut self) -> &mut Self::InputConfig {
&mut self.config
}
type SpecialEvent = backend::UnusedEvent;
fn dispatch_new_events<F>(&mut self, mut callback: F) -> Result<(), IoError>
where
F: FnMut(InputEvent<Self>, &mut LibinputConfig),
F: FnMut(InputEvent<Self>),
{
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::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 });
}
libinput::Event::Touch(touch_event) => {
on_touch_event(
&mut callback,
&self.seats,
&mut self.config,
touch_event,
&self.logger,
);
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::Keyboard(keyboard_event) => {
on_keyboard_event(
&mut callback,
&self.seats,
&mut self.config,
keyboard_event,
&self.logger,
);
},
libinput::Event::Touch(touch_event) => match touch_event {
event::TouchEvent::Down(down_event) => {
callback(InputEvent::TouchDown { event: down_event });
}
libinput::Event::Pointer(pointer_event) => {
on_pointer_event(
&mut callback,
&self.seats,
&mut self.config,
pointer_event,
&self.logger,
);
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<LibinputInputBackend>;
type Metadata = LibinputConfig;
type Metadata = ();
type Ret = ();
fn process_events<F>(&mut self, _: Readiness, _: Token, callback: F) -> std::io::Result<()>
fn process_events<F>(&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<()> {

View File

@ -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<F>(
callback: &mut F,
seats: &mut HashMap<libinput::Seat, backend::Seat>,
config: &mut LibinputConfig,
event: DeviceEvent,
logger: &Logger,
) where
F: FnMut(InputEvent<LibinputInputBackend>, &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<F>(
callback: &mut F,
seats: &HashMap<libinput::Seat, backend::Seat>,
config: &mut LibinputConfig,
event: TouchEvent,
logger: &Logger,
) where
F: FnMut(InputEvent<LibinputInputBackend>, &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<F>(
callback: &mut F,
seats: &HashMap<libinput::Seat, backend::Seat>,
config: &mut LibinputConfig,
event: KeyboardEvent,
logger: &Logger,
) where
F: FnMut(InputEvent<LibinputInputBackend>, &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<F>(
callback: &mut F,
seats: &HashMap<libinput::Seat, backend::Seat>,
config: &mut LibinputConfig,
event: PointerEvent,
logger: &Logger,
) where
F: FnMut(InputEvent<LibinputInputBackend>, &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");
}
}

View File

@ -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<RefCell<WindowSize>>,
}
@ -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<WinitInputBackend> for WinitKeyboardInputEvent {
fn time(&self) -> u32 {
self.time
}
fn device(&self) -> WinitVirtualDevice {
WinitVirtualDevice
}
}
impl KeyboardKeyEvent for WinitKeyboardInputEvent {
impl KeyboardKeyEvent<WinitInputBackend> for WinitKeyboardInputEvent {
fn key_code(&self) -> u32 {
self.key
}
@ -315,13 +332,17 @@ pub struct WinitMouseMovedEvent {
logical_position: LogicalPosition<f64>,
}
impl BackendEvent for WinitMouseMovedEvent {
impl BackendEvent<WinitInputBackend> for WinitMouseMovedEvent {
fn time(&self) -> u32 {
self.time
}
fn device(&self) -> WinitVirtualDevice {
WinitVirtualDevice
}
}
impl PointerMotionAbsoluteEvent for WinitMouseMovedEvent {
impl PointerMotionAbsoluteEvent<WinitInputBackend> 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<WinitInputBackend> for WinitMouseWheelEvent {
fn time(&self) -> u32 {
self.time
}
fn device(&self) -> WinitVirtualDevice {
WinitVirtualDevice
}
}
impl PointerAxisEvent for WinitMouseWheelEvent {
impl PointerAxisEvent<WinitInputBackend> 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<WinitInputBackend> for WinitMouseInputEvent {
fn time(&self) -> u32 {
self.time
}
fn device(&self) -> WinitVirtualDevice {
WinitVirtualDevice
}
}
impl PointerButtonEvent for WinitMouseInputEvent {
impl PointerButtonEvent<WinitInputBackend> for WinitMouseInputEvent {
fn button(&self) -> MouseButton {
self.button.into()
}
@ -417,13 +446,17 @@ pub struct WinitTouchStartedEvent {
id: u64,
}
impl BackendEvent for WinitTouchStartedEvent {
impl BackendEvent<WinitInputBackend> for WinitTouchStartedEvent {
fn time(&self) -> u32 {
self.time
}
fn device(&self) -> WinitVirtualDevice {
WinitVirtualDevice
}
}
impl TouchDownEvent for WinitTouchStartedEvent {
impl TouchDownEvent<WinitInputBackend> for WinitTouchStartedEvent {
fn slot(&self) -> Option<TouchSlot> {
Some(TouchSlot::new(self.id))
}
@ -460,13 +493,17 @@ pub struct WinitTouchMovedEvent {
id: u64,
}
impl BackendEvent for WinitTouchMovedEvent {
impl BackendEvent<WinitInputBackend> for WinitTouchMovedEvent {
fn time(&self) -> u32 {
self.time
}
fn device(&self) -> WinitVirtualDevice {
WinitVirtualDevice
}
}
impl TouchMotionEvent for WinitTouchMovedEvent {
impl TouchMotionEvent<WinitInputBackend> for WinitTouchMovedEvent {
fn slot(&self) -> Option<TouchSlot> {
Some(TouchSlot::new(self.id))
}
@ -501,13 +538,17 @@ pub struct WinitTouchEndedEvent {
id: u64,
}
impl BackendEvent for WinitTouchEndedEvent {
impl BackendEvent<WinitInputBackend> for WinitTouchEndedEvent {
fn time(&self) -> u32 {
self.time
}
fn device(&self) -> WinitVirtualDevice {
WinitVirtualDevice
}
}
impl TouchUpEvent for WinitTouchEndedEvent {
impl TouchUpEvent<WinitInputBackend> for WinitTouchEndedEvent {
fn slot(&self) -> Option<TouchSlot> {
Some(TouchSlot::new(self.id))
}
@ -520,27 +561,26 @@ pub struct WinitTouchCancelledEvent {
id: u64,
}
impl BackendEvent for WinitTouchCancelledEvent {
impl BackendEvent<WinitInputBackend> for WinitTouchCancelledEvent {
fn time(&self) -> u32 {
self.time
}
fn device(&self) -> WinitVirtualDevice {
WinitVirtualDevice
}
}
impl TouchCancelEvent for WinitTouchCancelledEvent {
impl TouchCancelEvent<WinitInputBackend> for WinitTouchCancelledEvent {
fn slot(&self) -> Option<TouchSlot> {
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<Seat> {
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<F>(&mut self, mut callback: F) -> ::std::result::Result<(), WinitInputError>
where
F: FnMut(InputEvent<Self>, &mut WinitInputConfig),
F: FnMut(InputEvent<Self>),
{
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;
}