### Configure sudo runner for tests Source: https://github.com/sludgephd/evdevil/blob/main/README.md To run the test suite and examples, configure a .cargo/config.toml file to use sudo with preserved environment variables. ```toml [target.'cfg(true)'] runner = "sudo -E --preserve-env=PATH" ``` -------------------------------- ### Control Force-Feedback Effects Source: https://context7.com/sludgephd/evdevil/llms.txt Upload and control force-feedback effects for haptic devices. This example shows how to check capabilities, upload rumble and periodic effects, set gain, and erase effects. ```rust use evdevil::Evdev; use evdevil::ff::{Feature, Rumble, Periodic, Waveform, Constant, Effect, Envelope, Replay}; use evdevil::event::ForceFeedbackEvent; use std::io; use std::thread; use std::time::Duration; fn main() -> io::Result<()> { let evdev = Evdev::open("/dev/input/event0")?; // Check force-feedback capabilities let ff_features = evdev.supported_ff_features()?; let max_effects = evdev.supported_ff_effects()?; println!("FF features: {:?}", ff_features); println!("Max simultaneous effects: {}", max_effects); if !ff_features.contains(Feature::RUMBLE) { println!("Device doesn't support rumble"); return Ok(()) } // Upload a simple rumble effect let rumble = Rumble::new(30000, 30000); // strong_magnitude, weak_magnitude let effect_id = evdev.upload_ff_effect(rumble)?; println!("Uploaded rumble effect with ID: {:?}", effect_id); // Start the effect evdev.control_ff(effect_id, true)?; thread::sleep(Duration::from_secs(1)); // Stop the effect evdev.control_ff(effect_id, false)?; // Upload a periodic sine wave effect (if supported) if ff_features.contains(Feature::PERIODIC) && ff_features.contains(Feature::SINE) { let periodic = Periodic::simple(Waveform::SINE, 100, 20000) .with_envelope(Envelope::new() .with_attack_length(500) .with_attack_level(0) .with_fade_length(500) .with_fade_level(0)); let effect = Effect::from(periodic) .with_replay(Replay::new(2000, 0)) // 2 second duration .with_direction(0x4000); // Direction (0-0xFFFF) let sine_id = evdev.upload_ff_effect(effect)?; evdev.control_ff(sine_id, true)?; } // Set global force-feedback gain (0-65535) if ff_features.contains(Feature::GAIN) { evdev.set_ff_gain(32768)?; } // Erase the effect when done evdev.erase_ff_effect(effect_id)?; Ok(()) } ``` -------------------------------- ### Write Multitouch Events with SlotWriter Source: https://context7.com/sludgephd/evdevil/llms.txt Create virtual multitouch devices and write multitouch events using the slot-based API. This example demonstrates setting up a virtual touchscreen and sending touch point data. ```rust use evdevil::uinput::{UinputDevice, AbsSetup}; use evdevil::{AbsInfo, InputId, Bus}; use evdevil::event::Abs; use std::io; fn main() -> io::Result<()> { let device = UinputDevice::builder()? .with_abs_axes([ AbsSetup::new(Abs::MT_SLOT, AbsInfo::new(0, 0, 9, 0, 0, 0)), AbsSetup::new(Abs::MT_TRACKING_ID, AbsInfo::new(0, 0, 65535, 0, 0, 0)), AbsSetup::new(Abs::MT_POSITION_X, AbsInfo::new(0, 0, 1920, 0, 0, 0)), AbsSetup::new(Abs::MT_POSITION_Y, AbsInfo::new(0, 0, 1080, 0, 0, 0)), ])? .build("Virtual Touchscreen")?; // Write multitouch events using SlotWriter device.writer() // First touch point .slot(0)? .set_tracking_id(1)? .set_position(100, 200)? .finish_slot()? // Second touch point .slot(1)? .set_tracking_id(2)? .set_position(500, 400)? .finish_slot()? .finish()?; // Release a touch point (set tracking_id to -1) device.writer() .slot(0)? .set_tracking_id(-1)? .finish_slot()? .finish()?; Ok(()) } ``` -------------------------------- ### Grab Exclusive Device Access Source: https://context7.com/sludgephd/evdevil/llms.txt Grab exclusive access to an input device to prevent other applications from receiving its events. This example demonstrates grabbing, reading a single event, and notes on releasing or revoking access. ```rust use evdevil::Evdev; use std::io; fn main() -> io::Result<()> { let evdev = Evdev::open("/dev/input/event0")?; // Grab exclusive access evdev.grab()?; println!("Device grabbed - other applications won't receive events"); // Read events exclusively... for event in evdev.into_reader()? { let event = event?; println!("{:?}", event); break; // Just read one for demo } // Release the grab (also happens automatically on drop) // evdev.ungrab()?; // Revoke access permanently (device becomes unusable) // evdev.revoke()?; Ok(()) } ``` -------------------------------- ### Create a virtual force-feedback device Source: https://context7.com/sludgephd/evdevil/llms.txt Initializes a UinputDevice with specific keys and force-feedback features, then processes incoming events for uploads, erasures, and control commands. ```rust use evdevil::uinput::UinputDevice; use evdevil::ff::Feature; use evdevil::event::{EventKind, UinputCode, Key}; use std::io; fn main() -> io::Result<()> { let device = UinputDevice::builder()? .with_keys([Key::BTN_SOUTH, Key::BTN_EAST])? // Enable force-feedback with max 16 effects .with_ff_features([Feature::RUMBLE, Feature::PERIODIC, Feature::GAIN])? .with_ff_effects_max(16)? .build("Virtual FF Gamepad")?; println!("Virtual device created. Waiting for force-feedback requests..."); // Process incoming events (LED changes, sound requests, FF uploads) for res in device.events() { let event = res?; match event.kind() { EventKind::Uinput(ev) => match ev.code() { UinputCode::FF_UPLOAD => { // Handle force-feedback effect upload device.ff_upload(&ev, |upload| { let effect = upload.effect(); let id = upload.effect_id(); println!("FF Upload: id={:?}, type={:?}", id, effect.effect_type()); println!(" Effect details: {:?}", effect.kind()); // Store effect data and return Ok to accept Ok(()) })?; } UinputCode::FF_ERASE => { // Handle force-feedback effect deletion device.ff_erase(&ev, |erase| { println!("FF Erase: id={:?}", erase.effect_id()); // Remove stored effect data Ok(()) })?; } _ => {} }, EventKind::ForceFeedback(ev) => { // Effect play/stop commands println!("FF Control: {:?}, value={}", ev.code(), ev.raw_value()); } EventKind::Led(ev) => { println!("LED {:?} = {}", ev.led(), ev.is_on()); } _ => {} } } Ok(()) } ``` -------------------------------- ### Configure Non-Blocking and Async I/O Source: https://context7.com/sludgephd/evdevil/llms.txt Demonstrates how to switch a device to non-blocking mode for synchronous polling and how to use async iterators with the tokio feature enabled. ```rust use evdevil::Evdev; use std::io; fn main() -> io::Result<()> { let evdev = Evdev::open("/dev/input/event0")?; // Enable non-blocking mode let was_blocking = evdev.set_nonblocking(true)?; println!("Was in blocking mode: {}", !was_blocking); let mut reader = evdev.into_reader()?; // With non-blocking mode, iterators return None when no events are ready // instead of blocking for event in reader.events() { match event { Ok(ev) => println!("{:?}", ev), Err(e) if e.kind() == io::ErrorKind::WouldBlock => { // No events available right now break; } Err(e) => return Err(e), } } // Check readability without blocking if reader.evdev().is_readable()? { println!("Device has pending events"); } // Block until readable (ignores non-blocking setting) // reader.evdev().block_until_readable()?; Ok(()) } ``` ```rust // Async operation with tokio feature enabled // Cargo.toml: evdevil = { version = "0.4", features = ["tokio"] } use evdevil::Evdev; use std::io; #[tokio::main] async fn main() -> io::Result<()> { let evdev = Evdev::open("/dev/input/event0")?; let mut reader = evdev.into_reader()?; // Async event iterator let mut events = reader.async_events()?; while let Some(event) = events.next().await { println!("{:?}", event?); } // Or async report iterator let mut reports = reader.async_reports()?; while let Some(report) = reports.next().await { for event in report? { println!("{:?}", event); } } Ok(()) } ``` -------------------------------- ### Create Virtual Input Devices with uinput Source: https://context7.com/sludgephd/evdevil/llms.txt Creates and configures a virtual input device using the uinput subsystem. This allows the program to simulate input events that appear as real devices to the system. It supports setting device identification, enabling various keys and axes, and sending events. ```rust use evdevil::uinput::{UinputDevice, AbsSetup}; use evdevil::{AbsInfo, InputId, Bus}; use evdevil::event::{Key, KeyEvent, KeyState, Abs, AbsEvent, EventKind, UinputCode}; use std::io; use std::thread; use std::time::Duration; fn main() -> io::Result<()> { // Build a virtual keyboard/gamepad device let device = UinputDevice::builder()? // Set device identification .with_input_id(InputId::new(Bus::VIRTUAL, 0x1234, 0x5678, 1))? // Set physical location string (optional) .with_phys("virtual/keyboard0")? // Enable specific keys/buttons .with_keys([Key::KEY_A, Key::KEY_B, Key::BTN_LEFT, Key::BTN_RIGHT])? // Enable relative axes (mouse movement) .with_rel_axes([evdevil::event::Rel::X, evdevil::event::Rel::Y])? // Enable absolute axes with configuration .with_abs_axes([ AbsSetup::new(Abs::X, AbsInfo::new(0, 0, 1000, 0, 0, 10)), AbsSetup::new(Abs::Y, AbsInfo::new(0, 0, 1000, 0, 0, 10)), ])? // Create the device with a name .build("My Virtual Input Device")?; println!("Created virtual device: {:?}", device.sysname()?); // Send key press events device.write(&[KeyEvent::new(Key::KEY_A, KeyState::PRESSED).into()])?; thread::sleep(Duration::from_millis(100)); device.write(&[KeyEvent::new(Key::KEY_A, KeyState::RELEASED).into()])?; // Use EventWriter for batched writes with automatic SYN_REPORT device.writer() .write(&[ AbsEvent::new(Abs::X, 500).into(), AbsEvent::new(Abs::Y, 300).into(), ])? .finish()?; Ok(()) } ``` -------------------------------- ### Enumerate and Open Evdev Devices in Rust Source: https://context7.com/sludgephd/evdevil/llms.txt Lists currently connected input devices using `enumerate()` and monitors for new devices with `enumerate_hotplug()`. It also shows how to open a specific device and retrieve its properties and capabilities. ```rust use evdevil::{enumerate, enumerate_hotplug, Evdev}; use std::io; fn main() -> io::Result<()> { // List all currently connected input devices for res in enumerate()? { let (path, evdev) = res?; let name = evdev.name()?; let input_id = evdev.input_id()?; println!("{}: {} (bus={:?}, vendor={:#x}, product={:#x})", path.display(), name, input_id.bus(), input_id.vendor(), input_id.product()); } // Or open a specific device directly let evdev = Evdev::open("/dev/input/event0")?; println!("Opened: {}", evdev.name()?); println!("Physical location: {:?}", evdev.phys()?); println!("Unique ID: {:?}", evdev.unique_id()?); println!("Driver version: {}", evdev.driver_version()?); // Check device capabilities println!("Supported events: {:?}", evdev.supported_events()?); println!("Supported keys: {:?}", evdev.supported_keys()?); println!("Supported relative axes: {:?}", evdev.supported_rel_axes()?); println!("Supported absolute axes: {:?}", evdev.supported_abs_axes()?); Ok(()) } ``` -------------------------------- ### Control Device LEDs Source: https://context7.com/sludgephd/evdevil/llms.txt Checks supported LEDs and toggles their state. Requires write permissions to the device node. ```rust use evdevil::Evdev; use evdevil::event::Led; use std::io; fn main() -> io::Result<()> { let evdev = Evdev::open("/dev/input/event0")?; // Check supported LEDs let leds = evdev.supported_leds()?; println!("Supported LEDs: {:?}", leds); // Get current LED state let led_state = evdev.led_state()?; println!("Caps Lock LED: {}", led_state.contains(Led::LED_CAPSL)); // Set LED state (requires write permission) evdev.set_led(Led::LED_CAPSL, true)?; // Turn on evdev.set_led(Led::LED_CAPSL, false)?; // Turn off Ok(()) } ``` -------------------------------- ### Handle Multitouch Devices Source: https://context7.com/sludgephd/evdevil/llms.txt Reads multitouch events from an input device, tracking touch slots and their associated state like position, tracking ID, and pressure. Requires opening a specific event device file. ```rust use evdevil::{Evdev, Slot}; use evdevil::event::{Abs, MtToolType}; use std::io; fn main() -> io::Result<()> { let evdev = Evdev::open("/dev/input/event0")?; let mut reader = evdev.into_reader()?; // Update state by reading all pending events reader.update()?; // Iterate over active touch slots for slot in reader.valid_slots() { let id = reader.slot_state(slot, Abs::MT_TRACKING_ID); let x = reader.slot_state(slot, Abs::MT_POSITION_X); let y = reader.slot_state(slot, Abs::MT_POSITION_Y); let pressure = reader.slot_state(slot, Abs::MT_PRESSURE); let tool = reader.slot_state(slot, Abs::MT_TOOL_TYPE) .map(MtToolType::from_raw); println!("Touch slot {:?}: id={:?}, pos=({:?}, {:?}), pressure={:?}, tool={:?}", slot, id, x, y, pressure, tool); } // Get currently selected slot let current = reader.current_slot(); println!("Currently selected slot: {:?}", current); Ok(()) } ``` -------------------------------- ### Monitor Device Hotplug Events Source: https://context7.com/sludgephd/evdevil/llms.txt Monitors for new device connections and disconnections. It can be used directly with `HotplugMonitor` or combined with device enumeration using `enumerate_hotplug()`. The latter is recommended as it first lists existing devices before blocking for new ones. ```rust use evdevil::hotplug::HotplugMonitor; use evdevil::enumerate_hotplug; use std::io; fn main() -> io::Result<()> { // Method 1: Direct HotplugMonitor usage let monitor = HotplugMonitor::new()?; // Can be put in non-blocking mode // monitor.set_nonblocking(true)?; for event in monitor { let event = event?; println!("New device at: {}", event.path().display()); // Open the device let evdev = event.open()?; println!(" Name: {}", evdev.name()?); } // Method 2: Combined enumeration + hotplug (recommended) // First yields existing devices, then blocks for new ones for res in enumerate_hotplug()? { let (path, evdev) = res?; println!("{}: {}", path.display(), evdev.name()?); } Ok(()) } ``` -------------------------------- ### Manage Key Repeat Settings Source: https://context7.com/sludgephd/evdevil/llms.txt Retrieves or updates the keyboard autorepeat delay and period. Note that these changes are global. ```rust use evdevil::{Evdev, KeyRepeat}; use std::io; fn main() -> io::Result<()> { let evdev = Evdev::open("/dev/input/event0")?; // Get current key repeat settings if let Some(repeat) = evdev.key_repeat()? { println!("Key repeat delay: {} ms", repeat.delay()); println!("Key repeat period: {} ms", repeat.period()); } else { println!("Device doesn't support key repeat"); } // Modify key repeat (use with caution - global setting!) // evdev.set_key_repeat(KeyRepeat::new(500, 50))?; // 500ms delay, 50ms period Ok(()) } ``` -------------------------------- ### Process Input Events by Report in Rust Source: https://context7.com/sludgephd/evdevil/llms.txt Processes input events in batches, where each batch is terminated by a SYN_REPORT. This is useful for handling atomic changes to device state. ```rust use evdevil::{Evdev, reader::Report}; use evdevil::event::EventKind; use std::io; fn main() -> io::Result<()> { let evdev = Evdev::open("/dev/input/event0")?; let mut reader = evdev.into_reader()?; // Process events in complete reports for report in reader.reports() { let report: Report = report?; println!("Report with {} events:", report.len()); for event in report.iter() { match event.kind() { EventKind::Key(ev) => { println!(" Key {:?}: {:?}", ev.key(), ev.state()); } EventKind::Abs(ev) => { println!(" Abs {:?}: {}", ev.abs(), ev.value()); } _ => {} // Ignore other event types } } } Ok(()) } ``` -------------------------------- ### Query and Modify Absolute Axis Information Source: https://context7.com/sludgephd/evdevil/llms.txt Retrieves supported absolute axes and their parameters like range, fuzz, and resolution. Modifying these values affects the device globally. ```rust use evdevil::Evdev; use evdevil::event::Abs; use std::io; fn main() -> io::Result<()> { let evdev = Evdev::open("/dev/input/event0")?; // Get list of supported absolute axes let abs_axes = evdev.supported_abs_axes()?; for abs in abs_axes.iter() { let info = evdev.abs_info(abs)?; println!("{:?}:", abs); println!(" Current value: {}", info.value()); println!(" Range: {} to {}", info.minimum(), info.maximum()); println!(" Fuzz: {}", info.fuzz()); println!(" Flat (deadzone): {}", info.flat()); println!(" Resolution: {} units/mm", info.resolution()); } // Modify axis info (use with caution - affects all applications!) // let mut info = evdev.abs_info(Abs::X)?; // info = info.with_flat(10); // Set deadzone // evdev.set_abs_info(Abs::X, info)?; Ok(()) } ``` -------------------------------- ### Robust Event Reading with EventReader in Rust Source: https://context7.com/sludgephd/evdevil/llms.txt Utilizes `EventReader` for synchronized and robust reading of input events, handling dropped events automatically. It provides an iterator for events and allows querying the current device state without syscalls. ```rust use evdevil::{Evdev, EventReader}; use evdevil::event::{EventKind, KeyEvent, KeyState, Key, Abs}; use std::io; fn main() -> io::Result<()> { let evdev = Evdev::open("/dev/input/event0")?; let mut reader = evdev.into_reader()?; println!("Reading events from: {}", reader.evdev().name()?); // Iterate over incoming events (blocking) for event in reader.events() { let event = event?; match event.kind() { EventKind::Key(ev) => { println!("Key {:?} is now {:?}", ev.key(), ev.state()); } EventKind::Rel(ev) => { println!("Relative axis {:?} moved by {}", ev.rel(), ev.value()); } EventKind::Abs(ev) => { println!("Absolute axis {:?} = {}", ev.abs(), ev.value()); } EventKind::Syn(_) => { // SYN_REPORT marks end of event batch } _ => {} // Ignore other event types } } // Query current device state without syscalls let key_state = reader.key_state(); if key_state.contains(Key::KEY_LEFTSHIFT) { println!("Left Shift is currently pressed"); } // Query absolute axis state let x = reader.abs_state(Abs::X); let y = reader.abs_state(Abs::Y); println!("Joystick position: ({}, {})", x, y); Ok(()) } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.