//! Common traits for input backends to receive input from. use std::path::PathBuf; pub use xkbcommon::xkb::Keycode; mod tablet; pub use tablet::{ ProximityState, TabletToolAxisEvent, TabletToolButtonEvent, TabletToolCapabilities, TabletToolDescriptor, TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TabletToolType, }; #[cfg(feature = "wayland_frontend")] use wayland_server::protocol::wl_pointer; use crate::utils::{Logical, Point, Raw, Size}; /// 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; /// Returns device USB (product,vendor) id fn usb_id(&self) -> Option<(u32, u32)>; /// Returns the syspath of the device. /// /// The path is an absolute path and includes the sys mount point. fn syspath(&self) -> Option; } /// 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 { /// Timestamp in milliseconds fn time_msec(&self) -> u32 { (self.time() / 1000) as u32 } /// Timestamp in microseconds, with an undefined base. /// /// Libinput does not guarantee that timestamps always increase monotonically. // # TODO: // - check if events can even arrive out of order. // - Make stronger time guarantees, if possible fn time(&self) -> u64; /// Returns the device, that generated this event fn device(&self) -> B::Device; } /// Used to mark events never emitted by an [`InputBackend`] implementation. /// /// Implements all event types and can be used in place for any [`Event`] type, /// that is not used by an [`InputBackend`] implementation. Initialization is not /// possible, making accidental use impossible and enabling a lot of possible /// compiler optimizations. #[derive(Debug)] pub enum UnusedEvent {} impl Event for UnusedEvent { fn time(&self) -> u64 { match *self {} } fn device(&self) -> B::Device { match *self {} } } /// State of key on a keyboard. Either pressed or released #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] pub enum KeyState { /// Key is released Released, /// Key is pressed Pressed, } /// Trait for keyboard event pub trait KeyboardKeyEvent: Event { /// Returns the numerical button code of the keyboard button. /// /// The value will correspond to one `KEY_` constants from the Linux [input event codes] inside /// `input-event-codes.h`. /// /// [input event codes]: https://gitlab.freedesktop.org/libinput/libinput/-/blob/main/include/linux/linux/input-event-codes.h fn key_code(&self) -> Keycode; /// State of the key fn state(&self) -> KeyState; /// Total number of keys pressed on all devices on the associated [`Seat`](crate::input::Seat) fn count(&self) -> u32; } impl KeyboardKeyEvent for UnusedEvent { fn key_code(&self) -> Keycode { match *self {} } fn state(&self) -> KeyState { match *self {} } fn count(&self) -> u32 { match *self {} } } /// A particular mouse button #[non_exhaustive] #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] pub enum MouseButton { /// Left mouse button Left, /// Middle mouse button Middle, /// Right mouse button Right, /// Back mouse button. Back, /// Forward mouse button. Forward, } /// State of a button on a pointer device, like mouse or tablet tool. Either pressed or released #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] pub enum ButtonState { /// Button is released Released, /// Button is pressed Pressed, } /// Common methods pointer event generated by pressed buttons do implement pub trait PointerButtonEvent: Event { /// Pressed button of the event. /// /// This may return [`None`] if the button pressed in the event is not a standard mouse button. You may /// obtain the button code using [`PointerButtonEvent::button_code`]. fn button(&self) -> Option { // These values are coming from . const BTN_LEFT: u32 = 0x110; const BTN_RIGHT: u32 = 0x111; const BTN_MIDDLE: u32 = 0x112; const BTN_SIDE: u32 = 0x113; const BTN_EXTRA: u32 = 0x114; const BTN_FORWARD: u32 = 0x115; const BTN_BACK: u32 = 0x116; match self.button_code() { BTN_LEFT => Some(MouseButton::Left), BTN_RIGHT => Some(MouseButton::Right), BTN_MIDDLE => Some(MouseButton::Middle), BTN_BACK | BTN_SIDE => Some(MouseButton::Back), BTN_FORWARD | BTN_EXTRA => Some(MouseButton::Forward), _ => None, } } /// Returns the numerical button code of the mouse button. /// /// The value will correspond to one `BTN_` constants from the Linux [input event codes] inside /// `input-event-codes.h`. /// /// [input event codes]: https://gitlab.freedesktop.org/libinput/libinput/-/blob/main/include/linux/linux/input-event-codes.h fn button_code(&self) -> u32; /// State of the button fn state(&self) -> ButtonState; } impl PointerButtonEvent for UnusedEvent { fn button_code(&self) -> u32 { match *self {} } fn state(&self) -> ButtonState { match *self {} } } /// Trait for gesture begin events. pub trait GestureBeginEvent: Event { /// Number of fingers. fn fingers(&self) -> u32; } impl GestureBeginEvent for UnusedEvent { fn fingers(&self) -> u32 { match *self {} } } /// Trait for gesture end events. pub trait GestureEndEvent: Event { /// True if event was cancelled. fn cancelled(&self) -> bool; } impl GestureEndEvent for UnusedEvent { fn cancelled(&self) -> bool { match *self {} } } /// Trait for gesture swipe begin event. pub trait GestureSwipeBeginEvent: GestureBeginEvent {} impl GestureSwipeBeginEvent for UnusedEvent {} /// Trait for gesture swipe update event. pub trait GestureSwipeUpdateEvent: Event { /// Delta of center on the x axis from last begin/update. fn delta_x(&self) -> f64; /// Delta of center on the y axis from last begin/update. fn delta_y(&self) -> f64; /// Delta between the last and new gesture center. fn delta(&self) -> Point { (self.delta_x(), self.delta_y()).into() } } impl GestureSwipeUpdateEvent for UnusedEvent { fn delta_x(&self) -> f64 { match *self {} } fn delta_y(&self) -> f64 { match *self {} } } /// Trait for gesture swipe end event. pub trait GestureSwipeEndEvent: GestureEndEvent {} impl GestureSwipeEndEvent for UnusedEvent {} /// Trait for gesture pinch begin event. pub trait GesturePinchBeginEvent: GestureBeginEvent {} impl GesturePinchBeginEvent for UnusedEvent {} /// Trait for gesture pinch update event. pub trait GesturePinchUpdateEvent: Event { /// Delta of center on the x axis from last begin/update. fn delta_x(&self) -> f64; /// Delta of center on the y axis from last begin/update. fn delta_y(&self) -> f64; /// Absolute scale compared to begin event. fn scale(&self) -> f64; /// Relative angle in degrees from last begin/update. fn rotation(&self) -> f64; /// Delta between the last and new gesture center. fn delta(&self) -> Point { (self.delta_x(), self.delta_y()).into() } } impl GesturePinchUpdateEvent for UnusedEvent { fn delta_x(&self) -> f64 { match *self {} } fn delta_y(&self) -> f64 { match *self {} } fn scale(&self) -> f64 { match *self {} } fn rotation(&self) -> f64 { match *self {} } } /// Trait for gesture pinch end event. pub trait GesturePinchEndEvent: GestureEndEvent {} impl GesturePinchEndEvent for UnusedEvent {} /// Trait for gesture hold begin event. pub trait GestureHoldBeginEvent: GestureBeginEvent {} impl GestureHoldBeginEvent for UnusedEvent {} /// Trait for gesture hold end event. pub trait GestureHoldEndEvent: GestureEndEvent {} impl GestureHoldEndEvent for UnusedEvent {} /// Axis when scrolling #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] pub enum Axis { /// Vertical axis Vertical, /// Horizontal axis Horizontal, } /// Source of an axis when scrolling #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum AxisSource { /// Finger. Mostly used for trackpads. /// /// Guarantees that a scroll sequence is terminated with a scroll value of 0. /// A caller may use this information to decide on whether kinetic scrolling should /// be triggered on this scroll sequence. /// /// The coordinate system is identical to the /// cursor movement, i.e. a scroll value of 1 represents the equivalent relative /// motion of 1. Finger, /// Continuous scrolling device. Almost identical to [`Finger`](AxisSource::Finger) /// /// No terminating event is guaranteed (though it may happen). /// /// The coordinate system is identical to /// the cursor movement, i.e. a scroll value of 1 represents the equivalent relative /// motion of 1. Continuous, /// Scroll wheel. /// /// No terminating event is guaranteed (though it may happen). Scrolling is in /// discrete steps. It is up to the caller how to interpret such different step sizes. Wheel, /// Scrolling through tilting the scroll wheel. /// /// No terminating event is guaranteed (though it may happen). Scrolling is in /// discrete steps. It is up to the caller how to interpret such different step sizes. WheelTilt, } /// Direction of physical motion that caused pointer axis event #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum AxisRelativeDirection { /// Physical motion matches axis direction Identical, /// Physical motion is inverse of axis direction (e.g. natural scrolling) Inverted, } #[cfg(feature = "wayland_frontend")] impl From for wl_pointer::AxisRelativeDirection { #[inline] fn from(direction: AxisRelativeDirection) -> Self { match direction { AxisRelativeDirection::Identical => wl_pointer::AxisRelativeDirection::Identical, AxisRelativeDirection::Inverted => wl_pointer::AxisRelativeDirection::Inverted, } } } /// Trait for pointer events generated by scrolling on an axis. 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`]. fn amount(&self, axis: Axis) -> Option; /// Amount of scrolling in discrete steps on the given [`Axis`]. /// /// Guaranteed to be `Some` when source returns either [`AxisSource::Wheel`] or [`AxisSource::WheelTilt`]. fn amount_v120(&self, axis: Axis) -> Option; /// Source of the scroll event. fn source(&self) -> AxisSource; /// Relative direction of physical motion. fn relative_direction(&self, axis: Axis) -> AxisRelativeDirection; } impl PointerAxisEvent for UnusedEvent { fn amount(&self, _axis: Axis) -> Option { match *self {} } fn amount_v120(&self, _axis: Axis) -> Option { match *self {} } fn source(&self) -> AxisSource { match *self {} } fn relative_direction(&self, _axis: Axis) -> AxisRelativeDirection { match *self {} } } /// Trait for pointer events generated by relative device movement. pub trait PointerMotionEvent: Event { /// Delta between the last and new pointer device position interpreted as pixel movement fn delta(&self) -> Point { (self.delta_x(), self.delta_y()).into() } /// Unaccelerated delta between the last and new pointer device position fn delta_unaccel(&self) -> Point { (self.delta_x_unaccel(), self.delta_y_unaccel()).into() } /// Delta on the x axis between the last and new pointer device position interpreted as pixel movement fn delta_x(&self) -> f64; /// Delta on the y axis between the last and new pointer device position interpreted as pixel movement fn delta_y(&self) -> f64; /// Unaccelerated delta on the x axis between the last and new pointer device position fn delta_x_unaccel(&self) -> f64; /// Unaccelerated delta on the y axis between the last and new pointer device position fn delta_y_unaccel(&self) -> f64; } impl PointerMotionEvent for UnusedEvent { fn delta_x(&self) -> f64 { match *self {} } fn delta_y(&self) -> f64 { match *self {} } fn delta_x_unaccel(&self) -> f64 { match *self {} } fn delta_y_unaccel(&self) -> f64 { match *self {} } } /// Trait for pointer events generated by absolute device positioning. pub trait PointerMotionAbsoluteEvent: AbsolutePositionEvent {} impl PointerMotionAbsoluteEvent for UnusedEvent {} /// Input event with absolute location data. pub trait AbsolutePositionEvent: Event { /// Device position in it's original coordinate space. /// /// The format is defined by the backend implementation. fn position(&self) -> Point { (self.x(), self.y()).into() } /// Device x position in it's original coordinate space. /// /// The format is defined by the backend implementation. fn x(&self) -> f64; /// Device y position in it's original coordinate space. /// /// The format is defined by the backend implementation. fn y(&self) -> f64; /// Device position converted to the targets coordinate space. /// E.g. the focused output's resolution. fn position_transformed(&self, coordinate_space: Size) -> Point { ( self.x_transformed(coordinate_space.w), self.y_transformed(coordinate_space.h), ) .into() } /// Device x position converted to the targets coordinate space's width. /// E.g. the focused output's width. fn x_transformed(&self, width: i32) -> f64; /// Device y position converted to the targets coordinate space's height. /// E.g. the focused output's height. fn y_transformed(&self, height: i32) -> f64; } impl AbsolutePositionEvent for UnusedEvent { fn x(&self) -> f64 { match *self {} } fn y(&self) -> f64 { match *self {} } fn x_transformed(&self, _width: i32) -> f64 { match *self {} } fn y_transformed(&self, _height: i32) -> f64 { match *self {} } } /// Slot of a different touch event. /// /// Touch events are grouped by slots, usually to identify different /// fingers on a multi-touch enabled input device. Events should only /// be interpreted in the context of other events on the same slot. #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct TouchSlot { id: Option, } impl From> for TouchSlot { #[inline] fn from(id: Option) -> Self { Self { id } } } impl From for i32 { #[inline] fn from(slot: TouchSlot) -> i32 { slot.id.map(|id| id as i32).unwrap_or(-1) } } /// Trait with functions available for all touch events. pub trait TouchEvent: Event { /// Multi-touch slot identifier. fn slot(&self) -> TouchSlot; } impl TouchEvent for UnusedEvent { #[inline] fn slot(&self) -> TouchSlot { match *self {} } } /// Trait for touch events starting at a given position. pub trait TouchDownEvent: TouchEvent + AbsolutePositionEvent {} impl TouchDownEvent for UnusedEvent {} /// Trait for touch events regarding movement on the screen pub trait TouchMotionEvent: TouchEvent + AbsolutePositionEvent {} impl TouchMotionEvent for UnusedEvent {} /// Trait for touch events finishing. pub trait TouchUpEvent: TouchEvent {} impl TouchUpEvent for UnusedEvent {} /// Trait for touch events canceling the chain pub trait TouchCancelEvent: TouchEvent {} impl TouchCancelEvent for UnusedEvent {} /// Trait for touch frame events pub trait TouchFrameEvent: Event {} impl TouchFrameEvent for UnusedEvent {} /// Types of Switches #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum Switch { /// The laptop lid was closed when the [`SwitchState`] is /// [`On`](SwitchState::On), or was opened when it is [`Off`](SwitchState::Off) Lid, /// This switch indicates whether the device is in normal laptop mode /// or behaves like a tablet-like device where the primary /// interaction is usually a touch screen. When in tablet mode, the /// keyboard and touchpad are usually inaccessible. /// /// If the switch is in state [`SwitchState::Off`], the /// device is in laptop mode. If the switch is in state /// [`SwitchState::On`], the device is in tablet mode and the /// keyboard or touchpad may not be accessible. /// /// It is up to the caller to identify which devices are inaccessible /// in tablet mode. TabletMode, } /// State of a Switch #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum SwitchState { /// Switch is off Off, /// Switch is on On, } /// Trait for switch toggle events pub trait SwitchToggleEvent: Event { /// [`Switch`] which triggered the event fn switch(&self) -> Option; /// [`State`](SwitchState) of the switch fn state(&self) -> SwitchState; } impl SwitchToggleEvent for UnusedEvent { fn switch(&self) -> Option { match *self {} } fn state(&self) -> SwitchState { match *self {} } } /// 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 /// given events. pub trait InputBackend: Sized { /// Type representing input devices type Device: Device; /// Type representing keyboard events type KeyboardKeyEvent: KeyboardKeyEvent; /// Type representing axis events on pointer devices type PointerAxisEvent: PointerAxisEvent; /// Type representing button events on pointer devices type PointerButtonEvent: PointerButtonEvent; /// Type representing motion events of pointer devices type PointerMotionEvent: PointerMotionEvent; /// Type representing motion events of pointer devices type PointerMotionAbsoluteEvent: PointerMotionAbsoluteEvent; /// Type representing swipe begin events of pointer devices type GestureSwipeBeginEvent: GestureSwipeBeginEvent; /// Type representing swipe update events of pointer devices type GestureSwipeUpdateEvent: GestureSwipeUpdateEvent; /// Type representing swipe end events of pointer devices type GestureSwipeEndEvent: GestureSwipeEndEvent; /// Type representing pinch begin events of pointer devices type GesturePinchBeginEvent: GesturePinchBeginEvent; /// Type representing pinch update events of pointer devices type GesturePinchUpdateEvent: GesturePinchUpdateEvent; /// Type representing pinch end events of pointer devices type GesturePinchEndEvent: GesturePinchEndEvent; /// Type representing hold begin events of pointer devices type GestureHoldBeginEvent: GestureHoldBeginEvent; /// Type representing hold end events of pointer devices type GestureHoldEndEvent: GestureHoldEndEvent; /// Type representing touch events starting type TouchDownEvent: TouchDownEvent; /// Type representing touch events ending type TouchUpEvent: TouchUpEvent; /// Type representing touch events from moving type TouchMotionEvent: TouchMotionEvent; /// Type representing canceling of touch events type TouchCancelEvent: TouchCancelEvent; /// Type representing touch frame events type TouchFrameEvent: TouchFrameEvent; /// Type representing axis events on tablet devices type TabletToolAxisEvent: TabletToolAxisEvent; /// Type representing proximity events on tablet devices type TabletToolProximityEvent: TabletToolProximityEvent; /// Type representing tip events on tablet devices type TabletToolTipEvent: TabletToolTipEvent; /// Type representing button events on tablet tool devices type TabletToolButtonEvent: TabletToolButtonEvent; /// Type representing switch toggle events type SwitchToggleEvent: SwitchToggleEvent; /// Special events that are custom to this backend type SpecialEvent; } /// Different events that can be generated by an input backend #[derive(Debug)] pub enum InputEvent { /// 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 occurred Keyboard { /// The keyboard event event: B::KeyboardKeyEvent, }, /// A relative pointer motion occurred PointerMotion { /// The pointer motion event event: B::PointerMotionEvent, }, /// An absolute pointer motion occurs PointerMotionAbsolute { /// The absolute pointer motion event event: B::PointerMotionAbsoluteEvent, }, /// A pointer button was pressed or released PointerButton { /// The pointer button event event: B::PointerButtonEvent, }, /// A pointer action occurred while scrolling on an axis PointerAxis { /// The pointer axis event event: B::PointerAxisEvent, }, /// A pointer swipe gesture began GestureSwipeBegin { /// The gesture event event: B::GestureSwipeBeginEvent, }, /// A pointer swipe gesture updated GestureSwipeUpdate { /// The gesture event event: B::GestureSwipeUpdateEvent, }, /// A pointer swipe gesture ended GestureSwipeEnd { /// The gesture event event: B::GestureSwipeEndEvent, }, /// A pointer pinch gesture began GesturePinchBegin { /// The gesture event event: B::GesturePinchBeginEvent, }, /// A pointer pinch gesture updated GesturePinchUpdate { /// The gesture event event: B::GesturePinchUpdateEvent, }, /// A pointer pinch gesture ended GesturePinchEnd { /// The gesture event event: B::GesturePinchEndEvent, }, /// A pointer hold gesture began GestureHoldBegin { /// The gesture event event: B::GestureHoldBeginEvent, }, /// A pointer hold gesture ended GestureHoldEnd { /// The gesture event event: B::GestureHoldEndEvent, }, /// A new touchpoint appeared TouchDown { /// The touch down event event: B::TouchDownEvent, }, /// A touchpoint moved TouchMotion { /// The touch motion event event: B::TouchMotionEvent, }, /// A touchpoint was removed TouchUp { /// The touch up event event: B::TouchUpEvent, }, /// A touch sequence was cancelled TouchCancel { /// The touch cancel event event: B::TouchCancelEvent, }, /// A touch frame was emitted /// /// A set of two events received on the same seat between two frames should /// be interpreted as an atomic event. TouchFrame { /// The touch frame event event: B::TouchFrameEvent, }, /// A tablet tool axis was emitted TabletToolAxis { /// The tablet tool axis event event: B::TabletToolAxisEvent, }, /// A tablet tool proximity was emitted TabletToolProximity { /// The tablet tool proximity event event: B::TabletToolProximityEvent, }, /// A tablet tool tip event was emitted TabletToolTip { /// The tablet tool axis event event: B::TabletToolTipEvent, }, /// A tablet tool button was pressed or released TabletToolButton { /// The pointer button event event: B::TabletToolButtonEvent, }, /// A switch was toggled SwitchToggle { /// The switch toggle event event: B::SwitchToggleEvent, }, /// Special event specific of this backend Special(B::SpecialEvent), } /// Converts an xorg mouse button to the format used by libinput. /// /// Taken from https://sources.debian.org/src/xserver-xorg-input-libinput/1.1.0-1/src/xf86libinput.c/?hl=1508#L236-L252 #[cfg(any(feature = "backend_winit", feature = "backend_x11"))] pub(crate) fn xorg_mouse_to_libinput(xorg: u32) -> u32 { match xorg { 0 => 0, 1 => 0x110, // BTN_LEFT 2 => 0x112, // BTN_MIDDLE 3 => 0x111, // BTN_RIGHT _ => xorg - 8 + 0x113, // BTN_SIZE } }