1use crate::sys;
4use serde::{Deserialize, Serialize};
5use std::fmt;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
12pub struct MaaStatus(pub i32);
13
14pub type MaaId = i64;
16
17impl MaaStatus {
18 pub const INVALID: Self = Self(sys::MaaStatusEnum_MaaStatus_Invalid as i32);
19 pub const PENDING: Self = Self(sys::MaaStatusEnum_MaaStatus_Pending as i32);
20 pub const RUNNING: Self = Self(sys::MaaStatusEnum_MaaStatus_Running as i32);
21 pub const SUCCEEDED: Self = Self(sys::MaaStatusEnum_MaaStatus_Succeeded as i32);
22 pub const FAILED: Self = Self(sys::MaaStatusEnum_MaaStatus_Failed as i32);
23
24 pub fn is_success(&self) -> bool {
26 *self == Self::SUCCEEDED
27 }
28
29 pub fn succeeded(&self) -> bool {
31 *self == Self::SUCCEEDED
32 }
33
34 pub fn is_failed(&self) -> bool {
36 *self == Self::FAILED
37 }
38
39 pub fn failed(&self) -> bool {
41 *self == Self::FAILED
42 }
43
44 pub fn done(&self) -> bool {
46 *self == Self::SUCCEEDED || *self == Self::FAILED
47 }
48
49 pub fn pending(&self) -> bool {
51 *self == Self::PENDING
52 }
53
54 pub fn running(&self) -> bool {
56 *self == Self::RUNNING
57 }
58}
59
60impl fmt::Display for MaaStatus {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 match *self {
63 Self::INVALID => write!(f, "Invalid"),
64 Self::PENDING => write!(f, "Pending"),
65 Self::RUNNING => write!(f, "Running"),
66 Self::SUCCEEDED => write!(f, "Succeeded"),
67 Self::FAILED => write!(f, "Failed"),
68 _ => write!(f, "Unknown({})", self.0),
69 }
70 }
71}
72
73pub fn check_bool(ret: sys::MaaBool) -> crate::MaaResult<()> {
74 if ret != 0 {
75 Ok(())
76 } else {
77 Err(crate::MaaError::FrameworkError(0))
78 }
79}
80
81impl From<i32> for MaaStatus {
82 fn from(value: i32) -> Self {
83 Self(value)
84 }
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Default)]
94#[serde(from = "RectDef")]
95pub struct Rect {
96 pub x: i32,
97 pub y: i32,
98 pub width: i32,
99 pub height: i32,
100}
101
102impl Serialize for Rect {
103 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
104 where
105 S: serde::Serializer,
106 {
107 (self.x, self.y, self.width, self.height).serialize(serializer)
108 }
109}
110
111#[derive(Deserialize)]
113#[serde(untagged)]
114enum RectDef {
115 Map {
116 x: i32,
117 y: i32,
118 #[serde(alias = "w")]
119 width: i32,
120 #[serde(alias = "h")]
121 height: i32,
122 },
123 Array(i32, i32, i32, i32),
124}
125
126impl From<RectDef> for Rect {
127 fn from(def: RectDef) -> Self {
128 match def {
129 RectDef::Map {
130 x,
131 y,
132 width,
133 height,
134 } => Rect {
135 x,
136 y,
137 width,
138 height,
139 },
140 RectDef::Array(x, y, w, h) => Rect {
141 x,
142 y,
143 width: w,
144 height: h,
145 },
146 }
147 }
148}
149
150impl From<(i32, i32, i32, i32)> for Rect {
151 fn from(tuple: (i32, i32, i32, i32)) -> Self {
152 Self {
153 x: tuple.0,
154 y: tuple.1,
155 width: tuple.2,
156 height: tuple.3,
157 }
158 }
159}
160
161impl From<sys::MaaRect> for Rect {
162 fn from(r: sys::MaaRect) -> Self {
163 Self {
164 x: r.x,
165 y: r.y,
166 width: r.width,
167 height: r.height,
168 }
169 }
170}
171
172impl Rect {
173 pub fn to_tuple(&self) -> (i32, i32, i32, i32) {
174 (self.x, self.y, self.width, self.height)
175 }
176}
177
178impl PartialEq<(i32, i32, i32, i32)> for Rect {
179 fn eq(&self, other: &(i32, i32, i32, i32)) -> bool {
180 self.x == other.0 && self.y == other.1 && self.width == other.2 && self.height == other.3
181 }
182}
183
184impl PartialEq<Rect> for (i32, i32, i32, i32) {
185 fn eq(&self, other: &Rect) -> bool {
186 self.0 == other.x && self.1 == other.y && self.2 == other.width && self.3 == other.height
187 }
188}
189
190#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
192pub struct Point {
193 pub x: i32,
194 pub y: i32,
195}
196
197impl Point {
198 pub fn new(x: i32, y: i32) -> Self {
199 Self { x, y }
200 }
201}
202
203#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
209#[repr(u64)]
210#[non_exhaustive]
211pub enum GamepadType {
212 Xbox360 = 0,
214 DualShock4 = 1,
216}
217
218#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
220#[repr(i32)]
221#[non_exhaustive]
222pub enum GamepadContact {
223 LeftStick = 0,
225 RightStick = 1,
227 LeftTrigger = 2,
229 RightTrigger = 3,
231}
232
233bitflags::bitflags! {
234 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
238 pub struct GamepadButton: u32 {
239 const DPAD_UP = 0x0001;
241 const DPAD_DOWN = 0x0002;
242 const DPAD_LEFT = 0x0004;
243 const DPAD_RIGHT = 0x0008;
244
245 const START = 0x0010;
247 const BACK = 0x0020;
248 const LEFT_THUMB = 0x0040; const RIGHT_THUMB = 0x0080; const LB = 0x0100; const RB = 0x0200; const GUIDE = 0x0400;
257
258 const A = 0x1000;
260 const B = 0x2000;
261 const X = 0x4000;
262 const Y = 0x8000;
263
264 const PS = 0x10000;
266 const TOUCHPAD = 0x20000;
267 }
268}
269
270impl GamepadButton {
271 pub const CROSS: Self = Self::A;
273 pub const CIRCLE: Self = Self::B;
274 pub const SQUARE: Self = Self::X;
275 pub const TRIANGLE: Self = Self::Y;
276 pub const L1: Self = Self::LB;
277 pub const R1: Self = Self::RB;
278 pub const L3: Self = Self::LEFT_THUMB;
279 pub const R3: Self = Self::RIGHT_THUMB;
280 pub const OPTIONS: Self = Self::START;
281 pub const SHARE: Self = Self::BACK;
282}
283
284bitflags::bitflags! {
289 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
293 pub struct ControllerFeature: u64 {
294 const USE_MOUSE_DOWN_UP_INSTEAD_OF_CLICK = 1;
298 const USE_KEY_DOWN_UP_INSTEAD_OF_CLICK = 1 << 1;
301 const NO_SCALING_TOUCH_POINTS = 1 << 2;
304 }
305}
306
307#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
313pub struct AndroidScreenResolution {
314 pub width: i32,
316 pub height: i32,
318}
319
320#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
322pub struct AndroidNativeControllerConfig {
323 pub library_path: String,
325 pub screen_resolution: AndroidScreenResolution,
327 #[serde(default, skip_serializing_if = "Option::is_none")]
329 pub display_id: Option<u32>,
330 #[serde(default, skip_serializing_if = "Option::is_none")]
332 pub force_stop: Option<bool>,
333}
334
335bitflags::bitflags! {
336 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
341 pub struct AdbScreencapMethod: u64 {
342 const ENCODE_TO_FILE_AND_PULL = 1;
343 const ENCODE = 1 << 1;
344 const RAW_WITH_GZIP = 1 << 2;
345 const RAW_BY_NETCAT = 1 << 3;
346 const MINICAP_DIRECT = 1 << 4;
347 const MINICAP_STREAM = 1 << 5;
348 const EMULATOR_EXTRAS = 1 << 6;
349 const ALL = !0;
350 }
351}
352
353impl AdbScreencapMethod {
354 pub const DEFAULT: Self = Self::from_bits_truncate(
356 Self::ALL.bits()
357 & !Self::RAW_BY_NETCAT.bits()
358 & !Self::MINICAP_DIRECT.bits()
359 & !Self::MINICAP_STREAM.bits(),
360 );
361}
362
363impl Default for AdbScreencapMethod {
364 fn default() -> Self {
365 Self::DEFAULT
366 }
367}
368
369bitflags::bitflags! {
370 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
375 pub struct AdbInputMethod: u64 {
376 const ADB_SHELL = 1;
377 const MINITOUCH_AND_ADB_KEY = 1 << 1;
378 const MAATOUCH = 1 << 2;
379 const EMULATOR_EXTRAS = 1 << 3;
380 const ALL = !0;
381 }
382}
383
384impl AdbInputMethod {
385 pub const DEFAULT: Self =
387 Self::from_bits_truncate(Self::ALL.bits() & !Self::EMULATOR_EXTRAS.bits());
388}
389
390impl Default for AdbInputMethod {
391 fn default() -> Self {
392 Self::DEFAULT
393 }
394}
395
396bitflags::bitflags! {
401 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
413 pub struct Win32ScreencapMethod: u64 {
414 const GDI = 1;
415 const FRAME_POOL = 1 << 1;
416 const DXGI_DESKTOP_DUP = 1 << 2;
417 const DXGI_DESKTOP_DUP_WINDOW = 1 << 3;
418 const PRINT_WINDOW = 1 << 4;
419 const SCREEN_DC = 1 << 5;
420 const ALL = !0;
421 const FOREGROUND = Self::DXGI_DESKTOP_DUP_WINDOW.bits() | Self::SCREEN_DC.bits();
422 const BACKGROUND = Self::FRAME_POOL.bits() | Self::PRINT_WINDOW.bits();
423 }
424}
425
426bitflags::bitflags! {
427 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
429 pub struct Win32InputMethod: u64 {
430 const SEIZE = 1;
431 const SEND_MESSAGE = 1 << 1;
432 const POST_MESSAGE = 1 << 2;
433 const LEGACY_EVENT = 1 << 3;
434 const POST_THREAD_MESSAGE = 1 << 4;
436 const SEND_MESSAGE_WITH_CURSOR_POS = 1 << 5;
437 const POST_MESSAGE_WITH_CURSOR_POS = 1 << 6;
438 const SEND_MESSAGE_WITH_WINDOW_POS = 1 << 7;
439 const POST_MESSAGE_WITH_WINDOW_POS = 1 << 8;
440 const INTERCEPTION = sys::MaaWin32InputMethod_Interception as u64;
443 }
444}
445
446#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
448pub struct RecognitionDetail {
449 pub node_name: String,
451 pub algorithm: AlgorithmEnum,
453 pub hit: bool,
455 pub box_rect: Rect,
457 pub detail: serde_json::Value,
459 #[serde(skip)]
461 pub raw_image: Option<Vec<u8>>,
462 #[serde(skip)]
464 pub draw_images: Vec<Vec<u8>>,
465 #[serde(default)]
467 pub sub_details: Vec<RecognitionDetail>,
468}
469
470impl RecognitionDetail {
471 pub fn as_template_match_result(&self) -> Option<TemplateMatchResult> {
472 serde_json::from_value(self.detail.clone()).ok()
473 }
474
475 pub fn as_feature_match_result(&self) -> Option<FeatureMatchResult> {
476 serde_json::from_value(self.detail.clone()).ok()
477 }
478
479 pub fn as_color_match_result(&self) -> Option<ColorMatchResult> {
480 serde_json::from_value(self.detail.clone()).ok()
481 }
482
483 pub fn as_ocr_result(&self) -> Option<OCRResult> {
484 serde_json::from_value(self.detail.clone()).ok()
485 }
486
487 pub fn as_neural_network_result(&self) -> Option<NeuralNetworkResult> {
488 serde_json::from_value(self.detail.clone()).ok()
489 }
490
491 pub fn as_custom_result(&self) -> Option<CustomRecognitionResult> {
492 serde_json::from_value(self.detail.clone()).ok()
493 }
494}
495
496#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
498pub struct ActionDetail {
499 pub node_name: String,
501 pub action: ActionEnum,
503 pub box_rect: Rect,
505 pub success: bool,
507 pub detail: serde_json::Value,
509}
510
511#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
512pub struct WaitFreezesDetail {
513 pub wf_id: MaaId,
514 pub name: String,
515 pub phase: String,
516 pub success: bool,
517 pub elapsed_ms: u64,
518 #[serde(default)]
519 pub reco_id_list: Vec<MaaId>,
520 pub roi: Rect,
521}
522
523impl ActionDetail {
524 pub fn as_click_result(&self) -> Option<ClickActionResult> {
525 serde_json::from_value(self.detail.clone()).ok()
526 }
527
528 pub fn as_long_press_result(&self) -> Option<LongPressActionResult> {
529 serde_json::from_value(self.detail.clone()).ok()
530 }
531
532 pub fn as_swipe_result(&self) -> Option<SwipeActionResult> {
533 serde_json::from_value(self.detail.clone()).ok()
534 }
535
536 pub fn as_multi_swipe_result(&self) -> Option<MultiSwipeActionResult> {
537 serde_json::from_value(self.detail.clone()).ok()
538 }
539
540 pub fn as_click_key_result(&self) -> Option<ClickKeyActionResult> {
541 serde_json::from_value(self.detail.clone()).ok()
542 }
543
544 pub fn as_input_text_result(&self) -> Option<InputTextActionResult> {
545 serde_json::from_value(self.detail.clone()).ok()
546 }
547
548 pub fn as_app_result(&self) -> Option<AppActionResult> {
549 serde_json::from_value(self.detail.clone()).ok()
550 }
551
552 pub fn as_scroll_result(&self) -> Option<ScrollActionResult> {
553 serde_json::from_value(self.detail.clone()).ok()
554 }
555
556 pub fn as_touch_result(&self) -> Option<TouchActionResult> {
557 serde_json::from_value(self.detail.clone()).ok()
558 }
559
560 pub fn as_shell_result(&self) -> Option<ShellActionResult> {
561 serde_json::from_value(self.detail.clone()).ok()
562 }
563}
564
565#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
571pub struct ClickActionResult {
572 pub point: Point,
573 pub contact: i32,
574 #[serde(default)]
575 pub pressure: i32,
576}
577
578#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
580pub struct LongPressActionResult {
581 pub point: Point,
582 pub duration: i32,
583 pub contact: i32,
584 #[serde(default)]
585 pub pressure: i32,
586}
587
588#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
590pub struct SwipeActionResult {
591 pub begin: Point,
592 pub end: Vec<Point>,
593 #[serde(default)]
594 pub end_hold: Vec<i32>,
595 #[serde(default)]
596 pub duration: Vec<i32>,
597 #[serde(default)]
598 pub only_hover: bool,
599 #[serde(default)]
600 pub starting: i32,
601 pub contact: i32,
602 #[serde(default)]
603 pub pressure: i32,
604}
605
606#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
608pub struct MultiSwipeActionResult {
609 pub swipes: Vec<SwipeActionResult>,
610}
611
612#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
614pub struct ClickKeyActionResult {
615 pub keycode: Vec<i32>,
616}
617
618#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
620pub struct LongPressKeyActionResult {
621 pub keycode: Vec<i32>,
622 pub duration: i32,
623}
624
625#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
627pub struct InputTextActionResult {
628 pub text: String,
629}
630
631#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
633pub struct AppActionResult {
634 pub package: String,
635}
636
637#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
639pub struct ScrollActionResult {
640 #[serde(default)]
641 pub point: Point,
642 pub dx: i32,
643 pub dy: i32,
644}
645
646#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
648pub struct TouchActionResult {
649 pub contact: i32,
650 pub point: Point,
651 #[serde(default)]
652 pub pressure: i32,
653}
654
655#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
657pub struct ShellActionResult {
658 pub cmd: String,
659 pub shell_timeout: i32,
660 pub success: bool,
661 pub output: String,
662}
663
664#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
666pub struct NodeDetail {
667 pub node_name: String,
668 pub reco_id: MaaId,
670 pub act_id: MaaId,
672 #[serde(default)]
674 pub recognition: Option<RecognitionDetail>,
675 #[serde(default)]
677 pub action: Option<ActionDetail>,
678 pub completed: bool,
680}
681
682#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
684pub struct TaskDetail {
685 pub entry: String,
687 pub node_id_list: Vec<MaaId>,
689 pub status: MaaStatus,
691 #[serde(default)]
693 pub nodes: Vec<Option<NodeDetail>>,
694}
695
696#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
698#[serde(into = "String", from = "String")]
699pub enum AlgorithmEnum {
700 DirectHit,
701 TemplateMatch,
702 FeatureMatch,
703 ColorMatch,
704 OCR,
705 NeuralNetworkClassify,
706 NeuralNetworkDetect,
707 And,
708 Or,
709 Custom,
710 Other(String),
711}
712
713impl From<String> for AlgorithmEnum {
714 fn from(s: String) -> Self {
715 match s.as_str() {
716 "DirectHit" => Self::DirectHit,
717 "TemplateMatch" => Self::TemplateMatch,
718 "FeatureMatch" => Self::FeatureMatch,
719 "ColorMatch" => Self::ColorMatch,
720 "OCR" => Self::OCR,
721 "NeuralNetworkClassify" => Self::NeuralNetworkClassify,
722 "NeuralNetworkDetect" => Self::NeuralNetworkDetect,
723 "And" => Self::And,
724 "Or" => Self::Or,
725 "Custom" => Self::Custom,
726 _ => Self::Other(s),
727 }
728 }
729}
730
731impl From<AlgorithmEnum> for String {
732 fn from(algo: AlgorithmEnum) -> Self {
733 match algo {
734 AlgorithmEnum::DirectHit => "DirectHit".to_string(),
735 AlgorithmEnum::TemplateMatch => "TemplateMatch".to_string(),
736 AlgorithmEnum::FeatureMatch => "FeatureMatch".to_string(),
737 AlgorithmEnum::ColorMatch => "ColorMatch".to_string(),
738 AlgorithmEnum::OCR => "OCR".to_string(),
739 AlgorithmEnum::NeuralNetworkClassify => "NeuralNetworkClassify".to_string(),
740 AlgorithmEnum::NeuralNetworkDetect => "NeuralNetworkDetect".to_string(),
741 AlgorithmEnum::And => "And".to_string(),
742 AlgorithmEnum::Or => "Or".to_string(),
743 AlgorithmEnum::Custom => "Custom".to_string(),
744 AlgorithmEnum::Other(s) => s,
745 }
746 }
747}
748
749impl AlgorithmEnum {
750 pub fn as_str(&self) -> &str {
751 match self {
752 Self::DirectHit => "DirectHit",
753 Self::TemplateMatch => "TemplateMatch",
754 Self::FeatureMatch => "FeatureMatch",
755 Self::ColorMatch => "ColorMatch",
756 Self::OCR => "OCR",
757 Self::NeuralNetworkClassify => "NeuralNetworkClassify",
758 Self::NeuralNetworkDetect => "NeuralNetworkDetect",
759 Self::And => "And",
760 Self::Or => "Or",
761 Self::Custom => "Custom",
762 Self::Other(s) => s.as_str(),
763 }
764 }
765}
766
767#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
769#[serde(into = "String", from = "String")]
770pub enum ActionEnum {
771 DoNothing,
772 Click,
773 LongPress,
774 Swipe,
775 MultiSwipe,
776 TouchDown,
777 TouchMove,
778 TouchUp,
779 ClickKey,
780 LongPressKey,
781 KeyDown,
782 KeyUp,
783 InputText,
784 StartApp,
785 StopApp,
786 StopTask,
787 Scroll,
788 Command,
789 Shell,
790 Custom,
791 Other(String),
792}
793
794impl From<String> for ActionEnum {
795 fn from(s: String) -> Self {
796 match s.as_str() {
797 "DoNothing" => Self::DoNothing,
798 "Click" => Self::Click,
799 "LongPress" => Self::LongPress,
800 "Swipe" => Self::Swipe,
801 "MultiSwipe" => Self::MultiSwipe,
802 "TouchDown" => Self::TouchDown,
803 "TouchMove" => Self::TouchMove,
804 "TouchUp" => Self::TouchUp,
805 "ClickKey" => Self::ClickKey,
806 "LongPressKey" => Self::LongPressKey,
807 "KeyDown" => Self::KeyDown,
808 "KeyUp" => Self::KeyUp,
809 "InputText" => Self::InputText,
810 "StartApp" => Self::StartApp,
811 "StopApp" => Self::StopApp,
812 "StopTask" => Self::StopTask,
813 "Scroll" => Self::Scroll,
814 "Command" => Self::Command,
815 "Shell" => Self::Shell,
816 "Custom" => Self::Custom,
817 _ => Self::Other(s),
818 }
819 }
820}
821
822impl From<ActionEnum> for String {
823 fn from(act: ActionEnum) -> Self {
824 match act {
825 ActionEnum::DoNothing => "DoNothing".to_string(),
826 ActionEnum::Click => "Click".to_string(),
827 ActionEnum::LongPress => "LongPress".to_string(),
828 ActionEnum::Swipe => "Swipe".to_string(),
829 ActionEnum::MultiSwipe => "MultiSwipe".to_string(),
830 ActionEnum::TouchDown => "TouchDown".to_string(),
831 ActionEnum::TouchMove => "TouchMove".to_string(),
832 ActionEnum::TouchUp => "TouchUp".to_string(),
833 ActionEnum::ClickKey => "ClickKey".to_string(),
834 ActionEnum::LongPressKey => "LongPressKey".to_string(),
835 ActionEnum::KeyDown => "KeyDown".to_string(),
836 ActionEnum::KeyUp => "KeyUp".to_string(),
837 ActionEnum::InputText => "InputText".to_string(),
838 ActionEnum::StartApp => "StartApp".to_string(),
839 ActionEnum::StopApp => "StopApp".to_string(),
840 ActionEnum::StopTask => "StopTask".to_string(),
841 ActionEnum::Scroll => "Scroll".to_string(),
842 ActionEnum::Command => "Command".to_string(),
843 ActionEnum::Shell => "Shell".to_string(),
844 ActionEnum::Custom => "Custom".to_string(),
845 ActionEnum::Other(s) => s,
846 }
847 }
848}
849
850impl ActionEnum {
851 pub fn as_str(&self) -> &str {
852 match self {
853 Self::DoNothing => "DoNothing",
854 Self::Click => "Click",
855 Self::LongPress => "LongPress",
856 Self::Swipe => "Swipe",
857 Self::MultiSwipe => "MultiSwipe",
858 Self::TouchDown => "TouchDown",
859 Self::TouchMove => "TouchMove",
860 Self::TouchUp => "TouchUp",
861 Self::ClickKey => "ClickKey",
862 Self::LongPressKey => "LongPressKey",
863 Self::KeyDown => "KeyDown",
864 Self::KeyUp => "KeyUp",
865 Self::InputText => "InputText",
866 Self::StartApp => "StartApp",
867 Self::StopApp => "StopApp",
868 Self::StopTask => "StopTask",
869 Self::Scroll => "Scroll",
870 Self::Command => "Command",
871 Self::Shell => "Shell",
872 Self::Custom => "Custom",
873 Self::Other(s) => s.as_str(),
874 }
875 }
876}
877
878#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
880#[non_exhaustive]
881pub enum NotificationType {
882 Starting,
883 Succeeded,
884 Failed,
885 Unknown,
886}
887
888impl NotificationType {
889 pub fn from_message(msg: &str) -> Self {
890 if msg.ends_with(".Starting") {
891 Self::Starting
892 } else if msg.ends_with(".Succeeded") {
893 Self::Succeeded
894 } else if msg.ends_with(".Failed") {
895 Self::Failed
896 } else {
897 Self::Unknown
898 }
899 }
900}
901
902#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
905pub struct BoxAndScore {
906 #[serde(rename = "box")]
907 pub box_rect: (i32, i32, i32, i32),
908 pub score: f64,
909}
910
911#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
912pub struct BoxAndCount {
913 #[serde(rename = "box")]
914 pub box_rect: (i32, i32, i32, i32),
915 pub count: i32,
916}
917
918pub type TemplateMatchResult = BoxAndScore;
919pub type FeatureMatchResult = BoxAndCount;
920pub type ColorMatchResult = BoxAndCount;
921
922#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
923pub struct OCRResult {
924 #[serde(flatten)]
925 pub base: BoxAndScore,
926 pub text: String,
927}
928
929#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
930pub struct NeuralNetworkResult {
931 #[serde(flatten)]
932 pub base: BoxAndScore,
933 pub cls_index: i32,
934 pub label: String,
935}
936
937pub type NeuralNetworkClassifyResult = NeuralNetworkResult;
938pub type NeuralNetworkDetectResult = NeuralNetworkResult;
939
940#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
941pub struct CustomRecognitionResult {
942 #[serde(rename = "box")]
943 pub box_rect: (i32, i32, i32, i32),
944 pub detail: serde_json::Value,
945}
946
947#[cfg(test)]
948mod tests {
949 use super::{AndroidNativeControllerConfig, AndroidScreenResolution};
950 use serde_json::json;
951
952 #[test]
953 fn android_native_controller_config_serializes_expected_shape() {
954 let config = AndroidNativeControllerConfig {
955 library_path: "/data/local/tmp/libmaa_unit.so".to_string(),
956 screen_resolution: AndroidScreenResolution {
957 width: 1920,
958 height: 1080,
959 },
960 display_id: Some(1),
961 force_stop: Some(true),
962 };
963
964 let value = serde_json::to_value(config).unwrap();
965
966 assert_eq!(
967 value,
968 json!({
969 "library_path": "/data/local/tmp/libmaa_unit.so",
970 "screen_resolution": {
971 "width": 1920,
972 "height": 1080
973 },
974 "display_id": 1,
975 "force_stop": true
976 })
977 );
978 }
979}