input/
event.rs

1//! Libinput Events
2
3use crate::{ffi, AsRaw, Context, Device, FromRaw, Libinput};
4
5/// A libinput `Event`
6#[derive(Debug, PartialEq, Eq, Hash)]
7#[non_exhaustive]
8pub enum Event {
9    /// A device related `Event`
10    Device(DeviceEvent),
11    /// A keyboard related `Event`
12    Keyboard(KeyboardEvent),
13    /// A pointer related `Event`
14    Pointer(PointerEvent),
15    /// A touch related `Event`
16    Touch(TouchEvent),
17    /// A tablet related `Event`
18    Tablet(TabletToolEvent),
19    /// A tabled pad related `Event`
20    TabletPad(TabletPadEvent),
21    /// A gesture related `Event`
22    Gesture(GestureEvent),
23    /// A switch related `Event`
24    Switch(SwitchEvent),
25}
26
27/// Common functions all (Sub-)Events implement.
28pub trait EventTrait: Context {
29    #[doc(hidden)]
30    fn as_raw_event(&self) -> *mut ffi::libinput_event;
31
32    /// Convert into a general `Event` again
33    fn into_event(self) -> Event
34    where
35        Self: Sized,
36    {
37        unsafe { Event::from_raw(self.as_raw_event(), self.context()) }
38    }
39
40    /// Return the device associated with this event.
41    ///
42    /// For device added/removed events this is the device added or removed.
43    /// For all other device events, this is the device that generated the event.
44    fn device(&self) -> Device {
45        unsafe {
46            Device::from_raw(
47                ffi::libinput_event_get_device(self.as_raw_event()),
48                self.context(),
49            )
50        }
51    }
52}
53
54impl EventTrait for Event {
55    fn as_raw_event(&self) -> *mut ffi::libinput_event {
56        self.as_raw_mut()
57    }
58}
59
60impl FromRaw<ffi::libinput_event> for Event {
61    unsafe fn from_raw(event: *mut ffi::libinput_event, context: &Libinput) -> Self {
62        Self::try_from_raw(event, context).expect("libinput returned invalid 'libinput_event_type'")
63    }
64
65    unsafe fn try_from_raw(event: *mut ffi::libinput_event, context: &Libinput) -> Option<Self> {
66        match ffi::libinput_event_get_type(event) {
67            ffi::libinput_event_type_LIBINPUT_EVENT_NONE => None,
68            ffi::libinput_event_type_LIBINPUT_EVENT_DEVICE_ADDED
69            | ffi::libinput_event_type_LIBINPUT_EVENT_DEVICE_REMOVED => {
70                Some(Event::Device(DeviceEvent::try_from_raw(
71                    ffi::libinput_event_get_device_notify_event(event),
72                    context,
73                )?))
74            }
75            ffi::libinput_event_type_LIBINPUT_EVENT_KEYBOARD_KEY => {
76                Some(Event::Keyboard(KeyboardEvent::try_from_raw(
77                    ffi::libinput_event_get_keyboard_event(event),
78                    context,
79                )?))
80            }
81            #[cfg(not(feature = "libinput_1_19"))]
82            ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_MOTION
83            | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE
84            | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_BUTTON
85            | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_AXIS => Some(Event::Pointer(
86                PointerEvent::try_from_raw(ffi::libinput_event_get_pointer_event(event), context)?,
87            )),
88            #[cfg(feature = "libinput_1_19")]
89            ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_MOTION
90            | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE
91            | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_BUTTON
92            | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_AXIS
93            | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_SCROLL_WHEEL
94            | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_SCROLL_FINGER
95            | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS => {
96                Some(Event::Pointer(PointerEvent::try_from_raw(
97                    ffi::libinput_event_get_pointer_event(event),
98                    context,
99                )?))
100            }
101            ffi::libinput_event_type_LIBINPUT_EVENT_TOUCH_DOWN
102            | ffi::libinput_event_type_LIBINPUT_EVENT_TOUCH_UP
103            | ffi::libinput_event_type_LIBINPUT_EVENT_TOUCH_MOTION
104            | ffi::libinput_event_type_LIBINPUT_EVENT_TOUCH_CANCEL
105            | ffi::libinput_event_type_LIBINPUT_EVENT_TOUCH_FRAME => Some(Event::Touch(
106                TouchEvent::try_from_raw(ffi::libinput_event_get_touch_event(event), context)?,
107            )),
108            ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_TOOL_AXIS
109            | ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY
110            | ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_TOOL_TIP
111            | ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_TOOL_BUTTON => {
112                Some(Event::Tablet(TabletToolEvent::try_from_raw(
113                    ffi::libinput_event_get_tablet_tool_event(event),
114                    context,
115                )?))
116            }
117            #[cfg(not(feature = "libinput_1_15"))]
118            ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_BUTTON
119            | ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_RING
120            | ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_STRIP => {
121                Some(Event::TabletPad(TabletPadEvent::try_from_raw(
122                    ffi::libinput_event_get_tablet_pad_event(event),
123                    context,
124                )?))
125            }
126            #[cfg(feature = "libinput_1_15")]
127            ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_BUTTON
128            | ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_RING
129            | ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_STRIP
130            | ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_KEY => {
131                Some(Event::TabletPad(TabletPadEvent::try_from_raw(
132                    ffi::libinput_event_get_tablet_pad_event(event),
133                    context,
134                )?))
135            }
136            #[cfg(not(feature = "libinput_1_19"))]
137            ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN
138            | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE
139            | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_END
140            | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_BEGIN
141            | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_UPDATE
142            | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_END => Some(Event::Gesture(
143                GestureEvent::try_from_raw(ffi::libinput_event_get_gesture_event(event), context)?,
144            )),
145            #[cfg(feature = "libinput_1_19")]
146            ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN
147            | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE
148            | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_END
149            | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_BEGIN
150            | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_UPDATE
151            | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_END
152            | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_HOLD_BEGIN
153            | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_HOLD_END => Some(Event::Gesture(
154                GestureEvent::try_from_raw(ffi::libinput_event_get_gesture_event(event), context)?,
155            )),
156            ffi::libinput_event_type_LIBINPUT_EVENT_SWITCH_TOGGLE => Some(Event::Switch(
157                SwitchEvent::try_from_raw(ffi::libinput_event_get_switch_event(event), context)?,
158            )),
159            _ => None,
160        }
161    }
162}
163
164impl AsRaw<ffi::libinput_event> for Event {
165    fn as_raw(&self) -> *const ffi::libinput_event {
166        match self {
167            Event::Device(event) => event.as_raw_event() as *const _,
168            Event::Keyboard(event) => event.as_raw_event() as *const _,
169            Event::Pointer(event) => event.as_raw_event() as *const _,
170            Event::Touch(event) => event.as_raw_event() as *const _,
171            Event::Tablet(event) => event.as_raw_event() as *const _,
172            Event::TabletPad(event) => event.as_raw_event() as *const _,
173            Event::Gesture(event) => event.as_raw_event() as *const _,
174            Event::Switch(event) => event.as_raw_event() as *const _,
175        }
176    }
177}
178
179impl Context for Event {
180    fn context(&self) -> &crate::Libinput {
181        match self {
182            Event::Device(event) => event.context(),
183            Event::Keyboard(event) => event.context(),
184            Event::Pointer(event) => event.context(),
185            Event::Touch(event) => event.context(),
186            Event::Tablet(event) => event.context(),
187            Event::TabletPad(event) => event.context(),
188            Event::Gesture(event) => event.context(),
189            Event::Switch(event) => event.context(),
190        }
191    }
192}
193
194macro_rules! ffi_event_struct {
195    ($(#[$attr:meta])* struct $struct_name:ident, $ffi_name:path, $get_base_fn:path) => (
196        #[derive(Eq)]
197        $(#[$attr])*
198        pub struct $struct_name
199        {
200            ffi: *mut $ffi_name,
201            context: $crate::context::Libinput,
202        }
203
204        impl std::fmt::Debug for $struct_name {
205            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
206                write!(f, "{} @{:p}", stringify!($struct_name), self.as_raw())
207            }
208        }
209
210        impl FromRaw<$ffi_name> for $struct_name
211        {
212            unsafe fn try_from_raw(ffi: *mut $ffi_name, context: &$crate::context::Libinput) -> Option<Self> {
213                Some(Self::from_raw(ffi, context))
214            }
215            unsafe fn from_raw(ffi: *mut $ffi_name, context: &$crate::context::Libinput) -> Self {
216                $struct_name {
217                    ffi,
218                    context: context.clone(),
219                }
220            }
221        }
222
223        impl AsRaw<$ffi_name> for $struct_name
224        {
225            fn as_raw(&self) -> *const $ffi_name {
226                self.ffi as *const _
227            }
228        }
229
230        impl $crate::Context for $struct_name {
231            fn context(&self) -> &$crate::context::Libinput {
232                &self.context
233            }
234        }
235
236        impl PartialEq for $struct_name {
237            fn eq(&self, other: &Self) -> bool {
238                self.as_raw() == other.as_raw()
239            }
240        }
241
242        impl std::hash::Hash for $struct_name {
243            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
244                self.as_raw().hash(state);
245            }
246        }
247
248        impl EventTrait for $struct_name {
249            #[doc(hidden)]
250            fn as_raw_event(&self) -> *mut $crate::ffi::libinput_event {
251                unsafe { $get_base_fn(self.as_raw_mut()) }
252            }
253        }
254
255        impl Drop for $struct_name {
256            fn drop(&mut self) {
257                unsafe { $crate::ffi::libinput_event_destroy(self.as_raw_event()) }
258            }
259        }
260    )
261}
262
263pub mod device;
264pub mod gesture;
265pub mod keyboard;
266pub mod pointer;
267pub mod switch;
268pub mod tablet_pad;
269pub mod tablet_tool;
270pub mod touch;
271
272pub use self::device::DeviceEvent;
273pub use self::gesture::GestureEvent;
274pub use self::keyboard::KeyboardEvent;
275pub use self::pointer::PointerEvent;
276pub use self::switch::SwitchEvent;
277pub use self::tablet_pad::TabletPadEvent;
278pub use self::tablet_tool::TabletToolEvent;
279pub use self::touch::TouchEvent;