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;
435 const SEND_MESSAGE_WITH_CURSOR_POS = 1 << 5;
436 const POST_MESSAGE_WITH_CURSOR_POS = 1 << 6;
437 const SEND_MESSAGE_WITH_WINDOW_POS = 1 << 7;
438 const POST_MESSAGE_WITH_WINDOW_POS = 1 << 8;
439 }
440}
441
442#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
444pub struct RecognitionDetail {
445 pub node_name: String,
447 pub algorithm: AlgorithmEnum,
449 pub hit: bool,
451 pub box_rect: Rect,
453 pub detail: serde_json::Value,
455 #[serde(skip)]
457 pub raw_image: Option<Vec<u8>>,
458 #[serde(skip)]
460 pub draw_images: Vec<Vec<u8>>,
461 #[serde(default)]
463 pub sub_details: Vec<RecognitionDetail>,
464}
465
466impl RecognitionDetail {
467 pub fn as_template_match_result(&self) -> Option<TemplateMatchResult> {
468 serde_json::from_value(self.detail.clone()).ok()
469 }
470
471 pub fn as_feature_match_result(&self) -> Option<FeatureMatchResult> {
472 serde_json::from_value(self.detail.clone()).ok()
473 }
474
475 pub fn as_color_match_result(&self) -> Option<ColorMatchResult> {
476 serde_json::from_value(self.detail.clone()).ok()
477 }
478
479 pub fn as_ocr_result(&self) -> Option<OCRResult> {
480 serde_json::from_value(self.detail.clone()).ok()
481 }
482
483 pub fn as_neural_network_result(&self) -> Option<NeuralNetworkResult> {
484 serde_json::from_value(self.detail.clone()).ok()
485 }
486
487 pub fn as_custom_result(&self) -> Option<CustomRecognitionResult> {
488 serde_json::from_value(self.detail.clone()).ok()
489 }
490}
491
492#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
494pub struct ActionDetail {
495 pub node_name: String,
497 pub action: ActionEnum,
499 pub box_rect: Rect,
501 pub success: bool,
503 pub detail: serde_json::Value,
505}
506
507impl ActionDetail {
508 pub fn as_click_result(&self) -> Option<ClickActionResult> {
509 serde_json::from_value(self.detail.clone()).ok()
510 }
511
512 pub fn as_long_press_result(&self) -> Option<LongPressActionResult> {
513 serde_json::from_value(self.detail.clone()).ok()
514 }
515
516 pub fn as_swipe_result(&self) -> Option<SwipeActionResult> {
517 serde_json::from_value(self.detail.clone()).ok()
518 }
519
520 pub fn as_multi_swipe_result(&self) -> Option<MultiSwipeActionResult> {
521 serde_json::from_value(self.detail.clone()).ok()
522 }
523
524 pub fn as_click_key_result(&self) -> Option<ClickKeyActionResult> {
525 serde_json::from_value(self.detail.clone()).ok()
526 }
527
528 pub fn as_input_text_result(&self) -> Option<InputTextActionResult> {
529 serde_json::from_value(self.detail.clone()).ok()
530 }
531
532 pub fn as_app_result(&self) -> Option<AppActionResult> {
533 serde_json::from_value(self.detail.clone()).ok()
534 }
535
536 pub fn as_scroll_result(&self) -> Option<ScrollActionResult> {
537 serde_json::from_value(self.detail.clone()).ok()
538 }
539
540 pub fn as_touch_result(&self) -> Option<TouchActionResult> {
541 serde_json::from_value(self.detail.clone()).ok()
542 }
543
544 pub fn as_shell_result(&self) -> Option<ShellActionResult> {
545 serde_json::from_value(self.detail.clone()).ok()
546 }
547}
548
549#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
555pub struct ClickActionResult {
556 pub point: Point,
557 pub contact: i32,
558 #[serde(default)]
559 pub pressure: i32,
560}
561
562#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
564pub struct LongPressActionResult {
565 pub point: Point,
566 pub duration: i32,
567 pub contact: i32,
568 #[serde(default)]
569 pub pressure: i32,
570}
571
572#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
574pub struct SwipeActionResult {
575 pub begin: Point,
576 pub end: Vec<Point>,
577 #[serde(default)]
578 pub end_hold: Vec<i32>,
579 #[serde(default)]
580 pub duration: Vec<i32>,
581 #[serde(default)]
582 pub only_hover: bool,
583 #[serde(default)]
584 pub starting: i32,
585 pub contact: i32,
586 #[serde(default)]
587 pub pressure: i32,
588}
589
590#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
592pub struct MultiSwipeActionResult {
593 pub swipes: Vec<SwipeActionResult>,
594}
595
596#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
598pub struct ClickKeyActionResult {
599 pub keycode: Vec<i32>,
600}
601
602#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
604pub struct LongPressKeyActionResult {
605 pub keycode: Vec<i32>,
606 pub duration: i32,
607}
608
609#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
611pub struct InputTextActionResult {
612 pub text: String,
613}
614
615#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
617pub struct AppActionResult {
618 pub package: String,
619}
620
621#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
623pub struct ScrollActionResult {
624 #[serde(default)]
625 pub point: Point,
626 pub dx: i32,
627 pub dy: i32,
628}
629
630#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
632pub struct TouchActionResult {
633 pub contact: i32,
634 pub point: Point,
635 #[serde(default)]
636 pub pressure: i32,
637}
638
639#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
641pub struct ShellActionResult {
642 pub cmd: String,
643 pub shell_timeout: i32,
644 pub success: bool,
645 pub output: String,
646}
647
648#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
650pub struct NodeDetail {
651 pub node_name: String,
652 pub reco_id: MaaId,
654 pub act_id: MaaId,
656 #[serde(default)]
658 pub recognition: Option<RecognitionDetail>,
659 #[serde(default)]
661 pub action: Option<ActionDetail>,
662 pub completed: bool,
664}
665
666#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
668pub struct TaskDetail {
669 pub entry: String,
671 pub node_id_list: Vec<MaaId>,
673 pub status: MaaStatus,
675 #[serde(default)]
677 pub nodes: Vec<Option<NodeDetail>>,
678}
679
680#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
682#[serde(into = "String", from = "String")]
683pub enum AlgorithmEnum {
684 DirectHit,
685 TemplateMatch,
686 FeatureMatch,
687 ColorMatch,
688 OCR,
689 NeuralNetworkClassify,
690 NeuralNetworkDetect,
691 And,
692 Or,
693 Custom,
694 Other(String),
695}
696
697impl From<String> for AlgorithmEnum {
698 fn from(s: String) -> Self {
699 match s.as_str() {
700 "DirectHit" => Self::DirectHit,
701 "TemplateMatch" => Self::TemplateMatch,
702 "FeatureMatch" => Self::FeatureMatch,
703 "ColorMatch" => Self::ColorMatch,
704 "OCR" => Self::OCR,
705 "NeuralNetworkClassify" => Self::NeuralNetworkClassify,
706 "NeuralNetworkDetect" => Self::NeuralNetworkDetect,
707 "And" => Self::And,
708 "Or" => Self::Or,
709 "Custom" => Self::Custom,
710 _ => Self::Other(s),
711 }
712 }
713}
714
715impl From<AlgorithmEnum> for String {
716 fn from(algo: AlgorithmEnum) -> Self {
717 match algo {
718 AlgorithmEnum::DirectHit => "DirectHit".to_string(),
719 AlgorithmEnum::TemplateMatch => "TemplateMatch".to_string(),
720 AlgorithmEnum::FeatureMatch => "FeatureMatch".to_string(),
721 AlgorithmEnum::ColorMatch => "ColorMatch".to_string(),
722 AlgorithmEnum::OCR => "OCR".to_string(),
723 AlgorithmEnum::NeuralNetworkClassify => "NeuralNetworkClassify".to_string(),
724 AlgorithmEnum::NeuralNetworkDetect => "NeuralNetworkDetect".to_string(),
725 AlgorithmEnum::And => "And".to_string(),
726 AlgorithmEnum::Or => "Or".to_string(),
727 AlgorithmEnum::Custom => "Custom".to_string(),
728 AlgorithmEnum::Other(s) => s,
729 }
730 }
731}
732
733impl AlgorithmEnum {
734 pub fn as_str(&self) -> &str {
735 match self {
736 Self::DirectHit => "DirectHit",
737 Self::TemplateMatch => "TemplateMatch",
738 Self::FeatureMatch => "FeatureMatch",
739 Self::ColorMatch => "ColorMatch",
740 Self::OCR => "OCR",
741 Self::NeuralNetworkClassify => "NeuralNetworkClassify",
742 Self::NeuralNetworkDetect => "NeuralNetworkDetect",
743 Self::And => "And",
744 Self::Or => "Or",
745 Self::Custom => "Custom",
746 Self::Other(s) => s.as_str(),
747 }
748 }
749}
750
751#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
753#[serde(into = "String", from = "String")]
754pub enum ActionEnum {
755 DoNothing,
756 Click,
757 LongPress,
758 Swipe,
759 MultiSwipe,
760 TouchDown,
761 TouchMove,
762 TouchUp,
763 ClickKey,
764 LongPressKey,
765 KeyDown,
766 KeyUp,
767 InputText,
768 StartApp,
769 StopApp,
770 StopTask,
771 Scroll,
772 Command,
773 Shell,
774 Custom,
775 Other(String),
776}
777
778impl From<String> for ActionEnum {
779 fn from(s: String) -> Self {
780 match s.as_str() {
781 "DoNothing" => Self::DoNothing,
782 "Click" => Self::Click,
783 "LongPress" => Self::LongPress,
784 "Swipe" => Self::Swipe,
785 "MultiSwipe" => Self::MultiSwipe,
786 "TouchDown" => Self::TouchDown,
787 "TouchMove" => Self::TouchMove,
788 "TouchUp" => Self::TouchUp,
789 "ClickKey" => Self::ClickKey,
790 "LongPressKey" => Self::LongPressKey,
791 "KeyDown" => Self::KeyDown,
792 "KeyUp" => Self::KeyUp,
793 "InputText" => Self::InputText,
794 "StartApp" => Self::StartApp,
795 "StopApp" => Self::StopApp,
796 "StopTask" => Self::StopTask,
797 "Scroll" => Self::Scroll,
798 "Command" => Self::Command,
799 "Shell" => Self::Shell,
800 "Custom" => Self::Custom,
801 _ => Self::Other(s),
802 }
803 }
804}
805
806impl From<ActionEnum> for String {
807 fn from(act: ActionEnum) -> Self {
808 match act {
809 ActionEnum::DoNothing => "DoNothing".to_string(),
810 ActionEnum::Click => "Click".to_string(),
811 ActionEnum::LongPress => "LongPress".to_string(),
812 ActionEnum::Swipe => "Swipe".to_string(),
813 ActionEnum::MultiSwipe => "MultiSwipe".to_string(),
814 ActionEnum::TouchDown => "TouchDown".to_string(),
815 ActionEnum::TouchMove => "TouchMove".to_string(),
816 ActionEnum::TouchUp => "TouchUp".to_string(),
817 ActionEnum::ClickKey => "ClickKey".to_string(),
818 ActionEnum::LongPressKey => "LongPressKey".to_string(),
819 ActionEnum::KeyDown => "KeyDown".to_string(),
820 ActionEnum::KeyUp => "KeyUp".to_string(),
821 ActionEnum::InputText => "InputText".to_string(),
822 ActionEnum::StartApp => "StartApp".to_string(),
823 ActionEnum::StopApp => "StopApp".to_string(),
824 ActionEnum::StopTask => "StopTask".to_string(),
825 ActionEnum::Scroll => "Scroll".to_string(),
826 ActionEnum::Command => "Command".to_string(),
827 ActionEnum::Shell => "Shell".to_string(),
828 ActionEnum::Custom => "Custom".to_string(),
829 ActionEnum::Other(s) => s,
830 }
831 }
832}
833
834impl ActionEnum {
835 pub fn as_str(&self) -> &str {
836 match self {
837 Self::DoNothing => "DoNothing",
838 Self::Click => "Click",
839 Self::LongPress => "LongPress",
840 Self::Swipe => "Swipe",
841 Self::MultiSwipe => "MultiSwipe",
842 Self::TouchDown => "TouchDown",
843 Self::TouchMove => "TouchMove",
844 Self::TouchUp => "TouchUp",
845 Self::ClickKey => "ClickKey",
846 Self::LongPressKey => "LongPressKey",
847 Self::KeyDown => "KeyDown",
848 Self::KeyUp => "KeyUp",
849 Self::InputText => "InputText",
850 Self::StartApp => "StartApp",
851 Self::StopApp => "StopApp",
852 Self::StopTask => "StopTask",
853 Self::Scroll => "Scroll",
854 Self::Command => "Command",
855 Self::Shell => "Shell",
856 Self::Custom => "Custom",
857 Self::Other(s) => s.as_str(),
858 }
859 }
860}
861
862#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
864#[non_exhaustive]
865pub enum NotificationType {
866 Starting,
867 Succeeded,
868 Failed,
869 Unknown,
870}
871
872impl NotificationType {
873 pub fn from_message(msg: &str) -> Self {
874 if msg.ends_with(".Starting") {
875 Self::Starting
876 } else if msg.ends_with(".Succeeded") {
877 Self::Succeeded
878 } else if msg.ends_with(".Failed") {
879 Self::Failed
880 } else {
881 Self::Unknown
882 }
883 }
884}
885
886#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
889pub struct BoxAndScore {
890 #[serde(rename = "box")]
891 pub box_rect: (i32, i32, i32, i32),
892 pub score: f64,
893}
894
895#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
896pub struct BoxAndCount {
897 #[serde(rename = "box")]
898 pub box_rect: (i32, i32, i32, i32),
899 pub count: i32,
900}
901
902pub type TemplateMatchResult = BoxAndScore;
903pub type FeatureMatchResult = BoxAndCount;
904pub type ColorMatchResult = BoxAndCount;
905
906#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
907pub struct OCRResult {
908 #[serde(flatten)]
909 pub base: BoxAndScore,
910 pub text: String,
911}
912
913#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
914pub struct NeuralNetworkResult {
915 #[serde(flatten)]
916 pub base: BoxAndScore,
917 pub cls_index: i32,
918 pub label: String,
919}
920
921pub type NeuralNetworkClassifyResult = NeuralNetworkResult;
922pub type NeuralNetworkDetectResult = NeuralNetworkResult;
923
924#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
925pub struct CustomRecognitionResult {
926 #[serde(rename = "box")]
927 pub box_rect: (i32, i32, i32, i32),
928 pub detail: serde_json::Value,
929}
930
931#[cfg(test)]
932mod tests {
933 use super::{AndroidNativeControllerConfig, AndroidScreenResolution};
934 use serde_json::json;
935
936 #[test]
937 fn android_native_controller_config_serializes_expected_shape() {
938 let config = AndroidNativeControllerConfig {
939 library_path: "/data/local/tmp/libmaa_unit.so".to_string(),
940 screen_resolution: AndroidScreenResolution {
941 width: 1920,
942 height: 1080,
943 },
944 display_id: Some(1),
945 force_stop: Some(true),
946 };
947
948 let value = serde_json::to_value(config).unwrap();
949
950 assert_eq!(
951 value,
952 json!({
953 "library_path": "/data/local/tmp/libmaa_unit.so",
954 "screen_resolution": {
955 "width": 1920,
956 "height": 1080
957 },
958 "display_id": 1,
959 "force_stop": true
960 })
961 );
962 }
963}