input-0.9.0/.cargo_vcs_info.json0000644000000001360000000000100122010ustar { "git": { "sha1": "cca7e43f9a6b5c46ccf4880489c53d2efee3c343" }, "path_in_vcs": "" }input-0.9.0/CHANGELOG.md000064400000000000000000000031641046102023000126060ustar 00000000000000## 0.9.0 - Update to bitflags 2.x and udev 0.8 - Don't require generated bindings for specific OS/architecture to build ## 0.8.3 - Fixed bitflags test for config entries (see https://github.com/Smithay/input.rs/pull/54, thanks @ids1024) - Fixed use of struct\_name in Debug impls (see https://github.com/Smithay/input.rs/pull/53, thanks @ids1024) ## 0.8.2 - Added missing `GestureEndEvent` implementation for `GestureHoldEvent` ## 0.8.1 - Fix missing feature flags for libinput 1.21 ## 0.8.0 (yanked) - Use safe-io types - Add libinput 1.21 support - Add (untested) pre-generated FreeBSD bindings - Upgrade udev dependency to 0.7 - Fix udev-device-unref memory corruption ## 0.7.0 - Add libinput 1.19 support ## 0.6.0 - Upgrade udev dependency to 0.6.0 ## 0.5.0 - Upgrade udev dependency to 0.4.0 - Update input-sys to 1.15, allowing usage of newer libinput versions - The exposed libinput functions are controlled via features! - **Breaking:** To remain compatible with the oldest available libinput version disable the default feature set - The new default is to always expose all functions ## 0.4.0 - Upgrade input-sys to libinput 1.9.0 - Optionally integrate with `udev` crate - Replace `libinput_interface` with `LibinputInterface` trait - Remove broken `Userdata` api ## 0.3.0 - Use bitflags 1.0 to represent bitflags ## 0.2.1 - Bugfixes - id_vendor() was incorrectly returning the product id - config_accel_profiles() was returning inverted results ([Flat,Adaptive] for devices that support neither, [] for devices supporting both) ## 0.2.0 - Remove invalid `Clone` implementations ## 0.1.0 - Initial release input-0.9.0/Cargo.toml0000644000000032700000000000100102010ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "input" version = "0.9.0" authors = ["Drakulix (Victoria Brekenfeld)"] exclude = [ ".gitignore", ".rustfmt.toml", ".github", ] description = "libinput bindings for rust" documentation = "https://docs.rs/input" readme = "README.md" keywords = [ "wayland", "input", "bindings", ] categories = ["external-ffi-bindings"] license = "MIT" repository = "https://github.com/Drakulix/input.rs" [dependencies.bitflags] version = "2.4" [dependencies.input-sys] version = "1.18.0" default-features = false [dependencies.io-lifetimes] version = "1.0.3" [dependencies.libc] version = "0.2" [dependencies.log] version = "0.4.20" optional = true [dependencies.udev] version = "0.8" optional = true [dev-dependencies.rustix] version = "0.38" features = ["event"] [features] default = [ "udev", "log", "libinput_1_21", ] libinput_1_11 = ["input-sys/libinput_1_11"] libinput_1_14 = [ "input-sys/libinput_1_14", "libinput_1_11", ] libinput_1_15 = [ "input-sys/libinput_1_15", "libinput_1_14", ] libinput_1_19 = [ "input-sys/libinput_1_19", "libinput_1_15", ] libinput_1_21 = [ "input-sys/libinput_1_21", "libinput_1_19", ] use_bindgen = ["input-sys/use_bindgen"] input-0.9.0/Cargo.toml.orig000064400000000000000000000021711046102023000136610ustar 00000000000000[package] name = "input" description = "libinput bindings for rust" license = "MIT" documentation = "https://docs.rs/input" repository = "https://github.com/Drakulix/input.rs" version = "0.9.0" keywords = ["wayland", "input", "bindings"] categories = ["external-ffi-bindings"] authors = ["Drakulix (Victoria Brekenfeld)"] edition = "2018" exclude = [".gitignore", ".rustfmt.toml", ".github"] [dependencies] io-lifetimes = "1.0.3" libc = "0.2" bitflags = "2.4" log = { version = "0.4.20", optional = true } [dependencies.input-sys] version = "1.18.0" path = "input-sys" default-features = false [dependencies.udev] version = "0.8" optional = true [dev-dependencies] rustix = { version = "0.38", features = ["event"] } [features] default = ["udev", "log", "libinput_1_21"] use_bindgen = ["input-sys/use_bindgen"] libinput_1_11 = ["input-sys/libinput_1_11"] libinput_1_14 = ["input-sys/libinput_1_14", "libinput_1_11"] libinput_1_15 = ["input-sys/libinput_1_15", "libinput_1_14"] libinput_1_19 = ["input-sys/libinput_1_19", "libinput_1_15"] libinput_1_21 = ["input-sys/libinput_1_21", "libinput_1_19"] [workspace] members = [ "input-sys" ] input-0.9.0/LICENSE000064400000000000000000000020621046102023000117760ustar 00000000000000MIT License Copyright (c) 2017 Victor Brekenfeld Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. input-0.9.0/README.md000064400000000000000000000043631046102023000122560ustar 00000000000000# Rust libinput bindings [![Build Status](https://img.shields.io/github/actions/workflow/status/Smithay/input.rs/ci.yml?branch=master&logo=github-actions&logoColor=white&style=for-the-badge)](https://github.com/Smithay/input.rs/actions/workflows/ci.yml) [![Crates.io](https://img.shields.io/crates/v/input.svg?logo=rust&style=for-the-badge)](https://crates.io/crates/input) [![License](https://img.shields.io/crates/l/input.svg?style=for-the-badge)](https://crates.io/crates/input) [![Docs](https://img.shields.io/docsrs/input?style=for-the-badge)](https://docs.rs/input) [libinput](https://wayland.freedesktop.org/libinput/doc/latest/) bindings for [Rust](https://www.rust-lang.org) These bindings closely follow libinput's concepts and it's original API. Please refer to the [libinput documentation](https://wayland.freedesktop.org/libinput/doc/latest/) to understand the general structure and concepts. **Note:** Due to a bug within libinput, these bindings are *not* compatible with libinput 1.19.**0**. Please use the fixed 1.19.**1** version. ## Usage Add to your `Cargo.toml`: ```toml input = "0.8" ``` Install the libinput dev dependencies: Ubuntu: ``` apt-get install libinput-dev ``` Fedora ``` dnf install libinput-devel ``` Configure and run event loop: ```rust use input::{Libinput, LibinputInterface}; use libc::{O_RDONLY, O_RDWR, O_WRONLY}; use std::fs::{File, OpenOptions}; use std::os::unix::{fs::OpenOptionsExt, io::OwnedFd}; use std::path::Path; struct Interface; impl LibinputInterface for Interface { fn open_restricted(&mut self, path: &Path, flags: i32) -> Result { OpenOptions::new() .custom_flags(flags) .read((flags & O_RDONLY != 0) | (flags & O_RDWR != 0)) .write((flags & O_WRONLY != 0) | (flags & O_RDWR != 0)) .open(path) .map(|file| file.into()) .map_err(|err| err.raw_os_error().unwrap()) } fn close_restricted(&mut self, fd: OwnedFd) { drop(File::from(fd)); } } fn main() { let mut input = Libinput::new_with_udev(Interface); input.udev_assign_seat("seat0").unwrap(); loop { input.dispatch().unwrap(); for event in &mut input { println!("Got event: {:?}", event); } } } ``` input-0.9.0/src/context.rs000064400000000000000000000355521046102023000136240ustar 00000000000000// TODO Error type instead of `Result<_, ()>` #![allow(clippy::result_unit_err)] use crate::{ffi, AsRaw, Device, Event, FromRaw}; use io_lifetimes::{AsFd, BorrowedFd, OwnedFd}; use std::{ ffi::{CStr, CString}, io::{Error as IoError, Result as IoResult}, iter::Iterator, os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}, path::Path, rc::Rc, }; #[cfg(feature = "udev")] use udev::ffi as udev; /// libinput does not open file descriptors to devices directly, /// instead `open_restricted` and `close_restricted` are called for /// each path that must be opened. /// /// Implementations are of course permitted to just use `open` and /// `close` respectively, but doing so would require root permissions /// to open devices. This interface provides an api agnostic way to /// use ConsoleKit or similar endpoints to open devices without /// direct priviledge escalation. pub trait LibinputInterface { /// Open the device at the given path with the flags provided and /// return the fd. /// /// ## Paramater /// - `path` - The device path to open /// - `flags` Flags as defined by open(2) /// /// ## Returns /// The file descriptor, or a negative errno on failure. fn open_restricted(&mut self, path: &Path, flags: i32) -> Result; /// Close the file descriptor. /// /// ## Parameter /// `fd` - The file descriptor to close fn close_restricted(&mut self, fd: OwnedFd); } unsafe extern "C" fn open_restricted( path: *const libc::c_char, flags: libc::c_int, user_data: *mut libc::c_void, ) -> libc::c_int { use std::borrow::Cow; if let Some(interface) = (user_data as *mut I).as_mut() { let path_str = CStr::from_ptr(path).to_string_lossy(); let res = match path_str { Cow::Borrowed(string) => interface.open_restricted(Path::new(string), flags), Cow::Owned(string) => interface.open_restricted(Path::new(&string), flags), }; match res { Ok(fd) => fd.into_raw_fd(), Err(errno) => { if errno > 0 { -errno } else { errno } } } } else { -1 } } unsafe extern "C" fn close_restricted( fd: libc::c_int, user_data: *mut libc::c_void, ) { if let Some(interface) = (user_data as *mut I).as_mut() { interface.close_restricted(unsafe { OwnedFd::from_raw_fd(fd) }) } } /// Libinput context /// /// Contexts can be used to track input devices and receive events from them. /// You can use either `new_from_udev` to create a context tracking all devices on a specific seat, /// or use `new_from_path` to track input devices manually. /// /// Either way you then have to use `dispatch()` and `next()` (provided by the `Iterator` trait) to /// receive events. pub struct Libinput { ffi: *mut ffi::libinput, _interface: Option>, } impl ::std::fmt::Debug for Libinput { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, "Libinput @{:p}", self.as_raw()) } } impl AsRaw for Libinput { fn as_raw(&self) -> *const ffi::libinput { self.ffi as *const _ } } impl Clone for Libinput { fn clone(&self) -> Self { Libinput { ffi: unsafe { ffi::libinput_ref(self.as_raw_mut()) }, _interface: self._interface.clone(), } } } impl Drop for Libinput { fn drop(&mut self) { unsafe { ffi::libinput_unref(self.ffi); } } } impl PartialEq for Libinput { fn eq(&self, other: &Self) -> bool { self.as_raw() == other.as_raw() } } impl Eq for Libinput {} impl ::std::hash::Hash for Libinput { fn hash(&self, state: &mut H) { self.as_raw().hash(state); } } impl Iterator for Libinput { type Item = Event; fn next(&mut self) -> Option { loop { let ptr = unsafe { ffi::libinput_get_event(self.as_raw_mut()) }; if ptr.is_null() { return None; } else { match unsafe { Event::try_from_raw(ptr, self) } { Some(x) => return Some(x), None => { #[cfg(feature = "log")] log::warn!("Skipping unknown event: {}", unsafe { ffi::libinput_event_get_type(ptr) }); continue; } } } } } } impl Libinput { /// Create a new libinput context using a udev context. /// /// This context is inactive until `udev_assign_seat` is called. /// /// ## Arguments /// /// - interface - A `LibinputInterface` providing functions to open and close devices. /// - userdata - Optionally some userdata attached to the newly created context (see [`Userdata`](./trait.Userdata.html)) /// - udev_context - Raw pointer to a valid udev context. /// /// # Safety /// /// This function is unsafe, because there is no way to verify that `udev_context` is indeed a valid udev context or even points to valid memory. #[cfg(feature = "udev")] pub fn new_with_udev(interface: I) -> Libinput { let boxed_userdata = Rc::new(interface); let boxed_interface = Box::new(ffi::libinput_interface { open_restricted: Some(open_restricted::), close_restricted: Some(close_restricted::), }); unsafe { let udev = udev::udev_new(); let libinput = ffi::libinput_udev_create_context( Box::into_raw(boxed_interface), Rc::as_ptr(&boxed_userdata) as *mut _, udev as *mut input_sys::udev, ); udev::udev_unref(udev); Libinput { ffi: libinput, _interface: Some(boxed_userdata as Rc), } } } /// Create a new libinput context that requires the caller to manually add or remove devices. /// /// The returned context is active, but will not yield any events /// until at least one device is added. /// /// Devices can be added and removed by calling `path_add_device` and `path_remove_device` respectively. /// /// ## Arguments /// /// - interface - A `LibinputInterface` providing functions to open and close devices. /// - userdata - Optionally some userdata attached to the newly created context (see [`Userdata`](./trait.Userdata.html)) /// pub fn new_from_path(interface: I) -> Libinput { let boxed_userdata = Rc::new(interface); let boxed_interface = Box::new(ffi::libinput_interface { open_restricted: Some(open_restricted::), close_restricted: Some(close_restricted::), }); Libinput { ffi: unsafe { ffi::libinput_path_create_context( Box::into_raw(boxed_interface), Rc::as_ptr(&boxed_userdata) as *mut _, ) }, _interface: Some(boxed_userdata as Rc), } } /// Add a device to a libinput context initialized with /// `new_from_context`. /// /// If successful, the device will be added to the internal list /// and re-opened on `resume`. The device can be removed with /// `path_remove_device()`. /// /// If the device was successfully initialized, it is returned. /// /// ## Warning /// /// It is an application bug to call this function on a context /// initialized with `new_from_udev`. pub fn path_add_device(&mut self, path: &str) -> Option { let path = CString::new(path).expect("Device Path contained a null-byte"); unsafe { let ptr = ffi::libinput_path_add_device(self.as_raw_mut(), path.as_ptr()); if ptr.is_null() { None } else { Some(Device::from_raw(ptr, self)) } } } /// Remove a device from a libinput context initialized with /// `new_from_path` and added to such a context with /// `path_add_device`. /// /// Events already processed from this input device are kept in /// the queue, the `DeviceRemovedEvent` event marks the end of /// events for this device. /// /// ## Warning /// /// It is an application bug to call this function on a context /// initialized with `new_from_udev`. pub fn path_remove_device(&mut self, device: Device) { unsafe { ffi::libinput_path_remove_device(device.as_raw_mut()) } } /// Assign a seat to this libinput context. /// /// New devices or the removal of existing devices will appear as /// events during `dispatch`. /// /// `udev_assign_seat` succeeds even if no input devices are /// currently available on this seat, or if devices are available /// but fail to open in `LibinputInterface::open_restricted`. /// /// Devices that do not have the minimum capabilities to be /// recognized as pointer, keyboard or touch device are ignored. /// Such devices and those that failed to open ignored until the /// next call to `resume`. /// /// ## Warning /// /// This function may only be called once per context. #[cfg(feature = "udev")] pub fn udev_assign_seat(&mut self, seat_id: &str) -> Result<(), ()> { let id = CString::new(seat_id).expect("Seat Id contained a null-byte"); unsafe { match ffi::libinput_udev_assign_seat(self.as_raw_mut(), id.as_ptr()) { 0 => Ok(()), -1 => Err(()), _ => unreachable!(), } } } ffi_func!( /// Suspend monitoring for new devices and close existing /// devices. /// /// This closes all open devices and terminates libinput but /// does keep the context valid to be resumed with `resume`. pub fn suspend, ffi::libinput_suspend, ()); /// Resume a suspended libinput context. /// /// This re-enables device monitoring and adds existing devices. pub fn resume(&mut self) -> Result<(), ()> { unsafe { match ffi::libinput_resume(self.as_raw_mut()) { 0 => Ok(()), -1 => Err(()), _ => unreachable!(), } } } /// Main event dispatchment function. /// /// Reads events of the file descriptors and processes them /// internally. Use `next` or any other function provided by the /// `Iterator` trait to retrieve the events until `None` is /// returned. /// /// Dispatching does not necessarily queue libinput events. This /// function should be called immediately once data is available /// on the file descriptor returned by `fd`. libinput has a number /// of timing-sensitive features (e.g. tap-to-click), any delay in /// calling `dispatch` may prevent these features from working /// correctly. pub fn dispatch(&mut self) -> IoResult<()> { unsafe { match ffi::libinput_dispatch(self.as_raw_mut()) { 0 => Ok(()), x if x < 0 => Err(IoError::from_raw_os_error(-x)), _ => unreachable!(), } } } /// libinput keeps a single file descriptor for all events. /// /// Call into `dispatch` if any events become available on this fd. /// /// The most simple variant to check for available bytes is to use /// `nix::poll`: /// /// ``` /// # extern crate libc; /// # extern crate rustix; /// # /// # use std::fs::{File, OpenOptions}; /// # use std::os::unix::{fs::OpenOptionsExt, io::OwnedFd}; /// # use std::path::Path; /// # use libc::{O_RDONLY, O_RDWR, O_WRONLY}; /// # /// use input::{Libinput, LibinputInterface}; /// use rustix::event::{poll, PollFlags, PollFd}; /// /// # struct Interface; /// # /// # impl LibinputInterface for Interface { /// # fn open_restricted(&mut self, path: &Path, flags: i32) -> Result { /// # OpenOptions::new() /// # .custom_flags(flags) /// # .read((flags & O_RDONLY != 0) | (flags & O_RDWR != 0)) /// # .write((flags & O_WRONLY != 0) | (flags & O_RDWR != 0)) /// # .open(path) /// # .map(|file| file.into()) /// # .map_err(|err| err.raw_os_error().unwrap()) /// # } /// # fn close_restricted(&mut self, fd: OwnedFd) { /// # unsafe { /// # File::from(fd); /// # } /// # } /// # } /// # /// # // Preventing infinite execution (in particular on CI) /// # std::thread::spawn(|| { /// # std::thread::sleep(std::time::Duration::from_secs(5)); /// # std::process::exit(0); /// # }); /// # /// let mut input = Libinput::new_with_udev(Interface); /// input.udev_assign_seat("seat0").unwrap(); /// /// while poll(&mut [PollFd::new(&input, PollFlags::IN)], -1).is_ok() { /// input.dispatch().unwrap(); /// for event in &mut input { /// // do some processing... /// } /// } /// ``` /// /// For more complex operations you may wish to use other approches /// as event loops e.g. in the `wayland-server` or the `tokio` /// crates to wait for data to become available on this file /// descriptor. /// /// # Safety /// /// See [`AsRawFd`] #[deprecated(since = "0.4.1", note = "Use the provided AsRawFd implementation")] pub unsafe fn fd(&self) -> RawFd { ffi::libinput_get_fd(self.as_raw_mut()) } /// Create a new instance of this type from a raw pointer. /// /// ## Warning /// /// If you make use of [`Userdata`](./trait.Userdata.html) make sure you use the correct types /// to allow receiving the set userdata. When dealing with raw pointers initialized by other /// libraries this must be done extra carefully to select a correct representation. /// /// If unsure using `()` is always a safe option.. /// /// # Safety /// /// If the pointer is pointing to a different struct, invalid memory or `NULL` the returned /// struct may panic on use or cause other undefined behavior. pub unsafe fn from_raw(ffi: *mut ffi::libinput) -> Self { Libinput { ffi: ffi::libinput_ref(ffi), _interface: None, } } } impl AsRawFd for Libinput { fn as_raw_fd(&self) -> RawFd { unsafe { ffi::libinput_get_fd(self.as_raw_mut()) } } } impl AsFd for Libinput { fn as_fd(&self) -> BorrowedFd<'_> { unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } } } input-0.9.0/src/device.rs000064400000000000000000002264011046102023000133720ustar 00000000000000// Allow unnecessary casts since ffi types may differ by C ABI // TODO Error type instead of `Result<_, ()>` // TODO Better way to handle `SendEventsMode::ENABLED` being 0? #![allow( clippy::bad_bit_mask, clippy::result_unit_err, clippy::unnecessary_cast )] use crate::{ event::{switch::Switch, tablet_pad::TabletPadModeGroup}, ffi, AsRaw, FromRaw, Libinput, Seat, }; use bitflags::bitflags; use std::ffi::{CStr, CString}; #[cfg(feature = "udev")] use udev::{ ffi::{udev as udev_context, udev_device, udev_device_get_udev, udev_ref}, Device as UdevDevice, FromRawWithContext as UdevFromRawWithContext, }; /// Capabilities on a device. /// /// A device may have one or more capabilities at a time, capabilities /// remain static for the lifetime of the device. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum DeviceCapability { /// Keyboard capability Keyboard, /// Pointer capability Pointer, /// Touch capability Touch, /// TabletTool capability TabletTool, /// TabletPad capability TabletPad, /// Gesture capability Gesture, /// Switch capability Switch, } /// Pointer Acceleration Profile #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum AccelProfile { /// A flat acceleration profile. /// /// Pointer motion is accelerated by a constant (device-specific) /// factor, depending on the current speed. Flat, /// An adaptive acceleration profile. /// /// Pointer acceleration depends on the input speed. This is the /// default profile for most devices. Adaptive, } /// The click method defines when to generate software-emulated /// buttons, usually on a device that does not have a specific /// physical button available. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum ClickMethod { /// Use software-button areas (see [Clickfinger behavior](https://wayland.freedesktop.org/libinput/doc/latest/clickpad_softbuttons.html#clickfinger)) /// to generate button events. ButtonAreas, /// The number of fingers decides which button press to generate. Clickfinger, } /// The scroll method of a device selects when to generate scroll axis /// events instead of pointer motion events. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum ScrollMethod { /// Never send scroll events instead of pointer motion events. /// /// This has no effect on events generated by scroll wheels. NoScroll, /// Send scroll events when two fingers are logically down on the /// device. TwoFinger, /// Send scroll events when a finger moves along the bottom or /// right edge of a device. Edge, /// Send scroll events when a button is down and the device moves /// along a scroll-capable axis. OnButtonDown, } /// Errors returned when applying configuration settings. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum DeviceConfigError { /// Configuration not available on this device. Unsupported, /// Invalid parameter range. Invalid, } bitflags! { /// The send-event mode of a device defines when a device may generate /// events and pass those events to the caller. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct SendEventsMode: u32 { /// Send events from this device normally. /// /// This is a placeholder mode only, any device detected by /// libinput can be enabled. Do not test for this value as bitmask. const ENABLED = ffi::libinput_config_send_events_mode_LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; /// Do not send events through this device. /// /// Depending on the device, this may close all file descriptors /// on the device or it may leave the file descriptors open and /// route events through a different device. /// /// If this mode is set, other disable modes may be ignored. /// For example, if both `Disabled` and `DisabledOnExternalMouse` /// are set, the device remains disabled when all external pointer /// devices are unplugged. const DISABLED = ffi::libinput_config_send_events_mode_LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; /// If an external pointer device is plugged in, do not send /// events from this device. /// /// This option may be available on built-in touchpads. const DISABLED_ON_EXTERNAL_MOUSE = ffi::libinput_config_send_events_mode_LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE; } } /// Map 1/2/3 finger tips to buttons #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum TapButtonMap { /// 1/2/3 finger tap maps to left/right/middle LeftRightMiddle, /// 1/2/3 finger tap maps to left/middle/right LeftMiddleRight, } /// Whenever scroll button lock is enabled or not #[cfg(feature = "libinput_1_15")] #[allow(missing_docs)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum ScrollButtonLockState { Disabled, Enabled, } /// Result returned when applying configuration settings. pub type DeviceConfigResult = Result<(), DeviceConfigError>; bitflags! { /// Mask reflecting LEDs on a device. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct Led: u32 { /// Num Lock Led const NUMLOCK = ffi::libinput_led_LIBINPUT_LED_NUM_LOCK; /// Caps Lock Led const CAPSLOCK = ffi::libinput_led_LIBINPUT_LED_CAPS_LOCK; /// Scroll Lock Led const SCROLLLOCK = ffi::libinput_led_LIBINPUT_LED_SCROLL_LOCK; } } ffi_ref_struct!( /// Device group /// /// Some physical devices like graphics tablets are represented by /// multiple kernel devices and thus by multiple `Device`s. /// /// libinput assigns these devices to the same `DeviceGroup` allowing /// the caller to identify such devices and adjust configuration /// settings accordingly. For example, setting a tablet to left-handed /// often means turning it upside down. A touch device on the same /// tablet would need to be turned upside down too to work correctly. /// /// All devices are part of a device group though for most devices the /// group will be a singleton. A device is assigned to a device group /// on `DeviceAddedEvent` and removed from that group on /// `DeviceRemovedEvent`. It is up to the caller to track how many /// devices are in each device group. /// /// Device groups do not get re-used once the last device in the group /// was removed, i.e. unplugging and re-plugging a physical device /// with grouped devices will return a different device group after /// every unplug. /// /// Device groups are assigned based on the LIBINPUT_DEVICE_GROUP udev /// property, see [Static device configuration](https://wayland.freedesktop.org/libinput/doc/latest/udev_config.html) via udev. struct DeviceGroup, ffi::libinput_device_group, ffi::libinput_device_group_ref, ffi::libinput_device_group_unref); ffi_ref_struct!( /// Representation of a single input device as seen by the kernel. /// /// A single physical device might consist out of multiple input /// devices like a keyboard-touchpad combination. See `DeviceGroup` /// if you want to track such combined physical devices. struct Device, ffi::libinput_device, ffi::libinput_device_ref, ffi::libinput_device_unref); impl Device { /// Get the libinput context from the device. pub fn context(&self) -> Libinput { self.context.clone() } /// Get the device group this device is assigned to. /// /// Some physical devices like graphics tablets are represented by /// multiple kernel devices and thus by multiple `Device`s. /// /// libinput assigns these devices to the same `DeviceGroup` /// allowing the caller to identify such devices and adjust /// configuration settings accordingly. For example, setting a /// tablet to left-handed often means turning it upside down. A /// touch device on the same tablet would need to be turned upside /// down too to work correctly. /// /// All devices are part of a device group though for most devices /// the group will be a singleton. A device is assigned to a /// device group on `DeviceAddedEvent` and removed from that group /// on `DeviceRemovedEvent`. It is up to the caller to track how /// many devices are in each device group. /// /// Device groups do not get re-used once the last device in the /// group was removed, i.e. unplugging and re-plugging a physical /// device with grouped devices will return a different device /// group after every unplug. /// /// Device groups are assigned based on the `LIBINPUT_DEVICE_GROUP` /// udev property, see [Static device configuration](https://wayland.freedesktop.org/libinput/doc/latest/udev_config.html) via udev. pub fn device_group(&self) -> DeviceGroup { unsafe { DeviceGroup::from_raw( ffi::libinput_device_get_device_group(self.as_raw_mut()), &self.context, ) } } /// Get the system name of the device. /// /// To get the descriptive device name, use `name`. pub fn sysname(&self) -> &str { unsafe { CStr::from_ptr(ffi::libinput_device_get_sysname(self.as_raw_mut())) .to_str() .expect("Device sysname is no valid utf8") } } /// The descriptive device name as advertised by the kernel and/or /// the hardware itself. /// /// To get the sysname for this device, use `sysname`. pub fn name(&self) -> &str { unsafe { CStr::from_ptr(ffi::libinput_device_get_name(self.as_raw_mut())) .to_str() .expect("Device name is no valid utf8") } } /// A device may be mapped to a single output, or all available /// outputs. /// /// If a device is mapped to a single output only, a relative /// device may not move beyond the boundaries of this output. An /// absolute device has its input coordinates mapped to the /// extents of this output. pub fn output_name(&self) -> Option<&str> { unsafe { let ptr = ffi::libinput_device_get_output_name(self.as_raw_mut()); if !ptr.is_null() { Some( CStr::from_ptr(ptr) .to_str() .expect("Device output_name is no valid utf8"), ) } else { None } } } ffi_func!( /// Get the product ID for this device. pub fn id_product, ffi::libinput_device_get_id_product, u32); ffi_func!( /// Get the vendor ID for this device. pub fn id_vendor, ffi::libinput_device_get_id_vendor, u32); /// Get the seat associated with this input device, see /// [Seats](https://wayland.freedesktop.org/libinput/doc/latest/seats.html) /// for details. /// /// A seat can be uniquely identified by the physical and logical /// seat name. There will ever be only one seat instance with a /// given physical and logical seat name pair at any given time, /// but if no external reference is kept, it may be destroyed if /// no device belonging to it is left. pub fn seat(&self) -> Seat { unsafe { Seat::from_raw( ffi::libinput_device_get_seat(self.as_raw_mut()), &self.context, ) } } /// Change the logical seat associated with this device by removing the device and adding it to the new seat. /// /// This command is identical to physically unplugging the device, /// then re-plugging it as a member of the new seat. libinput will /// generate a `DeviceRemovedEvent` event and this `Device` is /// considered removed from the context; it will not generate /// further events and will be freed when it goes out of scope. /// A `DeviceAddedEvent` event is generated with a new `Device` /// handle. It is the caller's responsibility to update references /// to the new device accordingly. /// /// If the logical seat name already exists in the device's /// physical seat, the device is added to this seat. Otherwise, a /// new seat is created. /// /// ## Note /// This change applies to this device until removal or `suspend`, /// whichever happens earlier. pub fn set_seat_logical_name(&mut self, name: &str) -> Result<(), ()> { let name = CString::new(name).expect("New logical_seat name contained a null-byte"); unsafe { if ffi::libinput_device_set_seat_logical_name(self.as_raw_mut(), name.as_ptr()) == 0 { Ok(()) } else { Err(()) } } } /// Return a udev handle to the device that is this libinput /// device, if any. /// /// Some devices may not have a udev device, or the udev device /// may be unobtainable. This function returns `None` if no udev /// device was available. /// /// Calling this function multiple times for the same device may /// not return the same udev handle each time. /// /// # Safety /// /// The result of this function is not definied if the passed udev `Context` /// is not the same as the one the libinput `Context` was created from. #[cfg(feature = "udev")] pub unsafe fn udev_device(&self) -> Option { let dev: *mut udev_device = ffi::libinput_device_get_udev_device(self.ffi) as *mut _; if dev.is_null() { None } else { // We have to ref the returned udev context as udev_device_get_udev does not // increase the ref_count but dropping a UdevDevice will unref it let ctx: *mut udev_context = udev_ref(udev_device_get_udev(dev)); Some(UdevDevice::from_raw_with_context(ctx, dev)) } } /// Update the LEDs on the device, if any. /// /// If the device does not have LEDs, or does not have one or more /// of the LEDs given in the mask, this function does nothing. /// /// ## Arguments /// /// leds: Leds to turn on /// /// Missing `Led`s will be turned off. /// The slice is interpreted as a bitmap. pub fn led_update(&mut self, leds: Led) { unsafe { ffi::libinput_device_led_update(self.as_raw_mut(), leds.bits()) } } /// Check if the given device has the specified capability. pub fn has_capability(&self, cap: DeviceCapability) -> bool { unsafe { ffi::libinput_device_has_capability( self.as_raw_mut(), match cap { DeviceCapability::Keyboard => { ffi::libinput_device_capability_LIBINPUT_DEVICE_CAP_KEYBOARD } DeviceCapability::Pointer => { ffi::libinput_device_capability_LIBINPUT_DEVICE_CAP_POINTER } DeviceCapability::Touch => { ffi::libinput_device_capability_LIBINPUT_DEVICE_CAP_TOUCH } DeviceCapability::TabletTool => { ffi::libinput_device_capability_LIBINPUT_DEVICE_CAP_TABLET_TOOL } DeviceCapability::TabletPad => { ffi::libinput_device_capability_LIBINPUT_DEVICE_CAP_TABLET_PAD } DeviceCapability::Gesture => { ffi::libinput_device_capability_LIBINPUT_DEVICE_CAP_GESTURE } DeviceCapability::Switch => { ffi::libinput_device_capability_LIBINPUT_DEVICE_CAP_SWITCH } }, ) != 0 } } /// Get the physical size of a device in mm, where meaningful. /// /// This function only succeeds on devices with the required data, /// i.e. tablets, touchpads and touchscreens. pub fn size(&self) -> Option<(f64, f64)> { let mut width = 0.0; let mut height = 0.0; match unsafe { ffi::libinput_device_get_size( self.as_raw_mut(), &mut width as *mut _, &mut height as *mut _, ) } { 0 => Some((width, height)), _ => None, } } /// Check if a `DeviceCapability::Pointer` device has a button /// with the given code (see linux/input.h). pub fn pointer_has_button(&self, button: u32) -> Result { match unsafe { ffi::libinput_device_pointer_has_button(self.as_raw_mut(), button) } { 1 => Ok(true), 0 => Ok(false), -1 => Err(()), _ => unreachable!(), } } /// Check if a `DeviceCapability::Keyboard` device has a key with /// the given code (see linux/input.h). pub fn keyboard_has_key(&self, key: u32) -> Result { match unsafe { ffi::libinput_device_keyboard_has_key(self.as_raw_mut(), key) } { 1 => Ok(true), 0 => Ok(false), -1 => Err(()), _ => unreachable!(), } } /// Check if a `DeviceCapability::Switch` device has a switch of the /// given type. pub fn switch_has_switch(&self, switch: Switch) -> Result { match unsafe { ffi::libinput_device_switch_has_switch(self.as_raw_mut(), switch as u32) } { 1 => Ok(true), 0 => Ok(false), -1 => Err(()), _ => unreachable!(), } } ffi_func!( /// Return the number of buttons on a device with the /// `DeviceCapability::TabletPad` capability. /// /// Buttons on a pad device are numbered sequentially, see Tablet /// pad button numbers for details. pub fn tablet_pad_number_of_buttons, ffi::libinput_device_tablet_pad_get_num_buttons, i32); ffi_func!( /// Return the number of rings a device with the /// `DeviceCapability::TabletPad` capability provides. pub fn tablet_pad_number_of_rings, ffi::libinput_device_tablet_pad_get_num_rings, i32); ffi_func!( /// Return the number of strips a device with the /// `DeviceCapability::TabletPad` capability provides. pub fn tablet_pad_number_of_strips, ffi::libinput_device_tablet_pad_get_num_strips, i32); ffi_func!( /// Most devices only provide a single mode group, however devices /// such as the Wacom Cintiq 22HD provide two mode groups. /// /// If multiple mode groups are available, a caller should use /// `TabletPadModeGroup::has_button`, /// `TabletPadModeGroup::has_ring` and /// `TabletPadModeGroup::has_strip()` to associate each button, /// ring and strip with the correct mode group. pub fn tablet_pad_number_of_mode_groups, ffi::libinput_device_tablet_pad_get_num_mode_groups, i32); /// Return the current mode this mode group is in. /// /// Note that the returned mode is the mode valid as of completing /// the last `dispatch`. The returned mode may thus be /// different than the mode returned by /// `TabletPadEventTrait::mode`. /// /// For example, if the mode was toggled three times between the /// call to `dispatch`, this function returns the third mode but /// the events in the event queue will return the modes 1, 2 and /// 3, respectively. pub fn tablet_pad_mode_group(&self, index: u32) -> Option { let ptr = unsafe { ffi::libinput_device_tablet_pad_get_mode_group(self.as_raw_mut(), index) }; if ptr.is_null() { None } else { Some(unsafe { TabletPadModeGroup::from_raw(ptr, &self.context) }) } } /// Check if a `DeviceCapability::TabletPad`-device has a key with the given code (see linux/input-event-codes.h). /// /// ## Returns /// - `Some(true)` if it has the requested key /// - `Some(false)` if it has not /// - `None` on error (no TabletPad device) #[cfg(feature = "libinput_1_15")] pub fn tablet_pad_has_key(&self, code: u32) -> Option { match unsafe { ffi::libinput_device_tablet_pad_has_key(self.as_raw_mut(), code) } { -1 => None, 0 => Some(false), 1 => Some(true), _ => panic!( "libinput returned invalid return code for libinput_device_tablet_pad_has_key" ), } } /// Check how many touches a `DeviceCapability::Touch`-exposing Device supports simultaneously. /// /// ## Returns /// - `Some(n)` amount of touches /// - `Some(0)` if unknown /// - `None` on error (no touch device) #[cfg(feature = "libinput_1_11")] pub fn touch_count(&mut self) -> Option { match unsafe { ffi::libinput_device_touch_get_touch_count(self.as_raw_mut()) } { -1 => None, n => Some(n as u32), } } /// Return the default pointer acceleration profile for this /// pointer device. pub fn config_accel_default_profile(&self) -> Option { match unsafe { ffi::libinput_device_config_accel_get_default_profile(self.as_raw_mut()) } { ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_NONE => None, ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT => { Some(AccelProfile::Flat) } ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE => { Some(AccelProfile::Adaptive) } _x => { #[cfg(feature = "log")] log::warn!( "Unknown AccelProfile ({}). Unsupported libinput version?", _x ); None } } } /// Get the current pointer acceleration profile for this pointer /// device. pub fn config_accel_profile(&self) -> Option { match unsafe { ffi::libinput_device_config_accel_get_profile(self.as_raw_mut()) } { ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_NONE => None, ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT => { Some(AccelProfile::Flat) } ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE => { Some(AccelProfile::Adaptive) } _x => { #[cfg(feature = "log")] log::warn!( "Unknown AccelProfile ({}). Unsupported libinput version?", _x ); None } } } /// Returns a bitmask of the configurable acceleration modes /// available on this device. pub fn config_accel_profiles(&self) -> Vec { let mut profiles = Vec::new(); let bitmask = unsafe { ffi::libinput_device_config_accel_get_profiles(self.as_raw_mut()) }; if bitmask & ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT as u32 != 0 { profiles.push(AccelProfile::Flat); } if bitmask & ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE as u32 != 0 { profiles.push(AccelProfile::Adaptive); } profiles } /// Set the pointer acceleration profile of this pointer device to /// the given mode. pub fn config_accel_set_profile(&mut self, profile: AccelProfile) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_accel_set_profile( self.as_raw_mut(), match profile { AccelProfile::Flat => { ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT } AccelProfile::Adaptive => { ffi::libinput_config_accel_profile_LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE } }, ) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } ffi_func!( /// Return the default speed setting for this device, normalized /// to a range of [-1, 1]. pub fn config_accel_default_speed, ffi::libinput_device_config_accel_get_default_speed, f64); ffi_func!( /// Get the current pointer acceleration setting for this pointer /// device. /// /// The returned value is normalized to a range of [-1, 1]. See /// `config_accel_set_speed` for details. pub fn config_accel_speed, ffi::libinput_device_config_accel_get_speed, f64); /// Set the pointer acceleration speed of this pointer device /// within a range of [-1, 1], where 0 is the default acceleration /// for this device, -1 is the slowest acceleration and 1 is the /// maximum acceleration available on this device. /// /// The actual pointer acceleration mechanism is /// implementation-dependent, as is the number of steps available /// within the range. libinput picks the semantically closest /// acceleration step if the requested value does not match a /// discrete setting. pub fn config_accel_set_speed(&mut self, speed: f64) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_accel_set_speed(self.as_raw_mut(), speed) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } ffi_func!( /// Check if a device uses libinput-internal pointer-acceleration. pub fn config_accel_is_available, ffi::libinput_device_config_accel_is_available, bool); /// Return the default calibration matrix for this device. /// /// On most devices, this is the identity matrix. If the udev /// property `LIBINPUT_CALIBRATION_MATRIX` is set on the respective u /// dev device, that property's value becomes the default matrix, /// see [Static device configuration via udev](https://wayland.freedesktop.org/libinput/doc/latest/udev_config.html). pub fn config_calibration_default_matrix(&self) -> Option<[f32; 6]> { let mut matrix = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]; if unsafe { ffi::libinput_device_config_calibration_get_default_matrix( self.as_raw_mut(), matrix.as_mut_ptr(), ) != 0 } { Some(matrix) } else { None } } /// Return the current calibration matrix for this device. pub fn config_calibration_matrix(&self) -> Option<[f32; 6]> { let mut matrix = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]; if unsafe { ffi::libinput_device_config_calibration_get_matrix( self.as_raw_mut(), matrix.as_mut_ptr(), ) != 0 } { Some(matrix) } else { None } } ffi_func!( /// Check if the device can be calibrated via a calibration matrix. pub fn config_calibration_has_matrix, ffi::libinput_device_config_calibration_has_matrix, bool); /// Apply the 3x3 transformation matrix to absolute device /// coordinates. /// /// This matrix has no effect on relative events. /// /// Given a 6-element array [a, b, c, d, e, f], the matrix is /// applied as /// ```text /// [ a b c ] [ x ] /// [ d e f ] * [ y ] /// [ 0 0 1 ] [ 1 ] /// # * /// ``` /// The translation component (c, f) is expected to be normalized /// to the device coordinate range. For example, the matrix /// ```text /// [ 1 0 1 ] /// [ 0 1 -1 ] /// [ 0 0 1 ] /// ``` /// moves all coordinates by 1 device-width to the right and 1 /// device-height up. /// /// The rotation matrix for rotation around the origin is defined /// as /// ```text /// [ cos(a) -sin(a) 0 ] /// [ sin(a) cos(a) 0 ] /// [ 0 0 1 ] /// ``` /// Note that any rotation requires an additional translation /// component to translate the rotated coordinates back into the /// original device space. The rotation matrixes for 90, 180 and /// 270 degrees clockwise are: /// ```text /// 90 deg cw: 180 deg cw: 270 deg cw: /// [ 0 -1 1] [ -1 0 1] [ 0 1 0 ] /// [ 1 0 0] [ 0 -1 1] [ -1 0 1 ] /// [ 0 0 1] [ 0 0 1] [ 0 0 1 ] /// ``` pub fn config_calibration_set_matrix(&mut self, matrix: [f32; 6]) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_calibration_set_matrix(self.as_raw_mut(), matrix.as_ptr()) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } /// Get the default button click method for this device. /// /// The button click method defines when to generate /// software-emulated buttons, usually on a device that does not /// have a specific physical button available. pub fn config_click_default_method(&self) -> Option { match unsafe { ffi::libinput_device_config_click_get_default_method(self.as_raw_mut()) } { ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_NONE => None, ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS => { Some(ClickMethod::ButtonAreas) } ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER => { Some(ClickMethod::Clickfinger) } _x => { #[cfg(feature = "log")] log::warn!( "Unknown ClickMethod ({}). Unsupported libinput version?", _x ); None } } } /// Get the button click method for this device. /// /// The button click method defines when to generate /// software-emulated buttons, usually on a device that does not /// have a specific physical button available. pub fn config_click_method(&self) -> Option { match unsafe { ffi::libinput_device_config_click_get_method(self.as_raw_mut()) } { ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_NONE => None, ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS => { Some(ClickMethod::ButtonAreas) } ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER => { Some(ClickMethod::Clickfinger) } _x => { #[cfg(feature = "log")] log::warn!( "Unknown ClickMethod ({}). Unsupported libinput version?", _x ); None } } } /// Check which button click methods a device supports. /// /// The button click method defines when to generate /// software-emulated buttons, usually on a device that does not /// have a specific physical button available. pub fn config_click_methods(&self) -> Vec { let mut methods = Vec::new(); let bitmask = unsafe { ffi::libinput_device_config_click_get_methods(self.as_raw_mut()) }; if bitmask & ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER as u32 != 0 { methods.push(ClickMethod::Clickfinger); } if bitmask & ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS as u32 != 0 { methods.push(ClickMethod::ButtonAreas); } methods } /// Set the button click method for this device. /// /// The button click method defines when to generate /// software-emulated buttons, usually on a device that does not /// have a specific physical button available. /// /// ## Note /// /// The selected click method may not take effect immediately. The /// device may require changing to a neutral state first before /// activating the new method. pub fn config_click_set_method(&mut self, method: ClickMethod) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_click_set_method( self.as_raw_mut(), match method { ClickMethod::ButtonAreas => { ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS } ClickMethod::Clickfinger => { ffi::libinput_config_click_method_LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER } }, ) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } /// Check if the disable-while typing feature is enabled on this /// device by default. /// /// If the device does not support disable-while-typing, this /// function returns `false`. pub fn config_dwt_default_enabled(&self) -> bool { match unsafe { ffi::libinput_device_config_dwt_get_default_enabled(self.as_raw_mut()) } { ffi::libinput_config_dwt_state_LIBINPUT_CONFIG_DWT_ENABLED => true, ffi::libinput_config_dwt_state_LIBINPUT_CONFIG_DWT_DISABLED => false, _ => panic!("libinput returned invalid 'libinput_config_dwt_state'"), } } /// Check if the disable-while typing feature is currently enabled /// on this device. /// /// If the device does not support disable-while-typing, this /// function returns `false`. pub fn config_dwt_enabled(&self) -> bool { match unsafe { ffi::libinput_device_config_dwt_get_enabled(self.as_raw_mut()) } { ffi::libinput_config_dwt_state_LIBINPUT_CONFIG_DWT_ENABLED => true, ffi::libinput_config_dwt_state_LIBINPUT_CONFIG_DWT_DISABLED => false, _ => panic!("libinput returned invalid 'libinput_config_dwt_state'"), } } ffi_func!( /// Check if this device supports configurable /// disable-while-typing feature. /// /// This feature is usually available on built-in touchpads and /// disables the touchpad while typing. See [Disable-while-typing](https://wayland.freedesktop.org/libinput/doc/latest/palm_detection.html#disable-while-typing) /// for details. pub fn config_dwt_is_available, ffi::libinput_device_config_dwt_is_available, bool); /// Enable or disable the disable-while-typing feature. /// /// When enabled, the device will be disabled while typing and /// for a short period after. See Disable-while-typing for /// details. /// /// ## Note /// /// Enabling or disabling disable-while-typing may not take /// effect immediately. pub fn config_dwt_set_enabled(&self, enabled: bool) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_dwt_set_enabled( self.as_raw_mut(), if enabled { ffi::libinput_config_dwt_state_LIBINPUT_CONFIG_DWT_ENABLED } else { ffi::libinput_config_dwt_state_LIBINPUT_CONFIG_DWT_DISABLED }, ) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } /// Check if the disable-while trackpointing feature is enabled on this /// device by default. /// /// If the device does not support disable-while-trackpointing, this /// function returns `false`. #[cfg(feature = "libinput_1_21")] pub fn config_dwtp_default_enabled(&self) -> bool { match unsafe { ffi::libinput_device_config_dwtp_get_default_enabled(self.as_raw_mut()) } { ffi::libinput_config_dwtp_state_LIBINPUT_CONFIG_DWTP_ENABLED => true, ffi::libinput_config_dwtp_state_LIBINPUT_CONFIG_DWTP_DISABLED => false, _ => panic!("libinput returned invalid 'libinput_config_dwtp_state'"), } } /// Check if the disable-while trackpointing feature is currently enabled /// on this device. /// /// If the device does not support disable-while-trackpointing, this /// function returns `false`. #[cfg(feature = "libinput_1_21")] pub fn config_dwtp_enabled(&self) -> bool { match unsafe { ffi::libinput_device_config_dwtp_get_enabled(self.as_raw_mut()) } { ffi::libinput_config_dwtp_state_LIBINPUT_CONFIG_DWTP_ENABLED => true, ffi::libinput_config_dwtp_state_LIBINPUT_CONFIG_DWTP_DISABLED => false, _ => panic!("libinput returned invalid 'libinput_config_dwtp_state'"), } } ffi_func!( /// Check if this device supports configurable /// disable-while-trackpointing feature. /// /// This feature is usually available on Thinkpads and /// disables the touchpad while using the trackpoint. #[cfg(feature = "libinput_1_21")] pub fn config_dwtp_is_available, ffi::libinput_device_config_dwtp_is_available, bool); /// Enable or disable the disable-while-trackpointing feature. /// /// When enabled, the device will be disabled while using the trackpoint and /// for a short period after. /// /// ## Note /// /// Enabling or disabling disable-while-trackpointing may not take /// effect immediately. #[cfg(feature = "libinput_1_21")] pub fn config_dwtp_set_enabled(&self, enabled: bool) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_dwtp_set_enabled( self.as_raw_mut(), if enabled { ffi::libinput_config_dwtp_state_LIBINPUT_CONFIG_DWTP_ENABLED } else { ffi::libinput_config_dwtp_state_LIBINPUT_CONFIG_DWTP_DISABLED }, ) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } ffi_func!( /// Get the current left-handed configuration of the device. pub fn config_left_handed, ffi::libinput_device_config_left_handed_get, bool); ffi_func!( /// Get the default left-handed configuration of the device. pub fn config_left_handed_default, ffi::libinput_device_config_left_handed_get_default, bool); ffi_func!( /// Check if a device has a configuration that supports /// left-handed usage. pub fn config_left_handed_is_available, ffi::libinput_device_config_left_handed_is_available, bool); /// Set the left-handed configuration of the device. /// /// The exact behavior is device-dependent. On a mouse and most /// pointing devices, left and right buttons are swapped but the /// middle button is unmodified. On a touchpad, physical buttons /// (if present) are swapped. On a clickpad, the top and bottom /// software-emulated buttons are swapped where present, the main /// area of the touchpad remains a left button. Tapping and /// clickfinger behavior is not affected by this setting. /// /// Changing the left-handed configuration of a device may not /// take effect until all buttons have been logically released. pub fn config_left_handed_set(&self, enabled: bool) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_left_handed_set(self.as_raw_mut(), enabled as i32) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } /// Check if configurable middle button emulation is enabled by /// default on this device. /// /// See [Middle button emulation](https://wayland.freedesktop.org/libinput/doc/latest/middle_button_emulation.html) for details. /// /// If the device does not have configurable middle button /// emulation, this function returns `false`. /// /// ## Note /// /// Some devices provide middle mouse button emulation but do not /// allow enabling/disabling that emulation. These devices always /// return `false`. pub fn config_middle_emulation_default_enabled(&self) -> bool { match unsafe { ffi::libinput_device_config_middle_emulation_get_default_enabled(self.as_raw_mut()) } { ffi::libinput_config_middle_emulation_state_LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED => true, ffi::libinput_config_middle_emulation_state_LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED => false, _ => panic!("libinput returned invalid 'libinput_config_middle_emulation_state'"), } } /// Check if configurable middle button emulation is enabled on /// this device. /// /// See [Middle button emulation](https://wayland.freedesktop.org/libinput/doc/latest/middle_button_emulation.html) /// for details. /// /// If the device does not have configurable middle button /// emulation, this function returns `false`. /// /// ## Note /// /// Some devices provide middle mouse button emulation but do not /// allow enabling/disabling that emulation. These devices always /// return `false`. pub fn config_middle_emulation_enabled(&self) -> bool { match unsafe { ffi::libinput_device_config_middle_emulation_get_enabled(self.as_raw_mut()) } { ffi::libinput_config_middle_emulation_state_LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED => true, ffi::libinput_config_middle_emulation_state_LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED => false, _ => panic!("libinput returned invalid 'libinput_config_middle_emulation_state'"), } } ffi_func!( /// Check if middle mouse button emulation configuration is /// available on this device. /// /// See [Middle button emulation](https://wayland.freedesktop.org/libinput/doc/latest/middle_button_emulation.html) /// for details. /// /// ## Note /// /// Some devices provide middle mouse button emulation but do not /// allow enabling/disabling that emulation. These devices return /// `false` in `config_middle_emulation_is_available`. pub fn config_middle_emulation_is_available, ffi::libinput_device_config_middle_emulation_is_available, bool); /// Enable or disable middle button emulation on this device. /// /// When enabled, a simultaneous press of the left and right /// button generates a middle mouse button event. Releasing the /// buttons generates a middle mouse button release, the left and /// right button events are discarded otherwise. /// /// See [Middle button emulation](https://wayland.freedesktop.org/libinput/doc/latest/middle_button_emulation.html) /// for details. pub fn config_middle_emulation_set_enabled(&self, enabled: bool) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_middle_emulation_set_enabled( self.as_raw_mut(), if enabled { ffi::libinput_config_middle_emulation_state_LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED } else { ffi::libinput_config_middle_emulation_state_LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED }, ) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } ffi_func!( /// Get the current rotation of a device in degrees clockwise off /// the logical neutral position. /// /// If this device does not support rotation, the return value is /// always 0. pub fn config_rotation_angle, ffi::libinput_device_config_rotation_get_angle, u32); ffi_func!( /// Get the default rotation of a device in degrees clockwise off /// the logical neutral position. /// /// If this device does not support rotation, the return value is /// always 0. pub fn config_rotation_default_angle, ffi::libinput_device_config_rotation_get_default_angle, u32); ffi_func!( /// Check whether a device can have a custom rotation applied. pub fn config_rotation_is_available, ffi::libinput_device_config_rotation_is_available, bool); /// Set the rotation of a device in degrees clockwise off the /// logical neutral position. /// /// Any subsequent motion events are adjusted according to the /// given angle. /// /// The angle has to be in the range of [0, 360] degrees, /// otherwise this function returns `DeviceConfigError::Invalid`. /// If the angle is a multiple of 360 or negative, the caller /// must ensure the correct ranging before calling this function. /// /// libinput guarantees that this function accepts multiples of /// 90 degrees. If a value is within the [0, 360] range but not a /// multiple of 90 degrees, this function may return /// `DeviceConfigError::Invalid` if the underlying device or /// implementation does not support finer-grained rotation angles. /// /// The rotation angle is applied to all motion events emitted by /// the device. Thus, rotating the device also changes the angle /// required or presented by scrolling, gestures, etc. /// /// Setting a rotation of 0 degrees on a device that does not /// support rotation always succeeds. pub fn config_rotation_set_angle(&self, angle: u32) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_rotation_set_angle(self.as_raw_mut(), angle) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } ffi_func!( /// Get the button for the `ScrollMethod::OnButtonDown` method /// for this device. /// /// If `ScrollMethod::OnButtonDown` scroll method is not /// supported, or no button is set, this function returns 0. /// /// ## Note /// /// The return value is independent of the currently selected /// scroll-method. For button scrolling to activate, a device /// must have the `ScrollMethod::OnButtonDown` method enabled, /// and a non-zero button set as scroll button. pub fn config_scroll_button, ffi::libinput_device_config_scroll_get_button, u32); ffi_func!( /// Get the default button for the `ScrollMethod::OnButtonDown` /// method for this device. /// /// If `ScrollMethod::OnButtonDown` scroll method is not /// supported, or no default button is set, /// this function returns 0. pub fn config_scroll_default_button, ffi::libinput_device_config_scroll_get_default_button, u32); /// Get the default scroll method for this device. /// /// The method defines when to generate scroll axis events /// instead of pointer motion events. /// /// A return value of `None` means the scroll method is not known pub fn config_scroll_default_method(&self) -> Option { match unsafe { ffi::libinput_device_config_scroll_get_default_method(self.as_raw_mut()) } { ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_NO_SCROLL => { Some(ScrollMethod::NoScroll) } ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_2FG => { Some(ScrollMethod::TwoFinger) } ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_EDGE => { Some(ScrollMethod::Edge) } ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN => { Some(ScrollMethod::OnButtonDown) } _x => { #[cfg(feature = "log")] log::warn!( "Unknown ScrollMethod ({}). Unsupported libinput version?", _x ); None } } } /// Get the scroll method for this device. /// /// The method defines when to generate scroll axis events /// instead of pointer motion events. /// /// A return value of `None` means the scroll method is not known pub fn config_scroll_method(&self) -> Option { match unsafe { ffi::libinput_device_config_scroll_get_method(self.as_raw_mut()) } { ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_NO_SCROLL => { Some(ScrollMethod::NoScroll) } ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_2FG => { Some(ScrollMethod::TwoFinger) } ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_EDGE => { Some(ScrollMethod::Edge) } ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN => { Some(ScrollMethod::OnButtonDown) } _ => panic!("libinput returned invalid 'libinput_config_scroll_method'"), } } /// Check which scroll methods a device supports. /// /// The method defines when to generate scroll axis events /// instead of pointer motion events. pub fn config_scroll_methods(&self) -> Vec { let mut methods = Vec::new(); let bitmask = unsafe { ffi::libinput_device_config_scroll_get_methods(self.as_raw_mut()) }; if bitmask & ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_NO_SCROLL as u32 != 0 { methods.push(ScrollMethod::NoScroll); } if bitmask & ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_2FG as u32 != 0 { methods.push(ScrollMethod::TwoFinger); } if bitmask & ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_EDGE as u32 != 0 { methods.push(ScrollMethod::Edge); } if bitmask & ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN as u32 != 0 { methods.push(ScrollMethod::OnButtonDown); } methods } /// Set the scroll method for this device. /// /// The method defines when to generate scroll axis events /// instead of pointer motion events. /// /// ## Note /// /// Setting `ScrollMethod::OnButtonDown` enables the scroll /// method, but scrolling is only activated when the configured /// button is held down. If no button is set, i.e. /// `config_scroll_button` returns 0, scrolling cannot activate. pub fn config_scroll_set_method(&mut self, method: ScrollMethod) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_scroll_set_method( self.as_raw_mut(), match method { ScrollMethod::NoScroll => { ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_NO_SCROLL } ScrollMethod::TwoFinger => { ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_2FG } ScrollMethod::Edge => { ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_EDGE } ScrollMethod::OnButtonDown => { ffi::libinput_config_scroll_method_LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN } }, ) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } ffi_func!( /// Get the default mode for scrolling on this device. pub fn config_scroll_default_natural_scroll_enabled, ffi::libinput_device_config_scroll_get_default_natural_scroll_enabled, bool); ffi_func!( /// Get the current mode for scrolling on this device. pub fn config_scroll_natural_scroll_enabled, ffi::libinput_device_config_scroll_get_natural_scroll_enabled, bool); ffi_func!( /// Return non-zero if the device supports "natural scrolling". /// /// In traditional scroll mode, the movement of fingers on a /// touchpad when scrolling matches the movement of the scroll /// bars. When the fingers move down, the scroll bar moves down, /// a line of text on the screen moves towards the upper end of /// the screen. This also matches scroll wheels on mice (wheel /// down, content moves up). /// /// Natural scrolling is the term coined by Apple for inverted /// scrolling. In this mode, the effect of scrolling movement of /// fingers on a touchpad resemble physical manipulation of /// paper. When the fingers move down, a line of text on the /// screen moves down (scrollbars move up). This is the opposite /// of scroll wheels on mice. /// /// A device supporting natural scrolling can be switched between /// traditional scroll mode and natural scroll mode. pub fn config_scroll_has_natural_scroll, ffi::libinput_device_config_scroll_has_natural_scroll, bool); /// Enable or disable natural scrolling on the device. pub fn config_scroll_set_natural_scroll_enabled( &mut self, enabled: bool, ) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_scroll_set_natural_scroll_enabled( self.as_raw_mut(), enabled as i32, ) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } /// Set the button for the `ScrollMethod::OnButtonDown` method /// for this device. /// /// When the current scroll method is set to /// `ScrollMethod::OnButtonDown`, no button press/release events /// will be send for the configured button. /// /// When the configured button is pressed, any motion events /// along a scroll-capable axis are turned into scroll axis /// events. /// /// ## Note /// /// Setting the button does not change the scroll method. To /// change the scroll method call `config_scroll_set_method`. /// If the button is 0, button scrolling is effectively disabled. pub fn config_scroll_set_button(&mut self, button: u32) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_scroll_set_button(self.as_raw_mut(), button) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } /// Get the current scroll button lock state /// /// If `ScrollMethod::OnButtonDown` is not supported, or no button is set, /// this functions returns `Disabled`. /// /// ## Note /// /// The return value is independent of the currently selected scroll-method. /// For the scroll button lock to activate, a device must have the /// `ScrollMethod::OnButtonDown` enabled, and a non-zero button set as scroll button. #[cfg(feature = "libinput_1_15")] pub fn config_scroll_button_lock(&self) -> ScrollButtonLockState { match unsafe { ffi::libinput_device_config_scroll_get_button_lock(self.as_raw() as *mut _) } { ffi::libinput_config_scroll_button_lock_state_LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED => ScrollButtonLockState::Disabled, ffi::libinput_config_scroll_button_lock_state_LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED => ScrollButtonLockState::Enabled, _ => panic!("libinput returned invalid libinput_config_scroll_button_lock_state"), } } /// Get the default scroll button lock state /// /// If `ScrollMethod::OnButtonDown` is not supported, or no button is set, /// this functions returns `Disabled`. #[cfg(feature = "libinput_1_15")] pub fn config_scroll_default_button_lock(&self) -> ScrollButtonLockState { match unsafe { ffi::libinput_device_config_scroll_get_default_button_lock(self.as_raw() as *mut _) } { ffi::libinput_config_scroll_button_lock_state_LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED => ScrollButtonLockState::Disabled, ffi::libinput_config_scroll_button_lock_state_LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED => ScrollButtonLockState::Enabled, _ => panic!("libinput returned invalid libinput_config_scroll_button_lock_state"), } } /// Set the scroll button lock. /// /// If the state is `Disabled` the button must physically be held down for /// button scrolling to work. If the state is `Enabled`, the button is considered /// logically down after the first press and release sequence, and logically /// up after the second press and release sequence. #[cfg(feature = "libinput_1_15")] pub fn config_scroll_set_button_lock( &mut self, state: ScrollButtonLockState, ) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_scroll_set_button_lock(self.as_raw_mut(), match state { ScrollButtonLockState::Enabled => ffi::libinput_config_scroll_button_lock_state_LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED, ScrollButtonLockState::Disabled => ffi::libinput_config_scroll_button_lock_state_LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED, } ) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } /// Get the send-event mode for this device. /// /// The mode defines when the device processes and sends events /// to the caller. /// /// If a caller enables the bits for multiple modes, some of /// which are subsets of another mode libinput may drop the bits /// that are subsets. In other words, don't expect /// `config_send_events_mode` to always return exactly the same /// as passed into `config_send_events_set_mode`. pub fn config_send_events_mode(&self) -> SendEventsMode { SendEventsMode::from_bits_truncate(unsafe { ffi::libinput_device_config_send_events_get_mode(self.as_raw_mut()) }) } /// Return the possible send-event modes for this device. /// /// These modes define when a device may process and send events. pub fn config_send_events_modes(&self) -> SendEventsMode { SendEventsMode::from_bits_truncate(unsafe { ffi::libinput_device_config_send_events_get_modes(self.as_raw_mut()) }) } /// Set the send-event mode for this device. /// /// The mode defines when the device processes and sends events /// to the caller. /// /// The selected mode may not take effect immediately. Events /// already received and processed from this device are /// unaffected and will be passed to the caller on the next call /// to `::next()`. /// /// If the mode is a mixture of `SendEventsMode`s, the device may /// wait for or generate events until it is in a neutral state. /// For example, this may include waiting for or generating /// button release events. /// /// If the device is already suspended, this function does /// nothing and returns success. Changing the send-event mode on /// a device that has been removed is permitted. pub fn config_send_events_set_mode(&self, mode: SendEventsMode) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_send_events_set_mode(self.as_raw_mut(), mode.bits()) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } /// Get the finger number to button number mapping for /// tap-to-click. /// /// The return value for a device that does not support tapping /// is always `TapButtonMap::LeftRightMiddle`. /// /// This will return `None` for devices /// where `config_tap_finger_count` returns 0. pub fn config_tap_button_map(&self) -> Option { if self.config_tap_finger_count() == 0 { None } else { match unsafe { ffi::libinput_device_config_tap_get_button_map(self.as_raw_mut()) } { ffi::libinput_config_tap_button_map_LIBINPUT_CONFIG_TAP_MAP_LRM => { Some(TapButtonMap::LeftRightMiddle) } ffi::libinput_config_tap_button_map_LIBINPUT_CONFIG_TAP_MAP_LMR => { Some(TapButtonMap::LeftMiddleRight) } _ => panic!("libinput returned invalid 'libinput_config_tap_button_map'"), } } } /// Get the default finger number to button number mapping for /// tap-to-click. /// /// The return value for a device that does not support tapping /// is always `TapButtonMap::LeftRightMiddle`. /// /// This will return `None` for devices /// where `config_tap_finger_count` returns 0. pub fn config_tap_default_button_map(&self) -> Option { if self.config_tap_finger_count() == 0 { None } else { match unsafe { ffi::libinput_device_config_tap_get_default_button_map(self.as_raw_mut()) } { ffi::libinput_config_tap_button_map_LIBINPUT_CONFIG_TAP_MAP_LRM => { Some(TapButtonMap::LeftRightMiddle) } ffi::libinput_config_tap_button_map_LIBINPUT_CONFIG_TAP_MAP_LMR => { Some(TapButtonMap::LeftMiddleRight) } _ => panic!("libinput returned invalid 'libinput_config_tap_button_map'"), } } } /// Return whether tap-and-drag is enabled or disabled by default /// on this device. pub fn config_tap_default_drag_enabled(&self) -> bool { match unsafe { ffi::libinput_device_config_tap_get_default_drag_enabled(self.as_raw_mut()) } { ffi::libinput_config_drag_state_LIBINPUT_CONFIG_DRAG_ENABLED => true, ffi::libinput_config_drag_state_LIBINPUT_CONFIG_DRAG_DISABLED => false, _ => panic!("libinput returned invalid 'libinput_config_drag_state'"), } } /// Check if drag-lock during tapping is enabled by default on /// this device. /// /// If the device does not support tapping, this function always /// returns `false`. /// /// Drag lock may be enabled by default even when tapping is /// disabled by default. pub fn config_tap_default_drag_lock_enabled(&self) -> bool { match unsafe { ffi::libinput_device_config_tap_get_default_drag_lock_enabled(self.as_raw_mut()) } { ffi::libinput_config_drag_lock_state_LIBINPUT_CONFIG_DRAG_LOCK_ENABLED => true, ffi::libinput_config_drag_lock_state_LIBINPUT_CONFIG_DRAG_LOCK_DISABLED => false, _ => panic!("libinput returned invalid 'libinput_config_drag_lock_state'"), } } /// Return the default setting for whether tap-to-click is /// enabled on this device. pub fn config_tap_default_enabled(&self) -> bool { match unsafe { ffi::libinput_device_config_tap_get_default_enabled(self.as_raw_mut()) } { ffi::libinput_config_tap_state_LIBINPUT_CONFIG_TAP_ENABLED => true, ffi::libinput_config_tap_state_LIBINPUT_CONFIG_TAP_DISABLED => false, _ => panic!("libinput returned invalid 'libinput_config_tap_state'"), } } /// Return whether tap-and-drag is enabled or disabled on this /// device. pub fn config_tap_drag_enabled(&self) -> bool { match unsafe { ffi::libinput_device_config_tap_get_drag_enabled(self.as_raw_mut()) } { ffi::libinput_config_drag_state_LIBINPUT_CONFIG_DRAG_ENABLED => true, ffi::libinput_config_drag_state_LIBINPUT_CONFIG_DRAG_DISABLED => false, _ => panic!("libinput returned invalid 'libinput_config_drag_state'"), } } /// Check if drag-lock during tapping is enabled on this device. /// /// If the device does not support tapping, this function always /// returns `false`. /// /// Drag lock may be enabled even when tapping is disabled. pub fn config_tap_drag_lock_enabled(&self) -> bool { match unsafe { ffi::libinput_device_config_tap_get_drag_lock_enabled(self.as_raw_mut()) } { ffi::libinput_config_drag_lock_state_LIBINPUT_CONFIG_DRAG_LOCK_ENABLED => true, ffi::libinput_config_drag_lock_state_LIBINPUT_CONFIG_DRAG_LOCK_DISABLED => false, _ => panic!("libinput returned invalid 'libinput_config_drag_lock_state'"), } } /// Check if tap-to-click is enabled on this device. /// /// If the device does not support tapping, this function always /// returns `false`. pub fn config_tap_enabled(&self) -> bool { match unsafe { ffi::libinput_device_config_tap_get_enabled(self.as_raw_mut()) } { ffi::libinput_config_tap_state_LIBINPUT_CONFIG_TAP_ENABLED => true, ffi::libinput_config_tap_state_LIBINPUT_CONFIG_TAP_DISABLED => false, _ => panic!("libinput returned invalid 'libinput_config_tap_state'"), } } ffi_func!( /// Check if the device supports tap-to-click and how many /// fingers can be used for tapping. /// /// See `config_tap_set_enabled` for more information. pub fn config_tap_finger_count, ffi::libinput_device_config_tap_get_finger_count, u32); /// Set the finger number to button number mapping for /// tap-to-click. /// /// The default mapping on most devices is to have a 1, 2 and 3 /// finger tap to map to the left, right and middle button, /// respectively. A device may permit changing the button mapping /// but disallow specific maps. In this case /// `DeviceConfigError::Disabled` is returned, the caller is /// expected to handle this case correctly. /// /// Changing the button mapping may not take effect immediately, /// the device may wait until it is in a neutral state before /// applying any changes. /// /// The mapping may be changed when tap-to-click is disabled. The /// new mapping takes effect when tap-to-click is enabled in the /// future. /// /// ## Note /// /// This will return `None` for devices where /// `config_tap_finger_count` returns 0. pub fn config_tap_set_button_map(&mut self, map: TapButtonMap) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_tap_set_button_map( self.as_raw_mut(), match map { TapButtonMap::LeftRightMiddle => { ffi::libinput_config_tap_button_map_LIBINPUT_CONFIG_TAP_MAP_LRM } TapButtonMap::LeftMiddleRight => { ffi::libinput_config_tap_button_map_LIBINPUT_CONFIG_TAP_MAP_LMR } }, ) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } /// Enable or disable tap-and-drag on this device. /// /// When enabled, a single-finger tap immediately followed by a /// finger down results in a button down event, subsequent finger /// motion thus triggers a drag. The button is released on finger /// up. /// See [Tap-and-drag](https://wayland.freedesktop.org/libinput/doc/latest/tapping.html#tapndrag) /// for more details. pub fn config_tap_set_drag_enabled(&mut self, enabled: bool) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_tap_set_drag_enabled( self.as_raw_mut(), if enabled { ffi::libinput_config_drag_state_LIBINPUT_CONFIG_DRAG_ENABLED } else { ffi::libinput_config_drag_state_LIBINPUT_CONFIG_DRAG_DISABLED }, ) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } /// Enable or disable drag-lock during tapping on this device. /// /// When enabled, a finger may be lifted and put back on the /// touchpad within a timeout and the drag process continues. /// When disabled, lifting the finger during a tap-and-drag will /// immediately stop the drag. /// See [Tap-and-drag](https://wayland.freedesktop.org/libinput/doc/latest/tapping.html#tapndrag) /// for details. /// /// Enabling drag lock on a device that has tapping disabled is /// permitted, but has no effect until tapping is enabled. pub fn config_tap_set_drag_lock_enabled(&mut self, enabled: bool) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_tap_set_drag_lock_enabled( self.as_raw_mut(), if enabled { ffi::libinput_config_drag_lock_state_LIBINPUT_CONFIG_DRAG_LOCK_ENABLED } else { ffi::libinput_config_drag_lock_state_LIBINPUT_CONFIG_DRAG_LOCK_DISABLED }, ) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } /// Enable or disable tap-to-click on this device, with a default /// mapping of 1, 2, 3 finger tap mapping to left, right, middle /// click, respectively. /// /// Tapping is limited by the number of simultaneous touches /// supported by the device, see `config_tap_finger_count`. pub fn config_tap_set_enabled(&mut self, enabled: bool) -> DeviceConfigResult { match unsafe { ffi::libinput_device_config_tap_set_enabled( self.as_raw_mut(), if enabled { ffi::libinput_config_tap_state_LIBINPUT_CONFIG_TAP_ENABLED } else { ffi::libinput_config_tap_state_LIBINPUT_CONFIG_TAP_DISABLED }, ) } { ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_SUCCESS => Ok(()), ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_UNSUPPORTED => { Err(DeviceConfigError::Unsupported) } ffi::libinput_config_status_LIBINPUT_CONFIG_STATUS_INVALID => { Err(DeviceConfigError::Invalid) } _ => panic!("libinput returned invalid 'libinput_config_status'"), } } } input-0.9.0/src/event/device.rs000064400000000000000000000062631046102023000145150ustar 00000000000000//! Device event types use super::EventTrait; use crate::{ffi, AsRaw, Context, FromRaw, Libinput}; /// Common functions all Device-Events implement. pub trait DeviceEventTrait: AsRaw + Context { /// Convert into a general `DeviceEvent` again fn into_device_event(self) -> DeviceEvent where Self: Sized, { unsafe { DeviceEvent::from_raw(self.as_raw_mut(), self.context()) } } } impl + Context> DeviceEventTrait for T {} /// A device related `Event` #[derive(Debug, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum DeviceEvent { /// Signals that a device has been added to the context. Added(DeviceAddedEvent), /// Signals that a device has been removed. Removed(DeviceRemovedEvent), } impl EventTrait for DeviceEvent { #[doc(hidden)] fn as_raw_event(&self) -> *mut ffi::libinput_event { match self { DeviceEvent::Added(event) => event.as_raw_event(), DeviceEvent::Removed(event) => event.as_raw_event(), } } } impl FromRaw for DeviceEvent { unsafe fn try_from_raw( event: *mut ffi::libinput_event_device_notify, context: &Libinput, ) -> Option { let base = ffi::libinput_event_device_notify_get_base_event(event); match ffi::libinput_event_get_type(base) { ffi::libinput_event_type_LIBINPUT_EVENT_DEVICE_ADDED => Some(DeviceEvent::Added( DeviceAddedEvent::try_from_raw(event, context)?, )), ffi::libinput_event_type_LIBINPUT_EVENT_DEVICE_REMOVED => Some(DeviceEvent::Removed( DeviceRemovedEvent::try_from_raw(event, context)?, )), _ => None, } } unsafe fn from_raw(event: *mut ffi::libinput_event_device_notify, context: &Libinput) -> Self { Self::try_from_raw(event, context).expect("Unknown libinput_event_device type") } } impl AsRaw for DeviceEvent { fn as_raw(&self) -> *const ffi::libinput_event_device_notify { match self { DeviceEvent::Added(event) => event.as_raw(), DeviceEvent::Removed(event) => event.as_raw(), } } } impl Context for DeviceEvent { fn context(&self) -> &Libinput { match self { DeviceEvent::Added(event) => event.context(), DeviceEvent::Removed(event) => event.context(), } } } ffi_event_struct! { /// Signals that a device has been added to the context. /// /// The device will not be read until the next time the user calls /// `Libinput::dispatch` and data is available. /// /// This allows setting up initial device configuration before any events are created. struct DeviceAddedEvent, ffi::libinput_event_device_notify, ffi::libinput_event_device_notify_get_base_event } ffi_event_struct! { /// Signals that a device has been removed. /// /// No more events from the associated device will be in the queue or be queued after this event. struct DeviceRemovedEvent, ffi::libinput_event_device_notify, ffi::libinput_event_device_notify_get_base_event } input-0.9.0/src/event/gesture.rs000064400000000000000000000505511046102023000147330ustar 00000000000000//! Gesture event types use super::EventTrait; use crate::{ffi, AsRaw, Context, FromRaw, Libinput}; /// Common functions all Gesture-Events implement. pub trait GestureEventTrait: AsRaw + Context { ffi_func!( /// The event time for this event fn time, ffi::libinput_event_gesture_get_time, u32); ffi_func!( /// The event time for this event in microseconds fn time_usec, ffi::libinput_event_gesture_get_time_usec, u64); ffi_func!( /// Return the number of fingers used for a gesture. /// /// This can be used e.g. to differentiate between 3 or 4 finger swipes. /// /// This function can be called on all gesture events and the returned finger /// count value will not change during a sequence. fn finger_count, ffi::libinput_event_gesture_get_finger_count, i32); /// Convert into a general `GestureEvent` again fn into_gesture_event(self) -> GestureEvent where Self: Sized, { unsafe { GestureEvent::from_raw(self.as_raw_mut(), self.context()) } } } impl + Context> GestureEventTrait for T {} /// A gesture related `Event` #[derive(Debug, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum GestureEvent { /// A swipe gesture `Event` Swipe(GestureSwipeEvent), /// A pinch gesture `Event` Pinch(GesturePinchEvent), #[cfg(feature = "libinput_1_19")] /// A hold gesture `Event` Hold(GestureHoldEvent), } impl EventTrait for GestureEvent { #[doc(hidden)] fn as_raw_event(&self) -> *mut ffi::libinput_event { match self { GestureEvent::Swipe(event) => event.as_raw_event(), GestureEvent::Pinch(event) => event.as_raw_event(), #[cfg(feature = "libinput_1_19")] GestureEvent::Hold(event) => event.as_raw_event(), } } } impl FromRaw for GestureEvent { unsafe fn try_from_raw( event: *mut ffi::libinput_event_gesture, context: &Libinput, ) -> Option { let base = ffi::libinput_event_gesture_get_base_event(event); match ffi::libinput_event_get_type(base) { ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_END => Some( GestureEvent::Swipe(GestureSwipeEvent::try_from_raw(event, context)?), ), ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_BEGIN | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_UPDATE | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_END => Some( GestureEvent::Pinch(GesturePinchEvent::try_from_raw(event, context)?), ), #[cfg(feature = "libinput_1_19")] ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_HOLD_BEGIN | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_HOLD_END => Some(GestureEvent::Hold( GestureHoldEvent::try_from_raw(event, context)?, )), _ => None, } } unsafe fn from_raw(event: *mut ffi::libinput_event_gesture, context: &Libinput) -> Self { Self::try_from_raw(event, context).expect("Unknown gesture event type") } } impl AsRaw for GestureEvent { fn as_raw(&self) -> *const ffi::libinput_event_gesture { match self { GestureEvent::Swipe(event) => event.as_raw(), GestureEvent::Pinch(event) => event.as_raw(), #[cfg(feature = "libinput_1_19")] GestureEvent::Hold(event) => event.as_raw(), } } } impl Context for GestureEvent { fn context(&self) -> &Libinput { match self { GestureEvent::Swipe(event) => event.context(), GestureEvent::Pinch(event) => event.context(), #[cfg(feature = "libinput_1_19")] GestureEvent::Hold(event) => event.context(), } } } /// Common functions for Gesture-Events having coordinates. pub trait GestureEventCoordinates: AsRaw { ffi_func!( /// Return the delta between the last event and the current event. /// /// If a device employs pointer acceleration, the delta returned by this /// function is the accelerated delta. /// /// Relative motion deltas are normalized to represent those of a device with /// 1000dpi resolution. See [Normalization of relative motion](https://wayland.freedesktop.org/libinput/doc/latest/motion_normalization.html) /// for more details. fn dx, ffi::libinput_event_gesture_get_dx, f64); ffi_func!( /// Return the relative delta of the unaccelerated motion vector of the /// current event. /// /// Relative unaccelerated motion deltas are normalized to represent those of /// a device with 1000dpi resolution. See [Normalization of relative motion](https://wayland.freedesktop.org/libinput/doc/latest/motion_normalization.html) /// for more details. Note that unaccelerated events are not equivalent to /// 'raw' events as read from the device. /// /// Any rotation applied to the device also applies to gesture motion (see /// `rotation_set_angle`). fn dx_unaccelerated, ffi::libinput_event_gesture_get_dx_unaccelerated, f64); ffi_func!( /// Return the delta between the last event and the current event. /// /// If a device employs pointer acceleration, the delta returned by this /// function is the accelerated delta. /// /// Relative motion deltas are normalized to represent those of a device with /// 1000dpi resolution. See [Normalization of relative motion](https://wayland.freedesktop.org/libinput/doc/latest/motion_normalization.html) /// for more details. fn dy, ffi::libinput_event_gesture_get_dy, f64); ffi_func!( /// Return the relative delta of the unaccelerated motion vector of the /// current event. /// /// Relative unaccelerated motion deltas are normalized to represent those of /// a device with 1000dpi resolution. See [Normalization of relative motion](https://wayland.freedesktop.org/libinput/doc/latest/motion_normalization.html) /// for more details. Note that unaccelerated events are not equivalent to /// 'raw' events as read from the device. /// /// Any rotation applied to the device also applies to gesture motion (see /// `rotation_set_angle`). fn dy_unaccelerated, ffi::libinput_event_gesture_get_dy_unaccelerated, f64); } /// Common functions for events noting the end of a gesture pub trait GestureEndEvent: AsRaw { ffi_func!( /// Return if the gesture ended normally, or if it was cancelled. fn cancelled, ffi::libinput_event_gesture_get_cancelled, bool); } /// Events for swipe gestures #[derive(Debug, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum GestureSwipeEvent { /// Swipe gesture began Begin(GestureSwipeBeginEvent), /// In-progress swipe gesture updated Update(GestureSwipeUpdateEvent), /// Swipe gesture ended End(GestureSwipeEndEvent), } /// Common functions for swipe gesture events pub trait GestureSwipeEventTrait: AsRaw + Context { /// Convert into a general `GestureSwipeEvent` fn into_gesture_swipe_event(self) -> GestureSwipeEvent where Self: Sized, { unsafe { GestureSwipeEvent::from_raw(self.as_raw_mut(), self.context()) } } } impl GestureSwipeEventTrait for GestureSwipeEvent {} impl EventTrait for GestureSwipeEvent { #[doc(hidden)] fn as_raw_event(&self) -> *mut ffi::libinput_event { match self { GestureSwipeEvent::Begin(event) => event.as_raw_event(), GestureSwipeEvent::Update(event) => event.as_raw_event(), GestureSwipeEvent::End(event) => event.as_raw_event(), } } } impl FromRaw for GestureSwipeEvent { unsafe fn try_from_raw( event: *mut ffi::libinput_event_gesture, context: &Libinput, ) -> Option { let base = ffi::libinput_event_gesture_get_base_event(event); match ffi::libinput_event_get_type(base) { ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN => Some( GestureSwipeEvent::Begin(GestureSwipeBeginEvent::try_from_raw(event, context)?), ), ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE => Some( GestureSwipeEvent::Update(GestureSwipeUpdateEvent::try_from_raw(event, context)?), ), ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_END => Some( GestureSwipeEvent::End(GestureSwipeEndEvent::try_from_raw(event, context)?), ), ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_BEGIN | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_UPDATE | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_END => { panic!("Tried to make GestureSwipeEvent from Pinch event") } #[cfg(feature = "libinput_1_19")] ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_HOLD_BEGIN | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_HOLD_END => { panic!("Tried to make GestureSwipeEvent from Hold event") } _ => None, } } unsafe fn from_raw(event: *mut ffi::libinput_event_gesture, context: &Libinput) -> Self { Self::try_from_raw(event, context).expect("Unknown gesture event type") } } impl AsRaw for GestureSwipeEvent { fn as_raw(&self) -> *const ffi::libinput_event_gesture { match self { GestureSwipeEvent::Begin(event) => event.as_raw(), GestureSwipeEvent::Update(event) => event.as_raw(), GestureSwipeEvent::End(event) => event.as_raw(), } } } impl Context for GestureSwipeEvent { fn context(&self) -> &Libinput { match self { GestureSwipeEvent::Begin(event) => event.context(), GestureSwipeEvent::Update(event) => event.context(), GestureSwipeEvent::End(event) => event.context(), } } } /// Events for pinch gestures #[derive(Debug, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum GesturePinchEvent { /// Pinch gesture began Begin(GesturePinchBeginEvent), /// In-progress pinch gesture updated Update(GesturePinchUpdateEvent), /// Pinch gesture ended End(GesturePinchEndEvent), } impl EventTrait for GesturePinchEvent { #[doc(hidden)] fn as_raw_event(&self) -> *mut ffi::libinput_event { match self { GesturePinchEvent::Begin(event) => event.as_raw_event(), GesturePinchEvent::Update(event) => event.as_raw_event(), GesturePinchEvent::End(event) => event.as_raw_event(), } } } /// Common functions for pinch gesture events pub trait GesturePinchEventTrait: AsRaw + Context { ffi_func!( /// Return the absolute scale of a pinch gesture, the scale is the division of /// the current distance between the fingers and the distance at the start of /// the gesture. /// /// The scale begins at 1.0, and if e.g. the fingers moved together by 50% /// then the scale will become 0.5, if they move twice as far apart as /// initially the scale becomes 2.0, etc. /// /// For gesture events that are of type `GesturePinchBeginEvent`, this function /// returns 1.0. /// For gesture events that are of type `GesturePinchEndEvent`, this function /// returns the scale value of the most recent `GesturePinchUpdateEvent` event /// (if any) or 1.0 otherwise. fn scale, ffi::libinput_event_gesture_get_scale, f64); /// Convert into a general `GesturePinchEvent` fn into_gesture_pinch_event(self) -> GesturePinchEvent where Self: Sized, { unsafe { GesturePinchEvent::from_raw(self.as_raw_mut(), self.context()) } } } impl GesturePinchEventTrait for GesturePinchEvent {} impl FromRaw for GesturePinchEvent { unsafe fn try_from_raw( event: *mut ffi::libinput_event_gesture, context: &Libinput, ) -> Option { let base = ffi::libinput_event_gesture_get_base_event(event); match ffi::libinput_event_get_type(base) { ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_END => { panic!("Tried to make GesturePinchEvent from Swipe event") } #[cfg(feature = "libinput_1_19")] ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_HOLD_BEGIN | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_HOLD_END => { panic!("Tried to make GestureSwipeEvent from Hold event") } ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_BEGIN => Some( GesturePinchEvent::Begin(GesturePinchBeginEvent::try_from_raw(event, context)?), ), ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_UPDATE => Some( GesturePinchEvent::Update(GesturePinchUpdateEvent::try_from_raw(event, context)?), ), ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_END => Some( GesturePinchEvent::End(GesturePinchEndEvent::try_from_raw(event, context)?), ), _ => None, } } unsafe fn from_raw(event: *mut ffi::libinput_event_gesture, context: &Libinput) -> Self { Self::try_from_raw(event, context).expect("Unknown gesture event type") } } impl AsRaw for GesturePinchEvent { fn as_raw(&self) -> *const ffi::libinput_event_gesture { match self { GesturePinchEvent::Begin(event) => event.as_raw(), GesturePinchEvent::Update(event) => event.as_raw(), GesturePinchEvent::End(event) => event.as_raw(), } } } impl Context for GesturePinchEvent { fn context(&self) -> &Libinput { match self { GesturePinchEvent::Begin(event) => event.context(), GesturePinchEvent::Update(event) => event.context(), GesturePinchEvent::End(event) => event.context(), } } } #[cfg(feature = "libinput_1_19")] #[derive(Debug, PartialEq, Eq, Hash)] #[non_exhaustive] /// Events for hold gestures pub enum GestureHoldEvent { /// Hold gesture began Begin(GestureHoldBeginEvent), /// Hold gesture ended End(GestureHoldEndEvent), } #[cfg(feature = "libinput_1_19")] impl EventTrait for GestureHoldEvent { #[doc(hidden)] fn as_raw_event(&self) -> *mut ffi::libinput_event { match self { GestureHoldEvent::Begin(event) => event.as_raw_event(), GestureHoldEvent::End(event) => event.as_raw_event(), } } } #[cfg(feature = "libinput_1_19")] /// Common functions for hold gesture events pub trait GestureHoldEventTrait: AsRaw + Context { /// Convert into a general `GesturePinchEvent` fn into_gesture_hold_event(self) -> GestureHoldEvent where Self: Sized, { unsafe { GestureHoldEvent::from_raw(self.as_raw_mut(), self.context()) } } } #[cfg(feature = "libinput_1_19")] impl GestureHoldEventTrait for GestureHoldEvent {} #[cfg(feature = "libinput_1_19")] impl FromRaw for GestureHoldEvent { unsafe fn try_from_raw( event: *mut ffi::libinput_event_gesture, context: &Libinput, ) -> Option { let base = ffi::libinput_event_gesture_get_base_event(event); match ffi::libinput_event_get_type(base) { ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_END => { panic!("Tried to make GesturePinchEvent from Swipe event") } ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_BEGIN | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_UPDATE | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_END => { panic!("Tried to make GestureSwipeEvent from Pinch event") } ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_HOLD_BEGIN => Some( GestureHoldEvent::Begin(GestureHoldBeginEvent::try_from_raw(event, context)?), ), ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_HOLD_END => Some( GestureHoldEvent::End(GestureHoldEndEvent::try_from_raw(event, context)?), ), _ => None, } } unsafe fn from_raw(event: *mut ffi::libinput_event_gesture, context: &Libinput) -> Self { Self::try_from_raw(event, context).expect("Unknown gesture event type") } } #[cfg(feature = "libinput_1_19")] impl AsRaw for GestureHoldEvent { fn as_raw(&self) -> *const ffi::libinput_event_gesture { match self { GestureHoldEvent::Begin(event) => event.as_raw(), GestureHoldEvent::End(event) => event.as_raw(), } } } #[cfg(feature = "libinput_1_19")] impl Context for GestureHoldEvent { fn context(&self) -> &Libinput { match self { GestureHoldEvent::Begin(event) => event.context(), GestureHoldEvent::End(event) => event.context(), } } } ffi_event_struct!( /// Swipe gesture began struct GestureSwipeBeginEvent, ffi::libinput_event_gesture, ffi::libinput_event_gesture_get_base_event); impl GestureSwipeEventTrait for GestureSwipeBeginEvent {} ffi_event_struct!( /// In-progress swipe gesture updated struct GestureSwipeUpdateEvent, ffi::libinput_event_gesture, ffi::libinput_event_gesture_get_base_event); impl GestureSwipeEventTrait for GestureSwipeUpdateEvent {} impl GestureEventCoordinates for GestureSwipeUpdateEvent {} ffi_event_struct!( /// Swipe gesture ended struct GestureSwipeEndEvent, ffi::libinput_event_gesture, ffi::libinput_event_gesture_get_base_event); impl GestureEndEvent for GestureSwipeEndEvent {} impl GestureSwipeEventTrait for GestureSwipeEndEvent {} ffi_event_struct!( /// Pinch gesture began struct GesturePinchBeginEvent, ffi::libinput_event_gesture, ffi::libinput_event_gesture_get_base_event); impl GesturePinchEventTrait for GesturePinchBeginEvent {} ffi_event_struct!( /// In-progress pinch gesture updated struct GesturePinchUpdateEvent, ffi::libinput_event_gesture, ffi::libinput_event_gesture_get_base_event); impl GesturePinchEventTrait for GesturePinchUpdateEvent {} impl GestureEventCoordinates for GesturePinchUpdateEvent {} impl GesturePinchUpdateEvent { ffi_func!( /// Return the angle delta in degrees between the last and the current /// `GesturePinchUpdateEvent`. /// /// The angle delta is defined as the change in angle of the line formed by /// the 2 fingers of a pinch gesture. Clockwise rotation is represented by a /// positive delta, counter-clockwise by a negative delta. If e.g. the fingers /// are on the 12 and 6 location of a clock face plate and they move to the 1 /// resp. 7 location in a single event then the angle delta is 30 degrees. /// /// If more than two fingers are present, the angle represents the rotation /// around the center of gravity. The calculation of the center of gravity is /// implementation-dependent. pub fn angle_delta, ffi::libinput_event_gesture_get_angle_delta, f64); } ffi_event_struct!( /// Pinch gesture ended struct GesturePinchEndEvent, ffi::libinput_event_gesture, ffi::libinput_event_gesture_get_base_event); impl GesturePinchEventTrait for GesturePinchEndEvent {} impl GestureEndEvent for GesturePinchEndEvent {} #[cfg(feature = "libinput_1_19")] ffi_event_struct!( /// Hold gesture began struct GestureHoldBeginEvent, ffi::libinput_event_gesture, ffi::libinput_event_gesture_get_base_event); #[cfg(feature = "libinput_1_19")] impl GestureHoldEventTrait for GestureHoldBeginEvent {} #[cfg(feature = "libinput_1_19")] ffi_event_struct!( /// Hold gesture ended struct GestureHoldEndEvent, ffi::libinput_event_gesture, ffi::libinput_event_gesture_get_base_event); #[cfg(feature = "libinput_1_19")] impl GestureEndEvent for GestureHoldEndEvent {} #[cfg(feature = "libinput_1_19")] impl GestureHoldEventTrait for GestureHoldEndEvent {} input-0.9.0/src/event/keyboard.rs000064400000000000000000000066111046102023000150530ustar 00000000000000//! Keyboard event types use super::EventTrait; use crate::{ffi, AsRaw, Context, FromRaw, Libinput}; /// State of a Key #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum KeyState { /// Key is pressed Pressed, /// Key is released Released, } /// Common functions for all Keyboard-Events implement. pub trait KeyboardEventTrait: AsRaw + Context { ffi_func!( /// The event time for this event fn time, ffi::libinput_event_keyboard_get_time, u32); ffi_func!( /// The event time for this event in microseconds fn time_usec, ffi::libinput_event_keyboard_get_time_usec, u64); ffi_func!( /// The keycode that triggered this key event fn key, ffi::libinput_event_keyboard_get_key, u32); /// The state change of the key fn key_state(&self) -> KeyState { match unsafe { ffi::libinput_event_keyboard_get_key_state(self.as_raw() as *mut _) } { ffi::libinput_key_state_LIBINPUT_KEY_STATE_PRESSED => KeyState::Pressed, ffi::libinput_key_state_LIBINPUT_KEY_STATE_RELEASED => KeyState::Released, _ => panic!("libinput returned invalid 'libinput_key_state'"), } } /// Convert into a general `KeyboardEvent` again fn into_keyboard_event(self) -> KeyboardEvent where Self: Sized, { unsafe { KeyboardEvent::from_raw(self.as_raw_mut(), self.context()) } } } impl + Context> KeyboardEventTrait for T {} /// A keyboard related `Event` #[derive(Debug, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum KeyboardEvent { /// An event related to pressing a key Key(KeyboardKeyEvent), } impl EventTrait for KeyboardEvent { #[doc(hidden)] fn as_raw_event(&self) -> *mut ffi::libinput_event { match self { KeyboardEvent::Key(event) => event.as_raw_event(), } } } impl FromRaw for KeyboardEvent { unsafe fn try_from_raw( event: *mut ffi::libinput_event_keyboard, context: &Libinput, ) -> Option { let base = ffi::libinput_event_keyboard_get_base_event(event); match ffi::libinput_event_get_type(base) { ffi::libinput_event_type_LIBINPUT_EVENT_KEYBOARD_KEY => Some(KeyboardEvent::Key( KeyboardKeyEvent::try_from_raw(event, context)?, )), _ => None, } } unsafe fn from_raw(event: *mut ffi::libinput_event_keyboard, context: &Libinput) -> Self { Self::try_from_raw(event, context).expect("Unknown key event type") } } impl AsRaw for KeyboardEvent { fn as_raw(&self) -> *const ffi::libinput_event_keyboard { match self { KeyboardEvent::Key(event) => event.as_raw(), } } } impl Context for KeyboardEvent { fn context(&self) -> &Libinput { match self { KeyboardEvent::Key(event) => event.context(), } } } ffi_event_struct!( /// An event related to pressing a key struct KeyboardKeyEvent, ffi::libinput_event_keyboard, ffi::libinput_event_keyboard_get_base_event); impl KeyboardKeyEvent { ffi_func!( /// For the key of a `KeyboardKeyEvent` event, return the total number of keys /// pressed on all devices on the associated seat after the event was triggered. pub fn seat_key_count, ffi::libinput_event_keyboard_get_seat_key_count, u32); } input-0.9.0/src/event/pointer.rs000064400000000000000000000611141046102023000147320ustar 00000000000000//! Pointer event types #![allow(deprecated)] use super::EventTrait; use crate::{ffi, AsRaw, Context, FromRaw, Libinput}; /// Common functions for all Pointer-Events implement. pub trait PointerEventTrait: AsRaw + Context { ffi_func!( /// The event time for this event fn time, ffi::libinput_event_pointer_get_time, u32); ffi_func!( /// The event time for this event in microseconds fn time_usec, ffi::libinput_event_pointer_get_time_usec, u64); /// Convert into a general `TouchEvent` again fn into_pointer_event(self) -> PointerEvent where Self: Sized, { unsafe { PointerEvent::from_raw(self.as_raw_mut(), self.context()) } } } impl + Context> PointerEventTrait for T {} /// A pointer related `Event` #[derive(Debug, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum PointerEvent { /// An event related to moving a pointer Motion(PointerMotionEvent), /// An event related to absolute pointer movement MotionAbsolute(PointerMotionAbsoluteEvent), /// An event related to button pressed on a pointer device Button(PointerButtonEvent), /// An event related to moving axis on a pointer device #[cfg_attr( feature = "libinput_1_19", deprecated = "Use `PointerEvent::Scroll*` events instead" )] Axis(PointerAxisEvent), /// A scroll event from a wheel. #[cfg(feature = "libinput_1_19")] ScrollWheel(PointerScrollWheelEvent), /// A scroll event caused by the movement of one or more fingers on a device. #[cfg(feature = "libinput_1_19")] ScrollFinger(PointerScrollFingerEvent), /// A scroll event from a continuous scroll source, e.g. button scrolling. #[cfg(feature = "libinput_1_19")] ScrollContinuous(PointerScrollContinuousEvent), } impl EventTrait for PointerEvent { #[doc(hidden)] fn as_raw_event(&self) -> *mut ffi::libinput_event { match self { PointerEvent::Motion(event) => event.as_raw_event(), PointerEvent::MotionAbsolute(event) => event.as_raw_event(), PointerEvent::Button(event) => event.as_raw_event(), PointerEvent::Axis(event) => event.as_raw_event(), #[cfg(feature = "libinput_1_19")] PointerEvent::ScrollWheel(event) => event.as_raw_event(), #[cfg(feature = "libinput_1_19")] PointerEvent::ScrollFinger(event) => event.as_raw_event(), #[cfg(feature = "libinput_1_19")] PointerEvent::ScrollContinuous(event) => event.as_raw_event(), } } } impl FromRaw for PointerEvent { unsafe fn try_from_raw( event: *mut ffi::libinput_event_pointer, context: &Libinput, ) -> Option { let base = ffi::libinput_event_pointer_get_base_event(event); match ffi::libinput_event_get_type(base) { ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_MOTION => Some(PointerEvent::Motion( PointerMotionEvent::try_from_raw(event, context)?, )), ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE => { Some(PointerEvent::MotionAbsolute( PointerMotionAbsoluteEvent::try_from_raw(event, context)?, )) } ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_BUTTON => Some(PointerEvent::Button( PointerButtonEvent::try_from_raw(event, context)?, )), ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_AXIS => Some(PointerEvent::Axis( PointerAxisEvent::try_from_raw(event, context)?, )), #[cfg(feature = "libinput_1_19")] ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_SCROLL_WHEEL => Some( PointerEvent::ScrollWheel(PointerScrollWheelEvent::try_from_raw(event, context)?), ), #[cfg(feature = "libinput_1_19")] ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_SCROLL_FINGER => Some( PointerEvent::ScrollFinger(PointerScrollFingerEvent::try_from_raw(event, context)?), ), #[cfg(feature = "libinput_1_19")] ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS => { Some(PointerEvent::ScrollContinuous( PointerScrollContinuousEvent::try_from_raw(event, context)?, )) } _ => None, } } unsafe fn from_raw(event: *mut ffi::libinput_event_pointer, context: &Libinput) -> Self { Self::try_from_raw(event, context).expect("Unknown pointer event type") } } impl AsRaw for PointerEvent { fn as_raw(&self) -> *const ffi::libinput_event_pointer { match self { PointerEvent::Motion(event) => event.as_raw(), PointerEvent::MotionAbsolute(event) => event.as_raw(), PointerEvent::Button(event) => event.as_raw(), PointerEvent::Axis(event) => event.as_raw(), #[cfg(feature = "libinput_1_19")] PointerEvent::ScrollWheel(event) => event.as_raw(), #[cfg(feature = "libinput_1_19")] PointerEvent::ScrollFinger(event) => event.as_raw(), #[cfg(feature = "libinput_1_19")] PointerEvent::ScrollContinuous(event) => event.as_raw(), } } } impl Context for PointerEvent { fn context(&self) -> &Libinput { match self { PointerEvent::Motion(event) => event.context(), PointerEvent::MotionAbsolute(event) => event.context(), PointerEvent::Button(event) => event.context(), PointerEvent::Axis(event) => event.context(), #[cfg(feature = "libinput_1_19")] PointerEvent::ScrollWheel(event) => event.context(), #[cfg(feature = "libinput_1_19")] PointerEvent::ScrollFinger(event) => event.context(), #[cfg(feature = "libinput_1_19")] PointerEvent::ScrollContinuous(event) => event.context(), } } } ffi_event_struct!( /// An event related to moving a pointer struct PointerMotionEvent, ffi::libinput_event_pointer, ffi::libinput_event_pointer_get_base_event); impl PointerMotionEvent { ffi_func!( /// Return the delta between the last event and the current event. /// /// If a device employs pointer acceleration, the delta returned by this /// function is the accelerated delta. /// /// Relative motion deltas are to be interpreted as pixel movement of a /// standardized mouse. See [Normalization of relative motion](https://wayland.freedesktop.org/libinput/doc/latest/motion_normalization.html) /// for more details. pub fn dx, ffi::libinput_event_pointer_get_dx, f64); ffi_func!( /// Return the relative delta of the unaccelerated motion vector of the /// current event. /// /// Relative unaccelerated motion deltas are raw device coordinates. Note that /// these coordinates are subject to the device's native resolution. Touchpad /// coordinates represent raw device coordinates in the X resolution of the /// touchpad. See [Normalization of relative motion](https://wayland.freedesktop.org/libinput/doc/latest/motion_normalization.html) /// for more details. /// /// Any rotation applied to the device also applies to unaccelerated motion /// (see `Device::rotation_set_angle`). pub fn dx_unaccelerated, ffi::libinput_event_pointer_get_dx_unaccelerated, f64); ffi_func!( /// Return the delta between the last event and the current event. /// /// If a device employs pointer acceleration, the delta returned by this /// function is the accelerated delta. /// /// Relative motion deltas are to be interpreted as pixel movement of a /// standardized mouse. See [Normalization of relative motion](https://wayland.freedesktop.org/libinput/doc/latest/motion_normalization.html) /// for more details. pub fn dy, ffi::libinput_event_pointer_get_dy, f64); ffi_func!( /// Return the relative delta of the unaccelerated motion vector of the /// current event. /// /// Relative unaccelerated motion deltas are raw device coordinates. Note that /// these coordinates are subject to the device's native resolution. Touchpad /// coordinates represent raw device coordinates in the X resolution of the /// touchpad. See [Normalization of relative motion](https://wayland.freedesktop.org/libinput/doc/latest/motion_normalization.html) /// for more details. /// /// Any rotation applied to the device also applies to unaccelerated motion /// (see `Device::rotation_set_angle`). pub fn dy_unaccelerated, ffi::libinput_event_pointer_get_dy_unaccelerated, f64); } ffi_event_struct!( /// An event related to absolute pointer movement struct PointerMotionAbsoluteEvent, ffi::libinput_event_pointer, ffi::libinput_event_pointer_get_base_event); impl PointerMotionAbsoluteEvent { ffi_func!( /// Return the current absolute x coordinate of the pointer event, in mm from /// the top left corner of the device. /// /// To get the corresponding output screen coordinate, use /// `absolute_x_transformed`. pub fn absolute_x, ffi::libinput_event_pointer_get_absolute_x, f64); ffi_func!( /// Return the current absolute y coordinate of the pointer event, in mm from /// the top left corner of the device. /// /// To get the corresponding output screen coordinate, use /// `absolute_y_transformed`. pub fn absolute_y, ffi::libinput_event_pointer_get_absolute_y, f64); /// Return the current absolute x coordinate of the pointer event, transformed /// to screen coordinates. /// /// ## Arguments /// /// - width - The current output screen width pub fn absolute_x_transformed(&self, width: u32) -> f64 { unsafe { ffi::libinput_event_pointer_get_absolute_x_transformed(self.as_raw_mut(), width) } } /// Return the current absolute y coordinate of the pointer event, transformed /// to screen coordinates. /// /// ## Arguments /// /// - height - The current output screen height pub fn absolute_y_transformed(&self, height: u32) -> f64 { unsafe { ffi::libinput_event_pointer_get_absolute_y_transformed(self.as_raw_mut(), height) } } } /// State of a Button #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ButtonState { /// Button is pressed Pressed, /// Button is released Released, } ffi_event_struct!( /// An event related to button pressed on a pointer device struct PointerButtonEvent, ffi::libinput_event_pointer, ffi::libinput_event_pointer_get_base_event); impl PointerButtonEvent { ffi_func!( /// Return the button that triggered this event. pub fn button, ffi::libinput_event_pointer_get_button, u32); ffi_func!( /// For the button returns the total number of buttons pressed on all devices /// on the associated seat after the event was triggered. pub fn seat_button_count, ffi::libinput_event_pointer_get_seat_button_count, u32); /// Return the button state that triggered this event. pub fn button_state(&self) -> ButtonState { match unsafe { ffi::libinput_event_pointer_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, _ => panic!("libinput returned invalid 'libinput_button_state'"), } } } /// The source for a `PointerAxisEvent`. #[cfg_attr( feature = "libinput_1_19", deprecated = "Use `PointerEvent::Scroll*` events instead" )] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum AxisSource { /// The event is caused by the rotation of a wheel. Wheel, /// The event is caused by the movement of one or more fingers on a device. Finger, /// The event is caused by the motion of some device. Continuous, /// The event is caused by the tilting of a mouse wheel rather than its rotation. /// /// This method is commonly used on mice without separate horizontal scroll wheels. #[cfg_attr( feature = "libinput_1_19", deprecated = "No device has ever sent this source." )] WheelTilt, } /// Axes on a device with the pointer capability that are not x or y coordinates. /// /// The two scroll axes `Vertical` and `Horizontal` are engaged separately, /// depending on the device. libinput provides some scroll direction locking but /// it is up to the caller to determine which axis is needed and appropriate in /// the current interaction #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Axis { /// Vertical axis Vertical, /// Horizontal axis Horizontal, } ffi_event_struct!( /// An event related to moving axis on a pointer device #[cfg_attr(feature = "libinput_1_19", deprecated = "Use `PointerEvent::Scroll*` events instead")] struct PointerAxisEvent, ffi::libinput_event_pointer, ffi::libinput_event_pointer_get_base_event); impl PointerAxisEvent { /// Check if the event has a valid value for the given axis. /// /// If this function returns true for an axis and `axis_value` returns a /// value of 0, the event is a scroll stop event. #[cfg_attr( feature = "libinput_1_19", deprecated = "Use `PointerScrollEvent::has_axis` instead" )] pub fn has_axis(&self, axis: Axis) -> bool { unsafe { ffi::libinput_event_pointer_has_axis( self.as_raw_mut(), match axis { Axis::Vertical => { ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL } Axis::Horizontal => { ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL } }, ) != 0 } } /// Return the source for a given axis event. /// /// Axis events (scroll events) can be caused by a hardware item such as a /// scroll wheel or emulated from other input sources, such as two-finger or /// edge scrolling on a touchpad. /// /// If the source is `Finger`, libinput guarantees that a scroll sequence is /// terminated with a scroll value of 0. A caller may use this information to /// decide on whether kinetic scrolling should be triggered on this scroll /// sequence. The coordinate system is identical to the cursor movement, i.e. /// a scroll value of 1 represents the equivalent relative motion of 1. /// /// If the source is `Wheel`, no terminating event is guaranteed (though it /// may happen). Scrolling is in discrete steps, the value is the angle the /// wheel moved in degrees. The default is 15 degrees per wheel click, but /// some mice may have differently grained wheels. It is up to the caller how /// to interpret such different step sizes. /// /// If the source is `Continuous`, no terminating event is guaranteed (though /// it may happen). The coordinate system is identical to the cursor movement, /// i.e. a scroll value of 1 represents the equivalent relative motion of 1. /// /// If the source is `WheelTilt`, no terminating event is guaranteed (though /// it may happen). Scrolling is in discrete steps and there is no physical /// equivalent for the value returned here. For backwards compatibility, the /// value returned by this function is identical to a single mouse wheel /// rotation by this device (see the documentation for `WheelTilt` above). /// Callers should not use this value but instead exclusively refer to the //. value returned by `axis_value_discrete`. #[cfg_attr( feature = "libinput_1_19", deprecated = "Use `PointerScroll*` events instead" )] pub fn axis_source(&self) -> AxisSource { match unsafe { ffi::libinput_event_pointer_get_axis_source(self.as_raw_mut()) } { ffi::libinput_pointer_axis_source_LIBINPUT_POINTER_AXIS_SOURCE_WHEEL => { AxisSource::Wheel } ffi::libinput_pointer_axis_source_LIBINPUT_POINTER_AXIS_SOURCE_FINGER => { AxisSource::Finger } ffi::libinput_pointer_axis_source_LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS => { AxisSource::Continuous } ffi::libinput_pointer_axis_source_LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT => { AxisSource::WheelTilt } // Axis Event is deprecated, no new variants will be added _ => unreachable!(), } } /// Return the axis value of the given axis. /// /// The interpretation of the value depends on the axis. For the two scrolling /// axes `Vertical` and `Horizontal`, the value of the event is in relative /// scroll units, with the positive direction being down or right, /// respectively. For the interpretation of the value, see `axis_source`. /// /// If `has_axis` returns `false` for an axis, this function returns 0 for /// that axis. #[cfg_attr( feature = "libinput_1_19", deprecated = "Use `PointerScrollEvent::scroll_value` instead" )] pub fn axis_value(&self, axis: Axis) -> f64 { unsafe { ffi::libinput_event_pointer_get_axis_value( self.as_raw_mut(), match axis { Axis::Vertical => { ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL } Axis::Horizontal => { ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL } }, ) } } /// Return the axis value in discrete steps for a given axis event. /// /// How a value translates into a discrete step depends on the source. /// /// If the source is `Wheel`, the discrete value correspond to the number of /// physical mouse wheel clicks. /// /// If the source is `Continuous` or `Finger`, the discrete value is always /// `None`. #[cfg_attr( feature = "libinput_1_19", deprecated = "Use `PointerScrollWheelEvent::scroll_value_v120` instead" )] pub fn axis_value_discrete(&self, axis: Axis) -> Option { match self.axis_source() { AxisSource::Continuous | AxisSource::Finger => None, _ => Some(unsafe { ffi::libinput_event_pointer_get_axis_value_discrete( self.as_raw_mut(), match axis { Axis::Vertical => { ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL } Axis::Horizontal => { ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL } }, ) }), } } } #[cfg(feature = "libinput_1_19")] ffi_event_struct!( /// An event related to moving a scroll whell on a pointer device struct PointerScrollWheelEvent, ffi::libinput_event_pointer, ffi::libinput_event_pointer_get_base_event); #[cfg(feature = "libinput_1_19")] ffi_event_struct!( /// An event related to moving a finger on a pointer device struct PointerScrollFingerEvent, ffi::libinput_event_pointer, ffi::libinput_event_pointer_get_base_event); #[cfg(feature = "libinput_1_19")] ffi_event_struct!( /// An event related to a continuous scroll source on a pointer device struct PointerScrollContinuousEvent, ffi::libinput_event_pointer, ffi::libinput_event_pointer_get_base_event); #[cfg(feature = "libinput_1_19")] /// Common functions of PointerScroll type events pub trait PointerScrollEvent: AsRaw { /// Check if the event has a valid value for the given axis. /// /// If this function returns true for an axis and `axis_value` returns a /// value of 0, the event is a scroll stop event. fn has_axis(&self, axis: Axis) -> bool { unsafe { ffi::libinput_event_pointer_has_axis( self.as_raw_mut(), match axis { Axis::Vertical => { ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL } Axis::Horizontal => { ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL } }, ) != 0 } } /// Return the axis value of the given axis. /// /// The interpretation of the value depends on the axis. For the two scrolling axes [`Axis::Vertical`] and [`Axis::Horizontal`], /// the value of the event is in relative scroll units, with the positive direction being down or right, /// respectively. If [`PointerScrollEvent::has_axis`] returns false for an axis, this function returns 0 for that axis. /// /// If the event is a [`PointerScrollFingerEvent`], libinput guarantees that a scroll sequence is terminated with a scroll value of 0. /// A caller may use this information to decide on whether kinetic scrolling should be triggered on this scroll sequence. /// The coordinate system is identical to the cursor movement, i.e. a scroll value of 1 represents the equivalent relative motion of 1. /// /// If the event is a [`PointerScrollWheelEvent`], no terminating event is guaranteed (though it may happen). /// Scrolling is in discrete steps, the value is the angle the wheel moved in degrees. The default is 15 degrees per wheel click, /// but some mice may have differently grained wheels. It is up to the caller how to interpret such different step sizes. /// Callers should use [`PointerScrollWheelEvent::scroll_value_v120`] for a simpler API of handling scroll wheel events of different step sizes. /// /// If the event is a [`PointerScrollContinuousEvent`], libinput guarantees that a scroll sequence is terminated with a scroll value of 0. /// The coordinate system is identical to the cursor movement, i.e. a scroll value of 1 represents the equivalent relative motion of 1. fn scroll_value(&self, axis: Axis) -> f64 { unsafe { ffi::libinput_event_pointer_get_scroll_value( self.as_raw_mut(), match axis { Axis::Vertical => { ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL } Axis::Horizontal => { ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL } }, ) } } } #[cfg(feature = "libinput_1_19")] impl PointerScrollEvent for PointerScrollWheelEvent {} #[cfg(feature = "libinput_1_19")] impl PointerScrollEvent for PointerScrollFingerEvent {} #[cfg(feature = "libinput_1_19")] impl PointerScrollEvent for PointerScrollContinuousEvent {} #[cfg(feature = "libinput_1_19")] impl PointerScrollWheelEvent { /// Return the axis value as a v120-normalized value, that represents the movement in logical mouse wheel clicks, normalized to the -120..+120 range. /// /// A value that is a fraction of ±120 indicates a wheel movement less than one logical click, /// a caller should either scroll by the respective fraction of the normal scroll distance or accumulate /// that value until a multiple of 120 is reached. /// /// For most callers, this is the preferred way of handling high-resolution scroll events. /// /// The normalized v120 value does not take device-specific physical angles or distances into account, /// i.e. a wheel with a click angle of 20 degrees produces only 18 logical clicks per 360 degree rotation, /// a wheel with a click angle of 15 degrees produces 24 logical clicks per 360 degree rotation. /// Where the physical angle matters, use [`PointerScrollEvent::scroll_value`] instead. /// /// 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). pub fn scroll_value_v120(&self, axis: Axis) -> f64 { unsafe { ffi::libinput_event_pointer_get_scroll_value_v120( self.as_raw_mut(), match axis { Axis::Vertical => { ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL } Axis::Horizontal => { ffi::libinput_pointer_axis_LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL } }, ) } } } input-0.9.0/src/event/switch.rs000064400000000000000000000110601046102023000145460ustar 00000000000000//! Switch event types use super::EventTrait; use crate::{ffi, AsRaw, Context, FromRaw, Libinput}; /// Common functions all Switch-Events implement. pub trait SwitchEventTrait: AsRaw + Context { ffi_func!( /// The event time for this event fn time, ffi::libinput_event_switch_get_time, u32); ffi_func!( /// The event time for this event in microseconds fn time_usec, ffi::libinput_event_switch_get_time_usec, u64); /// Convert into a general `SwitchEvent` again fn into_switch_event(self) -> SwitchEvent where Self: Sized, { unsafe { SwitchEvent::from_raw(self.as_raw_mut(), self.context()) } } } impl + Context> SwitchEventTrait for T {} /// A switch related `Event` #[derive(Debug, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum SwitchEvent { /// An event related a switch, that was toggled Toggle(SwitchToggleEvent), } impl EventTrait for SwitchEvent { #[doc(hidden)] fn as_raw_event(&self) -> *mut ffi::libinput_event { match self { SwitchEvent::Toggle(event) => event.as_raw_event(), } } } impl FromRaw for SwitchEvent { unsafe fn try_from_raw( event: *mut ffi::libinput_event_switch, context: &Libinput, ) -> Option { let base = ffi::libinput_event_switch_get_base_event(event); match ffi::libinput_event_get_type(base) { ffi::libinput_event_type_LIBINPUT_EVENT_SWITCH_TOGGLE => Some(SwitchEvent::Toggle( SwitchToggleEvent::try_from_raw(event, context)?, )), _ => None, } } unsafe fn from_raw(event: *mut ffi::libinput_event_switch, context: &Libinput) -> Self { Self::try_from_raw(event, context).expect("Unknown switch event type") } } impl AsRaw for SwitchEvent { fn as_raw(&self) -> *const ffi::libinput_event_switch { match self { SwitchEvent::Toggle(event) => event.as_raw(), } } } impl Context for SwitchEvent { fn context(&self) -> &Libinput { match self { SwitchEvent::Toggle(event) => event.context(), } } } /// Types of Switches #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[repr(u32)] #[non_exhaustive] pub enum Switch { /// The laptop lid was closed when the `SwitchState` is /// `On`, or was opened when it is `Off` Lid = ffi::libinput_switch_LIBINPUT_SWITCH_LID, /// This switch indicates whether the device is in normal laptop mode /// or behaves like a tablet-like device where the primary /// interaction is usually a touch screen. When in tablet mode, the /// keyboard and touchpad are usually inaccessible. /// /// If the switch is in state `SwitchState::Off`, the /// device is in laptop mode. If the switch is in state /// `SwitchState::On`, the device is in tablet mode and the /// keyboard or touchpad may not be accessible. /// /// It is up to the caller to identify which devices are inaccessible /// `in tablet mode. TabletMode = ffi::libinput_switch_LIBINPUT_SWITCH_TABLET_MODE, } /// State of a Switch #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum SwitchState { /// Switch is off Off, /// Switch is on On, } ffi_event_struct!( /// An event related a switch, that was toggled struct SwitchToggleEvent, ffi::libinput_event_switch, ffi::libinput_event_switch_get_base_event); impl SwitchToggleEvent { /// Return the switch that triggered this event. /// /// A return value of `None` means, the switch type is not known pub fn switch(&self) -> Option { match unsafe { ffi::libinput_event_switch_get_switch(self.as_raw_mut()) } { ffi::libinput_switch_LIBINPUT_SWITCH_LID => Some(Switch::Lid), ffi::libinput_switch_LIBINPUT_SWITCH_TABLET_MODE => Some(Switch::TabletMode), _x => { #[cfg(feature = "log")] log::warn!("Unknown Switch type returned by libinput: {}", _x); None } } } /// Return the switch state that triggered this event. pub fn switch_state(&self) -> SwitchState { match unsafe { ffi::libinput_event_switch_get_switch_state(self.as_raw_mut()) } { ffi::libinput_switch_state_LIBINPUT_SWITCH_STATE_OFF => SwitchState::Off, ffi::libinput_switch_state_LIBINPUT_SWITCH_STATE_ON => SwitchState::On, _ => panic!("libinput returned invalid 'libinput_switch_state'"), } } } input-0.9.0/src/event/tablet_pad/mode_group.rs000064400000000000000000000073131046102023000175120ustar 00000000000000use crate::{ffi, AsRaw, FromRaw}; ffi_ref_struct! { /// A mode on a tablet pad is a virtual grouping of functionality, usually based on /// some visual feedback like LEDs on the pad. /// /// The set of buttons, rings and strips that share the same mode are a "mode /// group". Whenever the mode changes, all buttons, rings and strips within this /// mode group are affected. See /// [Tablet pad modes](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-pad-modes) /// for detail. /// /// Most tablets only have a single mode group, some tablets provide multiple mode /// groups through independent banks of LEDs (e.g. the Wacom Cintiq 24HD). libinput /// guarantees that at least one mode group is always available. struct TabletPadModeGroup, ffi::libinput_tablet_pad_mode_group, ffi::libinput_tablet_pad_mode_group_ref, ffi::libinput_tablet_pad_mode_group_unref } impl TabletPadModeGroup { /// The toggle button in a mode group is the button assigned to cycle to or /// directly assign a new mode when pressed. /// /// Not all devices have a toggle button and some devices may have more than /// one toggle button. For example, the Wacom Cintiq 24HD has six toggle /// buttons in two groups, each directly selecting one of the three modes per /// group. /// /// Devices without mode switching capabilities return `false` for every button. pub fn button_is_toggle(&self, button: u32) -> bool { unsafe { ffi::libinput_tablet_pad_mode_group_button_is_toggle(self.as_raw_mut(), button) != 0 } } ffi_func!( /// The returned number is the same index as passed to `Device::tablet_pad_mode_group`. /// /// For tablets with only one mode this number is always 0. pub fn index, ffi::libinput_tablet_pad_mode_group_get_index, u32); ffi_func!( /// Return the current mode this mode group is in. /// /// Note that the returned mode is the mode valid as of completing the last /// `Libinput::dispatch`. The returned mode may thus be different than the mode /// returned by `TabletPadEvent::mode`. /// /// For example, if the mode was toggled three times between the call to /// `Libinput::dispatch`, this function returns the third mode but the events in the /// event queue will return the modes 1, 2 and 3, respectively. pub fn mode, ffi::libinput_tablet_pad_mode_group_get_mode, u32); ffi_func!( /// Query the mode group for the number of available modes. /// /// The number of modes is usually decided by the number of physical LEDs available on /// the device. Different mode groups may have a different number of modes. Use /// `TabletPadModeGroup::mode` to get the currently active mode. /// /// libinput guarantees that at least one mode is available. A device without mode /// switching capability has a single mode group and a single mode. pub fn number_of_modes, ffi::libinput_tablet_pad_mode_group_get_num_modes, u32); /// Devices without mode switching capabilities return `true` for every button. pub fn has_button(&self, button: u32) -> bool { unsafe { ffi::libinput_tablet_pad_mode_group_has_button(self.as_raw_mut(), button) != 0 } } /// Devices without mode switching capabilities return `true` for every ring. pub fn has_ring(&self, ring: u32) -> bool { unsafe { ffi::libinput_tablet_pad_mode_group_has_ring(self.as_raw_mut(), ring) != 0 } } /// Devices without mode switching capabilities return `true` for every strip. pub fn has_strip(&self, strip: u32) -> bool { unsafe { ffi::libinput_tablet_pad_mode_group_has_strip(self.as_raw_mut(), strip) != 0 } } } input-0.9.0/src/event/tablet_pad.rs000064400000000000000000000317731046102023000153610ustar 00000000000000//! Tablet pad event types pub use super::{keyboard::KeyState, pointer::ButtonState, EventTrait}; use crate::{ffi, AsRaw, Context, FromRaw, Libinput}; mod mode_group; pub use self::mode_group::*; /// Common functions all TabletPad-Events implement. pub trait TabletPadEventTrait: AsRaw + Context { ffi_func!( /// The event time for this event fn time, ffi::libinput_event_tablet_pad_get_time, u32); ffi_func!( /// The event time for this event in microseconds fn time_usec, ffi::libinput_event_tablet_pad_get_time_usec, u64); ffi_func!( /// Returns the mode the button, ring, or strip that triggered this event is in, at the time of the event. /// /// The mode is a virtual grouping of functionality, usually based on some /// visual feedback like LEDs on the pad. See [Tablet pad modes](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-pad-modes) /// for details. Mode indices start at 0, a device that does not support modes /// always returns 0. /// /// Mode switching is controlled by libinput and more than one mode may exist /// on the tablet. This function returns the mode that this event's button, /// ring or strip is logically in. If the button is a mode toggle button and /// the button event caused a new mode to be toggled, the mode returned is the /// new mode the button is in. /// /// Note that the returned mode is the mode valid as of the time of the event. /// The returned mode may thus be different to the mode returned by /// `TabletPadModeGroup::mode`. See `TabletPadModeGroup::mode` for details. fn mode, ffi::libinput_event_tablet_pad_get_mode, u32); /// Returns the mode group that the button, ring, or strip that triggered this /// event is considered in. /// /// The mode is a virtual grouping of functionality, usually based on some /// visual feedback like LEDs on the pad. See [Tablet pad modes](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-pad-modes) for details. fn mode_group(&self) -> TabletPadModeGroup { unsafe { TabletPadModeGroup::from_raw( ffi::libinput_event_tablet_pad_get_mode_group(self.as_raw_mut()), self.context(), ) } } /// Convert into a general `TabletPadEvent` again fn into_tablet_pad_event(self) -> TabletPadEvent where Self: Sized, { unsafe { TabletPadEvent::from_raw(self.as_raw_mut(), self.context()) } } } impl + Context> TabletPadEventTrait for T {} /// A tablet-pad related `Event` #[derive(Debug, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum TabletPadEvent { /// A button pressed on a device with the `DeviceCapability::TabletPad` /// capability. /// /// A Button-Event differs from a `Key`-Event (available with `feature="libinput_1_15"`) /// in that buttons are sequentially indexed from 0 and do not carry any other information. /// Keys have a specific functionality assigned to them. The key code thus carries a /// semantic meaning, a button number does not. /// /// This event is not to be confused with the button events emitted by tools /// on a tablet. See `TabletToolButtonEvent`. Button(TabletPadButtonEvent), /// A status change on a tablet ring with the `DeviceCapability::TabletPad` /// capability. Ring(TabletPadRingEvent), /// A status change on a strip on a device with the /// `DeviceCapability::TabletPad` capability. Strip(TabletPadStripEvent), /// A key pressed on a device with the `DeviceCapability::TabletPad` capability. /// /// A `Key`-Event differs from a `Button`-Event in that keys have a specific /// functionality assigned to them (buttons are sequencially ordered). A key code /// thus carries a semantic meaning, a button number does not. #[cfg(feature = "libinput_1_15")] Key(TabletPadKeyEvent), } impl EventTrait for TabletPadEvent { #[doc(hidden)] fn as_raw_event(&self) -> *mut ffi::libinput_event { match self { TabletPadEvent::Button(event) => event.as_raw_event(), TabletPadEvent::Ring(event) => event.as_raw_event(), TabletPadEvent::Strip(event) => event.as_raw_event(), #[cfg(feature = "libinput_1_15")] TabletPadEvent::Key(event) => event.as_raw_event(), } } } impl FromRaw for TabletPadEvent { unsafe fn try_from_raw( event: *mut ffi::libinput_event_tablet_pad, context: &Libinput, ) -> Option { let base = ffi::libinput_event_tablet_pad_get_base_event(event); match ffi::libinput_event_get_type(base) { ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_BUTTON => Some( TabletPadEvent::Button(TabletPadButtonEvent::try_from_raw(event, context)?), ), ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_RING => Some(TabletPadEvent::Ring( TabletPadRingEvent::try_from_raw(event, context)?, )), ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_STRIP => Some( TabletPadEvent::Strip(TabletPadStripEvent::try_from_raw(event, context)?), ), #[cfg(feature = "libinput_1_15")] ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_KEY => Some(TabletPadEvent::Key( TabletPadKeyEvent::try_from_raw(event, context)?, )), _ => None, } } unsafe fn from_raw(event: *mut ffi::libinput_event_tablet_pad, context: &Libinput) -> Self { Self::try_from_raw(event, context).expect("Unknown tablet pad event type") } } impl AsRaw for TabletPadEvent { fn as_raw(&self) -> *const ffi::libinput_event_tablet_pad { match self { TabletPadEvent::Button(event) => event.as_raw(), TabletPadEvent::Ring(event) => event.as_raw(), TabletPadEvent::Strip(event) => event.as_raw(), #[cfg(feature = "libinput_1_15")] TabletPadEvent::Key(event) => event.as_raw(), } } } impl Context for TabletPadEvent { fn context(&self) -> &Libinput { match self { TabletPadEvent::Button(event) => event.context(), TabletPadEvent::Ring(event) => event.context(), TabletPadEvent::Strip(event) => event.context(), #[cfg(feature = "libinput_1_15")] TabletPadEvent::Key(event) => event.context(), } } } ffi_event_struct!( /// A button pressed on a device with the `DeviceCapability::TabletPad` /// capability. /// /// This event is not to be confused with the button events emitted by tools /// on a tablet. See `TabletToolButtonEvent`. struct TabletPadButtonEvent, ffi::libinput_event_tablet_pad, ffi::libinput_event_tablet_pad_get_base_event); impl TabletPadButtonEvent { ffi_func!( /// Return the button number that triggered this event, starting at 0. /// /// Note that the number returned is a generic sequential button number and /// not a semantic button code as defined in linux/input.h. /// [See Tablet pad button numbers](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-pad-buttons) /// for more details. pub fn button_number, ffi::libinput_event_tablet_pad_get_button_number, u32); /// Return the button state of the event. pub fn button_state(&self) -> ButtonState { match unsafe { ffi::libinput_event_tablet_pad_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, _ => panic!("libinput returned invalid 'libinput_button_state'"), } } } /// The source for a `TabletPadRingEvent` event. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum RingAxisSource { /// An unknown source Unknown, /// Finger source Finger, } ffi_event_struct!( /// A status change on a tablet ring with the `DeviceCapability::TabletPad` /// capability. struct TabletPadRingEvent, ffi::libinput_event_tablet_pad, ffi::libinput_event_tablet_pad_get_base_event); impl TabletPadRingEvent { ffi_func!( /// Returns the number of the ring that has changed state, with 0 being the /// first ring. /// /// On tablets with only one ring, this function always returns 0. pub fn number, ffi::libinput_event_tablet_pad_get_ring_number, u32); ffi_func!( /// Returns the current position of the ring, in degrees counterclockwise from /// the northern-most point of the ring in the tablet's current logical /// orientation. /// /// If the source is `RingAxisSource::Finger`, libinput sends a terminating /// event with a ring value of -1 when the finger is lifted from the ring. A /// caller may use this information to e.g. determine if kinetic scrolling /// should be triggered. pub fn position, ffi::libinput_event_tablet_pad_get_ring_position, f64); /// Returns the source of the interaction with the ring. /// /// If the source is `RingAxisSource::Finger`, libinput sends a ring position /// value of -1 to terminate the current interaction. pub fn source(&self) -> RingAxisSource { match unsafe { ffi::libinput_event_tablet_pad_get_ring_source(self.as_raw_mut()) } { ffi::libinput_tablet_pad_ring_axis_source_LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN => { RingAxisSource::Unknown } ffi::libinput_tablet_pad_ring_axis_source_LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER => { RingAxisSource::Finger } _x => { #[cfg(feature = "log")] log::warn!("Unknown `RingAxisSource` returned by libinput: {}", _x); RingAxisSource::Unknown } } } } /// The source for a `TabletPadStripEvent` event. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum StripAxisSource { /// An unknown source Unknown, /// Finger source Finger, } ffi_event_struct!( /// A status change on a strip on a device with the `DeviceCapability::TabletPad` /// capability. struct TabletPadStripEvent, ffi::libinput_event_tablet_pad, ffi::libinput_event_tablet_pad_get_base_event); impl TabletPadStripEvent { ffi_func!( /// Returns the number of the strip that has changed state, with 0 being the /// first strip. /// /// On tablets with only one strip, this function always returns 0. pub fn number, ffi::libinput_event_tablet_pad_get_strip_number, u32); ffi_func!( /// Returns the current position of the strip, normalized to the range [0, 1], /// with 0 being the top/left-most point in the tablet's current logical /// orientation. /// /// If the source is `StripAxisSource::Finger`, libinput sends a terminating /// event with a ring value of -1 when the finger is lifted from the ring. A /// caller may use this information to e.g. determine if kinetic scrolling /// should be triggered. pub fn position, ffi::libinput_event_tablet_pad_get_strip_position, f64); /// Returns the source of the interaction with the strip. /// /// If the source is `StripAxisSource::Finger`, libinput sends a strip /// position value of -1 to terminate the current interaction pub fn source(&self) -> StripAxisSource { match unsafe { ffi::libinput_event_tablet_pad_get_strip_source(self.as_raw_mut()) } { ffi::libinput_tablet_pad_strip_axis_source_LIBINPUT_TABLET_PAD_STRIP_SOURCE_UNKNOWN => { StripAxisSource::Unknown } ffi::libinput_tablet_pad_strip_axis_source_LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER => { StripAxisSource::Finger } _x => { #[cfg(feature = "log")] log::warn!("Unknown `StripAxisSource` returned by libinput: {}", _x); StripAxisSource::Unknown } } } } #[cfg(feature = "libinput_1_15")] ffi_event_struct!( /// A key pressed on a device with the `DeviceCapability::TabletPad` capability. struct TabletPadKeyEvent, ffi::libinput_event_tablet_pad, ffi::libinput_event_tablet_pad_get_base_event); #[cfg(feature = "libinput_1_15")] impl TabletPadKeyEvent { ffi_func!( /// Return the key code that triggered this event, e.g. KEY_CONTROLPANEL. /// The list of key codes is defined in linux/input-event-codes.h pub fn key, ffi::libinput_event_tablet_pad_get_key, u32); /// Return the key state of the event pub fn key_state(&self) -> KeyState { match unsafe { ffi::libinput_event_tablet_pad_get_key_state(self.as_raw() as *mut _) } { ffi::libinput_key_state_LIBINPUT_KEY_STATE_PRESSED => KeyState::Pressed, ffi::libinput_key_state_LIBINPUT_KEY_STATE_RELEASED => KeyState::Released, _ => panic!("libinput returned invalid 'libinput_key_state'"), } } } input-0.9.0/src/event/tablet_tool/tool.rs000064400000000000000000000153141046102023000165400ustar 00000000000000use crate::{ffi, AsRaw, FromRaw}; /// Available tool types for a device with the `DeviceCapability::TabletTool` capability. /// /// The tool type defines the default usage of the tool as advertised by the /// manufacturer. Multiple different physical tools may share the same tool type, e.g. a /// Wacom Classic Pen, Wacom Pro Pen and a Wacom Grip Pen are all of type /// `TabletToolType::Pen`. Use `TabletTool::tool_id` to get a specific model where /// applicable. /// /// Note that on some device, the eraser tool is on the tail end of a pen device. On /// other devices, e.g. MS Surface 3, the eraser is the pen tip while a button is held /// down. /// /// ## Note /// /// The `TabletToolType` can only describe the default physical type of the device. For /// devices with adjustable physical properties the tool type remains the same, i.e. /// putting a Wacom stroke nib into a classic pen leaves the tool type as /// `TabletToolType::Pen`. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum TabletToolType { /// A generic pen. Pen, /// Eraser. Eraser, /// A paintbrush-like tool. Brush, /// Physical drawing tool, e.g. Wacom Inking Pen Pencil, /// An airbrush-like tool. Airbrush, /// A mouse bound to the tablet. Mouse, /// A mouse tool with a lens. Lens, /// A rotary device with positional and rotation data #[cfg(feature = "libinput_1_14")] Totem, } ffi_ref_struct! { /// An object representing a tool being used by a device with the /// `DeviceCapability::TabletTool` capability. /// /// Tablet events generated by such a device are bound to a specific tool rather than /// coming from the device directly. Depending on the hardware it is possible to track /// the same physical tool across multiple `Device`s, see /// [Tracking unique tools](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-serial-numbers). struct TabletTool, ffi::libinput_tablet_tool, ffi::libinput_tablet_tool_ref, ffi::libinput_tablet_tool_unref } impl TabletTool { ffi_func!( /// Return the serial number of a tool. /// /// If the tool does not report a serial number, this function returns zero. /// See [Tracking unique tools](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-serial-numbers) for details. pub fn serial, ffi::libinput_tablet_tool_get_serial, u64); ffi_func!( /// Return the tool ID for a tool object. /// /// If nonzero, this number identifies the specific type of the tool with more /// precision than the type returned in `tool_type`, /// see [Vendor-specific tablet tool types](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-tool-types). /// Not all tablets support a tool ID. /// /// Tablets known to support tool IDs include the Wacom Intuos 3, 4, 5, Wacom Cintiq /// and Wacom Intuos Pro series. pub fn tool_id, ffi::libinput_tablet_tool_get_tool_id, u64); /// Return the tool type for a tool object, /// see [Vendor-specific tablet tool types](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-tool-types) /// for details. /// /// A return value of `None` means the tool type is not known. pub fn tool_type(&self) -> Option { match unsafe { ffi::libinput_tablet_tool_get_type(self.as_raw_mut()) } { ffi::libinput_tablet_tool_type_LIBINPUT_TABLET_TOOL_TYPE_PEN => { Some(TabletToolType::Pen) } ffi::libinput_tablet_tool_type_LIBINPUT_TABLET_TOOL_TYPE_ERASER => { Some(TabletToolType::Eraser) } ffi::libinput_tablet_tool_type_LIBINPUT_TABLET_TOOL_TYPE_BRUSH => { Some(TabletToolType::Brush) } ffi::libinput_tablet_tool_type_LIBINPUT_TABLET_TOOL_TYPE_PENCIL => { Some(TabletToolType::Pencil) } ffi::libinput_tablet_tool_type_LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH => { Some(TabletToolType::Airbrush) } ffi::libinput_tablet_tool_type_LIBINPUT_TABLET_TOOL_TYPE_MOUSE => { Some(TabletToolType::Mouse) } ffi::libinput_tablet_tool_type_LIBINPUT_TABLET_TOOL_TYPE_LENS => { Some(TabletToolType::Lens) } #[cfg(feature = "libinput_1_14")] ffi::libinput_tablet_tool_type_LIBINPUT_TABLET_TOOL_TYPE_TOTEM => { Some(TabletToolType::Totem) } _x => { #[cfg(feature = "log")] log::warn!("Unknown `TabletToolType` returned by libinput: {}", _x); None } } } /// Check if a tablet tool has a button with the passed-in code (see linux/input.h). pub fn has_button(&self, button: u32) -> bool { unsafe { ffi::libinput_tablet_tool_has_button(self.as_raw_mut(), button) != 0 } } ffi_func!( /// Return whether the tablet tool supports distance. pub fn has_distance, ffi::libinput_tablet_tool_has_distance, bool); ffi_func!( /// Return whether the tablet tool supports pressure. pub fn has_pressure, ffi::libinput_tablet_tool_has_pressure, bool); ffi_func!( /// Return whether the tablet tool supports z-rotation.v pub fn has_rotation, ffi::libinput_tablet_tool_has_rotation, bool); ffi_func!( /// Return whether the tablet tool has a slider axis. pub fn has_slider, ffi::libinput_tablet_tool_has_slider, bool); ffi_func!( /// Return whether the tablet tool supports tilt. pub fn has_tilt, ffi::libinput_tablet_tool_has_tilt, bool); ffi_func!( /// Return whether the tablet tool has a relative wheel. pub fn has_wheel, ffi::libinput_tablet_tool_has_wheel, bool); ffi_func!( /// Returns `true` if the physical tool can be uniquely identified by libinput, or /// `false` otherwise. /// /// If a tool can be uniquely identified, keeping a reference to the tool allows /// tracking the tool across proximity out sequences and across compatible tablets. /// See [Tracking unique tools](https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#tablet-serial-numbers) /// for more details. pub fn is_unique, ffi::libinput_tablet_tool_is_unique, bool); #[cfg(feature = "libinput_1_14")] ffi_func!( /// Returns whether the tablet tool has a ellipsis major and minor. /// /// Where the underlying hardware only supports one of either major or minor, /// libinput emulated the other axis as a cicular contact, i.e. major == minor /// for all values of major. pub fn tablet_tool_has_size, ffi::libinput_tablet_tool_has_size, bool); } input-0.9.0/src/event/tablet_tool.rs000064400000000000000000000630371046102023000155700ustar 00000000000000//! Tablet tool event types use super::{pointer::ButtonState, EventTrait}; use crate::{ffi, AsRaw, Context, FromRaw, Libinput}; mod tool; pub use self::tool::*; /// Common functions all TabletTool-Events implement. pub trait TabletToolEventTrait: AsRaw + Context { 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); #[cfg(feature = "libinput_1_14")] ffi_func!( /// Check if the size major axis was updated in this event. /// /// For `TabletToolButtonEvent`s this function always returns false fn size_major_has_changed, ffi::libinput_event_tablet_tool_size_major_has_changed, bool); #[cfg(feature = "libinput_1_14")] ffi_func!( /// Check if the size minor axis was updated in this event. /// /// For `TabletToolButtonEvent`s this function always returns false fn size_minor_has_changed, ffi::libinput_event_tablet_tool_size_minor_has_changed, bool); #[cfg(feature = "libinput_1_14")] ffi_func!( /// Returns the current size in mm along the major axis of the touching ellipse. /// This axis is not necessarily aligned with either x or y, the rotation must /// be taken into account. /// /// Where no rotation is available on a tool, or where rotation is zero, the major /// axis aligns with the y axis and the minor axis with the x axis. /// /// If the axis does not exist on the current tool, this function returns 0. fn size_major, ffi::libinput_event_tablet_tool_get_size_major, f64); #[cfg(feature = "libinput_1_14")] ffi_func!( /// Returns the current size in mm along the minor axis of the touching ellipse. /// This axis is not necessarily aligned with either x or y, the rotation must /// be taken into account. /// /// Where no rotation is available on a tool, or where rotation is zero, the minor /// axis aligns with the y axis and the major axis with the x axis. /// /// If the axis does not exist on the current tool, this function returns 0. fn size_minor, ffi::libinput_event_tablet_tool_get_size_minor, 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_y_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()), self.context(), ) } } /// Convert into a general `TabletToolEvent` again fn into_tablet_tool_event(self) -> TabletToolEvent where Self: Sized, { unsafe { TabletToolEvent::from_raw(self.as_raw_mut(), self.context()) } } } impl + Context> TabletToolEventTrait for T {} /// An event related to a tablet tool #[derive(Debug, PartialEq, Eq, Hash)] #[non_exhaustive] 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(event) => event.as_raw_event(), TabletToolEvent::Proximity(event) => event.as_raw_event(), TabletToolEvent::Tip(event) => event.as_raw_event(), TabletToolEvent::Button(event) => event.as_raw_event(), } } } impl FromRaw for TabletToolEvent { unsafe fn try_from_raw( event: *mut ffi::libinput_event_tablet_tool, context: &Libinput, ) -> Option { 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 => Some( TabletToolEvent::Axis(TabletToolAxisEvent::try_from_raw(event, context)?), ), ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY => Some( TabletToolEvent::Proximity(TabletToolProximityEvent::try_from_raw(event, context)?), ), ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_TOOL_TIP => Some(TabletToolEvent::Tip( TabletToolTipEvent::try_from_raw(event, context)?, )), ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_TOOL_BUTTON => Some( TabletToolEvent::Button(TabletToolButtonEvent::try_from_raw(event, context)?), ), _ => None, } } unsafe fn from_raw(event: *mut ffi::libinput_event_tablet_tool, context: &Libinput) -> Self { Self::try_from_raw(event, context).expect("Unknown tablet tool event type") } } impl AsRaw for TabletToolEvent { fn as_raw(&self) -> *const ffi::libinput_event_tablet_tool { match self { TabletToolEvent::Axis(event) => event.as_raw(), TabletToolEvent::Proximity(event) => event.as_raw(), TabletToolEvent::Tip(event) => event.as_raw(), TabletToolEvent::Button(event) => event.as_raw(), } } } impl Context for TabletToolEvent { fn context(&self) -> &Libinput { match self { TabletToolEvent::Axis(event) => event.context(), TabletToolEvent::Proximity(event) => event.context(), TabletToolEvent::Tip(event) => event.context(), TabletToolEvent::Button(event) => event.context(), } } } 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 } _ => panic!("libinput returned invalid 'libinput_tablet_tool_proximity_state'"), } } } /// 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, _ => panic!("libinput returned invalid 'libinput_tablet_tool_top_state'"), } } } 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, _ => panic!("libinput returned invalid 'libinput_button_state'"), } } } input-0.9.0/src/event/touch.rs000064400000000000000000000167611046102023000144040ustar 00000000000000//! Touch event types use super::EventTrait; use crate::{ffi, AsRaw, Context, FromRaw, Libinput}; /// Common functions all Touch-Events implement. pub trait TouchEventTrait: AsRaw + Context { ffi_func!( /// The event time for this event fn time, ffi::libinput_event_touch_get_time, u32); ffi_func!( /// The event time for this event in microseconds fn time_usec, ffi::libinput_event_touch_get_time_usec, u64); /// Convert into a general `TouchEvent` again fn into_touch_event(self) -> TouchEvent where Self: Sized, { unsafe { TouchEvent::from_raw(self.as_raw_mut(), self.context()) } } } impl + Context> TouchEventTrait for T {} /// Touch slot related functions all TouchEvents implement, that can be mapped to slots. /// /// A touch slot is grouping all events related to a single gesture together. pub trait TouchEventSlot: AsRaw { ffi_func!( /// Get the seat slot of the touch event. /// /// A seat slot is a non-negative seat wide unique identifier of an active /// touch point. /// /// Events from single touch devices will be represented as one individual /// touch point per device. fn seat_slot, ffi::libinput_event_touch_get_seat_slot, u32); /// Get the slot of this touch event. /// /// See the kernel's multitouch protocol B documentation for more information. /// /// If the touch event has no assigned slot, for example if it is from a /// single touch device, this function returns `None`. fn slot(&self) -> Option { match unsafe { ffi::libinput_event_touch_get_slot(self.as_raw_mut()) } { x if x >= 0 => Some(x as u32), -1 => None, _ => panic!("libinput_event_touch_get_slot returned undocumentated value!"), } } } /// Position related functions all TouchEvents implement, that have a screen /// position assigned to them. pub trait TouchEventPosition: AsRaw { ffi_func!( /// Return the current absolute x coordinate of the touch event, in mm from /// the top left corner of the device. /// /// To get the corresponding output screen coordinate, use `x_transformed`. fn x, ffi::libinput_event_touch_get_x, f64); ffi_func!( /// Return the current absolute y coordinate of the touch event, in mm from /// the top left corner of the device. /// /// To get the corresponding output screen coordinate, use `y_transformed`. fn y, ffi::libinput_event_touch_get_y, f64); /// Return the current absolute x coordinate of the touch event, transformed /// to screen coordinates. /// /// ## Arguments /// /// - width - The current output screen width fn x_transformed(&self, width: u32) -> f64 { unsafe { ffi::libinput_event_touch_get_x_transformed(self.as_raw_mut(), width) } } /// Return the current absolute y coordinate of the touch event, transformed /// to screen coordinates. /// /// ## Arguments /// /// - height - The current output screen height fn y_transformed(&self, height: u32) -> f64 { unsafe { ffi::libinput_event_touch_get_y_transformed(self.as_raw_mut(), height) } } } /// A touch related `Event` #[derive(Debug, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum TouchEvent { /// An event related to resting the finger on the screen Down(TouchDownEvent), /// An event related to lifting the finger on the screen Up(TouchUpEvent), /// An event related to moving a finger on the screen Motion(TouchMotionEvent), /// An event cancelling previous events on this slot Cancel(TouchCancelEvent), /// Signals the end of a set of touchpoints at one device sample time. Frame(TouchFrameEvent), } impl EventTrait for TouchEvent { #[doc(hidden)] fn as_raw_event(&self) -> *mut ffi::libinput_event { match self { TouchEvent::Down(event) => event.as_raw_event(), TouchEvent::Up(event) => event.as_raw_event(), TouchEvent::Motion(event) => event.as_raw_event(), TouchEvent::Cancel(event) => event.as_raw_event(), TouchEvent::Frame(event) => event.as_raw_event(), } } } impl FromRaw for TouchEvent { unsafe fn try_from_raw( event: *mut ffi::libinput_event_touch, context: &Libinput, ) -> Option { let base = ffi::libinput_event_touch_get_base_event(event); match ffi::libinput_event_get_type(base) { ffi::libinput_event_type_LIBINPUT_EVENT_TOUCH_DOWN => Some(TouchEvent::Down( TouchDownEvent::try_from_raw(event, context)?, )), ffi::libinput_event_type_LIBINPUT_EVENT_TOUCH_UP => { Some(TouchEvent::Up(TouchUpEvent::try_from_raw(event, context)?)) } ffi::libinput_event_type_LIBINPUT_EVENT_TOUCH_MOTION => Some(TouchEvent::Motion( TouchMotionEvent::try_from_raw(event, context)?, )), ffi::libinput_event_type_LIBINPUT_EVENT_TOUCH_CANCEL => Some(TouchEvent::Cancel( TouchCancelEvent::try_from_raw(event, context)?, )), ffi::libinput_event_type_LIBINPUT_EVENT_TOUCH_FRAME => Some(TouchEvent::Frame( TouchFrameEvent::try_from_raw(event, context)?, )), _ => None, } } unsafe fn from_raw(event: *mut ffi::libinput_event_touch, context: &Libinput) -> Self { Self::try_from_raw(event, context).expect("Unknown touch event type") } } impl AsRaw for TouchEvent { fn as_raw(&self) -> *const ffi::libinput_event_touch { match self { TouchEvent::Down(event) => event.as_raw(), TouchEvent::Up(event) => event.as_raw(), TouchEvent::Motion(event) => event.as_raw(), TouchEvent::Cancel(event) => event.as_raw(), TouchEvent::Frame(event) => event.as_raw(), } } } impl Context for TouchEvent { fn context(&self) -> &Libinput { match self { TouchEvent::Down(event) => event.context(), TouchEvent::Up(event) => event.context(), TouchEvent::Motion(event) => event.context(), TouchEvent::Cancel(event) => event.context(), TouchEvent::Frame(event) => event.context(), } } } ffi_event_struct!( /// An event related to resting the finger on the screen struct TouchDownEvent, ffi::libinput_event_touch, ffi::libinput_event_touch_get_base_event); impl TouchEventSlot for TouchDownEvent {} impl TouchEventPosition for TouchDownEvent {} ffi_event_struct!( /// An event related to lifting the finger on the screen struct TouchUpEvent, ffi::libinput_event_touch, ffi::libinput_event_touch_get_base_event); impl TouchEventSlot for TouchUpEvent {} ffi_event_struct!( /// An event related to moving a finger on the screen struct TouchMotionEvent, ffi::libinput_event_touch, ffi::libinput_event_touch_get_base_event); impl TouchEventSlot for TouchMotionEvent {} impl TouchEventPosition for TouchMotionEvent {} ffi_event_struct!( /// An event cancelling previous events on this slot struct TouchCancelEvent, ffi::libinput_event_touch, ffi::libinput_event_touch_get_base_event); impl TouchEventSlot for TouchCancelEvent {} ffi_event_struct!( /// Signals the end of a set of touchpoints at one device sample time. struct TouchFrameEvent, ffi::libinput_event_touch, ffi::libinput_event_touch_get_base_event); input-0.9.0/src/event.rs000064400000000000000000000257621046102023000132630ustar 00000000000000//! Libinput Events use crate::{ffi, AsRaw, Context, Device, FromRaw, Libinput}; /// A libinput `Event` #[derive(Debug, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum Event { /// A device related `Event` Device(DeviceEvent), /// A keyboard related `Event` Keyboard(KeyboardEvent), /// A pointer related `Event` Pointer(PointerEvent), /// A touch related `Event` Touch(TouchEvent), /// A tablet related `Event` Tablet(TabletToolEvent), /// A tabled pad related `Event` TabletPad(TabletPadEvent), /// A gesture related `Event` Gesture(GestureEvent), /// A switch related `Event` Switch(SwitchEvent), } /// Common functions all (Sub-)Events implement. pub trait EventTrait: Context { #[doc(hidden)] fn as_raw_event(&self) -> *mut ffi::libinput_event; /// Convert into a general `Event` again fn into_event(self) -> Event where Self: Sized, { unsafe { Event::from_raw(self.as_raw_event(), self.context()) } } /// Return the device associated with this event. /// /// For device added/removed events this is the device added or removed. /// For all other device events, this is the device that generated the event. fn device(&self) -> Device { unsafe { Device::from_raw( ffi::libinput_event_get_device(self.as_raw_event()), self.context(), ) } } } impl EventTrait for Event { fn as_raw_event(&self) -> *mut ffi::libinput_event { self.as_raw_mut() } } impl FromRaw for Event { unsafe fn from_raw(event: *mut ffi::libinput_event, context: &Libinput) -> Self { Self::try_from_raw(event, context).expect("libinput returned invalid 'libinput_event_type'") } unsafe fn try_from_raw(event: *mut ffi::libinput_event, context: &Libinput) -> Option { match ffi::libinput_event_get_type(event) { ffi::libinput_event_type_LIBINPUT_EVENT_NONE => None, ffi::libinput_event_type_LIBINPUT_EVENT_DEVICE_ADDED | ffi::libinput_event_type_LIBINPUT_EVENT_DEVICE_REMOVED => { Some(Event::Device(DeviceEvent::try_from_raw( ffi::libinput_event_get_device_notify_event(event), context, )?)) } ffi::libinput_event_type_LIBINPUT_EVENT_KEYBOARD_KEY => { Some(Event::Keyboard(KeyboardEvent::try_from_raw( ffi::libinput_event_get_keyboard_event(event), context, )?)) } #[cfg(not(feature = "libinput_1_19"))] ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_MOTION | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_BUTTON | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_AXIS => Some(Event::Pointer( PointerEvent::try_from_raw(ffi::libinput_event_get_pointer_event(event), context)?, )), #[cfg(feature = "libinput_1_19")] ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_MOTION | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_BUTTON | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_AXIS | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_SCROLL_WHEEL | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_SCROLL_FINGER | ffi::libinput_event_type_LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS => { Some(Event::Pointer(PointerEvent::try_from_raw( ffi::libinput_event_get_pointer_event(event), context, )?)) } ffi::libinput_event_type_LIBINPUT_EVENT_TOUCH_DOWN | ffi::libinput_event_type_LIBINPUT_EVENT_TOUCH_UP | ffi::libinput_event_type_LIBINPUT_EVENT_TOUCH_MOTION | ffi::libinput_event_type_LIBINPUT_EVENT_TOUCH_CANCEL | ffi::libinput_event_type_LIBINPUT_EVENT_TOUCH_FRAME => Some(Event::Touch( TouchEvent::try_from_raw(ffi::libinput_event_get_touch_event(event), context)?, )), ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_TOOL_AXIS | ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY | ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_TOOL_TIP | ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_TOOL_BUTTON => { Some(Event::Tablet(TabletToolEvent::try_from_raw( ffi::libinput_event_get_tablet_tool_event(event), context, )?)) } #[cfg(not(feature = "libinput_1_15"))] ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_BUTTON | ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_RING | ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_STRIP => { Some(Event::TabletPad(TabletPadEvent::try_from_raw( ffi::libinput_event_get_tablet_pad_event(event), context, )?)) } #[cfg(feature = "libinput_1_15")] ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_BUTTON | ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_RING | ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_STRIP | ffi::libinput_event_type_LIBINPUT_EVENT_TABLET_PAD_KEY => { Some(Event::TabletPad(TabletPadEvent::try_from_raw( ffi::libinput_event_get_tablet_pad_event(event), context, )?)) } #[cfg(not(feature = "libinput_1_19"))] ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_END | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_BEGIN | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_UPDATE | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_END => Some(Event::Gesture( GestureEvent::try_from_raw(ffi::libinput_event_get_gesture_event(event), context)?, )), #[cfg(feature = "libinput_1_19")] ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_SWIPE_END | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_BEGIN | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_UPDATE | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_PINCH_END | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_HOLD_BEGIN | ffi::libinput_event_type_LIBINPUT_EVENT_GESTURE_HOLD_END => Some(Event::Gesture( GestureEvent::try_from_raw(ffi::libinput_event_get_gesture_event(event), context)?, )), ffi::libinput_event_type_LIBINPUT_EVENT_SWITCH_TOGGLE => Some(Event::Switch( SwitchEvent::try_from_raw(ffi::libinput_event_get_switch_event(event), context)?, )), _ => None, } } } impl AsRaw for Event { fn as_raw(&self) -> *const ffi::libinput_event { match self { Event::Device(event) => event.as_raw_event() as *const _, Event::Keyboard(event) => event.as_raw_event() as *const _, Event::Pointer(event) => event.as_raw_event() as *const _, Event::Touch(event) => event.as_raw_event() as *const _, Event::Tablet(event) => event.as_raw_event() as *const _, Event::TabletPad(event) => event.as_raw_event() as *const _, Event::Gesture(event) => event.as_raw_event() as *const _, Event::Switch(event) => event.as_raw_event() as *const _, } } } impl Context for Event { fn context(&self) -> &crate::Libinput { match self { Event::Device(event) => event.context(), Event::Keyboard(event) => event.context(), Event::Pointer(event) => event.context(), Event::Touch(event) => event.context(), Event::Tablet(event) => event.context(), Event::TabletPad(event) => event.context(), Event::Gesture(event) => event.context(), Event::Switch(event) => event.context(), } } } macro_rules! ffi_event_struct { ($(#[$attr:meta])* struct $struct_name:ident, $ffi_name:path, $get_base_fn:path) => ( #[derive(Eq)] $(#[$attr])* pub struct $struct_name { ffi: *mut $ffi_name, context: $crate::context::Libinput, } impl std::fmt::Debug for $struct_name { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{} @{:p}", stringify!($struct_name), self.as_raw()) } } impl FromRaw<$ffi_name> for $struct_name { unsafe fn try_from_raw(ffi: *mut $ffi_name, context: &$crate::context::Libinput) -> Option { Some(Self::from_raw(ffi, context)) } unsafe fn from_raw(ffi: *mut $ffi_name, context: &$crate::context::Libinput) -> Self { $struct_name { ffi, context: context.clone(), } } } impl AsRaw<$ffi_name> for $struct_name { fn as_raw(&self) -> *const $ffi_name { self.ffi as *const _ } } impl $crate::Context for $struct_name { fn context(&self) -> &$crate::context::Libinput { &self.context } } impl PartialEq for $struct_name { fn eq(&self, other: &Self) -> bool { self.as_raw() == other.as_raw() } } impl std::hash::Hash for $struct_name { fn hash(&self, state: &mut H) { self.as_raw().hash(state); } } impl EventTrait for $struct_name { #[doc(hidden)] fn as_raw_event(&self) -> *mut $crate::ffi::libinput_event { unsafe { $get_base_fn(self.as_raw_mut()) } } } impl Drop for $struct_name { fn drop(&mut self) { unsafe { $crate::ffi::libinput_event_destroy(self.as_raw_event()) } } } ) } pub mod device; pub mod gesture; pub mod keyboard; pub mod pointer; pub mod switch; pub mod tablet_pad; pub mod tablet_tool; pub mod touch; pub use self::device::DeviceEvent; pub use self::gesture::GestureEvent; pub use self::keyboard::KeyboardEvent; pub use self::pointer::PointerEvent; pub use self::switch::SwitchEvent; pub use self::tablet_pad::TabletPadEvent; pub use self::tablet_tool::TabletToolEvent; pub use self::touch::TouchEvent; input-0.9.0/src/lib.rs000064400000000000000000000172161046102023000127030ustar 00000000000000//! # Libinput bindings for rust //! //! These bindings closely follow libinput's concepts and it's original API. //! Please refer to the [libinput documentation](https://wayland.freedesktop.org/libinput/doc/latest/) //! to understand the general structure and concepts. //! //! ## Differences to the C-Library: //! //! - Refcounting does not need to be done manually. Just call `clone` when you need an additional reference. //! - Libinput logging cannot (currently) not be customized. //! //! ## Userdata handling //! //! Multiple types in the libinput library allow to attach a pointer of an arbitrary type, so called `userdata`. //! Using this data is unsafe as there is no way to find out what type is stored in the libinput struct. //! Additionally multiple references to the same libinput object may exist and userdata may be shared mutably. //! //! This is why using and setting userdata is an unsafe operation (except when creating an object). //! //! If you heavily rely on userdata, you should always stored them wrapped in a `Mutex` and use the same //! type for every userdata access to further simplify usage. //! //! You need to be especially cautious when initializing libinput types from raw pointers, you obtained //! from other libraries which may set their own userdata. If accessing their userdata make sure no shared //! mutable access may happen and don't store something else instead, if the library does not explicitly //! allow this. //! //! Generally usage of this api is error-prone and discouraged if not needed. //! //! ## Getting started //! To get started check out the [`Libinput` struct](./struct.Libinput.html). //! //! Here's a small example that prints all events: //! //! ``` //! use input::{Libinput, LibinputInterface}; //! use std::fs::{File, OpenOptions}; //! use std::os::unix::{fs::OpenOptionsExt, io::OwnedFd}; //! use std::path::Path; //! //! extern crate libc; //! use libc::{O_RDONLY, O_RDWR, O_WRONLY}; //! //! struct Interface; //! //! impl LibinputInterface for Interface { //! fn open_restricted(&mut self, path: &Path, flags: i32) -> Result { //! OpenOptions::new() //! .custom_flags(flags) //! .read((flags & O_RDONLY != 0) | (flags & O_RDWR != 0)) //! .write((flags & O_WRONLY != 0) | (flags & O_RDWR != 0)) //! .open(path) //! .map(|file| file.into()) //! .map_err(|err| err.raw_os_error().unwrap()) //! } //! fn close_restricted(&mut self, fd: OwnedFd) { //! unsafe { //! File::from(fd); //! } //! } //! } //! //! fn main() { //! # // Preventing infinite execution (in particular on CI) //! # std::thread::spawn(|| { //! # std::thread::sleep(std::time::Duration::from_secs(5)); //! # std::process::exit(0); //! # }); //! # //! let mut input = Libinput::new_with_udev(Interface); //! input.udev_assign_seat("seat0").unwrap(); //! loop { //! input.dispatch().unwrap(); //! for event in &mut input { //! println!("Got event: {:?}", event); //! } //! } //! } //! ``` #![deny(missing_docs)] /// Unsafe raw C API. pub mod ffi { pub use input_sys::*; } /// Trait for types that allow to optain the underlying raw libinput pointer. pub trait AsRaw { /// Receive a raw pointer representing this type. fn as_raw(&self) -> *const T; #[doc(hidden)] fn as_raw_mut(&self) -> *mut T { self.as_raw() as *mut _ } } /// Trait to receive the underlying context pub trait Context { /// Returns the underlying libinput context fn context(&self) -> &Libinput; } /// Trait for types that allow to be initialized from a raw pointer pub trait FromRaw { #[doc(hidden)] unsafe fn try_from_raw(ffi: *mut T, context: &context::Libinput) -> Option where Self: Sized; /// Create a new instance of this type from a raw pointer and it's context. /// If the type of the struct is a valid libinput type, but is unknown to this library, it panics instead. /// /// ## Warning /// /// If you make use of [`Userdata`](./trait.Userdata.html) make sure you use the correct types /// to allow receiving the set userdata. When dealing with raw pointers initialized by other /// libraries this must be done extra carefully to select a correct representation. /// /// If unsure using `()` is always a safe option.. /// /// # Safety /// /// If the pointer is pointing to a different struct, invalid memory or `NULL` the returned /// struct may panic on use or cause other undefined behavior. unsafe fn from_raw(ffi: *mut T, context: &context::Libinput) -> Self; } macro_rules! ffi_ref_struct { ($(#[$attr:meta])* struct $struct_name:ident, $ffi_name:path, $ref_fn:path, $unref_fn:path) => ( #[derive(Eq)] $(#[$attr])* pub struct $struct_name { ffi: *mut $ffi_name, context: $crate::context::Libinput, } impl ::std::fmt::Debug for $struct_name { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, "{} @{:p}", stringify!($struct_name), self.as_raw()) } } impl $crate::FromRaw<$ffi_name> for $struct_name { unsafe fn try_from_raw(ffi: *mut $ffi_name, context: &$crate::Libinput) -> Option { Some(Self::from_raw(ffi, context)) } unsafe fn from_raw(ffi: *mut $ffi_name, context: &$crate::Libinput) -> Self { $struct_name { ffi: $ref_fn(ffi), context: context.clone(), } } } impl $crate::AsRaw<$ffi_name> for $struct_name { fn as_raw(&self) -> *const $ffi_name { self.ffi as *const _ } } impl $crate::Context for $struct_name { fn context(&self) -> &$crate::Libinput { &self.context } } impl Clone for $struct_name { fn clone(&self) -> Self { unsafe { $struct_name::from_raw(self.as_raw_mut(), &self.context) } } } impl Drop for $struct_name { fn drop(&mut self) { unsafe { $unref_fn(self.ffi); } } } impl PartialEq for $struct_name { fn eq(&self, other: &Self) -> bool { self.as_raw() == other.as_raw() } } impl ::std::hash::Hash for $struct_name { fn hash(&self, state: &mut H) { self.as_raw().hash(state); } } ) } macro_rules! ffi_func { ($(#[$attr:meta])* fn $name:ident, $ffi_fn:path, bool) => ( $(#[$attr])* fn $name(&self) -> bool { unsafe { $ffi_fn(self.as_raw_mut()) != 0 } } ); ($(#[$attr:meta])* pub fn $name:ident, $ffi_fn:path, bool) => ( $(#[$attr])* pub fn $name(&self) -> bool { unsafe { $ffi_fn(self.as_raw_mut()) != 0 } } ); ($(#[$attr:meta])* fn $name:ident, $ffi_fn:path, $return_type:ty) => ( $(#[$attr])* fn $name(&self) -> $return_type { unsafe { $ffi_fn(self.as_raw_mut()) as $return_type } } ); ($(#[$attr:meta])* pub fn $name:ident, $ffi_fn:path, $return_type:ty) => ( $(#[$attr])* pub fn $name(&self) -> $return_type { unsafe { $ffi_fn(self.as_raw_mut()) as $return_type } } ); } mod context; mod device; pub mod event; mod seat; pub use context::*; pub use device::*; pub use event::Event; pub use seat::*; input-0.9.0/src/seat.rs000064400000000000000000000033641046102023000130700ustar 00000000000000use crate::{ffi, AsRaw, FromRaw, Libinput}; use std::ffi::CStr; ffi_ref_struct!( /// A seat has two identifiers, the physical name and the logical name. /// /// A device is always assigned to exactly one seat. It may change to a /// different logical seat but it cannot change physical seats. See /// [Seats](https://wayland.freedesktop.org/libinput/doc/latest/seats.html) /// for details. struct Seat, ffi::libinput_seat, ffi::libinput_seat_ref, ffi::libinput_seat_unref); impl Seat { /// Get the libinput context from the seat. pub fn context(&self) -> Libinput { self.context.clone() } /// Return the physical name of the seat. /// /// For libinput contexts created from udev, this is always the /// same value as passed into `udev_assign_seat` and all /// seats from that context will have the same physical name. /// /// The physical name of the seat is one that is usually set by the /// system or lower levels of the stack. In most cases, this is the /// base filter for devices - devices assigned to seats outside the /// current seat will not be available to the caller. pub fn physical_name(&self) -> &str { unsafe { CStr::from_ptr(ffi::libinput_seat_get_physical_name(self.as_raw_mut())) .to_str() .expect("Seat physical_name is no valid utf-8") } } /// Return the logical name of the seat. /// /// This is an identifier to group sets of devices within the /// compositor. pub fn logical_name(&self) -> &str { unsafe { CStr::from_ptr(ffi::libinput_seat_get_logical_name(self.as_raw_mut())) .to_str() .expect("Seat logical_name is no valid utf-8") } } }