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: &DeviceEvent) => event.as_raw_event() as *const _,
168 Event::Keyboard(event: &KeyboardEvent) => event.as_raw_event() as *const _,
169 Event::Pointer(event: &PointerEvent) => event.as_raw_event() as *const _,
170 Event::Touch(event: &TouchEvent) => event.as_raw_event() as *const _,
171 Event::Tablet(event: &TabletToolEvent) => event.as_raw_event() as *const _,
172 Event::TabletPad(event: &TabletPadEvent) => event.as_raw_event() as *const _,
173 Event::Gesture(event: &GestureEvent) => event.as_raw_event() as *const _,
174 Event::Switch(event: &SwitchEvent) => 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: &DeviceEvent) => event.context(),
183 Event::Keyboard(event: &KeyboardEvent) => event.context(),
184 Event::Pointer(event: &PointerEvent) => event.context(),
185 Event::Touch(event: &TouchEvent) => event.context(),
186 Event::Tablet(event: &TabletToolEvent) => event.context(),
187 Event::TabletPad(event: &TabletPadEvent) => event.context(),
188 Event::Gesture(event: &GestureEvent) => event.context(),
189 Event::Switch(event: &SwitchEvent) => 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;
280