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)]
403 pub struct LinuxScreencapMethod: u64 {
404 const NONE = sys::MaaLinuxScreencapMethod_None as u64;
405 const WLR = sys::MaaLinuxScreencapMethod_Wlr as u64;
407 const PIPEWIRE = sys::MaaLinuxScreencapMethod_PipeWire as u64;
409 }
410}
411
412bitflags::bitflags! {
413 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
415 pub struct LinuxInputMethod: u64 {
416 const NONE = sys::MaaLinuxInputMethod_None as u64;
417 const WLR = sys::MaaLinuxInputMethod_Wlr as u64;
419 const UINPUT = sys::MaaLinuxInputMethod_UInput as u64;
421 }
422}
423
424#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
426pub struct LinuxControllerConfig {
427 pub screencap_method: sys::MaaLinuxScreencapMethod,
429 pub input_method: sys::MaaLinuxInputMethod,
431 #[serde(default, skip_serializing_if = "Option::is_none")]
433 pub wlr_socket_path: Option<String>,
434 #[serde(default, skip_serializing_if = "Option::is_none")]
436 pub pw_socket_fd: Option<i32>,
437 #[serde(default, skip_serializing_if = "Option::is_none")]
439 pub pw_node_id: Option<u32>,
440 #[serde(default, skip_serializing_if = "Option::is_none")]
442 pub pw_screen_width: Option<i32>,
443 #[serde(default, skip_serializing_if = "Option::is_none")]
445 pub pw_screen_height: Option<i32>,
446 #[serde(default, skip_serializing_if = "Option::is_none")]
448 pub uinput_path: Option<String>,
449 #[serde(default, skip_serializing_if = "Option::is_none")]
451 pub use_win32_vk_code: Option<bool>,
452}
453
454bitflags::bitflags! {
459 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
471 pub struct Win32ScreencapMethod: u64 {
472 const GDI = 1;
473 const FRAME_POOL = 1 << 1;
474 const DXGI_DESKTOP_DUP = 1 << 2;
475 const DXGI_DESKTOP_DUP_WINDOW = 1 << 3;
476 const PRINT_WINDOW = 1 << 4;
477 const SCREEN_DC = 1 << 5;
478 const ALL = !0;
479 const FOREGROUND = Self::DXGI_DESKTOP_DUP_WINDOW.bits() | Self::SCREEN_DC.bits();
480 const BACKGROUND = Self::FRAME_POOL.bits() | Self::PRINT_WINDOW.bits();
481 }
482}
483
484bitflags::bitflags! {
485 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
487 pub struct Win32InputMethod: u64 {
488 const SEIZE = 1;
489 const SEND_MESSAGE = 1 << 1;
490 const POST_MESSAGE = 1 << 2;
491 const LEGACY_EVENT = 1 << 3;
492 const POST_THREAD_MESSAGE = 1 << 4;
494 const SEND_MESSAGE_WITH_CURSOR_POS = 1 << 5;
495 const POST_MESSAGE_WITH_CURSOR_POS = 1 << 6;
496 const SEND_MESSAGE_WITH_WINDOW_POS = 1 << 7;
497 const POST_MESSAGE_WITH_WINDOW_POS = 1 << 8;
498 const INTERCEPTION = sys::MaaWin32InputMethod_Interception as u64;
501 }
502}
503
504#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
506pub struct RecognitionDetail {
507 pub node_name: String,
509 pub algorithm: AlgorithmEnum,
511 pub hit: bool,
513 pub box_rect: Rect,
515 pub detail: serde_json::Value,
517 #[serde(skip)]
519 pub raw_image: Option<Vec<u8>>,
520 #[serde(skip)]
522 pub draw_images: Vec<Vec<u8>>,
523 #[serde(default)]
525 pub sub_details: Vec<RecognitionDetail>,
526}
527
528impl RecognitionDetail {
529 pub fn as_template_match_result(&self) -> Option<TemplateMatchResult> {
530 serde_json::from_value(self.detail.clone()).ok()
531 }
532
533 pub fn as_feature_match_result(&self) -> Option<FeatureMatchResult> {
534 serde_json::from_value(self.detail.clone()).ok()
535 }
536
537 pub fn as_color_match_result(&self) -> Option<ColorMatchResult> {
538 serde_json::from_value(self.detail.clone()).ok()
539 }
540
541 pub fn as_ocr_result(&self) -> Option<OCRResult> {
542 serde_json::from_value(self.detail.clone()).ok()
543 }
544
545 pub fn as_neural_network_result(&self) -> Option<NeuralNetworkResult> {
546 serde_json::from_value(self.detail.clone()).ok()
547 }
548
549 pub fn as_custom_result(&self) -> Option<CustomRecognitionResult> {
550 serde_json::from_value(self.detail.clone()).ok()
551 }
552}
553
554#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
556pub struct ActionDetail {
557 pub node_name: String,
559 pub action: ActionEnum,
561 pub box_rect: Rect,
563 pub success: bool,
565 pub detail: serde_json::Value,
567}
568
569#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
570pub struct WaitFreezesDetail {
571 pub wf_id: MaaId,
572 pub name: String,
573 pub phase: String,
574 pub success: bool,
575 pub elapsed_ms: u64,
576 #[serde(default)]
577 pub reco_id_list: Vec<MaaId>,
578 pub roi: Rect,
579}
580
581impl ActionDetail {
582 pub fn as_click_result(&self) -> Option<ClickActionResult> {
583 serde_json::from_value(self.detail.clone()).ok()
584 }
585
586 pub fn as_long_press_result(&self) -> Option<LongPressActionResult> {
587 serde_json::from_value(self.detail.clone()).ok()
588 }
589
590 pub fn as_swipe_result(&self) -> Option<SwipeActionResult> {
591 serde_json::from_value(self.detail.clone()).ok()
592 }
593
594 pub fn as_multi_swipe_result(&self) -> Option<MultiSwipeActionResult> {
595 serde_json::from_value(self.detail.clone()).ok()
596 }
597
598 pub fn as_click_key_result(&self) -> Option<ClickKeyActionResult> {
599 serde_json::from_value(self.detail.clone()).ok()
600 }
601
602 pub fn as_input_text_result(&self) -> Option<InputTextActionResult> {
603 serde_json::from_value(self.detail.clone()).ok()
604 }
605
606 pub fn as_app_result(&self) -> Option<AppActionResult> {
607 serde_json::from_value(self.detail.clone()).ok()
608 }
609
610 pub fn as_scroll_result(&self) -> Option<ScrollActionResult> {
611 serde_json::from_value(self.detail.clone()).ok()
612 }
613
614 pub fn as_touch_result(&self) -> Option<TouchActionResult> {
615 serde_json::from_value(self.detail.clone()).ok()
616 }
617
618 pub fn as_shell_result(&self) -> Option<ShellActionResult> {
619 serde_json::from_value(self.detail.clone()).ok()
620 }
621}
622
623#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
629pub struct ClickActionResult {
630 pub point: Point,
631 pub contact: i32,
632 #[serde(default)]
633 pub pressure: i32,
634}
635
636#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
638pub struct LongPressActionResult {
639 pub point: Point,
640 pub duration: i32,
641 pub contact: i32,
642 #[serde(default)]
643 pub pressure: i32,
644}
645
646#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
648pub struct SwipeActionResult {
649 pub begin: Point,
650 pub end: Vec<Point>,
651 #[serde(default)]
652 pub end_hold: Vec<i32>,
653 #[serde(default)]
654 pub duration: Vec<i32>,
655 #[serde(default)]
656 pub only_hover: bool,
657 #[serde(default)]
658 pub starting: i32,
659 pub contact: i32,
660 #[serde(default)]
661 pub pressure: i32,
662}
663
664#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
666pub struct MultiSwipeActionResult {
667 pub swipes: Vec<SwipeActionResult>,
668}
669
670#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
672pub struct ClickKeyActionResult {
673 pub keycode: Vec<i32>,
674}
675
676#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
678pub struct LongPressKeyActionResult {
679 pub keycode: Vec<i32>,
680 pub duration: i32,
681}
682
683#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
685pub struct InputTextActionResult {
686 pub text: String,
687}
688
689#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
691pub struct AppActionResult {
692 pub package: String,
693}
694
695#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
697pub struct ScrollActionResult {
698 #[serde(default)]
699 pub point: Point,
700 pub dx: i32,
701 pub dy: i32,
702}
703
704#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
706pub struct TouchActionResult {
707 pub contact: i32,
708 pub point: Point,
709 #[serde(default)]
710 pub pressure: i32,
711}
712
713#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
715pub struct ShellActionResult {
716 pub cmd: String,
717 pub shell_timeout: i32,
718 pub success: bool,
719 pub output: String,
720}
721
722#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
724pub struct NodeDetail {
725 pub node_name: String,
726 pub reco_id: MaaId,
728 pub act_id: MaaId,
730 #[serde(default)]
732 pub recognition: Option<RecognitionDetail>,
733 #[serde(default)]
735 pub action: Option<ActionDetail>,
736 pub completed: bool,
738}
739
740#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
742pub struct TaskDetail {
743 pub entry: String,
745 pub node_id_list: Vec<MaaId>,
747 pub status: MaaStatus,
749 #[serde(default)]
751 pub nodes: Vec<Option<NodeDetail>>,
752}
753
754#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
756#[serde(into = "String", from = "String")]
757pub enum AlgorithmEnum {
758 DirectHit,
759 TemplateMatch,
760 FeatureMatch,
761 ColorMatch,
762 OCR,
763 NeuralNetworkClassify,
764 NeuralNetworkDetect,
765 And,
766 Or,
767 Custom,
768 Other(String),
769}
770
771impl From<String> for AlgorithmEnum {
772 fn from(s: String) -> Self {
773 match s.as_str() {
774 "DirectHit" => Self::DirectHit,
775 "TemplateMatch" => Self::TemplateMatch,
776 "FeatureMatch" => Self::FeatureMatch,
777 "ColorMatch" => Self::ColorMatch,
778 "OCR" => Self::OCR,
779 "NeuralNetworkClassify" => Self::NeuralNetworkClassify,
780 "NeuralNetworkDetect" => Self::NeuralNetworkDetect,
781 "And" => Self::And,
782 "Or" => Self::Or,
783 "Custom" => Self::Custom,
784 _ => Self::Other(s),
785 }
786 }
787}
788
789impl From<AlgorithmEnum> for String {
790 fn from(algo: AlgorithmEnum) -> Self {
791 match algo {
792 AlgorithmEnum::DirectHit => "DirectHit".to_string(),
793 AlgorithmEnum::TemplateMatch => "TemplateMatch".to_string(),
794 AlgorithmEnum::FeatureMatch => "FeatureMatch".to_string(),
795 AlgorithmEnum::ColorMatch => "ColorMatch".to_string(),
796 AlgorithmEnum::OCR => "OCR".to_string(),
797 AlgorithmEnum::NeuralNetworkClassify => "NeuralNetworkClassify".to_string(),
798 AlgorithmEnum::NeuralNetworkDetect => "NeuralNetworkDetect".to_string(),
799 AlgorithmEnum::And => "And".to_string(),
800 AlgorithmEnum::Or => "Or".to_string(),
801 AlgorithmEnum::Custom => "Custom".to_string(),
802 AlgorithmEnum::Other(s) => s,
803 }
804 }
805}
806
807impl AlgorithmEnum {
808 pub fn as_str(&self) -> &str {
809 match self {
810 Self::DirectHit => "DirectHit",
811 Self::TemplateMatch => "TemplateMatch",
812 Self::FeatureMatch => "FeatureMatch",
813 Self::ColorMatch => "ColorMatch",
814 Self::OCR => "OCR",
815 Self::NeuralNetworkClassify => "NeuralNetworkClassify",
816 Self::NeuralNetworkDetect => "NeuralNetworkDetect",
817 Self::And => "And",
818 Self::Or => "Or",
819 Self::Custom => "Custom",
820 Self::Other(s) => s.as_str(),
821 }
822 }
823}
824
825#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
827#[serde(into = "String", from = "String")]
828pub enum ActionEnum {
829 DoNothing,
830 Click,
831 LongPress,
832 Swipe,
833 MultiSwipe,
834 TouchDown,
835 TouchMove,
836 TouchUp,
837 ClickKey,
838 LongPressKey,
839 KeyDown,
840 KeyUp,
841 InputText,
842 StartApp,
843 StopApp,
844 StopTask,
845 Scroll,
846 Command,
847 Shell,
848 Custom,
849 Other(String),
850}
851
852impl From<String> for ActionEnum {
853 fn from(s: String) -> Self {
854 match s.as_str() {
855 "DoNothing" => Self::DoNothing,
856 "Click" => Self::Click,
857 "LongPress" => Self::LongPress,
858 "Swipe" => Self::Swipe,
859 "MultiSwipe" => Self::MultiSwipe,
860 "TouchDown" => Self::TouchDown,
861 "TouchMove" => Self::TouchMove,
862 "TouchUp" => Self::TouchUp,
863 "ClickKey" => Self::ClickKey,
864 "LongPressKey" => Self::LongPressKey,
865 "KeyDown" => Self::KeyDown,
866 "KeyUp" => Self::KeyUp,
867 "InputText" => Self::InputText,
868 "StartApp" => Self::StartApp,
869 "StopApp" => Self::StopApp,
870 "StopTask" => Self::StopTask,
871 "Scroll" => Self::Scroll,
872 "Command" => Self::Command,
873 "Shell" => Self::Shell,
874 "Custom" => Self::Custom,
875 _ => Self::Other(s),
876 }
877 }
878}
879
880impl From<ActionEnum> for String {
881 fn from(act: ActionEnum) -> Self {
882 match act {
883 ActionEnum::DoNothing => "DoNothing".to_string(),
884 ActionEnum::Click => "Click".to_string(),
885 ActionEnum::LongPress => "LongPress".to_string(),
886 ActionEnum::Swipe => "Swipe".to_string(),
887 ActionEnum::MultiSwipe => "MultiSwipe".to_string(),
888 ActionEnum::TouchDown => "TouchDown".to_string(),
889 ActionEnum::TouchMove => "TouchMove".to_string(),
890 ActionEnum::TouchUp => "TouchUp".to_string(),
891 ActionEnum::ClickKey => "ClickKey".to_string(),
892 ActionEnum::LongPressKey => "LongPressKey".to_string(),
893 ActionEnum::KeyDown => "KeyDown".to_string(),
894 ActionEnum::KeyUp => "KeyUp".to_string(),
895 ActionEnum::InputText => "InputText".to_string(),
896 ActionEnum::StartApp => "StartApp".to_string(),
897 ActionEnum::StopApp => "StopApp".to_string(),
898 ActionEnum::StopTask => "StopTask".to_string(),
899 ActionEnum::Scroll => "Scroll".to_string(),
900 ActionEnum::Command => "Command".to_string(),
901 ActionEnum::Shell => "Shell".to_string(),
902 ActionEnum::Custom => "Custom".to_string(),
903 ActionEnum::Other(s) => s,
904 }
905 }
906}
907
908impl ActionEnum {
909 pub fn as_str(&self) -> &str {
910 match self {
911 Self::DoNothing => "DoNothing",
912 Self::Click => "Click",
913 Self::LongPress => "LongPress",
914 Self::Swipe => "Swipe",
915 Self::MultiSwipe => "MultiSwipe",
916 Self::TouchDown => "TouchDown",
917 Self::TouchMove => "TouchMove",
918 Self::TouchUp => "TouchUp",
919 Self::ClickKey => "ClickKey",
920 Self::LongPressKey => "LongPressKey",
921 Self::KeyDown => "KeyDown",
922 Self::KeyUp => "KeyUp",
923 Self::InputText => "InputText",
924 Self::StartApp => "StartApp",
925 Self::StopApp => "StopApp",
926 Self::StopTask => "StopTask",
927 Self::Scroll => "Scroll",
928 Self::Command => "Command",
929 Self::Shell => "Shell",
930 Self::Custom => "Custom",
931 Self::Other(s) => s.as_str(),
932 }
933 }
934}
935
936#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
938#[non_exhaustive]
939pub enum NotificationType {
940 Starting,
941 Succeeded,
942 Failed,
943 Unknown,
944}
945
946impl NotificationType {
947 pub fn from_message(msg: &str) -> Self {
948 if msg.ends_with(".Starting") {
949 Self::Starting
950 } else if msg.ends_with(".Succeeded") {
951 Self::Succeeded
952 } else if msg.ends_with(".Failed") {
953 Self::Failed
954 } else {
955 Self::Unknown
956 }
957 }
958}
959
960#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
963pub struct BoxAndScore {
964 #[serde(rename = "box")]
965 pub box_rect: (i32, i32, i32, i32),
966 pub score: f64,
967}
968
969#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
970pub struct BoxAndCount {
971 #[serde(rename = "box")]
972 pub box_rect: (i32, i32, i32, i32),
973 pub count: i32,
974}
975
976pub type TemplateMatchResult = BoxAndScore;
977pub type FeatureMatchResult = BoxAndCount;
978pub type ColorMatchResult = BoxAndCount;
979
980#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
981pub struct OCRResult {
982 #[serde(flatten)]
983 pub base: BoxAndScore,
984 pub text: String,
985}
986
987#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
988pub struct NeuralNetworkResult {
989 #[serde(flatten)]
990 pub base: BoxAndScore,
991 pub cls_index: i32,
992 pub label: String,
993}
994
995pub type NeuralNetworkClassifyResult = NeuralNetworkResult;
996pub type NeuralNetworkDetectResult = NeuralNetworkResult;
997
998#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
999pub struct CustomRecognitionResult {
1000 #[serde(rename = "box")]
1001 pub box_rect: (i32, i32, i32, i32),
1002 pub detail: serde_json::Value,
1003}
1004
1005#[cfg(test)]
1006mod tests {
1007 use super::{
1008 AndroidNativeControllerConfig, AndroidScreenResolution, LinuxControllerConfig,
1009 LinuxInputMethod, LinuxScreencapMethod,
1010 };
1011 use serde_json::json;
1012
1013 #[test]
1014 fn android_native_controller_config_serializes_expected_shape() {
1015 let config = AndroidNativeControllerConfig {
1016 library_path: "/data/local/tmp/libmaa_unit.so".to_string(),
1017 screen_resolution: AndroidScreenResolution {
1018 width: 1920,
1019 height: 1080,
1020 },
1021 display_id: Some(1),
1022 force_stop: Some(true),
1023 };
1024
1025 let value = serde_json::to_value(config).unwrap();
1026
1027 assert_eq!(
1028 value,
1029 json!({
1030 "library_path": "/data/local/tmp/libmaa_unit.so",
1031 "screen_resolution": {
1032 "width": 1920,
1033 "height": 1080
1034 },
1035 "display_id": 1,
1036 "force_stop": true
1037 })
1038 );
1039 }
1040
1041 #[test]
1042 fn linux_controller_config_serializes_expected_shape() {
1043 let config = LinuxControllerConfig {
1044 screencap_method: LinuxScreencapMethod::PIPEWIRE.bits(),
1045 input_method: LinuxInputMethod::UINPUT.bits(),
1046 wlr_socket_path: None,
1047 pw_socket_fd: Some(42),
1048 pw_node_id: Some(7),
1049 pw_screen_width: Some(1920),
1050 pw_screen_height: Some(1080),
1051 uinput_path: None,
1052 use_win32_vk_code: Some(true),
1053 };
1054
1055 let value = serde_json::to_value(config).unwrap();
1056
1057 assert_eq!(
1058 value,
1059 json!({
1060 "screencap_method": 4,
1061 "input_method": 2,
1062 "pw_socket_fd": 42,
1063 "pw_node_id": 7,
1064 "pw_screen_width": 1920,
1065 "pw_screen_height": 1080,
1066 "use_win32_vk_code": true
1067 })
1068 );
1069 }
1070}