1use std::{io, fs, ptr};
5use std::os::unix::io::{RawFd, AsRawFd, IntoRawFd, FromRawFd};
6use std::os::unix::ffi::OsStrExt;
7use std::os::fd::{AsFd, BorrowedFd, OwnedFd};
8use std::os::raw::c_char;
9use std::mem::{MaybeUninit, size_of};
10use std::path::{Path, PathBuf};
11use std::slice::{from_raw_parts, from_raw_parts_mut};
12use std::ffi::{OsStr, OsString, CStr};
13use crate::sys;
14use nix;
15use crate::{Key, InputId, AbsoluteInfoSetup, kinds};
16use crate::macros::convert_error;
17
18pub use crate::sys::{UINPUT_MAX_NAME_SIZE, UINPUT_VERSION};
19
20pub struct UInputHandle<F>(F);
22
23fn copy_name(dest: &mut [c_char; UINPUT_MAX_NAME_SIZE as usize], name: &[u8]) -> io::Result<()> {
24 if name.len() >= UINPUT_MAX_NAME_SIZE as usize {
25 Err(io::Error::new(io::ErrorKind::InvalidInput, "name too long"))
26 } else {
27 unsafe {
28 ptr::copy_nonoverlapping(name.as_ptr() as *const _, dest.as_mut_ptr() as *mut _, name.len());
29 }
30 dest[name.len()] = 0;
31
32 Ok(())
33 }
34}
35
36impl<F> UInputHandle<F> {
37 pub const fn new(fd: F) -> Self {
39 UInputHandle(fd)
40 }
41
42 pub fn into_inner(self) -> F {
44 self.0
45 }
46
47 pub const fn as_inner(&self) -> &F {
49 &self.0
50 }
51
52 pub fn as_inner_mut(&mut self) -> &mut F {
54 &mut self.0
55 }
56}
57
58impl<F: AsRawFd> AsFd for UInputHandle<F> {
59 fn as_fd<'a>(&'a self) -> BorrowedFd<'a> {
60 unsafe {
61 BorrowedFd::borrow_raw(self.fd())
62 }
63 }
64}
65
66impl<F: IntoRawFd> IntoRawFd for UInputHandle<F> {
67 fn into_raw_fd(self) -> RawFd {
68 self.0.into_raw_fd()
69 }
70}
71
72impl<F: FromRawFd> FromRawFd for UInputHandle<F> {
73 unsafe fn from_raw_fd(fd: RawFd) -> Self {
74 UInputHandle(FromRawFd::from_raw_fd(fd))
75 }
76}
77
78impl UInputHandle<OwnedFd> {
79 pub unsafe fn from_fd(fd: RawFd) -> Self {
81 FromRawFd::from_raw_fd(fd)
82 }
83}
84
85impl<F: AsRawFd> UInputHandle<F> {
86 #[inline]
87 fn fd(&self) -> RawFd {
88 self.0.as_raw_fd()
89 }
90
91 pub fn create_legacy(&self, id: &InputId, name: &[u8], ff_effects_max: u32, abs: &[AbsoluteInfoSetup]) -> io::Result<()> {
93 let mut setup: sys::uinput_user_dev = unsafe { MaybeUninit::zeroed().assume_init() };
94 setup.id = (*id).into();
95 setup.ff_effects_max = ff_effects_max;
96
97 copy_name(&mut setup.name, name)?;
98
99 for abs in abs {
100 let code = abs.axis as usize;
101 if code >= sys::ABS_CNT as _ {
102 return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid abs axis code"))
103 }
104
105 let abs = &abs.info;
106 setup.absmax[code] = abs.maximum;
107 setup.absmin[code] = abs.minimum;
108 setup.absfuzz[code] = abs.fuzz;
109 setup.absflat[code] = abs.flat;
110 }
111
112 let setup = unsafe { from_raw_parts(&setup as *const _ as *const u8, size_of::<sys::uinput_user_dev>()) };
113 nix::unistd::write(self, setup).map_err(convert_error)?;
114
115 self.dev_create()
116 }
117
118 pub fn create(&self, id: &InputId, name: &[u8], ff_effects_max: u32, abs: &[AbsoluteInfoSetup]) -> io::Result<()> {
120 let mut setup: sys::uinput_setup = unsafe { MaybeUninit::zeroed().assume_init() };
121 setup.id = (*id).into();
122 setup.ff_effects_max = ff_effects_max;
123
124 copy_name(&mut setup.name, name)?;
125
126 match self.dev_setup(&setup) {
127 Err(ref e) if e.raw_os_error() == Some(sys::Errno::EINVAL as _) =>
128 return self.create_legacy(id, name, ff_effects_max, abs),
129 v => v,
130 }?;
131
132 for abs in abs {
133 self.abs_setup(abs.into())?;
134 }
135
136 self.dev_create()
137 }
138
139 pub fn write(&self, events: &[sys::input_event]) -> io::Result<usize> {
141 let events = unsafe { from_raw_parts(events.as_ptr() as *const u8, size_of::<sys::input_event>() * events.len()) };
142 nix::unistd::write(self, events)
143 .map(|c| c / size_of::<sys::input_event>()).map_err(convert_error)
144 }
145
146 pub fn read(&self, events: &mut [sys::input_event]) -> io::Result<usize> {
148 let events = unsafe { from_raw_parts_mut(events.as_mut_ptr() as *mut u8, size_of::<sys::input_event>() * events.len()) };
149 nix::unistd::read(self.fd(), events)
150 .map(|len| len / size_of::<sys::input_event>()).map_err(convert_error)
151 }
152
153 pub fn sys_path(&self) -> io::Result<PathBuf> {
157 let sys = self.sys_name()?;
158 let sys = CStr::from_bytes_with_nul(&sys).map(|c| c.to_bytes()).unwrap_or(&sys);
159 Ok(Path::new("/sys/devices/virtual/input/").join(OsStr::from_bytes(sys)))
160 }
161
162 pub fn evdev_name(&self) -> io::Result<OsString> {
164 let sys = self.sys_path()?;
165 fs::read_dir(&sys)?.filter_map(|e| match e {
166 Err(err) => Some(Err(err)),
167 Ok(e) => match e.file_type() {
168 Err(err) => Some(Err(err)),
169 Ok(ty) if ty.is_dir() => {
170 let name = e.file_name();
171 if name.as_bytes().starts_with(b"event") {
172 Some(Ok(e.file_name()))
173 } else {
174 None
175 }
176 },
177 Ok(..) => None,
178 },
179 }).next().unwrap_or_else(|| Err(io::Error::new(io::ErrorKind::NotFound, "event input device not found")))
180 }
181
182 pub fn evdev_path(&self) -> io::Result<PathBuf> {
186 self.evdev_name().map(|ev| Path::new("/dev/input/").join(ev))
187 }
188
189 ioctl_impl! {
190 {
191 @call dev_create = ui_dev_create
193 }
194 {
195 @call dev_destroy = ui_dev_destroy
197 }
198 {
199 @set dev_setup(&sys::uinput_setup) = ui_dev_setup
201 }
202 {
203 @set abs_setup(&sys::uinput_abs_setup) = ui_abs_setup
205 }
206 {
207 @set set_evbit(kinds::EventKind) = ui_set_evbit
209 }
210 {
211 @set set_keybit(Key) = ui_set_keybit
213 }
214 {
215 @set set_relbit(kinds::RelativeAxis) = ui_set_relbit
217 }
218 {
219 @set set_absbit(kinds::AbsoluteAxis) = ui_set_absbit
221 }
222 {
223 @set set_mscbit(kinds::MiscKind) = ui_set_mscbit
225 }
226 {
227 @set set_ledbit(kinds::LedKind) = ui_set_ledbit
229 }
230 {
231 @set set_sndbit(kinds::SoundKind) = ui_set_sndbit
233 }
234 {
235 @set set_ffbit(kinds::ForceFeedbackKind) = ui_set_ffbit
237 }
238 {
239 @set_str set_phys = ui_set_phys
241 }
242 {
243 @set set_swbit(kinds::SwitchKind) = ui_set_swbit
245 }
246 {
247 @set set_propbit(kinds::InputProperty) = ui_set_propbit
249 }
250 {
251 @set ff_upload_begin(&mut sys::uinput_ff_upload) = ui_begin_ff_upload
253 }
254 {
255 @set ff_upload_end(&sys::uinput_ff_upload) = ui_end_ff_upload
257 }
258 {
259 @set ff_erase_begin(&mut sys::uinput_ff_erase) = ui_begin_ff_erase
261 }
262 {
263 @set ff_erase_end(&sys::uinput_ff_erase) = ui_end_ff_erase
265 }
266 {
267 @get_str sys_name, sys_name_buf = ui_get_sysname
269 }
270 {
271 @get version = ui_get_version -> u32
273 }
274 }
275}