evtest/
evtest.rs

1use evdev_rs::enums::*;
2use evdev_rs::*;
3use std::fs::OpenOptions;
4use std::io;
5use std::io::ErrorKind;
6use std::io::Read;
7use std::os::unix::fs::OpenOptionsExt;
8
9fn usage() {
10    println!("Usage: evtest /path/to/device");
11}
12
13fn print_abs_bits(dev: &Device, axis: &EV_ABS) {
14    let code = EventCode::EV_ABS(axis.clone());
15
16    if !dev.has(code) {
17        return;
18    }
19
20    let abs = dev.abs_info(&code).unwrap();
21
22    println!("\tValue\t{}", abs.value);
23    println!("\tMin\t{}", abs.minimum);
24    println!("\tMax\t{}", abs.maximum);
25    if abs.fuzz != 0 {
26        println!("\tFuzz\t{}", abs.fuzz);
27    }
28    if abs.flat != 0 {
29        println!("\tFlat\t{}", abs.flat);
30    }
31    if abs.resolution != 0 {
32        println!("\tResolution\t{}", abs.resolution);
33    }
34}
35
36fn print_code_bits(dev: &Device, ev_type: &EventType) {
37    for code in EventCodeIterator::new(ev_type) {
38        if !dev.has(code) {
39            continue;
40        }
41
42        println!("    Event code: {}", code);
43        match code {
44            EventCode::EV_ABS(k) => print_abs_bits(dev, &k),
45            _ => (),
46        }
47    }
48}
49
50fn print_bits(dev: &Device) {
51    println!("Supported events:");
52
53    for ev_type in EventTypeIterator::new() {
54        if dev.has(ev_type) {
55            println!("  Event type: {} ", ev_type);
56        }
57
58        match ev_type {
59            EventType::EV_KEY
60            | EventType::EV_REL
61            | EventType::EV_ABS
62            | EventType::EV_LED => print_code_bits(dev, &ev_type),
63            _ => (),
64        }
65    }
66}
67
68fn print_props(dev: &Device) {
69    println!("Properties:");
70
71    for input_prop in InputPropIterator::new() {
72        if dev.has_property(&input_prop) {
73            println!("  Property type: {}", input_prop);
74        }
75    }
76}
77
78fn print_event(ev: &InputEvent) {
79    match ev.event_code {
80        EventCode::EV_SYN(_) => println!(
81            "Event: time {}.{}, ++++++++++++++++++++ {} +++++++++++++++",
82            ev.time.tv_sec,
83            ev.time.tv_usec,
84            ev.event_type().unwrap()
85        ),
86        _ => println!(
87            "Event: time {}.{}, type {} , code {} , value {}",
88            ev.time.tv_sec,
89            ev.time.tv_usec,
90            ev.event_type()
91                .map(|ev_type| format!("{}", ev_type))
92                .unwrap_or("None".to_owned()),
93            ev.event_code,
94            ev.value
95        ),
96    }
97}
98
99fn print_sync_dropped_event(ev: &InputEvent) {
100    print!("SYNC DROPPED: ");
101    print_event(ev);
102}
103
104fn main() {
105    let mut args = std::env::args();
106
107    if args.len() != 2 {
108        usage();
109        std::process::exit(1);
110    }
111
112    let path = &args.nth(1).unwrap();
113    let mut file = OpenOptions::new()
114        .read(true)
115        .write(true)
116        .custom_flags(libc::O_NONBLOCK)
117        .open(path)
118        .unwrap();
119    let mut buffer = Vec::new();
120    let result = file.read_to_end(&mut buffer);
121    if result.is_ok() || result.unwrap_err().kind() != ErrorKind::WouldBlock {
122        println!("Failed to drain pending events from device file");
123    }
124
125    let u_d = UninitDevice::new().unwrap();
126    let d = u_d.set_file(file).unwrap();
127
128    println!(
129        "Input device ID: bus 0x{:x} vendor 0x{:x} product 0x{:x}",
130        d.bustype(),
131        d.vendor_id(),
132        d.product_id()
133    );
134    println!("Evdev version: {:x}", d.driver_version());
135    println!("Input device name: \"{}\"", d.name().unwrap_or(""));
136    println!("Phys location: {}", d.phys().unwrap_or(""));
137    println!("Uniq identifier: {}", d.uniq().unwrap_or(""));
138
139    print_bits(&d);
140    print_props(&d);
141
142    let mut a: io::Result<(ReadStatus, InputEvent)>;
143    loop {
144        a = d.next_event(ReadFlag::NORMAL);
145        if a.is_ok() {
146            let mut result = a.ok().unwrap();
147            match result.0 {
148                ReadStatus::Sync => {
149                    println!("::::::::::::::::::::: dropped ::::::::::::::::::::::");
150                    while result.0 == ReadStatus::Sync {
151                        print_sync_dropped_event(&result.1);
152                        a = d.next_event(ReadFlag::SYNC);
153                        if a.is_ok() {
154                            result = a.ok().unwrap();
155                        } else {
156                            break;
157                        }
158                    }
159                    println!("::::::::::::::::::::: re-synced ::::::::::::::::::::");
160                }
161                ReadStatus::Success => print_event(&result.1),
162            }
163        } else {
164            let err = a.err().unwrap();
165            match err.raw_os_error() {
166                Some(libc::EAGAIN) => continue,
167                _ => {
168                    println!("{}", err);
169                    break;
170                }
171            }
172        }
173    }
174}