1use crate::error::Result;
4use crate::options::MouseOptions;
5use crate::page::Page;
6use crate::types::MouseButton;
7use parking_lot::Mutex;
8use serde_json::{json, Value};
9use std::sync::Arc;
10use std::time::Duration;
11
12#[derive(Clone)]
16pub struct Mouse {
17 page: Page,
18 pos: Arc<Mutex<(f64, f64)>>,
19}
20
21impl Mouse {
22 pub(crate) fn with_pos(page: Page, pos: Arc<Mutex<(f64, f64)>>) -> Self {
24 Self { page, pos }
25 }
26
27 fn pos(&self) -> (f64, f64) {
28 *self.pos.lock()
29 }
30
31 async fn dispatch(
32 &self,
33 r#type: &str,
34 x: f64,
35 y: f64,
36 button: MouseButton,
37 buttons: u8,
38 click_count: u32,
39 ) -> Result<()> {
40 self.page
41 .session()
42 .send(
43 "Input.dispatchMouseEvent",
44 json!({
45 "type": r#type,
46 "x": x,
47 "y": y,
48 "button": button.as_str(),
49 "buttons": buttons,
50 "clickCount": click_count,
51 }),
52 )
53 .await
54 .map(|_: Value| ())
55 }
56
57 pub async fn move_to(&self, x: f64, y: f64, _options: Option<MouseOptions>) -> Result<()> {
59 *self.pos.lock() = (x, y);
60 self.dispatch("mouseMoved", x, y, MouseButton::Left, 0, 0).await
61 }
62
63 pub async fn down(&self, options: Option<MouseOptions>) -> Result<()> {
65 let opts = options.unwrap_or_default();
66 let button = opts.button.unwrap_or_default();
67 let (x, y) = self.pos();
68 let count = opts.click_count.unwrap_or(1);
69 self.dispatch("mousePressed", x, y, button, button.bitmask(), count).await
70 }
71
72 pub async fn up(&self, options: Option<MouseOptions>) -> Result<()> {
74 let opts = options.unwrap_or_default();
75 let button = opts.button.unwrap_or_default();
76 let (x, y) = self.pos();
77 let count = opts.click_count.unwrap_or(1);
78 self.dispatch("mouseReleased", x, y, button, 0, count).await
79 }
80
81 pub async fn click(&self, x: f64, y: f64, options: Option<MouseOptions>) -> Result<()> {
83 self.perform_click(x, y, options, 1).await
84 }
85
86 pub async fn dblclick(&self, x: f64, y: f64, options: Option<MouseOptions>) -> Result<()> {
88 self.perform_click(x, y, options, 2).await
89 }
90
91 async fn perform_click(
92 &self,
93 x: f64,
94 y: f64,
95 options: Option<MouseOptions>,
96 default_count: u32,
97 ) -> Result<()> {
98 let opts = options.unwrap_or_default();
99 let button = opts.button.unwrap_or_default();
100 let count = opts.click_count.unwrap_or(default_count);
101 let delay = opts.delay.map(|ms| Duration::from_millis(ms as u64));
102
103 *self.pos.lock() = (x, y);
104 self.dispatch("mouseMoved", x, y, MouseButton::Left, 0, 0).await?;
105 for i in 0..count {
106 self.dispatch("mousePressed", x, y, button, button.bitmask(), i + 1).await?;
107 self.dispatch("mouseReleased", x, y, button, 0, i + 1).await?;
108 if let Some(d) = delay {
109 if i + 1 < count {
110 tokio::time::sleep(d).await;
111 }
112 }
113 }
114 Ok(())
115 }
116
117 pub async fn wheel(&self, delta_x: f64, delta_y: f64) -> Result<()> {
119 let (x, y) = self.pos();
120 self.page
121 .session()
122 .send(
123 "Input.dispatchMouseEvent",
124 json!({
125 "type": "mouseWheel",
126 "x": x,
127 "y": y,
128 "deltaX": delta_x,
129 "deltaY": delta_y,
130 "button": "none",
131 "buttons": 0,
132 }),
133 )
134 .await
135 .map(|_: Value| ())
136 }
137}