rustenium/input/cdp/
touchscreen.rs1use std::sync::Arc;
2use tokio::sync::Mutex;
3
4use rustenium_cdp_definitions::browser_protocol::input::commands::{
5 DispatchTouchEvent, DispatchTouchEventMethod, DispatchTouchEventParams, DispatchTouchEventType,
6};
7use rustenium_cdp_definitions::browser_protocol::input::types::TouchPoint;
8use rustenium_core::error::CdpCommandResultError;
9use rustenium_core::session::CdpSession;
10use rustenium_core::WebsocketConnectionTransport;
11use tokio::sync::Mutex as TokioMutex;
12
13use crate::error::cdp::InputError;
14use crate::input::mouse::Point;
15
16pub struct TouchHandle {
18 session: Arc<TokioMutex<CdpSession<WebsocketConnectionTransport>>>,
19 touchscreen: Arc<Touchscreen>,
20 id: usize,
21 position: Arc<Mutex<Point>>,
22}
23
24impl TouchHandle {
25 fn new(
26 session: Arc<TokioMutex<CdpSession<WebsocketConnectionTransport>>>,
27 touchscreen: Arc<Touchscreen>,
28 id: usize,
29 x: f64,
30 y: f64,
31 ) -> Self {
32 Self {
33 session,
34 touchscreen,
35 id,
36 position: Arc::new(Mutex::new(Point { x: x.round(), y: y.round() })),
37 }
38 }
39
40 fn make_point(x: f64, y: f64, id: usize) -> TouchPoint {
41 let mut p = TouchPoint::new(x.round(), y.round());
42 p.id = Some(id as f64);
43 p.radius_x = Some(1.0);
44 p.radius_y = Some(1.0);
45 p.force = Some(1.0);
46 p
47 }
48
49 pub async fn move_to(&self, x: f64, y: f64) -> Result<(), InputError> {
51 let new_pos = Point { x: x.round(), y: y.round() };
52 let cmd = DispatchTouchEvent {
53 method: DispatchTouchEventMethod::DispatchTouchEvent,
54 params: DispatchTouchEventParams::new(
55 DispatchTouchEventType::TouchMove,
56 vec![Self::make_point(new_pos.x, new_pos.y, self.id)],
57 ),
58 };
59 self.session.lock().await.send(cmd).await
60 .map_err(|e| InputError::CommandError(CdpCommandResultError::SessionSendError(e)))?;
61 *self.position.lock().await = new_pos;
62 Ok(())
63 }
64
65 pub async fn end(&self) -> Result<(), InputError> {
67 let cmd = DispatchTouchEvent {
68 method: DispatchTouchEventMethod::DispatchTouchEvent,
69 params: DispatchTouchEventParams::new(DispatchTouchEventType::TouchEnd, vec![]),
70 };
71 self.session.lock().await.send(cmd).await
72 .map_err(|e| InputError::CommandError(CdpCommandResultError::SessionSendError(e)))?;
73 self.touchscreen.remove_handle(self.id).await;
74 Ok(())
75 }
76}
77
78#[derive(Clone)]
80pub struct Touchscreen {
81 session: Arc<TokioMutex<CdpSession<WebsocketConnectionTransport>>>,
82 touches: Arc<Mutex<Vec<usize>>>,
83 id_counter: Arc<Mutex<usize>>,
84}
85
86impl Touchscreen {
87 pub fn new(session: Arc<TokioMutex<CdpSession<WebsocketConnectionTransport>>>) -> Self {
88 Self {
89 session,
90 touches: Arc::new(Mutex::new(Vec::new())),
91 id_counter: Arc::new(Mutex::new(0)),
92 }
93 }
94
95 pub async fn touch_start(self: &Arc<Self>, x: f64, y: f64) -> Result<TouchHandle, InputError> {
97 let id = {
98 let mut counter = self.id_counter.lock().await;
99 let id = *counter;
100 *counter += 1;
101 id
102 };
103
104 let mut p = TouchPoint::new(x.round(), y.round());
105 p.id = Some(id as f64);
106 p.radius_x = Some(1.0);
107 p.radius_y = Some(1.0);
108 p.force = Some(1.0);
109
110 let cmd = DispatchTouchEvent {
111 method: DispatchTouchEventMethod::DispatchTouchEvent,
112 params: DispatchTouchEventParams::new(DispatchTouchEventType::TouchStart, vec![p]),
113 };
114 self.session.lock().await.send(cmd).await
115 .map_err(|e| InputError::CommandError(CdpCommandResultError::SessionSendError(e)))?;
116
117 self.touches.lock().await.push(id);
118
119 Ok(TouchHandle::new(self.session.clone(), self.clone(), id, x, y))
120 }
121
122 pub(crate) async fn remove_handle(&self, id: usize) {
123 self.touches.lock().await.retain(|&t| t != id);
124 }
125}