use crate::error::{AutoError, Result};
use crate::platform::screen::WindowsScreen;
use crate::{
keyboard::Key,
platform::{WindowsClipboard, WindowsKeyboard, WindowsMouse},
};
use image::RgbaImage;
use std::thread;
use std::time::Duration;
pub struct AutoControl;
impl AutoControl {
pub fn new() -> Self {
Self
}
pub fn position(&self) -> Result<(i32, i32)> {
Ok(WindowsMouse::position().unwrap())
}
pub fn left_click(&self) -> Result<()> {
Ok(WindowsMouse::left_click().unwrap())
}
pub fn right_click(&self) -> Result<()> {
Ok(WindowsMouse::right_click().unwrap())
}
pub fn middle_click(&self) -> Result<()> {
Ok(WindowsMouse::middle_click().unwrap())
}
pub fn left_down(&self) -> Result<()> {
Ok(WindowsMouse::left_down().unwrap())
}
pub fn left_up(&self) -> Result<()> {
Ok(WindowsMouse::left_up().unwrap())
}
pub fn double_click(&self) -> Result<()> {
self.left_click().unwrap();
thread::sleep(Duration::from_millis(80));
self.left_click().unwrap();
Ok(())
}
pub fn move_relative(&self, dx: i32, dy: i32) -> Result<()> {
Ok(WindowsMouse::move_relative(dx, dy).unwrap())
}
pub fn move_absolute(&self, x: i32, y: i32) -> Result<()> {
Ok(WindowsMouse::move_absolute(x, y).unwrap())
}
pub fn scroll_vertical(&self, delta: i32) -> Result<()> {
if delta > 0 {
WindowsMouse::wheel_up(delta).unwrap();
} else {
WindowsMouse::wheel_down(delta.abs()).unwrap();
}
Ok(())
}
pub fn scroll_horizontal(&self, delta: i32) -> Result<()> {
if delta > 0 {
WindowsMouse::wheel_right(delta).unwrap();
} else {
WindowsMouse::wheel_left(delta.abs()).unwrap();
}
Ok(())
}
pub fn smooth_move(&self, x: i32, y: i32, duration_ms: u64) -> Result<()> {
let (sx, sy) = WindowsMouse::position().unwrap();
let steps = 120;
let dx = (x - sx) as f32 / steps as f32;
let dy = (y - sy) as f32 / steps as f32;
for i in 0..steps {
WindowsMouse::move_absolute(
(sx as f32 + dx * i as f32) as i32,
(sy as f32 + dy * i as f32) as i32,
)
.unwrap();
thread::sleep(Duration::from_millis(duration_ms / steps as u64));
}
WindowsMouse::move_absolute(x, y).unwrap();
Ok(())
}
pub fn drag(&self, from: (i32, i32), to: (i32, i32), duration_ms: u64) -> Result<()> {
self.move_absolute(from.0, from.1).unwrap();
self.left_down().unwrap();
self.smooth_move(to.0, to.1, duration_ms).unwrap();
self.left_up().unwrap();
Ok(())
}
pub fn key_down(&self, key: Key) -> Result<()> {
Ok(WindowsKeyboard::key_down(key.vk()).unwrap())
}
pub fn key_up(&self, key: Key) -> Result<()> {
Ok(WindowsKeyboard::key_up(key.vk()).unwrap())
}
pub fn key_down_str(&self, key: &str) -> Result<()> {
let key = key
.parse::<Key>()
.map_err(|_| AutoError::InvalidKey(key.to_string()))
.unwrap();
self.key_down(key)
}
pub fn key_up_str(&self, key: &str) -> Result<()> {
let key = key
.parse::<Key>()
.map_err(|_| AutoError::InvalidKey(key.to_string()))
.unwrap();
self.key_up(key)
}
pub fn press(&self, key: Key) -> Result<()> {
Ok(WindowsKeyboard::press(key.vk()).unwrap())
}
pub fn press_str(&self, key: &str) -> Result<()> {
let key = key
.parse::<Key>()
.map_err(|_| AutoError::InvalidKey(key.to_string()))
.unwrap();
self.press(key)
}
fn combo_vk(&self, keys: &[u16]) -> Result<()> {
WindowsKeyboard::combo(keys)
}
pub fn combo<const N: usize>(&self, keys: [Key; N]) -> Result<()> {
let vks: Vec<u16> = keys.into_iter().map(Key::vk).collect();
self.combo_vk(&vks)
}
pub fn combo_str<const N: usize>(&self, keys: [&str; N]) -> Result<()> {
let vks: Vec<u16> = keys
.into_iter()
.map(|k| {
k.parse::<Key>()
.map(|k| k.vk())
.map_err(|_| AutoError::InvalidKey(k.to_string()))
})
.collect::<Result<_>>()
.unwrap();
self.combo_vk(&vks)
}
pub fn text(&self, text: &str) -> Result<()> {
Ok(WindowsKeyboard::text(text).unwrap())
}
pub fn wait(&self, ms: u64) -> Result<()> {
thread::sleep(Duration::from_millis(ms));
Ok(())
}
pub fn screen_width(&self) -> Result<i32> {
Ok(WindowsScreen::screen_width().unwrap())
}
pub fn screen_height(&self) -> Result<i32> {
Ok(WindowsScreen::screen_height().unwrap())
}
pub fn screen_size(&self) -> Result<(i32, i32)> {
Ok(WindowsScreen::screen_size().unwrap())
}
pub fn clipboard_get_text(&self) -> Result<String> {
WindowsClipboard::get_text()
}
pub fn clipboard_set_text(&self, text: &str) -> Result<()> {
WindowsClipboard::set_text(text)
}
pub fn clipboard_clear(&self) -> Result<()> {
WindowsClipboard::clear()
}
pub fn clipboard_get_image(&self) -> Result<RgbaImage> {
WindowsClipboard::get_image()
}
pub fn clipboard_set_image(&self, image: &RgbaImage) -> Result<()> {
WindowsClipboard::set_image(image)
}
pub fn screenshot(&self) -> Result<RgbaImage> {
WindowsScreen::screenshot()
}
pub fn screenshot_region(&self, x: u32, y: u32, width: u32, height: u32) -> Result<RgbaImage> {
WindowsScreen::screenshot_region(x, y, width, height)
}
}