blob: 739908c1bf6993ce2704bed7e7acefd98e031752 [file] [log] [blame]
mod events;
use 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
&& 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]) -> Result<(), String> {
// Open the set of character devices.
let files = input_devices
.iter()
.map(|x| {
EventReader::new_from_path(Path::new(x))
.map_err(|e| format!("Failed to open file '{}': {}", x.display(), e))
})
.collect::<Result<Vec<EventReader>, String>>()?;
// Create a EventReader object for each input file, all sending to the channel `tx`.
let (tx, rx) = mpsc::sync_channel(0);
let _threads = files
.into_iter()
.map(|mut r| {
let tx = tx.clone();
std::thread::spawn(move || {
while let Ok(event) = r.read() {
tx.send(event).ok();
}
})
})
.collect::<Vec<_>>();
// Wait for key strokes.
println!("Type 'abc<shift>' to pass test.");
let mut iter = rx.iter();
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")
.subcommand(
clap::SubCommand::with_name("keyboard")
.about("runs a keyboard test")
.arg(clap::Arg::with_name("files").required(true).min_values(1)),
)
.get_matches();
// Run the user-specified command
match matches.subcommand() {
("keyboard", Some(keyboard_matches)) => {
let files = keyboard_matches
.values_of("files")
.unwrap()
.map(Path::new)
.collect::<Vec<&Path>>();
run_keyboard_test(&files)
}
_ => Err("Must provide a subcommand indicating which test to run.".to_string()),
}
}