input/event/
pointer.rs

1//! Pointer event types
2#![allow(deprecated)]
3
4use super::EventTrait;
5use crate::{ffi, AsRaw, Context, FromRaw, Libinput};
6
7/// Common functions for all Pointer-Events implement.
8pub trait PointerEventTrait: AsRaw<ffi::libinput_event_pointer> + Context {
9    ffi_func!(
10    /// The event time for this event
11    fn time, ffi::libinput_event_pointer_get_time, u32);
12    ffi_func!(
13    /// The event time for this event in microseconds
14    fn time_usec, ffi::libinput_event_pointer_get_time_usec, u64);
15
16    /// Convert into a general `TouchEvent` again
17    fn into_pointer_event(self) -> PointerEvent
18    where
19        Self: Sized,
20    {
21        unsafe { PointerEvent::from_raw(self.as_raw_mut(), self.context()) }
22    }
23}
24
25impl<T: AsRaw<ffi::libinput_event_pointer> + Context> PointerEventTrait for T {}
26
27/// A pointer related `Event`
28#[derive(Debug, PartialEq, Eq, Hash)]
29#[non_exhaustive]
30pub enum PointerEvent {
31    /// An event related to moving a pointer
32    Motion(PointerMotionEvent),
33    /// An event related to absolute pointer movement
34    MotionAbsolute(PointerMotionAbsoluteEvent),
35    /// An event related to button pressed on a pointer device
36    Button(PointerButtonEvent),
37    /// An event related to moving axis on a pointer device
38    #[cfg_attr(
39        feature = "libinput_1_19",
40        deprecated = "Use `PointerEvent::Scroll*` events instead"
41    )]
42    Axis(PointerAxisEvent),
43    /// A scroll event from a wheel.
44    #[cfg(feature = "libinput_1_19")]
45    ScrollWheel(PointerScrollWheelEvent),
46    /// A scroll event caused by the movement of one or more fingers on a device.
47    #[cfg(feature = "libinput_1_19")]
48    ScrollFinger(PointerScrollFingerEvent),
49    /// A scroll event from a continuous scroll source, e.g. button scrolling.
50    #[cfg(feature = "libinput_1_19")]
51    ScrollContinuous(PointerScrollContinuousEvent),
52}
53
54impl EventTrait for PointerEvent {
55    #[doc(hidden)]
56    fn as_raw_event(&self) -> *mut ffi::libinput_event {
57        match self {
58            PointerEvent::Motion(event) => event.as_raw_event(),
59            PointerEvent::MotionAbsolute(event) => event.as_raw_event(),
60            PointerEvent::Button(event) => event.as_raw_event(),
61            PointerEvent::Axis(event) => event.as_raw_event(),
62            #[cfg(feature = "libinput_1_19")]
63            PointerEvent::ScrollWheel(event) => event.as_raw_event(),
64            #[cfg(feature = "libinput_1_19")]
65            PointerEvent::ScrollFinger(event) => event.as_raw_event(),
66            #[cfg(feature = "libinput_1_19")]
67            PointerEvent::ScrollContinuous(event) => event.as_raw_event(),
68        }
69    }
70}
71
72impl FromRaw<ffi::libinput_event_pointer> for PointerEvent {
73    unsafe fn try_from_raw(
74        event: *mut ffi::libinput_event_pointer,
75        context: &Libinput,
76    ) -> Option<Self> {
77        let base = ffi::libinput_event_pointer_get_base_event(event);
78        match ffi::libinput_event_get_type(base) {
79            ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_MOTION => Some(PointerEvent::Motion(
80                PointerMotionEvent::try_from_raw(event, context)?,
81            )),
82            ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE => {
83                Some(PointerEvent::MotionAbsolute(
84                    PointerMotionAbsoluteEvent::try_from_raw(event, context)?,
85                ))
86            }
87            ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_BUTTON => Some(PointerEvent::Button(
88                PointerButtonEvent::try_from_raw(event, context)?,
89            )),
90            ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_AXIS => Some(PointerEvent::Axis(
91                PointerAxisEvent::try_from_raw(event, context)?,
92            )),
93            #[cfg(feature = "libinput_1_19")]
94            ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_SCROLL_WHEEL => Some(
95                PointerEvent::ScrollWheel(PointerScrollWheelEvent::try_from_raw(event, context)?),
96            ),
97            #[cfg(feature = "libinput_1_19")]
98            ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_SCROLL_FINGER => Some(
99                PointerEvent::ScrollFinger(PointerScrollFingerEvent::try_from_raw(event, context)?),
100            ),
101            #[cfg(feature = "libinput_1_19")]
102            ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS => {
103                Some(PointerEvent::ScrollContinuous(
104                    PointerScrollContinuousEvent::try_from_raw(event, context)?,
105                ))
106            }
107            _ => None,
108        }
109    }
110    unsafe fn from_raw(event: *mut ffi::libinput_event_pointer, context: &Libinput) -> Self {
111        Self::try_from_raw(event, context).expect("Unknown pointer event type")
112    }
113}
114
115impl AsRaw<ffi::libinput_event_pointer> for PointerEvent {
116    fn as_raw(&self) -> *const ffi::libinput_event_pointer {
117        match self {
118            PointerEvent::Motion(event) => event.as_raw(),
119            PointerEvent::MotionAbsolute(event) => event.as_raw(),
120            PointerEvent::Button(event) => event.as_raw(),
121            PointerEvent::Axis(event) => event.as_raw(),
122            #[cfg(feature = "libinput_1_19")]
123            PointerEvent::ScrollWheel(event) => event.as_raw(),
124            #[cfg(feature = "libinput_1_19")]
125            PointerEvent::ScrollFinger(event) => event.as_raw(),
126            #[cfg(feature = "libinput_1_19")]
127            PointerEvent::ScrollContinuous(event) => event.as_raw(),
128        }
129    }
130}
131
132impl Context for PointerEvent {
133    fn context(&self) -> &Libinput {
134        match self {
135            PointerEvent::Motion(event) => event.context(),
136            PointerEvent::MotionAbsolute(event) => event.context(),
137            PointerEvent::Button(event) => event.context(),
138            PointerEvent::Axis(event) => event.context(),
139            #[cfg(feature = "libinput_1_19")]
140            PointerEvent::ScrollWheel(event) => event.context(),
141            #[cfg(feature = "libinput_1_19")]
142            PointerEvent::ScrollFinger(event) => event.context(),
143            #[cfg(feature = "libinput_1_19")]
144            PointerEvent::ScrollContinuous(event) => event.context(),
145        }
146    }
147}
148
149ffi_event_struct!(
150/// An event related to moving a pointer
151struct PointerMotionEvent, ffi::libinput_event_pointer, ffi::libinput_event_pointer_get_base_event);
152
153impl PointerMotionEvent {
154    ffi_func!(
155    /// Return the delta between the last event and the current event.
156    ///
157    /// If a device employs pointer acceleration, the delta returned by this
158    /// function is the accelerated delta.
159    ///
160    /// Relative motion deltas are to be interpreted as pixel movement of a
161    /// standardized mouse. See [Normalization of relative motion](https://wayland.freedesktop.org/libinput/doc/latest/motion_normalization.html)
162    /// for more details.
163    pub fn dx, ffi::libinput_event_pointer_get_dx, f64);
164    ffi_func!(
165    /// Return the relative delta of the unaccelerated motion vector of the
166    /// current event.
167    ///
168    /// Relative unaccelerated motion deltas are raw device coordinates. Note that
169    /// these coordinates are subject to the device's native resolution. Touchpad
170    /// coordinates represent raw device coordinates in the X resolution of the
171    /// touchpad. See [Normalization of relative motion](https://wayland.freedesktop.org/libinput/doc/latest/motion_normalization.html)
172    /// for more details.
173    ///
174    /// Any rotation applied to the device also applies to unaccelerated motion
175    /// (see `Device::rotation_set_angle`).
176    pub fn dx_unaccelerated, ffi::libinput_event_pointer_get_dx_unaccelerated, f64);
177    ffi_func!(
178    /// Return the delta between the last event and the current event.
179    ///
180    /// If a device employs pointer acceleration, the delta returned by this
181    /// function is the accelerated delta.
182    ///
183    /// Relative motion deltas are to be interpreted as pixel movement of a
184    /// standardized mouse. See [Normalization of relative motion](https://wayland.freedesktop.org/libinput/doc/latest/motion_normalization.html)
185    /// for more details.
186    pub fn dy, ffi::libinput_event_pointer_get_dy, f64);
187    ffi_func!(
188    /// Return the relative delta of the unaccelerated motion vector of the
189    /// current event.
190    ///
191    /// Relative unaccelerated motion deltas are raw device coordinates. Note that
192    /// these coordinates are subject to the device's native resolution. Touchpad
193    /// coordinates represent raw device coordinates in the X resolution of the
194    /// touchpad. See [Normalization of relative motion](https://wayland.freedesktop.org/libinput/doc/latest/motion_normalization.html)
195    /// for more details.
196    ///
197    /// Any rotation applied to the device also applies to unaccelerated motion
198    /// (see `Device::rotation_set_angle`).
199    pub fn dy_unaccelerated, ffi::libinput_event_pointer_get_dy_unaccelerated, f64);
200}
201
202ffi_event_struct!(
203/// An event related to absolute pointer movement
204struct PointerMotionAbsoluteEvent, ffi::libinput_event_pointer, ffi::libinput_event_pointer_get_base_event);
205
206impl PointerMotionAbsoluteEvent {
207    ffi_func!(
208    /// Return the current absolute x coordinate of the pointer event, in mm from
209    /// the top left corner of the device.
210    ///
211    /// To get the corresponding output screen coordinate, use
212    /// `absolute_x_transformed`.
213    pub fn absolute_x, ffi::libinput_event_pointer_get_absolute_x, f64);
214    ffi_func!(
215    /// Return the current absolute y coordinate of the pointer event, in mm from
216    /// the top left corner of the device.
217    ///
218    /// To get the corresponding output screen coordinate, use
219    /// `absolute_y_transformed`.
220    pub fn absolute_y, ffi::libinput_event_pointer_get_absolute_y, f64);
221
222    /// Return the current absolute x coordinate of the pointer event, transformed
223    /// to screen coordinates.
224    ///
225    /// ## Arguments
226    ///
227    /// - width - The current output screen width
228    pub fn absolute_x_transformed(&self, width: u32) -> f64 {
229        unsafe { ffi::libinput_event_pointer_get_absolute_x_transformed(self.as_raw_mut(), width) }
230    }
231
232    /// Return the current absolute y coordinate of the pointer event, transformed
233    /// to screen coordinates.
234    ///
235    /// ## Arguments
236    ///
237    /// - height - The current output screen height
238    pub fn absolute_y_transformed(&self, height: u32) -> f64 {
239        unsafe { ffi::libinput_event_pointer_get_absolute_y_transformed(self.as_raw_mut(), height) }
240    }
241}
242
243/// State of a Button
244#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
245pub enum ButtonState {
246    /// Button is pressed
247    Pressed,
248    /// Button is released
249    Released,
250}
251
252ffi_event_struct!(
253/// An event related to button pressed on a pointer device
254struct PointerButtonEvent, ffi::libinput_event_pointer, ffi::libinput_event_pointer_get_base_event);
255
256impl PointerButtonEvent {
257    ffi_func!(
258    /// Return the button that triggered this event.
259    pub fn button, ffi::libinput_event_pointer_get_button, u32);
260    ffi_func!(
261    /// For the button returns the total number of buttons pressed on all devices
262    /// on the associated seat after the event was triggered.
263    pub fn seat_button_count, ffi::libinput_event_pointer_get_seat_button_count, u32);
264
265    /// Return the button state that triggered this event.
266    pub fn button_state(&self) -> ButtonState {
267        match unsafe { ffi::libinput_event_pointer_get_button_state(self.as_raw_mut()) } {
268            ffi::libinput_button_state_LIBINPUT_BUTTON_STATE_PRESSED => ButtonState::Pressed,
269            ffi::libinput_button_state_LIBINPUT_BUTTON_STATE_RELEASED => ButtonState::Released,
270            _ => panic!("libinput returned invalid 'libinput_button_state'"),
271        }
272    }
273}
274
275/// The source for a `PointerAxisEvent`.
276#[cfg_attr(
277    feature = "libinput_1_19",
278    deprecated = "Use `PointerEvent::Scroll*` events instead"
279)]
280#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
281pub enum AxisSource {
282    /// The event is caused by the rotation of a wheel.
283    Wheel,
284    /// The event is caused by the movement of one or more fingers on a device.
285    Finger,
286    /// The event is caused by the motion of some device.
287    Continuous,
288    /// The event is caused by the tilting of a mouse wheel rather than its rotation.
289    ///
290    /// This method is commonly used on mice without separate horizontal scroll wheels.
291    #[cfg_attr(
292        feature = "libinput_1_19",
293        deprecated = "No device has ever sent this source."
294    )]
295    WheelTilt,
296}
297
298/// Axes on a device with the pointer capability that are not  x or y coordinates.
299///
300/// The two scroll axes `Vertical` and `Horizontal` are engaged separately,
301/// depending on the device. libinput provides some scroll direction locking but
302/// it is up to the caller to determine which axis is needed and appropriate in
303/// the current interaction
304#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
305pub enum Axis {
306    /// Vertical axis
307    Vertical,
308    /// Horizontal axis
309    Horizontal,
310}
311
312ffi_event_struct!(
313/// An event related to moving axis on a pointer device
314#[cfg_attr(feature = "libinput_1_19", deprecated = "Use `PointerEvent::Scroll*` events instead")]
315struct PointerAxisEvent, ffi::libinput_event_pointer, ffi::libinput_event_pointer_get_base_event);
316
317impl PointerAxisEvent {
318    /// Check if the event has a valid value for the given axis.
319    ///
320    /// If this function returns true for an axis and `axis_value` returns a
321    /// value of 0, the event is a scroll stop event.
322    #[cfg_attr(
323        feature = "libinput_1_19",
324        deprecated = "Use `PointerScrollEvent::has_axis` instead"
325    )]
326    pub fn has_axis(&self, axis: Axis) -> bool {
327        unsafe {
328            ffi::libinput_event_pointer_has_axis(
329                self.as_raw_mut(),
330                match axis {
331                    Axis::Vertical => {
332                        ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL
333                    }
334                    Axis::Horizontal => {
335                        ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL
336                    }
337                },
338            ) != 0
339        }
340    }
341
342    /// Return the source for a given axis event.
343    ///
344    /// Axis events (scroll events) can be caused by a hardware item such as a
345    /// scroll wheel or emulated from other input sources, such as two-finger or
346    /// edge scrolling on a touchpad.
347    ///
348    /// If the source is `Finger`, libinput guarantees that a scroll sequence is
349    /// terminated with a scroll value of 0. A caller may use this information to
350    /// decide on whether kinetic scrolling should be triggered on this scroll
351    /// sequence. The coordinate system is identical to the cursor movement, i.e.
352    /// a scroll value of 1 represents the equivalent relative motion of 1.
353    ///
354    /// If the source is `Wheel`, no terminating event is guaranteed (though it
355    /// may happen). Scrolling is in discrete steps, the value is the angle the
356    /// wheel moved in degrees. The default is 15 degrees per wheel click, but
357    /// some mice may have differently grained wheels. It is up to the caller how
358    /// to interpret such different step sizes.
359    ///
360    /// If the source is `Continuous`, no terminating event is guaranteed (though
361    /// it may happen). The coordinate system is identical to the cursor movement,
362    /// i.e. a scroll value of 1 represents the equivalent relative motion of 1.
363    ///
364    /// If the source is `WheelTilt`, no terminating event is guaranteed (though
365    /// it may happen). Scrolling is in discrete steps and there is no physical
366    /// equivalent for the value returned here. For backwards compatibility, the
367    /// value returned by this function is identical to a single mouse wheel
368    /// rotation by this device (see the documentation for `WheelTilt` above).
369    /// Callers should not use this value but instead exclusively refer to the
370    //. value returned by `axis_value_discrete`.
371    #[cfg_attr(
372        feature = "libinput_1_19",
373        deprecated = "Use `PointerScroll*` events instead"
374    )]
375    pub fn axis_source(&self) -> AxisSource {
376        match unsafe { ffi::libinput_event_pointer_get_axis_source(self.as_raw_mut()) } {
377            ffi::libinput_pointer_axis_source_LIBINPUT_POINTER_AXIS_SOURCE_WHEEL => {
378                AxisSource::Wheel
379            }
380            ffi::libinput_pointer_axis_source_LIBINPUT_POINTER_AXIS_SOURCE_FINGER => {
381                AxisSource::Finger
382            }
383            ffi::libinput_pointer_axis_source_LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS => {
384                AxisSource::Continuous
385            }
386            ffi::libinput_pointer_axis_source_LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT => {
387                AxisSource::WheelTilt
388            }
389            // Axis Event is deprecated, no new variants will be added
390            _ => unreachable!(),
391        }
392    }
393
394    /// Return the axis value of the given axis.
395    ///
396    /// The interpretation of the value depends on the axis. For the two scrolling
397    /// axes `Vertical` and `Horizontal`, the value of the event is in relative
398    /// scroll units, with the positive direction being down or right,
399    /// respectively. For the interpretation of the value, see `axis_source`.
400    ///
401    /// If `has_axis` returns `false` for an axis, this function returns 0 for
402    /// that axis.
403    #[cfg_attr(
404        feature = "libinput_1_19",
405        deprecated = "Use `PointerScrollEvent::scroll_value` instead"
406    )]
407    pub fn axis_value(&self, axis: Axis) -> f64 {
408        unsafe {
409            ffi::libinput_event_pointer_get_axis_value(
410                self.as_raw_mut(),
411                match axis {
412                    Axis::Vertical => {
413                        ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL
414                    }
415                    Axis::Horizontal => {
416                        ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL
417                    }
418                },
419            )
420        }
421    }
422
423    /// Return the axis value in discrete steps for a given axis event.
424    ///
425    /// How a value translates into a discrete step depends on the source.
426    ///
427    /// If the source is `Wheel`, the discrete value correspond to the number of
428    /// physical mouse wheel clicks.
429    ///
430    /// If the source is `Continuous` or `Finger`, the discrete value is always
431    /// `None`.
432    #[cfg_attr(
433        feature = "libinput_1_19",
434        deprecated = "Use `PointerScrollWheelEvent::scroll_value_v120` instead"
435    )]
436    pub fn axis_value_discrete(&self, axis: Axis) -> Option<f64> {
437        match self.axis_source() {
438            AxisSource::Continuous | AxisSource::Finger => None,
439            _ => Some(unsafe {
440                ffi::libinput_event_pointer_get_axis_value_discrete(
441                    self.as_raw_mut(),
442                    match axis {
443                        Axis::Vertical => {
444                            ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL
445                        }
446                        Axis::Horizontal => {
447                            ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL
448                        }
449                    },
450                )
451            }),
452        }
453    }
454}
455
456#[cfg(feature = "libinput_1_19")]
457ffi_event_struct!(
458/// An event related to moving a scroll whell on a pointer device
459struct PointerScrollWheelEvent, ffi::libinput_event_pointer, ffi::libinput_event_pointer_get_base_event);
460
461#[cfg(feature = "libinput_1_19")]
462ffi_event_struct!(
463/// An event related to moving a finger on a pointer device
464struct PointerScrollFingerEvent, ffi::libinput_event_pointer, ffi::libinput_event_pointer_get_base_event);
465
466#[cfg(feature = "libinput_1_19")]
467ffi_event_struct!(
468/// An event related to a continuous scroll source on a pointer device
469struct PointerScrollContinuousEvent, ffi::libinput_event_pointer, ffi::libinput_event_pointer_get_base_event);
470
471#[cfg(feature = "libinput_1_19")]
472/// Common functions of PointerScroll type events
473pub trait PointerScrollEvent: AsRaw<ffi::libinput_event_pointer> {
474    /// Check if the event has a valid value for the given axis.
475    ///
476    /// If this function returns true for an axis and `axis_value` returns a
477    /// value of 0, the event is a scroll stop event.
478    fn has_axis(&self, axis: Axis) -> bool {
479        unsafe {
480            ffi::libinput_event_pointer_has_axis(
481                self.as_raw_mut(),
482                match axis {
483                    Axis::Vertical => {
484                        ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL
485                    }
486                    Axis::Horizontal => {
487                        ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL
488                    }
489                },
490            ) != 0
491        }
492    }
493
494    /// Return the axis value of the given axis.
495    ///
496    /// The interpretation of the value depends on the axis. For the two scrolling axes [`Axis::Vertical`] and [`Axis::Horizontal`],
497    /// the value of the event is in relative scroll units, with the positive direction being down or right,
498    /// respectively. If [`PointerScrollEvent::has_axis`] returns false for an axis, this function returns 0 for that axis.
499    ///
500    /// If the event is a [`PointerScrollFingerEvent`], libinput guarantees that a scroll sequence is terminated with a scroll value of 0.
501    /// A caller may use this information to decide on whether kinetic scrolling should be triggered on this scroll sequence.
502    /// The coordinate system is identical to the cursor movement, i.e. a scroll value of 1 represents the equivalent relative motion of 1.
503    ///
504    /// If the event is a [`PointerScrollWheelEvent`], no terminating event is guaranteed (though it may happen).
505    /// Scrolling is in discrete steps, the value is the angle the wheel moved in degrees. The default is 15 degrees per wheel click,
506    /// but some mice may have differently grained wheels. It is up to the caller how to interpret such different step sizes.
507    /// Callers should use [`PointerScrollWheelEvent::scroll_value_v120`] for a simpler API of handling scroll wheel events of different step sizes.
508    ///
509    /// If the event is a [`PointerScrollContinuousEvent`], libinput guarantees that a scroll sequence is terminated with a scroll value of 0.
510    /// The coordinate system is identical to the cursor movement, i.e. a scroll value of 1 represents the equivalent relative motion of 1.
511    fn scroll_value(&self, axis: Axis) -> f64 {
512        unsafe {
513            ffi::libinput_event_pointer_get_scroll_value(
514                self.as_raw_mut(),
515                match axis {
516                    Axis::Vertical => {
517                        ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL
518                    }
519                    Axis::Horizontal => {
520                        ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL
521                    }
522                },
523            )
524        }
525    }
526}
527
528#[cfg(feature = "libinput_1_19")]
529impl PointerScrollEvent for PointerScrollWheelEvent {}
530#[cfg(feature = "libinput_1_19")]
531impl PointerScrollEvent for PointerScrollFingerEvent {}
532#[cfg(feature = "libinput_1_19")]
533impl PointerScrollEvent for PointerScrollContinuousEvent {}
534
535#[cfg(feature = "libinput_1_19")]
536impl PointerScrollWheelEvent {
537    /// Return the axis value as a v120-normalized value, that represents the movement in logical mouse wheel clicks, normalized to the -120..+120 range.
538    ///
539    /// A value that is a fraction of ±120 indicates a wheel movement less than one logical click,
540    /// a caller should either scroll by the respective fraction of the normal scroll distance or accumulate
541    /// that value until a multiple of 120 is reached.
542    ///
543    /// For most callers, this is the preferred way of handling high-resolution scroll events.
544    ///
545    /// The normalized v120 value does not take device-specific physical angles or distances into account,
546    /// i.e. a wheel with a click angle of 20 degrees produces only 18 logical clicks per 360 degree rotation,
547    /// a wheel with a click angle of 15 degrees produces 24 logical clicks per 360 degree rotation.
548    /// Where the physical angle matters, use [`PointerScrollEvent::scroll_value`] instead.
549    ///
550    /// The magic number 120 originates from the [Windows Vista Mouse Wheel design document](http://download.microsoft.com/download/b/d/1/bd1f7ef4-7d72-419e-bc5c-9f79ad7bb66e/wheel.docx).
551    pub fn scroll_value_v120(&self, axis: Axis) -> f64 {
552        unsafe {
553            ffi::libinput_event_pointer_get_scroll_value_v120(
554                self.as_raw_mut(),
555                match axis {
556                    Axis::Vertical => {
557                        ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL
558                    }
559                    Axis::Horizontal => {
560                        ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL
561                    }
562                },
563            )
564        }
565    }
566}