use serde::Serialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum MouseButton {
Left,
Right,
Middle,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum KeyboardModifier {
Alt,
Control,
Meta,
Shift,
ControlOrMeta,
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
pub struct Position {
pub x: f64,
pub y: f64,
}
#[derive(Debug, Clone, Default)]
pub struct ClickOptions {
pub button: Option<MouseButton>,
pub click_count: Option<u32>,
pub delay: Option<f64>,
pub force: Option<bool>,
pub modifiers: Option<Vec<KeyboardModifier>>,
pub no_wait_after: Option<bool>,
pub position: Option<Position>,
pub timeout: Option<f64>,
pub trial: Option<bool>,
}
impl ClickOptions {
pub fn builder() -> ClickOptionsBuilder {
ClickOptionsBuilder::default()
}
pub(crate) fn to_json(&self) -> serde_json::Value {
let mut json = serde_json::json!({});
if let Some(button) = &self.button {
json["button"] = serde_json::to_value(button).unwrap();
}
if let Some(click_count) = self.click_count {
json["clickCount"] = serde_json::json!(click_count);
}
if let Some(delay) = self.delay {
json["delay"] = serde_json::json!(delay);
}
if let Some(force) = self.force {
json["force"] = serde_json::json!(force);
}
if let Some(modifiers) = &self.modifiers {
json["modifiers"] = serde_json::to_value(modifiers).unwrap();
}
if let Some(no_wait_after) = self.no_wait_after {
json["noWaitAfter"] = serde_json::json!(no_wait_after);
}
if let Some(position) = &self.position {
json["position"] = serde_json::to_value(position).unwrap();
}
if let Some(timeout) = self.timeout {
json["timeout"] = serde_json::json!(timeout);
} else {
json["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
}
if let Some(trial) = self.trial {
json["trial"] = serde_json::json!(trial);
}
json
}
}
#[derive(Debug, Clone, Default)]
pub struct ClickOptionsBuilder {
button: Option<MouseButton>,
click_count: Option<u32>,
delay: Option<f64>,
force: Option<bool>,
modifiers: Option<Vec<KeyboardModifier>>,
no_wait_after: Option<bool>,
position: Option<Position>,
timeout: Option<f64>,
trial: Option<bool>,
}
impl ClickOptionsBuilder {
pub fn button(mut self, button: MouseButton) -> Self {
self.button = Some(button);
self
}
pub fn click_count(mut self, click_count: u32) -> Self {
self.click_count = Some(click_count);
self
}
pub fn delay(mut self, delay: f64) -> Self {
self.delay = Some(delay);
self
}
pub fn force(mut self, force: bool) -> Self {
self.force = Some(force);
self
}
pub fn modifiers(mut self, modifiers: Vec<KeyboardModifier>) -> Self {
self.modifiers = Some(modifiers);
self
}
pub fn no_wait_after(mut self, no_wait_after: bool) -> Self {
self.no_wait_after = Some(no_wait_after);
self
}
pub fn position(mut self, position: Position) -> Self {
self.position = Some(position);
self
}
pub fn timeout(mut self, timeout: f64) -> Self {
self.timeout = Some(timeout);
self
}
pub fn trial(mut self, trial: bool) -> Self {
self.trial = Some(trial);
self
}
pub fn build(self) -> ClickOptions {
ClickOptions {
button: self.button,
click_count: self.click_count,
delay: self.delay,
force: self.force,
modifiers: self.modifiers,
no_wait_after: self.no_wait_after,
position: self.position,
timeout: self.timeout,
trial: self.trial,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mouse_button_serialization() {
assert_eq!(
serde_json::to_string(&MouseButton::Left).unwrap(),
"\"left\""
);
assert_eq!(
serde_json::to_string(&MouseButton::Right).unwrap(),
"\"right\""
);
assert_eq!(
serde_json::to_string(&MouseButton::Middle).unwrap(),
"\"middle\""
);
}
#[test]
fn test_keyboard_modifier_serialization() {
assert_eq!(
serde_json::to_string(&KeyboardModifier::Alt).unwrap(),
"\"Alt\""
);
assert_eq!(
serde_json::to_string(&KeyboardModifier::Control).unwrap(),
"\"Control\""
);
assert_eq!(
serde_json::to_string(&KeyboardModifier::Meta).unwrap(),
"\"Meta\""
);
assert_eq!(
serde_json::to_string(&KeyboardModifier::Shift).unwrap(),
"\"Shift\""
);
assert_eq!(
serde_json::to_string(&KeyboardModifier::ControlOrMeta).unwrap(),
"\"ControlOrMeta\""
);
}
#[test]
fn test_builder_button() {
let options = ClickOptions::builder().button(MouseButton::Right).build();
let json = options.to_json();
assert_eq!(json["button"], "right");
}
#[test]
fn test_builder_click_count() {
let options = ClickOptions::builder().click_count(2).build();
let json = options.to_json();
assert_eq!(json["clickCount"], 2);
}
#[test]
fn test_builder_delay() {
let options = ClickOptions::builder().delay(100.0).build();
let json = options.to_json();
assert_eq!(json["delay"], 100.0);
}
#[test]
fn test_builder_force() {
let options = ClickOptions::builder().force(true).build();
let json = options.to_json();
assert_eq!(json["force"], true);
}
#[test]
fn test_builder_modifiers() {
let options = ClickOptions::builder()
.modifiers(vec![KeyboardModifier::Shift, KeyboardModifier::Control])
.build();
let json = options.to_json();
assert_eq!(json["modifiers"], serde_json::json!(["Shift", "Control"]));
}
#[test]
fn test_builder_position() {
let position = Position { x: 10.0, y: 20.0 };
let options = ClickOptions::builder().position(position).build();
let json = options.to_json();
assert_eq!(json["position"]["x"], 10.0);
assert_eq!(json["position"]["y"], 20.0);
}
#[test]
fn test_builder_timeout() {
let options = ClickOptions::builder().timeout(5000.0).build();
let json = options.to_json();
assert_eq!(json["timeout"], 5000.0);
}
#[test]
fn test_builder_trial() {
let options = ClickOptions::builder().trial(true).build();
let json = options.to_json();
assert_eq!(json["trial"], true);
}
#[test]
fn test_builder_multiple_options() {
let options = ClickOptions::builder()
.button(MouseButton::Right)
.modifiers(vec![KeyboardModifier::Shift])
.position(Position { x: 5.0, y: 10.0 })
.force(true)
.timeout(3000.0)
.build();
let json = options.to_json();
assert_eq!(json["button"], "right");
assert_eq!(json["modifiers"], serde_json::json!(["Shift"]));
assert_eq!(json["position"]["x"], 5.0);
assert_eq!(json["position"]["y"], 10.0);
assert_eq!(json["force"], true);
assert_eq!(json["timeout"], 3000.0);
}
}