diff --git a/vuinputd-tests/src/bin/test-scenarios.rs b/vuinputd-tests/src/bin/test-scenarios.rs index e9e41a7..6b1b145 100644 --- a/vuinputd-tests/src/bin/test-scenarios.rs +++ b/vuinputd-tests/src/bin/test-scenarios.rs @@ -4,9 +4,11 @@ use clap::{Parser, Subcommand}; use vuinputd_tests::scenarios::{ - ScenarioArgs, basic_keyboard::BasicKeyboard, basic_mouse::BasicMouse, basic_ps4_gamepad::BasicPs4Gamepad, basic_xbox_gamepad::BasicXboxGamepad/* - reuse_keyboard::ReuseKeyboard, reuse_xbox_gamepad::ReuseXboxGamepad, - ScenarioArgs, stress_keyboard::StressKeyboard, stress_xbox_gamepad::StressXboxGamepad, */ + basic_keyboard::BasicKeyboard, basic_mouse::BasicMouse, basic_ps4_gamepad::BasicPs4Gamepad, + basic_xbox_gamepad::BasicXboxGamepad, /* + reuse_keyboard::ReuseKeyboard, reuse_xbox_gamepad::ReuseXboxGamepad, + ScenarioArgs, stress_keyboard::StressKeyboard, stress_xbox_gamepad::StressXboxGamepad, */ + ScenarioArgs, }; #[derive(Parser)] @@ -38,7 +40,6 @@ enum Commands { /// Basic Xbox gamepad test BasicXboxGamepad, - /* /// Reuse keyboard test (create, destroy, recreate) ReuseKeyboard, diff --git a/vuinputd-tests/src/devices/keyboard.rs b/vuinputd-tests/src/devices/keyboard.rs index bb384da..2dd1376 100644 --- a/vuinputd-tests/src/devices/keyboard.rs +++ b/vuinputd-tests/src/devices/keyboard.rs @@ -3,8 +3,8 @@ // Author: Johannes Leupolz use super::Device; -use std::{ffi::CStr, fs::File}; use std::io; +use std::{ffi::CStr, fs::File}; use uinput_ioctls::*; /// Key codes. Those are used by udev to recognize a device as a keyboard. @@ -125,7 +125,6 @@ pub const KEY_PAGEDOWN: u16 = 109; pub const KEY_INSERT: u16 = 110; pub const KEY_DELETE: u16 = 111; - /// Configure a full 101-key standard keyboard unsafe fn set_standard_keyboard_keys(fd: i32) -> Result<(), std::io::Error> { // We need to set more bits so that systemd recognizes a keyboard as a keyboard. @@ -269,11 +268,10 @@ impl Device for KeyboardDevice { } fn get_event_device(sysname: &str) -> Result { - super::utils::fetch_device_node(sysname) - .and_then(|devnode| File::open(&devnode)) + super::utils::fetch_device_node(sysname).and_then(|devnode| File::open(&devnode)) } - fn setup(device:Option<&str>,name: &str) -> Result { + fn setup(device: Option<&str>, name: &str) -> Result { let fd = super::utils::open_uinput(device)?; unsafe { set_standard_keyboard_keys(fd) }?; diff --git a/vuinputd-tests/src/devices/mod.rs b/vuinputd-tests/src/devices/mod.rs index 43ffd5c..9d77113 100644 --- a/vuinputd-tests/src/devices/mod.rs +++ b/vuinputd-tests/src/devices/mod.rs @@ -8,8 +8,8 @@ use std::io; pub mod keyboard; pub mod mouse; pub mod ps4_gamepad; -pub mod xbox_gamepad; pub mod utils; +pub mod xbox_gamepad; pub use keyboard::KeyboardDevice; pub use mouse::MouseDevice; @@ -26,13 +26,13 @@ pub const EV_ABS: u16 = 0x03; pub trait Device { fn name() -> &'static str; fn get_event_device(sysname: &str) -> Result; - + /// Phase 1: open uinput, configure keys, call ui_dev_setup - fn setup(device:Option<&str>,name: &str) -> Result; - + fn setup(device: Option<&str>, name: &str) -> Result; + /// Phase 2: call ui_dev_create, get sysname and devnode fn create(fd: i32) -> Result; - + /// Phase 3: call ui_dev_destroy and close fd fn destroy(fd: i32); -} \ No newline at end of file +} diff --git a/vuinputd-tests/src/devices/mouse.rs b/vuinputd-tests/src/devices/mouse.rs index 5861bd3..352e792 100644 --- a/vuinputd-tests/src/devices/mouse.rs +++ b/vuinputd-tests/src/devices/mouse.rs @@ -2,10 +2,10 @@ // // Author: Johannes Leupolz -use super::{ Device}; -use std::{ffi::CStr, fs::File}; -use std::io; +use super::Device; use libc::c_int; +use std::io; +use std::{ffi::CStr, fs::File}; use uinput_ioctls::*; // Mouse codes @@ -32,7 +32,6 @@ unsafe fn setup_mouse(fd: c_int) -> io::Result<()> { Ok(()) } - pub struct MouseDevice; impl Device for MouseDevice { @@ -41,8 +40,7 @@ impl Device for MouseDevice { } fn get_event_device(sysname: &str) -> Result { - super::utils::fetch_device_node(sysname) - .and_then(|devnode| File::open(&devnode)) + super::utils::fetch_device_node(sysname).and_then(|devnode| File::open(&devnode)) } fn setup(device: Option<&str>, name: &str) -> Result { diff --git a/vuinputd-tests/src/devices/ps4_gamepad.rs b/vuinputd-tests/src/devices/ps4_gamepad.rs new file mode 100644 index 0000000..b08106e --- /dev/null +++ b/vuinputd-tests/src/devices/ps4_gamepad.rs @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: MIT +// +// Author: Johannes Leupolz + +use super::Device; +use libc::c_int; +use std::io; +use std::{ffi::CStr, fs::File}; +use uinput_ioctls::*; + +// PS4 Gamepad codes +const BTN_SOUTH: u16 = 304; // Cross +const BTN_EAST: u16 = 305; // Circle +const BTN_NORTH: u16 = 306; // Square +const BTN_WEST: u16 = 307; // Triangle +const BTN_TOP: u16 = 310; // L1 +const BTN_TOP2: u16 = 311; // R1 +const BTN_BASE: u16 = 312; // Share +const BTN_BASE2: u16 = 313; // Options +const BTN_BASE3: u16 = 314; // L3 +const BTN_BASE23: u16 = 315; // R3 +const BTN_TL: u16 = 316; // L2 +const BTN_TR: u16 = 317; // R2 +const BTN_SELECT: u16 = 318; +const BTN_START: u16 = 319; +const BTN_THUMBL: u16 = 320; +const BTN_THUMBR: u16 = 321; +const BTN_TOUCH: u16 = 322; +const BTN_TR2: u16 = 323; +const BTN_DPAD_UP: u16 = 325; +const BTN_DPAD_DOWN: u16 = 326; +const BTN_DPAD_LEFT: u16 = 327; +const BTN_DPAD_RIGHT: u16 = 328; + +const ABS_X: u16 = 0; +const ABS_Y: u16 = 1; +const ABS_Z: u16 = 2; +const ABS_RX: u16 = 3; +const ABS_RY: u16 = 4; +const ABS_RZ: u16 = 5; +const ABS_THROTTLE: u16 = 6; +const ABS_RUDDER: u16 = 7; +const ABS_PRESSURE: u16 = 24; +const ABS_DISTANCE: u16 = 32; +const ABS_MT_POSITION_X: u16 = 47; +const ABS_MT_POSITION_Y: u16 = 48; +const ABS_MT_TRACKING_ID: u16 = 57; +const ABS_MT_PRESSURE: u16 = 47; +const ABS_MT_TOOL_TYPE: u16 = 55; +const ABS_MT_WIDTH: u16 = 56; + +// Xbox Gamepad codes +const BTN_A: u16 = 304; // A +const BTN_B: u16 = 305; // B +const BTN_X: u16 = 306; // X +const BTN_Y: u16 = 307; // Y +const BTN_TL2: u16 = 319; // LT + +pub struct Ps4GamepadDevice; + +/// Setup PS4 gamepad device +unsafe fn setup_ps4_gamepad(fd: c_int) -> io::Result<()> { + // EV_SYN + ui_set_evbit(fd, super::EV_SYN.try_into().unwrap())?; + // EV_KEY + ui_set_evbit(fd, super::EV_KEY.try_into().unwrap())?; + ui_set_keybit(fd, BTN_SOUTH.try_into().unwrap())?; + ui_set_keybit(fd, BTN_EAST.try_into().unwrap())?; + ui_set_keybit(fd, BTN_NORTH.try_into().unwrap())?; + ui_set_keybit(fd, BTN_WEST.try_into().unwrap())?; + ui_set_keybit(fd, BTN_TOP.try_into().unwrap())?; + ui_set_keybit(fd, BTN_TOP2.try_into().unwrap())?; + ui_set_keybit(fd, BTN_BASE.try_into().unwrap())?; + ui_set_keybit(fd, BTN_BASE2.try_into().unwrap())?; + ui_set_keybit(fd, BTN_BASE3.try_into().unwrap())?; + ui_set_keybit(fd, BTN_BASE23.try_into().unwrap())?; + ui_set_keybit(fd, BTN_TL.try_into().unwrap())?; + ui_set_keybit(fd, BTN_TR.try_into().unwrap())?; + ui_set_keybit(fd, BTN_SELECT.try_into().unwrap())?; + ui_set_keybit(fd, BTN_START.try_into().unwrap())?; + ui_set_keybit(fd, BTN_THUMBL.try_into().unwrap())?; + ui_set_keybit(fd, BTN_THUMBR.try_into().unwrap())?; + ui_set_keybit(fd, BTN_TOUCH.try_into().unwrap())?; + ui_set_keybit(fd, BTN_TR2.try_into().unwrap())?; + ui_set_keybit(fd, BTN_DPAD_UP.try_into().unwrap())?; + ui_set_keybit(fd, BTN_DPAD_DOWN.try_into().unwrap())?; + ui_set_keybit(fd, BTN_DPAD_LEFT.try_into().unwrap())?; + ui_set_keybit(fd, BTN_DPAD_RIGHT.try_into().unwrap())?; + // EV_ABS + ui_set_evbit(fd, super::EV_ABS.try_into().unwrap())?; + ui_set_absbit(fd, ABS_X.try_into().unwrap())?; + ui_set_absbit(fd, ABS_Y.try_into().unwrap())?; + ui_set_absbit(fd, ABS_RX.try_into().unwrap())?; + ui_set_absbit(fd, ABS_RY.try_into().unwrap())?; + ui_set_absbit(fd, ABS_PRESSURE.try_into().unwrap())?; + ui_set_absbit(fd, ABS_DISTANCE.try_into().unwrap())?; + + Ok(()) +} + +impl Device for Ps4GamepadDevice { + fn name() -> &'static str { + "PS4 Gamepad" + } + + fn get_event_device(sysname: &str) -> Result { + super::utils::fetch_device_node(sysname).and_then(|devnode| File::open(&devnode)) + } + + fn setup(device: Option<&str>, name: &str) -> Result { + let fd = super::utils::open_uinput(device)?; + unsafe { setup_ps4_gamepad(fd) }?; + + unsafe { + let mut usetup: libc::uinput_setup = std::mem::zeroed(); + usetup.id.bustype = BUS_USB; + usetup.id.vendor = 0xbeef; + usetup.id.product = 0xdead; + + let name_cstr = CString::new(name).unwrap(); + let name_ptr = usetup.name.as_mut_ptr() as *mut c_char; + std::ptr::copy_nonoverlapping( + name_cstr.as_ptr(), + name_ptr, + name_cstr.to_bytes_with_nul().len(), + ); + + let usetup_ptr = &mut usetup as *mut libc::uinput_setup; + ui_dev_setup(fd, usetup_ptr).map_err(|e| { + eprintln!("ui_dev_setup failed: {:?}", e); + e + })?; + } + + Ok(fd) + } + + fn create(fd: i32) -> Result { + unsafe { + ui_dev_create(fd).map_err(|e| { + eprintln!("ui_dev_create failed: {:?}", e); + e + })?; + + let mut resultbuf: [c_char; 64] = [0; 64]; + ui_get_sysname(fd, resultbuf.as_mut_slice()).map_err(|e| { + eprintln!("ui_get_sysname failed: {:?}", e); + e + })?; + + let sysname = format!( + "{}{}", + SYS_INPUT_DIR, + CStr::from_ptr(resultbuf.as_ptr()).to_string_lossy() + ); + + Ok(sysname) + } + } + + fn destroy(fd: i32) { + unsafe { + ui_dev_destroy(fd).unwrap_or_else(|e| { + eprintln!("ui_dev_destroy failed: {:?}", e); + std::process::exit(1); + }); + close(fd); + } + } +} + +use libc::{c_char, close}; +use std::ffi::CString; + +const SYS_INPUT_DIR: &str = "/sys/devices/virtual/input/"; +const BUS_USB: u16 = 0x03; diff --git a/vuinputd-tests/src/devices/utils.rs b/vuinputd-tests/src/devices/utils.rs index 33234d8..ff4fdec 100644 --- a/vuinputd-tests/src/devices/utils.rs +++ b/vuinputd-tests/src/devices/utils.rs @@ -2,6 +2,7 @@ // // Author: Johannes Leupolz +use crate::test_log::{LoggedInputEvent, TestLog}; use libc::{c_int, close, open, write, O_NONBLOCK, O_WRONLY}; use libc::{input_event, timespec, uinput_setup, CLOCK_MONOTONIC}; use std::ffi::{CStr, CString}; @@ -12,7 +13,6 @@ use std::os::fd::AsRawFd; use std::os::raw::{c_char, c_void}; use std::ptr; pub use uinput_ioctls::*; -use crate::test_log::{LoggedInputEvent, TestLog}; // Constants (same numeric values as in linux headers) const EV_SYN: u16 = 0x00; @@ -20,7 +20,6 @@ const EV_KEY: u16 = 0x01; const SYN_REPORT: u16 = 0; const BUS_USB: u16 = 0x03; - pub fn emit(fd: c_int, ev_type: u16, code: u16, val: i32) -> io::Result<()> { // libc's input_event struct layout: // struct input_event { @@ -126,8 +125,7 @@ pub fn monotonic_time() -> (i64, i64) { (ts.tv_sec, ts.tv_nsec) } - -pub fn open_uinput(device:Option<&str>) -> io::Result { +pub fn open_uinput(device: Option<&str>) -> io::Result { let device = match device { Some(dev_path) => dev_path, _ => "/dev/uinput", @@ -140,4 +138,4 @@ pub fn open_uinput(device:Option<&str>) -> io::Result { return Err(io::Error::last_os_error()); } Ok(fd) -} \ No newline at end of file +} diff --git a/vuinputd-tests/src/devices/xbox_gamepad.rs b/vuinputd-tests/src/devices/xbox_gamepad.rs new file mode 100644 index 0000000..bca3931 --- /dev/null +++ b/vuinputd-tests/src/devices/xbox_gamepad.rs @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: MIT +// +// Author: Johannes Leupolz + +use super::Device; +use libc::c_int; +use std::io; +use std::{ffi::CStr, fs::File}; +use uinput_ioctls::*; + +// PS4 Gamepad codes +const BTN_SOUTH: u16 = 304; // Cross +const BTN_EAST: u16 = 305; // Circle +const BTN_NORTH: u16 = 306; // Square +const BTN_WEST: u16 = 307; // Triangle +const BTN_TOP: u16 = 310; // L1 +const BTN_TOP2: u16 = 311; // R1 +const BTN_BASE: u16 = 312; // Share +const BTN_BASE2: u16 = 313; // Options +const BTN_BASE3: u16 = 314; // L3 +const BTN_BASE23: u16 = 315; // R3 +const BTN_TL: u16 = 316; // L2 +const BTN_TR: u16 = 317; // R2 +const BTN_SELECT: u16 = 318; +const BTN_START: u16 = 319; +const BTN_THUMBL: u16 = 320; +const BTN_THUMBR: u16 = 321; +const BTN_TOUCH: u16 = 322; +const BTN_TR2: u16 = 323; +const BTN_DPAD_UP: u16 = 325; +const BTN_DPAD_DOWN: u16 = 326; +const BTN_DPAD_LEFT: u16 = 327; +const BTN_DPAD_RIGHT: u16 = 328; + +const ABS_X: u16 = 0; +const ABS_Y: u16 = 1; +const ABS_Z: u16 = 2; +const ABS_RX: u16 = 3; +const ABS_RY: u16 = 4; +const ABS_RZ: u16 = 5; +const ABS_THROTTLE: u16 = 6; +const ABS_RUDDER: u16 = 7; +const ABS_PRESSURE: u16 = 24; +const ABS_DISTANCE: u16 = 32; +const ABS_MT_POSITION_X: u16 = 47; +const ABS_MT_POSITION_Y: u16 = 48; +const ABS_MT_TRACKING_ID: u16 = 57; +const ABS_MT_PRESSURE: u16 = 47; +const ABS_MT_TOOL_TYPE: u16 = 55; +const ABS_MT_WIDTH: u16 = 56; + +// Xbox Gamepad codes +const BTN_A: u16 = 304; // A +const BTN_B: u16 = 305; // B +const BTN_X: u16 = 306; // X +const BTN_Y: u16 = 307; // Y +const BTN_TL2: u16 = 319; // LT + +/// Setup Xbox gamepad device +unsafe fn setup_xbox_gamepad(fd: c_int) -> io::Result<()> { + // EV_SYN + ui_set_evbit(fd, super::EV_SYN.try_into().unwrap())?; + // EV_KEY + ui_set_evbit(fd, super::EV_KEY.try_into().unwrap())?; + ui_set_keybit(fd, BTN_A.try_into().unwrap())?; + ui_set_keybit(fd, BTN_B.try_into().unwrap())?; + ui_set_keybit(fd, BTN_X.try_into().unwrap())?; + ui_set_keybit(fd, BTN_Y.try_into().unwrap())?; + ui_set_keybit(fd, BTN_TL.try_into().unwrap())?; + ui_set_keybit(fd, BTN_TR.try_into().unwrap())?; + ui_set_keybit(fd, BTN_SELECT.try_into().unwrap())?; + ui_set_keybit(fd, BTN_START.try_into().unwrap())?; + ui_set_keybit(fd, BTN_THUMBL.try_into().unwrap())?; + ui_set_keybit(fd, BTN_THUMBR.try_into().unwrap())?; + ui_set_keybit(fd, BTN_TL2.try_into().unwrap())?; + ui_set_keybit(fd, BTN_TR2.try_into().unwrap())?; + ui_set_keybit(fd, BTN_DPAD_UP.try_into().unwrap())?; + ui_set_keybit(fd, BTN_DPAD_DOWN.try_into().unwrap())?; + ui_set_keybit(fd, BTN_DPAD_LEFT.try_into().unwrap())?; + ui_set_keybit(fd, BTN_DPAD_RIGHT.try_into().unwrap())?; + // EV_ABS + ui_set_evbit(fd, super::EV_ABS.try_into().unwrap())?; + ui_set_absbit(fd, ABS_X.try_into().unwrap())?; + ui_set_absbit(fd, ABS_Y.try_into().unwrap())?; + ui_set_absbit(fd, ABS_RX.try_into().unwrap())?; + ui_set_absbit(fd, ABS_RY.try_into().unwrap())?; + ui_set_absbit(fd, ABS_PRESSURE.try_into().unwrap())?; + ui_set_absbit(fd, ABS_DISTANCE.try_into().unwrap())?; + + Ok(()) +} + +pub struct XboxGamepadDevice; + +impl Device for XboxGamepadDevice { + fn name() -> &'static str { + "Xbox Gamepad" + } + + fn get_event_device(sysname: &str) -> Result { + super::utils::fetch_device_node(sysname).and_then(|devnode| File::open(&devnode)) + } + + fn setup(device: Option<&str>, name: &str) -> Result { + let fd = super::utils::open_uinput(device)?; + unsafe { setup_xbox_gamepad(fd) }?; + + unsafe { + let mut usetup: libc::uinput_setup = std::mem::zeroed(); + usetup.id.bustype = BUS_USB; + usetup.id.vendor = 0xbeef; + usetup.id.product = 0xdead; + + let name_cstr = CString::new(name).unwrap(); + let name_ptr = usetup.name.as_mut_ptr() as *mut c_char; + std::ptr::copy_nonoverlapping( + name_cstr.as_ptr(), + name_ptr, + name_cstr.to_bytes_with_nul().len(), + ); + + let usetup_ptr = &mut usetup as *mut libc::uinput_setup; + ui_dev_setup(fd, usetup_ptr).map_err(|e| { + eprintln!("ui_dev_setup failed: {:?}", e); + e + })?; + } + + Ok(fd) + } + + fn create(fd: i32) -> Result { + unsafe { + ui_dev_create(fd).map_err(|e| { + eprintln!("ui_dev_create failed: {:?}", e); + e + })?; + + let mut resultbuf: [c_char; 64] = [0; 64]; + ui_get_sysname(fd, resultbuf.as_mut_slice()).map_err(|e| { + eprintln!("ui_get_sysname failed: {:?}", e); + e + })?; + + let sysname = format!( + "{}{}", + SYS_INPUT_DIR, + CStr::from_ptr(resultbuf.as_ptr()).to_string_lossy() + ); + + Ok(sysname) + } + } + + fn destroy(fd: i32) { + unsafe { + ui_dev_destroy(fd).unwrap_or_else(|e| { + eprintln!("ui_dev_destroy failed: {:?}", e); + std::process::exit(1); + }); + close(fd); + } + } +} + +use libc::{c_char, close}; +use std::ffi::CString; + +const SYS_INPUT_DIR: &str = "/sys/devices/virtual/input/"; +const BUS_USB: u16 = 0x03; diff --git a/vuinputd-tests/src/scenarios/basic_keyboard.rs b/vuinputd-tests/src/scenarios/basic_keyboard.rs index 149873f..2abfd85 100644 --- a/vuinputd-tests/src/scenarios/basic_keyboard.rs +++ b/vuinputd-tests/src/scenarios/basic_keyboard.rs @@ -6,9 +6,9 @@ use std::thread; use std::time::Duration; use crate::devices::keyboard::KeyboardDevice; +use crate::devices::{utils, Device}; use crate::scenarios::ScenarioArgs; -use crate::devices::{Device, utils}; -use crate::test_log::{TestLog}; +use crate::test_log::TestLog; const KEY_SPACE: u16 = 57; @@ -16,8 +16,11 @@ pub struct BasicKeyboard; impl BasicKeyboard { pub fn run(args: &ScenarioArgs) -> Result<(), std::io::Error> { - let device = args.dev_path.clone().unwrap_or_else(|| "/dev/uinput".to_string()); - let fd = KeyboardDevice::setup(Some(&device),"Example Keyboard")?; + let device = args + .dev_path + .clone() + .unwrap_or_else(|| "/dev/uinput".to_string()); + let fd = KeyboardDevice::setup(Some(&device), "Example Keyboard")?; let sysname = KeyboardDevice::create(fd)?; eprintln!("sysname: {}", sysname); @@ -30,11 +33,13 @@ impl BasicKeyboard { let ev1 = utils::emit_read_and_log(fd, &event_device, 0x01, KEY_SPACE, 1)?; let ev2 = utils::emit_read_and_log(fd, &event_device, 0x01, KEY_SPACE, 0)?; - let eventlog = TestLog { events: vec![ev1, ev2] }; + let eventlog = TestLog { + events: vec![ev1, ev2], + }; let serialized = serde_json::to_string(&eventlog).unwrap(); println!("Event log: {}", serialized); KeyboardDevice::destroy(fd); Ok(()) } -} \ No newline at end of file +} diff --git a/vuinputd-tests/src/scenarios/basic_mouse.rs b/vuinputd-tests/src/scenarios/basic_mouse.rs index 3a46d40..be23d64 100644 --- a/vuinputd-tests/src/scenarios/basic_mouse.rs +++ b/vuinputd-tests/src/scenarios/basic_mouse.rs @@ -5,8 +5,8 @@ use std::thread; use std::time::Duration; use crate::devices::mouse::MouseDevice; +use crate::devices::{utils, Device}; use crate::scenarios::ScenarioArgs; -use crate::devices::{Device, utils}; use crate::test_log::{LoggedInputEvent, TestLog}; const BTN_LEFT: u16 = 272; @@ -15,8 +15,11 @@ pub struct BasicMouse; impl BasicMouse { pub fn run(args: &ScenarioArgs) -> Result<(), std::io::Error> { - let device = args.dev_path.clone().unwrap_or_else(|| "/dev/uinput".to_string()); - + let device = args + .dev_path + .clone() + .unwrap_or_else(|| "/dev/uinput".to_string()); + let fd = MouseDevice::setup(Some(&device), "Example Mouse")?; let sysname = MouseDevice::create(fd)?; eprintln!("sysname: {}", sysname); @@ -30,7 +33,9 @@ impl BasicMouse { let ev1 = utils::emit_read_and_log(fd, &event_device, 0x01, BTN_LEFT, 1)?; let ev2 = utils::emit_read_and_log(fd, &event_device, 0x01, BTN_LEFT, 0)?; - let eventlog = TestLog { events: vec![ev1, ev2] }; + let eventlog = TestLog { + events: vec![ev1, ev2], + }; let serialized = serde_json::to_string(&eventlog).unwrap(); println!("Event log: {}", serialized); diff --git a/vuinputd-tests/src/scenarios/basic_ps4_gamepad.rs b/vuinputd-tests/src/scenarios/basic_ps4_gamepad.rs index 8952dd3..3224b76 100644 --- a/vuinputd-tests/src/scenarios/basic_ps4_gamepad.rs +++ b/vuinputd-tests/src/scenarios/basic_ps4_gamepad.rs @@ -5,8 +5,8 @@ use std::thread; use std::time::Duration; use crate::devices::ps4_gamepad::Ps4GamepadDevice; +use crate::devices::{utils, Device}; use crate::scenarios::ScenarioArgs; -use crate::devices::{Device, utils}; use crate::test_log::{LoggedInputEvent, TestLog}; const BTN_SOUTH: u16 = 304; @@ -15,8 +15,11 @@ pub struct BasicPs4Gamepad; impl BasicPs4Gamepad { pub fn run(args: &ScenarioArgs) -> Result<(), std::io::Error> { - let device = args.dev_path.clone().unwrap_or_else(|| "/dev/uinput".to_string()); - + let device = args + .dev_path + .clone() + .unwrap_or_else(|| "/dev/uinput".to_string()); + let fd = Ps4GamepadDevice::setup(Some(&device), "PS4 Gamepad")?; let sysname = Ps4GamepadDevice::create(fd)?; eprintln!("sysname: {}", sysname); @@ -30,11 +33,13 @@ impl BasicPs4Gamepad { let ev1 = utils::emit_read_and_log(fd, &event_device, 0x01, BTN_SOUTH, 1)?; let ev2 = utils::emit_read_and_log(fd, &event_device, 0x01, BTN_SOUTH, 0)?; - let eventlog = TestLog { events: vec![ev1, ev2] }; + let eventlog = TestLog { + events: vec![ev1, ev2], + }; let serialized = serde_json::to_string(&eventlog).unwrap(); println!("Event log: {}", serialized); Ps4GamepadDevice::destroy(fd); Ok(()) } -} \ No newline at end of file +} diff --git a/vuinputd-tests/src/scenarios/basic_xbox_gamepad.rs b/vuinputd-tests/src/scenarios/basic_xbox_gamepad.rs index 76dfb6e..d7fbb74 100644 --- a/vuinputd-tests/src/scenarios/basic_xbox_gamepad.rs +++ b/vuinputd-tests/src/scenarios/basic_xbox_gamepad.rs @@ -6,8 +6,8 @@ use std::thread; use std::time::Duration; use crate::devices::xbox_gamepad::XboxGamepadDevice; +use crate::devices::{utils, Device}; use crate::scenarios::ScenarioArgs; -use crate::devices::{Device, utils}; use crate::test_log::{LoggedInputEvent, TestLog}; const BTN_A: u16 = 304; @@ -16,8 +16,11 @@ pub struct BasicXboxGamepad; impl BasicXboxGamepad { pub fn run(args: &ScenarioArgs) -> Result<(), std::io::Error> { - let device = args.dev_path.clone().unwrap_or_else(|| "/dev/uinput".to_string()); - + let device = args + .dev_path + .clone() + .unwrap_or_else(|| "/dev/uinput".to_string()); + let fd = XboxGamepadDevice::setup(Some(&device), "Xbox Gamepad")?; let sysname = XboxGamepadDevice::create(fd)?; eprintln!("sysname: {}", sysname); @@ -31,7 +34,9 @@ impl BasicXboxGamepad { let ev1 = utils::emit_read_and_log(fd, &event_device, 0x01, BTN_A, 1)?; let ev2 = utils::emit_read_and_log(fd, &event_device, 0x01, BTN_A, 0)?; - let eventlog = TestLog { events: vec![ev1, ev2] }; + let eventlog = TestLog { + events: vec![ev1, ev2], + }; let serialized = serde_json::to_string(&eventlog).unwrap(); println!("Event log: {}", serialized); diff --git a/vuinputd-tests/tests/integration_tests.rs b/vuinputd-tests/tests/integration_tests.rs index 4e96b58..c88bc04 100644 --- a/vuinputd-tests/tests/integration_tests.rs +++ b/vuinputd-tests/tests/integration_tests.rs @@ -128,7 +128,7 @@ fn test_keyboard_in_container_with_uinput() { ))] #[test] fn test_keyboard_in_container_with_vuinput_placement_in_container() { - let _guard: run_vuinputd::VuinputdGuard=run_vuinputd::ensure_vuinputd_running(&[]); + let _guard: run_vuinputd::VuinputdGuard = run_vuinputd::ensure_vuinputd_running(&[]); let test_keyboard = env!("CARGO_BIN_EXE_test-keyboard"); @@ -164,7 +164,7 @@ fn test_keyboard_in_container_with_vuinput_placement_in_container() { ))] #[test] fn test_keyboard_in_container_with_vuinput_placement_on_host() { - let _guard=run_vuinputd::ensure_vuinputd_running(&["--placement","on-host"]); + let _guard = run_vuinputd::ensure_vuinputd_running(&["--placement", "on-host"]); let test_keyboard = env!("CARGO_BIN_EXE_test-keyboard"); diff --git a/vuinputd-tests/tests/podman_tests.rs b/vuinputd-tests/tests/podman_tests.rs index 291d2c1..4951a46 100644 --- a/vuinputd-tests/tests/podman_tests.rs +++ b/vuinputd-tests/tests/podman_tests.rs @@ -66,7 +66,7 @@ fn test_podman_ipc() { ))] #[test] fn test_keyboard_in_container_with_vuinput() { - let _guard=run_vuinputd::ensure_vuinputd_running(&[]); + let _guard = run_vuinputd::ensure_vuinputd_running(&[]); let (builder, _ipc) = podman::PodmanBuilder::new() .run_cmd() @@ -91,3 +91,37 @@ fn test_keyboard_in_container_with_vuinput() { assert!(out.status.success()); } + +#[cfg(all( + feature = "requires-rootless", + feature = "requires-uinput", + feature = "requires-podman" +))] +#[test] +fn test_keyboard_in_container_with_vuinput_rootless_with_userns() { + let _guard = run_vuinputd::ensure_vuinputd_running(&[]); + + let (builder, _ipc) = podman::PodmanBuilder::new() + .run_cmd() + .rm() + .userns("auto") + .with_ipc() + .expect("failed to create IPC"); + let builder = builder + //.detach() + //.name(&format!("vuinputd-podman-tests")) + .device("/dev/vuinput-test:/dev/uinput") + .allow_input_devices() + .image("localhost/vuinputd-tests:latest") + .command(&["/test-keyboard"]); + + let out = builder + .run() + .unwrap_or_else(|e| panic!("failed to run podman!: {e}")); + + println!("Output"); + println!("stdout: {}", str::from_utf8(&out.stdout).unwrap()); + println!("stderr: {}", str::from_utf8(&out.stderr).unwrap()); + + assert!(out.status.success()); +}