1use crate::compat::{input_event, input_id, uinput_abs_setup, uinput_setup, UINPUT_MAX_NAME_SIZE};
6use crate::ff::FFEffectData;
7use crate::inputid::{BusType, InputId};
8use crate::{
9 sys, AttributeSetRef, FFEffectCode, InputEvent, KeyCode, MiscCode, PropType, RelativeAxisCode,
10 SwitchCode, SynchronizationEvent, UInputCode, UInputEvent, UinputAbsSetup,
11};
12use std::ffi::{CStr, OsStr};
13use std::os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd};
14use std::os::unix::ffi::OsStrExt;
15use std::path::{Path, PathBuf};
16use std::{fs, io};
17
18const UINPUT_PATH: &str = "/dev/uinput";
19const SYSFS_PATH: &str = "/sys/devices/virtual/input";
20const DEV_PATH: &str = "/dev/input";
21
22#[derive(Debug)]
24pub struct VirtualDeviceBuilder<'a> {
25 fd: OwnedFd,
26 name: &'a [u8],
27 id: Option<input_id>,
28 ff_effects_max: u32,
29}
30
31impl<'a> VirtualDeviceBuilder<'a> {
35 #[deprecated(note = "use `VirtualDevice::builder()` instead")]
36 #[doc(hidden)]
37 pub fn new() -> io::Result<Self> {
38 let fd = fs::OpenOptions::new()
40 .read(true)
41 .write(true)
42 .open(UINPUT_PATH)?;
43
44 Ok(VirtualDeviceBuilder {
45 fd: fd.into(),
46 name: Default::default(),
47 id: None,
48 ff_effects_max: 0,
49 })
50 }
51
52 #[inline]
54 pub fn name<S: AsRef<[u8]> + ?Sized>(mut self, name: &'a S) -> Self {
55 self.name = name.as_ref();
56 self
57 }
58
59 #[inline]
61 pub fn input_id(mut self, id: InputId) -> Self {
62 self.id = Some(id.0);
63 self
64 }
65
66 pub fn with_phys(self, path: &CStr) -> io::Result<Self> {
68 unsafe {
69 sys::ui_set_phys(self.fd.as_raw_fd(), path.as_ptr())?;
70 }
71 Ok(self)
72 }
73
74 pub fn with_keys(self, keys: &AttributeSetRef<KeyCode>) -> io::Result<Self> {
76 unsafe {
78 sys::ui_set_evbit(
79 self.fd.as_raw_fd(),
80 crate::EventType::KEY.0 as nix::sys::ioctl::ioctl_param_type,
81 )?;
82 }
83
84 for bit in keys.iter() {
85 unsafe {
86 sys::ui_set_keybit(
87 self.fd.as_raw_fd(),
88 bit.0 as nix::sys::ioctl::ioctl_param_type,
89 )?;
90 }
91 }
92
93 Ok(self)
94 }
95
96 pub fn with_absolute_axis(self, axis: &UinputAbsSetup) -> io::Result<Self> {
98 unsafe {
99 sys::ui_set_evbit(
100 self.fd.as_raw_fd(),
101 crate::EventType::ABSOLUTE.0 as nix::sys::ioctl::ioctl_param_type,
102 )?;
103 sys::ui_set_absbit(
104 self.fd.as_raw_fd(),
105 axis.code() as nix::sys::ioctl::ioctl_param_type,
106 )?;
107 sys::ui_abs_setup(self.fd.as_raw_fd(), &axis.0 as *const uinput_abs_setup)?;
108 }
109
110 Ok(self)
111 }
112
113 pub fn with_relative_axes(self, axes: &AttributeSetRef<RelativeAxisCode>) -> io::Result<Self> {
115 unsafe {
116 sys::ui_set_evbit(
117 self.fd.as_raw_fd(),
118 crate::EventType::RELATIVE.0 as nix::sys::ioctl::ioctl_param_type,
119 )?;
120 }
121
122 for bit in axes.iter() {
123 unsafe {
124 sys::ui_set_relbit(
125 self.fd.as_raw_fd(),
126 bit.0 as nix::sys::ioctl::ioctl_param_type,
127 )?;
128 }
129 }
130
131 Ok(self)
132 }
133
134 pub fn with_properties(self, switches: &AttributeSetRef<PropType>) -> io::Result<Self> {
136 for bit in switches.iter() {
137 unsafe {
138 sys::ui_set_propbit(
139 self.fd.as_raw_fd(),
140 bit.0 as nix::sys::ioctl::ioctl_param_type,
141 )?;
142 }
143 }
144
145 Ok(self)
146 }
147
148 pub fn with_switches(self, switches: &AttributeSetRef<SwitchCode>) -> io::Result<Self> {
150 unsafe {
151 sys::ui_set_evbit(
152 self.fd.as_raw_fd(),
153 crate::EventType::SWITCH.0 as nix::sys::ioctl::ioctl_param_type,
154 )?;
155 }
156
157 for bit in switches.iter() {
158 unsafe {
159 sys::ui_set_swbit(
160 self.fd.as_raw_fd(),
161 bit.0 as nix::sys::ioctl::ioctl_param_type,
162 )?;
163 }
164 }
165
166 Ok(self)
167 }
168
169 pub fn with_ff(self, ff: &AttributeSetRef<FFEffectCode>) -> io::Result<Self> {
171 unsafe {
172 sys::ui_set_evbit(
173 self.fd.as_raw_fd(),
174 crate::EventType::FORCEFEEDBACK.0 as nix::sys::ioctl::ioctl_param_type,
175 )?;
176 }
177
178 for bit in ff.iter() {
179 unsafe {
180 sys::ui_set_ffbit(
181 self.fd.as_raw_fd(),
182 bit.0 as nix::sys::ioctl::ioctl_param_type,
183 )?;
184 }
185 }
186
187 Ok(self)
188 }
189
190 pub fn with_ff_effects_max(mut self, ff_effects_max: u32) -> Self {
192 self.ff_effects_max = ff_effects_max;
193 self
194 }
195
196 pub fn with_msc(self, misc_set: &AttributeSetRef<MiscCode>) -> io::Result<Self> {
198 unsafe {
199 sys::ui_set_evbit(
200 self.fd.as_raw_fd(),
201 crate::EventType::MISC.0 as nix::sys::ioctl::ioctl_param_type,
202 )?;
203 }
204
205 for bit in misc_set.iter() {
206 unsafe {
207 sys::ui_set_mscbit(
208 self.fd.as_raw_fd(),
209 bit.0 as nix::sys::ioctl::ioctl_param_type,
210 )?;
211 }
212 }
213
214 Ok(self)
215 }
216
217 pub fn build(self) -> io::Result<VirtualDevice> {
222 let mut usetup = uinput_setup {
225 id: self.id.unwrap_or(DEFAULT_ID),
226 name: [0; UINPUT_MAX_NAME_SIZE],
227 ff_effects_max: self.ff_effects_max,
228 };
229
230 let name_bytes = unsafe { &*(self.name as *const [u8] as *const [libc::c_char]) };
232 assert!(name_bytes.len() + 1 < UINPUT_MAX_NAME_SIZE);
236 usetup.name[..name_bytes.len()].copy_from_slice(name_bytes);
237
238 VirtualDevice::new(self.fd, &usetup)
239 }
240}
241
242const DEFAULT_ID: input_id = input_id {
243 bustype: BusType::BUS_USB.0,
244 vendor: 0x1234, product: 0x5678, version: 0x111,
247};
248
249#[derive(Debug)]
251pub struct VirtualDevice {
252 fd: OwnedFd,
253 pub(crate) event_buf: Vec<input_event>,
254}
255
256impl VirtualDevice {
257 pub fn builder<'a>() -> io::Result<VirtualDeviceBuilder<'a>> {
259 #[allow(deprecated)]
260 VirtualDeviceBuilder::new()
261 }
262
263 fn new(fd: OwnedFd, usetup: &uinput_setup) -> io::Result<Self> {
265 unsafe { sys::ui_dev_setup(fd.as_raw_fd(), usetup)? };
266 unsafe { sys::ui_dev_create(fd.as_raw_fd())? };
267
268 Ok(VirtualDevice {
269 fd,
270 event_buf: vec![],
271 })
272 }
273
274 #[inline]
275 fn write_raw(&mut self, events: &[InputEvent]) -> io::Result<()> {
276 crate::write_events(self.fd.as_fd(), events)?;
277 Ok(())
278 }
279
280 pub fn get_syspath(&mut self) -> io::Result<PathBuf> {
285 let mut syspath = vec![0u8; 256];
286 let len = unsafe { sys::ui_get_sysname(self.fd.as_raw_fd(), &mut syspath)? };
287 syspath.truncate(len as usize - 1);
288
289 let syspath = OsStr::from_bytes(&syspath);
290
291 Ok(Path::new(SYSFS_PATH).join(syspath))
292 }
293
294 pub fn enumerate_dev_nodes_blocking(&mut self) -> io::Result<DevNodesBlocking> {
296 let path = self.get_syspath()?;
297 let dir = std::fs::read_dir(path)?;
298
299 Ok(DevNodesBlocking { dir })
300 }
301
302 #[cfg(feature = "tokio")]
304 pub async fn enumerate_dev_nodes(&mut self) -> io::Result<DevNodes> {
305 let path = self.get_syspath()?;
306 let dir = tokio::fs::read_dir(path).await?;
307
308 Ok(DevNodes { dir })
309 }
310
311 pub fn emit(&mut self, events: &[InputEvent]) -> io::Result<()> {
319 self.write_raw(events)?;
320 let syn = *SynchronizationEvent::new(crate::SynchronizationCode::SYN_REPORT, 0);
321 self.write_raw(&[syn])
322 }
323
324 pub fn process_ff_upload(&mut self, event: UInputEvent) -> io::Result<FFUploadEvent> {
335 assert_eq!(event.code(), UInputCode::UI_FF_UPLOAD);
336
337 let mut request: sys::uinput_ff_upload = unsafe { std::mem::zeroed() };
338 request.request_id = event.value() as u32;
339 unsafe { sys::ui_begin_ff_upload(self.fd.as_raw_fd(), &mut request)? };
340
341 request.retval = 0;
342
343 let fd = self.fd.try_clone()?;
344
345 Ok(FFUploadEvent { fd, request })
346 }
347
348 pub fn process_ff_erase(&mut self, event: UInputEvent) -> io::Result<FFEraseEvent> {
359 assert_eq!(event.code(), UInputCode::UI_FF_ERASE);
360
361 let mut request: sys::uinput_ff_erase = unsafe { std::mem::zeroed() };
362 request.request_id = event.value() as u32;
363 unsafe { sys::ui_begin_ff_erase(self.fd.as_raw_fd(), &mut request)? };
364
365 request.retval = 0;
366
367 let fd = self.fd.try_clone()?;
368
369 Ok(FFEraseEvent { fd, request })
370 }
371
372 pub(crate) fn fill_events(&mut self) -> io::Result<usize> {
377 let fd = self.fd.as_raw_fd();
378 self.event_buf.reserve(crate::EVENT_BATCH_SIZE);
379
380 let spare_capacity = self.event_buf.spare_capacity_mut();
381 let spare_capacity_size = std::mem::size_of_val(spare_capacity);
382
383 let res = unsafe { libc::read(fd, spare_capacity.as_mut_ptr() as _, spare_capacity_size) };
385 let bytes_read = nix::errno::Errno::result(res)?;
386 let num_read = bytes_read as usize / std::mem::size_of::<input_event>();
387 unsafe {
388 let len = self.event_buf.len();
389 self.event_buf.set_len(len + num_read);
390 }
391 Ok(num_read)
392 }
393
394 pub fn fetch_events(&mut self) -> io::Result<impl Iterator<Item = InputEvent> + '_> {
400 self.fill_events()?;
401 Ok(self.event_buf.drain(..).map(InputEvent::from))
402 }
403
404 #[cfg(feature = "tokio")]
405 #[inline]
406 pub fn into_event_stream(self) -> io::Result<VirtualEventStream> {
407 VirtualEventStream::new(self)
408 }
409}
410
411pub struct DevNodesBlocking {
414 dir: std::fs::ReadDir,
415}
416
417impl Iterator for DevNodesBlocking {
418 type Item = io::Result<PathBuf>;
419
420 fn next(&mut self) -> Option<Self::Item> {
421 for entry in self.dir.by_ref() {
422 let entry = match entry {
423 Ok(entry) => entry,
424 Err(e) => return Some(Err(e)),
425 };
426
427 let file_name = entry.file_name();
429
430 if !file_name.as_bytes().starts_with(b"event") {
432 continue;
433 }
434
435 let path = Path::new(DEV_PATH).join(file_name);
437
438 return Some(Ok(path));
439 }
440
441 None
442 }
443}
444
445#[cfg(feature = "tokio")]
449pub struct DevNodes {
450 dir: tokio::fs::ReadDir,
451}
452
453#[cfg(feature = "tokio")]
454impl DevNodes {
455 pub async fn next_entry(&mut self) -> io::Result<Option<PathBuf>> {
457 while let Some(entry) = self.dir.next_entry().await? {
458 let file_name = entry.file_name();
460
461 if !file_name.as_bytes().starts_with(b"event") {
463 continue;
464 }
465
466 let path = Path::new(DEV_PATH).join(file_name);
468
469 return Ok(Some(path));
470 }
471
472 Ok(None)
473 }
474}
475
476impl AsFd for VirtualDevice {
477 fn as_fd(&self) -> BorrowedFd<'_> {
478 self.fd.as_fd()
479 }
480}
481
482impl AsRawFd for VirtualDevice {
483 fn as_raw_fd(&self) -> RawFd {
484 self.fd.as_raw_fd()
485 }
486}
487
488pub struct FFUploadEvent {
490 fd: OwnedFd,
491 request: sys::uinput_ff_upload,
492}
493
494impl FFUploadEvent {
495 pub fn old_effect(&self) -> FFEffectData {
497 self.request.old.into()
498 }
499
500 pub fn effect_id(&self) -> i16 {
502 self.request.effect.id
503 }
504
505 pub fn set_effect_id(&mut self, id: i16) {
507 self.request.effect.id = id;
508 }
509
510 pub fn effect(&self) -> FFEffectData {
512 self.request.effect.into()
513 }
514
515 pub fn retval(&self) -> i32 {
517 self.request.retval
518 }
519
520 pub fn set_retval(&mut self, value: i32) {
522 self.request.retval = value;
523 }
524}
525
526impl Drop for FFUploadEvent {
527 fn drop(&mut self) {
528 unsafe {
529 let _ = sys::ui_end_ff_upload(self.fd.as_raw_fd(), &self.request);
530 }
531 }
532}
533
534pub struct FFEraseEvent {
536 fd: OwnedFd,
537 request: sys::uinput_ff_erase,
538}
539
540impl FFEraseEvent {
541 pub fn effect_id(&self) -> u32 {
543 self.request.effect_id
544 }
545
546 pub fn retval(&self) -> i32 {
548 self.request.retval
549 }
550
551 pub fn set_retval(&mut self, value: i32) {
553 self.request.retval = value;
554 }
555}
556
557impl Drop for FFEraseEvent {
558 fn drop(&mut self) {
559 unsafe {
560 let _ = sys::ui_end_ff_erase(self.fd.as_raw_fd(), &self.request);
561 }
562 }
563}
564
565#[cfg(feature = "tokio")]
566mod tokio_stream {
567 use super::*;
568
569 use std::future::poll_fn;
570 use std::task::{ready, Context, Poll};
571 use tokio::io::unix::AsyncFd;
572
573 pub struct VirtualEventStream {
580 device: AsyncFd<VirtualDevice>,
581 index: usize,
582 }
583 impl Unpin for VirtualEventStream {}
584
585 impl VirtualEventStream {
586 pub(crate) fn new(device: VirtualDevice) -> io::Result<Self> {
587 use nix::fcntl;
588 fcntl::fcntl(device.as_raw_fd(), fcntl::F_SETFL(fcntl::OFlag::O_NONBLOCK))?;
589 let device = AsyncFd::new(device)?;
590 Ok(Self { device, index: 0 })
591 }
592
593 pub fn device(&self) -> &VirtualDevice {
595 self.device.get_ref()
596 }
597
598 pub fn device_mut(&mut self) -> &mut VirtualDevice {
600 self.device.get_mut()
601 }
602
603 pub async fn next_event(&mut self) -> io::Result<InputEvent> {
606 poll_fn(|cx| self.poll_event(cx)).await
607 }
608
609 pub fn poll_event(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<InputEvent>> {
611 'outer: loop {
612 if let Some(&ev) = self.device.get_ref().event_buf.get(self.index) {
613 self.index += 1;
614 return Poll::Ready(Ok(InputEvent::from(ev)));
615 }
616
617 self.device.get_mut().event_buf.clear();
618 self.index = 0;
619
620 loop {
621 let mut guard = ready!(self.device.poll_read_ready_mut(cx))?;
622
623 let res = guard.try_io(|device| device.get_mut().fill_events());
624 match res {
625 Ok(res) => {
626 let _ = res?;
627 continue 'outer;
628 }
629 Err(_would_block) => continue,
630 }
631 }
632 }
633 }
634 }
635
636 #[cfg(feature = "stream-trait")]
637 impl futures_core::Stream for VirtualEventStream {
638 type Item = io::Result<InputEvent>;
639 fn poll_next(
640 self: std::pin::Pin<&mut Self>,
641 cx: &mut Context<'_>,
642 ) -> Poll<Option<Self::Item>> {
643 self.get_mut().poll_event(cx).map(Some)
644 }
645 }
646}
647#[cfg(feature = "tokio")]
648pub use tokio_stream::VirtualEventStream;