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