1use serde::Serialize;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
17#[serde(rename_all = "lowercase")]
18#[non_exhaustive]
19pub enum MouseButton {
20 Left,
22 Right,
24 Middle,
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
38#[non_exhaustive]
39pub enum KeyboardModifier {
40 Alt,
42 Control,
44 Meta,
46 Shift,
48 ControlOrMeta,
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
64pub struct Position {
65 pub x: f64,
67 pub y: f64,
69}
70
71#[derive(Debug, Clone, Default)]
101#[non_exhaustive]
102pub struct ClickOptions {
103 pub button: Option<MouseButton>,
105 pub click_count: Option<u32>,
107 pub delay: Option<f64>,
109 pub force: Option<bool>,
111 pub modifiers: Option<Vec<KeyboardModifier>>,
113 pub no_wait_after: Option<bool>,
115 pub position: Option<Position>,
117 pub timeout: Option<f64>,
119 pub trial: Option<bool>,
121}
122
123impl ClickOptions {
124 pub fn builder() -> ClickOptionsBuilder {
126 ClickOptionsBuilder::default()
127 }
128
129 pub(crate) fn to_json(&self) -> serde_json::Value {
131 let mut json = serde_json::json!({});
132
133 if let Some(button) = &self.button {
134 json["button"] =
135 serde_json::to_value(button).expect("serialization of MouseButton cannot fail");
136 }
137
138 if let Some(click_count) = self.click_count {
139 json["clickCount"] = serde_json::json!(click_count);
140 }
141
142 if let Some(delay) = self.delay {
143 json["delay"] = serde_json::json!(delay);
144 }
145
146 if let Some(force) = self.force {
147 json["force"] = serde_json::json!(force);
148 }
149
150 if let Some(modifiers) = &self.modifiers {
151 json["modifiers"] =
152 serde_json::to_value(modifiers).expect("serialization of modifiers cannot fail");
153 }
154
155 if let Some(no_wait_after) = self.no_wait_after {
156 json["noWaitAfter"] = serde_json::json!(no_wait_after);
157 }
158
159 if let Some(position) = &self.position {
160 json["position"] =
161 serde_json::to_value(position).expect("serialization of position cannot fail");
162 }
163
164 if let Some(timeout) = self.timeout {
166 json["timeout"] = serde_json::json!(timeout);
167 } else {
168 json["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
169 }
170
171 if let Some(trial) = self.trial {
172 json["trial"] = serde_json::json!(trial);
173 }
174
175 json
176 }
177}
178
179#[derive(Debug, Clone, Default)]
183pub struct ClickOptionsBuilder {
184 button: Option<MouseButton>,
185 click_count: Option<u32>,
186 delay: Option<f64>,
187 force: Option<bool>,
188 modifiers: Option<Vec<KeyboardModifier>>,
189 no_wait_after: Option<bool>,
190 position: Option<Position>,
191 timeout: Option<f64>,
192 trial: Option<bool>,
193}
194
195impl ClickOptionsBuilder {
196 pub fn button(mut self, button: MouseButton) -> Self {
198 self.button = Some(button);
199 self
200 }
201
202 pub fn click_count(mut self, click_count: u32) -> Self {
204 self.click_count = Some(click_count);
205 self
206 }
207
208 pub fn delay(mut self, delay: f64) -> Self {
210 self.delay = Some(delay);
211 self
212 }
213
214 pub fn force(mut self, force: bool) -> Self {
216 self.force = Some(force);
217 self
218 }
219
220 pub fn modifiers(mut self, modifiers: Vec<KeyboardModifier>) -> Self {
222 self.modifiers = Some(modifiers);
223 self
224 }
225
226 pub fn no_wait_after(mut self, no_wait_after: bool) -> Self {
228 self.no_wait_after = Some(no_wait_after);
229 self
230 }
231
232 pub fn position(mut self, position: Position) -> Self {
234 self.position = Some(position);
235 self
236 }
237
238 pub fn timeout(mut self, timeout: f64) -> Self {
240 self.timeout = Some(timeout);
241 self
242 }
243
244 pub fn trial(mut self, trial: bool) -> Self {
246 self.trial = Some(trial);
247 self
248 }
249
250 pub fn build(self) -> ClickOptions {
252 ClickOptions {
253 button: self.button,
254 click_count: self.click_count,
255 delay: self.delay,
256 force: self.force,
257 modifiers: self.modifiers,
258 no_wait_after: self.no_wait_after,
259 position: self.position,
260 timeout: self.timeout,
261 trial: self.trial,
262 }
263 }
264}
265
266#[cfg(test)]
267mod tests {
268 use super::*;
269
270 #[test]
271 fn test_mouse_button_serialization() {
272 assert_eq!(
273 serde_json::to_string(&MouseButton::Left).unwrap(),
274 "\"left\""
275 );
276 assert_eq!(
277 serde_json::to_string(&MouseButton::Right).unwrap(),
278 "\"right\""
279 );
280 assert_eq!(
281 serde_json::to_string(&MouseButton::Middle).unwrap(),
282 "\"middle\""
283 );
284 }
285
286 #[test]
287 fn test_keyboard_modifier_serialization() {
288 assert_eq!(
289 serde_json::to_string(&KeyboardModifier::Alt).unwrap(),
290 "\"Alt\""
291 );
292 assert_eq!(
293 serde_json::to_string(&KeyboardModifier::Control).unwrap(),
294 "\"Control\""
295 );
296 assert_eq!(
297 serde_json::to_string(&KeyboardModifier::Meta).unwrap(),
298 "\"Meta\""
299 );
300 assert_eq!(
301 serde_json::to_string(&KeyboardModifier::Shift).unwrap(),
302 "\"Shift\""
303 );
304 assert_eq!(
305 serde_json::to_string(&KeyboardModifier::ControlOrMeta).unwrap(),
306 "\"ControlOrMeta\""
307 );
308 }
309
310 #[test]
311 fn test_builder_button() {
312 let options = ClickOptions::builder().button(MouseButton::Right).build();
313
314 let json = options.to_json();
315 assert_eq!(json["button"], "right");
316 }
317
318 #[test]
319 fn test_builder_click_count() {
320 let options = ClickOptions::builder().click_count(2).build();
321
322 let json = options.to_json();
323 assert_eq!(json["clickCount"], 2);
324 }
325
326 #[test]
327 fn test_builder_delay() {
328 let options = ClickOptions::builder().delay(100.0).build();
329
330 let json = options.to_json();
331 assert_eq!(json["delay"], 100.0);
332 }
333
334 #[test]
335 fn test_builder_force() {
336 let options = ClickOptions::builder().force(true).build();
337
338 let json = options.to_json();
339 assert_eq!(json["force"], true);
340 }
341
342 #[test]
343 fn test_builder_modifiers() {
344 let options = ClickOptions::builder()
345 .modifiers(vec![KeyboardModifier::Shift, KeyboardModifier::Control])
346 .build();
347
348 let json = options.to_json();
349 assert_eq!(json["modifiers"], serde_json::json!(["Shift", "Control"]));
350 }
351
352 #[test]
353 fn test_builder_position() {
354 let position = Position { x: 10.0, y: 20.0 };
355 let options = ClickOptions::builder().position(position).build();
356
357 let json = options.to_json();
358 assert_eq!(json["position"]["x"], 10.0);
359 assert_eq!(json["position"]["y"], 20.0);
360 }
361
362 #[test]
363 fn test_builder_timeout() {
364 let options = ClickOptions::builder().timeout(5000.0).build();
365
366 let json = options.to_json();
367 assert_eq!(json["timeout"], 5000.0);
368 }
369
370 #[test]
371 fn test_builder_trial() {
372 let options = ClickOptions::builder().trial(true).build();
373
374 let json = options.to_json();
375 assert_eq!(json["trial"], true);
376 }
377
378 #[test]
379 fn test_builder_multiple_options() {
380 let options = ClickOptions::builder()
381 .button(MouseButton::Right)
382 .modifiers(vec![KeyboardModifier::Shift])
383 .position(Position { x: 5.0, y: 10.0 })
384 .force(true)
385 .timeout(3000.0)
386 .build();
387
388 let json = options.to_json();
389 assert_eq!(json["button"], "right");
390 assert_eq!(json["modifiers"], serde_json::json!(["Shift"]));
391 assert_eq!(json["position"]["x"], 5.0);
392 assert_eq!(json["position"]["y"], 10.0);
393 assert_eq!(json["force"], true);
394 assert_eq!(json["timeout"], 3000.0);
395 }
396}