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 Self::new_wlroots_with_vk_code(wlr_socket_path, false)
204 }
205
206 pub fn new_wlroots_with_vk_code(
213 wlr_socket_path: &str,
214 use_win32_vk_code: bool,
215 ) -> MaaResult<Self> {
216 let c_path = CString::new(wlr_socket_path)?;
217 let handle = unsafe {
218 sys::MaaWlRootsControllerCreate(c_path.as_ptr(), use_win32_vk_code as sys::MaaBool)
219 };
220
221 Self::from_handle(handle)
222 }
223
224 #[cfg(feature = "custom")]
226 pub fn new_custom<T: crate::custom_controller::CustomControllerCallback + 'static>(
227 callback: T,
228 ) -> MaaResult<Self> {
229 let boxed: Box<Box<dyn crate::custom_controller::CustomControllerCallback>> =
230 Box::new(Box::new(callback));
231 let cb_ptr = Box::into_raw(boxed) as *mut c_void;
232 let callbacks = crate::custom_controller::get_callbacks();
233 let handle =
234 unsafe { sys::MaaCustomControllerCreate(callbacks as *const _ as *mut _, cb_ptr) };
235
236 NonNull::new(handle).map(Self::new_owned).ok_or_else(|| {
237 unsafe {
238 let _ = Box::from_raw(
239 cb_ptr as *mut Box<dyn crate::custom_controller::CustomControllerCallback>,
240 );
241 }
242 MaaError::FrameworkError(-1)
243 })
244 }
245
246 fn from_handle(handle: *mut sys::MaaController) -> MaaResult<Self> {
248 if let Some(ptr) = NonNull::new(handle) {
249 Ok(Self::new_owned(ptr))
250 } else {
251 Err(MaaError::FrameworkError(-1))
252 }
253 }
254
255 fn new_owned(handle: NonNull<sys::MaaController>) -> Self {
256 Self::new_with_retained(handle, Vec::new())
257 }
258
259 fn new_with_retained(
260 handle: NonNull<sys::MaaController>,
261 retained_handles: Vec<Arc<ControllerInner>>,
262 ) -> Self {
263 Self {
264 inner: Arc::new(ControllerInner {
265 handle,
266 owns_handle: true,
267 _retained_handles: retained_handles,
268 callbacks: Mutex::new(HashMap::new()),
269 event_sinks: Mutex::new(HashMap::new()),
270 }),
271 }
272 }
273
274 pub fn post_click(&self, x: i32, y: i32) -> MaaResult<common::MaaId> {
276 let id = unsafe { sys::MaaControllerPostClick(self.inner.handle.as_ptr(), x, y) };
277 Ok(id)
278 }
279
280 pub fn post_screencap(&self) -> MaaResult<common::MaaId> {
282 let id = unsafe { sys::MaaControllerPostScreencap(self.inner.handle.as_ptr()) };
283 Ok(id)
284 }
285
286 pub fn post_click_v2(
293 &self,
294 x: i32,
295 y: i32,
296 contact: i32,
297 pressure: i32,
298 ) -> MaaResult<common::MaaId> {
299 let id = unsafe {
300 sys::MaaControllerPostClickV2(self.inner.handle.as_ptr(), x, y, contact, pressure)
301 };
302 Ok(id)
303 }
304
305 pub fn post_swipe(
312 &self,
313 x1: i32,
314 y1: i32,
315 x2: i32,
316 y2: i32,
317 duration: i32,
318 ) -> MaaResult<common::MaaId> {
319 let id = unsafe {
320 sys::MaaControllerPostSwipe(self.inner.handle.as_ptr(), x1, y1, x2, y2, duration)
321 };
322 Ok(id)
323 }
324
325 pub fn post_click_key(&self, keycode: i32) -> MaaResult<common::MaaId> {
330 let id = unsafe { sys::MaaControllerPostClickKey(self.inner.handle.as_ptr(), keycode) };
331 Ok(id)
332 }
333
334 #[deprecated(note = "Use post_click_key instead")]
336 pub fn post_press(&self, keycode: i32) -> MaaResult<common::MaaId> {
337 self.post_click_key(keycode)
338 }
339
340 pub fn post_input_text(&self, text: &str) -> MaaResult<common::MaaId> {
345 let c_text = CString::new(text)?;
346 let id =
347 unsafe { sys::MaaControllerPostInputText(self.inner.handle.as_ptr(), c_text.as_ptr()) };
348 Ok(id)
349 }
350
351 pub fn post_shell(&self, cmd: &str, timeout: i64) -> MaaResult<common::MaaId> {
357 let c_cmd = CString::new(cmd)?;
358 let id = unsafe {
359 sys::MaaControllerPostShell(self.inner.handle.as_ptr(), c_cmd.as_ptr(), timeout)
360 };
361 Ok(id)
362 }
363
364 pub fn post_touch_down(
371 &self,
372 contact: i32,
373 x: i32,
374 y: i32,
375 pressure: i32,
376 ) -> MaaResult<common::MaaId> {
377 let id = unsafe {
378 sys::MaaControllerPostTouchDown(self.inner.handle.as_ptr(), contact, x, y, pressure)
379 };
380 Ok(id)
381 }
382
383 pub fn post_touch_move(
390 &self,
391 contact: i32,
392 x: i32,
393 y: i32,
394 pressure: i32,
395 ) -> MaaResult<common::MaaId> {
396 let id = unsafe {
397 sys::MaaControllerPostTouchMove(self.inner.handle.as_ptr(), contact, x, y, pressure)
398 };
399 Ok(id)
400 }
401
402 pub fn post_touch_up(&self, contact: i32) -> MaaResult<common::MaaId> {
407 let id = unsafe { sys::MaaControllerPostTouchUp(self.inner.handle.as_ptr(), contact) };
408 Ok(id)
409 }
410
411 pub fn post_relative_move(&self, dx: i32, dy: i32) -> MaaResult<common::MaaId> {
417 let id = unsafe { sys::MaaControllerPostRelativeMove(self.inner.handle.as_ptr(), dx, dy) };
418 Ok(id)
419 }
420
421 #[inline]
423 pub fn raw(&self) -> *mut sys::MaaController {
424 self.inner.handle.as_ptr()
425 }
426
427 pub fn post_connection(&self) -> MaaResult<common::MaaId> {
433 let id = unsafe { sys::MaaControllerPostConnection(self.inner.handle.as_ptr()) };
434 Ok(id)
435 }
436
437 pub fn connected(&self) -> bool {
439 unsafe { sys::MaaControllerConnected(self.inner.handle.as_ptr()) != 0 }
440 }
441
442 pub fn uuid(&self) -> MaaResult<String> {
444 let buffer = crate::buffer::MaaStringBuffer::new()?;
445 let ret = unsafe { sys::MaaControllerGetUuid(self.inner.handle.as_ptr(), buffer.as_ptr()) };
446 if ret != 0 {
447 Ok(buffer.to_string())
448 } else {
449 Err(MaaError::FrameworkError(0))
450 }
451 }
452
453 pub fn info(&self) -> MaaResult<serde_json::Value> {
458 let buffer = crate::buffer::MaaStringBuffer::new()?;
459 let ret = unsafe { sys::MaaControllerGetInfo(self.inner.handle.as_ptr(), buffer.as_ptr()) };
460 if ret != 0 {
461 serde_json::from_str(&buffer.to_string()).map_err(|e| {
462 MaaError::InvalidArgument(format!("Failed to parse controller info: {}", e))
463 })
464 } else {
465 Err(MaaError::FrameworkError(0))
466 }
467 }
468
469 pub fn resolution(&self) -> MaaResult<(i32, i32)> {
471 let mut width: i32 = 0;
472 let mut height: i32 = 0;
473 let ret = unsafe {
474 sys::MaaControllerGetResolution(self.inner.handle.as_ptr(), &mut width, &mut height)
475 };
476 if ret != 0 {
477 Ok((width, height))
478 } else {
479 Err(MaaError::FrameworkError(0))
480 }
481 }
482
483 pub fn post_swipe_v2(
494 &self,
495 x1: i32,
496 y1: i32,
497 x2: i32,
498 y2: i32,
499 duration: i32,
500 contact: i32,
501 pressure: i32,
502 ) -> MaaResult<common::MaaId> {
503 let id = unsafe {
504 sys::MaaControllerPostSwipeV2(
505 self.inner.handle.as_ptr(),
506 x1,
507 y1,
508 x2,
509 y2,
510 duration,
511 contact,
512 pressure,
513 )
514 };
515 Ok(id)
516 }
517
518 pub fn post_key_down(&self, keycode: i32) -> MaaResult<common::MaaId> {
522 let id = unsafe { sys::MaaControllerPostKeyDown(self.inner.handle.as_ptr(), keycode) };
523 Ok(id)
524 }
525
526 pub fn post_key_up(&self, keycode: i32) -> MaaResult<common::MaaId> {
528 let id = unsafe { sys::MaaControllerPostKeyUp(self.inner.handle.as_ptr(), keycode) };
529 Ok(id)
530 }
531
532 pub fn post_start_app(&self, intent: &str) -> MaaResult<common::MaaId> {
539 let c_intent = CString::new(intent)?;
540 let id = unsafe {
541 sys::MaaControllerPostStartApp(self.inner.handle.as_ptr(), c_intent.as_ptr())
542 };
543 Ok(id)
544 }
545
546 pub fn post_stop_app(&self, intent: &str) -> MaaResult<common::MaaId> {
551 let c_intent = CString::new(intent)?;
552 let id =
553 unsafe { sys::MaaControllerPostStopApp(self.inner.handle.as_ptr(), c_intent.as_ptr()) };
554 Ok(id)
555 }
556
557 pub fn post_scroll(&self, dx: i32, dy: i32) -> MaaResult<common::MaaId> {
565 let id = unsafe { sys::MaaControllerPostScroll(self.inner.handle.as_ptr(), dx, dy) };
566 Ok(id)
567 }
568
569 pub fn post_inactive(&self) -> MaaResult<common::MaaId> {
576 let id = unsafe { sys::MaaControllerPostInactive(self.inner.handle.as_ptr()) };
577 Ok(id)
578 }
579
580 pub fn cached_image(&self) -> MaaResult<crate::buffer::MaaImageBuffer> {
584 let buffer = crate::buffer::MaaImageBuffer::new()?;
585 let ret =
586 unsafe { sys::MaaControllerCachedImage(self.inner.handle.as_ptr(), buffer.as_ptr()) };
587 if ret != 0 {
588 Ok(buffer)
589 } else {
590 Err(MaaError::FrameworkError(0))
591 }
592 }
593
594 pub fn shell_output(&self) -> MaaResult<String> {
598 let buffer = crate::buffer::MaaStringBuffer::new()?;
599 let ret = unsafe {
600 sys::MaaControllerGetShellOutput(self.inner.handle.as_ptr(), buffer.as_ptr())
601 };
602 if ret != 0 {
603 Ok(buffer.to_string())
604 } else {
605 Err(MaaError::FrameworkError(0))
606 }
607 }
608
609 pub fn status(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
613 let s = unsafe { sys::MaaControllerStatus(self.inner.handle.as_ptr(), ctrl_id) };
614 common::MaaStatus(s)
615 }
616
617 pub fn wait(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
619 let s = unsafe { sys::MaaControllerWait(self.inner.handle.as_ptr(), ctrl_id) };
620 common::MaaStatus(s)
621 }
622
623 pub fn set_screenshot_target_long_side(&self, long_side: i32) -> MaaResult<()> {
627 let mut val = long_side;
628 let ret = unsafe {
629 sys::MaaControllerSetOption(
630 self.inner.handle.as_ptr(),
631 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotTargetLongSide as i32,
632 &mut val as *mut _ as *mut c_void,
633 std::mem::size_of::<i32>() as u64,
634 )
635 };
636 common::check_bool(ret)
637 }
638
639 pub fn set_screenshot_target_short_side(&self, short_side: i32) -> MaaResult<()> {
641 let mut val = short_side;
642 let ret = unsafe {
643 sys::MaaControllerSetOption(
644 self.inner.handle.as_ptr(),
645 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotTargetShortSide as i32,
646 &mut val as *mut _ as *mut c_void,
647 std::mem::size_of::<i32>() as u64,
648 )
649 };
650 common::check_bool(ret)
651 }
652
653 pub fn set_screenshot_use_raw_size(&self, enable: bool) -> MaaResult<()> {
655 let mut val: u8 = if enable { 1 } else { 0 };
656 let ret = unsafe {
657 sys::MaaControllerSetOption(
658 self.inner.handle.as_ptr(),
659 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotUseRawSize as i32,
660 &mut val as *mut _ as *mut c_void,
661 std::mem::size_of::<u8>() as u64,
662 )
663 };
664 common::check_bool(ret)
665 }
666
667 pub fn set_screenshot_resize_method(&self, method: i32) -> MaaResult<()> {
676 let mut val = method;
677 let ret = unsafe {
678 sys::MaaControllerSetOption(
679 self.inner.handle.as_ptr(),
680 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotResizeMethod as i32,
681 &mut val as *mut _ as *mut c_void,
682 std::mem::size_of::<i32>() as u64,
683 )
684 };
685 common::check_bool(ret)
686 }
687
688 pub fn set_mouse_lock_follow(&self, enable: bool) -> MaaResult<()> {
693 let mut val: u8 = if enable { 1 } else { 0 };
694 let ret = unsafe {
695 sys::MaaControllerSetOption(
696 self.inner.handle.as_ptr(),
697 sys::MaaCtrlOptionEnum_MaaCtrlOption_MouseLockFollow as i32,
698 &mut val as *mut _ as *mut c_void,
699 std::mem::size_of::<u8>() as u64,
700 )
701 };
702 common::check_bool(ret)
703 }
704
705 pub fn new_dbg(read_path: &str) -> MaaResult<Self> {
708 let c_read = CString::new(read_path)?;
709 let handle = unsafe { sys::MaaDbgControllerCreate(c_read.as_ptr()) };
710 Self::from_handle(handle)
711 }
712
713 pub fn new_replay(recording_path: &str) -> MaaResult<Self> {
715 let c_recording = CString::new(recording_path)?;
716 let handle = unsafe { sys::MaaReplayControllerCreate(c_recording.as_ptr()) };
717 Self::from_handle(handle)
718 }
719
720 pub fn new_record(inner: &Controller, recording_path: &str) -> MaaResult<Self> {
722 let c_recording = CString::new(recording_path)?;
723 let handle = unsafe { sys::MaaRecordControllerCreate(inner.raw(), c_recording.as_ptr()) };
724
725 if let Some(ptr) = NonNull::new(handle) {
726 Ok(Self::new_with_retained(ptr, vec![Arc::clone(&inner.inner)]))
727 } else {
728 Err(MaaError::FrameworkError(-1))
729 }
730 }
731
732 #[cfg(feature = "win32")]
734 pub fn new_gamepad(
735 hwnd: *mut c_void,
736 gamepad_type: crate::common::GamepadType,
737 screencap_method: crate::common::Win32ScreencapMethod,
738 ) -> MaaResult<Self> {
739 let handle = unsafe {
740 sys::MaaGamepadControllerCreate(hwnd, gamepad_type as u64, screencap_method.bits())
741 };
742 Self::from_handle(handle)
743 }
744
745 pub fn add_sink<F>(&self, callback: F) -> MaaResult<sys::MaaSinkId>
749 where
750 F: Fn(&str, &str) + Send + Sync + 'static,
751 {
752 let (cb_fn, cb_arg) = crate::callback::EventCallback::new(callback);
753 let sink_id =
754 unsafe { sys::MaaControllerAddSink(self.inner.handle.as_ptr(), cb_fn, cb_arg) };
755 if sink_id != 0 {
756 self.inner
757 .callbacks
758 .lock()
759 .unwrap()
760 .insert(sink_id, cb_arg as usize);
761 Ok(sink_id)
762 } else {
763 unsafe { crate::callback::EventCallback::drop_callback(cb_arg) };
764 Err(MaaError::FrameworkError(0))
765 }
766 }
767
768 pub fn add_event_sink(
780 &self,
781 sink: Box<dyn crate::event_sink::EventSink>,
782 ) -> MaaResult<sys::MaaSinkId> {
783 let handle_id = self.inner.handle.as_ptr() as crate::common::MaaId;
784 let (cb, arg) = crate::callback::EventCallback::new_sink(handle_id, sink);
785 let id = unsafe { sys::MaaControllerAddSink(self.inner.handle.as_ptr(), cb, arg) };
786 if id > 0 {
787 self.inner
788 .event_sinks
789 .lock()
790 .unwrap()
791 .insert(id, arg as usize);
792 Ok(id)
793 } else {
794 unsafe { crate::callback::EventCallback::drop_sink(arg) };
795 Err(MaaError::FrameworkError(0))
796 }
797 }
798
799 pub fn remove_sink(&self, sink_id: sys::MaaSinkId) {
800 unsafe { sys::MaaControllerRemoveSink(self.inner.handle.as_ptr(), sink_id) };
801 if let Some(ptr) = self.inner.callbacks.lock().unwrap().remove(&sink_id) {
802 unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
803 } else if let Some(ptr) = self.inner.event_sinks.lock().unwrap().remove(&sink_id) {
804 unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
805 }
806 }
807
808 pub fn clear_sinks(&self) {
809 unsafe { sys::MaaControllerClearSinks(self.inner.handle.as_ptr()) };
810 let mut callbacks = self.inner.callbacks.lock().unwrap();
811 for (_, ptr) in callbacks.drain() {
812 unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
813 }
814 let mut event_sinks = self.inner.event_sinks.lock().unwrap();
815 for (_, ptr) in event_sinks.drain() {
816 unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
817 }
818 }
819}
820
821impl Drop for ControllerInner {
822 fn drop(&mut self) {
823 unsafe {
824 if self.owns_handle {
825 sys::MaaControllerClearSinks(self.handle.as_ptr());
826 let mut callbacks = self.callbacks.lock().unwrap();
827 for (_, ptr) in callbacks.drain() {
828 crate::callback::EventCallback::drop_callback(ptr as *mut c_void);
829 }
830 let mut event_sinks = self.event_sinks.lock().unwrap();
831 for (_, ptr) in event_sinks.drain() {
832 crate::callback::EventCallback::drop_sink(ptr as *mut c_void);
833 }
834 sys::MaaControllerDestroy(self.handle.as_ptr());
835 }
836 }
837 }
838}
839
840#[cfg(feature = "adb")]
844pub struct AdbControllerBuilder {
845 adb_path: String,
846 address: String,
847 screencap_methods: sys::MaaAdbScreencapMethod,
848 input_methods: sys::MaaAdbInputMethod,
849 config: String,
850 agent_path: String,
851}
852
853#[cfg(feature = "adb")]
854impl AdbControllerBuilder {
855 pub fn new(adb_path: &str, address: &str) -> Self {
857 Self {
858 adb_path: adb_path.to_string(),
859 address: address.to_string(),
860 screencap_methods: sys::MaaAdbScreencapMethod_Default as sys::MaaAdbScreencapMethod,
861 input_methods: sys::MaaAdbInputMethod_Default as sys::MaaAdbInputMethod,
862 config: "{}".to_string(),
863 agent_path: String::new(),
864 }
865 }
866
867 pub fn screencap_methods(mut self, methods: sys::MaaAdbScreencapMethod) -> Self {
869 self.screencap_methods = methods;
870 self
871 }
872
873 pub fn input_methods(mut self, methods: sys::MaaAdbInputMethod) -> Self {
875 self.input_methods = methods;
876 self
877 }
878
879 pub fn config(mut self, config: &str) -> Self {
881 self.config = config.to_string();
882 self
883 }
884
885 pub fn agent_path(mut self, path: &str) -> Self {
887 self.agent_path = path.to_string();
888 self
889 }
890
891 pub fn build(self) -> MaaResult<Controller> {
893 Controller::create_adb(
894 &self.adb_path,
895 &self.address,
896 self.screencap_methods,
897 self.input_methods,
898 &self.config,
899 &self.agent_path,
900 )
901 }
902}
903
904pub struct ControllerRef<'a> {
910 handle: *mut sys::MaaController,
911 _marker: std::marker::PhantomData<&'a ()>,
912}
913
914impl<'a> std::fmt::Debug for ControllerRef<'a> {
915 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
916 f.debug_struct("ControllerRef")
917 .field("handle", &self.handle)
918 .finish()
919 }
920}
921
922impl<'a> ControllerRef<'a> {
923 pub(crate) fn from_ptr(handle: *mut sys::MaaController) -> Option<Self> {
924 if handle.is_null() {
925 None
926 } else {
927 Some(Self {
928 handle,
929 _marker: std::marker::PhantomData,
930 })
931 }
932 }
933
934 pub fn connected(&self) -> bool {
936 unsafe { sys::MaaControllerConnected(self.handle) != 0 }
937 }
938
939 pub fn uuid(&self) -> MaaResult<String> {
941 let buffer = crate::buffer::MaaStringBuffer::new()?;
942 let ret = unsafe { sys::MaaControllerGetUuid(self.handle, buffer.as_ptr()) };
943 if ret != 0 {
944 Ok(buffer.to_string())
945 } else {
946 Err(MaaError::FrameworkError(0))
947 }
948 }
949
950 pub fn info(&self) -> MaaResult<serde_json::Value> {
952 let buffer = crate::buffer::MaaStringBuffer::new()?;
953 let ret = unsafe { sys::MaaControllerGetInfo(self.handle, buffer.as_ptr()) };
954 if ret != 0 {
955 serde_json::from_str(&buffer.to_string()).map_err(|e| {
956 MaaError::InvalidArgument(format!("Failed to parse controller info: {}", e))
957 })
958 } else {
959 Err(MaaError::FrameworkError(0))
960 }
961 }
962
963 pub fn resolution(&self) -> MaaResult<(i32, i32)> {
965 let mut width: i32 = 0;
966 let mut height: i32 = 0;
967 let ret = unsafe { sys::MaaControllerGetResolution(self.handle, &mut width, &mut height) };
968 if ret != 0 {
969 Ok((width, height))
970 } else {
971 Err(MaaError::FrameworkError(0))
972 }
973 }
974
975 pub fn status(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
977 let s = unsafe { sys::MaaControllerStatus(self.handle, ctrl_id) };
978 common::MaaStatus(s)
979 }
980
981 pub fn wait(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
983 let s = unsafe { sys::MaaControllerWait(self.handle, ctrl_id) };
984 common::MaaStatus(s)
985 }
986
987 pub fn cached_image(&self) -> MaaResult<crate::buffer::MaaImageBuffer> {
989 let buffer = crate::buffer::MaaImageBuffer::new()?;
990 let ret = unsafe { sys::MaaControllerCachedImage(self.handle, buffer.as_ptr()) };
991 if ret != 0 {
992 Ok(buffer)
993 } else {
994 Err(MaaError::FrameworkError(0))
995 }
996 }
997
998 pub fn raw(&self) -> *mut sys::MaaController {
1000 self.handle
1001 }
1002}