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