| 1 | //! Libinput Events |
| 2 | |
| 3 | use crate::{ffi, AsRaw, Context, Device, FromRaw, Libinput}; |
| 4 | |
| 5 | /// A libinput `Event` |
| 6 | #[derive (Debug, PartialEq, Eq, Hash)] |
| 7 | #[non_exhaustive ] |
| 8 | pub 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. |
| 28 | pub 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 | |
| 54 | impl EventTrait for Event { |
| 55 | fn as_raw_event(&self) -> *mut ffi::libinput_event { |
| 56 | self.as_raw_mut() |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | impl 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 | |
| 164 | impl 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 | |
| 179 | impl 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 | |
| 194 | macro_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 | |
| 263 | pub mod device; |
| 264 | pub mod gesture; |
| 265 | pub mod keyboard; |
| 266 | pub mod pointer; |
| 267 | pub mod switch; |
| 268 | pub mod tablet_pad; |
| 269 | pub mod tablet_tool; |
| 270 | pub mod touch; |
| 271 | |
| 272 | pub use self::device::DeviceEvent; |
| 273 | pub use self::gesture::GestureEvent; |
| 274 | pub use self::keyboard::KeyboardEvent; |
| 275 | pub use self::pointer::PointerEvent; |
| 276 | pub use self::switch::SwitchEvent; |
| 277 | pub use self::tablet_pad::TabletPadEvent; |
| 278 | pub use self::tablet_tool::TabletToolEvent; |
| 279 | pub use self::touch::TouchEvent; |
| 280 | |