1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
//! Tablet tool event types

use super::EventTrait;
use {AsRaw, FromRaw};
pub use event::pointer::ButtonState;
use ffi;

mod tool;
pub use self::tool::*;

/// Common functions all TabletTool-Events implement.
pub trait TabletToolEventTrait: AsRaw<ffi::libinput_event_tablet_tool> {
    ffi_func!(
    /// The event time for this event
    fn time, ffi::libinput_event_tablet_tool_get_time, u32);
    ffi_func!(
    /// The event time for this event in microseconds
    fn time_usec, ffi::libinput_event_tablet_tool_get_time_usec, u64);
    ffi_func!(
    /// Check if the distance axis was updated in this event.
    ///
    /// For `TabletToolProximityEvent`s this function always returns `true`. For
    /// `TabletToolButtonEvent`s this function always returns `false`.
    fn distance_has_changed, ffi::libinput_event_tablet_tool_distance_has_changed, bool);
    ffi_func!(
    /// Returns the current distance from the tablet's sensor, normalized to the range
    /// [0, 1].
    ///
    /// If this axis does not exist on the current tool, this function returns 0.
    fn distance, ffi::libinput_event_tablet_tool_get_distance, f64);
    ffi_func!(
    /// Return the delta between the last event and the current event.
    ///
    /// If the tool employs pointer acceleration, the delta returned by this function is
    /// the accelerated delta.
    ///
    /// This value is in screen coordinate space, the delta is to be interpreted like
    /// the return value of `PointerMotionEvent::dx`. See
    /// [Relative motion for tablet tools](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-relative-motion)
    /// for more details.
    fn dx, ffi::libinput_event_tablet_tool_get_dx, f64);
    ffi_func!(
    /// Return the delta between the last event and the current event.
    ///
    /// If the tool employs pointer acceleration, the delta returned by this function is
    /// the accelerated delta.
    ///
    /// This value is in screen coordinate space, the delta is to be interpreted like
    /// the return value of `PointerMotionEvent::dy`. See
    /// [Relative motion for tablet tools](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-relative-motion)
    /// for more details.
    fn dy, ffi::libinput_event_tablet_tool_get_dy, f64);
    ffi_func!(
    /// Check if the pressure axis was updated in this event. For `TabletToolButtonEvent`s this function always returns `false`.
    fn pressure_has_changed, ffi::libinput_event_tablet_tool_pressure_has_changed, bool);
    ffi_func!(
    /// Returns the current pressure being applied on the tool in use, normalized to the
    /// range [0, 1].
    ///
    /// If this axis does not exist on the current tool, this function returns 0.
    fn pressure, ffi::libinput_event_tablet_tool_get_pressure, f64);
    ffi_func!(
    /// Check if the z-rotation axis was updated in this event.
    ///
    /// For `TabletToolButtonEvent`s this function always returns `false`.
    fn rotation_has_changed, ffi::libinput_event_tablet_tool_rotation_has_changed, bool);
    ffi_func!(
    /// Returns the current z rotation of the tool in degrees, clockwise from the tool's
    /// logical neutral position.
    ///
    /// For tools of type `TabletToolType::Mouse` and `TabletToolType::Lens` the logical
    /// neutral position is pointing to the current logical north of the tablet. For
    /// tools of type `TabletToolType::Brush`, the logical neutral position is with the
    /// buttons pointing up.
    ///
    /// If this axis does not exist on the current tool, this function returns 0.
    fn rotation, ffi::libinput_event_tablet_tool_get_rotation, f64);
    ffi_func!(
    /// Check if the slider axis was updated in this event.
    ///
    /// For `TabletToolButtonEvent`s this function always returns `false`.
    fn slider_has_changed, ffi::libinput_event_tablet_tool_slider_has_changed, bool);
    ffi_func!(
    /// Returns the current position of the slider on the tool, normalized to the range
    /// [-1, 1].
    ///
    /// The logical zero is the neutral position of the slider, or the logical center of
    /// the axis. This axis is available on e.g. the Wacom Airbrush.
    ///
    /// If this axis does not exist on the current tool, this function returns 0.
    fn slider_position, ffi::libinput_event_tablet_tool_get_slider_position, f64);
    ffi_func!(
    /// Check if the tilt x axis was updated in this event.
    ///
    /// For `TabletToolButtonEvent`s this function always returns `false`.
    fn tilt_x_has_changed, ffi::libinput_event_tablet_tool_tilt_x_has_changed, bool);
    ffi_func!(
    /// Check if the tilt y axis was updated in this event.
    ///
    /// For `TabletToolButtonEvent`s this function always returns `false`.
    fn tilt_y_has_changed, ffi::libinput_event_tablet_tool_tilt_y_has_changed, bool);
    ffi_func!(
    /// Returns the current tilt along the X axis of the tablet's current logical
    /// orientation, in degrees off the tablet's z axis.
    ///
    /// That is, if the tool is perfectly orthogonal to the tablet, the tilt angle is 0.
    /// When the top tilts towards the logical top/left of the tablet, the x/y tilt
    /// angles are negative, if the top tilts towards the logical bottom/right of the
    /// tablet, the x/y tilt angles are positive.
    ///
    /// If this axis does not exist on the current tool, this function returns 0.
    fn tilt_x, ffi::libinput_event_tablet_tool_get_tilt_x, f64);
    ffi_func!(
    /// Returns the current tilt along the Y axis of the tablet's current logical
    /// orientation, in degrees off the tablet's z axis.
    ///
    /// That is, if the tool is perfectly orthogonal to the tablet, the tilt angle is 0.
    /// When the top tilts towards the logical top/left of the tablet, the x/y tilt
    /// angles are negative, if the top tilts towards the logical bottom/right of the
    /// tablet, the x/y tilt angles are positive.
    ///
    /// If this axis does not exist on the current tool, this function returns 0.
    fn tilt_y, ffi::libinput_event_tablet_tool_get_tilt_y, f64);
    ffi_func!(
    /// Check if the wheel axis was updated in this event.
    ///
    /// For `TabletToolButtonEvent`s this function always returns `false`.
    fn wheel_has_changed, ffi::libinput_event_tablet_tool_wheel_has_changed, bool);
    ffi_func!(
    /// Return the delta for the wheel in degrees.
    fn wheel_delta, ffi::libinput_event_tablet_tool_get_wheel_delta, f64);
    ffi_func!(
    /// Return the delta for the wheel in discrete steps (e.g. wheel clicks).
    fn wheel_delta_discrete, ffi::libinput_event_tablet_tool_get_wheel_delta_discrete, f64);
    ffi_func!(
    /// Check if the x axis was updated in this event.
    ///
    /// For `TabletToolButtonEvent`s this function always returns `false`.
    fn x_has_changed, ffi::libinput_event_tablet_tool_x_has_changed, bool);
    ffi_func!(
    /// Check if the y axis was updated in this event.
    ///
    /// For `TabletToolButtonEvent`s this function always returns `false`.
    fn y_has_changed, ffi::libinput_event_tablet_tool_y_has_changed, bool);
    ffi_func!(
    /// Returns the X coordinate of the tablet tool, in mm from the top left corner of
    /// the tablet in its current logical orientation.
    ///
    /// Use `x_transformed` for transforming the axis value into a different coordinate
    /// space.
    ///
    /// ## Note
    ///
    /// On some devices, returned value may be negative or larger than the width of the
    /// device. See [Out-of-bounds motion events](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-bounds)
    /// for more details.
    fn x, ffi::libinput_event_tablet_tool_get_x, f64);
    ffi_func!(
    /// Returns the Y coordinate of the tablet tool, in mm from the top left corner of
    /// the tablet in its current logical orientation.
    ///
    /// Use `y_transformed` for transforming the axis value into a different coordinate
    /// space.
    ///
    /// ## Note
    ///
    /// On some devices, returned value may be negative or larger than the width of the
    /// device. See [Out-of-bounds motion events](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-bounds)
    /// for more details.
    fn y, ffi::libinput_event_tablet_tool_get_y, f64);

    /// Return the current absolute x coordinate of the tablet tool event, transformed
    /// to screen coordinates.
    ///
    /// ## Note
    ///
    /// This function may be called for a specific axis even if `x_has_changed` returns
    /// `false` for that axis. libinput always includes all device axes in the event.
    ///
    /// On some devices, returned value may be negative or larger than the width of the
    /// device. See [Out-of-bounds motion events](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-bounds)
    /// for more details.
    fn x_transformed(&self, width: u32) -> f64 {
        unsafe { ffi::libinput_event_tablet_tool_get_x_transformed(self.as_raw_mut(), width) }
    }

    /// Return the current absolute y coordinate of the tablet tool event, transformed
    /// to screen coordinates.
    ///
    /// ## Note
    ///
    /// This function may be called for a specific axis even if `y_has_changed` returns
    /// `false` for that axis. libinput always includes all device axes in the event.
    ///
    /// On some devices, returned value may be negative or larger than the width of the
    /// device. See [Out-of-bounds motion events](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-bounds)
    /// for more details.
    fn y_transformed(&self, height: u32) -> f64 {
        unsafe { ffi::libinput_event_tablet_tool_get_x_transformed(self.as_raw_mut(), height) }
    }

    /// Returns the tool that was in use during this event.
    ///
    /// ## Note
    ///
    /// Physical tool tracking requires hardware support. If unavailable, libinput
    /// creates one tool per type per tablet. See [Tracking unique tools](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-serial-numbers)
    /// for more details.
    fn tool(&self) -> TabletTool {
        unsafe { TabletTool::from_raw(ffi::libinput_event_tablet_tool_get_tool(self.as_raw_mut())) }
    }

    /// Convert into a general `TabletToolEvent` again
    fn into_tablet_tool_event(self) -> TabletToolEvent
        where Self: Sized
    {
        unsafe { TabletToolEvent::from_raw(self.as_raw_mut()) }
    }
}

impl<T: AsRaw<ffi::libinput_event_tablet_tool>> TabletToolEventTrait for T {}

/// An event related to a tablet tool
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum TabletToolEvent {
    /// One or more axes have changed state on a device with the
    /// `DeviceCapability::TabletTool` capability.
    ///
    /// This event is only sent when the tool is in proximity, see
    /// `TabletToolProximityEvent` for details.
    ///
    /// The proximity event contains the initial state of the axis as the tool comes into
    /// proximity. An event of type `TabletToolAxisEvent` is only sent when an axis value
    /// changes from this initial state. It is possible for a tool to enter and leave
    /// proximity without sending an event of type `TabletToolAxisEvent`.
    ///
    /// An event of type `TabletToolAxisEvent` is sent when the tip state does not
    /// change. See the documentation for `TabletToolTipEvent` for more details.
    Axis(TabletToolAxisEvent),
    /// Signals that a tool has come in or out of proximity of a device with the
    /// `DeviceCapability::TabletTool` capability.
    ///
    /// Proximity events contain each of the current values for each axis, and these
    /// values may be extracted from them in the same way they are with
    /// `TabletToolAxisEvent` events.
    ///
    /// Some tools may always be in proximity. For these tools, proximity events with
    /// `ProximityState::In` are sent only once after `DeviceAddedEvent`, and proximity
    /// events with `ProximityState::Out` are sent only once before `DeviceRemovedEvent`.
    ///
    /// If the tool that comes into proximity supports x/y coordinates, libinput
    /// guarantees that both x and y are set in the proximity event.
    ///
    /// When a tool goes out of proximity, the value of every axis should be assumed to
    /// have an undefined state and any buttons that are currently held down on the
    /// stylus are marked as released. Button release events for each button that was
    /// held down on the stylus are sent before the proximity out event.
    Proximity(TabletToolProximityEvent),
    /// Signals that a tool has come in contact with the surface of a device with the
    /// `DeviceCapability::TabletTool` capability.
    ///
    /// On devices without distance proximity detection, the `TabletToolTipEvent` is sent
    /// immediately after `TabletToolProximityEvent` for the tip down event, and
    /// immediately before for the tip up event.
    ///
    /// The decision when a tip touches the surface is device-dependent and may be
    /// derived from pressure data or other means. If the tip state is changed by axes
    /// changing state, the `TabletToolTipEvent` includes the changed axes and no
    /// additional axis event is sent for this state change. In other words, a caller
    /// must look at both `TabletToolAxisEvent` and `TabletToolTipEvent` events to know
    /// the current state of the axes.
    ///
    /// If a button state change occurs at the same time as a tip state change, the order
    /// of events is device-dependent.
    Tip(TabletToolTipEvent),
    /// Signals that a tool has changed a logical button state on a device with the
    /// `DeviceCapability::TabletTool` capability.
    ///
    /// Button state changes occur on their own and do not include axis state changes. If
    /// button and axis state changes occur within the same logical hardware event, the
    /// order of the `TabletToolButtonEvent` and `TabletToolAxisEvent` is device-specific.
    ///
    /// This event is not to be confused with the button events emitted by the tablet
    /// pad. See `TabletPadButtonEvent`.
    Button(TabletToolButtonEvent),
}

impl EventTrait for TabletToolEvent {
    #[doc(hidden)]
    fn as_raw_event(&self) -> *mut ffi::libinput_event {
        match *self {
            TabletToolEvent::Axis(ref event) => event.as_raw_event(),
            TabletToolEvent::Proximity(ref event) => event.as_raw_event(),
            TabletToolEvent::Tip(ref event) => event.as_raw_event(),
            TabletToolEvent::Button(ref event) => event.as_raw_event(),
        }
    }
}

impl FromRaw<ffi::libinput_event_tablet_tool> for TabletToolEvent {
    unsafe fn from_raw(event: *mut ffi::libinput_event_tablet_tool) -> Self {
        let base = ffi::libinput_event_tablet_tool_get_base_event(event);
        match ffi::libinput_event_get_type(base) {
            ffi::libinput_event_type::LIBINPUT_EVENT_TABLET_TOOL_AXIS => {
                TabletToolEvent::Axis(TabletToolAxisEvent::from_raw(event))
            }
            ffi::libinput_event_type::LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY => {
                TabletToolEvent::Proximity(TabletToolProximityEvent::from_raw(event))
            }
            ffi::libinput_event_type::LIBINPUT_EVENT_TABLET_TOOL_TIP => {
                TabletToolEvent::Tip(TabletToolTipEvent::from_raw(event))
            }
            ffi::libinput_event_type::LIBINPUT_EVENT_TABLET_TOOL_BUTTON => {
                TabletToolEvent::Button(TabletToolButtonEvent::from_raw(event))
            }
            _ => unreachable!(),
        }
    }
}

impl AsRaw<ffi::libinput_event_tablet_tool> for TabletToolEvent {
    fn as_raw(&self) -> *const ffi::libinput_event_tablet_tool {
        match *self {
            TabletToolEvent::Axis(ref event) => event.as_raw(),
            TabletToolEvent::Proximity(ref event) => event.as_raw(),
            TabletToolEvent::Tip(ref event) => event.as_raw(),
            TabletToolEvent::Button(ref event) => event.as_raw(),
        }
    }
}

ffi_event_struct!(
/// One or more axes have changed state on a device with the
/// `DeviceCapability::TabletTool` capability.
///
/// This event is only sent when the tool is in proximity, see
/// `TabletToolProximityEvent` for details.
///
/// The proximity event contains the initial state of the axis as the tool comes into
/// proximity. An event of type `TabletToolAxisEvent` is only sent when an axis value
/// changes from this initial state. It is possible for a tool to enter and leave
/// proximity without sending an event of type `TabletToolAxisEvent`.
///
/// An event of type `TabletToolAxisEvent` is sent when the tip state does not
/// change. See the documentation for `TabletToolTipEvent` for more details.
struct TabletToolAxisEvent, ffi::libinput_event_tablet_tool, ffi::libinput_event_tablet_tool_get_base_event);

/// The state of proximity for a tool on a device.
///
/// The proximity of a tool is a binary state signalling whether the tool is within a
/// detectable distance of the tablet device. A tool that is out of proximity cannot
/// generate events.
///
/// 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
/// the surface.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ProximityState {
    /// Out of proximity
    Out,
    /// In proximity
    In,
}

ffi_event_struct!(
/// Signals that a tool has come in or out of proximity of a device with the
/// `DeviceCapability::TabletTool` capability.
///
/// Proximity events contain each of the current values for each axis, and these
/// values may be extracted from them in the same way they are with
/// `TabletToolAxisEvent` events.
///
/// Some tools may always be in proximity. For these tools, proximity events with
/// `ProximityState::In` are sent only once after `DeviceAddedEvent`, and proximity
/// events with `ProximityState::Out` are sent only once before `DeviceRemovedEvent`.
///
/// If the tool that comes into proximity supports x/y coordinates, libinput
/// guarantees that both x and y are set in the proximity event.
///
/// When a tool goes out of proximity, the value of every axis should be assumed to
/// have an undefined state and any buttons that are currently held down on the
/// stylus are marked as released. Button release events for each button that was
/// held down on the stylus are sent before the proximity out event.
struct TabletToolProximityEvent, ffi::libinput_event_tablet_tool, ffi::libinput_event_tablet_tool_get_base_event);

impl TabletToolProximityEvent {
    /// Returns the new proximity state of a tool from a proximity event.
    ///
    /// Used to check whether or not a tool came in or out of proximity during an
    /// `TabletToolProximityEvent`.
    ///
    /// See [Handling of proximity events](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-fake-proximity)
    /// for recommendations on proximity handling.
    pub fn proximity_state(&self) -> ProximityState {
        match unsafe { ffi::libinput_event_tablet_tool_get_proximity_state(self.as_raw_mut()) } {
            ffi::libinput_tablet_tool_proximity_state::LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT => {
                ProximityState::Out
            }
            ffi::libinput_tablet_tool_proximity_state::LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN => {
                ProximityState::In
            }
        }
    }
}

/// The tip contact state for a tool on a device.
///
/// The tip contact state of a tool is a binary state signalling whether the tool is
/// touching the surface of the tablet device.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TipState {
    /// Not touching the surface
    Up,
    /// Touching the surface
    Down,
}

ffi_event_struct!(
/// Signals that a tool has come in contact with the surface of a device with the
/// `DeviceCapability::TabletTool` capability.
///
/// On devices without distance proximity detection, the `TabletToolTipEvent` is sent
/// immediately after `TabletToolProximityEvent` for the tip down event, and
/// immediately before for the tip up event.
///
/// The decision when a tip touches the surface is device-dependent and may be
/// derived from pressure data or other means. If the tip state is changed by axes
/// changing state, the `TabletToolTipEvent` includes the changed axes and no
/// additional axis event is sent for this state change. In other words, a caller
/// must look at both `TabletToolAxisEvent` and `TabletToolTipEvent` events to know
/// the current state of the axes.
///
/// If a button state change occurs at the same time as a tip state change, the order
/// of events is device-dependent.
struct TabletToolTipEvent, ffi::libinput_event_tablet_tool, ffi::libinput_event_tablet_tool_get_base_event);

impl TabletToolTipEvent {
    /// Returns the new tip state of a tool from a tip event.
    ///
    /// Used to check whether or not a tool came in contact with the tablet surface or
    /// left contact with the tablet surface during an `TabletToolTipEvent`.
    pub fn tip_state(&self) -> TipState {
        match unsafe { ffi::libinput_event_tablet_tool_get_tip_state(self.as_raw_mut()) } {
            ffi::libinput_tablet_tool_tip_state::LIBINPUT_TABLET_TOOL_TIP_UP => TipState::Up,
            ffi::libinput_tablet_tool_tip_state::LIBINPUT_TABLET_TOOL_TIP_DOWN => TipState::Down,
        }
    }
}

ffi_event_struct!(
/// Signals that a tool has changed a logical button state on a device with the
/// `DeviceCapability::TabletTool` capability.
///
/// Button state changes occur on their own and do not include axis state changes. If
/// button and axis state changes occur within the same logical hardware event, the
/// order of the `TabletToolButtonEvent` and `TabletToolAxisEvent` is device-specific.
///
/// This event is not to be confused with the button events emitted by the tablet
/// pad. See `TabletPadButtonEvent`.
struct TabletToolButtonEvent, ffi::libinput_event_tablet_tool, ffi::libinput_event_tablet_tool_get_base_event);

impl TabletToolButtonEvent {
    ffi_func!(
    /// Return the button that triggered this event.
    pub fn button, ffi::libinput_event_tablet_tool_get_button, u32);
    ffi_func!(
    /// For the button of a `TabletToolButtonEvent`, return the total number of buttons
    /// pressed on all devices on the associated seat after the the event was triggered.
    pub fn seat_button_count, ffi::libinput_event_tablet_tool_get_seat_button_count, u32);

    /// Return the button state of the event.
    pub fn button_state(&self) -> ButtonState {
        match unsafe { ffi::libinput_event_tablet_tool_get_button_state(self.as_raw_mut()) } {
            ffi::libinput_button_state::LIBINPUT_BUTTON_STATE_PRESSED => ButtonState::Pressed,
            ffi::libinput_button_state::LIBINPUT_BUTTON_STATE_RELEASED => ButtonState::Released,
        }
    }
}