evdev_rs/
uinput.rs

1use crate::{device::DeviceWrapper, InputEvent};
2use libc::c_int;
3use std::io;
4use std::os::unix::io::RawFd;
5
6use crate::util::*;
7
8use evdev_sys as raw;
9
10/// Opaque struct representing an evdev uinput device
11pub struct UInputDevice {
12    raw: *mut raw::libevdev_uinput,
13}
14
15unsafe impl Send for UInputDevice {}
16
17impl UInputDevice {
18    fn raw(&self) -> *mut raw::libevdev_uinput {
19        self.raw
20    }
21
22    /// Create a uinput device based on the given libevdev device.
23    ///
24    /// The uinput device will be an exact copy of the libevdev device, minus
25    /// the bits that uinput doesn't allow to be set.
26    pub fn create_from_device<T: DeviceWrapper>(device: &T) -> io::Result<UInputDevice> {
27        let mut libevdev_uinput = std::ptr::null_mut();
28        let result = unsafe {
29            raw::libevdev_uinput_create_from_device(
30                device.raw(),
31                raw::LIBEVDEV_UINPUT_OPEN_MANAGED,
32                &mut libevdev_uinput,
33            )
34        };
35
36        match result {
37            0 => Ok(UInputDevice {
38                raw: libevdev_uinput,
39            }),
40            error => Err(io::Error::from_raw_os_error(-error)),
41        }
42    }
43
44    ///Return the device node representing this uinput device.
45    ///
46    /// This relies on `libevdev_uinput_get_syspath()` to provide a valid syspath.
47    pub fn devnode(&self) -> Option<&str> {
48        unsafe { ptr_to_str(raw::libevdev_uinput_get_devnode(self.raw())) }
49    }
50
51    ///Return the syspath representing this uinput device.
52    ///
53    /// If the UI_GET_SYSNAME ioctl not available, libevdev makes an educated
54    /// guess. The UI_GET_SYSNAME ioctl is available since Linux 3.15.
55    ///
56    /// The syspath returned is the one of the input node itself
57    /// (e.g. /sys/devices/virtual/input/input123), not the syspath of the
58    /// device node returned with libevdev_uinput_get_devnode().
59    pub fn syspath(&self) -> Option<&str> {
60        unsafe { ptr_to_str(raw::libevdev_uinput_get_syspath(self.raw())) }
61    }
62
63    /// Return the file descriptor used to create this uinput device.
64    ///
65    /// This is the fd pointing to /dev/uinput. This file descriptor may be used
66    /// to write events that are emitted by the uinput device. Closing this file
67    /// descriptor will destroy the uinput device.
68    pub fn as_fd(&self) -> Option<RawFd> {
69        match unsafe { raw::libevdev_uinput_get_fd(self.raw()) } {
70            0 => None,
71            result => Some(result),
72        }
73    }
74
75    #[deprecated(
76        since = "0.5.0",
77        note = "Prefer `as_fd`. Some function names were changed so they
78        more closely match their type signature. See issue 42 for discussion
79        https://github.com/ndesh26/evdev-rs/issues/42"
80    )]
81    pub fn fd(&self) -> Option<RawFd> {
82        self.as_fd()
83    }
84
85    /// Post an event through the uinput device.
86    ///
87    /// It is the caller's responsibility that any event sequence is terminated
88    /// with an EV_SYN/SYN_REPORT/0 event. Otherwise, listeners on the device
89    /// node will not see the events until the next EV_SYN event is posted.
90    pub fn write_event(&self, event: &InputEvent) -> io::Result<()> {
91        let (ev_type, ev_code) = event_code_to_int(&event.event_code);
92        let ev_value = event.value as c_int;
93
94        let result = unsafe {
95            raw::libevdev_uinput_write_event(self.raw(), ev_type, ev_code, ev_value)
96        };
97
98        match result {
99            0 => Ok(()),
100            error => Err(io::Error::from_raw_os_error(-error)),
101        }
102    }
103}
104
105impl Drop for UInputDevice {
106    fn drop(&mut self) {
107        unsafe {
108            raw::libevdev_uinput_destroy(self.raw());
109        }
110    }
111}
112
113impl std::fmt::Debug for UInputDevice {
114    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
115        f.debug_struct("UInputDevice")
116            .field("devnode", &self.devnode())
117            .finish()
118    }
119}