blob: 676ed1ae744d746401eae3660105d6ffa512f322 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::{env, time::Duration};
use fuchsia_async as fasync;
use input_synthesis;
use structopt::StructOpt;
#[derive(Debug, StructOpt)]
#[structopt(name = "input")]
/// simple tool to inject input events into Scenic
struct Opt {
#[structopt(subcommand)]
command: Command,
}
const KEYEVENT_HELP: &str = r#"Injects a single key event.
This command simulates a single key down + up sequence. The argument is a decimal HID usage
`code`, prior to any remapping the IME may do.
Common usage codes:
key | code
----------|-----
enter | 40
escape | 41
backspace | 42
tab | 43
The time between the down and up report is `--duration`."#;
#[derive(Debug, StructOpt)]
enum Command {
#[structopt(name = "text")]
/// Injects text using QWERTY keystrokes
///
/// Text is injected by translating a string into keystrokes using a QWERTY keymap. This
/// facility is intended for end-to-end and input testing purposes only.
///
/// Only printable ASCII characters are mapped. Tab, newline, and other control haracters are
/// not supported, and `keyevent` should be used instead.
///
/// The events simulated consist of a series of keyboard reports, ending in a report with no
/// keys. The number of reports is near the lower bound of reports needed to produce the
/// requested string, minimizing pauses and shift-state transitions.
///
/// The `--duration` is divided between the reports. Care should be taken not to provide so
/// long a duration that key repeat kicks in.
///
/// Note: when using through `fx shell` with quotes, you may need to surround the invocation in
/// strong quotes, e.g.:
///
/// fx shell 'input text "Hello, world!"'
Text {
#[structopt(short = "d", long = "duration", default_value = "0")]
/// Duration of the event(s) in milliseconds
duration: u32,
/// Input text to inject
input: String,
},
#[structopt(name = "keyevent", raw(help = "KEYEVENT_HELP"))]
KeyboardEvent {
#[structopt(short = "d", long = "duration", default_value = "0")]
/// Duration of the event(s) in milliseconds
duration: u32,
/// HID usage code
usage: u32,
},
#[structopt(name = "tap")]
/// Injects a single tap event
///
/// This command simulates a single touch down + up sequence. By default, the `x` and `y`
/// coordinates are in the range 0 to 1000 and will be proportionally transformed to the
/// current display, but you can specify a virtual range for the input with the `--width` and
/// `--height` options.
///
/// The time between the down and up report is `--duration`.
Tap {
#[structopt(short = "w", long = "width", default_value = "1000")]
/// Width of the display
width: u32,
#[structopt(short = "h", long = "height", default_value = "1000")]
/// Height of the display
height: u32,
#[structopt(short = "tc", long = "tap_event_count", default_value = "1")]
/// Number of tap events to send (`--duration` is divided over the tap events)
tap_event_count: usize,
#[structopt(short = "d", long = "duration", default_value = "0")]
/// Duration of the event(s) in milliseconds
duration: u32,
/// X axis coordinate
x: u32,
/// Y axis coordinate
y: u32,
},
#[structopt(name = "swipe")]
/// Injects a swipe event
///
/// This command simulates a touch down, a series of touch move, followed up a touch up event.
/// By default, the `x` and `y` coordinates are in the range 0 to 1000 and will be
/// proportionally transformed to the current display, but you can specify a virtual range for
/// the input with the `--width` and `--height` options.
///
/// The time between the down and up report is `--duration`.
Swipe {
#[structopt(short = "w", long = "width", default_value = "1000")]
/// Width of the display
width: u32,
#[structopt(short = "h", long = "height", default_value = "1000")]
/// Height of the display
height: u32,
#[structopt(short = "mc", long = "move_event_count", default_value = "100")]
/// Number of move events to send in between the down and up events of the swipe
move_event_count: usize,
#[structopt(short = "d", long = "duration", default_value = "0")]
/// Duration of the event(s) in milliseconds
duration: u32,
/// X axis start coordinate
x0: u32,
/// Y axis start coordinate
y0: u32,
/// X axis end coordinate
x1: u32,
/// Y axis end coordinate
y1: u32,
},
#[structopt(name = "media_button")]
/// Injects a MediaButton event
MediaButton {
#[structopt(parse(try_from_str = "parse_bool"))]
/// 0 or 1
mic_mute: bool,
#[structopt(parse(try_from_str = "parse_bool"))]
/// 0 or 1
volume_up: bool,
#[structopt(parse(try_from_str = "parse_bool"))]
/// 0 or 1
volume_down: bool,
#[structopt(parse(try_from_str = "parse_bool"))]
/// 0 or 1
reset: bool,
#[structopt(parse(try_from_str = "parse_bool"))]
/// 0 or 1
pause: bool,
},
}
fn parse_bool(src: &str) -> Result<bool, String> {
match src {
"0" | "false" => Ok(false),
"1" | "true" => Ok(true),
_ => Err(format!("cannot parse {:?} to bool", src)),
}
}
macro_rules! run {
( $executor:expr, $command:ident, [ $( $args:expr ),* $( , )? ] ) => {
$executor.run(
input_synthesis::$command(
$($args),*
),
1,
).expect("failed to run command");
}
}
fn main() {
// TODO: Remove this workaround once topaz tests have been updated.
let (mut args, options): (Vec<_>, Vec<_>) = env::args_os().partition(|s| match s.to_str() {
Some(s) => s.get(0..2) != Some("--"),
_ => false,
});
args.extend(options);
let opt = Opt::from_iter(args.into_iter());
let mut executor = fasync::Executor::new().expect("failed to create executor");
match opt.command {
Command::Text { input, duration } => {
run!(executor, text_command, [input, Duration::from_millis(duration as u64),])
}
Command::KeyboardEvent { usage, duration } => {
run!(executor, keyboard_event_command, [usage, Duration::from_millis(duration as u64),])
}
Command::Tap { width, height, tap_event_count, duration, x, y } => run!(
executor,
tap_event_command,
[x, y, width, height, tap_event_count, Duration::from_millis(duration as u64),]
),
Command::Swipe { width, height, move_event_count, duration, x0, y0, x1, y1 } => run!(
executor,
swipe_command,
[
x0,
y0,
x1,
y1,
width,
height,
move_event_count,
Duration::from_millis(duration as u64),
]
),
Command::MediaButton { mic_mute, volume_up, volume_down, reset, pause } => run!(
executor,
media_button_event_command,
[mic_mute, volume_up, volume_down, reset, pause]
),
};
}