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