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 callbacks: Mutex<HashMap<sys::MaaSinkId, usize>>,
28 event_sinks: Mutex<HashMap<sys::MaaSinkId, usize>>,
29}
30
31unsafe impl Send for ControllerInner {}
32unsafe impl Sync for ControllerInner {}
33
34unsafe impl Send for Controller {}
36unsafe impl Sync for Controller {}
37
38impl std::fmt::Debug for Controller {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 f.debug_struct("Controller")
41 .field("handle", &self.inner.handle)
42 .finish()
43 }
44}
45
46impl Controller {
47 #[cfg(feature = "adb")]
55 pub fn new_adb(
56 adb_path: &str,
57 address: &str,
58 config: &str,
59 agent_path: &str,
60 ) -> MaaResult<Self> {
61 Self::create_adb(
62 adb_path,
63 address,
64 sys::MaaAdbScreencapMethod_Default as sys::MaaAdbScreencapMethod,
65 sys::MaaAdbInputMethod_Default as sys::MaaAdbInputMethod,
66 config,
67 agent_path,
68 )
69 }
70
71 #[cfg(feature = "adb")]
73 fn resolve_agent_path(agent_path: &str) -> MaaResult<String> {
74 if !agent_path.is_empty() {
75 return Ok(agent_path.to_string());
76 }
77 let cur = std::env::current_dir().map_err(|e| {
78 MaaError::InvalidArgument(format!("agent_path empty and current_dir failed: {}", e))
79 })?;
80 let s = cur.to_str().ok_or_else(|| {
81 MaaError::InvalidArgument(
82 "agent_path empty and current directory is not valid UTF-8".to_string(),
83 )
84 })?;
85 Ok(s.to_string())
86 }
87
88 #[cfg(feature = "adb")]
89 pub(crate) fn create_adb(
90 adb_path: &str,
91 address: &str,
92 screencap_method: sys::MaaAdbScreencapMethod,
93 input_method: sys::MaaAdbInputMethod,
94 config: &str,
95 agent_path: &str,
96 ) -> MaaResult<Self> {
97 let path = Self::resolve_agent_path(agent_path)?;
98 let c_adb = CString::new(adb_path)?;
99 let c_addr = CString::new(address)?;
100 let c_cfg = CString::new(config)?;
101 let c_agent = CString::new(path.as_str())?;
102
103 let handle = unsafe {
104 sys::MaaAdbControllerCreate(
105 c_adb.as_ptr(),
106 c_addr.as_ptr(),
107 screencap_method,
108 input_method,
109 c_cfg.as_ptr(),
110 c_agent.as_ptr(),
111 )
112 };
113
114 if let Some(ptr) = NonNull::new(handle) {
115 Ok(Self {
116 inner: Arc::new(ControllerInner {
117 handle: ptr,
118 owns_handle: true,
119 callbacks: Mutex::new(HashMap::new()),
120 event_sinks: Mutex::new(HashMap::new()),
121 }),
122 })
123 } else {
124 Err(MaaError::FrameworkError(-1))
125 }
126 }
127
128 #[cfg(feature = "win32")]
130 pub fn new_win32(
131 hwnd: *mut c_void,
132 screencap_method: sys::MaaWin32ScreencapMethod,
133 mouse_method: sys::MaaWin32InputMethod,
134 keyboard_method: sys::MaaWin32InputMethod,
135 ) -> MaaResult<Self> {
136 let handle = unsafe {
137 sys::MaaWin32ControllerCreate(hwnd, screencap_method, mouse_method, keyboard_method)
138 };
139
140 Self::from_handle(handle)
141 }
142
143 pub fn new_playcover(address: &str, uuid: &str) -> MaaResult<Self> {
146 let c_addr = CString::new(address)?;
147 let c_uuid = CString::new(uuid)?;
148 let handle = unsafe { sys::MaaPlayCoverControllerCreate(c_addr.as_ptr(), c_uuid.as_ptr()) };
149
150 Self::from_handle(handle)
151 }
152
153 pub fn new_wlroots(wlr_socket_path: &str) -> MaaResult<Self> {
158 let c_path = CString::new(wlr_socket_path)?;
159 let handle = unsafe { sys::MaaWlRootsControllerCreate(c_path.as_ptr()) };
160
161 Self::from_handle(handle)
162 }
163
164 #[cfg(feature = "custom")]
166 pub fn new_custom<T: crate::custom_controller::CustomControllerCallback + 'static>(
167 callback: T,
168 ) -> MaaResult<Self> {
169 let boxed: Box<Box<dyn crate::custom_controller::CustomControllerCallback>> =
170 Box::new(Box::new(callback));
171 let cb_ptr = Box::into_raw(boxed) as *mut c_void;
172 let callbacks = crate::custom_controller::get_callbacks();
173 let handle =
174 unsafe { sys::MaaCustomControllerCreate(callbacks as *const _ as *mut _, cb_ptr) };
175
176 NonNull::new(handle)
177 .map(|ptr| Self {
178 inner: Arc::new(ControllerInner {
179 handle: ptr,
180 owns_handle: true,
181 callbacks: Mutex::new(HashMap::new()),
182 event_sinks: Mutex::new(HashMap::new()),
183 }),
184 })
185 .ok_or_else(|| {
186 unsafe {
187 let _ = Box::from_raw(
188 cb_ptr as *mut Box<dyn crate::custom_controller::CustomControllerCallback>,
189 );
190 }
191 MaaError::FrameworkError(-1)
192 })
193 }
194
195 fn from_handle(handle: *mut sys::MaaController) -> MaaResult<Self> {
197 if let Some(ptr) = NonNull::new(handle) {
198 Ok(Self {
199 inner: Arc::new(ControllerInner {
200 handle: ptr,
201 owns_handle: true,
202 callbacks: Mutex::new(HashMap::new()),
203 event_sinks: Mutex::new(HashMap::new()),
204 }),
205 })
206 } else {
207 Err(MaaError::FrameworkError(-1))
208 }
209 }
210
211 pub fn post_click(&self, x: i32, y: i32) -> MaaResult<common::MaaId> {
213 let id = unsafe { sys::MaaControllerPostClick(self.inner.handle.as_ptr(), x, y) };
214 Ok(id)
215 }
216
217 pub fn post_screencap(&self) -> MaaResult<common::MaaId> {
219 let id = unsafe { sys::MaaControllerPostScreencap(self.inner.handle.as_ptr()) };
220 Ok(id)
221 }
222
223 pub fn post_click_v2(
230 &self,
231 x: i32,
232 y: i32,
233 contact: i32,
234 pressure: i32,
235 ) -> MaaResult<common::MaaId> {
236 let id = unsafe {
237 sys::MaaControllerPostClickV2(self.inner.handle.as_ptr(), x, y, contact, pressure)
238 };
239 Ok(id)
240 }
241
242 pub fn post_swipe(
249 &self,
250 x1: i32,
251 y1: i32,
252 x2: i32,
253 y2: i32,
254 duration: i32,
255 ) -> MaaResult<common::MaaId> {
256 let id = unsafe {
257 sys::MaaControllerPostSwipe(self.inner.handle.as_ptr(), x1, y1, x2, y2, duration)
258 };
259 Ok(id)
260 }
261
262 pub fn post_click_key(&self, keycode: i32) -> MaaResult<common::MaaId> {
267 let id = unsafe { sys::MaaControllerPostClickKey(self.inner.handle.as_ptr(), keycode) };
268 Ok(id)
269 }
270
271 #[deprecated(note = "Use post_click_key instead")]
273 pub fn post_press(&self, keycode: i32) -> MaaResult<common::MaaId> {
274 self.post_click_key(keycode)
275 }
276
277 pub fn post_input_text(&self, text: &str) -> MaaResult<common::MaaId> {
282 let c_text = CString::new(text)?;
283 let id =
284 unsafe { sys::MaaControllerPostInputText(self.inner.handle.as_ptr(), c_text.as_ptr()) };
285 Ok(id)
286 }
287
288 pub fn post_shell(&self, cmd: &str, timeout: i64) -> MaaResult<common::MaaId> {
294 let c_cmd = CString::new(cmd)?;
295 let id = unsafe {
296 sys::MaaControllerPostShell(self.inner.handle.as_ptr(), c_cmd.as_ptr(), timeout)
297 };
298 Ok(id)
299 }
300
301 pub fn post_touch_down(
308 &self,
309 contact: i32,
310 x: i32,
311 y: i32,
312 pressure: i32,
313 ) -> MaaResult<common::MaaId> {
314 let id = unsafe {
315 sys::MaaControllerPostTouchDown(self.inner.handle.as_ptr(), contact, x, y, pressure)
316 };
317 Ok(id)
318 }
319
320 pub fn post_touch_move(
327 &self,
328 contact: i32,
329 x: i32,
330 y: i32,
331 pressure: i32,
332 ) -> MaaResult<common::MaaId> {
333 let id = unsafe {
334 sys::MaaControllerPostTouchMove(self.inner.handle.as_ptr(), contact, x, y, pressure)
335 };
336 Ok(id)
337 }
338
339 pub fn post_touch_up(&self, contact: i32) -> MaaResult<common::MaaId> {
344 let id = unsafe { sys::MaaControllerPostTouchUp(self.inner.handle.as_ptr(), contact) };
345 Ok(id)
346 }
347
348 pub fn post_relative_move(&self, dx: i32, dy: i32) -> MaaResult<common::MaaId> {
354 let id =
355 unsafe { sys::MaaControllerPostRelativeMove(self.inner.handle.as_ptr(), dx, dy) };
356 Ok(id)
357 }
358
359 #[inline]
361 pub fn raw(&self) -> *mut sys::MaaController {
362 self.inner.handle.as_ptr()
363 }
364
365 pub fn post_connection(&self) -> MaaResult<common::MaaId> {
371 let id = unsafe { sys::MaaControllerPostConnection(self.inner.handle.as_ptr()) };
372 Ok(id)
373 }
374
375 pub fn connected(&self) -> bool {
377 unsafe { sys::MaaControllerConnected(self.inner.handle.as_ptr()) != 0 }
378 }
379
380 pub fn uuid(&self) -> MaaResult<String> {
382 let buffer = crate::buffer::MaaStringBuffer::new()?;
383 let ret = unsafe { sys::MaaControllerGetUuid(self.inner.handle.as_ptr(), buffer.as_ptr()) };
384 if ret != 0 {
385 Ok(buffer.to_string())
386 } else {
387 Err(MaaError::FrameworkError(0))
388 }
389 }
390
391 pub fn info(&self) -> MaaResult<serde_json::Value> {
396 let buffer = crate::buffer::MaaStringBuffer::new()?;
397 let ret = unsafe { sys::MaaControllerGetInfo(self.inner.handle.as_ptr(), buffer.as_ptr()) };
398 if ret != 0 {
399 serde_json::from_str(&buffer.to_string()).map_err(|e| {
400 MaaError::InvalidArgument(format!("Failed to parse controller info: {}", e))
401 })
402 } else {
403 Err(MaaError::FrameworkError(0))
404 }
405 }
406
407 pub fn resolution(&self) -> MaaResult<(i32, i32)> {
409 let mut width: i32 = 0;
410 let mut height: i32 = 0;
411 let ret = unsafe {
412 sys::MaaControllerGetResolution(self.inner.handle.as_ptr(), &mut width, &mut height)
413 };
414 if ret != 0 {
415 Ok((width, height))
416 } else {
417 Err(MaaError::FrameworkError(0))
418 }
419 }
420
421 pub fn post_swipe_v2(
432 &self,
433 x1: i32,
434 y1: i32,
435 x2: i32,
436 y2: i32,
437 duration: i32,
438 contact: i32,
439 pressure: i32,
440 ) -> MaaResult<common::MaaId> {
441 let id = unsafe {
442 sys::MaaControllerPostSwipeV2(
443 self.inner.handle.as_ptr(),
444 x1,
445 y1,
446 x2,
447 y2,
448 duration,
449 contact,
450 pressure,
451 )
452 };
453 Ok(id)
454 }
455
456 pub fn post_key_down(&self, keycode: i32) -> MaaResult<common::MaaId> {
460 let id = unsafe { sys::MaaControllerPostKeyDown(self.inner.handle.as_ptr(), keycode) };
461 Ok(id)
462 }
463
464 pub fn post_key_up(&self, keycode: i32) -> MaaResult<common::MaaId> {
466 let id = unsafe { sys::MaaControllerPostKeyUp(self.inner.handle.as_ptr(), keycode) };
467 Ok(id)
468 }
469
470 pub fn post_start_app(&self, intent: &str) -> MaaResult<common::MaaId> {
477 let c_intent = CString::new(intent)?;
478 let id = unsafe {
479 sys::MaaControllerPostStartApp(self.inner.handle.as_ptr(), c_intent.as_ptr())
480 };
481 Ok(id)
482 }
483
484 pub fn post_stop_app(&self, intent: &str) -> MaaResult<common::MaaId> {
489 let c_intent = CString::new(intent)?;
490 let id =
491 unsafe { sys::MaaControllerPostStopApp(self.inner.handle.as_ptr(), c_intent.as_ptr()) };
492 Ok(id)
493 }
494
495 pub fn post_scroll(&self, dx: i32, dy: i32) -> MaaResult<common::MaaId> {
503 let id = unsafe { sys::MaaControllerPostScroll(self.inner.handle.as_ptr(), dx, dy) };
504 Ok(id)
505 }
506
507 pub fn post_inactive(&self) -> MaaResult<common::MaaId> {
514 let id = unsafe { sys::MaaControllerPostInactive(self.inner.handle.as_ptr()) };
515 Ok(id)
516 }
517
518 pub fn cached_image(&self) -> MaaResult<crate::buffer::MaaImageBuffer> {
522 let buffer = crate::buffer::MaaImageBuffer::new()?;
523 let ret =
524 unsafe { sys::MaaControllerCachedImage(self.inner.handle.as_ptr(), buffer.as_ptr()) };
525 if ret != 0 {
526 Ok(buffer)
527 } else {
528 Err(MaaError::FrameworkError(0))
529 }
530 }
531
532 pub fn shell_output(&self) -> MaaResult<String> {
536 let buffer = crate::buffer::MaaStringBuffer::new()?;
537 let ret = unsafe {
538 sys::MaaControllerGetShellOutput(self.inner.handle.as_ptr(), buffer.as_ptr())
539 };
540 if ret != 0 {
541 Ok(buffer.to_string())
542 } else {
543 Err(MaaError::FrameworkError(0))
544 }
545 }
546
547 pub fn status(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
551 let s = unsafe { sys::MaaControllerStatus(self.inner.handle.as_ptr(), ctrl_id) };
552 common::MaaStatus(s)
553 }
554
555 pub fn wait(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
557 let s = unsafe { sys::MaaControllerWait(self.inner.handle.as_ptr(), ctrl_id) };
558 common::MaaStatus(s)
559 }
560
561 pub fn set_screenshot_target_long_side(&self, long_side: i32) -> MaaResult<()> {
565 let mut val = long_side;
566 let ret = unsafe {
567 sys::MaaControllerSetOption(
568 self.inner.handle.as_ptr(),
569 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotTargetLongSide as i32,
570 &mut val as *mut _ as *mut c_void,
571 std::mem::size_of::<i32>() as u64,
572 )
573 };
574 common::check_bool(ret)
575 }
576
577 pub fn set_screenshot_target_short_side(&self, short_side: i32) -> MaaResult<()> {
579 let mut val = short_side;
580 let ret = unsafe {
581 sys::MaaControllerSetOption(
582 self.inner.handle.as_ptr(),
583 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotTargetShortSide as i32,
584 &mut val as *mut _ as *mut c_void,
585 std::mem::size_of::<i32>() as u64,
586 )
587 };
588 common::check_bool(ret)
589 }
590
591 pub fn set_screenshot_use_raw_size(&self, enable: bool) -> MaaResult<()> {
593 let mut val: u8 = if enable { 1 } else { 0 };
594 let ret = unsafe {
595 sys::MaaControllerSetOption(
596 self.inner.handle.as_ptr(),
597 sys::MaaCtrlOptionEnum_MaaCtrlOption_ScreenshotUseRawSize as i32,
598 &mut val as *mut _ as *mut c_void,
599 std::mem::size_of::<u8>() as u64,
600 )
601 };
602 common::check_bool(ret)
603 }
604
605 #[cfg(feature = "dbg")]
608 pub fn new_dbg(
609 read_path: &str,
610 write_path: &str,
611 dbg_type: sys::MaaDbgControllerType,
612 config: &str,
613 ) -> MaaResult<Self> {
614 let c_read = CString::new(read_path)?;
615 let c_write = CString::new(write_path)?;
616 let c_cfg = CString::new(config)?;
617 let handle = unsafe {
618 sys::MaaDbgControllerCreate(c_read.as_ptr(), c_write.as_ptr(), dbg_type, c_cfg.as_ptr())
619 };
620 Self::from_handle(handle)
621 }
622
623 #[cfg(feature = "win32")]
625 pub fn new_gamepad(
626 hwnd: *mut c_void,
627 gamepad_type: crate::common::GamepadType,
628 screencap_method: crate::common::Win32ScreencapMethod,
629 ) -> MaaResult<Self> {
630 let handle = unsafe {
631 sys::MaaGamepadControllerCreate(hwnd, gamepad_type as u64, screencap_method.bits())
632 };
633 Self::from_handle(handle)
634 }
635
636 pub fn add_sink<F>(&self, callback: F) -> MaaResult<sys::MaaSinkId>
640 where
641 F: Fn(&str, &str) + Send + Sync + 'static,
642 {
643 let (cb_fn, cb_arg) = crate::callback::EventCallback::new(callback);
644 let sink_id =
645 unsafe { sys::MaaControllerAddSink(self.inner.handle.as_ptr(), cb_fn, cb_arg) };
646 if sink_id != 0 {
647 self.inner
648 .callbacks
649 .lock()
650 .unwrap()
651 .insert(sink_id, cb_arg as usize);
652 Ok(sink_id)
653 } else {
654 unsafe { crate::callback::EventCallback::drop_callback(cb_arg) };
655 Err(MaaError::FrameworkError(0))
656 }
657 }
658
659 pub fn add_event_sink(
671 &self,
672 sink: Box<dyn crate::event_sink::EventSink>,
673 ) -> MaaResult<sys::MaaSinkId> {
674 let handle_id = self.inner.handle.as_ptr() as crate::common::MaaId;
675 let (cb, arg) = crate::callback::EventCallback::new_sink(handle_id, sink);
676 let id = unsafe { sys::MaaControllerAddSink(self.inner.handle.as_ptr(), cb, arg) };
677 if id > 0 {
678 self.inner
679 .event_sinks
680 .lock()
681 .unwrap()
682 .insert(id, arg as usize);
683 Ok(id)
684 } else {
685 unsafe { crate::callback::EventCallback::drop_sink(arg) };
686 Err(MaaError::FrameworkError(0))
687 }
688 }
689
690 pub fn remove_sink(&self, sink_id: sys::MaaSinkId) {
691 unsafe { sys::MaaControllerRemoveSink(self.inner.handle.as_ptr(), sink_id) };
692 if let Some(ptr) = self.inner.callbacks.lock().unwrap().remove(&sink_id) {
693 unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
694 } else if let Some(ptr) = self.inner.event_sinks.lock().unwrap().remove(&sink_id) {
695 unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
696 }
697 }
698
699 pub fn clear_sinks(&self) {
700 unsafe { sys::MaaControllerClearSinks(self.inner.handle.as_ptr()) };
701 let mut callbacks = self.inner.callbacks.lock().unwrap();
702 for (_, ptr) in callbacks.drain() {
703 unsafe { crate::callback::EventCallback::drop_callback(ptr as *mut c_void) };
704 }
705 let mut event_sinks = self.inner.event_sinks.lock().unwrap();
706 for (_, ptr) in event_sinks.drain() {
707 unsafe { crate::callback::EventCallback::drop_sink(ptr as *mut c_void) };
708 }
709 }
710}
711
712impl Drop for ControllerInner {
713 fn drop(&mut self) {
714 unsafe {
715 if self.owns_handle {
716 sys::MaaControllerClearSinks(self.handle.as_ptr());
717 let mut callbacks = self.callbacks.lock().unwrap();
718 for (_, ptr) in callbacks.drain() {
719 crate::callback::EventCallback::drop_callback(ptr as *mut c_void);
720 }
721 let mut event_sinks = self.event_sinks.lock().unwrap();
722 for (_, ptr) in event_sinks.drain() {
723 crate::callback::EventCallback::drop_sink(ptr as *mut c_void);
724 }
725 sys::MaaControllerDestroy(self.handle.as_ptr());
726 }
727 }
728 }
729}
730
731#[cfg(feature = "adb")]
735pub struct AdbControllerBuilder {
736 adb_path: String,
737 address: String,
738 screencap_methods: sys::MaaAdbScreencapMethod,
739 input_methods: sys::MaaAdbInputMethod,
740 config: String,
741 agent_path: String,
742}
743
744#[cfg(feature = "adb")]
745impl AdbControllerBuilder {
746 pub fn new(adb_path: &str, address: &str) -> Self {
748 Self {
749 adb_path: adb_path.to_string(),
750 address: address.to_string(),
751 screencap_methods: sys::MaaAdbScreencapMethod_Default as sys::MaaAdbScreencapMethod,
752 input_methods: sys::MaaAdbInputMethod_Default as sys::MaaAdbInputMethod,
753 config: "{}".to_string(),
754 agent_path: String::new(),
755 }
756 }
757
758 pub fn screencap_methods(mut self, methods: sys::MaaAdbScreencapMethod) -> Self {
760 self.screencap_methods = methods;
761 self
762 }
763
764 pub fn input_methods(mut self, methods: sys::MaaAdbInputMethod) -> Self {
766 self.input_methods = methods;
767 self
768 }
769
770 pub fn config(mut self, config: &str) -> Self {
772 self.config = config.to_string();
773 self
774 }
775
776 pub fn agent_path(mut self, path: &str) -> Self {
778 self.agent_path = path.to_string();
779 self
780 }
781
782 pub fn build(self) -> MaaResult<Controller> {
784 Controller::create_adb(
785 &self.adb_path,
786 &self.address,
787 self.screencap_methods,
788 self.input_methods,
789 &self.config,
790 &self.agent_path,
791 )
792 }
793}
794
795pub struct ControllerRef<'a> {
801 handle: *mut sys::MaaController,
802 _marker: std::marker::PhantomData<&'a ()>,
803}
804
805impl<'a> std::fmt::Debug for ControllerRef<'a> {
806 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
807 f.debug_struct("ControllerRef")
808 .field("handle", &self.handle)
809 .finish()
810 }
811}
812
813impl<'a> ControllerRef<'a> {
814 pub(crate) fn from_ptr(handle: *mut sys::MaaController) -> Option<Self> {
815 if handle.is_null() {
816 None
817 } else {
818 Some(Self {
819 handle,
820 _marker: std::marker::PhantomData,
821 })
822 }
823 }
824
825 pub fn connected(&self) -> bool {
827 unsafe { sys::MaaControllerConnected(self.handle) != 0 }
828 }
829
830 pub fn uuid(&self) -> MaaResult<String> {
832 let buffer = crate::buffer::MaaStringBuffer::new()?;
833 let ret = unsafe { sys::MaaControllerGetUuid(self.handle, buffer.as_ptr()) };
834 if ret != 0 {
835 Ok(buffer.to_string())
836 } else {
837 Err(MaaError::FrameworkError(0))
838 }
839 }
840
841 pub fn info(&self) -> MaaResult<serde_json::Value> {
843 let buffer = crate::buffer::MaaStringBuffer::new()?;
844 let ret = unsafe { sys::MaaControllerGetInfo(self.handle, buffer.as_ptr()) };
845 if ret != 0 {
846 serde_json::from_str(&buffer.to_string()).map_err(|e| {
847 MaaError::InvalidArgument(format!("Failed to parse controller info: {}", e))
848 })
849 } else {
850 Err(MaaError::FrameworkError(0))
851 }
852 }
853
854 pub fn resolution(&self) -> MaaResult<(i32, i32)> {
856 let mut width: i32 = 0;
857 let mut height: i32 = 0;
858 let ret = unsafe { sys::MaaControllerGetResolution(self.handle, &mut width, &mut height) };
859 if ret != 0 {
860 Ok((width, height))
861 } else {
862 Err(MaaError::FrameworkError(0))
863 }
864 }
865
866 pub fn status(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
868 let s = unsafe { sys::MaaControllerStatus(self.handle, ctrl_id) };
869 common::MaaStatus(s)
870 }
871
872 pub fn wait(&self, ctrl_id: common::MaaId) -> common::MaaStatus {
874 let s = unsafe { sys::MaaControllerWait(self.handle, ctrl_id) };
875 common::MaaStatus(s)
876 }
877
878 pub fn cached_image(&self) -> MaaResult<crate::buffer::MaaImageBuffer> {
880 let buffer = crate::buffer::MaaImageBuffer::new()?;
881 let ret = unsafe { sys::MaaControllerCachedImage(self.handle, buffer.as_ptr()) };
882 if ret != 0 {
883 Ok(buffer)
884 } else {
885 Err(MaaError::FrameworkError(0))
886 }
887 }
888
889 pub fn raw(&self) -> *mut sys::MaaController {
891 self.handle
892 }
893}