windows-troll 0.1.0

Modular Windows prank library
//! CLI for the
//! [`mouse_teleporter`](windows_troll::modules::mouse_teleporter)
//! module.

use std::thread;
use std::time::Duration;

use clap::{arg, ArgMatches, Command};
use rand::{rng, RngExt};

use windows_troll::modules::mouse_teleporter;

use crate::cli::CliModule;

/// CLI registration for the mouse-teleporter module.
pub struct MouseTeleporterCli;

impl CliModule for MouseTeleporterCli {
    fn name(&self) -> &'static str {
        "mouse-teleporter"
    }

    fn about(&self) -> &'static str {
        "Move the mouse to chosen or random positions"
    }

    fn command(&self) -> Command {
        Command::new(self.name())
            .about(self.about())
            .subcommand_required(true)
            .arg_required_else_help(true)
            .subcommand(
                Command::new("teleport")
                    .about("Move the mouse to a specific position")
                    .arg(arg!(<X> "Horizontal screen coordinate").value_parser(clap::value_parser!(i32)))
                    .arg(arg!(<Y> "Vertical screen coordinate").value_parser(clap::value_parser!(i32))),
            )
            .subcommand(Command::new("random").about("Move the mouse to a random position"))
            .subcommand(
                Command::new("resolution").about("Print the primary display resolution"),
            )
            .subcommand(
                Command::new("loop")
                    .about("Continuously move the mouse to random positions")
                    .arg(
                        arg!(-m --min <SECONDS> "Minimum wait time in seconds")
                            .default_value("10")
                            .value_parser(clap::value_parser!(u64)),
                    )
                    .arg(
                        arg!(-M --max <SECONDS> "Maximum wait time in seconds")
                            .default_value("60")
                            .value_parser(clap::value_parser!(u64)),
                    ),
            )
    }

    fn run(&self, matches: &ArgMatches) -> Result<(), Box<dyn std::error::Error>> {
        match matches.subcommand() {
            Some(("teleport", m)) => run_teleport(m),
            Some(("random", _)) => run_random(),
            Some(("resolution", _)) => run_resolution(),
            Some(("loop", m)) => run_loop(m),
            _ => unreachable!("exhausted subcommands"),
        }
    }
}

fn run_teleport(m: &ArgMatches) -> Result<(), Box<dyn std::error::Error>> {
    let x = *m.get_one::<i32>("X").expect("required argument");
    let y = *m.get_one::<i32>("Y").expect("required argument");
    if mouse_teleporter::teleport_mouse(x, y) {
        println!("Teleported mouse to ({x}, {y})");
    } else {
        println!("Failed to teleport mouse to ({x}, {y})");
    }
    Ok(())
}

fn run_random() -> Result<(), Box<dyn std::error::Error>> {
    let (x, y) = mouse_teleporter::teleport_random();
    println!("Teleported mouse to random position ({x}, {y})");
    Ok(())
}

fn run_resolution() -> Result<(), Box<dyn std::error::Error>> {
    let res = mouse_teleporter::get_resolution();
    println!("{}x{}", res.width, res.height);
    Ok(())
}

fn run_loop(m: &ArgMatches) -> Result<(), Box<dyn std::error::Error>> {
    let mut min = *m.get_one::<u64>("min").expect("has default");
    let mut max = *m.get_one::<u64>("max").expect("has default");
    if min > max {
        std::mem::swap(&mut min, &mut max);
    }

    println!("mouse-teleporter loop started. Press Ctrl+C to exit.");
    println!("wait range: {min}..={max} seconds");

    let mut rng = rng();
    loop {
        let wait = rng.random_range(min..=max);
        println!("waiting {wait}s...");
        thread::sleep(Duration::from_secs(wait));

        let (x, y) = mouse_teleporter::teleport_random();
        println!("teleported mouse to ({x}, {y})");
    }
}