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}