hippox-drivers 0.3.5

🦛All indivisible atomic driver units in Hippox.
//! Mouse drag driver module
//!
//! This module provides functionality to drag from one position to another
//! using mouse press, move, and release.
use super::common::{MouseButton, mouse_press, mouse_release, set_mouse_position};
use crate::{
    DriverCallback, DriverCategory, DriverContext, DriverError, DriverResult,
    types::{Driver, DriverParameter},
};
use serde_json::{Value, json};
use std::collections::HashMap;
use tracing::{debug, info};
/// Driver for dragging the mouse
#[derive(Debug)]
pub struct MouseControlDragDriver;
#[async_trait::async_trait]
impl Driver for MouseControlDragDriver {
    /// Returns the unique name of this driver
    fn name(&self) -> &str {
        return "mouse_control_drag";
    }
    /// Returns a brief description of the driver's functionality
    fn description(&self) -> &str {
        return "Drag from one position to another";
    }
    /// Returns detailed usage guidance for LLMs
    fn usage_hint(&self) -> &str {
        return "Use this skill to drag and drop. Press at start coordinates, move to end coordinates, then release.";
    }
    /// Returns the parameter definitions for this driver
    fn parameters(&self) -> Vec<DriverParameter> {
        return vec![
            DriverParameter {
                name: "start_x".to_string(),
                param_type: "integer".to_string(),
                description: "Starting X coordinate".to_string(),
                required: true,
                default: None,
                example: Some(Value::Number(100.into())),
                enum_values: None,
            },
            DriverParameter {
                name: "start_y".to_string(),
                param_type: "integer".to_string(),
                description: "Starting Y coordinate".to_string(),
                required: true,
                default: None,
                example: Some(Value::Number(100.into())),
                enum_values: None,
            },
            DriverParameter {
                name: "end_x".to_string(),
                param_type: "integer".to_string(),
                description: "Ending X coordinate".to_string(),
                required: true,
                default: None,
                example: Some(Value::Number(300.into())),
                enum_values: None,
            },
            DriverParameter {
                name: "end_y".to_string(),
                param_type: "integer".to_string(),
                description: "Ending Y coordinate".to_string(),
                required: true,
                default: None,
                example: Some(Value::Number(300.into())),
                enum_values: None,
            },
            DriverParameter {
                name: "button".to_string(),
                param_type: "string".to_string(),
                description: "Mouse button: 'left', 'right', or 'middle'".to_string(),
                required: false,
                default: Some(Value::String("left".to_string())),
                example: Some(Value::String("left".to_string())),
                enum_values: Some(vec!["left".to_string(), "right".to_string(), "middle".to_string()]),
            },
        ];
    }
    /// Returns an example call for this driver
    fn example_call(&self) -> DriverResult<Value> {
        return Ok(json!({
            "action": "mouse_control_drag",
            "parameters": {
                "start_x": 100,
                "start_y": 100,
                "end_x": 300,
                "end_y": 300,
                "button": "left"
            }
        }));
    }
    /// Returns an example output from this driver
    fn example_output(&self) -> String {
        return "Dragged from (100, 100) to (300, 300)".to_string();
    }
    /// Returns the category of this driver
    fn category(&self) -> DriverCategory {
        return DriverCategory::Mouse;
    }
    /// Executes the driver with the given parameters
    async fn execute(
        &self,
        parameters: &HashMap<String, Value>,
        _callback: Option<&dyn DriverCallback>,
        _context: Option<&DriverContext>,
    ) -> DriverResult<String> {
        debug!("Executing mouse_control_drag driver");
        let start_x = parameters.get("start_x").and_then(|v| v.as_i64()).ok_or_else(|| DriverError::missing_parameter("start_x"))? as i32;
        let start_y = parameters.get("start_y").and_then(|v| v.as_i64()).ok_or_else(|| DriverError::missing_parameter("start_y"))? as i32;
        let end_x = parameters.get("end_x").and_then(|v| v.as_i64()).ok_or_else(|| DriverError::missing_parameter("end_x"))? as i32;
        let end_y = parameters.get("end_y").and_then(|v| v.as_i64()).ok_or_else(|| DriverError::missing_parameter("end_y"))? as i32;
        let button_str = parameters.get("button").and_then(|v| v.as_str()).unwrap_or("left");
        let button = match button_str {
            "left" => MouseButton::Left,
            "right" => MouseButton::Right,
            "middle" => MouseButton::Middle,
            _ => MouseButton::Left,
        };
        debug!("Dragging from ({}, {}) to ({}, {}) with {} button", start_x, start_y, end_x, end_y, button_str);
        // Press at start
        mouse_press(button.clone(), start_x, start_y)?;
        // Move to end with small steps
        let steps = 20;
        for i in 1..=steps {
            let t = i as f64 / steps as f64;
            let x = start_x + ((end_x - start_x) as f64 * t) as i32;
            let y = start_y + ((end_y - start_y) as f64 * t) as i32;
            set_mouse_position(x, y)?;
            tokio::time::sleep(std::time::Duration::from_millis(5)).await;
        }
        // Release at end
        mouse_release(button, end_x, end_y)?;
        let result = format!("Dragged from ({}, {}) to ({}, {})", start_x, start_y, end_x, end_y);
        info!("{}", result);
        return Ok(result);
    }
    /// Validates the parameters before execution
    fn validate(&self, parameters: &HashMap<String, Value>) -> DriverResult<()> {
        parameters.get("start_x").and_then(|v| v.as_i64()).ok_or_else(|| DriverError::missing_parameter("start_x"))?;
        parameters.get("start_y").and_then(|v| v.as_i64()).ok_or_else(|| DriverError::missing_parameter("start_y"))?;
        parameters.get("end_x").and_then(|v| v.as_i64()).ok_or_else(|| DriverError::missing_parameter("end_x"))?;
        parameters.get("end_y").and_then(|v| v.as_i64()).ok_or_else(|| DriverError::missing_parameter("end_y"))?;
        return Ok(());
    }
}