1 | // Allow unnecessary casts since ffi types may differ by C ABI |
2 | // TODO Error type instead of `Result<_, ()>` |
3 | // TODO Better way to handle `SendEventsMode::ENABLED` being 0? |
4 | #![allow ( |
5 | clippy::bad_bit_mask, |
6 | clippy::result_unit_err, |
7 | clippy::unnecessary_cast |
8 | )] |
9 | |
10 | use crate::{ |
11 | event::{switch::Switch, tablet_pad::TabletPadModeGroup}, |
12 | ffi, AsRaw, FromRaw, Libinput, Seat, |
13 | }; |
14 | use bitflags::bitflags; |
15 | use std::ffi::{CStr, CString}; |
16 | #[cfg (feature = "udev" )] |
17 | use udev::{ |
18 | ffi::{udev as udev_context, udev_device, udev_device_get_udev, udev_ref}, |
19 | Device as UdevDevice, FromRawWithContext as UdevFromRawWithContext, |
20 | }; |
21 | |
22 | /// Capabilities on a device. |
23 | /// |
24 | /// A device may have one or more capabilities at a time, capabilities |
25 | /// remain static for the lifetime of the device. |
26 | #[derive (Debug, Copy, Clone, PartialEq, Eq, Hash)] |
27 | #[non_exhaustive ] |
28 | pub enum DeviceCapability { |
29 | /// Keyboard capability |
30 | Keyboard, |
31 | /// Pointer capability |
32 | Pointer, |
33 | /// Touch capability |
34 | Touch, |
35 | /// TabletTool capability |
36 | TabletTool, |
37 | /// TabletPad capability |
38 | TabletPad, |
39 | /// Gesture capability |
40 | Gesture, |
41 | /// Switch capability |
42 | Switch, |
43 | } |
44 | |
45 | /// Pointer Acceleration Profile |
46 | #[derive (Debug, Copy, Clone, PartialEq, Eq, Hash)] |
47 | #[non_exhaustive ] |
48 | pub enum AccelProfile { |
49 | /// A flat acceleration profile. |
50 | /// |
51 | /// Pointer motion is accelerated by a constant (device-specific) |
52 | /// factor, depending on the current speed. |
53 | Flat, |
54 | /// An adaptive acceleration profile. |
55 | /// |
56 | /// Pointer acceleration depends on the input speed. This is the |
57 | /// default profile for most devices. |
58 | Adaptive, |
59 | } |
60 | |
61 | /// The click method defines when to generate software-emulated |
62 | /// buttons, usually on a device that does not have a specific |
63 | /// physical button available. |
64 | #[derive (Debug, Copy, Clone, PartialEq, Eq, Hash)] |
65 | #[non_exhaustive ] |
66 | pub enum ClickMethod { |
67 | /// Use software-button areas (see [Clickfinger behavior](https://wayland.freedesktop.org/libinput/doc/latest/clickpad_softbuttons.html#clickfinger)) |
68 | /// to generate button events. |
69 | ButtonAreas, |
70 | /// The number of fingers decides which button press to generate. |
71 | Clickfinger, |
72 | } |
73 | |
74 | /// The scroll method of a device selects when to generate scroll axis |
75 | /// events instead of pointer motion events. |
76 | #[derive (Debug, Copy, Clone, PartialEq, Eq, Hash)] |
77 | #[non_exhaustive ] |
78 | pub enum ScrollMethod { |
79 | /// Never send scroll events instead of pointer motion events. |
80 | /// |
81 | /// This has no effect on events generated by scroll wheels. |
82 | NoScroll, |
83 | /// Send scroll events when two fingers are logically down on the |
84 | /// device. |
85 | TwoFinger, |
86 | /// Send scroll events when a finger moves along the bottom or |
87 | /// right edge of a device. |
88 | Edge, |
89 | /// Send scroll events when a button is down and the device moves |
90 | /// along a scroll-capable axis. |
91 | OnButtonDown, |
92 | } |
93 | |
94 | /// Errors returned when applying configuration settings. |
95 | #[derive (Debug, Copy, Clone, PartialEq, Eq, Hash)] |
96 | pub enum DeviceConfigError { |
97 | /// Configuration not available on this device. |
98 | Unsupported, |
99 | /// Invalid parameter range. |
100 | Invalid, |
101 | } |
102 | |
103 | bitflags! { |
104 | /// The send-event mode of a device defines when a device may generate |
105 | /// events and pass those events to the caller. |
106 | 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 ] |
134 | pub 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)] |
145 | pub enum ScrollButtonLockState { |
146 | Disabled, |
147 | Enabled, |
148 | } |
149 | |
150 | /// Result returned when applying configuration settings. |
151 | pub type DeviceConfigResult = Result<(), DeviceConfigError>; |
152 | |
153 | bitflags! { |
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 | |
165 | ffi_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. |
190 | struct DeviceGroup, ffi::libinput_device_group, ffi::libinput_device_group_ref, ffi::libinput_device_group_unref); |
191 | |
192 | ffi_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. |
198 | struct Device, ffi::libinput_device, ffi::libinput_device_ref, ffi::libinput_device_unref); |
199 | |
200 | impl 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 | |