input/
device.rs

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
10use crate::{
11    event::{switch::Switch, tablet_pad::TabletPadModeGroup},
12    ffi, AsRaw, FromRaw, Libinput, Seat,
13};
14use bitflags::bitflags;
15use std::ffi::{CStr, CString};
16#[cfg(feature = "udev")]
17use 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]
28pub 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]
48pub 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]
66pub 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]
78pub 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)]
96pub enum DeviceConfigError {
97    /// Configuration not available on this device.
98    Unsupported,
99    /// Invalid parameter range.
100    Invalid,
101}
102
103bitflags! {
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]
135pub 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)]
146pub enum ScrollButtonLockState {
147    Disabled,
148    Enabled,
149}
150
151/// Result returned when applying configuration settings.
152pub type DeviceConfigResult = Result<(), DeviceConfigError>;
153
154bitflags! {
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
167ffi_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.
192struct DeviceGroup, ffi::libinput_device_group, ffi::libinput_device_group_ref, ffi::libinput_device_group_unref);
193
194ffi_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.
200struct Device, ffi::libinput_device, ffi::libinput_device_ref, ffi::libinput_device_unref);
201
202impl 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}