use crate::mouse::mouse_input;
use crate::script_engine::instruction::{
InstructionData, InstructionHandler, InstructionMetadata, ScriptError,
};
use crate::script_engine::VMContext;
use windows::Win32::UI::Input::KeyboardAndMouse::INPUT;
#[derive(Clone)]
pub struct ScrollDownParams {
pub x: Option<i32>,
pub y: Option<i32>,
pub times: u32,
pub scroll_input: INPUT,
}
pub struct ScrollDownHandler;
impl InstructionHandler for ScrollDownHandler {
fn name(&self) -> &str {
"scrolldown"
}
#[inline]
fn parse(&self, args: &[&str]) -> Result<InstructionData, ScriptError> {
let mut x: Option<i32> = None;
let mut y: Option<i32> = None;
let mut times: u32 = 1;
match args.len() {
0 => {}
1 => {
if let Ok(val) = args[0].parse::<u32>() {
times = val;
} else if let Ok(val) = args[0].parse::<i32>() {
if val >= 0 {
times = val as u32;
} else {
return Err(ScriptError::ParseError(
"Scroll times must be positive".into(),
));
}
} else {
return Err(ScriptError::ParseError(
format!("Invalid argument '{}'. Expected: scrolldown [x] [y] [times]", args[0]).into(),
));
}
}
2 => {
if let Ok(val) = args[0].parse::<i32>() {
if val < 0 {
return Err(ScriptError::ParseError(
format!("Coordinates cannot be negative: {}", val).into(),
));
}
x = Some(val);
} else {
return Err(ScriptError::ParseError(
format!("Invalid argument '{}'. Expected: scrolldown [x] [y] [times]", args[0]).into(),
));
}
if let Ok(val) = args[1].parse::<i32>() {
if val < 0 {
return Err(ScriptError::ParseError(
format!("Coordinates cannot be negative: {}", val).into(),
));
}
y = Some(val);
} else {
return Err(ScriptError::ParseError(
format!("Invalid argument '{}'. Expected: scrolldown [x] [y] [times]", args[1]).into(),
));
}
}
_ => {
if let Ok(val) = args[0].parse::<i32>() {
if val < 0 {
return Err(ScriptError::ParseError(
format!("Coordinates cannot be negative: {}", val).into(),
));
}
x = Some(val);
} else {
return Err(ScriptError::ParseError(
format!("Invalid argument '{}'. Expected: scrolldown [x] [y] [times]", args[0]).into(),
));
}
if let Ok(val) = args[1].parse::<i32>() {
if val < 0 {
return Err(ScriptError::ParseError(
format!("Coordinates cannot be negative: {}", val).into(),
));
}
y = Some(val);
} else {
return Err(ScriptError::ParseError(
format!("Invalid argument '{}'. Expected: scrolldown [x] [y] [times]", args[1]).into(),
));
}
if let Ok(val) = args[2].parse::<u32>() {
times = val;
} else if let Ok(val) = args[2].parse::<i32>() {
if val >= 0 {
times = val as u32;
}
}
}
}
if let (Some(x_val), Some(y_val)) = (x, y) {
if x_val < 0 || y_val < 0 {
return Err(ScriptError::ParseError(
format!("Coordinates cannot be negative: ({}, {})", x_val, y_val).into(),
));
}
}
if times < 1 || times > 100 {
return Err(ScriptError::ParseError(
"Scroll times must be between 1 and 100".into(),
));
}
Ok(InstructionData::Custom(Box::new(ScrollDownParams {
x,
y,
times,
scroll_input: mouse_input::build_scroll_down(120),
})))
}
#[inline]
fn execute(
&self,
vm: &mut VMContext,
data: &InstructionData,
_metadata: Option<&InstructionMetadata>,
) -> Result<(), ScriptError> {
let params = data.extract_custom::<ScrollDownParams>("Invalid scroll parameters")?;
if let (Some(x), Some(y)) = (params.x, params.y) {
let (screen_x, screen_y) = match vm.process.window_geometry {
Some(geo) => (x + geo.window_left, y + geo.window_top),
None => (x, y),
};
mouse_input::set_cursor_pos(screen_x, screen_y).map_err(|e| {
ScriptError::ExecutionError(format!("SetCursorPos failed: {:?}", e))
})?;
}
for _ in 0..params.times {
mouse_input::execute_single_input(¶ms.scroll_input).map_err(|e| {
ScriptError::ExecutionError(format!("Scroll down failed: {:?}", e))
})?;
}
Ok(())
}
}