input/event/tablet_tool/tool.rs
1use crate::{ffi, AsRaw, FromRaw};
2#[cfg(feature = "libinput_1_26")]
3use crate::{DeviceConfigError, DeviceConfigResult};
4
5/// Available tool types for a device with the `DeviceCapability::TabletTool` capability.
6///
7/// The tool type defines the default usage of the tool as advertised by the
8/// manufacturer. Multiple different physical tools may share the same tool type, e.g. a
9/// Wacom Classic Pen, Wacom Pro Pen and a Wacom Grip Pen are all of type
10/// `TabletToolType::Pen`. Use `TabletTool::tool_id` to get a specific model where
11/// applicable.
12///
13/// Note that on some device, the eraser tool is on the tail end of a pen device. On
14/// other devices, e.g. MS Surface 3, the eraser is the pen tip while a button is held
15/// down.
16///
17/// ## Note
18///
19/// The `TabletToolType` can only describe the default physical type of the device. For
20/// devices with adjustable physical properties the tool type remains the same, i.e.
21/// putting a Wacom stroke nib into a classic pen leaves the tool type as
22/// `TabletToolType::Pen`.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24#[non_exhaustive]
25pub enum TabletToolType {
26 /// A generic pen.
27 Pen,
28 /// Eraser.
29 Eraser,
30 /// A paintbrush-like tool.
31 Brush,
32 /// Physical drawing tool, e.g. Wacom Inking Pen
33 Pencil,
34 /// An airbrush-like tool.
35 Airbrush,
36 /// A mouse bound to the tablet.
37 Mouse,
38 /// A mouse tool with a lens.
39 Lens,
40 /// A rotary device with positional and rotation data
41 #[cfg(feature = "libinput_1_14")]
42 Totem,
43}
44
45ffi_ref_struct! {
46 /// An object representing a tool being used by a device with the
47 /// `DeviceCapability::TabletTool` capability.
48 ///
49 /// Tablet events generated by such a device are bound to a specific tool rather than
50 /// coming from the device directly. Depending on the hardware it is possible to track
51 /// the same physical tool across multiple `Device`s, see
52 /// [Tracking unique tools](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-serial-numbers).
53 struct TabletTool, ffi::libinput_tablet_tool, ffi::libinput_tablet_tool_ref, ffi::libinput_tablet_tool_unref
54}
55
56impl TabletTool {
57 ffi_func!(
58 /// Return the serial number of a tool.
59 ///
60 /// If the tool does not report a serial number, this function returns zero.
61 /// See [Tracking unique tools](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-serial-numbers) for details.
62 pub fn serial, ffi::libinput_tablet_tool_get_serial, u64);
63 ffi_func!(
64 /// Return the tool ID for a tool object.
65 ///
66 /// If nonzero, this number identifies the specific type of the tool with more
67 /// precision than the type returned in `tool_type`,
68 /// see [Vendor-specific tablet tool types](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-tool-types).
69 /// Not all tablets support a tool ID.
70 ///
71 /// Tablets known to support tool IDs include the Wacom Intuos 3, 4, 5, Wacom Cintiq
72 /// and Wacom Intuos Pro series.
73 pub fn tool_id, ffi::libinput_tablet_tool_get_tool_id, u64);
74
75 /// Return the tool type for a tool object,
76 /// see [Vendor-specific tablet tool types](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-tool-types)
77 /// for details.
78 ///
79 /// A return value of `None` means the tool type is not known.
80 pub fn tool_type(&self) -> Option<TabletToolType> {
81 match unsafe { ffi::libinput_tablet_tool_get_type(self.as_raw_mut()) } {
82 ffi::libinput_tablet_tool_type_LIBINPUT_TABLET_TOOL_TYPE_PEN => {
83 Some(TabletToolType::Pen)
84 }
85 ffi::libinput_tablet_tool_type_LIBINPUT_TABLET_TOOL_TYPE_ERASER => {
86 Some(TabletToolType::Eraser)
87 }
88 ffi::libinput_tablet_tool_type_LIBINPUT_TABLET_TOOL_TYPE_BRUSH => {
89 Some(TabletToolType::Brush)
90 }
91 ffi::libinput_tablet_tool_type_LIBINPUT_TABLET_TOOL_TYPE_PENCIL => {
92 Some(TabletToolType::Pencil)
93 }
94 ffi::libinput_tablet_tool_type_LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH => {
95 Some(TabletToolType::Airbrush)
96 }
97 ffi::libinput_tablet_tool_type_LIBINPUT_TABLET_TOOL_TYPE_MOUSE => {
98 Some(TabletToolType::Mouse)
99 }
100 ffi::libinput_tablet_tool_type_LIBINPUT_TABLET_TOOL_TYPE_LENS => {
101 Some(TabletToolType::Lens)
102 }
103 #[cfg(feature = "libinput_1_14")]
104 ffi::libinput_tablet_tool_type_LIBINPUT_TABLET_TOOL_TYPE_TOTEM => {
105 Some(TabletToolType::Totem)
106 }
107 _x => {
108 #[cfg(feature = "log")]
109 log::warn!("Unknown `TabletToolType` returned by libinput: {}", _x);
110 None
111 }
112 }
113 }
114
115 /// Check if a tablet tool has a button with the passed-in code (see linux/input.h).
116 pub fn has_button(&self, button: u32) -> bool {
117 unsafe { ffi::libinput_tablet_tool_has_button(self.as_raw_mut(), button) != 0 }
118 }
119
120 ffi_func!(
121 /// Return whether the tablet tool supports distance.
122 pub fn has_distance, ffi::libinput_tablet_tool_has_distance, bool);
123 ffi_func!(
124 /// Return whether the tablet tool supports pressure.
125 pub fn has_pressure, ffi::libinput_tablet_tool_has_pressure, bool);
126 ffi_func!(
127 /// Return whether the tablet tool supports z-rotation.v
128 pub fn has_rotation, ffi::libinput_tablet_tool_has_rotation, bool);
129 ffi_func!(
130 /// Return whether the tablet tool has a slider axis.
131 pub fn has_slider, ffi::libinput_tablet_tool_has_slider, bool);
132 ffi_func!(
133 /// Return whether the tablet tool supports tilt.
134 pub fn has_tilt, ffi::libinput_tablet_tool_has_tilt, bool);
135 ffi_func!(
136 /// Return whether the tablet tool has a relative wheel.
137 pub fn has_wheel, ffi::libinput_tablet_tool_has_wheel, bool);
138 ffi_func!(
139 /// Returns `true` if the physical tool can be uniquely identified by libinput, or
140 /// `false` otherwise.
141 ///
142 /// If a tool can be uniquely identified, keeping a reference to the tool allows
143 /// tracking the tool across proximity out sequences and across compatible tablets.
144 /// See [Tracking unique tools](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-serial-numbers)
145 /// for more details.
146 pub fn is_unique, ffi::libinput_tablet_tool_is_unique, bool);
147 #[cfg(feature = "libinput_1_14")]
148 ffi_func!(
149 /// Returns whether the tablet tool has a ellipsis major and minor.
150 ///
151 /// Where the underlying hardware only supports one of either major or minor,
152 /// libinput emulated the other axis as a cicular contact, i.e. major == minor
153 /// for all values of major.
154 pub fn tablet_tool_has_size, ffi::libinput_tablet_tool_has_size, bool);
155
156 /// Set the pressure range for this tablet tool.
157 ///
158 /// This maps the given logical pressure range into the available hardware
159 /// pressure range so that a hardware pressure of the given minimum value
160 /// maps into a logical pressure of 0.0 (as returned by
161 /// [`TabletToolEventTrait::get_pressure`](crate::event::tablet_tool::TabletToolEventTrait::pressure))
162 /// and the hardware pressure of the given maximum value is mapped into
163 /// the logical pressure of 1.0 (as returned by
164 /// [`TabletToolEventTrait::get_pressure`](crate::event::tablet_tool::TabletToolEventTrait::pressure))
165 ///
166 /// The minimum value must be less than the maximum value, libinput may
167 /// require the values to have a specific distance to each other,
168 /// i.e. that (maximium - minimum > N) for an implementation-defined value of N.
169 #[cfg(feature = "libinput_1_26")]
170 pub fn config_pressure_range_set(&self, minimum: f64, maximum: f64) -> DeviceConfigResult {
171 match unsafe {
172 ffi::libinput_tablet_tool_config_pressure_range_set(self.as_raw_mut(), minimum, maximum)
173 } {
174 ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()),
175 ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => {
176 Err(DeviceConfigError::Unsupported)
177 }
178 ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => {
179 Err(DeviceConfigError::Invalid)
180 }
181 _ => panic!("libinput returned invalid 'libinput_config_status'"),
182 }
183 }
184
185 #[cfg(feature = "libinput_1_26")]
186 ffi_func!(
187 /// Check if a tablet tool can have a custom pressure range.
188 pub fn config_pressure_range_is_available, ffi::libinput_tablet_tool_config_pressure_range_is_available, bool);
189
190 #[cfg(feature = "libinput_1_26")]
191 ffi_func!(
192 /// Get the minimum pressure value for this tablet tool, normalized to the
193 /// range [0.0, 1.0] of the available hardware pressure.
194 ///
195 /// If the tool does not support pressure range configuration, the return
196 /// value of this function is always 0.0.
197 pub fn config_pressure_range_get_minimum, ffi::libinput_tablet_tool_config_pressure_range_get_minimum, f64);
198
199 #[cfg(feature = "libinput_1_26")]
200 ffi_func!(
201 /// Get the maximum pressure value for this tablet tool, normalized to the range [0.0, 1.0] of the available hardware pressure.
202 ///
203 /// If the tool does not support pressure range configuration, the return value of this function is always 1.0.
204 pub fn config_pressure_range_get_maximum, ffi::libinput_tablet_tool_config_pressure_range_get_maximum, f64);
205
206 #[cfg(feature = "libinput_1_26")]
207 ffi_func!(
208 /// Get the minimum pressure value for this tablet tool, normalized to the range [0.0, 1.0] of the available hardware pressure.
209 ///
210 /// If the tool does not support pressure range configuration, the return value of this function is always 0.0.
211 pub fn config_pressure_range_get_default_minimum, ffi::libinput_tablet_tool_config_pressure_range_get_default_minimum, f64);
212
213 #[cfg(feature = "libinput_1_26")]
214 ffi_func!(
215 /// Get the maximum pressure value for this tablet tool, normalized to the range [0.0, 1.0] of the available hardware pressure.
216 ///
217 /// If the tool does not support pressure range configuration, the return value of this function is always 1.0.
218 pub fn config_pressure_range_get_default_maximum, ffi::libinput_tablet_tool_config_pressure_range_get_default_maximum, f64);
219}
220
221/// Used to change tablet tool eraser mode using [`TabletTool::config_eraser_button_set_mode`]
222#[cfg(feature = "libinput_1_29")]
223#[doc(alias = "libinput_config_eraser_button_mode")]
224#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
225#[non_exhaustive]
226pub enum EraserButtonMode {
227 /// The eraser button on the tool sends a button event instead.
228 /// If this tool comes into proximity as an eraser,
229 /// a button event on the pen is emulated instead.
230 ///
231 /// See [`TabletTool::config_eraser_button_set_mode`] for details.
232 Button,
233 /// Use the default hardware behavior of the tool.
234 /// libinput does not modify the behavior of the eraser button (if any).
235 Default,
236}
237
238#[cfg(feature = "libinput_1_29")]
239impl EraserButtonMode {
240 fn from_ffi(v: ffi::libinput_config_eraser_button_mode) -> Self {
241 match v {
242 ffi::libinput_config_eraser_button_mode_LIBINPUT_CONFIG_ERASER_BUTTON_BUTTON => {
243 Self::Button
244 }
245 ffi::libinput_config_eraser_button_mode_LIBINPUT_CONFIG_ERASER_BUTTON_DEFAULT => {
246 Self::Default
247 }
248 _ => unreachable!(),
249 }
250 }
251
252 fn as_ffi(&self) -> ffi::libinput_config_eraser_button_mode {
253 match self {
254 EraserButtonMode::Button => {
255 ffi::libinput_config_eraser_button_mode_LIBINPUT_CONFIG_ERASER_BUTTON_BUTTON
256 }
257 EraserButtonMode::Default => {
258 ffi::libinput_config_eraser_button_mode_LIBINPUT_CONFIG_ERASER_BUTTON_DEFAULT
259 }
260 }
261 }
262}
263
264#[cfg(feature = "libinput_1_29")]
265impl TabletTool {
266 /// Get the button configured to emulate an eraser for this tool.
267 #[doc(alias = "libinput_tablet_tool_config_eraser_button_get_button")]
268 pub fn config_eraser_button_get_button(&self) -> Option<u32> {
269 let btn = unsafe {
270 ffi::libinput_tablet_tool_config_eraser_button_get_button(self.as_raw_mut()) as u32
271 };
272 (btn != 0).then_some(btn)
273 }
274
275 /// Get the default button configured to emulate an eraser for this tool.
276 #[doc(alias = "libinput_tablet_tool_config_eraser_button_get_default_button")]
277 pub fn config_eraser_button_get_default_button(&self) -> Option<u32> {
278 let btn = unsafe {
279 ffi::libinput_tablet_tool_config_eraser_button_get_default_button(self.as_raw_mut())
280 as u32
281 };
282 (btn != 0).then_some(btn)
283 }
284
285 /// Get the mode for the eraser button.
286 #[doc(alias = "libinput_tablet_tool_config_eraser_button_get_mode")]
287 pub fn config_eraser_button_get_mode(&self) -> EraserButtonMode {
288 EraserButtonMode::from_ffi(unsafe {
289 ffi::libinput_tablet_tool_config_eraser_button_get_mode(self.as_raw_mut())
290 })
291 }
292
293 /// Get the default mode for the eraser button.
294 #[doc(alias = "libinput_tablet_tool_config_eraser_button_get_default_mode")]
295 pub fn config_eraser_button_get_default_mode(&self) -> EraserButtonMode {
296 EraserButtonMode::from_ffi(unsafe {
297 ffi::libinput_tablet_tool_config_eraser_button_get_default_mode(self.as_raw_mut())
298 })
299 }
300
301 ffi_func!(
302 /// Check if a tool can change the behavior of or to a firmware eraser button.
303 ///
304 /// returns: Non-zero if the device can be set to change to an eraser on button
305 #[doc(alias = "libinput_tablet_tool_config_eraser_button_get_modes")]
306 pub fn config_eraser_button_get_modes, ffi::libinput_tablet_tool_config_eraser_button_get_modes, u32);
307
308 /// Set a button to be the eraser button for this tool.
309 /// This configuration has no effect unless the caller also sets
310 /// the eraser mode to [`ConfigEraserButtonMode::Button`] via
311 /// [`TabletTool::config_eraser_button_set_mode()`].
312 #[doc(alias = "libinput_tablet_tool_config_eraser_button_set_button")]
313 pub fn config_eraser_button_set_button(&self, button: u32) -> DeviceConfigResult {
314 DeviceConfigError::from_ffi(unsafe {
315 ffi::libinput_tablet_tool_config_eraser_button_set_button(self.as_raw_mut(), button)
316 })
317 }
318
319 /// Change the eraser button behavior on a tool.
320 #[doc(alias = "libinput_tablet_tool_config_eraser_button_set_mode")]
321 pub fn config_eraser_button_set_mode(&self, mode: EraserButtonMode) -> DeviceConfigResult {
322 DeviceConfigError::from_ffi(unsafe {
323 ffi::libinput_tablet_tool_config_eraser_button_set_mode(
324 self.as_raw_mut(),
325 mode.as_ffi(),
326 )
327 })
328 }
329}