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_linux<T: Serialize>(config: &T) -> MaaResult<Self> {
206 let config_json = serde_json::to_string(config).map_err(|e| {
207 MaaError::InvalidConfig(format!(
208 "Failed to serialize Linux controller config: {}",
209 e
210 ))
211 })?;
212 let c_config = CString::new(config_json)?;
213 let handle = unsafe { sys::MaaLinuxControllerCreate(c_config.as_ptr()) };
214
215 Self::from_handle(handle)
216 }
217
218 #[allow(deprecated)]
223 #[deprecated(note = "Use `Controller::new_linux` instead")]
224 pub fn new_wlroots(wlr_socket_path: &str) -> MaaResult<Self> {
225 Self::new_wlroots_with_vk_code(wlr_socket_path, false)
226 }
227
228 #[deprecated(note = "Use `Controller::new_linux` instead")]
235 pub fn new_wlroots_with_vk_code(
236 wlr_socket_path: &str,
237 use_win32_vk_code: bool,
238 ) -> MaaResult<Self> {
239 let c_path = CString::new(wlr_socket_path)?;
240 let handle = unsafe {
241 sys::MaaWlRootsControllerCreate(c_path.as_ptr(), use_win32_vk_code as sys::MaaBool)
242 };
243
244 Self::from_handle(handle)
245 }
246
247 #[cfg(target_os = "linux")]
268 #[allow(deprecated)]
269 #[deprecated(note = "Use `Controller::new_linux` instead")]
270 pub fn new_kwin(device_node: &str, screen_width: i32, screen_height: i32) -> MaaResult<Self> {
271 Self::new_kwin_with_vk_code(device_node, screen_width, screen_height, false)
272 }
273
274 #[cfg(target_os = "linux")]
286 #[deprecated(note = "Use `Controller::new_linux` instead")]
287 pub fn new_kwin_with_vk_code(
288 device_node: &str,
289 screen_width: i32,
290 screen_height: i32,
291 use_win32_vk_code: bool,
292 ) -> MaaResult<Self> {
293 let c_node = CString::new(device_node)?;
294 let handle = unsafe {
295 sys::MaaKWinControllerCreate(
296 c_node.as_ptr(),
297 screen_width,
298 screen_height,
299 use_win32_vk_code as sys::MaaBool,
300 )
301 };
302
303 Self::from_handle(handle)
304 }
305
306 #[cfg(feature = "custom")]
308 pub fn new_custom<T: crate::custom_controller::CustomControllerCallback + 'static>(
309 callback: T,
310 ) -> MaaResult<Self> {
311 let boxed: Box<Box<dyn crate::custom_controller::CustomControllerCallback>> =
312 Box::new(Box::new(callback));
313 let cb_ptr = Box::into_raw(boxed) as *mut c_void;
314 let callbacks = crate::custom_controller::get_callbacks();
315 let handle =
316 unsafe { sys::MaaCustomControllerCreate(callbacks as *const _ as *mut _, cb_ptr) };
317
318 NonNull::new(handle).map(Self::new_owned).ok_or_else(|| {
319 unsafe {
320 let _ = Box::from_raw(
321 cb_ptr as *mut Box<dyn crate::custom_controller::CustomControllerCallback>,
322 );
323 }
324 MaaError::FrameworkError(-1)
325 })
326 }
327
328 fn from_handle(handle: *mut sys::MaaController) -> MaaResult<Self> {
330 if let Some(ptr) = NonNull::new(handle) {
331 Ok(Self::new_owned(ptr))
332 } else {
333 Err(MaaError::FrameworkError(-1))
334 }
335 }
336
337 fn new_owned(handle: NonNull<sys::MaaController>) -> Self {
338 Self::new_with_retained(handle, Vec::new())
339 }
340
341 fn new_with_retained(
342 handle: NonNull<sys::MaaController>,
343 retained_handles: Vec<Arc<ControllerInner>>,
344 ) -> Self {
345 Self {
346 inner: Arc::new(ControllerInner {
347 handle,
348 owns_handle: true,
349 _retained_handles: retained_handles,
350 callbacks: Mutex::new(HashMap::new()),
351 event_sinks: Mutex::new(HashMap::new()),
352 }),
353 }
354 }
355
356 pub fn post_click(&self, x: i32, y: i32) -> MaaResult<common::MaaId> {
358 let id = unsafe { sys::MaaControllerPostClick(self.inner.handle.as_ptr(), x, y) };
359 Ok(id)
360 }
361
362 pub fn post_screencap(&self) -> MaaResult<common::MaaId> {
364 let id = unsafe { sys::MaaControllerPostScreencap(self.inner.handle.as_ptr()) };
365 Ok(id)
366 }
367
368 pub fn post_click_v2(
375 &self,
376 x: i32,
377 y: i32,
378 contact: i32,
379 pressure: i32,
380 ) -> MaaResult<common::MaaId> {
381 let id = unsafe {
382 sys::MaaControllerPostClickV2(self.inner.handle.as_ptr(), x, y, contact, pressure)
383 };
384 Ok(id)
385 }
386
387 pub fn post_swipe(
394 &self,
395 x1: i32,
396 y1: i32,
397 x2: i32,
398 y2: i32,
399 duration: i32,
400 ) -> MaaResult<common::MaaId> {
401 let id = unsafe {
402 sys::MaaControllerPostSwipe(self.inner.handle.as_ptr(), x1, y1, x2, y2, duration)
403 };
404 Ok(id)
405 }
406
407 pub fn post_click_key(&self, keycode: i32) -> MaaResult<common::MaaId> {
412 let id = unsafe { sys::MaaControllerPostClickKey(self.inner.handle.as_ptr(), keycode) };
413 Ok(id)
414 }
415
416 #[deprecated(note = "Use post_click_key instead")]
418 pub fn post_press(&self, keycode: i32) -> MaaResult<common::MaaId> {
419 self.post_click_key(keycode)
420 }
421
422 pub fn post_input_text(&self, text: &str) -> MaaResult<common::MaaId> {
427 let c_text = CString::new(text)?;
428 let id =
429 unsafe { sys::MaaControllerPostInputText(self.inner.handle.as_ptr(), c_text.as_ptr()) };
430 Ok(id)
431 }
432
433 pub fn post_shell(&self, cmd: &str, timeout: i64) -> MaaResult<common::MaaId> {
439 let c_cmd = CString::new(cmd)?;
440 let id = unsafe {
441 sys::MaaControllerPostShell(self.inner.handle.as_ptr(), c_cmd.as_ptr(), timeout)
442 };
443 Ok(id)
444 }
445
446 pub fn post_touch_down(
453 &self,
454 contact: i32,
455 x: i32,
456 y: i32,
457 pressure: i32,
458 ) -> MaaResult<common::MaaId> {
459 let id = unsafe {
460 sys::MaaControllerPostTouchDown(self.inner.handle.as_ptr(), contact, x, y, pressure)
461 };
462 Ok(id)
463 }
464
465 pub fn post_touch_move(
472 &self,
473 contact: i32,
474 x: i32,
475 y: i32,
476 pressure: i32,
477 ) -> MaaResult<common::MaaId> {
478 let id = unsafe {
479 sys::MaaControllerPostTouchMove(self.inner.handle.as_ptr(), contact, x, y, pressure)
480 };
481 Ok(id)
482 }
483
484 pub fn post_touch_up(&self, contact: i32) -> MaaResult<common::MaaId> {
489 let id = unsafe { sys::MaaControllerPostTouchUp(self.inner.handle.as_ptr(), contact) };
490 Ok(id)
491 }
492
493 pub fn post_relative_move(&self, dx: i32, dy: i32) -> MaaResult<common::MaaId> {
499 let id = unsafe { sys::MaaControllerPostRelativeMove(self.inner.handle.as_ptr(), dx, dy) };
500 Ok(id)
501 }
502
503 #[inline]
505 pub fn raw(&self) -> *mut sys::MaaController {
506 self.inner.handle.as_ptr()
507 }
508
509 pub fn post_connection(&self) -> MaaResult<common::MaaId> {
515 let id = unsafe { sys::MaaControllerPostConnection(self.inner.handle.as_ptr()) };
516 Ok(id)
517 }
518
519 pub fn connected(&self) -> bool {
521 unsafe { sys::MaaControllerConnected(self.inner.handle.as_ptr()) != 0 }
522 }
523
524 pub fn uuid(&self) -> MaaResult<String> {
526 let buffer = crate::buffer::MaaStringBuffer::new()?;
527 let ret = unsafe { sys::MaaControllerGetUuid(self.inner.handle.as_ptr(), buffer.as_ptr()) };
528 if ret != 0 {
529 Ok(buffer.to_string())
530 } else {
531 Err(MaaError::FrameworkError(0))
532 }
533 }
534
535 pub fn info(&self) -> MaaResult<serde_json::Value> {
540 let buffer = crate::buffer::MaaStringBuffer::new()?;
541 let ret = unsafe { sys::MaaControllerGetInfo(self.inner.handle.as_ptr(), buffer.as_ptr()) };
542 if ret != 0 {
543 serde_json::from_str(&buffer.to_string()).map_err(|e| {
544 MaaError::InvalidArgument(format!("Failed to parse controller info: {}", e))
545 })
546 } else {
547 Err(MaaError::FrameworkError(0))
548 }
549 }
550
551 pub fn resolution(&self) -> MaaResult<(i32, i32)> {
553 let mut width: i32 = 0;
554 let mut height: i32 = 0;
555 let ret = unsafe {
556 sys::MaaControllerGetResolution(self.inner.handle.as_ptr(), &mut width, &mut height)
557 };
558 if ret != 0 {
559 Ok((width, height))
560 } else {
561 Err(MaaError::FrameworkError(0))
562 }
563 }
564
565 pub fn post_swipe_v2(
576 &self,
577 x1: i32,
578 y1: i32,
579 x2: i32,
580 y2: i32,
581 duration: i32,
582 contact: i32,
583 pressure: i32,
584 ) -> MaaResult<common::MaaId> {
585 let id = unsafe {
586 sys::MaaControllerPostSwipeV2(
587 self.inner.handle.as_ptr(),
588 x1,
589 y1,
590 x2,
591 y2,
592 duration,
593 contact,
594 pressure,
595 )
596 };
597 Ok(id)
598 }
599
600 pub fn post_key_down(&self, keycode: i32) -> MaaResult<common::MaaId> {
604 let id = unsafe { sys::MaaControllerPostKeyDown(self.inner.handle.as_ptr(), keycode) };
605 Ok(id)
606 }
607
608 pub fn post_key_up(&self, keycode: i32) -> MaaResult<common::MaaId> {
610 let id = unsafe { sys::MaaControllerPostKeyUp(self.inner.handle.as_ptr(), keycode) };
611 Ok(id)
612 }
613
614 pub fn post_start_app(&self, intent: &str) -> MaaResult<common::MaaId> {
621 let c_intent = CString::new(intent)?;
622 let id = unsafe {
623 sys::MaaControllerPostStartApp(self.inner.handle.as_ptr(), c_intent.as_ptr())
624 };
625 Ok(id)
626 }
627
628 pub fn post_stop_app(&self, intent: &str) -> MaaResult<common::MaaId> {
633 let c_intent = CString::new(intent)?;
634 let id =
635 unsafe { sys::MaaControllerPostStopApp(self.inner.handle.as_ptr(), c_intent.as_ptr()) };
636 Ok(id)
637 }
638
639 pub fn post_scroll(&self, dx: i32, dy: i32) -> MaaResult<common::MaaId> {
647 let id = unsafe { sys::MaaControllerPostScroll(self.inner.handle.as_ptr(), dx, dy) };
648 Ok(id)
649 }
650
651 pub fn post_inactive(&self) -> MaaResult<common::MaaId> {
658 let id = unsafe { sys::MaaControllerPostInactive(self.inner.handle.as_ptr()) };
659 Ok(id)
660 }
661
662 pub fn cached_image(&self) -> MaaResult<crate::buffer::MaaImageBuffer> {
666 let buffer = crate::buffer::MaaImageBuffer::new()?;
667 let ret =
668 unsafe { sys::MaaControllerCachedImage(self.inner.handle.as_ptr(), buffer.as_ptr()) };
669 if ret != 0 {
670 Ok(buffer)
671 } else {
672 Err(MaaError::FrameworkError(0))
673 }
674 }
675
676 pub fn shell_output(&self) -> MaaResult<String> {
680 let buffer = crate::buffer::MaaStringBuffer::new()?;
681 let ret = unsafe {
682 sys::MaaControllerGetShellOutput(self.inner.handle.as_ptr(), buffer.as_ptr())
683 };
684 if ret != 0 {
685 Ok(buffer.to_string())
686 } else {
687 Err(MaaError::FrameworkError(0))
688 }
689 }
690
691 pub fn status(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
695 let s = unsafe { sys::MaaControllerStatus(self.inner.handle.as_ptr(), ctrl_id) };
696 common::MaaStatus(s)
697 }
698
699 pub fn wait(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
701 let s = unsafe { sys::MaaControllerWait(self.inner.handle.as_ptr(), ctrl_id) };
702 common::MaaStatus(s)
703 }
704
705 pub fn set_screenshot_target_long_side(&self, long_side: i32) -> MaaResult<()> {
709 let mut val = long_side;
710 let ret = unsafe {
711 sys::MaaControllerSetOption(
712 self.inner.handle.as_ptr(),
713 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotTargetLongSide as i32,
714 &mut val as *mut _ as *mut c_void,
715 std::mem::size_of::<i32>() as u64,
716 )
717 };
718 common::check_bool(ret)
719 }
720
721 pub fn set_screenshot_target_short_side(&self, short_side: i32) -> MaaResult<()> {
723 let mut val = short_side;
724 let ret = unsafe {
725 sys::MaaControllerSetOption(
726 self.inner.handle.as_ptr(),
727 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotTargetShortSide as i32,
728 &mut val as *mut _ as *mut c_void,
729 std::mem::size_of::<i32>() as u64,
730 )
731 };
732 common::check_bool(ret)
733 }
734
735 pub fn set_screenshot_use_raw_size(&self, enable: bool) -> MaaResult<()> {
737 let mut val: u8 = if enable { 1 } else { 0 };
738 let ret = unsafe {
739 sys::MaaControllerSetOption(
740 self.inner.handle.as_ptr(),
741 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotUseRawSize as i32,
742 &mut val as *mut _ as *mut c_void,
743 std::mem::size_of::<u8>() as u64,
744 )
745 };
746 common::check_bool(ret)
747 }
748
749 pub fn set_screenshot_resize_method(&self, method: i32) -> MaaResult<()> {
758 let mut val = method;
759 let ret = unsafe {
760 sys::MaaControllerSetOption(
761 self.inner.handle.as_ptr(),
762 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotResizeMethod as i32,
763 &mut val as *mut _ as *mut c_void,
764 std::mem::size_of::<i32>() as u64,
765 )
766 };
767 common::check_bool(ret)
768 }
769
770 pub fn set_mouse_lock_follow(&self, enable: bool) -> MaaResult<()> {
775 let mut val: u8 = if enable { 1 } else { 0 };
776 let ret = unsafe {
777 sys::MaaControllerSetOption(
778 self.inner.handle.as_ptr(),
779 sys::MaaCtrlOptionEnum_MaaCtrlOption_MouseLockFollow as i32,
780 &mut val as *mut _ as *mut c_void,
781 std::mem::size_of::<u8>() as u64,
782 )
783 };
784 common::check_bool(ret)
785 }
786
787 pub fn set_background_managed_keys(&self, keys: &[i32]) -> MaaResult<()> {
795 let ret = unsafe {
796 sys::MaaControllerSetOption(
797 self.inner.handle.as_ptr(),
798 sys::MaaCtrlOptionEnum_MaaCtrlOption_BackgroundManagedKeys as i32,
799 keys.as_ptr() as *mut c_void,
800 std::mem::size_of_val(keys) as u64,
801 )
802 };
803 common::check_bool(ret)
804 }
805
806 pub fn new_dbg(read_path: &str) -> MaaResult<Self> {
809 let c_read = CString::new(read_path)?;
810 let handle = unsafe { sys::MaaDbgControllerCreate(c_read.as_ptr()) };
811 Self::from_handle(handle)
812 }
813
814 pub fn new_replay(recording_path: &str) -> MaaResult<Self> {
816 let c_recording = CString::new(recording_path)?;
817 let handle = unsafe { sys::MaaReplayControllerCreate(c_recording.as_ptr()) };
818 Self::from_handle(handle)
819 }
820
821 pub fn new_record(inner: &Controller, recording_path: &str) -> MaaResult<Self> {
823 let c_recording = CString::new(recording_path)?;
824 let handle = unsafe { sys::MaaRecordControllerCreate(inner.raw(), c_recording.as_ptr()) };
825
826 if let Some(ptr) = NonNull::new(handle) {
827 Ok(Self::new_with_retained(ptr, vec![Arc::clone(&inner.inner)]))
828 } else {
829 Err(MaaError::FrameworkError(-1))
830 }
831 }
832
833 #[cfg(feature = "win32")]
835 pub fn new_gamepad(
836 hwnd: *mut c_void,
837 gamepad_type: crate::common::GamepadType,
838 screencap_method: crate::common::Win32ScreencapMethod,
839 ) -> MaaResult<Self> {
840 let handle = unsafe {
841 sys::MaaGamepadControllerCreate(hwnd, gamepad_type as u64, screencap_method.bits())
842 };
843 Self::from_handle(handle)
844 }
845
846 pub fn add_sink<F>(&self, callback: F) -> MaaResult<sys::MaaSinkId>
850 where
851 F: Fn(&str, &str) + Send + Sync + 'static,
852 {
853 let (cb_fn, cb_arg) = crate::callback::EventCallback::new(callback);
854 let sink_id =
855 unsafe { sys::MaaControllerAddSink(self.inner.handle.as_ptr(), cb_fn, cb_arg) };
856 if sink_id != 0 {
857 self.inner
858 .callbacks
859 .lock()
860 .unwrap()
861 .insert(sink_id, cb_arg as usize);
862 Ok(sink_id)
863 } else {
864 unsafe { crate::callback::EventCallback::drop_callback(cb_arg) };
865 Err(MaaError::FrameworkError(0))
866 }
867 }
868
869 pub fn add_event_sink(
881 &self,
882 sink: Box<dyn crate::event_sink::EventSink>,
883 ) -> MaaResult<sys::MaaSinkId> {
884 let handle_id = self.inner.handle.as_ptr() as crate::common::MaaId;
885 let (cb, arg) = crate::callback::EventCallback::new_sink(handle_id, sink);
886 let id = unsafe { sys::MaaControllerAddSink(self.inner.handle.as_ptr(), cb, arg) };
887 if id > 0 {
888 self.inner
889 .event_sinks
890 .lock()
891 .unwrap()
892 .insert(id, arg as usize);
893 Ok(id)
894 } else {
895 unsafe { crate::callback::EventCallback::drop_sink(arg) };
896 Err(MaaError::FrameworkError(0))
897 }
898 }
899
900 pub fn remove_sink(&self, sink_id: sys::MaaSinkId) {
901 unsafe { sys::MaaControllerRemoveSink(self.inner.handle.as_ptr(), sink_id) };
902 if let Some(ptr) = self.inner.callbacks.lock().unwrap().remove(&sink_id) {
903 unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
904 } else if let Some(ptr) = self.inner.event_sinks.lock().unwrap().remove(&sink_id) {
905 unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
906 }
907 }
908
909 pub fn clear_sinks(&self) {
910 unsafe { sys::MaaControllerClearSinks(self.inner.handle.as_ptr()) };
911 let mut callbacks = self.inner.callbacks.lock().unwrap();
912 for (_, ptr) in callbacks.drain() {
913 unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
914 }
915 let mut event_sinks = self.inner.event_sinks.lock().unwrap();
916 for (_, ptr) in event_sinks.drain() {
917 unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
918 }
919 }
920}
921
922impl Drop for ControllerInner {
923 fn drop(&mut self) {
924 unsafe {
925 if self.owns_handle {
926 sys::MaaControllerClearSinks(self.handle.as_ptr());
927 let mut callbacks = self.callbacks.lock().unwrap();
928 for (_, ptr) in callbacks.drain() {
929 crate::callback::EventCallback::drop_callback(ptr as *mut c_void);
930 }
931 let mut event_sinks = self.event_sinks.lock().unwrap();
932 for (_, ptr) in event_sinks.drain() {
933 crate::callback::EventCallback::drop_sink(ptr as *mut c_void);
934 }
935 sys::MaaControllerDestroy(self.handle.as_ptr());
936 }
937 }
938 }
939}
940
941#[cfg(feature = "adb")]
945pub struct AdbControllerBuilder {
946 adb_path: String,
947 address: String,
948 screencap_methods: sys::MaaAdbScreencapMethod,
949 input_methods: sys::MaaAdbInputMethod,
950 config: String,
951 agent_path: String,
952}
953
954#[cfg(feature = "adb")]
955impl AdbControllerBuilder {
956 pub fn new(adb_path: &str, address: &str) -> Self {
958 Self {
959 adb_path: adb_path.to_string(),
960 address: address.to_string(),
961 screencap_methods: sys::MaaAdbScreencapMethod_Default as sys::MaaAdbScreencapMethod,
962 input_methods: sys::MaaAdbInputMethod_Default as sys::MaaAdbInputMethod,
963 config: "{}".to_string(),
964 agent_path: String::new(),
965 }
966 }
967
968 pub fn screencap_methods(mut self, methods: sys::MaaAdbScreencapMethod) -> Self {
970 self.screencap_methods = methods;
971 self
972 }
973
974 pub fn input_methods(mut self, methods: sys::MaaAdbInputMethod) -> Self {
976 self.input_methods = methods;
977 self
978 }
979
980 pub fn config(mut self, config: &str) -> Self {
982 self.config = config.to_string();
983 self
984 }
985
986 pub fn agent_path(mut self, path: &str) -> Self {
988 self.agent_path = path.to_string();
989 self
990 }
991
992 pub fn build(self) -> MaaResult<Controller> {
994 Controller::create_adb(
995 &self.adb_path,
996 &self.address,
997 self.screencap_methods,
998 self.input_methods,
999 &self.config,
1000 &self.agent_path,
1001 )
1002 }
1003}
1004
1005pub struct ControllerRef<'a> {
1011 handle: *mut sys::MaaController,
1012 _marker: std::marker::PhantomData<&'a ()>,
1013}
1014
1015impl<'a> std::fmt::Debug for ControllerRef<'a> {
1016 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1017 f.debug_struct("ControllerRef")
1018 .field("handle", &self.handle)
1019 .finish()
1020 }
1021}
1022
1023impl<'a> ControllerRef<'a> {
1024 pub(crate) fn from_ptr(handle: *mut sys::MaaController) -> Option<Self> {
1025 if handle.is_null() {
1026 None
1027 } else {
1028 Some(Self {
1029 handle,
1030 _marker: std::marker::PhantomData,
1031 })
1032 }
1033 }
1034
1035 pub fn connected(&self) -> bool {
1037 unsafe { sys::MaaControllerConnected(self.handle) != 0 }
1038 }
1039
1040 pub fn uuid(&self) -> MaaResult<String> {
1042 let buffer = crate::buffer::MaaStringBuffer::new()?;
1043 let ret = unsafe { sys::MaaControllerGetUuid(self.handle, buffer.as_ptr()) };
1044 if ret != 0 {
1045 Ok(buffer.to_string())
1046 } else {
1047 Err(MaaError::FrameworkError(0))
1048 }
1049 }
1050
1051 pub fn info(&self) -> MaaResult<serde_json::Value> {
1053 let buffer = crate::buffer::MaaStringBuffer::new()?;
1054 let ret = unsafe { sys::MaaControllerGetInfo(self.handle, buffer.as_ptr()) };
1055 if ret != 0 {
1056 serde_json::from_str(&buffer.to_string()).map_err(|e| {
1057 MaaError::InvalidArgument(format!("Failed to parse controller info: {}", e))
1058 })
1059 } else {
1060 Err(MaaError::FrameworkError(0))
1061 }
1062 }
1063
1064 pub fn resolution(&self) -> MaaResult<(i32, i32)> {
1066 let mut width: i32 = 0;
1067 let mut height: i32 = 0;
1068 let ret = unsafe { sys::MaaControllerGetResolution(self.handle, &mut width, &mut height) };
1069 if ret != 0 {
1070 Ok((width, height))
1071 } else {
1072 Err(MaaError::FrameworkError(0))
1073 }
1074 }
1075
1076 pub fn status(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
1078 let s = unsafe { sys::MaaControllerStatus(self.handle, ctrl_id) };
1079 common::MaaStatus(s)
1080 }
1081
1082 pub fn wait(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
1084 let s = unsafe { sys::MaaControllerWait(self.handle, ctrl_id) };
1085 common::MaaStatus(s)
1086 }
1087
1088 pub fn cached_image(&self) -> MaaResult<crate::buffer::MaaImageBuffer> {
1090 let buffer = crate::buffer::MaaImageBuffer::new()?;
1091 let ret = unsafe { sys::MaaControllerCachedImage(self.handle, buffer.as_ptr()) };
1092 if ret != 0 {
1093 Ok(buffer)
1094 } else {
1095 Err(MaaError::FrameworkError(0))
1096 }
1097 }
1098
1099 pub fn raw(&self) -> *mut sys::MaaController {
1101 self.handle
1102 }
1103}