use glam::Vec2; use idmap::{idmap, IdMap}; use idmap_derive::IntegerId; use input_linux::{ AbsoluteAxis, AbsoluteInfo, AbsoluteInfoSetup, EventKind, InputId, Key, RelativeAxis, UInputHandle, }; use libc::{input_event, timeval}; use once_cell::sync::Lazy; use std::fs::File; use std::mem::transmute; use strum::{EnumIter, EnumString, IntoEnumIterator}; pub fn initialize() -> Box { if let Some(uinput) = UInputProvider::try_new() { log::info!("Initialized uinput."); return Box::new(uinput); } log::error!("Could not create uinput provider. Keyboard/Mouse input will not work!"); log::error!("Check if you're in `input` group: `id -nG`"); Box::new(DummyProvider {}) } pub trait HidProvider { fn mouse_move(&mut self, pos: Vec2); fn send_button(&self, button: u16, down: bool); fn wheel(&self, delta: i32); fn set_modifiers(&mut self, mods: u8); fn send_key(&self, key: u16, down: bool); fn set_desktop_extent(&mut self, extent: Vec2); fn on_new_frame(&mut self); } pub struct UInputProvider { handle: UInputHandle, desktop_extent: Vec2, mouse_moved: bool, cur_modifiers: u8, } pub struct DummyProvider; pub const MOUSE_LEFT: u16 = 0x110; pub const MOUSE_RIGHT: u16 = 0x111; pub const MOUSE_MIDDLE: u16 = 0x112; const MOUSE_EXTENT: f32 = 32768.; const EV_SYN: u16 = 0x0; const EV_KEY: u16 = 0x1; const EV_REL: u16 = 0x2; const EV_ABS: u16 = 0x3; impl UInputProvider { fn try_new() -> Option { if let Ok(file) = File::create("/dev/uinput") { let handle = UInputHandle::new(file); let id = InputId { bustype: 0x03, vendor: 0x4711, product: 0x0829, version: 5, }; let name = b"WlxOverlay-S Keyboard-Mouse Hybrid Thing\0"; let abs_info = vec![ AbsoluteInfoSetup { axis: input_linux::AbsoluteAxis::X, info: AbsoluteInfo { value: 0, minimum: 0, maximum: MOUSE_EXTENT as _, fuzz: 0, flat: 0, resolution: 10, }, }, AbsoluteInfoSetup { axis: input_linux::AbsoluteAxis::Y, info: AbsoluteInfo { value: 0, minimum: 0, maximum: MOUSE_EXTENT as _, fuzz: 0, flat: 0, resolution: 10, }, }, ]; if handle.set_evbit(EventKind::Key).is_err() { return None; } if handle.set_evbit(EventKind::Absolute).is_err() { return None; } if handle.set_evbit(EventKind::Relative).is_err() { return None; } for btn in MOUSE_LEFT..=MOUSE_MIDDLE { let key: Key = unsafe { transmute(btn) }; if handle.set_keybit(key).is_err() { return None; } } for key in VirtualKey::iter() { let key: Key = unsafe { transmute((key as u16) - 8) }; if handle.set_keybit(key).is_err() { return None; } } if handle.set_absbit(AbsoluteAxis::X).is_err() { return None; } if handle.set_absbit(AbsoluteAxis::Y).is_err() { return None; } if handle.set_relbit(RelativeAxis::Wheel).is_err() { return None; } if handle.create(&id, name, 0, &abs_info).is_ok() { return Some(UInputProvider { handle, desktop_extent: Vec2::ZERO, mouse_moved: false, cur_modifiers: 0, }); } } None } } impl HidProvider for UInputProvider { fn mouse_move(&mut self, pos: Vec2) { if self.mouse_moved { return; } self.mouse_moved = true; #[cfg(debug_assertions)] log::trace!("Mouse move: {:?}", pos); let pos = pos * (MOUSE_EXTENT / self.desktop_extent); let time = get_time(); let events = [ new_event(time, EV_ABS, AbsoluteAxis::X as _, pos.x as i32), new_event(time, EV_ABS, AbsoluteAxis::Y as _, pos.y as i32), new_event(time, EV_SYN, 0, 0), ]; if let Err(res) = self.handle.write(&events) { log::error!("{}", res.to_string()); } } fn send_button(&self, button: u16, down: bool) { let time = get_time(); let events = [ new_event(time, EV_KEY, button, down as _), new_event(time, EV_SYN, 0, 0), ]; if let Err(res) = self.handle.write(&events) { log::error!("send_button: {}", res.to_string()); } } fn wheel(&self, delta: i32) { let time = get_time(); let events = [ new_event(time, EV_REL, RelativeAxis::Wheel as _, delta), new_event(time, EV_SYN, 0, 0), ]; if let Err(res) = self.handle.write(&events) { log::error!("wheel: {}", res.to_string()); } } fn set_modifiers(&mut self, modifiers: u8) { let changed = self.cur_modifiers ^ modifiers; for i in 0..7 { let m = 1 << i; if changed & m != 0 { if let Some(vk) = MODS_TO_KEYS.get(m).into_iter().flatten().next() { self.send_key(*vk as u16, modifiers & m != 0); } } } self.cur_modifiers = modifiers; } fn send_key(&self, key: u16, down: bool) { let time = get_time(); let events = [ new_event(time, EV_KEY, key - 8, down as _), new_event(time, EV_SYN, 0, 0), ]; if let Err(res) = self.handle.write(&events) { log::error!("send_key: {}", res.to_string()); } } fn set_desktop_extent(&mut self, extent: Vec2) { log::info!("Desktop extent: {:?}", extent); self.desktop_extent = extent; } fn on_new_frame(&mut self) { self.mouse_moved = false; } } impl HidProvider for DummyProvider { fn mouse_move(&mut self, _pos: Vec2) {} fn send_button(&self, _button: u16, _down: bool) {} fn wheel(&self, _delta: i32) {} fn set_modifiers(&mut self, _modifiers: u8) {} fn send_key(&self, _key: u16, _down: bool) {} fn set_desktop_extent(&mut self, _extent: Vec2) {} fn on_new_frame(&mut self) {} } #[inline] fn get_time() -> timeval { let mut time = timeval { tv_sec: 0, tv_usec: 0, }; unsafe { libc::gettimeofday(&mut time, std::ptr::null_mut()) }; time } #[inline] fn new_event(time: timeval, type_: u16, code: u16, value: i32) -> input_event { input_event { time, type_, code, value, } } pub type KeyModifier = u8; pub const SHIFT: KeyModifier = 0x01; pub const CAPS_LOCK: KeyModifier = 0x02; pub const CTRL: KeyModifier = 0x04; pub const ALT: KeyModifier = 0x08; pub const NUM_LOCK: KeyModifier = 0x10; pub const SUPER: KeyModifier = 0x40; pub const META: KeyModifier = 0x80; #[allow(non_camel_case_types)] #[repr(u16)] #[derive(Debug, PartialEq, Clone, Copy, IntegerId, EnumString, EnumIter)] pub enum VirtualKey { Escape = 9, N1, // number row N2, N3, N4, N5, N6, N7, N8, N9, N0, Minus, Plus, BackSpace, Tab, Q, W, E, R, T, Y, U, I, O, P, Oem4, // [ { Oem6, // ] } Return, LCtrl, A, S, D, F, G, H, J, K, L, Oem1, // ; : Oem7, // ' " Oem3, // ` ~ LShift, Oem5, // \ | Z, X, C, V, B, N, M, Comma, // , < Period, // . > Oem2, // / ? RShift, KP_Multiply, LAlt, Space, Caps, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, NumLock, Scroll, KP_7, // KeyPad KP_8, KP_9, KP_Subtract, KP_4, KP_5, KP_6, KP_Add, KP_1, KP_2, KP_3, KP_0, KP_Decimal, Oem102 = 94, // Optional key usually between LShift and Z F11, F12, AbntC1, Katakana, Hiragana, Henkan, Kana, Muhenkan, KP_Enter = 104, RCtrl, KP_Divide, Print, Meta, // Right Alt aka AltGr Home = 110, Up, Prior, Left, Right, End, Down, Next, Insert, Delete, XF86AudioMute = 121, XF86AudioLowerVolume, XF86AudioRaiseVolume, Pause = 127, AbntC2 = 129, Hangul, Hanja, LSuper = 133, RSuper, Menu, Help = 146, XF86MenuKB, XF86Sleep = 150, XF86Xfer = 155, XF86Launch1, XF86Launch2, XF86WWW, XF86Mail = 163, XF86Favorites, XF86MyComputer, XF86Back, XF86Forward, XF86AudioNext = 171, XF86AudioPlay, XF86AudioPrev, XF86AudioStop, XF86HomePage = 180, XF86Reload, F13 = 191, F14, F15, F16, F17, F18, F19, F20, F21, F22, F23, F24, Hyper = 207, XF86Launch3, XF86Launch4, XF86LaunchB, XF86Search = 225, } pub static KEYS_TO_MODS: Lazy> = Lazy::new(|| { idmap! { VirtualKey::LShift => SHIFT, VirtualKey::RShift => SHIFT, VirtualKey::Caps => CAPS_LOCK, VirtualKey::LCtrl => CTRL, VirtualKey::RCtrl => CTRL, VirtualKey::LAlt => ALT, VirtualKey::NumLock => NUM_LOCK, VirtualKey::LSuper => SUPER, VirtualKey::RSuper => SUPER, VirtualKey::Meta => META, } }); pub static MODS_TO_KEYS: Lazy>> = Lazy::new(|| { idmap! { SHIFT => vec![VirtualKey::LShift, VirtualKey::RShift], CAPS_LOCK => vec![VirtualKey::Caps], CTRL => vec![VirtualKey::LCtrl, VirtualKey::RCtrl], ALT => vec![VirtualKey::LAlt], NUM_LOCK => vec![VirtualKey::NumLock], SUPER => vec![VirtualKey::LSuper, VirtualKey::RSuper], META => vec![VirtualKey::Meta], } });