blob: d0ac6c6979e599d406858a10f216b4715791339e [file] [log] [blame]
mod events;
use crate::events::{EventReader, EventType, InputEvent, KeyboardCode, KeyboardValue};
use std::path::Path;
use std::sync::mpsc;
/// Wait for the given key to be pressed on the given `events` interator.
///
/// Returns `true` if the keystroke was detected before the iterator finished.
fn wait_for_key_press<I>(code: KeyboardCode, events: &mut I) -> Result<(), String>
where
I: Iterator<Item = InputEvent>,
{
for e in events {
if { e.type_ } == (EventType::Key as u16)
&& e.code == (code as u16)
&& e.value == (KeyboardValue::KeyDown as i32)
{
return Ok(());
}
}
Err("Device closed while waiting for key press.".to_string())
}
fn run_keyboard_test(input_devices: &[&Path], enable_debugging: bool) -> Result<(), String> {
// Create a EventReader object for each input file, each with its own thread, all sending to
// the channel `tx`.
let (tx, rx) = mpsc::sync_channel(0);
for path in input_devices.iter() {
let mut reader = EventReader::new_from_path(path)
.map_err(|e| format!("Failed to open file '{}': {}", path.display(), e))?;
let tx = tx.clone();
std::thread::spawn(move || {
while let Ok(event) = reader.read() {
tx.send(event).ok();
}
});
}
// Wait for key strokes.
println!("Type 'abc<shift>' to pass test.");
let mut iter = rx.iter().inspect(|&x| {
if enable_debugging {
println!("{:?}", x);
}
});
let codes = [
KeyboardCode::A,
KeyboardCode::B,
KeyboardCode::C,
KeyboardCode::LeftShift,
];
for code in &codes {
println!(" waiting for {:?} ...", code);
if let error @ Err(_) = wait_for_key_press(*code, &mut iter) {
return error;
}
}
println!("PASS");
Ok(())
}
fn main() -> Result<(), String> {
// Parse command line arguments.
let matches = clap::App::new("VirtIO Input Tester")
.arg(
clap::Arg::with_name("debug")
.short("d")
.help("Show debugging information."),
)
.subcommand(
clap::SubCommand::with_name("keyboard")
.about("runs a keyboard test")
.arg(clap::Arg::with_name("files").required(true).min_values(1)),
)
.get_matches();
let enable_debugging = matches.is_present("debug");
// Run the user-specified command
if let ("keyboard", Some(keyboard_matches)) = matches.subcommand() {
let files = keyboard_matches
.values_of("files")
.unwrap()
.map(Path::new)
.collect::<Vec<&Path>>();
run_keyboard_test(&files, enable_debugging)
} else {
Err("Must provide a subcommand indicating which test to run.".to_string())
}
}