1use crate::{MaaError, MaaResult, common, sys};
4use std::collections::HashMap;
5use std::ffi::CString;
6use std::os::raw::c_void;
7use std::ptr::NonNull;
8use std::sync::{Arc, Mutex};
9
10#[derive(Clone)]
20pub struct Controller {
21 inner: Arc<ControllerInner>,
22}
23
24struct ControllerInner {
25 handle: NonNull<sys::MaaController>,
26 owns_handle: bool,
27 _retained_handles: Vec<Arc<ControllerInner>>,
28 callbacks: Mutex<HashMap<sys::MaaSinkId, usize>>,
29 event_sinks: Mutex<HashMap<sys::MaaSinkId, usize>>,
30}
31
32unsafe impl Send for ControllerInner {}
33unsafe impl Sync for ControllerInner {}
34
35unsafe impl Send for Controller {}
37unsafe impl Sync for Controller {}
38
39impl std::fmt::Debug for Controller {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 f.debug_struct("Controller")
42 .field("handle", &self.inner.handle)
43 .finish()
44 }
45}
46
47impl Controller {
48 #[cfg(feature = "adb")]
56 pub fn new_adb(
57 adb_path: &str,
58 address: &str,
59 config: &str,
60 agent_path: &str,
61 ) -> MaaResult<Self> {
62 Self::create_adb(
63 adb_path,
64 address,
65 sys::MaaAdbScreencapMethod_Default as sys::MaaAdbScreencapMethod,
66 sys::MaaAdbInputMethod_Default as sys::MaaAdbInputMethod,
67 config,
68 agent_path,
69 )
70 }
71
72 #[cfg(feature = "adb")]
74 fn resolve_agent_path(agent_path: &str) -> MaaResult<String> {
75 if !agent_path.is_empty() {
76 return Ok(agent_path.to_string());
77 }
78 let cur = std::env::current_dir().map_err(|e| {
79 MaaError::InvalidArgument(format!("agent_path empty and current_dir failed: {}", e))
80 })?;
81 let s = cur.to_str().ok_or_else(|| {
82 MaaError::InvalidArgument(
83 "agent_path empty and current directory is not valid UTF-8".to_string(),
84 )
85 })?;
86 Ok(s.to_string())
87 }
88
89 #[cfg(feature = "adb")]
90 pub(crate) fn create_adb(
91 adb_path: &str,
92 address: &str,
93 screencap_method: sys::MaaAdbScreencapMethod,
94 input_method: sys::MaaAdbInputMethod,
95 config: &str,
96 agent_path: &str,
97 ) -> MaaResult<Self> {
98 let path = Self::resolve_agent_path(agent_path)?;
99 let c_adb = CString::new(adb_path)?;
100 let c_addr = CString::new(address)?;
101 let c_cfg = CString::new(config)?;
102 let c_agent = CString::new(path.as_str())?;
103
104 let handle = unsafe {
105 sys::MaaAdbControllerCreate(
106 c_adb.as_ptr(),
107 c_addr.as_ptr(),
108 screencap_method,
109 input_method,
110 c_cfg.as_ptr(),
111 c_agent.as_ptr(),
112 )
113 };
114
115 if let Some(ptr) = NonNull::new(handle) {
116 Ok(Self::new_owned(ptr))
117 } else {
118 Err(MaaError::FrameworkError(-1))
119 }
120 }
121
122 #[cfg(feature = "win32")]
124 pub fn new_win32(
125 hwnd: *mut c_void,
126 screencap_method: sys::MaaWin32ScreencapMethod,
127 mouse_method: sys::MaaWin32InputMethod,
128 keyboard_method: sys::MaaWin32InputMethod,
129 ) -> MaaResult<Self> {
130 let handle = unsafe {
131 sys::MaaWin32ControllerCreate(hwnd, screencap_method, mouse_method, keyboard_method)
132 };
133
134 Self::from_handle(handle)
135 }
136
137 pub fn new_macos(
144 window_id: u32,
145 screencap_method: sys::MaaMacOSScreencapMethod,
146 input_method: sys::MaaMacOSInputMethod,
147 ) -> MaaResult<Self> {
148 let handle =
149 unsafe { sys::MaaMacOSControllerCreate(window_id, screencap_method, input_method) };
150
151 Self::from_handle(handle)
152 }
153
154 pub fn new_playcover(address: &str, uuid: &str) -> MaaResult<Self> {
157 let c_addr = CString::new(address)?;
158 let c_uuid = CString::new(uuid)?;
159 let handle = unsafe { sys::MaaPlayCoverControllerCreate(c_addr.as_ptr(), c_uuid.as_ptr()) };
160
161 Self::from_handle(handle)
162 }
163
164 pub fn new_wlroots(wlr_socket_path: &str) -> MaaResult<Self> {
169 let c_path = CString::new(wlr_socket_path)?;
170 let handle = unsafe { sys::MaaWlRootsControllerCreate(c_path.as_ptr()) };
171
172 Self::from_handle(handle)
173 }
174
175 #[cfg(feature = "custom")]
177 pub fn new_custom<T: crate::custom_controller::CustomControllerCallback + 'static>(
178 callback: T,
179 ) -> MaaResult<Self> {
180 let boxed: Box<Box<dyn crate::custom_controller::CustomControllerCallback>> =
181 Box::new(Box::new(callback));
182 let cb_ptr = Box::into_raw(boxed) as *mut c_void;
183 let callbacks = crate::custom_controller::get_callbacks();
184 let handle =
185 unsafe { sys::MaaCustomControllerCreate(callbacks as *const _ as *mut _, cb_ptr) };
186
187 NonNull::new(handle).map(Self::new_owned).ok_or_else(|| {
188 unsafe {
189 let _ = Box::from_raw(
190 cb_ptr as *mut Box<dyn crate::custom_controller::CustomControllerCallback>,
191 );
192 }
193 MaaError::FrameworkError(-1)
194 })
195 }
196
197 fn from_handle(handle: *mut sys::MaaController) -> MaaResult<Self> {
199 if let Some(ptr) = NonNull::new(handle) {
200 Ok(Self::new_owned(ptr))
201 } else {
202 Err(MaaError::FrameworkError(-1))
203 }
204 }
205
206 fn new_owned(handle: NonNull<sys::MaaController>) -> Self {
207 Self::new_with_retained(handle, Vec::new())
208 }
209
210 fn new_with_retained(
211 handle: NonNull<sys::MaaController>,
212 retained_handles: Vec<Arc<ControllerInner>>,
213 ) -> Self {
214 Self {
215 inner: Arc::new(ControllerInner {
216 handle,
217 owns_handle: true,
218 _retained_handles: retained_handles,
219 callbacks: Mutex::new(HashMap::new()),
220 event_sinks: Mutex::new(HashMap::new()),
221 }),
222 }
223 }
224
225 pub fn post_click(&self, x: i32, y: i32) -> MaaResult<common::MaaId> {
227 let id = unsafe { sys::MaaControllerPostClick(self.inner.handle.as_ptr(), x, y) };
228 Ok(id)
229 }
230
231 pub fn post_screencap(&self) -> MaaResult<common::MaaId> {
233 let id = unsafe { sys::MaaControllerPostScreencap(self.inner.handle.as_ptr()) };
234 Ok(id)
235 }
236
237 pub fn post_click_v2(
244 &self,
245 x: i32,
246 y: i32,
247 contact: i32,
248 pressure: i32,
249 ) -> MaaResult<common::MaaId> {
250 let id = unsafe {
251 sys::MaaControllerPostClickV2(self.inner.handle.as_ptr(), x, y, contact, pressure)
252 };
253 Ok(id)
254 }
255
256 pub fn post_swipe(
263 &self,
264 x1: i32,
265 y1: i32,
266 x2: i32,
267 y2: i32,
268 duration: i32,
269 ) -> MaaResult<common::MaaId> {
270 let id = unsafe {
271 sys::MaaControllerPostSwipe(self.inner.handle.as_ptr(), x1, y1, x2, y2, duration)
272 };
273 Ok(id)
274 }
275
276 pub fn post_click_key(&self, keycode: i32) -> MaaResult<common::MaaId> {
281 let id = unsafe { sys::MaaControllerPostClickKey(self.inner.handle.as_ptr(), keycode) };
282 Ok(id)
283 }
284
285 #[deprecated(note = "Use post_click_key instead")]
287 pub fn post_press(&self, keycode: i32) -> MaaResult<common::MaaId> {
288 self.post_click_key(keycode)
289 }
290
291 pub fn post_input_text(&self, text: &str) -> MaaResult<common::MaaId> {
296 let c_text = CString::new(text)?;
297 let id =
298 unsafe { sys::MaaControllerPostInputText(self.inner.handle.as_ptr(), c_text.as_ptr()) };
299 Ok(id)
300 }
301
302 pub fn post_shell(&self, cmd: &str, timeout: i64) -> MaaResult<common::MaaId> {
308 let c_cmd = CString::new(cmd)?;
309 let id = unsafe {
310 sys::MaaControllerPostShell(self.inner.handle.as_ptr(), c_cmd.as_ptr(), timeout)
311 };
312 Ok(id)
313 }
314
315 pub fn post_touch_down(
322 &self,
323 contact: i32,
324 x: i32,
325 y: i32,
326 pressure: i32,
327 ) -> MaaResult<common::MaaId> {
328 let id = unsafe {
329 sys::MaaControllerPostTouchDown(self.inner.handle.as_ptr(), contact, x, y, pressure)
330 };
331 Ok(id)
332 }
333
334 pub fn post_touch_move(
341 &self,
342 contact: i32,
343 x: i32,
344 y: i32,
345 pressure: i32,
346 ) -> MaaResult<common::MaaId> {
347 let id = unsafe {
348 sys::MaaControllerPostTouchMove(self.inner.handle.as_ptr(), contact, x, y, pressure)
349 };
350 Ok(id)
351 }
352
353 pub fn post_touch_up(&self, contact: i32) -> MaaResult<common::MaaId> {
358 let id = unsafe { sys::MaaControllerPostTouchUp(self.inner.handle.as_ptr(), contact) };
359 Ok(id)
360 }
361
362 pub fn post_relative_move(&self, dx: i32, dy: i32) -> MaaResult<common::MaaId> {
368 let id = unsafe { sys::MaaControllerPostRelativeMove(self.inner.handle.as_ptr(), dx, dy) };
369 Ok(id)
370 }
371
372 #[inline]
374 pub fn raw(&self) -> *mut sys::MaaController {
375 self.inner.handle.as_ptr()
376 }
377
378 pub fn post_connection(&self) -> MaaResult<common::MaaId> {
384 let id = unsafe { sys::MaaControllerPostConnection(self.inner.handle.as_ptr()) };
385 Ok(id)
386 }
387
388 pub fn connected(&self) -> bool {
390 unsafe { sys::MaaControllerConnected(self.inner.handle.as_ptr()) != 0 }
391 }
392
393 pub fn uuid(&self) -> MaaResult<String> {
395 let buffer = crate::buffer::MaaStringBuffer::new()?;
396 let ret = unsafe { sys::MaaControllerGetUuid(self.inner.handle.as_ptr(), buffer.as_ptr()) };
397 if ret != 0 {
398 Ok(buffer.to_string())
399 } else {
400 Err(MaaError::FrameworkError(0))
401 }
402 }
403
404 pub fn info(&self) -> MaaResult<serde_json::Value> {
409 let buffer = crate::buffer::MaaStringBuffer::new()?;
410 let ret = unsafe { sys::MaaControllerGetInfo(self.inner.handle.as_ptr(), buffer.as_ptr()) };
411 if ret != 0 {
412 serde_json::from_str(&buffer.to_string()).map_err(|e| {
413 MaaError::InvalidArgument(format!("Failed to parse controller info: {}", e))
414 })
415 } else {
416 Err(MaaError::FrameworkError(0))
417 }
418 }
419
420 pub fn resolution(&self) -> MaaResult<(i32, i32)> {
422 let mut width: i32 = 0;
423 let mut height: i32 = 0;
424 let ret = unsafe {
425 sys::MaaControllerGetResolution(self.inner.handle.as_ptr(), &mut width, &mut height)
426 };
427 if ret != 0 {
428 Ok((width, height))
429 } else {
430 Err(MaaError::FrameworkError(0))
431 }
432 }
433
434 pub fn post_swipe_v2(
445 &self,
446 x1: i32,
447 y1: i32,
448 x2: i32,
449 y2: i32,
450 duration: i32,
451 contact: i32,
452 pressure: i32,
453 ) -> MaaResult<common::MaaId> {
454 let id = unsafe {
455 sys::MaaControllerPostSwipeV2(
456 self.inner.handle.as_ptr(),
457 x1,
458 y1,
459 x2,
460 y2,
461 duration,
462 contact,
463 pressure,
464 )
465 };
466 Ok(id)
467 }
468
469 pub fn post_key_down(&self, keycode: i32) -> MaaResult<common::MaaId> {
473 let id = unsafe { sys::MaaControllerPostKeyDown(self.inner.handle.as_ptr(), keycode) };
474 Ok(id)
475 }
476
477 pub fn post_key_up(&self, keycode: i32) -> MaaResult<common::MaaId> {
479 let id = unsafe { sys::MaaControllerPostKeyUp(self.inner.handle.as_ptr(), keycode) };
480 Ok(id)
481 }
482
483 pub fn post_start_app(&self, intent: &str) -> MaaResult<common::MaaId> {
490 let c_intent = CString::new(intent)?;
491 let id = unsafe {
492 sys::MaaControllerPostStartApp(self.inner.handle.as_ptr(), c_intent.as_ptr())
493 };
494 Ok(id)
495 }
496
497 pub fn post_stop_app(&self, intent: &str) -> MaaResult<common::MaaId> {
502 let c_intent = CString::new(intent)?;
503 let id =
504 unsafe { sys::MaaControllerPostStopApp(self.inner.handle.as_ptr(), c_intent.as_ptr()) };
505 Ok(id)
506 }
507
508 pub fn post_scroll(&self, dx: i32, dy: i32) -> MaaResult<common::MaaId> {
516 let id = unsafe { sys::MaaControllerPostScroll(self.inner.handle.as_ptr(), dx, dy) };
517 Ok(id)
518 }
519
520 pub fn post_inactive(&self) -> MaaResult<common::MaaId> {
527 let id = unsafe { sys::MaaControllerPostInactive(self.inner.handle.as_ptr()) };
528 Ok(id)
529 }
530
531 pub fn cached_image(&self) -> MaaResult<crate::buffer::MaaImageBuffer> {
535 let buffer = crate::buffer::MaaImageBuffer::new()?;
536 let ret =
537 unsafe { sys::MaaControllerCachedImage(self.inner.handle.as_ptr(), buffer.as_ptr()) };
538 if ret != 0 {
539 Ok(buffer)
540 } else {
541 Err(MaaError::FrameworkError(0))
542 }
543 }
544
545 pub fn shell_output(&self) -> MaaResult<String> {
549 let buffer = crate::buffer::MaaStringBuffer::new()?;
550 let ret = unsafe {
551 sys::MaaControllerGetShellOutput(self.inner.handle.as_ptr(), buffer.as_ptr())
552 };
553 if ret != 0 {
554 Ok(buffer.to_string())
555 } else {
556 Err(MaaError::FrameworkError(0))
557 }
558 }
559
560 pub fn status(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
564 let s = unsafe { sys::MaaControllerStatus(self.inner.handle.as_ptr(), ctrl_id) };
565 common::MaaStatus(s)
566 }
567
568 pub fn wait(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
570 let s = unsafe { sys::MaaControllerWait(self.inner.handle.as_ptr(), ctrl_id) };
571 common::MaaStatus(s)
572 }
573
574 pub fn set_screenshot_target_long_side(&self, long_side: i32) -> MaaResult<()> {
578 let mut val = long_side;
579 let ret = unsafe {
580 sys::MaaControllerSetOption(
581 self.inner.handle.as_ptr(),
582 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotTargetLongSide as i32,
583 &mut val as *mut _ as *mut c_void,
584 std::mem::size_of::<i32>() as u64,
585 )
586 };
587 common::check_bool(ret)
588 }
589
590 pub fn set_screenshot_target_short_side(&self, short_side: i32) -> MaaResult<()> {
592 let mut val = short_side;
593 let ret = unsafe {
594 sys::MaaControllerSetOption(
595 self.inner.handle.as_ptr(),
596 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotTargetShortSide as i32,
597 &mut val as *mut _ as *mut c_void,
598 std::mem::size_of::<i32>() as u64,
599 )
600 };
601 common::check_bool(ret)
602 }
603
604 pub fn set_screenshot_use_raw_size(&self, enable: bool) -> MaaResult<()> {
606 let mut val: u8 = if enable { 1 } else { 0 };
607 let ret = unsafe {
608 sys::MaaControllerSetOption(
609 self.inner.handle.as_ptr(),
610 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotUseRawSize as i32,
611 &mut val as *mut _ as *mut c_void,
612 std::mem::size_of::<u8>() as u64,
613 )
614 };
615 common::check_bool(ret)
616 }
617
618 pub fn new_dbg(read_path: &str) -> MaaResult<Self> {
621 let c_read = CString::new(read_path)?;
622 let handle = unsafe { sys::MaaDbgControllerCreate(c_read.as_ptr()) };
623 Self::from_handle(handle)
624 }
625
626 pub fn new_replay(recording_path: &str) -> MaaResult<Self> {
628 let c_recording = CString::new(recording_path)?;
629 let handle = unsafe { sys::MaaReplayControllerCreate(c_recording.as_ptr()) };
630 Self::from_handle(handle)
631 }
632
633 pub fn new_record(inner: &Controller, recording_path: &str) -> MaaResult<Self> {
635 let c_recording = CString::new(recording_path)?;
636 let handle = unsafe { sys::MaaRecordControllerCreate(inner.raw(), c_recording.as_ptr()) };
637
638 if let Some(ptr) = NonNull::new(handle) {
639 Ok(Self::new_with_retained(ptr, vec![Arc::clone(&inner.inner)]))
640 } else {
641 Err(MaaError::FrameworkError(-1))
642 }
643 }
644
645 #[cfg(feature = "win32")]
647 pub fn new_gamepad(
648 hwnd: *mut c_void,
649 gamepad_type: crate::common::GamepadType,
650 screencap_method: crate::common::Win32ScreencapMethod,
651 ) -> MaaResult<Self> {
652 let handle = unsafe {
653 sys::MaaGamepadControllerCreate(hwnd, gamepad_type as u64, screencap_method.bits())
654 };
655 Self::from_handle(handle)
656 }
657
658 pub fn add_sink<F>(&self, callback: F) -> MaaResult<sys::MaaSinkId>
662 where
663 F: Fn(&str, &str) + Send + Sync + 'static,
664 {
665 let (cb_fn, cb_arg) = crate::callback::EventCallback::new(callback);
666 let sink_id =
667 unsafe { sys::MaaControllerAddSink(self.inner.handle.as_ptr(), cb_fn, cb_arg) };
668 if sink_id != 0 {
669 self.inner
670 .callbacks
671 .lock()
672 .unwrap()
673 .insert(sink_id, cb_arg as usize);
674 Ok(sink_id)
675 } else {
676 unsafe { crate::callback::EventCallback::drop_callback(cb_arg) };
677 Err(MaaError::FrameworkError(0))
678 }
679 }
680
681 pub fn add_event_sink(
693 &self,
694 sink: Box<dyn crate::event_sink::EventSink>,
695 ) -> MaaResult<sys::MaaSinkId> {
696 let handle_id = self.inner.handle.as_ptr() as crate::common::MaaId;
697 let (cb, arg) = crate::callback::EventCallback::new_sink(handle_id, sink);
698 let id = unsafe { sys::MaaControllerAddSink(self.inner.handle.as_ptr(), cb, arg) };
699 if id > 0 {
700 self.inner
701 .event_sinks
702 .lock()
703 .unwrap()
704 .insert(id, arg as usize);
705 Ok(id)
706 } else {
707 unsafe { crate::callback::EventCallback::drop_sink(arg) };
708 Err(MaaError::FrameworkError(0))
709 }
710 }
711
712 pub fn remove_sink(&self, sink_id: sys::MaaSinkId) {
713 unsafe { sys::MaaControllerRemoveSink(self.inner.handle.as_ptr(), sink_id) };
714 if let Some(ptr) = self.inner.callbacks.lock().unwrap().remove(&sink_id) {
715 unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
716 } else if let Some(ptr) = self.inner.event_sinks.lock().unwrap().remove(&sink_id) {
717 unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
718 }
719 }
720
721 pub fn clear_sinks(&self) {
722 unsafe { sys::MaaControllerClearSinks(self.inner.handle.as_ptr()) };
723 let mut callbacks = self.inner.callbacks.lock().unwrap();
724 for (_, ptr) in callbacks.drain() {
725 unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
726 }
727 let mut event_sinks = self.inner.event_sinks.lock().unwrap();
728 for (_, ptr) in event_sinks.drain() {
729 unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
730 }
731 }
732}
733
734impl Drop for ControllerInner {
735 fn drop(&mut self) {
736 unsafe {
737 if self.owns_handle {
738 sys::MaaControllerClearSinks(self.handle.as_ptr());
739 let mut callbacks = self.callbacks.lock().unwrap();
740 for (_, ptr) in callbacks.drain() {
741 crate::callback::EventCallback::drop_callback(ptr as *mut c_void);
742 }
743 let mut event_sinks = self.event_sinks.lock().unwrap();
744 for (_, ptr) in event_sinks.drain() {
745 crate::callback::EventCallback::drop_sink(ptr as *mut c_void);
746 }
747 sys::MaaControllerDestroy(self.handle.as_ptr());
748 }
749 }
750 }
751}
752
753#[cfg(feature = "adb")]
757pub struct AdbControllerBuilder {
758 adb_path: String,
759 address: String,
760 screencap_methods: sys::MaaAdbScreencapMethod,
761 input_methods: sys::MaaAdbInputMethod,
762 config: String,
763 agent_path: String,
764}
765
766#[cfg(feature = "adb")]
767impl AdbControllerBuilder {
768 pub fn new(adb_path: &str, address: &str) -> Self {
770 Self {
771 adb_path: adb_path.to_string(),
772 address: address.to_string(),
773 screencap_methods: sys::MaaAdbScreencapMethod_Default as sys::MaaAdbScreencapMethod,
774 input_methods: sys::MaaAdbInputMethod_Default as sys::MaaAdbInputMethod,
775 config: "{}".to_string(),
776 agent_path: String::new(),
777 }
778 }
779
780 pub fn screencap_methods(mut self, methods: sys::MaaAdbScreencapMethod) -> Self {
782 self.screencap_methods = methods;
783 self
784 }
785
786 pub fn input_methods(mut self, methods: sys::MaaAdbInputMethod) -> Self {
788 self.input_methods = methods;
789 self
790 }
791
792 pub fn config(mut self, config: &str) -> Self {
794 self.config = config.to_string();
795 self
796 }
797
798 pub fn agent_path(mut self, path: &str) -> Self {
800 self.agent_path = path.to_string();
801 self
802 }
803
804 pub fn build(self) -> MaaResult<Controller> {
806 Controller::create_adb(
807 &self.adb_path,
808 &self.address,
809 self.screencap_methods,
810 self.input_methods,
811 &self.config,
812 &self.agent_path,
813 )
814 }
815}
816
817pub struct ControllerRef<'a> {
823 handle: *mut sys::MaaController,
824 _marker: std::marker::PhantomData<&'a ()>,
825}
826
827impl<'a> std::fmt::Debug for ControllerRef<'a> {
828 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
829 f.debug_struct("ControllerRef")
830 .field("handle", &self.handle)
831 .finish()
832 }
833}
834
835impl<'a> ControllerRef<'a> {
836 pub(crate) fn from_ptr(handle: *mut sys::MaaController) -> Option<Self> {
837 if handle.is_null() {
838 None
839 } else {
840 Some(Self {
841 handle,
842 _marker: std::marker::PhantomData,
843 })
844 }
845 }
846
847 pub fn connected(&self) -> bool {
849 unsafe { sys::MaaControllerConnected(self.handle) != 0 }
850 }
851
852 pub fn uuid(&self) -> MaaResult<String> {
854 let buffer = crate::buffer::MaaStringBuffer::new()?;
855 let ret = unsafe { sys::MaaControllerGetUuid(self.handle, buffer.as_ptr()) };
856 if ret != 0 {
857 Ok(buffer.to_string())
858 } else {
859 Err(MaaError::FrameworkError(0))
860 }
861 }
862
863 pub fn info(&self) -> MaaResult<serde_json::Value> {
865 let buffer = crate::buffer::MaaStringBuffer::new()?;
866 let ret = unsafe { sys::MaaControllerGetInfo(self.handle, buffer.as_ptr()) };
867 if ret != 0 {
868 serde_json::from_str(&buffer.to_string()).map_err(|e| {
869 MaaError::InvalidArgument(format!("Failed to parse controller info: {}", e))
870 })
871 } else {
872 Err(MaaError::FrameworkError(0))
873 }
874 }
875
876 pub fn resolution(&self) -> MaaResult<(i32, i32)> {
878 let mut width: i32 = 0;
879 let mut height: i32 = 0;
880 let ret = unsafe { sys::MaaControllerGetResolution(self.handle, &mut width, &mut height) };
881 if ret != 0 {
882 Ok((width, height))
883 } else {
884 Err(MaaError::FrameworkError(0))
885 }
886 }
887
888 pub fn status(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
890 let s = unsafe { sys::MaaControllerStatus(self.handle, ctrl_id) };
891 common::MaaStatus(s)
892 }
893
894 pub fn wait(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
896 let s = unsafe { sys::MaaControllerWait(self.handle, ctrl_id) };
897 common::MaaStatus(s)
898 }
899
900 pub fn cached_image(&self) -> MaaResult<crate::buffer::MaaImageBuffer> {
902 let buffer = crate::buffer::MaaImageBuffer::new()?;
903 let ret = unsafe { sys::MaaControllerCachedImage(self.handle, buffer.as_ptr()) };
904 if ret != 0 {
905 Ok(buffer)
906 } else {
907 Err(MaaError::FrameworkError(0))
908 }
909 }
910
911 pub fn raw(&self) -> *mut sys::MaaController {
913 self.handle
914 }
915}