clicker 0.5.0

a simple desktop automation tool
mod parse;

use inputbot::{KeybdKey, MouseButton};
use log::*;
use rand::Rng;
use std::{thread, time};
use structopt::{clap::AppSettings, StructOpt};

#[derive(StructOpt)]
#[structopt(rename_all = "kebab-case", global_settings(&[AppSettings::ColoredHelp]))]
struct Opt {
	/// the time in milliseconds that is going to be waited between clicks
	#[structopt(short, long, default_value = "70")]
	delay: u64,
	/// the time in milliseconds that is going to be spent between the mouse down and the mouse up event
	#[structopt(short, long, default_value = "5")]
	click_time: u64,
	/// if this is specified, the mouse button is only going to be clicked if this key is pressed
	#[structopt(short, long, parse(try_from_str = parse::keycode))]
	key: Option<KeybdKey>,
	/// the mouse button that is going to be pressed
	#[structopt(short, long, default_value = "Left", parse(try_from_str = parse::mousebutton))]
	button: MouseButton,
	/// the max value of wait time in milliseconds that will be randomly addet to each delay
	#[structopt(short, long)]
	random_delay: Option<u64>,
	/// the max value of wait time in milliseconds that will be randomly added to each click_time
	#[structopt(long)]
	random_click_time: Option<u64>,
}

fn main() {
	// initialize logging and cli arguments
	env_logger::init();
	let opt = Opt::from_args();

	if let Some(key) = opt.key {
		key.bind(move || {
			while key.is_pressed() {
				perform_click(&opt)
			}
		});
		inputbot::handle_input_events();
	} else {
		loop {
			perform_click(&opt)
		}
	}
}

/// perform a click according to the the provided options
fn perform_click(opt: &Opt) {
	let click_time = randomized_time(opt.click_time, opt.random_click_time);

	debug!("clicking with {}ms click time", click_time);
	click(opt.button, click_time);

	let delay = randomized_time(opt.delay, opt.random_delay);

	debug!("waiting {}ms until next click", delay);
	thread::sleep(time::Duration::from_millis(delay));
}

/// generate a time of a base time and a random value
fn randomized_time(time: u64, max_rnd: Option<u64>) -> u64 {
	if let Some(max_rnd) = max_rnd {
		time + rand::thread_rng().gen_range(0..max_rnd + 1)
	} else {
		time
	}
}

/// click the specified mouse button
fn click(button: MouseButton, time: u64) {
	button.press();
	thread::sleep(time::Duration::from_millis(time));
	button.release();
	debug!("clicked {:?} mouse button", button);
}