1use crate::protocol::action_options::Scroll;
6use serde::Serialize;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
18#[serde(rename_all = "lowercase")]
19#[non_exhaustive]
20pub enum MouseButton {
21 Left,
23 Right,
25 Middle,
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
39#[non_exhaustive]
40pub enum KeyboardModifier {
41 Alt,
43 Control,
45 Meta,
47 Shift,
49 ControlOrMeta,
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
65pub struct Position {
66 pub x: f64,
68 pub y: f64,
70}
71
72#[derive(Debug, Clone, Default, serde::Serialize)]
102#[serde(rename_all = "camelCase")]
103#[non_exhaustive]
104pub struct ClickOptions {
105 #[serde(skip_serializing_if = "Option::is_none")]
107 pub button: Option<MouseButton>,
108 #[serde(skip_serializing_if = "Option::is_none")]
110 pub click_count: Option<u32>,
111 #[serde(skip_serializing_if = "Option::is_none")]
113 pub delay: Option<f64>,
114 #[serde(skip_serializing_if = "Option::is_none")]
116 pub force: Option<bool>,
117 #[serde(skip_serializing_if = "Option::is_none")]
119 pub modifiers: Option<Vec<KeyboardModifier>>,
120 #[serde(skip_serializing_if = "Option::is_none")]
122 pub no_wait_after: Option<bool>,
123 #[serde(skip_serializing_if = "Option::is_none")]
125 pub position: Option<Position>,
126 #[serde(serialize_with = "crate::protocol::serialize_timeout_or_default")]
129 pub timeout: Option<f64>,
130 #[serde(skip_serializing_if = "Option::is_none")]
132 pub trial: Option<bool>,
133 #[serde(skip_serializing_if = "Option::is_none")]
135 pub scroll: Option<Scroll>,
136}
137
138impl ClickOptions {
139 pub fn builder() -> ClickOptionsBuilder {
141 ClickOptionsBuilder::default()
142 }
143
144 pub(crate) fn to_json(&self) -> serde_json::Value {
146 serde_json::to_value(self).expect("ClickOptions serialization cannot fail")
147 }
148}
149
150#[derive(Debug, Clone, Default)]
154pub struct ClickOptionsBuilder {
155 button: Option<MouseButton>,
156 click_count: Option<u32>,
157 delay: Option<f64>,
158 force: Option<bool>,
159 modifiers: Option<Vec<KeyboardModifier>>,
160 no_wait_after: Option<bool>,
161 position: Option<Position>,
162 timeout: Option<f64>,
163 trial: Option<bool>,
164 scroll: Option<Scroll>,
165}
166
167impl ClickOptionsBuilder {
168 pub fn button(mut self, button: MouseButton) -> Self {
170 self.button = Some(button);
171 self
172 }
173
174 pub fn click_count(mut self, click_count: u32) -> Self {
176 self.click_count = Some(click_count);
177 self
178 }
179
180 pub fn delay(mut self, delay: f64) -> Self {
182 self.delay = Some(delay);
183 self
184 }
185
186 pub fn force(mut self, force: bool) -> Self {
188 self.force = Some(force);
189 self
190 }
191
192 pub fn modifiers(mut self, modifiers: Vec<KeyboardModifier>) -> Self {
194 self.modifiers = Some(modifiers);
195 self
196 }
197
198 pub fn no_wait_after(mut self, no_wait_after: bool) -> Self {
200 self.no_wait_after = Some(no_wait_after);
201 self
202 }
203
204 pub fn position(mut self, position: Position) -> Self {
206 self.position = Some(position);
207 self
208 }
209
210 pub fn timeout(mut self, timeout: f64) -> Self {
212 self.timeout = Some(timeout);
213 self
214 }
215
216 pub fn trial(mut self, trial: bool) -> Self {
218 self.trial = Some(trial);
219 self
220 }
221
222 pub fn scroll(mut self, scroll: Scroll) -> Self {
225 self.scroll = Some(scroll);
226 self
227 }
228
229 pub fn build(self) -> ClickOptions {
231 ClickOptions {
232 button: self.button,
233 click_count: self.click_count,
234 delay: self.delay,
235 force: self.force,
236 modifiers: self.modifiers,
237 no_wait_after: self.no_wait_after,
238 position: self.position,
239 timeout: self.timeout,
240 trial: self.trial,
241 scroll: self.scroll,
242 }
243 }
244}
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249
250 #[test]
251 fn test_mouse_button_serialization() {
252 assert_eq!(
253 serde_json::to_string(&MouseButton::Left).unwrap(),
254 "\"left\""
255 );
256 assert_eq!(
257 serde_json::to_string(&MouseButton::Right).unwrap(),
258 "\"right\""
259 );
260 assert_eq!(
261 serde_json::to_string(&MouseButton::Middle).unwrap(),
262 "\"middle\""
263 );
264 }
265
266 #[test]
267 fn test_keyboard_modifier_serialization() {
268 assert_eq!(
269 serde_json::to_string(&KeyboardModifier::Alt).unwrap(),
270 "\"Alt\""
271 );
272 assert_eq!(
273 serde_json::to_string(&KeyboardModifier::Control).unwrap(),
274 "\"Control\""
275 );
276 assert_eq!(
277 serde_json::to_string(&KeyboardModifier::Meta).unwrap(),
278 "\"Meta\""
279 );
280 assert_eq!(
281 serde_json::to_string(&KeyboardModifier::Shift).unwrap(),
282 "\"Shift\""
283 );
284 assert_eq!(
285 serde_json::to_string(&KeyboardModifier::ControlOrMeta).unwrap(),
286 "\"ControlOrMeta\""
287 );
288 }
289
290 #[test]
291 fn test_builder_button() {
292 let options = ClickOptions::builder().button(MouseButton::Right).build();
293
294 let json = options.to_json();
295 assert_eq!(json["button"], "right");
296 }
297
298 #[test]
299 fn test_builder_click_count() {
300 let options = ClickOptions::builder().click_count(2).build();
301
302 let json = options.to_json();
303 assert_eq!(json["clickCount"], 2);
304 }
305
306 #[test]
307 fn test_builder_delay() {
308 let options = ClickOptions::builder().delay(100.0).build();
309
310 let json = options.to_json();
311 assert_eq!(json["delay"], 100.0);
312 }
313
314 #[test]
315 fn test_builder_force() {
316 let options = ClickOptions::builder().force(true).build();
317
318 let json = options.to_json();
319 assert_eq!(json["force"], true);
320 }
321
322 #[test]
323 fn test_builder_modifiers() {
324 let options = ClickOptions::builder()
325 .modifiers(vec![KeyboardModifier::Shift, KeyboardModifier::Control])
326 .build();
327
328 let json = options.to_json();
329 assert_eq!(json["modifiers"], serde_json::json!(["Shift", "Control"]));
330 }
331
332 #[test]
333 fn test_builder_position() {
334 let position = Position { x: 10.0, y: 20.0 };
335 let options = ClickOptions::builder().position(position).build();
336
337 let json = options.to_json();
338 assert_eq!(json["position"]["x"], 10.0);
339 assert_eq!(json["position"]["y"], 20.0);
340 }
341
342 #[test]
343 fn test_builder_timeout() {
344 let options = ClickOptions::builder().timeout(5000.0).build();
345
346 let json = options.to_json();
347 assert_eq!(json["timeout"], 5000.0);
348 }
349
350 #[test]
351 fn test_builder_trial() {
352 let options = ClickOptions::builder().trial(true).build();
353
354 let json = options.to_json();
355 assert_eq!(json["trial"], true);
356 }
357
358 #[test]
359 fn test_builder_multiple_options() {
360 let options = ClickOptions::builder()
361 .button(MouseButton::Right)
362 .modifiers(vec![KeyboardModifier::Shift])
363 .position(Position { x: 5.0, y: 10.0 })
364 .force(true)
365 .timeout(3000.0)
366 .build();
367
368 let json = options.to_json();
369 assert_eq!(json["button"], "right");
370 assert_eq!(json["modifiers"], serde_json::json!(["Shift"]));
371 assert_eq!(json["position"]["x"], 5.0);
372 assert_eq!(json["position"]["y"], 10.0);
373 assert_eq!(json["force"], true);
374 assert_eq!(json["timeout"], 3000.0);
375 }
376}