1use crate::{MaaError, MaaResult, common, sys};
4use serde::Serialize;
5use std::collections::HashMap;
6use std::ffi::CString;
7use std::os::raw::c_void;
8#[cfg(feature = "dynamic")]
9use std::panic::AssertUnwindSafe;
10use std::ptr::NonNull;
11use std::sync::{Arc, Mutex};
12
13#[derive(Clone)]
23pub struct Controller {
24 inner: Arc<ControllerInner>,
25}
26
27struct ControllerInner {
28 handle: NonNull<sys::MaaController>,
29 owns_handle: bool,
30 _retained_handles: Vec<Arc<ControllerInner>>,
31 callbacks: Mutex<HashMap<sys::MaaSinkId, usize>>,
32 event_sinks: Mutex<HashMap<sys::MaaSinkId, usize>>,
33}
34
35unsafe impl Send for ControllerInner {}
36unsafe impl Sync for ControllerInner {}
37
38unsafe impl Send for Controller {}
40unsafe impl Sync for Controller {}
41
42impl std::fmt::Debug for Controller {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 f.debug_struct("Controller")
45 .field("handle", &self.inner.handle)
46 .finish()
47 }
48}
49
50impl Controller {
51 #[cfg(feature = "adb")]
59 pub fn new_adb(
60 adb_path: &str,
61 address: &str,
62 config: &str,
63 agent_path: &str,
64 ) -> MaaResult<Self> {
65 Self::create_adb(
66 adb_path,
67 address,
68 sys::MaaAdbScreencapMethod_Default as sys::MaaAdbScreencapMethod,
69 sys::MaaAdbInputMethod_Default as sys::MaaAdbInputMethod,
70 config,
71 agent_path,
72 )
73 }
74
75 #[cfg(feature = "adb")]
77 fn resolve_agent_path(agent_path: &str) -> MaaResult<String> {
78 if !agent_path.is_empty() {
79 return Ok(agent_path.to_string());
80 }
81 let cur = std::env::current_dir().map_err(|e| {
82 MaaError::InvalidArgument(format!("agent_path empty and current_dir failed: {}", e))
83 })?;
84 let s = cur.to_str().ok_or_else(|| {
85 MaaError::InvalidArgument(
86 "agent_path empty and current directory is not valid UTF-8".to_string(),
87 )
88 })?;
89 Ok(s.to_string())
90 }
91
92 #[cfg(feature = "adb")]
93 pub(crate) fn create_adb(
94 adb_path: &str,
95 address: &str,
96 screencap_method: sys::MaaAdbScreencapMethod,
97 input_method: sys::MaaAdbInputMethod,
98 config: &str,
99 agent_path: &str,
100 ) -> MaaResult<Self> {
101 let path = Self::resolve_agent_path(agent_path)?;
102 let c_adb = CString::new(adb_path)?;
103 let c_addr = CString::new(address)?;
104 let c_cfg = CString::new(config)?;
105 let c_agent = CString::new(path.as_str())?;
106
107 let handle = unsafe {
108 sys::MaaAdbControllerCreate(
109 c_adb.as_ptr(),
110 c_addr.as_ptr(),
111 screencap_method,
112 input_method,
113 c_cfg.as_ptr(),
114 c_agent.as_ptr(),
115 )
116 };
117
118 if let Some(ptr) = NonNull::new(handle) {
119 Ok(Self::new_owned(ptr))
120 } else {
121 Err(MaaError::FrameworkError(-1))
122 }
123 }
124
125 #[cfg(feature = "win32")]
127 pub fn new_win32(
128 hwnd: *mut c_void,
129 screencap_method: sys::MaaWin32ScreencapMethod,
130 mouse_method: sys::MaaWin32InputMethod,
131 keyboard_method: sys::MaaWin32InputMethod,
132 ) -> MaaResult<Self> {
133 let handle = unsafe {
134 sys::MaaWin32ControllerCreate(hwnd, screencap_method, mouse_method, keyboard_method)
135 };
136
137 Self::from_handle(handle)
138 }
139
140 pub fn new_macos(
147 window_id: u32,
148 screencap_method: sys::MaaMacOSScreencapMethod,
149 input_method: sys::MaaMacOSInputMethod,
150 ) -> MaaResult<Self> {
151 let handle =
152 unsafe { sys::MaaMacOSControllerCreate(window_id, screencap_method, input_method) };
153
154 Self::from_handle(handle)
155 }
156
157 pub fn new_android_native<T: Serialize>(config: &T) -> MaaResult<Self> {
164 let config_json = serde_json::to_string(config).map_err(|e| {
165 MaaError::InvalidConfig(format!(
166 "Failed to serialize Android native controller config: {}",
167 e
168 ))
169 })?;
170 let c_config = CString::new(config_json)?;
171
172 #[cfg(feature = "dynamic")]
173 let handle = std::panic::catch_unwind(AssertUnwindSafe(|| unsafe {
174 sys::MaaAndroidNativeControllerCreate(c_config.as_ptr())
175 }))
176 .map_err(|_| {
177 MaaError::InvalidArgument(
178 "Android native controller is not available in this MaaFramework build".to_string(),
179 )
180 })?;
181
182 #[cfg(not(feature = "dynamic"))]
183 let handle = unsafe { sys::MaaAndroidNativeControllerCreate(c_config.as_ptr()) };
184
185 Self::from_handle(handle)
186 }
187
188 pub fn new_playcover(address: &str, uuid: &str) -> MaaResult<Self> {
191 let c_addr = CString::new(address)?;
192 let c_uuid = CString::new(uuid)?;
193 let handle = unsafe { sys::MaaPlayCoverControllerCreate(c_addr.as_ptr(), c_uuid.as_ptr()) };
194
195 Self::from_handle(handle)
196 }
197
198 pub fn new_wlroots(wlr_socket_path: &str) -> MaaResult<Self> {
203 let c_path = CString::new(wlr_socket_path)?;
204 let handle = unsafe { sys::MaaWlRootsControllerCreate(c_path.as_ptr()) };
205
206 Self::from_handle(handle)
207 }
208
209 #[cfg(feature = "custom")]
211 pub fn new_custom<T: crate::custom_controller::CustomControllerCallback + 'static>(
212 callback: T,
213 ) -> MaaResult<Self> {
214 let boxed: Box<Box<dyn crate::custom_controller::CustomControllerCallback>> =
215 Box::new(Box::new(callback));
216 let cb_ptr = Box::into_raw(boxed) as *mut c_void;
217 let callbacks = crate::custom_controller::get_callbacks();
218 let handle =
219 unsafe { sys::MaaCustomControllerCreate(callbacks as *const _ as *mut _, cb_ptr) };
220
221 NonNull::new(handle).map(Self::new_owned).ok_or_else(|| {
222 unsafe {
223 let _ = Box::from_raw(
224 cb_ptr as *mut Box<dyn crate::custom_controller::CustomControllerCallback>,
225 );
226 }
227 MaaError::FrameworkError(-1)
228 })
229 }
230
231 fn from_handle(handle: *mut sys::MaaController) -> MaaResult<Self> {
233 if let Some(ptr) = NonNull::new(handle) {
234 Ok(Self::new_owned(ptr))
235 } else {
236 Err(MaaError::FrameworkError(-1))
237 }
238 }
239
240 fn new_owned(handle: NonNull<sys::MaaController>) -> Self {
241 Self::new_with_retained(handle, Vec::new())
242 }
243
244 fn new_with_retained(
245 handle: NonNull<sys::MaaController>,
246 retained_handles: Vec<Arc<ControllerInner>>,
247 ) -> Self {
248 Self {
249 inner: Arc::new(ControllerInner {
250 handle,
251 owns_handle: true,
252 _retained_handles: retained_handles,
253 callbacks: Mutex::new(HashMap::new()),
254 event_sinks: Mutex::new(HashMap::new()),
255 }),
256 }
257 }
258
259 pub fn post_click(&self, x: i32, y: i32) -> MaaResult<common::MaaId> {
261 let id = unsafe { sys::MaaControllerPostClick(self.inner.handle.as_ptr(), x, y) };
262 Ok(id)
263 }
264
265 pub fn post_screencap(&self) -> MaaResult<common::MaaId> {
267 let id = unsafe { sys::MaaControllerPostScreencap(self.inner.handle.as_ptr()) };
268 Ok(id)
269 }
270
271 pub fn post_click_v2(
278 &self,
279 x: i32,
280 y: i32,
281 contact: i32,
282 pressure: i32,
283 ) -> MaaResult<common::MaaId> {
284 let id = unsafe {
285 sys::MaaControllerPostClickV2(self.inner.handle.as_ptr(), x, y, contact, pressure)
286 };
287 Ok(id)
288 }
289
290 pub fn post_swipe(
297 &self,
298 x1: i32,
299 y1: i32,
300 x2: i32,
301 y2: i32,
302 duration: i32,
303 ) -> MaaResult<common::MaaId> {
304 let id = unsafe {
305 sys::MaaControllerPostSwipe(self.inner.handle.as_ptr(), x1, y1, x2, y2, duration)
306 };
307 Ok(id)
308 }
309
310 pub fn post_click_key(&self, keycode: i32) -> MaaResult<common::MaaId> {
315 let id = unsafe { sys::MaaControllerPostClickKey(self.inner.handle.as_ptr(), keycode) };
316 Ok(id)
317 }
318
319 #[deprecated(note = "Use post_click_key instead")]
321 pub fn post_press(&self, keycode: i32) -> MaaResult<common::MaaId> {
322 self.post_click_key(keycode)
323 }
324
325 pub fn post_input_text(&self, text: &str) -> MaaResult<common::MaaId> {
330 let c_text = CString::new(text)?;
331 let id =
332 unsafe { sys::MaaControllerPostInputText(self.inner.handle.as_ptr(), c_text.as_ptr()) };
333 Ok(id)
334 }
335
336 pub fn post_shell(&self, cmd: &str, timeout: i64) -> MaaResult<common::MaaId> {
342 let c_cmd = CString::new(cmd)?;
343 let id = unsafe {
344 sys::MaaControllerPostShell(self.inner.handle.as_ptr(), c_cmd.as_ptr(), timeout)
345 };
346 Ok(id)
347 }
348
349 pub fn post_touch_down(
356 &self,
357 contact: i32,
358 x: i32,
359 y: i32,
360 pressure: i32,
361 ) -> MaaResult<common::MaaId> {
362 let id = unsafe {
363 sys::MaaControllerPostTouchDown(self.inner.handle.as_ptr(), contact, x, y, pressure)
364 };
365 Ok(id)
366 }
367
368 pub fn post_touch_move(
375 &self,
376 contact: i32,
377 x: i32,
378 y: i32,
379 pressure: i32,
380 ) -> MaaResult<common::MaaId> {
381 let id = unsafe {
382 sys::MaaControllerPostTouchMove(self.inner.handle.as_ptr(), contact, x, y, pressure)
383 };
384 Ok(id)
385 }
386
387 pub fn post_touch_up(&self, contact: i32) -> MaaResult<common::MaaId> {
392 let id = unsafe { sys::MaaControllerPostTouchUp(self.inner.handle.as_ptr(), contact) };
393 Ok(id)
394 }
395
396 pub fn post_relative_move(&self, dx: i32, dy: i32) -> MaaResult<common::MaaId> {
402 let id = unsafe { sys::MaaControllerPostRelativeMove(self.inner.handle.as_ptr(), dx, dy) };
403 Ok(id)
404 }
405
406 #[inline]
408 pub fn raw(&self) -> *mut sys::MaaController {
409 self.inner.handle.as_ptr()
410 }
411
412 pub fn post_connection(&self) -> MaaResult<common::MaaId> {
418 let id = unsafe { sys::MaaControllerPostConnection(self.inner.handle.as_ptr()) };
419 Ok(id)
420 }
421
422 pub fn connected(&self) -> bool {
424 unsafe { sys::MaaControllerConnected(self.inner.handle.as_ptr()) != 0 }
425 }
426
427 pub fn uuid(&self) -> MaaResult<String> {
429 let buffer = crate::buffer::MaaStringBuffer::new()?;
430 let ret = unsafe { sys::MaaControllerGetUuid(self.inner.handle.as_ptr(), buffer.as_ptr()) };
431 if ret != 0 {
432 Ok(buffer.to_string())
433 } else {
434 Err(MaaError::FrameworkError(0))
435 }
436 }
437
438 pub fn info(&self) -> MaaResult<serde_json::Value> {
443 let buffer = crate::buffer::MaaStringBuffer::new()?;
444 let ret = unsafe { sys::MaaControllerGetInfo(self.inner.handle.as_ptr(), buffer.as_ptr()) };
445 if ret != 0 {
446 serde_json::from_str(&buffer.to_string()).map_err(|e| {
447 MaaError::InvalidArgument(format!("Failed to parse controller info: {}", e))
448 })
449 } else {
450 Err(MaaError::FrameworkError(0))
451 }
452 }
453
454 pub fn resolution(&self) -> MaaResult<(i32, i32)> {
456 let mut width: i32 = 0;
457 let mut height: i32 = 0;
458 let ret = unsafe {
459 sys::MaaControllerGetResolution(self.inner.handle.as_ptr(), &mut width, &mut height)
460 };
461 if ret != 0 {
462 Ok((width, height))
463 } else {
464 Err(MaaError::FrameworkError(0))
465 }
466 }
467
468 pub fn post_swipe_v2(
479 &self,
480 x1: i32,
481 y1: i32,
482 x2: i32,
483 y2: i32,
484 duration: i32,
485 contact: i32,
486 pressure: i32,
487 ) -> MaaResult<common::MaaId> {
488 let id = unsafe {
489 sys::MaaControllerPostSwipeV2(
490 self.inner.handle.as_ptr(),
491 x1,
492 y1,
493 x2,
494 y2,
495 duration,
496 contact,
497 pressure,
498 )
499 };
500 Ok(id)
501 }
502
503 pub fn post_key_down(&self, keycode: i32) -> MaaResult<common::MaaId> {
507 let id = unsafe { sys::MaaControllerPostKeyDown(self.inner.handle.as_ptr(), keycode) };
508 Ok(id)
509 }
510
511 pub fn post_key_up(&self, keycode: i32) -> MaaResult<common::MaaId> {
513 let id = unsafe { sys::MaaControllerPostKeyUp(self.inner.handle.as_ptr(), keycode) };
514 Ok(id)
515 }
516
517 pub fn post_start_app(&self, intent: &str) -> MaaResult<common::MaaId> {
524 let c_intent = CString::new(intent)?;
525 let id = unsafe {
526 sys::MaaControllerPostStartApp(self.inner.handle.as_ptr(), c_intent.as_ptr())
527 };
528 Ok(id)
529 }
530
531 pub fn post_stop_app(&self, intent: &str) -> MaaResult<common::MaaId> {
536 let c_intent = CString::new(intent)?;
537 let id =
538 unsafe { sys::MaaControllerPostStopApp(self.inner.handle.as_ptr(), c_intent.as_ptr()) };
539 Ok(id)
540 }
541
542 pub fn post_scroll(&self, dx: i32, dy: i32) -> MaaResult<common::MaaId> {
550 let id = unsafe { sys::MaaControllerPostScroll(self.inner.handle.as_ptr(), dx, dy) };
551 Ok(id)
552 }
553
554 pub fn post_inactive(&self) -> MaaResult<common::MaaId> {
561 let id = unsafe { sys::MaaControllerPostInactive(self.inner.handle.as_ptr()) };
562 Ok(id)
563 }
564
565 pub fn cached_image(&self) -> MaaResult<crate::buffer::MaaImageBuffer> {
569 let buffer = crate::buffer::MaaImageBuffer::new()?;
570 let ret =
571 unsafe { sys::MaaControllerCachedImage(self.inner.handle.as_ptr(), buffer.as_ptr()) };
572 if ret != 0 {
573 Ok(buffer)
574 } else {
575 Err(MaaError::FrameworkError(0))
576 }
577 }
578
579 pub fn shell_output(&self) -> MaaResult<String> {
583 let buffer = crate::buffer::MaaStringBuffer::new()?;
584 let ret = unsafe {
585 sys::MaaControllerGetShellOutput(self.inner.handle.as_ptr(), buffer.as_ptr())
586 };
587 if ret != 0 {
588 Ok(buffer.to_string())
589 } else {
590 Err(MaaError::FrameworkError(0))
591 }
592 }
593
594 pub fn status(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
598 let s = unsafe { sys::MaaControllerStatus(self.inner.handle.as_ptr(), ctrl_id) };
599 common::MaaStatus(s)
600 }
601
602 pub fn wait(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
604 let s = unsafe { sys::MaaControllerWait(self.inner.handle.as_ptr(), ctrl_id) };
605 common::MaaStatus(s)
606 }
607
608 pub fn set_screenshot_target_long_side(&self, long_side: i32) -> MaaResult<()> {
612 let mut val = long_side;
613 let ret = unsafe {
614 sys::MaaControllerSetOption(
615 self.inner.handle.as_ptr(),
616 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotTargetLongSide as i32,
617 &mut val as *mut _ as *mut c_void,
618 std::mem::size_of::<i32>() as u64,
619 )
620 };
621 common::check_bool(ret)
622 }
623
624 pub fn set_screenshot_target_short_side(&self, short_side: i32) -> MaaResult<()> {
626 let mut val = short_side;
627 let ret = unsafe {
628 sys::MaaControllerSetOption(
629 self.inner.handle.as_ptr(),
630 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotTargetShortSide as i32,
631 &mut val as *mut _ as *mut c_void,
632 std::mem::size_of::<i32>() as u64,
633 )
634 };
635 common::check_bool(ret)
636 }
637
638 pub fn set_screenshot_use_raw_size(&self, enable: bool) -> MaaResult<()> {
640 let mut val: u8 = if enable { 1 } else { 0 };
641 let ret = unsafe {
642 sys::MaaControllerSetOption(
643 self.inner.handle.as_ptr(),
644 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotUseRawSize as i32,
645 &mut val as *mut _ as *mut c_void,
646 std::mem::size_of::<u8>() as u64,
647 )
648 };
649 common::check_bool(ret)
650 }
651
652 pub fn set_screenshot_resize_method(&self, method: i32) -> MaaResult<()> {
661 let mut val = method;
662 let ret = unsafe {
663 sys::MaaControllerSetOption(
664 self.inner.handle.as_ptr(),
665 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotResizeMethod as i32,
666 &mut val as *mut _ as *mut c_void,
667 std::mem::size_of::<i32>() as u64,
668 )
669 };
670 common::check_bool(ret)
671 }
672
673 pub fn set_mouse_lock_follow(&self, enable: bool) -> MaaResult<()> {
678 let mut val: u8 = if enable { 1 } else { 0 };
679 let ret = unsafe {
680 sys::MaaControllerSetOption(
681 self.inner.handle.as_ptr(),
682 sys::MaaCtrlOptionEnum_MaaCtrlOption_MouseLockFollow as i32,
683 &mut val as *mut _ as *mut c_void,
684 std::mem::size_of::<u8>() as u64,
685 )
686 };
687 common::check_bool(ret)
688 }
689
690 pub fn new_dbg(read_path: &str) -> MaaResult<Self> {
693 let c_read = CString::new(read_path)?;
694 let handle = unsafe { sys::MaaDbgControllerCreate(c_read.as_ptr()) };
695 Self::from_handle(handle)
696 }
697
698 pub fn new_replay(recording_path: &str) -> MaaResult<Self> {
700 let c_recording = CString::new(recording_path)?;
701 let handle = unsafe { sys::MaaReplayControllerCreate(c_recording.as_ptr()) };
702 Self::from_handle(handle)
703 }
704
705 pub fn new_record(inner: &Controller, recording_path: &str) -> MaaResult<Self> {
707 let c_recording = CString::new(recording_path)?;
708 let handle = unsafe { sys::MaaRecordControllerCreate(inner.raw(), c_recording.as_ptr()) };
709
710 if let Some(ptr) = NonNull::new(handle) {
711 Ok(Self::new_with_retained(ptr, vec![Arc::clone(&inner.inner)]))
712 } else {
713 Err(MaaError::FrameworkError(-1))
714 }
715 }
716
717 #[cfg(feature = "win32")]
719 pub fn new_gamepad(
720 hwnd: *mut c_void,
721 gamepad_type: crate::common::GamepadType,
722 screencap_method: crate::common::Win32ScreencapMethod,
723 ) -> MaaResult<Self> {
724 let handle = unsafe {
725 sys::MaaGamepadControllerCreate(hwnd, gamepad_type as u64, screencap_method.bits())
726 };
727 Self::from_handle(handle)
728 }
729
730 pub fn add_sink<F>(&self, callback: F) -> MaaResult<sys::MaaSinkId>
734 where
735 F: Fn(&str, &str) + Send + Sync + 'static,
736 {
737 let (cb_fn, cb_arg) = crate::callback::EventCallback::new(callback);
738 let sink_id =
739 unsafe { sys::MaaControllerAddSink(self.inner.handle.as_ptr(), cb_fn, cb_arg) };
740 if sink_id != 0 {
741 self.inner
742 .callbacks
743 .lock()
744 .unwrap()
745 .insert(sink_id, cb_arg as usize);
746 Ok(sink_id)
747 } else {
748 unsafe { crate::callback::EventCallback::drop_callback(cb_arg) };
749 Err(MaaError::FrameworkError(0))
750 }
751 }
752
753 pub fn add_event_sink(
765 &self,
766 sink: Box<dyn crate::event_sink::EventSink>,
767 ) -> MaaResult<sys::MaaSinkId> {
768 let handle_id = self.inner.handle.as_ptr() as crate::common::MaaId;
769 let (cb, arg) = crate::callback::EventCallback::new_sink(handle_id, sink);
770 let id = unsafe { sys::MaaControllerAddSink(self.inner.handle.as_ptr(), cb, arg) };
771 if id > 0 {
772 self.inner
773 .event_sinks
774 .lock()
775 .unwrap()
776 .insert(id, arg as usize);
777 Ok(id)
778 } else {
779 unsafe { crate::callback::EventCallback::drop_sink(arg) };
780 Err(MaaError::FrameworkError(0))
781 }
782 }
783
784 pub fn remove_sink(&self, sink_id: sys::MaaSinkId) {
785 unsafe { sys::MaaControllerRemoveSink(self.inner.handle.as_ptr(), sink_id) };
786 if let Some(ptr) = self.inner.callbacks.lock().unwrap().remove(&sink_id) {
787 unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
788 } else if let Some(ptr) = self.inner.event_sinks.lock().unwrap().remove(&sink_id) {
789 unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
790 }
791 }
792
793 pub fn clear_sinks(&self) {
794 unsafe { sys::MaaControllerClearSinks(self.inner.handle.as_ptr()) };
795 let mut callbacks = self.inner.callbacks.lock().unwrap();
796 for (_, ptr) in callbacks.drain() {
797 unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
798 }
799 let mut event_sinks = self.inner.event_sinks.lock().unwrap();
800 for (_, ptr) in event_sinks.drain() {
801 unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
802 }
803 }
804}
805
806impl Drop for ControllerInner {
807 fn drop(&mut self) {
808 unsafe {
809 if self.owns_handle {
810 sys::MaaControllerClearSinks(self.handle.as_ptr());
811 let mut callbacks = self.callbacks.lock().unwrap();
812 for (_, ptr) in callbacks.drain() {
813 crate::callback::EventCallback::drop_callback(ptr as *mut c_void);
814 }
815 let mut event_sinks = self.event_sinks.lock().unwrap();
816 for (_, ptr) in event_sinks.drain() {
817 crate::callback::EventCallback::drop_sink(ptr as *mut c_void);
818 }
819 sys::MaaControllerDestroy(self.handle.as_ptr());
820 }
821 }
822 }
823}
824
825#[cfg(feature = "adb")]
829pub struct AdbControllerBuilder {
830 adb_path: String,
831 address: String,
832 screencap_methods: sys::MaaAdbScreencapMethod,
833 input_methods: sys::MaaAdbInputMethod,
834 config: String,
835 agent_path: String,
836}
837
838#[cfg(feature = "adb")]
839impl AdbControllerBuilder {
840 pub fn new(adb_path: &str, address: &str) -> Self {
842 Self {
843 adb_path: adb_path.to_string(),
844 address: address.to_string(),
845 screencap_methods: sys::MaaAdbScreencapMethod_Default as sys::MaaAdbScreencapMethod,
846 input_methods: sys::MaaAdbInputMethod_Default as sys::MaaAdbInputMethod,
847 config: "{}".to_string(),
848 agent_path: String::new(),
849 }
850 }
851
852 pub fn screencap_methods(mut self, methods: sys::MaaAdbScreencapMethod) -> Self {
854 self.screencap_methods = methods;
855 self
856 }
857
858 pub fn input_methods(mut self, methods: sys::MaaAdbInputMethod) -> Self {
860 self.input_methods = methods;
861 self
862 }
863
864 pub fn config(mut self, config: &str) -> Self {
866 self.config = config.to_string();
867 self
868 }
869
870 pub fn agent_path(mut self, path: &str) -> Self {
872 self.agent_path = path.to_string();
873 self
874 }
875
876 pub fn build(self) -> MaaResult<Controller> {
878 Controller::create_adb(
879 &self.adb_path,
880 &self.address,
881 self.screencap_methods,
882 self.input_methods,
883 &self.config,
884 &self.agent_path,
885 )
886 }
887}
888
889pub struct ControllerRef<'a> {
895 handle: *mut sys::MaaController,
896 _marker: std::marker::PhantomData<&'a ()>,
897}
898
899impl<'a> std::fmt::Debug for ControllerRef<'a> {
900 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
901 f.debug_struct("ControllerRef")
902 .field("handle", &self.handle)
903 .finish()
904 }
905}
906
907impl<'a> ControllerRef<'a> {
908 pub(crate) fn from_ptr(handle: *mut sys::MaaController) -> Option<Self> {
909 if handle.is_null() {
910 None
911 } else {
912 Some(Self {
913 handle,
914 _marker: std::marker::PhantomData,
915 })
916 }
917 }
918
919 pub fn connected(&self) -> bool {
921 unsafe { sys::MaaControllerConnected(self.handle) != 0 }
922 }
923
924 pub fn uuid(&self) -> MaaResult<String> {
926 let buffer = crate::buffer::MaaStringBuffer::new()?;
927 let ret = unsafe { sys::MaaControllerGetUuid(self.handle, buffer.as_ptr()) };
928 if ret != 0 {
929 Ok(buffer.to_string())
930 } else {
931 Err(MaaError::FrameworkError(0))
932 }
933 }
934
935 pub fn info(&self) -> MaaResult<serde_json::Value> {
937 let buffer = crate::buffer::MaaStringBuffer::new()?;
938 let ret = unsafe { sys::MaaControllerGetInfo(self.handle, buffer.as_ptr()) };
939 if ret != 0 {
940 serde_json::from_str(&buffer.to_string()).map_err(|e| {
941 MaaError::InvalidArgument(format!("Failed to parse controller info: {}", e))
942 })
943 } else {
944 Err(MaaError::FrameworkError(0))
945 }
946 }
947
948 pub fn resolution(&self) -> MaaResult<(i32, i32)> {
950 let mut width: i32 = 0;
951 let mut height: i32 = 0;
952 let ret = unsafe { sys::MaaControllerGetResolution(self.handle, &mut width, &mut height) };
953 if ret != 0 {
954 Ok((width, height))
955 } else {
956 Err(MaaError::FrameworkError(0))
957 }
958 }
959
960 pub fn status(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
962 let s = unsafe { sys::MaaControllerStatus(self.handle, ctrl_id) };
963 common::MaaStatus(s)
964 }
965
966 pub fn wait(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
968 let s = unsafe { sys::MaaControllerWait(self.handle, ctrl_id) };
969 common::MaaStatus(s)
970 }
971
972 pub fn cached_image(&self) -> MaaResult<crate::buffer::MaaImageBuffer> {
974 let buffer = crate::buffer::MaaImageBuffer::new()?;
975 let ret = unsafe { sys::MaaControllerCachedImage(self.handle, buffer.as_ptr()) };
976 if ret != 0 {
977 Ok(buffer)
978 } else {
979 Err(MaaError::FrameworkError(0))
980 }
981 }
982
983 pub fn raw(&self) -> *mut sys::MaaController {
985 self.handle
986 }
987}