use evdev_rs_tokio::enums::*; use evdev_rs_tokio::*; use std::io; use tokio::fs::File; fn usage() { println!("Usage: evtest /path/to/device"); } fn print_abs_bits(dev: &Device, axis: &EV_ABS) { let code = EventCode::EV_ABS(axis.clone()); if !dev.has(&code) { return; } let abs = dev.abs_info(&code).unwrap(); println!("\tValue\t{}", abs.value); println!("\tMin\t{}", abs.minimum); println!("\tMax\t{}", abs.maximum); if abs.fuzz != 0 { println!("\tFuzz\t{}", abs.fuzz); } if abs.flat != 0 { println!("\tFlat\t{}", abs.flat); } if abs.resolution != 0 { println!("\tResolution\t{}", abs.resolution); } } fn print_code_bits(dev: &Device, ev_code: &EventCode, max: &EventCode) { for code in ev_code.iter() { if code == *max { break; } if !dev.has(&code) { continue; } println!(" Event code: {}", code); match code { EventCode::EV_ABS(k) => print_abs_bits(dev, &k), _ => (), } } } fn print_bits(dev: &Device) { println!("Supported events:"); for ev_type in EventType::EV_SYN.iter() { if dev.has(&ev_type) { println!(" Event type: {} ", ev_type); } match ev_type { EventType::EV_KEY => print_code_bits( dev, &EventCode::EV_KEY(EV_KEY::KEY_RESERVED), &EventCode::EV_KEY(EV_KEY::KEY_MAX), ), EventType::EV_REL => print_code_bits( dev, &EventCode::EV_REL(EV_REL::REL_X), &EventCode::EV_REL(EV_REL::REL_MAX), ), EventType::EV_ABS => print_code_bits( dev, &EventCode::EV_ABS(EV_ABS::ABS_X), &EventCode::EV_ABS(EV_ABS::ABS_MAX), ), EventType::EV_LED => print_code_bits( dev, &EventCode::EV_LED(EV_LED::LED_NUML), &EventCode::EV_LED(EV_LED::LED_MAX), ), _ => (), } } } fn print_props(dev: &Device) { println!("Properties:"); for input_prop in InputProp::INPUT_PROP_POINTER.iter() { if dev.has(&input_prop) { println!(" Property type: {}", input_prop); } } } fn print_event(ev: &InputEvent) { match ev.event_code { EventCode::EV_SYN(_) => println!( "Event: time {}.{}, ++++++++++++++++++++ {} +++++++++++++++", ev.time.tv_sec, ev.time.tv_usec, ev.event_type().unwrap() ), _ => println!( "Event: time {}.{}, type {} , code {} , value {}", ev.time.tv_sec, ev.time.tv_usec, ev.event_type() .map(|ev_type| format!("{}", ev_type)) .unwrap_or("None".to_owned()), ev.event_code, ev.value ), } } fn print_sync_dropped_event(ev: &InputEvent) { print!("SYNC DROPPED: "); print_event(ev); } #[tokio::main] async fn main() { let mut args = std::env::args(); if args.len() != 2 { usage(); std::process::exit(1); } let path = &args.nth(1).unwrap(); let f = File::open(path).await.unwrap(); let u_d = UninitDevice::new().unwrap(); let d = u_d.set_file(f).unwrap(); println!( "Input device ID: bus 0x{:x} vendor 0x{:x} product 0x{:x}", d.bustype(), d.vendor_id(), d.product_id() ); println!("Evdev version: {:x}", d.driver_version()); println!("Input device name: \"{}\"", d.name().unwrap_or("")); println!("Phys location: {}", d.phys().unwrap_or("")); println!("Uniq identifier: {}", d.uniq().unwrap_or("")); print_bits(&d); print_props(&d); let mut a: io::Result<(ReadStatus, InputEvent)>; loop { a = d.next_event(ReadFlag::NORMAL | ReadFlag::BLOCKING); if a.is_ok() { let mut result = a.ok().unwrap(); match result.0 { ReadStatus::Sync => { println!("::::::::::::::::::::: dropped ::::::::::::::::::::::"); while result.0 == ReadStatus::Sync { print_sync_dropped_event(&result.1); a = d.next_event(ReadFlag::SYNC); if a.is_ok() { result = a.ok().unwrap(); } else { break; } } println!("::::::::::::::::::::: re-synced ::::::::::::::::::::"); } ReadStatus::Success => print_event(&result.1), } } else { let err = a.err().unwrap(); match err.raw_os_error() { Some(libc::EAGAIN) => continue, _ => { println!("{}", err); break; } } } } }