1 | // Allow unnecessary casts since ffi types may differ by C ABI |
2 | // TODO Error type instead of `Result<_, ()>` |
3 | // TODO Better way to handle `SendEventsMode::ENABLED` being 0? |
4 | #![allow ( |
5 | clippy::bad_bit_mask, |
6 | clippy::result_unit_err, |
7 | clippy::unnecessary_cast |
8 | )] |
9 | |
10 | use crate::{ |
11 | event::{switch::Switch, tablet_pad::TabletPadModeGroup}, |
12 | ffi, AsRaw, FromRaw, Libinput, Seat, |
13 | }; |
14 | use bitflags::bitflags; |
15 | use std::ffi::{CStr, CString}; |
16 | #[cfg (feature = "udev" )] |
17 | use udev::{ |
18 | ffi::{udev as udev_context, udev_device, udev_device_get_udev, udev_ref}, |
19 | Device as UdevDevice, FromRawWithContext as UdevFromRawWithContext, |
20 | }; |
21 | |
22 | /// Capabilities on a device. |
23 | /// |
24 | /// A device may have one or more capabilities at a time, capabilities |
25 | /// remain static for the lifetime of the device. |
26 | #[derive (Debug, Copy, Clone, PartialEq, Eq, Hash)] |
27 | #[non_exhaustive ] |
28 | pub enum DeviceCapability { |
29 | /// Keyboard capability |
30 | Keyboard, |
31 | /// Pointer capability |
32 | Pointer, |
33 | /// Touch capability |
34 | Touch, |
35 | /// TabletTool capability |
36 | TabletTool, |
37 | /// TabletPad capability |
38 | TabletPad, |
39 | /// Gesture capability |
40 | Gesture, |
41 | /// Switch capability |
42 | Switch, |
43 | } |
44 | |
45 | /// Pointer Acceleration Profile |
46 | #[derive (Debug, Copy, Clone, PartialEq, Eq, Hash)] |
47 | #[non_exhaustive ] |
48 | pub enum AccelProfile { |
49 | /// A flat acceleration profile. |
50 | /// |
51 | /// Pointer motion is accelerated by a constant (device-specific) |
52 | /// factor, depending on the current speed. |
53 | Flat, |
54 | /// An adaptive acceleration profile. |
55 | /// |
56 | /// Pointer acceleration depends on the input speed. This is the |
57 | /// default profile for most devices. |
58 | Adaptive, |
59 | } |
60 | |
61 | /// The click method defines when to generate software-emulated |
62 | /// buttons, usually on a device that does not have a specific |
63 | /// physical button available. |
64 | #[derive (Debug, Copy, Clone, PartialEq, Eq, Hash)] |
65 | #[non_exhaustive ] |
66 | pub enum ClickMethod { |
67 | /// Use software-button areas (see [Clickfinger behavior](https://wayland.freedesktop.org/libinput/doc/latest/clickpad_softbuttons.html#clickfinger)) |
68 | /// to generate button events. |
69 | ButtonAreas, |
70 | /// The number of fingers decides which button press to generate. |
71 | Clickfinger, |
72 | } |
73 | |
74 | /// The scroll method of a device selects when to generate scroll axis |
75 | /// events instead of pointer motion events. |
76 | #[derive (Debug, Copy, Clone, PartialEq, Eq, Hash)] |
77 | #[non_exhaustive ] |
78 | pub enum ScrollMethod { |
79 | /// Never send scroll events instead of pointer motion events. |
80 | /// |
81 | /// This has no effect on events generated by scroll wheels. |
82 | NoScroll, |
83 | /// Send scroll events when two fingers are logically down on the |
84 | /// device. |
85 | TwoFinger, |
86 | /// Send scroll events when a finger moves along the bottom or |
87 | /// right edge of a device. |
88 | Edge, |
89 | /// Send scroll events when a button is down and the device moves |
90 | /// along a scroll-capable axis. |
91 | OnButtonDown, |
92 | } |
93 | |
94 | /// Errors returned when applying configuration settings. |
95 | #[derive (Debug, Copy, Clone, PartialEq, Eq, Hash)] |
96 | pub enum DeviceConfigError { |
97 | /// Configuration not available on this device. |
98 | Unsupported, |
99 | /// Invalid parameter range. |
100 | Invalid, |
101 | } |
102 | |
103 | bitflags! { |
104 | /// The send-event mode of a device defines when a device may generate |
105 | /// events and pass those events to the caller. |
106 | #[derive (Clone, Copy, Debug, Eq, Hash, PartialEq)] |
107 | pub struct SendEventsMode: u32 { |
108 | /// Send events from this device normally. |
109 | /// |
110 | /// This is a placeholder mode only, any device detected by |
111 | /// libinput can be enabled. Do not test for this value as bitmask. |
112 | const ENABLED = ffi::libinput_config_send_events_mode_LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; |
113 | /// Do not send events through this device. |
114 | /// |
115 | /// Depending on the device, this may close all file descriptors |
116 | /// on the device or it may leave the file descriptors open and |
117 | /// route events through a different device. |
118 | /// |
119 | /// If this mode is set, other disable modes may be ignored. |
120 | /// For example, if both `Disabled` and `DisabledOnExternalMouse` |
121 | /// are set, the device remains disabled when all external pointer |
122 | /// devices are unplugged. |
123 | const DISABLED = ffi::libinput_config_send_events_mode_LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; |
124 | /// If an external pointer device is plugged in, do not send |
125 | /// events from this device. |
126 | /// |
127 | /// This option may be available on built-in touchpads. |
128 | const DISABLED_ON_EXTERNAL_MOUSE = ffi::libinput_config_send_events_mode_LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE; |
129 | } |
130 | } |
131 | |
132 | /// Map 1/2/3 finger tips to buttons |
133 | #[derive (Debug, Copy, Clone, PartialEq, Eq, Hash)] |
134 | #[non_exhaustive ] |
135 | pub enum TapButtonMap { |
136 | /// 1/2/3 finger tap maps to left/right/middle |
137 | LeftRightMiddle, |
138 | /// 1/2/3 finger tap maps to left/middle/right |
139 | LeftMiddleRight, |
140 | } |
141 | |
142 | /// Whenever scroll button lock is enabled or not |
143 | #[cfg (feature = "libinput_1_15" )] |
144 | #[allow (missing_docs)] |
145 | #[derive (Debug, Copy, Clone, PartialEq, Eq, Hash)] |
146 | pub enum ScrollButtonLockState { |
147 | Disabled, |
148 | Enabled, |
149 | } |
150 | |
151 | /// Result returned when applying configuration settings. |
152 | pub type DeviceConfigResult = Result<(), DeviceConfigError>; |
153 | |
154 | bitflags! { |
155 | /// Mask reflecting LEDs on a device. |
156 | #[derive (Clone, Copy, Debug, Eq, Hash, PartialEq)] |
157 | pub struct Led: u32 { |
158 | /// Num Lock Led |
159 | const NUMLOCK = ffi::libinput_led_LIBINPUT_LED_NUM_LOCK; |
160 | /// Caps Lock Led |
161 | const CAPSLOCK = ffi::libinput_led_LIBINPUT_LED_CAPS_LOCK; |
162 | /// Scroll Lock Led |
163 | const SCROLLLOCK = ffi::libinput_led_LIBINPUT_LED_SCROLL_LOCK; |
164 | } |
165 | } |
166 | |
167 | ffi_ref_struct!( |
168 | /// Device group |
169 | /// |
170 | /// Some physical devices like graphics tablets are represented by |
171 | /// multiple kernel devices and thus by multiple `Device`s. |
172 | /// |
173 | /// libinput assigns these devices to the same `DeviceGroup` allowing |
174 | /// the caller to identify such devices and adjust configuration |
175 | /// settings accordingly. For example, setting a tablet to left-handed |
176 | /// often means turning it upside down. A touch device on the same |
177 | /// tablet would need to be turned upside down too to work correctly. |
178 | /// |
179 | /// All devices are part of a device group though for most devices the |
180 | /// group will be a singleton. A device is assigned to a device group |
181 | /// on `DeviceAddedEvent` and removed from that group on |
182 | /// `DeviceRemovedEvent`. It is up to the caller to track how many |
183 | /// devices are in each device group. |
184 | /// |
185 | /// Device groups do not get re-used once the last device in the group |
186 | /// was removed, i.e. unplugging and re-plugging a physical device |
187 | /// with grouped devices will return a different device group after |
188 | /// every unplug. |
189 | /// |
190 | /// Device groups are assigned based on the LIBINPUT_DEVICE_GROUP udev |
191 | /// property, see [Static device configuration](https://wayland.freedesktop.org/libinput/doc/latest/udev_config.html) via udev. |
192 | struct DeviceGroup, ffi::libinput_device_group, ffi::libinput_device_group_ref, ffi::libinput_device_group_unref); |
193 | |
194 | ffi_ref_struct!( |
195 | /// Representation of a single input device as seen by the kernel. |
196 | /// |
197 | /// A single physical device might consist out of multiple input |
198 | /// devices like a keyboard-touchpad combination. See `DeviceGroup` |
199 | /// if you want to track such combined physical devices. |
200 | struct Device, ffi::libinput_device, ffi::libinput_device_ref, ffi::libinput_device_unref); |
201 | |
202 | impl Device { |
203 | /// Get the libinput context from the device. |
204 | pub fn context(&self) -> Libinput { |
205 | self.context.clone() |
206 | } |
207 | |
208 | /// Get the device group this device is assigned to. |
209 | /// |
210 | /// Some physical devices like graphics tablets are represented by |
211 | /// multiple kernel devices and thus by multiple `Device`s. |
212 | /// |
213 | /// libinput assigns these devices to the same `DeviceGroup` |
214 | /// allowing the caller to identify such devices and adjust |
215 | /// configuration settings accordingly. For example, setting a |
216 | /// tablet to left-handed often means turning it upside down. A |
217 | /// touch device on the same tablet would need to be turned upside |
218 | /// down too to work correctly. |
219 | /// |
220 | /// All devices are part of a device group though for most devices |
221 | /// the group will be a singleton. A device is assigned to a |
222 | /// device group on `DeviceAddedEvent` and removed from that group |
223 | /// on `DeviceRemovedEvent`. It is up to the caller to track how |
224 | /// many devices are in each device group. |
225 | /// |
226 | /// Device groups do not get re-used once the last device in the |
227 | /// group was removed, i.e. unplugging and re-plugging a physical |
228 | /// device with grouped devices will return a different device |
229 | /// group after every unplug. |
230 | /// |
231 | /// Device groups are assigned based on the `LIBINPUT_DEVICE_GROUP` |
232 | /// udev property, see [Static device configuration](https://wayland.freedesktop.org/libinput/doc/latest/udev_config.html) via udev. |
233 | pub fn device_group(&self) -> DeviceGroup { |
234 | unsafe { |
235 | DeviceGroup::from_raw( |
236 | ffi::libinput_device_get_device_group(self.as_raw_mut()), |
237 | &self.context, |
238 | ) |
239 | } |
240 | } |
241 | |
242 | /// Get the system name of the device. |
243 | /// |
244 | /// To get the descriptive device name, use `name`. |
245 | pub fn sysname(&self) -> &str { |
246 | unsafe { |
247 | CStr::from_ptr(ffi::libinput_device_get_sysname(self.as_raw_mut())) |
248 | .to_str() |
249 | .expect("Device sysname is no valid utf8" ) |
250 | } |
251 | } |
252 | |
253 | /// The descriptive device name as advertised by the kernel and/or |
254 | /// the hardware itself. |
255 | /// |
256 | /// To get the sysname for this device, use `sysname`. |
257 | pub fn name(&self) -> &str { |
258 | unsafe { |
259 | CStr::from_ptr(ffi::libinput_device_get_name(self.as_raw_mut())) |
260 | .to_str() |
261 | .expect("Device name is no valid utf8" ) |
262 | } |
263 | } |
264 | |
265 | /// A device may be mapped to a single output, or all available |
266 | /// outputs. |
267 | /// |
268 | /// If a device is mapped to a single output only, a relative |
269 | /// device may not move beyond the boundaries of this output. An |
270 | /// absolute device has its input coordinates mapped to the |
271 | /// extents of this output. |
272 | pub fn output_name(&self) -> Option<&str> { |
273 | unsafe { |
274 | let ptr = ffi::libinput_device_get_output_name(self.as_raw_mut()); |
275 | if !ptr.is_null() { |
276 | Some( |
277 | CStr::from_ptr(ptr) |
278 | .to_str() |
279 | .expect("Device output_name is no valid utf8" ), |
280 | ) |
281 | } else { |
282 | None |
283 | } |
284 | } |
285 | } |
286 | |
287 | ffi_func!( |
288 | /// Get the product ID for this device. |
289 | pub fn id_product, ffi::libinput_device_get_id_product, u32); |
290 | ffi_func!( |
291 | /// Get the vendor ID for this device. |
292 | pub fn id_vendor, ffi::libinput_device_get_id_vendor, u32); |
293 | |
294 | /// Get the seat associated with this input device, see |
295 | /// [Seats](https://wayland.freedesktop.org/libinput/doc/latest/seats.html) |
296 | /// for details. |
297 | /// |
298 | /// A seat can be uniquely identified by the physical and logical |
299 | /// seat name. There will ever be only one seat instance with a |
300 | /// given physical and logical seat name pair at any given time, |
301 | /// but if no external reference is kept, it may be destroyed if |
302 | /// no device belonging to it is left. |
303 | pub fn seat(&self) -> Seat { |
304 | unsafe { |
305 | Seat::from_raw( |
306 | ffi::libinput_device_get_seat(self.as_raw_mut()), |
307 | &self.context, |
308 | ) |
309 | } |
310 | } |
311 | |
312 | /// Change the logical seat associated with this device by removing the device and adding it to the new seat. |
313 | /// |
314 | /// This command is identical to physically unplugging the device, |
315 | /// then re-plugging it as a member of the new seat. libinput will |
316 | /// generate a `DeviceRemovedEvent` event and this `Device` is |
317 | /// considered removed from the context; it will not generate |
318 | /// further events and will be freed when it goes out of scope. |
319 | /// A `DeviceAddedEvent` event is generated with a new `Device` |
320 | /// handle. It is the caller's responsibility to update references |
321 | /// to the new device accordingly. |
322 | /// |
323 | /// If the logical seat name already exists in the device's |
324 | /// physical seat, the device is added to this seat. Otherwise, a |
325 | /// new seat is created. |
326 | /// |
327 | /// ## Note |
328 | /// This change applies to this device until removal or `suspend`, |
329 | /// whichever happens earlier. |
330 | pub fn set_seat_logical_name(&mut self, name: &str) -> Result<(), ()> { |
331 | let name = CString::new(name).expect("New logical_seat name contained a null-byte" ); |
332 | unsafe { |
333 | if ffi::libinput_device_set_seat_logical_name(self.as_raw_mut(), name.as_ptr()) == 0 { |
334 | Ok(()) |
335 | } else { |
336 | Err(()) |
337 | } |
338 | } |
339 | } |
340 | |
341 | /// Return a udev handle to the device that is this libinput |
342 | /// device, if any. |
343 | /// |
344 | /// Some devices may not have a udev device, or the udev device |
345 | /// may be unobtainable. This function returns `None` if no udev |
346 | /// device was available. |
347 | /// |
348 | /// Calling this function multiple times for the same device may |
349 | /// not return the same udev handle each time. |
350 | /// |
351 | /// # Safety |
352 | /// |
353 | /// The result of this function is not definied if the passed udev `Context` |
354 | /// is not the same as the one the libinput `Context` was created from. |
355 | #[cfg (feature = "udev" )] |
356 | pub unsafe fn udev_device(&self) -> Option<UdevDevice> { |
357 | let dev: *mut udev_device = ffi::libinput_device_get_udev_device(self.ffi) as *mut _; |
358 | if dev.is_null() { |
359 | None |
360 | } else { |
361 | // We have to ref the returned udev context as udev_device_get_udev does not |
362 | // increase the ref_count but dropping a UdevDevice will unref it |
363 | let ctx: *mut udev_context = udev_ref(udev_device_get_udev(dev)); |
364 | Some(UdevDevice::from_raw_with_context(ctx, dev)) |
365 | } |
366 | } |
367 | |
368 | /// Update the LEDs on the device, if any. |
369 | /// |
370 | /// If the device does not have LEDs, or does not have one or more |
371 | /// of the LEDs given in the mask, this function does nothing. |
372 | /// |
373 | /// ## Arguments |
374 | /// |
375 | /// leds: Leds to turn on |
376 | /// |
377 | /// Missing `Led`s will be turned off. |
378 | /// The slice is interpreted as a bitmap. |
379 | pub fn led_update(&mut self, leds: Led) { |
380 | unsafe { ffi::libinput_device_led_update(self.as_raw_mut(), leds.bits()) } |
381 | } |
382 | |
383 | /// Check if the given device has the specified capability. |
384 | pub fn has_capability(&self, cap: DeviceCapability) -> bool { |
385 | unsafe { |
386 | ffi::libinput_device_has_capability( |
387 | self.as_raw_mut(), |
388 | match cap { |
389 | DeviceCapability::Keyboard => { |
390 | ffi::libinput_device_capability_LIBINPUT_DEVICE_CAP_KEYBOARD |
391 | } |
392 | DeviceCapability::Pointer => { |
393 | ffi::libinput_device_capability_LIBINPUT_DEVICE_CAP_POINTER |
394 | } |
395 | DeviceCapability::Touch => { |
396 | ffi::libinput_device_capability_LIBINPUT_DEVICE_CAP_TOUCH |
397 | } |
398 | DeviceCapability::TabletTool => { |
399 | ffi::libinput_device_capability_LIBINPUT_DEVICE_CAP_TABLET_TOOL |
400 | } |
401 | DeviceCapability::TabletPad => { |
402 | ffi::libinput_device_capability_LIBINPUT_DEVICE_CAP_TABLET_PAD |
403 | } |
404 | DeviceCapability::Gesture => { |
405 | ffi::libinput_device_capability_LIBINPUT_DEVICE_CAP_GESTURE |
406 | } |
407 | DeviceCapability::Switch => { |
408 | ffi::libinput_device_capability_LIBINPUT_DEVICE_CAP_SWITCH |
409 | } |
410 | }, |
411 | ) != 0 |
412 | } |
413 | } |
414 | |
415 | /// Get the physical size of a device in mm, where meaningful. |
416 | /// |
417 | /// This function only succeeds on devices with the required data, |
418 | /// i.e. tablets, touchpads and touchscreens. |
419 | pub fn size(&self) -> Option<(f64, f64)> { |
420 | let mut width = 0.0; |
421 | let mut height = 0.0; |
422 | |
423 | match unsafe { |
424 | ffi::libinput_device_get_size( |
425 | self.as_raw_mut(), |
426 | &mut width as *mut _, |
427 | &mut height as *mut _, |
428 | ) |
429 | } { |
430 | 0 => Some((width, height)), |
431 | _ => None, |
432 | } |
433 | } |
434 | |
435 | /// Check if a `DeviceCapability::Pointer` device has a button |
436 | /// with the given code (see linux/input.h). |
437 | pub fn pointer_has_button(&self, button: u32) -> Result<bool, ()> { |
438 | match unsafe { ffi::libinput_device_pointer_has_button(self.as_raw_mut(), button) } { |
439 | 1 => Ok(true), |
440 | 0 => Ok(false), |
441 | -1 => Err(()), |
442 | _ => unreachable!(), |
443 | } |
444 | } |
445 | |
446 | /// Check if a `DeviceCapability::Keyboard` device has a key with |
447 | /// the given code (see linux/input.h). |
448 | pub fn keyboard_has_key(&self, key: u32) -> Result<bool, ()> { |
449 | match unsafe { ffi::libinput_device_keyboard_has_key(self.as_raw_mut(), key) } { |
450 | 1 => Ok(true), |
451 | 0 => Ok(false), |
452 | -1 => Err(()), |
453 | _ => unreachable!(), |
454 | } |
455 | } |
456 | |
457 | /// Check if a `DeviceCapability::Switch` device has a switch of the |
458 | /// given type. |
459 | pub fn switch_has_switch(&self, switch: Switch) -> Result<bool, ()> { |
460 | match unsafe { ffi::libinput_device_switch_has_switch(self.as_raw_mut(), switch as u32) } { |
461 | 1 => Ok(true), |
462 | 0 => Ok(false), |
463 | -1 => Err(()), |
464 | _ => unreachable!(), |
465 | } |
466 | } |
467 | |
468 | ffi_func!( |
469 | /// Return the number of buttons on a device with the |
470 | /// `DeviceCapability::TabletPad` capability. |
471 | /// |
472 | /// Buttons on a pad device are numbered sequentially, see Tablet |
473 | /// pad button numbers for details. |
474 | pub fn tablet_pad_number_of_buttons, ffi::libinput_device_tablet_pad_get_num_buttons, i32); |
475 | ffi_func!( |
476 | /// Return the number of rings a device with the |
477 | /// `DeviceCapability::TabletPad` capability provides. |
478 | pub fn tablet_pad_number_of_rings, ffi::libinput_device_tablet_pad_get_num_rings, i32); |
479 | ffi_func!( |
480 | /// Return the number of strips a device with the |
481 | /// `DeviceCapability::TabletPad` capability provides. |
482 | pub fn tablet_pad_number_of_strips, ffi::libinput_device_tablet_pad_get_num_strips, i32); |
483 | ffi_func!( |
484 | /// Most devices only provide a single mode group, however devices |
485 | /// such as the Wacom Cintiq 22HD provide two mode groups. |
486 | /// |
487 | /// If multiple mode groups are available, a caller should use |
488 | /// `TabletPadModeGroup::has_button`, |
489 | /// `TabletPadModeGroup::has_ring` and |
490 | /// `TabletPadModeGroup::has_strip()` to associate each button, |
491 | /// ring and strip with the correct mode group. |
492 | pub fn tablet_pad_number_of_mode_groups, ffi::libinput_device_tablet_pad_get_num_mode_groups, i32); |
493 | |
494 | /// Return the current mode this mode group is in. |
495 | /// |
496 | /// Note that the returned mode is the mode valid as of completing |
497 | /// the last `dispatch`. The returned mode may thus be |
498 | /// different than the mode returned by |
499 | /// `TabletPadEventTrait::mode`. |
500 | /// |
501 | /// For example, if the mode was toggled three times between the |
502 | /// call to `dispatch`, this function returns the third mode but |
503 | /// the events in the event queue will return the modes 1, 2 and |
504 | /// 3, respectively. |
505 | pub fn tablet_pad_mode_group(&self, index: u32) -> Option<TabletPadModeGroup> { |
506 | let ptr = |
507 | unsafe { ffi::libinput_device_tablet_pad_get_mode_group(self.as_raw_mut(), index) }; |
508 | if ptr.is_null() { |
509 | None |
510 | } else { |
511 | Some(unsafe { TabletPadModeGroup::from_raw(ptr, &self.context) }) |
512 | } |
513 | } |
514 | |
515 | /// Check if a `DeviceCapability::TabletPad`-device has a key with the given code (see linux/input-event-codes.h). |
516 | /// |
517 | /// ## Returns |
518 | /// - `Some(true)` if it has the requested key |
519 | /// - `Some(false)` if it has not |
520 | /// - `None` on error (no TabletPad device) |
521 | #[cfg (feature = "libinput_1_15" )] |
522 | pub fn tablet_pad_has_key(&self, code: u32) -> Option<bool> { |
523 | match unsafe { ffi::libinput_device_tablet_pad_has_key(self.as_raw_mut(), code) } { |
524 | -1 => None, |
525 | 0 => Some(false), |
526 | 1 => Some(true), |
527 | _ => panic!( |
528 | "libinput returned invalid return code for libinput_device_tablet_pad_has_key" |
529 | ), |
530 | } |
531 | } |
532 | |
533 | /// Check how many touches a `DeviceCapability::Touch`-exposing Device supports simultaneously. |
534 | /// |
535 | /// ## Returns |
536 | /// - `Some(n)` amount of touches |
537 | /// - `Some(0)` if unknown |
538 | /// - `None` on error (no touch device) |
539 | #[cfg (feature = "libinput_1_11" )] |
540 | pub fn touch_count(&mut self) -> Option<u32> { |
541 | match unsafe { ffi::libinput_device_touch_get_touch_count(self.as_raw_mut()) } { |
542 | -1 => None, |
543 | n => Some(n as u32), |
544 | } |
545 | } |
546 | |
547 | /// Return the default pointer acceleration profile for this |
548 | /// pointer device. |
549 | pub fn config_accel_default_profile(&self) -> Option<AccelProfile> { |
550 | match unsafe { ffi::libinput_device_config_accel_get_default_profile(self.as_raw_mut()) } { |
551 | ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_NONE => None, |
552 | ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT => { |
553 | Some(AccelProfile::Flat) |
554 | } |
555 | ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE => { |
556 | Some(AccelProfile::Adaptive) |
557 | } |
558 | _x => { |
559 | #[cfg (feature = "log" )] |
560 | log::warn!( |
561 | "Unknown AccelProfile ( {}). Unsupported libinput version?" , |
562 | _x |
563 | ); |
564 | None |
565 | } |
566 | } |
567 | } |
568 | |
569 | /// Get the current pointer acceleration profile for this pointer |
570 | /// device. |
571 | pub fn config_accel_profile(&self) -> Option<AccelProfile> { |
572 | match unsafe { ffi::libinput_device_config_accel_get_profile(self.as_raw_mut()) } { |
573 | ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_NONE => None, |
574 | ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT => { |
575 | Some(AccelProfile::Flat) |
576 | } |
577 | ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE => { |
578 | Some(AccelProfile::Adaptive) |
579 | } |
580 | _x => { |
581 | #[cfg (feature = "log" )] |
582 | log::warn!( |
583 | "Unknown AccelProfile ( {}). Unsupported libinput version?" , |
584 | _x |
585 | ); |
586 | None |
587 | } |
588 | } |
589 | } |
590 | |
591 | /// Returns a bitmask of the configurable acceleration modes |
592 | /// available on this device. |
593 | pub fn config_accel_profiles(&self) -> Vec<AccelProfile> { |
594 | let mut profiles = Vec::new(); |
595 | let bitmask = unsafe { ffi::libinput_device_config_accel_get_profiles(self.as_raw_mut()) }; |
596 | if bitmask & ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT as u32 |
597 | != 0 |
598 | { |
599 | profiles.push(AccelProfile::Flat); |
600 | } |
601 | if bitmask |
602 | & ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE as u32 |
603 | != 0 |
604 | { |
605 | profiles.push(AccelProfile::Adaptive); |
606 | } |
607 | profiles |
608 | } |
609 | |
610 | /// Set the pointer acceleration profile of this pointer device to |
611 | /// the given mode. |
612 | pub fn config_accel_set_profile(&mut self, profile: AccelProfile) -> DeviceConfigResult { |
613 | match unsafe { |
614 | ffi::libinput_device_config_accel_set_profile( |
615 | self.as_raw_mut(), |
616 | match profile { |
617 | AccelProfile::Flat => { |
618 | ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT |
619 | } |
620 | AccelProfile::Adaptive => { |
621 | ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE |
622 | } |
623 | }, |
624 | ) |
625 | } { |
626 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
627 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
628 | Err(DeviceConfigError::Unsupported) |
629 | } |
630 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
631 | Err(DeviceConfigError::Invalid) |
632 | } |
633 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
634 | } |
635 | } |
636 | |
637 | ffi_func!( |
638 | /// Return the default speed setting for this device, normalized |
639 | /// to a range of [-1, 1]. |
640 | pub fn config_accel_default_speed, ffi::libinput_device_config_accel_get_default_speed, f64); |
641 | ffi_func!( |
642 | /// Get the current pointer acceleration setting for this pointer |
643 | /// device. |
644 | /// |
645 | /// The returned value is normalized to a range of [-1, 1]. See |
646 | /// `config_accel_set_speed` for details. |
647 | pub fn config_accel_speed, ffi::libinput_device_config_accel_get_speed, f64); |
648 | |
649 | /// Set the pointer acceleration speed of this pointer device |
650 | /// within a range of [-1, 1], where 0 is the default acceleration |
651 | /// for this device, -1 is the slowest acceleration and 1 is the |
652 | /// maximum acceleration available on this device. |
653 | /// |
654 | /// The actual pointer acceleration mechanism is |
655 | /// implementation-dependent, as is the number of steps available |
656 | /// within the range. libinput picks the semantically closest |
657 | /// acceleration step if the requested value does not match a |
658 | /// discrete setting. |
659 | pub fn config_accel_set_speed(&mut self, speed: f64) -> DeviceConfigResult { |
660 | match unsafe { ffi::libinput_device_config_accel_set_speed(self.as_raw_mut(), speed) } { |
661 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
662 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
663 | Err(DeviceConfigError::Unsupported) |
664 | } |
665 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
666 | Err(DeviceConfigError::Invalid) |
667 | } |
668 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
669 | } |
670 | } |
671 | |
672 | ffi_func!( |
673 | /// Check if a device uses libinput-internal pointer-acceleration. |
674 | pub fn config_accel_is_available, ffi::libinput_device_config_accel_is_available, bool); |
675 | |
676 | /// Return the default calibration matrix for this device. |
677 | /// |
678 | /// On most devices, this is the identity matrix. If the udev |
679 | /// property `LIBINPUT_CALIBRATION_MATRIX` is set on the respective u |
680 | /// dev device, that property's value becomes the default matrix, |
681 | /// see [Static device configuration via udev](https://wayland.freedesktop.org/libinput/doc/latest/udev_config.html). |
682 | pub fn config_calibration_default_matrix(&self) -> Option<[f32; 6]> { |
683 | let mut matrix = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]; |
684 | if unsafe { |
685 | ffi::libinput_device_config_calibration_get_default_matrix( |
686 | self.as_raw_mut(), |
687 | matrix.as_mut_ptr(), |
688 | ) != 0 |
689 | } { |
690 | Some(matrix) |
691 | } else { |
692 | None |
693 | } |
694 | } |
695 | |
696 | /// Return the current calibration matrix for this device. |
697 | pub fn config_calibration_matrix(&self) -> Option<[f32; 6]> { |
698 | let mut matrix = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]; |
699 | if unsafe { |
700 | ffi::libinput_device_config_calibration_get_matrix( |
701 | self.as_raw_mut(), |
702 | matrix.as_mut_ptr(), |
703 | ) != 0 |
704 | } { |
705 | Some(matrix) |
706 | } else { |
707 | None |
708 | } |
709 | } |
710 | |
711 | ffi_func!( |
712 | /// Check if the device can be calibrated via a calibration matrix. |
713 | pub fn config_calibration_has_matrix, ffi::libinput_device_config_calibration_has_matrix, bool); |
714 | |
715 | /// Apply the 3x3 transformation matrix to absolute device |
716 | /// coordinates. |
717 | /// |
718 | /// This matrix has no effect on relative events. |
719 | /// |
720 | /// Given a 6-element array [a, b, c, d, e, f], the matrix is |
721 | /// applied as |
722 | /// ```text |
723 | /// [ a b c ] [ x ] |
724 | /// [ d e f ] * [ y ] |
725 | /// [ 0 0 1 ] [ 1 ] |
726 | /// # * |
727 | /// ``` |
728 | /// The translation component (c, f) is expected to be normalized |
729 | /// to the device coordinate range. For example, the matrix |
730 | /// ```text |
731 | /// [ 1 0 1 ] |
732 | /// [ 0 1 -1 ] |
733 | /// [ 0 0 1 ] |
734 | /// ``` |
735 | /// moves all coordinates by 1 device-width to the right and 1 |
736 | /// device-height up. |
737 | /// |
738 | /// The rotation matrix for rotation around the origin is defined |
739 | /// as |
740 | /// ```text |
741 | /// [ cos(a) -sin(a) 0 ] |
742 | /// [ sin(a) cos(a) 0 ] |
743 | /// [ 0 0 1 ] |
744 | /// ``` |
745 | /// Note that any rotation requires an additional translation |
746 | /// component to translate the rotated coordinates back into the |
747 | /// original device space. The rotation matrixes for 90, 180 and |
748 | /// 270 degrees clockwise are: |
749 | /// ```text |
750 | /// 90 deg cw: 180 deg cw: 270 deg cw: |
751 | /// [ 0 -1 1] [ -1 0 1] [ 0 1 0 ] |
752 | /// [ 1 0 0] [ 0 -1 1] [ -1 0 1 ] |
753 | /// [ 0 0 1] [ 0 0 1] [ 0 0 1 ] |
754 | /// ``` |
755 | pub fn config_calibration_set_matrix(&mut self, matrix: [f32; 6]) -> DeviceConfigResult { |
756 | match unsafe { |
757 | ffi::libinput_device_config_calibration_set_matrix(self.as_raw_mut(), matrix.as_ptr()) |
758 | } { |
759 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
760 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
761 | Err(DeviceConfigError::Unsupported) |
762 | } |
763 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
764 | Err(DeviceConfigError::Invalid) |
765 | } |
766 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
767 | } |
768 | } |
769 | |
770 | /// Get the default button click method for this device. |
771 | /// |
772 | /// The button click method defines when to generate |
773 | /// software-emulated buttons, usually on a device that does not |
774 | /// have a specific physical button available. |
775 | pub fn config_click_default_method(&self) -> Option<ClickMethod> { |
776 | match unsafe { ffi::libinput_device_config_click_get_default_method(self.as_raw_mut()) } { |
777 | ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_NONE => None, |
778 | ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS => { |
779 | Some(ClickMethod::ButtonAreas) |
780 | } |
781 | ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER => { |
782 | Some(ClickMethod::Clickfinger) |
783 | } |
784 | _x => { |
785 | #[cfg (feature = "log" )] |
786 | log::warn!( |
787 | "Unknown ClickMethod ( {}). Unsupported libinput version?" , |
788 | _x |
789 | ); |
790 | None |
791 | } |
792 | } |
793 | } |
794 | |
795 | /// Get the button click method for this device. |
796 | /// |
797 | /// The button click method defines when to generate |
798 | /// software-emulated buttons, usually on a device that does not |
799 | /// have a specific physical button available. |
800 | pub fn config_click_method(&self) -> Option<ClickMethod> { |
801 | match unsafe { ffi::libinput_device_config_click_get_method(self.as_raw_mut()) } { |
802 | ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_NONE => None, |
803 | ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS => { |
804 | Some(ClickMethod::ButtonAreas) |
805 | } |
806 | ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER => { |
807 | Some(ClickMethod::Clickfinger) |
808 | } |
809 | _x => { |
810 | #[cfg (feature = "log" )] |
811 | log::warn!( |
812 | "Unknown ClickMethod ( {}). Unsupported libinput version?" , |
813 | _x |
814 | ); |
815 | None |
816 | } |
817 | } |
818 | } |
819 | |
820 | /// Check which button click methods a device supports. |
821 | /// |
822 | /// The button click method defines when to generate |
823 | /// software-emulated buttons, usually on a device that does not |
824 | /// have a specific physical button available. |
825 | pub fn config_click_methods(&self) -> Vec<ClickMethod> { |
826 | let mut methods = Vec::new(); |
827 | let bitmask = unsafe { ffi::libinput_device_config_click_get_methods(self.as_raw_mut()) }; |
828 | if bitmask |
829 | & ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER as u32 |
830 | != 0 |
831 | { |
832 | methods.push(ClickMethod::Clickfinger); |
833 | } |
834 | if bitmask |
835 | & ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS as u32 |
836 | != 0 |
837 | { |
838 | methods.push(ClickMethod::ButtonAreas); |
839 | } |
840 | methods |
841 | } |
842 | |
843 | /// Set the button click method for this device. |
844 | /// |
845 | /// The button click method defines when to generate |
846 | /// software-emulated buttons, usually on a device that does not |
847 | /// have a specific physical button available. |
848 | /// |
849 | /// ## Note |
850 | /// |
851 | /// The selected click method may not take effect immediately. The |
852 | /// device may require changing to a neutral state first before |
853 | /// activating the new method. |
854 | pub fn config_click_set_method(&mut self, method: ClickMethod) -> DeviceConfigResult { |
855 | match unsafe { |
856 | ffi::libinput_device_config_click_set_method( |
857 | self.as_raw_mut(), |
858 | match method { |
859 | ClickMethod::ButtonAreas => { |
860 | ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS |
861 | } |
862 | ClickMethod::Clickfinger => { |
863 | ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER |
864 | } |
865 | }, |
866 | ) |
867 | } { |
868 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
869 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
870 | Err(DeviceConfigError::Unsupported) |
871 | } |
872 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
873 | Err(DeviceConfigError::Invalid) |
874 | } |
875 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
876 | } |
877 | } |
878 | |
879 | /// Check if the disable-while typing feature is enabled on this |
880 | /// device by default. |
881 | /// |
882 | /// If the device does not support disable-while-typing, this |
883 | /// function returns `false`. |
884 | pub fn config_dwt_default_enabled(&self) -> bool { |
885 | match unsafe { ffi::libinput_device_config_dwt_get_default_enabled(self.as_raw_mut()) } { |
886 | ffi::libinput_config_dwt_state_LIBINPUT_CONFIG_DWT_ENABLED => true, |
887 | ffi::libinput_config_dwt_state_LIBINPUT_CONFIG_DWT_DISABLED => false, |
888 | _ => panic!("libinput returned invalid 'libinput_config_dwt_state'" ), |
889 | } |
890 | } |
891 | |
892 | /// Check if the disable-while typing feature is currently enabled |
893 | /// on this device. |
894 | /// |
895 | /// If the device does not support disable-while-typing, this |
896 | /// function returns `false`. |
897 | pub fn config_dwt_enabled(&self) -> bool { |
898 | match unsafe { ffi::libinput_device_config_dwt_get_enabled(self.as_raw_mut()) } { |
899 | ffi::libinput_config_dwt_state_LIBINPUT_CONFIG_DWT_ENABLED => true, |
900 | ffi::libinput_config_dwt_state_LIBINPUT_CONFIG_DWT_DISABLED => false, |
901 | _ => panic!("libinput returned invalid 'libinput_config_dwt_state'" ), |
902 | } |
903 | } |
904 | |
905 | ffi_func!( |
906 | /// Check if this device supports configurable |
907 | /// disable-while-typing feature. |
908 | /// |
909 | /// This feature is usually available on built-in touchpads and |
910 | /// disables the touchpad while typing. See [Disable-while-typing](https://wayland.freedesktop.org/libinput/doc/latest/palm_detection.html#disable-while-typing) |
911 | /// for details. |
912 | pub fn config_dwt_is_available, ffi::libinput_device_config_dwt_is_available, bool); |
913 | |
914 | /// Enable or disable the disable-while-typing feature. |
915 | /// |
916 | /// When enabled, the device will be disabled while typing and |
917 | /// for a short period after. See Disable-while-typing for |
918 | /// details. |
919 | /// |
920 | /// ## Note |
921 | /// |
922 | /// Enabling or disabling disable-while-typing may not take |
923 | /// effect immediately. |
924 | pub fn config_dwt_set_enabled(&self, enabled: bool) -> DeviceConfigResult { |
925 | match unsafe { |
926 | ffi::libinput_device_config_dwt_set_enabled( |
927 | self.as_raw_mut(), |
928 | if enabled { |
929 | ffi::libinput_config_dwt_state_LIBINPUT_CONFIG_DWT_ENABLED |
930 | } else { |
931 | ffi::libinput_config_dwt_state_LIBINPUT_CONFIG_DWT_DISABLED |
932 | }, |
933 | ) |
934 | } { |
935 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
936 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
937 | Err(DeviceConfigError::Unsupported) |
938 | } |
939 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
940 | Err(DeviceConfigError::Invalid) |
941 | } |
942 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
943 | } |
944 | } |
945 | |
946 | /// Check if the disable-while trackpointing feature is enabled on this |
947 | /// device by default. |
948 | /// |
949 | /// If the device does not support disable-while-trackpointing, this |
950 | /// function returns `false`. |
951 | #[cfg (feature = "libinput_1_21" )] |
952 | pub fn config_dwtp_default_enabled(&self) -> bool { |
953 | match unsafe { ffi::libinput_device_config_dwtp_get_default_enabled(self.as_raw_mut()) } { |
954 | ffi::libinput_config_dwtp_state_LIBINPUT_CONFIG_DWTP_ENABLED => true, |
955 | ffi::libinput_config_dwtp_state_LIBINPUT_CONFIG_DWTP_DISABLED => false, |
956 | _ => panic!("libinput returned invalid 'libinput_config_dwtp_state'" ), |
957 | } |
958 | } |
959 | |
960 | /// Check if the disable-while trackpointing feature is currently enabled |
961 | /// on this device. |
962 | /// |
963 | /// If the device does not support disable-while-trackpointing, this |
964 | /// function returns `false`. |
965 | #[cfg (feature = "libinput_1_21" )] |
966 | pub fn config_dwtp_enabled(&self) -> bool { |
967 | match unsafe { ffi::libinput_device_config_dwtp_get_enabled(self.as_raw_mut()) } { |
968 | ffi::libinput_config_dwtp_state_LIBINPUT_CONFIG_DWTP_ENABLED => true, |
969 | ffi::libinput_config_dwtp_state_LIBINPUT_CONFIG_DWTP_DISABLED => false, |
970 | _ => panic!("libinput returned invalid 'libinput_config_dwtp_state'" ), |
971 | } |
972 | } |
973 | |
974 | ffi_func!( |
975 | /// Check if this device supports configurable |
976 | /// disable-while-trackpointing feature. |
977 | /// |
978 | /// This feature is usually available on Thinkpads and |
979 | /// disables the touchpad while using the trackpoint. |
980 | #[cfg (feature = "libinput_1_21" )] |
981 | pub fn config_dwtp_is_available, ffi::libinput_device_config_dwtp_is_available, bool); |
982 | |
983 | /// Enable or disable the disable-while-trackpointing feature. |
984 | /// |
985 | /// When enabled, the device will be disabled while using the trackpoint and |
986 | /// for a short period after. |
987 | /// |
988 | /// ## Note |
989 | /// |
990 | /// Enabling or disabling disable-while-trackpointing may not take |
991 | /// effect immediately. |
992 | #[cfg (feature = "libinput_1_21" )] |
993 | pub fn config_dwtp_set_enabled(&self, enabled: bool) -> DeviceConfigResult { |
994 | match unsafe { |
995 | ffi::libinput_device_config_dwtp_set_enabled( |
996 | self.as_raw_mut(), |
997 | if enabled { |
998 | ffi::libinput_config_dwtp_state_LIBINPUT_CONFIG_DWTP_ENABLED |
999 | } else { |
1000 | ffi::libinput_config_dwtp_state_LIBINPUT_CONFIG_DWTP_DISABLED |
1001 | }, |
1002 | ) |
1003 | } { |
1004 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
1005 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
1006 | Err(DeviceConfigError::Unsupported) |
1007 | } |
1008 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
1009 | Err(DeviceConfigError::Invalid) |
1010 | } |
1011 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
1012 | } |
1013 | } |
1014 | |
1015 | ffi_func!( |
1016 | /// Get the current left-handed configuration of the device. |
1017 | pub fn config_left_handed, ffi::libinput_device_config_left_handed_get, bool); |
1018 | ffi_func!( |
1019 | /// Get the default left-handed configuration of the device. |
1020 | pub fn config_left_handed_default, ffi::libinput_device_config_left_handed_get_default, bool); |
1021 | ffi_func!( |
1022 | /// Check if a device has a configuration that supports |
1023 | /// left-handed usage. |
1024 | pub fn config_left_handed_is_available, ffi::libinput_device_config_left_handed_is_available, bool); |
1025 | |
1026 | /// Set the left-handed configuration of the device. |
1027 | /// |
1028 | /// The exact behavior is device-dependent. On a mouse and most |
1029 | /// pointing devices, left and right buttons are swapped but the |
1030 | /// middle button is unmodified. On a touchpad, physical buttons |
1031 | /// (if present) are swapped. On a clickpad, the top and bottom |
1032 | /// software-emulated buttons are swapped where present, the main |
1033 | /// area of the touchpad remains a left button. Tapping and |
1034 | /// clickfinger behavior is not affected by this setting. |
1035 | /// |
1036 | /// Changing the left-handed configuration of a device may not |
1037 | /// take effect until all buttons have been logically released. |
1038 | pub fn config_left_handed_set(&self, enabled: bool) -> DeviceConfigResult { |
1039 | match unsafe { |
1040 | ffi::libinput_device_config_left_handed_set(self.as_raw_mut(), enabled as i32) |
1041 | } { |
1042 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
1043 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
1044 | Err(DeviceConfigError::Unsupported) |
1045 | } |
1046 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
1047 | Err(DeviceConfigError::Invalid) |
1048 | } |
1049 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
1050 | } |
1051 | } |
1052 | |
1053 | /// Check if configurable middle button emulation is enabled by |
1054 | /// default on this device. |
1055 | /// |
1056 | /// See [Middle button emulation](https://wayland.freedesktop.org/libinput/doc/latest/middle_button_emulation.html) for details. |
1057 | /// |
1058 | /// If the device does not have configurable middle button |
1059 | /// emulation, this function returns `false`. |
1060 | /// |
1061 | /// ## Note |
1062 | /// |
1063 | /// Some devices provide middle mouse button emulation but do not |
1064 | /// allow enabling/disabling that emulation. These devices always |
1065 | /// return `false`. |
1066 | pub fn config_middle_emulation_default_enabled(&self) -> bool { |
1067 | match unsafe { |
1068 | ffi::libinput_device_config_middle_emulation_get_default_enabled(self.as_raw_mut()) |
1069 | } { |
1070 | ffi::libinput_config_middle_emulation_state_LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED => true, |
1071 | ffi::libinput_config_middle_emulation_state_LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED => false, |
1072 | _ => panic!("libinput returned invalid 'libinput_config_middle_emulation_state'" ), |
1073 | } |
1074 | } |
1075 | |
1076 | /// Check if configurable middle button emulation is enabled on |
1077 | /// this device. |
1078 | /// |
1079 | /// See [Middle button emulation](https://wayland.freedesktop.org/libinput/doc/latest/middle_button_emulation.html) |
1080 | /// for details. |
1081 | /// |
1082 | /// If the device does not have configurable middle button |
1083 | /// emulation, this function returns `false`. |
1084 | /// |
1085 | /// ## Note |
1086 | /// |
1087 | /// Some devices provide middle mouse button emulation but do not |
1088 | /// allow enabling/disabling that emulation. These devices always |
1089 | /// return `false`. |
1090 | pub fn config_middle_emulation_enabled(&self) -> bool { |
1091 | match unsafe { ffi::libinput_device_config_middle_emulation_get_enabled(self.as_raw_mut()) } { |
1092 | ffi::libinput_config_middle_emulation_state_LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED => true, |
1093 | ffi::libinput_config_middle_emulation_state_LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED => false, |
1094 | _ => panic!("libinput returned invalid 'libinput_config_middle_emulation_state'" ), |
1095 | } |
1096 | } |
1097 | |
1098 | ffi_func!( |
1099 | /// Check if middle mouse button emulation configuration is |
1100 | /// available on this device. |
1101 | /// |
1102 | /// See [Middle button emulation](https://wayland.freedesktop.org/libinput/doc/latest/middle_button_emulation.html) |
1103 | /// for details. |
1104 | /// |
1105 | /// ## Note |
1106 | /// |
1107 | /// Some devices provide middle mouse button emulation but do not |
1108 | /// allow enabling/disabling that emulation. These devices return |
1109 | /// `false` in `config_middle_emulation_is_available`. |
1110 | pub fn config_middle_emulation_is_available, ffi::libinput_device_config_middle_emulation_is_available, bool); |
1111 | |
1112 | /// Enable or disable middle button emulation on this device. |
1113 | /// |
1114 | /// When enabled, a simultaneous press of the left and right |
1115 | /// button generates a middle mouse button event. Releasing the |
1116 | /// buttons generates a middle mouse button release, the left and |
1117 | /// right button events are discarded otherwise. |
1118 | /// |
1119 | /// See [Middle button emulation](https://wayland.freedesktop.org/libinput/doc/latest/middle_button_emulation.html) |
1120 | /// for details. |
1121 | pub fn config_middle_emulation_set_enabled(&self, enabled: bool) -> DeviceConfigResult { |
1122 | match unsafe { |
1123 | ffi::libinput_device_config_middle_emulation_set_enabled( |
1124 | self.as_raw_mut(), |
1125 | if enabled { |
1126 | ffi::libinput_config_middle_emulation_state_LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED |
1127 | } else { |
1128 | ffi::libinput_config_middle_emulation_state_LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED |
1129 | }, |
1130 | ) |
1131 | } { |
1132 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
1133 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
1134 | Err(DeviceConfigError::Unsupported) |
1135 | } |
1136 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
1137 | Err(DeviceConfigError::Invalid) |
1138 | } |
1139 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
1140 | } |
1141 | } |
1142 | |
1143 | ffi_func!( |
1144 | /// Get the current rotation of a device in degrees clockwise off |
1145 | /// the logical neutral position. |
1146 | /// |
1147 | /// If this device does not support rotation, the return value is |
1148 | /// always 0. |
1149 | pub fn config_rotation_angle, ffi::libinput_device_config_rotation_get_angle, u32); |
1150 | ffi_func!( |
1151 | /// Get the default rotation of a device in degrees clockwise off |
1152 | /// the logical neutral position. |
1153 | /// |
1154 | /// If this device does not support rotation, the return value is |
1155 | /// always 0. |
1156 | pub fn config_rotation_default_angle, ffi::libinput_device_config_rotation_get_default_angle, u32); |
1157 | ffi_func!( |
1158 | /// Check whether a device can have a custom rotation applied. |
1159 | pub fn config_rotation_is_available, ffi::libinput_device_config_rotation_is_available, bool); |
1160 | |
1161 | /// Set the rotation of a device in degrees clockwise off the |
1162 | /// logical neutral position. |
1163 | /// |
1164 | /// Any subsequent motion events are adjusted according to the |
1165 | /// given angle. |
1166 | /// |
1167 | /// The angle has to be in the range of [0, 360] degrees, |
1168 | /// otherwise this function returns `DeviceConfigError::Invalid`. |
1169 | /// If the angle is a multiple of 360 or negative, the caller |
1170 | /// must ensure the correct ranging before calling this function. |
1171 | /// |
1172 | /// libinput guarantees that this function accepts multiples of |
1173 | /// 90 degrees. If a value is within the [0, 360] range but not a |
1174 | /// multiple of 90 degrees, this function may return |
1175 | /// `DeviceConfigError::Invalid` if the underlying device or |
1176 | /// implementation does not support finer-grained rotation angles. |
1177 | /// |
1178 | /// The rotation angle is applied to all motion events emitted by |
1179 | /// the device. Thus, rotating the device also changes the angle |
1180 | /// required or presented by scrolling, gestures, etc. |
1181 | /// |
1182 | /// Setting a rotation of 0 degrees on a device that does not |
1183 | /// support rotation always succeeds. |
1184 | pub fn config_rotation_set_angle(&self, angle: u32) -> DeviceConfigResult { |
1185 | match unsafe { ffi::libinput_device_config_rotation_set_angle(self.as_raw_mut(), angle) } { |
1186 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
1187 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
1188 | Err(DeviceConfigError::Unsupported) |
1189 | } |
1190 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
1191 | Err(DeviceConfigError::Invalid) |
1192 | } |
1193 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
1194 | } |
1195 | } |
1196 | |
1197 | ffi_func!( |
1198 | /// Get the button for the `ScrollMethod::OnButtonDown` method |
1199 | /// for this device. |
1200 | /// |
1201 | /// If `ScrollMethod::OnButtonDown` scroll method is not |
1202 | /// supported, or no button is set, this function returns 0. |
1203 | /// |
1204 | /// ## Note |
1205 | /// |
1206 | /// The return value is independent of the currently selected |
1207 | /// scroll-method. For button scrolling to activate, a device |
1208 | /// must have the `ScrollMethod::OnButtonDown` method enabled, |
1209 | /// and a non-zero button set as scroll button. |
1210 | pub fn config_scroll_button, ffi::libinput_device_config_scroll_get_button, u32); |
1211 | ffi_func!( |
1212 | /// Get the default button for the `ScrollMethod::OnButtonDown` |
1213 | /// method for this device. |
1214 | /// |
1215 | /// If `ScrollMethod::OnButtonDown` scroll method is not |
1216 | /// supported, or no default button is set, |
1217 | /// this function returns 0. |
1218 | pub fn config_scroll_default_button, ffi::libinput_device_config_scroll_get_default_button, u32); |
1219 | |
1220 | /// Get the default scroll method for this device. |
1221 | /// |
1222 | /// The method defines when to generate scroll axis events |
1223 | /// instead of pointer motion events. |
1224 | /// |
1225 | /// A return value of `None` means the scroll method is not known |
1226 | pub fn config_scroll_default_method(&self) -> Option<ScrollMethod> { |
1227 | match unsafe { ffi::libinput_device_config_scroll_get_default_method(self.as_raw_mut()) } { |
1228 | ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_NO_SCROLL => { |
1229 | Some(ScrollMethod::NoScroll) |
1230 | } |
1231 | ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_2FG => { |
1232 | Some(ScrollMethod::TwoFinger) |
1233 | } |
1234 | ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_EDGE => { |
1235 | Some(ScrollMethod::Edge) |
1236 | } |
1237 | ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN => { |
1238 | Some(ScrollMethod::OnButtonDown) |
1239 | } |
1240 | _x => { |
1241 | #[cfg (feature = "log" )] |
1242 | log::warn!( |
1243 | "Unknown ScrollMethod ( {}). Unsupported libinput version?" , |
1244 | _x |
1245 | ); |
1246 | None |
1247 | } |
1248 | } |
1249 | } |
1250 | |
1251 | /// Get the scroll method for this device. |
1252 | /// |
1253 | /// The method defines when to generate scroll axis events |
1254 | /// instead of pointer motion events. |
1255 | /// |
1256 | /// A return value of `None` means the scroll method is not known |
1257 | pub fn config_scroll_method(&self) -> Option<ScrollMethod> { |
1258 | match unsafe { ffi::libinput_device_config_scroll_get_method(self.as_raw_mut()) } { |
1259 | ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_NO_SCROLL => { |
1260 | Some(ScrollMethod::NoScroll) |
1261 | } |
1262 | ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_2FG => { |
1263 | Some(ScrollMethod::TwoFinger) |
1264 | } |
1265 | ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_EDGE => { |
1266 | Some(ScrollMethod::Edge) |
1267 | } |
1268 | ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN => { |
1269 | Some(ScrollMethod::OnButtonDown) |
1270 | } |
1271 | _ => panic!("libinput returned invalid 'libinput_config_scroll_method'" ), |
1272 | } |
1273 | } |
1274 | |
1275 | /// Check which scroll methods a device supports. |
1276 | /// |
1277 | /// The method defines when to generate scroll axis events |
1278 | /// instead of pointer motion events. |
1279 | pub fn config_scroll_methods(&self) -> Vec<ScrollMethod> { |
1280 | let mut methods = Vec::new(); |
1281 | let bitmask = unsafe { ffi::libinput_device_config_scroll_get_methods(self.as_raw_mut()) }; |
1282 | if bitmask & ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_NO_SCROLL as u32 != 0 |
1283 | { |
1284 | methods.push(ScrollMethod::NoScroll); |
1285 | } |
1286 | if bitmask & ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_2FG as u32 != 0 { |
1287 | methods.push(ScrollMethod::TwoFinger); |
1288 | } |
1289 | if bitmask & ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_EDGE as u32 != 0 { |
1290 | methods.push(ScrollMethod::Edge); |
1291 | } |
1292 | if bitmask & ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN as u32 |
1293 | != 0 |
1294 | { |
1295 | methods.push(ScrollMethod::OnButtonDown); |
1296 | } |
1297 | methods |
1298 | } |
1299 | |
1300 | /// Set the scroll method for this device. |
1301 | /// |
1302 | /// The method defines when to generate scroll axis events |
1303 | /// instead of pointer motion events. |
1304 | /// |
1305 | /// ## Note |
1306 | /// |
1307 | /// Setting `ScrollMethod::OnButtonDown` enables the scroll |
1308 | /// method, but scrolling is only activated when the configured |
1309 | /// button is held down. If no button is set, i.e. |
1310 | /// `config_scroll_button` returns 0, scrolling cannot activate. |
1311 | pub fn config_scroll_set_method(&mut self, method: ScrollMethod) -> DeviceConfigResult { |
1312 | match unsafe { |
1313 | ffi::libinput_device_config_scroll_set_method( |
1314 | self.as_raw_mut(), |
1315 | match method { |
1316 | ScrollMethod::NoScroll => { |
1317 | ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_NO_SCROLL |
1318 | } |
1319 | ScrollMethod::TwoFinger => { |
1320 | ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_2FG |
1321 | } |
1322 | ScrollMethod::Edge => { |
1323 | ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_EDGE |
1324 | } |
1325 | ScrollMethod::OnButtonDown => { |
1326 | ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN |
1327 | } |
1328 | }, |
1329 | ) |
1330 | } { |
1331 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
1332 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
1333 | Err(DeviceConfigError::Unsupported) |
1334 | } |
1335 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
1336 | Err(DeviceConfigError::Invalid) |
1337 | } |
1338 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
1339 | } |
1340 | } |
1341 | |
1342 | ffi_func!( |
1343 | /// Get the default mode for scrolling on this device. |
1344 | pub fn config_scroll_default_natural_scroll_enabled, ffi::libinput_device_config_scroll_get_default_natural_scroll_enabled, bool); |
1345 | ffi_func!( |
1346 | /// Get the current mode for scrolling on this device. |
1347 | pub fn config_scroll_natural_scroll_enabled, ffi::libinput_device_config_scroll_get_natural_scroll_enabled, bool); |
1348 | ffi_func!( |
1349 | /// Return non-zero if the device supports "natural scrolling". |
1350 | /// |
1351 | /// In traditional scroll mode, the movement of fingers on a |
1352 | /// touchpad when scrolling matches the movement of the scroll |
1353 | /// bars. When the fingers move down, the scroll bar moves down, |
1354 | /// a line of text on the screen moves towards the upper end of |
1355 | /// the screen. This also matches scroll wheels on mice (wheel |
1356 | /// down, content moves up). |
1357 | /// |
1358 | /// Natural scrolling is the term coined by Apple for inverted |
1359 | /// scrolling. In this mode, the effect of scrolling movement of |
1360 | /// fingers on a touchpad resemble physical manipulation of |
1361 | /// paper. When the fingers move down, a line of text on the |
1362 | /// screen moves down (scrollbars move up). This is the opposite |
1363 | /// of scroll wheels on mice. |
1364 | /// |
1365 | /// A device supporting natural scrolling can be switched between |
1366 | /// traditional scroll mode and natural scroll mode. |
1367 | pub fn config_scroll_has_natural_scroll, ffi::libinput_device_config_scroll_has_natural_scroll, bool); |
1368 | |
1369 | /// Enable or disable natural scrolling on the device. |
1370 | pub fn config_scroll_set_natural_scroll_enabled( |
1371 | &mut self, |
1372 | enabled: bool, |
1373 | ) -> DeviceConfigResult { |
1374 | match unsafe { |
1375 | ffi::libinput_device_config_scroll_set_natural_scroll_enabled( |
1376 | self.as_raw_mut(), |
1377 | enabled as i32, |
1378 | ) |
1379 | } { |
1380 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
1381 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
1382 | Err(DeviceConfigError::Unsupported) |
1383 | } |
1384 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
1385 | Err(DeviceConfigError::Invalid) |
1386 | } |
1387 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
1388 | } |
1389 | } |
1390 | |
1391 | /// Set the button for the `ScrollMethod::OnButtonDown` method |
1392 | /// for this device. |
1393 | /// |
1394 | /// When the current scroll method is set to |
1395 | /// `ScrollMethod::OnButtonDown`, no button press/release events |
1396 | /// will be send for the configured button. |
1397 | /// |
1398 | /// When the configured button is pressed, any motion events |
1399 | /// along a scroll-capable axis are turned into scroll axis |
1400 | /// events. |
1401 | /// |
1402 | /// ## Note |
1403 | /// |
1404 | /// Setting the button does not change the scroll method. To |
1405 | /// change the scroll method call `config_scroll_set_method`. |
1406 | /// If the button is 0, button scrolling is effectively disabled. |
1407 | pub fn config_scroll_set_button(&mut self, button: u32) -> DeviceConfigResult { |
1408 | match unsafe { ffi::libinput_device_config_scroll_set_button(self.as_raw_mut(), button) } { |
1409 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
1410 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
1411 | Err(DeviceConfigError::Unsupported) |
1412 | } |
1413 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
1414 | Err(DeviceConfigError::Invalid) |
1415 | } |
1416 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
1417 | } |
1418 | } |
1419 | |
1420 | /// Get the current scroll button lock state |
1421 | /// |
1422 | /// If `ScrollMethod::OnButtonDown` is not supported, or no button is set, |
1423 | /// this functions returns `Disabled`. |
1424 | /// |
1425 | /// ## Note |
1426 | /// |
1427 | /// The return value is independent of the currently selected scroll-method. |
1428 | /// For the scroll button lock to activate, a device must have the |
1429 | /// `ScrollMethod::OnButtonDown` enabled, and a non-zero button set as scroll button. |
1430 | #[cfg (feature = "libinput_1_15" )] |
1431 | pub fn config_scroll_button_lock(&self) -> ScrollButtonLockState { |
1432 | match unsafe { ffi::libinput_device_config_scroll_get_button_lock(self.as_raw() as *mut _) } { |
1433 | ffi::libinput_config_scroll_button_lock_state_LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED => ScrollButtonLockState::Disabled, |
1434 | ffi::libinput_config_scroll_button_lock_state_LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED => ScrollButtonLockState::Enabled, |
1435 | _ => panic!("libinput returned invalid libinput_config_scroll_button_lock_state" ), |
1436 | } |
1437 | } |
1438 | |
1439 | /// Get the default scroll button lock state |
1440 | /// |
1441 | /// If `ScrollMethod::OnButtonDown` is not supported, or no button is set, |
1442 | /// this functions returns `Disabled`. |
1443 | #[cfg (feature = "libinput_1_15" )] |
1444 | pub fn config_scroll_default_button_lock(&self) -> ScrollButtonLockState { |
1445 | match unsafe { ffi::libinput_device_config_scroll_get_default_button_lock(self.as_raw() as *mut _) } { |
1446 | ffi::libinput_config_scroll_button_lock_state_LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED => ScrollButtonLockState::Disabled, |
1447 | ffi::libinput_config_scroll_button_lock_state_LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED => ScrollButtonLockState::Enabled, |
1448 | _ => panic!("libinput returned invalid libinput_config_scroll_button_lock_state" ), |
1449 | } |
1450 | } |
1451 | |
1452 | /// Set the scroll button lock. |
1453 | /// |
1454 | /// If the state is `Disabled` the button must physically be held down for |
1455 | /// button scrolling to work. If the state is `Enabled`, the button is considered |
1456 | /// logically down after the first press and release sequence, and logically |
1457 | /// up after the second press and release sequence. |
1458 | #[cfg (feature = "libinput_1_15" )] |
1459 | pub fn config_scroll_set_button_lock( |
1460 | &mut self, |
1461 | state: ScrollButtonLockState, |
1462 | ) -> DeviceConfigResult { |
1463 | match unsafe { |
1464 | ffi::libinput_device_config_scroll_set_button_lock(self.as_raw_mut(), |
1465 | match state { |
1466 | ScrollButtonLockState::Enabled => ffi::libinput_config_scroll_button_lock_state_LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED, |
1467 | ScrollButtonLockState::Disabled => ffi::libinput_config_scroll_button_lock_state_LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED, |
1468 | } |
1469 | ) |
1470 | } { |
1471 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
1472 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
1473 | Err(DeviceConfigError::Unsupported) |
1474 | } |
1475 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
1476 | Err(DeviceConfigError::Invalid) |
1477 | } |
1478 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
1479 | } |
1480 | } |
1481 | |
1482 | /// Get the send-event mode for this device. |
1483 | /// |
1484 | /// The mode defines when the device processes and sends events |
1485 | /// to the caller. |
1486 | /// |
1487 | /// If a caller enables the bits for multiple modes, some of |
1488 | /// which are subsets of another mode libinput may drop the bits |
1489 | /// that are subsets. In other words, don't expect |
1490 | /// `config_send_events_mode` to always return exactly the same |
1491 | /// as passed into `config_send_events_set_mode`. |
1492 | pub fn config_send_events_mode(&self) -> SendEventsMode { |
1493 | SendEventsMode::from_bits_truncate(unsafe { |
1494 | ffi::libinput_device_config_send_events_get_mode(self.as_raw_mut()) |
1495 | }) |
1496 | } |
1497 | |
1498 | /// Return the possible send-event modes for this device. |
1499 | /// |
1500 | /// These modes define when a device may process and send events. |
1501 | pub fn config_send_events_modes(&self) -> SendEventsMode { |
1502 | SendEventsMode::from_bits_truncate(unsafe { |
1503 | ffi::libinput_device_config_send_events_get_modes(self.as_raw_mut()) |
1504 | }) |
1505 | } |
1506 | |
1507 | /// Set the send-event mode for this device. |
1508 | /// |
1509 | /// The mode defines when the device processes and sends events |
1510 | /// to the caller. |
1511 | /// |
1512 | /// The selected mode may not take effect immediately. Events |
1513 | /// already received and processed from this device are |
1514 | /// unaffected and will be passed to the caller on the next call |
1515 | /// to `<Libinput as Iterator>::next()`. |
1516 | /// |
1517 | /// If the mode is a mixture of `SendEventsMode`s, the device may |
1518 | /// wait for or generate events until it is in a neutral state. |
1519 | /// For example, this may include waiting for or generating |
1520 | /// button release events. |
1521 | /// |
1522 | /// If the device is already suspended, this function does |
1523 | /// nothing and returns success. Changing the send-event mode on |
1524 | /// a device that has been removed is permitted. |
1525 | pub fn config_send_events_set_mode(&self, mode: SendEventsMode) -> DeviceConfigResult { |
1526 | match unsafe { |
1527 | ffi::libinput_device_config_send_events_set_mode(self.as_raw_mut(), mode.bits()) |
1528 | } { |
1529 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
1530 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
1531 | Err(DeviceConfigError::Unsupported) |
1532 | } |
1533 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
1534 | Err(DeviceConfigError::Invalid) |
1535 | } |
1536 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
1537 | } |
1538 | } |
1539 | |
1540 | /// Get the finger number to button number mapping for |
1541 | /// tap-to-click. |
1542 | /// |
1543 | /// The return value for a device that does not support tapping |
1544 | /// is always `TapButtonMap::LeftRightMiddle`. |
1545 | /// |
1546 | /// This will return `None` for devices |
1547 | /// where `config_tap_finger_count` returns 0. |
1548 | pub fn config_tap_button_map(&self) -> Option<TapButtonMap> { |
1549 | if self.config_tap_finger_count() == 0 { |
1550 | None |
1551 | } else { |
1552 | match unsafe { ffi::libinput_device_config_tap_get_button_map(self.as_raw_mut()) } { |
1553 | ffi::libinput_config_tap_button_map_LIBINPUT_CONFIG_TAP_MAP_LRM => { |
1554 | Some(TapButtonMap::LeftRightMiddle) |
1555 | } |
1556 | ffi::libinput_config_tap_button_map_LIBINPUT_CONFIG_TAP_MAP_LMR => { |
1557 | Some(TapButtonMap::LeftMiddleRight) |
1558 | } |
1559 | _ => panic!("libinput returned invalid 'libinput_config_tap_button_map'" ), |
1560 | } |
1561 | } |
1562 | } |
1563 | |
1564 | /// Get the default finger number to button number mapping for |
1565 | /// tap-to-click. |
1566 | /// |
1567 | /// The return value for a device that does not support tapping |
1568 | /// is always `TapButtonMap::LeftRightMiddle`. |
1569 | /// |
1570 | /// This will return `None` for devices |
1571 | /// where `config_tap_finger_count` returns 0. |
1572 | pub fn config_tap_default_button_map(&self) -> Option<TapButtonMap> { |
1573 | if self.config_tap_finger_count() == 0 { |
1574 | None |
1575 | } else { |
1576 | match unsafe { |
1577 | ffi::libinput_device_config_tap_get_default_button_map(self.as_raw_mut()) |
1578 | } { |
1579 | ffi::libinput_config_tap_button_map_LIBINPUT_CONFIG_TAP_MAP_LRM => { |
1580 | Some(TapButtonMap::LeftRightMiddle) |
1581 | } |
1582 | ffi::libinput_config_tap_button_map_LIBINPUT_CONFIG_TAP_MAP_LMR => { |
1583 | Some(TapButtonMap::LeftMiddleRight) |
1584 | } |
1585 | _ => panic!("libinput returned invalid 'libinput_config_tap_button_map'" ), |
1586 | } |
1587 | } |
1588 | } |
1589 | |
1590 | /// Return whether tap-and-drag is enabled or disabled by default |
1591 | /// on this device. |
1592 | pub fn config_tap_default_drag_enabled(&self) -> bool { |
1593 | match unsafe { ffi::libinput_device_config_tap_get_default_drag_enabled(self.as_raw_mut()) } |
1594 | { |
1595 | ffi::libinput_config_drag_state_LIBINPUT_CONFIG_DRAG_ENABLED => true, |
1596 | ffi::libinput_config_drag_state_LIBINPUT_CONFIG_DRAG_DISABLED => false, |
1597 | _ => panic!("libinput returned invalid 'libinput_config_drag_state'" ), |
1598 | } |
1599 | } |
1600 | |
1601 | /// Check if drag-lock during tapping is enabled by default on |
1602 | /// this device. |
1603 | /// |
1604 | /// If the device does not support tapping, this function always |
1605 | /// returns `false`. |
1606 | /// |
1607 | /// Drag lock may be enabled by default even when tapping is |
1608 | /// disabled by default. |
1609 | pub fn config_tap_default_drag_lock_enabled(&self) -> bool { |
1610 | match unsafe { |
1611 | ffi::libinput_device_config_tap_get_default_drag_lock_enabled(self.as_raw_mut()) |
1612 | } { |
1613 | ffi::libinput_config_drag_lock_state_LIBINPUT_CONFIG_DRAG_LOCK_ENABLED => true, |
1614 | ffi::libinput_config_drag_lock_state_LIBINPUT_CONFIG_DRAG_LOCK_DISABLED => false, |
1615 | _ => panic!("libinput returned invalid 'libinput_config_drag_lock_state'" ), |
1616 | } |
1617 | } |
1618 | |
1619 | /// Return the default setting for whether tap-to-click is |
1620 | /// enabled on this device. |
1621 | pub fn config_tap_default_enabled(&self) -> bool { |
1622 | match unsafe { ffi::libinput_device_config_tap_get_default_enabled(self.as_raw_mut()) } { |
1623 | ffi::libinput_config_tap_state_LIBINPUT_CONFIG_TAP_ENABLED => true, |
1624 | ffi::libinput_config_tap_state_LIBINPUT_CONFIG_TAP_DISABLED => false, |
1625 | _ => panic!("libinput returned invalid 'libinput_config_tap_state'" ), |
1626 | } |
1627 | } |
1628 | |
1629 | /// Return whether tap-and-drag is enabled or disabled on this |
1630 | /// device. |
1631 | pub fn config_tap_drag_enabled(&self) -> bool { |
1632 | match unsafe { ffi::libinput_device_config_tap_get_drag_enabled(self.as_raw_mut()) } { |
1633 | ffi::libinput_config_drag_state_LIBINPUT_CONFIG_DRAG_ENABLED => true, |
1634 | ffi::libinput_config_drag_state_LIBINPUT_CONFIG_DRAG_DISABLED => false, |
1635 | _ => panic!("libinput returned invalid 'libinput_config_drag_state'" ), |
1636 | } |
1637 | } |
1638 | |
1639 | /// Check if drag-lock during tapping is enabled on this device. |
1640 | /// |
1641 | /// If the device does not support tapping, this function always |
1642 | /// returns `false`. |
1643 | /// |
1644 | /// Drag lock may be enabled even when tapping is disabled. |
1645 | pub fn config_tap_drag_lock_enabled(&self) -> bool { |
1646 | match unsafe { ffi::libinput_device_config_tap_get_drag_lock_enabled(self.as_raw_mut()) } { |
1647 | ffi::libinput_config_drag_lock_state_LIBINPUT_CONFIG_DRAG_LOCK_ENABLED => true, |
1648 | ffi::libinput_config_drag_lock_state_LIBINPUT_CONFIG_DRAG_LOCK_DISABLED => false, |
1649 | _ => panic!("libinput returned invalid 'libinput_config_drag_lock_state'" ), |
1650 | } |
1651 | } |
1652 | |
1653 | /// Check if tap-to-click is enabled on this device. |
1654 | /// |
1655 | /// If the device does not support tapping, this function always |
1656 | /// returns `false`. |
1657 | pub fn config_tap_enabled(&self) -> bool { |
1658 | match unsafe { ffi::libinput_device_config_tap_get_enabled(self.as_raw_mut()) } { |
1659 | ffi::libinput_config_tap_state_LIBINPUT_CONFIG_TAP_ENABLED => true, |
1660 | ffi::libinput_config_tap_state_LIBINPUT_CONFIG_TAP_DISABLED => false, |
1661 | _ => panic!("libinput returned invalid 'libinput_config_tap_state'" ), |
1662 | } |
1663 | } |
1664 | |
1665 | ffi_func!( |
1666 | /// Check if the device supports tap-to-click and how many |
1667 | /// fingers can be used for tapping. |
1668 | /// |
1669 | /// See `config_tap_set_enabled` for more information. |
1670 | pub fn config_tap_finger_count, ffi::libinput_device_config_tap_get_finger_count, u32); |
1671 | |
1672 | /// Set the finger number to button number mapping for |
1673 | /// tap-to-click. |
1674 | /// |
1675 | /// The default mapping on most devices is to have a 1, 2 and 3 |
1676 | /// finger tap to map to the left, right and middle button, |
1677 | /// respectively. A device may permit changing the button mapping |
1678 | /// but disallow specific maps. In this case |
1679 | /// `DeviceConfigError::Disabled` is returned, the caller is |
1680 | /// expected to handle this case correctly. |
1681 | /// |
1682 | /// Changing the button mapping may not take effect immediately, |
1683 | /// the device may wait until it is in a neutral state before |
1684 | /// applying any changes. |
1685 | /// |
1686 | /// The mapping may be changed when tap-to-click is disabled. The |
1687 | /// new mapping takes effect when tap-to-click is enabled in the |
1688 | /// future. |
1689 | /// |
1690 | /// ## Note |
1691 | /// |
1692 | /// This will return `None` for devices where |
1693 | /// `config_tap_finger_count` returns 0. |
1694 | pub fn config_tap_set_button_map(&mut self, map: TapButtonMap) -> DeviceConfigResult { |
1695 | match unsafe { |
1696 | ffi::libinput_device_config_tap_set_button_map( |
1697 | self.as_raw_mut(), |
1698 | match map { |
1699 | TapButtonMap::LeftRightMiddle => { |
1700 | ffi::libinput_config_tap_button_map_LIBINPUT_CONFIG_TAP_MAP_LRM |
1701 | } |
1702 | TapButtonMap::LeftMiddleRight => { |
1703 | ffi::libinput_config_tap_button_map_LIBINPUT_CONFIG_TAP_MAP_LMR |
1704 | } |
1705 | }, |
1706 | ) |
1707 | } { |
1708 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
1709 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
1710 | Err(DeviceConfigError::Unsupported) |
1711 | } |
1712 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
1713 | Err(DeviceConfigError::Invalid) |
1714 | } |
1715 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
1716 | } |
1717 | } |
1718 | |
1719 | /// Enable or disable tap-and-drag on this device. |
1720 | /// |
1721 | /// When enabled, a single-finger tap immediately followed by a |
1722 | /// finger down results in a button down event, subsequent finger |
1723 | /// motion thus triggers a drag. The button is released on finger |
1724 | /// up. |
1725 | /// See [Tap-and-drag](https://wayland.freedesktop.org/libinput/doc/latest/tapping.html#tapndrag) |
1726 | /// for more details. |
1727 | pub fn config_tap_set_drag_enabled(&mut self, enabled: bool) -> DeviceConfigResult { |
1728 | match unsafe { |
1729 | ffi::libinput_device_config_tap_set_drag_enabled( |
1730 | self.as_raw_mut(), |
1731 | if enabled { |
1732 | ffi::libinput_config_drag_state_LIBINPUT_CONFIG_DRAG_ENABLED |
1733 | } else { |
1734 | ffi::libinput_config_drag_state_LIBINPUT_CONFIG_DRAG_DISABLED |
1735 | }, |
1736 | ) |
1737 | } { |
1738 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
1739 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
1740 | Err(DeviceConfigError::Unsupported) |
1741 | } |
1742 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
1743 | Err(DeviceConfigError::Invalid) |
1744 | } |
1745 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
1746 | } |
1747 | } |
1748 | |
1749 | /// Enable or disable drag-lock during tapping on this device. |
1750 | /// |
1751 | /// When enabled, a finger may be lifted and put back on the |
1752 | /// touchpad within a timeout and the drag process continues. |
1753 | /// When disabled, lifting the finger during a tap-and-drag will |
1754 | /// immediately stop the drag. |
1755 | /// See [Tap-and-drag](https://wayland.freedesktop.org/libinput/doc/latest/tapping.html#tapndrag) |
1756 | /// for details. |
1757 | /// |
1758 | /// Enabling drag lock on a device that has tapping disabled is |
1759 | /// permitted, but has no effect until tapping is enabled. |
1760 | pub fn config_tap_set_drag_lock_enabled(&mut self, enabled: bool) -> DeviceConfigResult { |
1761 | match unsafe { |
1762 | ffi::libinput_device_config_tap_set_drag_lock_enabled( |
1763 | self.as_raw_mut(), |
1764 | if enabled { |
1765 | ffi::libinput_config_drag_lock_state_LIBINPUT_CONFIG_DRAG_LOCK_ENABLED |
1766 | } else { |
1767 | ffi::libinput_config_drag_lock_state_LIBINPUT_CONFIG_DRAG_LOCK_DISABLED |
1768 | }, |
1769 | ) |
1770 | } { |
1771 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
1772 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
1773 | Err(DeviceConfigError::Unsupported) |
1774 | } |
1775 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
1776 | Err(DeviceConfigError::Invalid) |
1777 | } |
1778 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
1779 | } |
1780 | } |
1781 | |
1782 | /// Enable or disable tap-to-click on this device, with a default |
1783 | /// mapping of 1, 2, 3 finger tap mapping to left, right, middle |
1784 | /// click, respectively. |
1785 | /// |
1786 | /// Tapping is limited by the number of simultaneous touches |
1787 | /// supported by the device, see `config_tap_finger_count`. |
1788 | pub fn config_tap_set_enabled(&mut self, enabled: bool) -> DeviceConfigResult { |
1789 | match unsafe { |
1790 | ffi::libinput_device_config_tap_set_enabled( |
1791 | self.as_raw_mut(), |
1792 | if enabled { |
1793 | ffi::libinput_config_tap_state_LIBINPUT_CONFIG_TAP_ENABLED |
1794 | } else { |
1795 | ffi::libinput_config_tap_state_LIBINPUT_CONFIG_TAP_DISABLED |
1796 | }, |
1797 | ) |
1798 | } { |
1799 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), |
1800 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { |
1801 | Err(DeviceConfigError::Unsupported) |
1802 | } |
1803 | ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { |
1804 | Err(DeviceConfigError::Invalid) |
1805 | } |
1806 | _ => panic!("libinput returned invalid 'libinput_config_status'" ), |
1807 | } |
1808 | } |
1809 | } |
1810 | |