use crate::keyboard::keyboard_input;
use crate::script_engine::instruction::{
InstructionData, InstructionHandler, InstructionMetadata, ScriptError,
};
use crate::script_engine::VMContext;
use std::thread;
use std::time::Duration;
pub struct PasteHandler;
impl InstructionHandler for PasteHandler {
fn name(&self) -> &str {
"paste"
}
fn parse(&self, args: &[&str]) -> Result<InstructionData, ScriptError> {
let delay_ms = if args.is_empty() {
20 } else {
args[0].parse::<u32>().map_err(|e| {
ScriptError::ParseError(format!("Invalid delay '{}': {}", args[0], e))
})?
};
Ok(InstructionData::Custom(Box::new(delay_ms)))
}
fn execute(
&self,
_vm: &mut VMContext,
data: &InstructionData,
_metadata: Option<&InstructionMetadata>,
) -> Result<(), ScriptError> {
let delay_ms = *data.extract_custom::<u32>("Invalid paste delay")?;
const VK_CONTROL: u8 = 0x11;
const VK_V: u8 = 0x56;
let ctrl_down = keyboard_input::build_key_down_input(VK_CONTROL, false);
keyboard_input::execute_single_input(&ctrl_down).map_err(|e| {
ScriptError::ExecutionError(format!("Failed to press CONTROL: {:?}", e))
})?;
if delay_ms > 0 {
thread::sleep(Duration::from_millis(delay_ms as u64));
}
let v_down = keyboard_input::build_key_down_input(VK_V, false);
let v_up = keyboard_input::build_key_up_input(VK_V, false);
keyboard_input::execute_inputs(&[v_down, v_up]).map_err(|e| {
ScriptError::ExecutionError(format!("Failed to press V: {:?}", e))
})?;
if delay_ms > 0 {
thread::sleep(Duration::from_millis(delay_ms as u64));
}
let ctrl_up = keyboard_input::build_key_up_input(VK_CONTROL, false);
keyboard_input::execute_single_input(&ctrl_up).map_err(|e| {
ScriptError::ExecutionError(format!("Failed to release CONTROL: {:?}", e))
})?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_paste_default() {
let handler = PasteHandler;
let result = handler.parse(&[]).unwrap();
match result {
InstructionData::Custom(boxed) => {
let delay = boxed.downcast_ref::<u32>().unwrap();
assert_eq!(*delay, 20);
}
_ => panic!("Expected Custom data"),
}
}
#[test]
fn test_parse_paste_with_delay() {
let handler = PasteHandler;
let result = handler.parse(&["50"]).unwrap();
match result {
InstructionData::Custom(boxed) => {
let delay = boxed.downcast_ref::<u32>().unwrap();
assert_eq!(*delay, 50);
}
_ => panic!("Expected Custom data"),
}
}
#[test]
fn test_parse_paste_invalid_delay() {
let handler = PasteHandler;
assert!(handler.parse(&["abc"]).is_err());
}
}