input/event/
tablet_tool.rs

1//! Tablet tool event types
2
3use super::{pointer::ButtonState, EventTrait};
4use crate::{ffi, AsRaw, Context, FromRaw, Libinput};
5
6mod tool;
7pub use self::tool::*;
8
9/// Common functions all TabletTool-Events implement.
10pub trait TabletToolEventTrait: AsRaw<ffi::libinput_event_tablet_tool> + Context {
11    ffi_func!(
12    /// The event time for this event
13    fn time, ffi::libinput_event_tablet_tool_get_time, u32);
14    ffi_func!(
15    /// The event time for this event in microseconds
16    fn time_usec, ffi::libinput_event_tablet_tool_get_time_usec, u64);
17    ffi_func!(
18    /// Check if the distance axis was updated in this event.
19    ///
20    /// For `TabletToolProximityEvent`s this function always returns `true`. For
21    /// `TabletToolButtonEvent`s this function always returns `false`.
22    fn distance_has_changed, ffi::libinput_event_tablet_tool_distance_has_changed, bool);
23    ffi_func!(
24    /// Returns the current distance from the tablet's sensor, normalized to the range
25    /// [0, 1].
26    ///
27    /// If this axis does not exist on the current tool, this function returns 0.
28    fn distance, ffi::libinput_event_tablet_tool_get_distance, f64);
29    ffi_func!(
30    /// Return the delta between the last event and the current event.
31    ///
32    /// If the tool employs pointer acceleration, the delta returned by this function is
33    /// the accelerated delta.
34    ///
35    /// This value is in screen coordinate space, the delta is to be interpreted like
36    /// the return value of `PointerMotionEvent::dx`. See
37    /// [Relative motion for tablet tools](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-relative-motion)
38    /// for more details.
39    fn dx, ffi::libinput_event_tablet_tool_get_dx, f64);
40    ffi_func!(
41    /// Return the delta between the last event and the current event.
42    ///
43    /// If the tool employs pointer acceleration, the delta returned by this function is
44    /// the accelerated delta.
45    ///
46    /// This value is in screen coordinate space, the delta is to be interpreted like
47    /// the return value of `PointerMotionEvent::dy`. See
48    /// [Relative motion for tablet tools](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-relative-motion)
49    /// for more details.
50    fn dy, ffi::libinput_event_tablet_tool_get_dy, f64);
51    ffi_func!(
52    /// Check if the pressure axis was updated in this event. For `TabletToolButtonEvent`s this function always returns `false`.
53    fn pressure_has_changed, ffi::libinput_event_tablet_tool_pressure_has_changed, bool);
54    ffi_func!(
55    /// Returns the current pressure being applied on the tool in use, normalized to the
56    /// range [0, 1].
57    ///
58    /// If this axis does not exist on the current tool, this function returns 0.
59    fn pressure, ffi::libinput_event_tablet_tool_get_pressure, f64);
60    ffi_func!(
61    /// Check if the z-rotation axis was updated in this event.
62    ///
63    /// For `TabletToolButtonEvent`s this function always returns `false`.
64    fn rotation_has_changed, ffi::libinput_event_tablet_tool_rotation_has_changed, bool);
65    ffi_func!(
66    /// Returns the current z rotation of the tool in degrees, clockwise from the tool's
67    /// logical neutral position.
68    ///
69    /// For tools of type `TabletToolType::Mouse` and `TabletToolType::Lens` the logical
70    /// neutral position is pointing to the current logical north of the tablet. For
71    /// tools of type `TabletToolType::Brush`, the logical neutral position is with the
72    /// buttons pointing up.
73    ///
74    /// If this axis does not exist on the current tool, this function returns 0.
75    fn rotation, ffi::libinput_event_tablet_tool_get_rotation, f64);
76    ffi_func!(
77    /// Check if the slider axis was updated in this event.
78    ///
79    /// For `TabletToolButtonEvent`s this function always returns `false`.
80    fn slider_has_changed, ffi::libinput_event_tablet_tool_slider_has_changed, bool);
81    ffi_func!(
82    /// Returns the current position of the slider on the tool, normalized to the range
83    /// [-1, 1].
84    ///
85    /// The logical zero is the neutral position of the slider, or the logical center of
86    /// the axis. This axis is available on e.g. the Wacom Airbrush.
87    ///
88    /// If this axis does not exist on the current tool, this function returns 0.
89    fn slider_position, ffi::libinput_event_tablet_tool_get_slider_position, f64);
90    ffi_func!(
91    /// Check if the tilt x axis was updated in this event.
92    ///
93    /// For `TabletToolButtonEvent`s this function always returns `false`.
94    fn tilt_x_has_changed, ffi::libinput_event_tablet_tool_tilt_x_has_changed, bool);
95    ffi_func!(
96    /// Check if the tilt y axis was updated in this event.
97    ///
98    /// For `TabletToolButtonEvent`s this function always returns `false`.
99    fn tilt_y_has_changed, ffi::libinput_event_tablet_tool_tilt_y_has_changed, bool);
100    ffi_func!(
101    /// Returns the current tilt along the X axis of the tablet's current logical
102    /// orientation, in degrees off the tablet's z axis.
103    ///
104    /// That is, if the tool is perfectly orthogonal to the tablet, the tilt angle is 0.
105    /// When the top tilts towards the logical top/left of the tablet, the x/y tilt
106    /// angles are negative, if the top tilts towards the logical bottom/right of the
107    /// tablet, the x/y tilt angles are positive.
108    ///
109    /// If this axis does not exist on the current tool, this function returns 0.
110    fn tilt_x, ffi::libinput_event_tablet_tool_get_tilt_x, f64);
111    ffi_func!(
112    /// Returns the current tilt along the Y axis of the tablet's current logical
113    /// orientation, in degrees off the tablet's z axis.
114    ///
115    /// That is, if the tool is perfectly orthogonal to the tablet, the tilt angle is 0.
116    /// When the top tilts towards the logical top/left of the tablet, the x/y tilt
117    /// angles are negative, if the top tilts towards the logical bottom/right of the
118    /// tablet, the x/y tilt angles are positive.
119    ///
120    /// If this axis does not exist on the current tool, this function returns 0.
121    fn tilt_y, ffi::libinput_event_tablet_tool_get_tilt_y, f64);
122    #[cfg(feature = "libinput_1_14")]
123    ffi_func!(
124    /// Check if the size major axis was updated in this event.
125    ///
126    /// For `TabletToolButtonEvent`s this function always returns false
127    fn size_major_has_changed, ffi::libinput_event_tablet_tool_size_major_has_changed, bool);
128    #[cfg(feature = "libinput_1_14")]
129    ffi_func!(
130    /// Check if the size minor axis was updated in this event.
131    ///
132    /// For `TabletToolButtonEvent`s this function always returns false
133    fn size_minor_has_changed, ffi::libinput_event_tablet_tool_size_minor_has_changed, bool);
134    #[cfg(feature = "libinput_1_14")]
135    ffi_func!(
136    /// Returns the current size in mm along the major axis of the touching ellipse.
137    /// This axis is not necessarily aligned with either x or y, the rotation must
138    /// be taken into account.
139    ///
140    /// Where no rotation is available on a tool, or where rotation is zero, the major
141    /// axis aligns with the y axis and the minor axis with the x axis.
142    ///
143    /// If the axis does not exist on the current tool, this function returns 0.
144    fn size_major, ffi::libinput_event_tablet_tool_get_size_major, f64);
145    #[cfg(feature = "libinput_1_14")]
146    ffi_func!(
147    /// Returns the current size in mm along the minor axis of the touching ellipse.
148    /// This axis is not necessarily aligned with either x or y, the rotation must
149    /// be taken into account.
150    ///
151    /// Where no rotation is available on a tool, or where rotation is zero, the minor
152    /// axis aligns with the y axis and the major axis with the x axis.
153    ///
154    /// If the axis does not exist on the current tool, this function returns 0.
155    fn size_minor, ffi::libinput_event_tablet_tool_get_size_minor, f64);
156    ffi_func!(
157    /// Check if the wheel axis was updated in this event.
158    ///
159    /// For `TabletToolButtonEvent`s this function always returns `false`.
160    fn wheel_has_changed, ffi::libinput_event_tablet_tool_wheel_has_changed, bool);
161    ffi_func!(
162    /// Return the delta for the wheel in degrees.
163    fn wheel_delta, ffi::libinput_event_tablet_tool_get_wheel_delta, f64);
164    ffi_func!(
165    /// Return the delta for the wheel in discrete steps (e.g. wheel clicks).
166    fn wheel_delta_discrete, ffi::libinput_event_tablet_tool_get_wheel_delta_discrete, f64);
167    ffi_func!(
168    /// Check if the x axis was updated in this event.
169    ///
170    /// For `TabletToolButtonEvent`s this function always returns `false`.
171    fn x_has_changed, ffi::libinput_event_tablet_tool_x_has_changed, bool);
172    ffi_func!(
173    /// Check if the y axis was updated in this event.
174    ///
175    /// For `TabletToolButtonEvent`s this function always returns `false`.
176    fn y_has_changed, ffi::libinput_event_tablet_tool_y_has_changed, bool);
177    ffi_func!(
178    /// Returns the X coordinate of the tablet tool, in mm from the top left corner of
179    /// the tablet in its current logical orientation.
180    ///
181    /// Use `x_transformed` for transforming the axis value into a different coordinate
182    /// space.
183    ///
184    /// If an area is defined for this device, the coordinate is in mm from the
185    /// top left corner of the area. See
186    /// [`Device::config_area_set_rectangle`](crate::Device::config_area_set_rectangle) for details.
187    ///
188    /// ## Note
189    ///
190    /// On some devices, returned value may be negative or larger than the width of the
191    /// device. See [Out-of-bounds motion events](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-bounds)
192    /// for more details.
193    fn x, ffi::libinput_event_tablet_tool_get_x, f64);
194    ffi_func!(
195    /// Returns the Y coordinate of the tablet tool, in mm from the top left corner of
196    /// the tablet in its current logical orientation.
197    ///
198    /// Use `y_transformed` for transforming the axis value into a different coordinate
199    /// space.
200    ///
201    /// If an area is defined for this device, the coordinate is in mm from the
202    /// top left corner of the area. See
203    /// [`Device::config_area_set_rectangle`](crate::Device::config_area_set_rectangle) for details.
204    ///
205    /// ## Note
206    ///
207    /// On some devices, returned value may be negative or larger than the width of the
208    /// device. See [Out-of-bounds motion events](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-bounds)
209    /// for more details.
210    fn y, ffi::libinput_event_tablet_tool_get_y, f64);
211
212    /// Return the current absolute x coordinate of the tablet tool event, transformed
213    /// to screen coordinates.
214    ///
215    /// ## Note
216    ///
217    /// This function may be called for a specific axis even if `x_has_changed` returns
218    /// `false` for that axis. libinput always includes all device axes in the event.
219    ///
220    /// On some devices, returned value may be negative or larger than the width of the
221    /// device. See [Out-of-bounds motion events](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-bounds)
222    /// for more details.
223    fn x_transformed(&self, width: u32) -> f64 {
224        unsafe { ffi::libinput_event_tablet_tool_get_x_transformed(self.as_raw_mut(), width) }
225    }
226
227    /// Return the current absolute y coordinate of the tablet tool event, transformed
228    /// to screen coordinates.
229    ///
230    /// ## Note
231    ///
232    /// This function may be called for a specific axis even if `y_has_changed` returns
233    /// `false` for that axis. libinput always includes all device axes in the event.
234    ///
235    /// On some devices, returned value may be negative or larger than the width of the
236    /// device. See [Out-of-bounds motion events](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-bounds)
237    /// for more details.
238    fn y_transformed(&self, height: u32) -> f64 {
239        unsafe { ffi::libinput_event_tablet_tool_get_y_transformed(self.as_raw_mut(), height) }
240    }
241
242    /// Returns the tool that was in use during this event.
243    ///
244    /// ## Note
245    ///
246    /// Physical tool tracking requires hardware support. If unavailable, libinput
247    /// creates one tool per type per tablet. See [Tracking unique tools](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-serial-numbers)
248    /// for more details.
249    fn tool(&self) -> TabletTool {
250        unsafe {
251            TabletTool::from_raw(
252                ffi::libinput_event_tablet_tool_get_tool(self.as_raw_mut()),
253                self.context(),
254            )
255        }
256    }
257
258    /// Convert into a general `TabletToolEvent` again
259    fn into_tablet_tool_event(self) -> TabletToolEvent
260    where
261        Self: Sized,
262    {
263        unsafe { TabletToolEvent::from_raw(self.as_raw_mut(), self.context()) }
264    }
265}
266
267impl<T: AsRaw<ffi::libinput_event_tablet_tool> + Context> TabletToolEventTrait for T {}
268
269/// An event related to a tablet tool
270#[derive(Debug, PartialEq, Eq, Hash)]
271#[non_exhaustive]
272pub enum TabletToolEvent {
273    /// One or more axes have changed state on a device with the
274    /// `DeviceCapability::TabletTool` capability.
275    ///
276    /// This event is only sent when the tool is in proximity, see
277    /// `TabletToolProximityEvent` for details.
278    ///
279    /// The proximity event contains the initial state of the axis as the tool comes into
280    /// proximity. An event of type `TabletToolAxisEvent` is only sent when an axis value
281    /// changes from this initial state. It is possible for a tool to enter and leave
282    /// proximity without sending an event of type `TabletToolAxisEvent`.
283    ///
284    /// An event of type `TabletToolAxisEvent` is sent when the tip state does not
285    /// change. See the documentation for `TabletToolTipEvent` for more details.
286    Axis(TabletToolAxisEvent),
287    /// Signals that a tool has come in or out of proximity of a device with the
288    /// `DeviceCapability::TabletTool` capability.
289    ///
290    /// Proximity events contain each of the current values for each axis, and these
291    /// values may be extracted from them in the same way they are with
292    /// `TabletToolAxisEvent` events.
293    ///
294    /// Some tools may always be in proximity. For these tools, proximity events with
295    /// `ProximityState::In` are sent only once after `DeviceAddedEvent`, and proximity
296    /// events with `ProximityState::Out` are sent only once before `DeviceRemovedEvent`.
297    ///
298    /// If the tool that comes into proximity supports x/y coordinates, libinput
299    /// guarantees that both x and y are set in the proximity event.
300    ///
301    /// When a tool goes out of proximity, the value of every axis should be assumed to
302    /// have an undefined state and any buttons that are currently held down on the
303    /// stylus are marked as released. Button release events for each button that was
304    /// held down on the stylus are sent before the proximity out event.
305    Proximity(TabletToolProximityEvent),
306    /// Signals that a tool has come in contact with the surface of a device with the
307    /// `DeviceCapability::TabletTool` capability.
308    ///
309    /// On devices without distance proximity detection, the `TabletToolTipEvent` is sent
310    /// immediately after `TabletToolProximityEvent` for the tip down event, and
311    /// immediately before for the tip up event.
312    ///
313    /// The decision when a tip touches the surface is device-dependent and may be
314    /// derived from pressure data or other means. If the tip state is changed by axes
315    /// changing state, the `TabletToolTipEvent` includes the changed axes and no
316    /// additional axis event is sent for this state change. In other words, a caller
317    /// must look at both `TabletToolAxisEvent` and `TabletToolTipEvent` events to know
318    /// the current state of the axes.
319    ///
320    /// If a button state change occurs at the same time as a tip state change, the order
321    /// of events is device-dependent.
322    Tip(TabletToolTipEvent),
323    /// Signals that a tool has changed a logical button state on a device with the
324    /// `DeviceCapability::TabletTool` capability.
325    ///
326    /// Button state changes occur on their own and do not include axis state changes. If
327    /// button and axis state changes occur within the same logical hardware event, the
328    /// order of the `TabletToolButtonEvent` and `TabletToolAxisEvent` is device-specific.
329    ///
330    /// This event is not to be confused with the button events emitted by the tablet
331    /// pad. See `TabletPadButtonEvent`.
332    Button(TabletToolButtonEvent),
333}
334
335impl EventTrait for TabletToolEvent {
336    #[doc(hidden)]
337    fn as_raw_event(&self) -> *mut ffi::libinput_event {
338        match self {
339            TabletToolEvent::Axis(event) => event.as_raw_event(),
340            TabletToolEvent::Proximity(event) => event.as_raw_event(),
341            TabletToolEvent::Tip(event) => event.as_raw_event(),
342            TabletToolEvent::Button(event) => event.as_raw_event(),
343        }
344    }
345}
346
347impl FromRaw<ffi::libinput_event_tablet_tool> for TabletToolEvent {
348    unsafe fn try_from_raw(
349        event: *mut ffi::libinput_event_tablet_tool,
350        context: &Libinput,
351    ) -> Option<Self> {
352        let base = ffi::libinput_event_tablet_tool_get_base_event(event);
353        match ffi::libinput_event_get_type(base) {
354            ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_TOOL_AXIS => Some(
355                TabletToolEvent::Axis(TabletToolAxisEvent::try_from_raw(event, context)?),
356            ),
357            ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY => Some(
358                TabletToolEvent::Proximity(TabletToolProximityEvent::try_from_raw(event, context)?),
359            ),
360            ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_TOOL_TIP => Some(TabletToolEvent::Tip(
361                TabletToolTipEvent::try_from_raw(event, context)?,
362            )),
363            ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_TOOL_BUTTON => Some(
364                TabletToolEvent::Button(TabletToolButtonEvent::try_from_raw(event, context)?),
365            ),
366            _ => None,
367        }
368    }
369    unsafe fn from_raw(event: *mut ffi::libinput_event_tablet_tool, context: &Libinput) -> Self {
370        Self::try_from_raw(event, context).expect("Unknown tablet tool event type")
371    }
372}
373
374impl AsRaw<ffi::libinput_event_tablet_tool> for TabletToolEvent {
375    fn as_raw(&self) -> *const ffi::libinput_event_tablet_tool {
376        match self {
377            TabletToolEvent::Axis(event) => event.as_raw(),
378            TabletToolEvent::Proximity(event) => event.as_raw(),
379            TabletToolEvent::Tip(event) => event.as_raw(),
380            TabletToolEvent::Button(event) => event.as_raw(),
381        }
382    }
383}
384
385impl Context for TabletToolEvent {
386    fn context(&self) -> &Libinput {
387        match self {
388            TabletToolEvent::Axis(event) => event.context(),
389            TabletToolEvent::Proximity(event) => event.context(),
390            TabletToolEvent::Tip(event) => event.context(),
391            TabletToolEvent::Button(event) => event.context(),
392        }
393    }
394}
395
396ffi_event_struct! {
397    /// One or more axes have changed state on a device with the
398    /// `DeviceCapability::TabletTool` capability.
399    ///
400    /// This event is only sent when the tool is in proximity, see
401    /// `TabletToolProximityEvent` for details.
402    ///
403    /// The proximity event contains the initial state of the axis as the tool comes into
404    /// proximity. An event of type `TabletToolAxisEvent` is only sent when an axis value
405    /// changes from this initial state. It is possible for a tool to enter and leave
406    /// proximity without sending an event of type `TabletToolAxisEvent`.
407    ///
408    /// An event of type `TabletToolAxisEvent` is sent when the tip state does not
409    /// change. See the documentation for `TabletToolTipEvent` for more details.
410    struct TabletToolAxisEvent, ffi::libinput_event_tablet_tool, ffi::libinput_event_tablet_tool_get_base_event
411}
412
413/// The state of proximity for a tool on a device.
414///
415/// The proximity of a tool is a binary state signalling whether the tool is within a
416/// detectable distance of the tablet device. A tool that is out of proximity cannot
417/// generate events.
418///
419/// On some hardware a tool goes out of proximity when it ceases to touch the surface. On /// other hardware, the tool is still detectable within a short distance (a few cm) off
420/// the surface.
421#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
422pub enum ProximityState {
423    /// Out of proximity
424    Out,
425    /// In proximity
426    In,
427}
428
429ffi_event_struct! {
430    /// Signals that a tool has come in or out of proximity of a device with the
431    /// `DeviceCapability::TabletTool` capability.
432    ///
433    /// Proximity events contain each of the current values for each axis, and these
434    /// values may be extracted from them in the same way they are with
435    /// `TabletToolAxisEvent` events.
436    ///
437    /// Some tools may always be in proximity. For these tools, proximity events with
438    /// `ProximityState::In` are sent only once after `DeviceAddedEvent`, and proximity
439    /// events with `ProximityState::Out` are sent only once before `DeviceRemovedEvent`.
440    ///
441    /// If the tool that comes into proximity supports x/y coordinates, libinput
442    /// guarantees that both x and y are set in the proximity event.
443    ///
444    /// When a tool goes out of proximity, the value of every axis should be assumed to
445    /// have an undefined state and any buttons that are currently held down on the
446    /// stylus are marked as released. Button release events for each button that was
447    /// held down on the stylus are sent before the proximity out event.
448    struct TabletToolProximityEvent, ffi::libinput_event_tablet_tool, ffi::libinput_event_tablet_tool_get_base_event
449}
450
451impl TabletToolProximityEvent {
452    /// Returns the new proximity state of a tool from a proximity event.
453    ///
454    /// Used to check whether or not a tool came in or out of proximity during an
455    /// `TabletToolProximityEvent`.
456    ///
457    /// See [Handling of proximity events](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-fake-proximity)
458    /// for recommendations on proximity handling.
459    pub fn proximity_state(&self) -> ProximityState {
460        match unsafe { ffi::libinput_event_tablet_tool_get_proximity_state(self.as_raw_mut()) } {
461            ffi::libinput_tablet_tool_proximity_state_LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT => {
462                ProximityState::Out
463            }
464            ffi::libinput_tablet_tool_proximity_state_LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN => {
465                ProximityState::In
466            }
467            _ => panic!("libinput returned invalid 'libinput_tablet_tool_proximity_state'"),
468        }
469    }
470}
471
472/// The tip contact state for a tool on a device.
473///
474/// The tip contact state of a tool is a binary state signalling whether the tool is
475/// touching the surface of the tablet device.
476#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
477pub enum TipState {
478    /// Not touching the surface
479    Up,
480    /// Touching the surface
481    Down,
482}
483
484ffi_event_struct! {
485    /// Signals that a tool has come in contact with the surface of a device with the
486    /// `DeviceCapability::TabletTool` capability.
487    ///
488    /// On devices without distance proximity detection, the `TabletToolTipEvent` is sent
489    /// immediately after `TabletToolProximityEvent` for the tip down event, and
490    /// immediately before for the tip up event.
491    ///
492    /// The decision when a tip touches the surface is device-dependent and may be
493    /// derived from pressure data or other means. If the tip state is changed by axes
494    /// changing state, the `TabletToolTipEvent` includes the changed axes and no
495    /// additional axis event is sent for this state change. In other words, a caller
496    /// must look at both `TabletToolAxisEvent` and `TabletToolTipEvent` events to know
497    /// the current state of the axes.
498    ///
499    /// If a button state change occurs at the same time as a tip state change, the order
500    /// of events is device-dependent.
501    struct TabletToolTipEvent, ffi::libinput_event_tablet_tool, ffi::libinput_event_tablet_tool_get_base_event
502}
503
504impl TabletToolTipEvent {
505    /// Returns the new tip state of a tool from a tip event.
506    ///
507    /// Used to check whether or not a tool came in contact with the tablet surface or
508    /// left contact with the tablet surface during an `TabletToolTipEvent`.
509    pub fn tip_state(&self) -> TipState {
510        match unsafe { ffi::libinput_event_tablet_tool_get_tip_state(self.as_raw_mut()) } {
511            ffi::libinput_tablet_tool_tip_state_LIBINPUT_TABLET_TOOL_TIP_UP => TipState::Up,
512            ffi::libinput_tablet_tool_tip_state_LIBINPUT_TABLET_TOOL_TIP_DOWN => TipState::Down,
513            _ => panic!("libinput returned invalid 'libinput_tablet_tool_top_state'"),
514        }
515    }
516}
517
518ffi_event_struct! {
519    /// Signals that a tool has changed a logical button state on a device with the
520    /// `DeviceCapability::TabletTool` capability.
521    ///
522    /// Button state changes occur on their own and do not include axis state changes. If
523    /// button and axis state changes occur within the same logical hardware event, the
524    /// order of the `TabletToolButtonEvent` and `TabletToolAxisEvent` is device-specific.
525    ///
526    /// This event is not to be confused with the button events emitted by the tablet
527    /// pad. See `TabletPadButtonEvent`.
528    struct TabletToolButtonEvent, ffi::libinput_event_tablet_tool, ffi::libinput_event_tablet_tool_get_base_event
529}
530
531impl TabletToolButtonEvent {
532    ffi_func!(
533    /// Return the button that triggered this event.
534    pub fn button, ffi::libinput_event_tablet_tool_get_button, u32);
535    ffi_func!(
536    /// For the button of a `TabletToolButtonEvent`, return the total number of buttons
537    /// pressed on all devices on the associated seat after the the event was triggered.
538    pub fn seat_button_count, ffi::libinput_event_tablet_tool_get_seat_button_count, u32);
539
540    /// Return the button state of the event.
541    pub fn button_state(&self) -> ButtonState {
542        match unsafe { ffi::libinput_event_tablet_tool_get_button_state(self.as_raw_mut()) } {
543            ffi::libinput_button_state_LIBINPUT_BUTTON_STATE_PRESSED => ButtonState::Pressed,
544            ffi::libinput_button_state_LIBINPUT_BUTTON_STATE_RELEASED => ButtonState::Released,
545            _ => panic!("libinput returned invalid 'libinput_button_state'"),
546        }
547    }
548}