maa_framework/
controller.rs

1use std::{fmt::Display, ops::Deref};
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6    error::Error,
7    internal,
8    maa_bool, CallbackHandler, MaaResult, MaaStatus,
9};
10
11#[cfg(feature = "adb")]
12#[doc(cfg(feature = "adb"))]
13pub mod adb;
14#[cfg(feature = "dbg")]
15#[doc(cfg(feature = "dbg"))]
16pub mod dbg;
17#[cfg(feature = "win32")]
18#[doc(cfg(feature = "win32"))]
19pub mod win32;
20
21#[cfg(feature = "adb")]
22use self::adb::MaaAdbControllerType;
23
24#[cfg(feature = "custom_controller")]
25use crate::custom::custom_controller::MaaCustomController;
26
27#[cfg(feature = "dbg")]
28use self::dbg::MaaDbgControllerType;
29
30#[cfg(feature = "win32")]
31use self::win32::{MaaWin32ControllerType, MaaWin32Hwnd};
32
33pub use internal::MaaCtrlId;
34
35/// A handle to a controller instance
36///
37/// # Note
38///
39/// See [MaaInstance](crate::instance::MaaInstance) for lifetime hints.
40pub struct MaaControllerInstance<T> {
41    pub(crate) handle: internal::MaaControllerHandle,
42    _phantom: std::marker::PhantomData<T>,
43}
44
45impl<T> Deref for MaaControllerInstance<T> {
46    type Target = internal::MaaControllerHandle;
47
48    fn deref(&self) -> &Self::Target {
49        &self.handle
50    }
51}
52
53unsafe impl<T> Send for MaaControllerInstance<T> {}
54unsafe impl<T> Sync for MaaControllerInstance<T> {}
55
56impl<T> MaaControllerInstance<T> {
57    /// Create a new AdbController
58    ///
59    /// # Notes
60    /// This directly calls MaaAdbControllerCreateV2 since MaaAdbControllerCreate is deprecated
61    #[cfg(feature = "adb")]
62    #[doc(cfg(feature = "adb"))]
63    pub fn new_adb(
64        adb_path: &str,
65        address: &str,
66        controller_type: MaaAdbControllerType,
67        config: &str,
68        agent_path: &str,
69        handler: Option<T>,
70    ) -> Self
71    where
72        T: CallbackHandler,
73    {
74        let adb_path = internal::to_cstring(adb_path);
75        let address = internal::to_cstring(address);
76        let config = internal::to_cstring(config);
77        let agent_path = internal::to_cstring(agent_path);
78
79        let handle = unsafe {
80            match handler {
81                Some(handler) => {
82                    let handler = Box::new(handler);
83                    let handler = Box::into_raw(handler);
84
85                    internal::MaaAdbControllerCreateV2(
86                        adb_path,
87                        address,
88                        controller_type.into(),
89                        config,
90                        agent_path,
91                        Some(internal::callback_handler::<T>),
92                        handler.cast(),
93                    )
94                }
95                None => internal::MaaAdbControllerCreateV2(
96                    adb_path,
97                    address,
98                    controller_type.into(),
99                    config,
100                    agent_path,
101                    None,
102                    std::ptr::null_mut(),
103                ),
104            }
105        };
106
107        MaaControllerInstance {
108            handle,
109            _phantom: std::marker::PhantomData,
110        }
111    }
112
113    #[cfg(feature = "win32")]
114    #[doc(cfg(feature = "win32"))]
115    pub fn new_win32(
116        hwnd: MaaWin32Hwnd,
117        controller_type: MaaWin32ControllerType,
118        handler: Option<T>,
119    ) -> Self
120    where
121        T: CallbackHandler,
122    {
123        let handle = unsafe {
124            match handler {
125                Some(handler) => {
126                    let handler = Box::new(handler);
127                    let handler = Box::into_raw(handler);
128
129                    internal::MaaWin32ControllerCreate(
130                        *hwnd,
131                        controller_type.into(),
132                        Some(internal::callback_handler::<T>),
133                        handler.cast(),
134                    )
135                }
136                None => internal::MaaWin32ControllerCreate(
137                    *hwnd,
138                    controller_type.into(),
139                    None,
140                    std::ptr::null_mut(),
141                ),
142            }
143        };
144
145        MaaControllerInstance {
146            handle,
147            _phantom: std::marker::PhantomData,
148        }
149    }
150
151    #[cfg(feature = "dbg")]
152    #[doc(cfg(feature = "dbg"))]
153    pub fn new_dbg(
154        read_path: &str,
155        write_path: &str,
156        controller_type: MaaDbgControllerType,
157        config: &str,
158        handler: Option<T>,
159    ) -> Self
160    where
161        T: CallbackHandler,
162    {
163        let read_path = internal::to_cstring(read_path);
164        let write_path = internal::to_cstring(write_path);
165        let config = internal::to_cstring(config);
166
167        let handle = unsafe {
168            match handler {
169                Some(handler) => {
170                    let handler = Box::new(handler);
171                    let handler = Box::into_raw(handler);
172
173                    internal::MaaDbgControllerCreate(
174                        read_path,
175                        write_path,
176                        controller_type.into(),
177                        config,
178                        Some(internal::callback_handler::<T>),
179                        handler.cast(),
180                    )
181                }
182                None => internal::MaaDbgControllerCreate(
183                    read_path,
184                    write_path,
185                    controller_type.into(),
186                    config,
187                    None,
188                    std::ptr::null_mut(),
189                ),
190            }
191        };
192
193        MaaControllerInstance {
194            handle,
195            _phantom: std::marker::PhantomData,
196        }
197    }
198
199    #[cfg(feature = "custom_controller")]
200    #[doc(cfg(feature = "custom_controller"))]
201    pub fn new_custom<C>(controller: C, handler: Option<T>) -> Self
202    where
203        T: CallbackHandler,
204        C: MaaCustomController,
205    {
206        use crate::custom::custom_controller;
207
208        let controller_api = internal::MaaCustomControllerAPI {
209            connect: Some(custom_controller::custom_controller_connect::<C>),
210            request_uuid: Some(custom_controller::custom_controller_request_uuid::<C>),
211            request_resolution: Some(custom_controller::custom_controller_request_resolution::<C>),
212            start_app: Some(custom_controller::custom_controller_start_app::<C>),
213            stop_app: Some(custom_controller::custom_controller_stop_app::<C>),
214            screencap: Some(custom_controller::custom_controller_screencap::<C>),
215            click: Some(custom_controller::custom_controller_click::<C>),
216            swipe: Some(custom_controller::custom_controller_swipe::<C>),
217            touch_down: Some(custom_controller::custom_controller_touch_down::<C>),
218            touch_move: Some(custom_controller::custom_controller_touch_move::<C>),
219            touch_up: Some(custom_controller::custom_controller_touch_up::<C>),
220            press_key: Some(custom_controller::custom_controller_press_key::<C>),
221            input_text: Some(custom_controller::custom_controller_input_text::<C>),
222        };
223
224        let controller_api = Box::new(controller_api);
225        let controller_api = Box::into_raw(controller_api);
226
227        let handle = unsafe {
228            match handler {
229                Some(handler) => {
230                    let handler = Box::new(handler);
231                    let handler = Box::into_raw(handler);
232
233                    internal::MaaCustomControllerCreate(
234                        controller_api,
235                        &controller as *const C as *mut C as *mut std::ffi::c_void,
236                        Some(internal::callback_handler::<T>),
237                        handler.cast(),
238                    )
239                }
240                None => internal::MaaCustomControllerCreate(
241                    controller_api,
242                    &controller as *const C as *mut C as *mut std::ffi::c_void,
243                    None,
244                    std::ptr::null_mut(),
245                ),
246            }
247        };
248
249        MaaControllerInstance {
250            handle,
251            _phantom: std::marker::PhantomData,
252        }
253    }
254
255    pub(crate) fn new_from_handle(handle: internal::MaaControllerHandle) -> Self {
256        MaaControllerInstance {
257            handle,
258            _phantom: std::marker::PhantomData,
259        }
260    }
261
262    pub fn set_controller_option(&self, option: MaaControllerOption) -> MaaResult<()> {
263        let key = option.get_inner_key();
264
265        let ret = unsafe {
266            match option {
267                MaaControllerOption::DefaultAppPackage(ref package) => {
268                    let val_size = package.len() as u64;
269                    let package = package.as_ptr() as *mut std::os::raw::c_void;
270                    let package = package as *mut std::os::raw::c_void;
271                    internal::MaaControllerSetOption(self.handle, key, package, val_size)
272                }
273                MaaControllerOption::DefaultAppPackageEntry(ref package) => {
274                    let val_size = package.len() as u64;
275                    let package = package.as_ptr() as *mut std::os::raw::c_void;
276                    let package = package as *mut std::os::raw::c_void;
277                    internal::MaaControllerSetOption(self.handle, key, package, val_size)
278                }
279                MaaControllerOption::Recording(ref package) => {
280                    let val_size = std::mem::size_of::<bool>() as u64;
281                    let package = package as *const bool as *mut std::os::raw::c_void;
282                    internal::MaaControllerSetOption(self.handle, key, package, val_size)
283                }
284                MaaControllerOption::ScreenshotTargetLongSide(ref package) => {
285                    let val_size = std::mem::size_of::<i32>() as u64;
286                    let package = package as *const i32 as *mut std::os::raw::c_void;
287                    internal::MaaControllerSetOption(self.handle, key, package, val_size)
288                }
289                MaaControllerOption::ScreenshotTargetShortSide(ref package) => {
290                    let val_size = std::mem::size_of::<i32>() as u64;
291                    let package = package as *const i32 as *mut std::os::raw::c_void;
292                    internal::MaaControllerSetOption(self.handle, key, package, val_size)
293                }
294                _ => internal::MaaControllerSetOption(self.handle, key, std::ptr::null_mut(), 0),
295            }
296        };
297
298        if !maa_bool!(ret) {
299            Err(Error::MaaControllerSetOptionError(option))
300        } else {
301            Ok(())
302        }
303    }
304
305    pub fn post_connect(&self) -> MaaCtrlId {
306        unsafe { internal::MaaControllerPostConnection(self.handle) }
307    }
308
309    pub fn post_click(&self, x: i32, y: i32) -> MaaCtrlId {
310        unsafe { internal::MaaControllerPostClick(self.handle, x, y) }
311    }
312
313    pub fn post_swipe(&self, x1: i32, y1: i32, x2: i32, y2: i32, duration: i32) -> MaaCtrlId {
314        unsafe { internal::MaaControllerPostSwipe(self.handle, x1, y1, x2, y2, duration) }
315    }
316
317    pub fn post_press_key(&self, keycode: i32) -> MaaCtrlId {
318        unsafe { internal::MaaControllerPostPressKey(self.handle, keycode) }
319    }
320
321    pub fn post_input_text(&self, text: &str) -> MaaCtrlId {
322        let text = internal::to_cstring(text);
323        unsafe { internal::MaaControllerPostInputText(self.handle, text) }
324    }
325
326    pub fn post_touch_down(&self, contact: i32, x: i32, y: i32, pressure: i32) -> MaaCtrlId {
327        unsafe { internal::MaaControllerPostTouchDown(self.handle, contact, x, y, pressure) }
328    }
329
330    pub fn post_touch_move(&self, contact: i32, x: i32, y: i32, pressure: i32) -> MaaCtrlId {
331        unsafe { internal::MaaControllerPostTouchMove(self.handle, contact, x, y, pressure) }
332    }
333
334    pub fn post_touch_up(&self, contact: i32) -> MaaCtrlId {
335        unsafe { internal::MaaControllerPostTouchUp(self.handle, contact) }
336    }
337
338    pub fn post_screencap(&self) -> MaaCtrlId {
339        unsafe { internal::MaaControllerPostScreencap(self.handle) }
340    }
341
342    pub fn status(&self, id: MaaCtrlId) -> MaaResult<MaaStatus> {
343        let status = unsafe { internal::MaaControllerStatus(self.handle, id) };
344
345        MaaStatus::try_from(status)
346    }
347
348    pub fn wait(&self, id: MaaCtrlId) -> MaaResult<MaaStatus> {
349        let status = unsafe { internal::MaaControllerWait(self.handle, id) };
350
351        MaaStatus::try_from(status)
352    }
353
354    pub fn connected(&self) -> bool {
355        unsafe { maa_bool!(internal::MaaControllerConnected(self.handle)) }
356    }
357}
358
359impl<T> Drop for MaaControllerInstance<T> {
360    fn drop(&mut self) {
361        unsafe {
362            internal::MaaControllerDestroy(self.handle);
363        }
364    }
365}
366
367#[derive(Debug, Serialize, Deserialize)]
368pub enum MaaControllerOption {
369    Invalid,
370    ScreenshotTargetLongSide(i32),
371    ScreenshotTargetShortSide(i32),
372    DefaultAppPackageEntry(String),
373    DefaultAppPackage(String),
374    Recording(bool),
375}
376
377impl Display for MaaControllerOption {
378    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
379        match self {
380            MaaControllerOption::Invalid => write!(f, "Invalid"),
381            MaaControllerOption::ScreenshotTargetLongSide(val) => {
382                write!(f, "ScreenshotTargetLongSide: {}", val)
383            }
384            MaaControllerOption::ScreenshotTargetShortSide(val) => {
385                write!(f, "ScreenshotTargetShortSide: {}", val)
386            }
387            MaaControllerOption::DefaultAppPackageEntry(val) => {
388                write!(f, "DefaultAppPackageEntry: {}", val)
389            }
390            MaaControllerOption::DefaultAppPackage(val) => write!(f, "DefaultAppPackage: {}", val),
391            MaaControllerOption::Recording(val) => write!(f, "Recording: {}", val),
392        }
393    }
394}
395
396impl MaaControllerOption {
397    fn get_inner_key(&self) -> internal::MaaCtrlOption {
398        match self {
399            MaaControllerOption::Invalid => internal::MaaCtrlOptionEnum_MaaCtrlOption_Invalid,
400            MaaControllerOption::ScreenshotTargetLongSide(_) => {
401                internal::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotTargetLongSide
402            }
403            MaaControllerOption::ScreenshotTargetShortSide(_) => {
404                internal::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotTargetShortSide
405            }
406            MaaControllerOption::DefaultAppPackageEntry(_) => {
407                internal::MaaCtrlOptionEnum_MaaCtrlOption_DefaultAppPackageEntry
408            }
409            MaaControllerOption::DefaultAppPackage(_) => {
410                internal::MaaCtrlOptionEnum_MaaCtrlOption_DefaultAppPackage
411            }
412            MaaControllerOption::Recording(_) => {
413                internal::MaaCtrlOptionEnum_MaaCtrlOption_Recording
414            }
415        }
416    }
417}