vmouse/
vmouse.rs

1use std::fs::File;
2
3use evdev_rs::enums::{BusType, EventCode, EventType, EV_KEY, EV_REL, EV_SYN};
4use evdev_rs::{Device, DeviceWrapper, InputEvent, ReadFlag, UInputDevice, UninitDevice};
5
6const MOUSE_STEP_X: i32 = 10;
7const MOUSE_STEP_Y: i32 = 10;
8
9fn main() -> Result<(), std::io::Error> {
10    // Parse command line arguments
11    let mut args = std::env::args();
12
13    if args.len() != 2 {
14        let n = args.nth(0).unwrap();
15        println!("Usage: `{} DEVICE`, eg. `{} /dev/input/event13`", n, n);
16        std::process::exit(1);
17    }
18
19    let device = &args.nth(1).unwrap();
20
21    // Connect to real keyboard
22    let f = File::open(device)?;
23    let d = Device::new_from_file(f)?;
24
25    if let Some(n) = d.name() {
26        println!(
27            "Connected to device: '{}' ({:04x}:{:04x})",
28            n,
29            d.vendor_id(),
30            d.product_id()
31        );
32    }
33
34    // Create virtual device
35    let u = UninitDevice::new().unwrap();
36
37    // Setup device
38    // per: https://01.org/linuxgraphics/gfx-docs/drm/input/uinput.html#mouse-movements
39
40    u.set_name("Virtual Mouse");
41    u.set_bustype(BusType::BUS_USB as u16);
42    u.set_vendor_id(0xabcd);
43    u.set_product_id(0xefef);
44
45    // Note mouse keys have to be enabled for this to be detected
46    // as a usable device, see: https://stackoverflow.com/a/64559658/6074942
47    u.enable(EventCode::EV_KEY(EV_KEY::BTN_LEFT))?;
48    u.enable(EventCode::EV_KEY(EV_KEY::BTN_RIGHT))?;
49
50    u.enable(EventCode::EV_REL(EV_REL::REL_X))?;
51    u.enable(EventCode::EV_REL(EV_REL::REL_Y))?;
52
53    u.enable(EventCode::EV_SYN(EV_SYN::SYN_REPORT))?;
54
55    // Attempt to create UInputDevice from UninitDevice
56    let v = UInputDevice::create_from_device(&u)?;
57
58    loop {
59        // Fetch keyboard events
60        let (_status, event) = d.next_event(ReadFlag::NORMAL | ReadFlag::BLOCKING)?;
61
62        // Map these to mouse events
63        println!("Event: {:?}", event);
64
65        // Map direction keys to mouse events
66        let e = match event.event_code {
67            EventCode::EV_KEY(EV_KEY::KEY_RIGHT) => Some((EV_REL::REL_X, MOUSE_STEP_X)),
68            EventCode::EV_KEY(EV_KEY::KEY_LEFT) => Some((EV_REL::REL_X, -MOUSE_STEP_X)),
69            EventCode::EV_KEY(EV_KEY::KEY_UP) => Some((EV_REL::REL_Y, -MOUSE_STEP_Y)),
70            EventCode::EV_KEY(EV_KEY::KEY_DOWN) => Some((EV_REL::REL_Y, MOUSE_STEP_Y)),
71            _ => None,
72        };
73
74        // Write mapped event
75        if let Some((e, n)) = e {
76            v.write_event(&InputEvent {
77                time: event.time,
78                event_code: EventCode::EV_REL(e),
79                value: n,
80            })?;
81
82            v.write_event(&InputEvent {
83                time: event.time,
84                event_code: EventCode::EV_SYN(EV_SYN::SYN_REPORT),
85                value: 0,
86            })?;
87        }
88    }
89}