1use crate::sys;
4use std::fmt;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
11pub struct MaaStatus(pub i32);
12
13pub type MaaId = i64;
15
16impl MaaStatus {
17 pub const INVALID: Self = Self(sys::MaaStatusEnum_MaaStatus_Invalid as i32);
18 pub const PENDING: Self = Self(sys::MaaStatusEnum_MaaStatus_Pending as i32);
19 pub const RUNNING: Self = Self(sys::MaaStatusEnum_MaaStatus_Running as i32);
20 pub const SUCCEEDED: Self = Self(sys::MaaStatusEnum_MaaStatus_Succeeded as i32);
21 pub const FAILED: Self = Self(sys::MaaStatusEnum_MaaStatus_Failed as i32);
22
23 pub fn is_success(&self) -> bool {
25 *self == Self::SUCCEEDED
26 }
27
28 pub fn succeeded(&self) -> bool {
30 *self == Self::SUCCEEDED
31 }
32
33 pub fn is_failed(&self) -> bool {
35 *self == Self::FAILED
36 }
37
38 pub fn failed(&self) -> bool {
40 *self == Self::FAILED
41 }
42
43 pub fn done(&self) -> bool {
45 *self == Self::SUCCEEDED || *self == Self::FAILED
46 }
47
48 pub fn pending(&self) -> bool {
50 *self == Self::PENDING
51 }
52
53 pub fn running(&self) -> bool {
55 *self == Self::RUNNING
56 }
57}
58
59impl fmt::Display for MaaStatus {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 match *self {
62 Self::INVALID => write!(f, "Invalid"),
63 Self::PENDING => write!(f, "Pending"),
64 Self::RUNNING => write!(f, "Running"),
65 Self::SUCCEEDED => write!(f, "Succeeded"),
66 Self::FAILED => write!(f, "Failed"),
67 _ => write!(f, "Unknown({})", self.0),
68 }
69 }
70}
71
72pub fn check_bool(ret: sys::MaaBool) -> crate::MaaResult<()> {
73 if ret != 0 {
74 Ok(())
75 } else {
76 Err(crate::MaaError::FrameworkError(0))
77 }
78}
79
80impl From<i32> for MaaStatus {
81 fn from(value: i32) -> Self {
82 Self(value)
83 }
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
88pub struct Rect {
89 pub x: i32,
90 pub y: i32,
91 pub width: i32,
92 pub height: i32,
93}
94
95impl From<sys::MaaRect> for Rect {
96 fn from(r: sys::MaaRect) -> Self {
97 Self {
98 x: r.x,
99 y: r.y,
100 width: r.width,
101 height: r.height,
102 }
103 }
104}
105
106impl Default for Rect {
107 fn default() -> Self {
108 Self {
109 x: 0,
110 y: 0,
111 width: 0,
112 height: 0,
113 }
114 }
115}
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
119pub struct Point {
120 pub x: i32,
121 pub y: i32,
122}
123
124impl Point {
125 pub fn new(x: i32, y: i32) -> Self {
126 Self { x, y }
127 }
128}
129
130#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
136#[repr(u64)]
137#[non_exhaustive]
138pub enum GamepadType {
139 Xbox360 = 0,
141 DualShock4 = 1,
143}
144
145#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
147#[repr(i32)]
148#[non_exhaustive]
149pub enum GamepadContact {
150 LeftStick = 0,
152 RightStick = 1,
154 LeftTrigger = 2,
156 RightTrigger = 3,
158}
159
160bitflags::bitflags! {
161 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
165 pub struct GamepadButton: u32 {
166 const DPAD_UP = 0x0001;
168 const DPAD_DOWN = 0x0002;
169 const DPAD_LEFT = 0x0004;
170 const DPAD_RIGHT = 0x0008;
171
172 const START = 0x0010;
174 const BACK = 0x0020;
175 const LEFT_THUMB = 0x0040; const RIGHT_THUMB = 0x0080; const LB = 0x0100; const RB = 0x0200; const GUIDE = 0x0400;
184
185 const A = 0x1000;
187 const B = 0x2000;
188 const X = 0x4000;
189 const Y = 0x8000;
190
191 const PS = 0x10000;
193 const TOUCHPAD = 0x20000;
194 }
195}
196
197impl GamepadButton {
198 pub const CROSS: Self = Self::A;
200 pub const CIRCLE: Self = Self::B;
201 pub const SQUARE: Self = Self::X;
202 pub const TRIANGLE: Self = Self::Y;
203 pub const L1: Self = Self::LB;
204 pub const R1: Self = Self::RB;
205 pub const L3: Self = Self::LEFT_THUMB;
206 pub const R3: Self = Self::RIGHT_THUMB;
207 pub const OPTIONS: Self = Self::START;
208 pub const SHARE: Self = Self::BACK;
209}
210
211bitflags::bitflags! {
216 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
220 pub struct ControllerFeature: u64 {
221 const USE_MOUSE_DOWN_UP_INSTEAD_OF_CLICK = 1;
225 const USE_KEY_DOWN_UP_INSTEAD_OF_CLICK = 1 << 1;
228 const NO_SCALING_TOUCH_POINTS = 1 << 2;
231 }
232}
233
234bitflags::bitflags! {
239 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
244 pub struct AdbScreencapMethod: u64 {
245 const ENCODE_TO_FILE_AND_PULL = 1;
246 const ENCODE = 1 << 1;
247 const RAW_WITH_GZIP = 1 << 2;
248 const RAW_BY_NETCAT = 1 << 3;
249 const MINICAP_DIRECT = 1 << 4;
250 const MINICAP_STREAM = 1 << 5;
251 const EMULATOR_EXTRAS = 1 << 6;
252 const ALL = !0;
253 }
254}
255
256impl AdbScreencapMethod {
257 pub const DEFAULT: Self = Self::from_bits_truncate(
259 Self::ALL.bits()
260 & !Self::RAW_BY_NETCAT.bits()
261 & !Self::MINICAP_DIRECT.bits()
262 & !Self::MINICAP_STREAM.bits(),
263 );
264}
265
266impl Default for AdbScreencapMethod {
267 fn default() -> Self {
268 Self::DEFAULT
269 }
270}
271
272bitflags::bitflags! {
273 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
278 pub struct AdbInputMethod: u64 {
279 const ADB_SHELL = 1;
280 const MINITOUCH_AND_ADB_KEY = 1 << 1;
281 const MAATOUCH = 1 << 2;
282 const EMULATOR_EXTRAS = 1 << 3;
283 const ALL = !0;
284 }
285}
286
287impl AdbInputMethod {
288 pub const DEFAULT: Self =
290 Self::from_bits_truncate(Self::ALL.bits() & !Self::EMULATOR_EXTRAS.bits());
291}
292
293impl Default for AdbInputMethod {
294 fn default() -> Self {
295 Self::DEFAULT
296 }
297}
298
299bitflags::bitflags! {
304 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
306 pub struct Win32ScreencapMethod: u64 {
307 const GDI = 1;
308 const FRAME_POOL = 1 << 1;
309 const DXGI_DESKTOP_DUP = 1 << 2;
310 const DXGI_DESKTOP_DUP_WINDOW = 1 << 3;
311 const PRINT_WINDOW = 1 << 4;
312 const SCREEN_DC = 1 << 5;
313 }
314}
315
316bitflags::bitflags! {
317 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
319 pub struct Win32InputMethod: u64 {
320 const SEIZE = 1;
321 const SEND_MESSAGE = 1 << 1;
322 const POST_MESSAGE = 1 << 2;
323 const LEGACY_EVENT = 1 << 3;
324 const POST_THREAD_MESSAGE = 1 << 4;
325 const SEND_MESSAGE_WITH_CURSOR_POS = 1 << 5;
326 const POST_MESSAGE_WITH_CURSOR_POS = 1 << 6;
327 }
328}
329
330#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
332pub struct RecognitionDetail {
333 pub node_name: String,
335 pub algorithm: AlgorithmEnum,
337 pub hit: bool,
339 pub box_rect: Rect,
341 pub detail: serde_json::Value,
343 #[serde(skip)]
345 pub raw_image: Option<Vec<u8>>,
346 #[serde(skip)]
348 pub draw_images: Vec<Vec<u8>>,
349 #[serde(default)]
351 pub sub_details: Vec<RecognitionDetail>,
352}
353
354impl RecognitionDetail {
355 pub fn as_template_match_result(&self) -> Option<TemplateMatchResult> {
356 serde_json::from_value(self.detail.clone()).ok()
357 }
358
359 pub fn as_feature_match_result(&self) -> Option<FeatureMatchResult> {
360 serde_json::from_value(self.detail.clone()).ok()
361 }
362
363 pub fn as_color_match_result(&self) -> Option<ColorMatchResult> {
364 serde_json::from_value(self.detail.clone()).ok()
365 }
366
367 pub fn as_ocr_result(&self) -> Option<OCRResult> {
368 serde_json::from_value(self.detail.clone()).ok()
369 }
370
371 pub fn as_neural_network_result(&self) -> Option<NeuralNetworkResult> {
372 serde_json::from_value(self.detail.clone()).ok()
373 }
374
375 pub fn as_custom_result(&self) -> Option<CustomRecognitionResult> {
376 serde_json::from_value(self.detail.clone()).ok()
377 }
378}
379
380#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
382pub struct ActionDetail {
383 pub node_name: String,
385 pub action: ActionEnum,
387 pub box_rect: Rect,
389 pub success: bool,
391 pub detail: serde_json::Value,
393}
394
395impl ActionDetail {
396 pub fn as_click_result(&self) -> Option<ClickActionResult> {
397 serde_json::from_value(self.detail.clone()).ok()
398 }
399
400 pub fn as_long_press_result(&self) -> Option<LongPressActionResult> {
401 serde_json::from_value(self.detail.clone()).ok()
402 }
403
404 pub fn as_swipe_result(&self) -> Option<SwipeActionResult> {
405 serde_json::from_value(self.detail.clone()).ok()
406 }
407
408 pub fn as_multi_swipe_result(&self) -> Option<MultiSwipeActionResult> {
409 serde_json::from_value(self.detail.clone()).ok()
410 }
411
412 pub fn as_click_key_result(&self) -> Option<ClickKeyActionResult> {
413 serde_json::from_value(self.detail.clone()).ok()
414 }
415
416 pub fn as_input_text_result(&self) -> Option<InputTextActionResult> {
417 serde_json::from_value(self.detail.clone()).ok()
418 }
419
420 pub fn as_app_result(&self) -> Option<AppActionResult> {
421 serde_json::from_value(self.detail.clone()).ok()
422 }
423
424 pub fn as_scroll_result(&self) -> Option<ScrollActionResult> {
425 serde_json::from_value(self.detail.clone()).ok()
426 }
427
428 pub fn as_touch_result(&self) -> Option<TouchActionResult> {
429 serde_json::from_value(self.detail.clone()).ok()
430 }
431
432 pub fn as_shell_result(&self) -> Option<ShellActionResult> {
433 serde_json::from_value(self.detail.clone()).ok()
434 }
435}
436
437#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
443pub struct ClickActionResult {
444 pub point: Point,
445 pub contact: i32,
446}
447
448#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
450pub struct LongPressActionResult {
451 pub point: Point,
452 pub duration: i32,
453 pub contact: i32,
454}
455
456#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
458pub struct SwipeActionResult {
459 pub begin: Point,
460 pub end: Vec<Point>,
461 #[serde(default)]
462 pub end_hold: Vec<i32>,
463 #[serde(default)]
464 pub duration: Vec<i32>,
465 #[serde(default)]
466 pub only_hover: bool,
467 #[serde(default)]
468 pub starting: i32,
469 pub contact: i32,
470}
471
472#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
474pub struct MultiSwipeActionResult {
475 pub swipes: Vec<SwipeActionResult>,
476}
477
478#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
480pub struct ClickKeyActionResult {
481 pub keycode: Vec<i32>,
482}
483
484#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
486pub struct LongPressKeyActionResult {
487 pub keycode: Vec<i32>,
488 pub duration: i32,
489}
490
491#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
493pub struct InputTextActionResult {
494 pub text: String,
495}
496
497#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
499pub struct AppActionResult {
500 pub package: String,
501}
502
503#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
505pub struct ScrollActionResult {
506 pub dx: i32,
507 pub dy: i32,
508}
509
510#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
512pub struct TouchActionResult {
513 pub contact: i32,
514 pub point: Point,
515 #[serde(default)]
516 pub pressure: i32,
517}
518
519#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
521pub struct ShellActionResult {
522 pub cmd: String,
523 pub timeout: i32,
524 pub success: bool,
525 pub output: String,
526}
527
528#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
530pub struct NodeDetail {
531 pub node_name: String,
532 pub reco_id: MaaId,
534 pub act_id: MaaId,
536 #[serde(default)]
538 pub recognition: Option<RecognitionDetail>,
539 #[serde(default)]
541 pub action: Option<ActionDetail>,
542 pub completed: bool,
544}
545
546#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
548pub struct TaskDetail {
549 pub entry: String,
551 pub node_id_list: Vec<MaaId>,
553 pub status: MaaStatus,
555 #[serde(default)]
557 pub nodes: Vec<Option<NodeDetail>>,
558}
559
560#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
562#[serde(into = "String", from = "String")]
563pub enum AlgorithmEnum {
564 DirectHit,
565 TemplateMatch,
566 FeatureMatch,
567 ColorMatch,
568 OCR,
569 NeuralNetworkClassify,
570 NeuralNetworkDetect,
571 And,
572 Or,
573 Custom,
574 Other(String),
575}
576
577impl From<String> for AlgorithmEnum {
578 fn from(s: String) -> Self {
579 match s.as_str() {
580 "DirectHit" => Self::DirectHit,
581 "TemplateMatch" => Self::TemplateMatch,
582 "FeatureMatch" => Self::FeatureMatch,
583 "ColorMatch" => Self::ColorMatch,
584 "OCR" => Self::OCR,
585 "NeuralNetworkClassify" => Self::NeuralNetworkClassify,
586 "NeuralNetworkDetect" => Self::NeuralNetworkDetect,
587 "And" => Self::And,
588 "Or" => Self::Or,
589 "Custom" => Self::Custom,
590 _ => Self::Other(s),
591 }
592 }
593}
594
595impl From<AlgorithmEnum> for String {
596 fn from(algo: AlgorithmEnum) -> Self {
597 match algo {
598 AlgorithmEnum::DirectHit => "DirectHit".to_string(),
599 AlgorithmEnum::TemplateMatch => "TemplateMatch".to_string(),
600 AlgorithmEnum::FeatureMatch => "FeatureMatch".to_string(),
601 AlgorithmEnum::ColorMatch => "ColorMatch".to_string(),
602 AlgorithmEnum::OCR => "OCR".to_string(),
603 AlgorithmEnum::NeuralNetworkClassify => "NeuralNetworkClassify".to_string(),
604 AlgorithmEnum::NeuralNetworkDetect => "NeuralNetworkDetect".to_string(),
605 AlgorithmEnum::And => "And".to_string(),
606 AlgorithmEnum::Or => "Or".to_string(),
607 AlgorithmEnum::Custom => "Custom".to_string(),
608 AlgorithmEnum::Other(s) => s,
609 }
610 }
611}
612
613impl AlgorithmEnum {
614 pub fn as_str(&self) -> &str {
615 match self {
616 Self::DirectHit => "DirectHit",
617 Self::TemplateMatch => "TemplateMatch",
618 Self::FeatureMatch => "FeatureMatch",
619 Self::ColorMatch => "ColorMatch",
620 Self::OCR => "OCR",
621 Self::NeuralNetworkClassify => "NeuralNetworkClassify",
622 Self::NeuralNetworkDetect => "NeuralNetworkDetect",
623 Self::And => "And",
624 Self::Or => "Or",
625 Self::Custom => "Custom",
626 Self::Other(s) => s.as_str(),
627 }
628 }
629}
630
631#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
633#[serde(into = "String", from = "String")]
634pub enum ActionEnum {
635 DoNothing,
636 Click,
637 LongPress,
638 Swipe,
639 MultiSwipe,
640 TouchDown,
641 TouchMove,
642 TouchUp,
643 ClickKey,
644 LongPressKey,
645 KeyDown,
646 KeyUp,
647 InputText,
648 StartApp,
649 StopApp,
650 StopTask,
651 Scroll,
652 Command,
653 Shell,
654 Custom,
655 Other(String),
656}
657
658impl From<String> for ActionEnum {
659 fn from(s: String) -> Self {
660 match s.as_str() {
661 "DoNothing" => Self::DoNothing,
662 "Click" => Self::Click,
663 "LongPress" => Self::LongPress,
664 "Swipe" => Self::Swipe,
665 "MultiSwipe" => Self::MultiSwipe,
666 "TouchDown" => Self::TouchDown,
667 "TouchMove" => Self::TouchMove,
668 "TouchUp" => Self::TouchUp,
669 "ClickKey" => Self::ClickKey,
670 "LongPressKey" => Self::LongPressKey,
671 "KeyDown" => Self::KeyDown,
672 "KeyUp" => Self::KeyUp,
673 "InputText" => Self::InputText,
674 "StartApp" => Self::StartApp,
675 "StopApp" => Self::StopApp,
676 "StopTask" => Self::StopTask,
677 "Scroll" => Self::Scroll,
678 "Command" => Self::Command,
679 "Shell" => Self::Shell,
680 "Custom" => Self::Custom,
681 _ => Self::Other(s),
682 }
683 }
684}
685
686impl From<ActionEnum> for String {
687 fn from(act: ActionEnum) -> Self {
688 match act {
689 ActionEnum::DoNothing => "DoNothing".to_string(),
690 ActionEnum::Click => "Click".to_string(),
691 ActionEnum::LongPress => "LongPress".to_string(),
692 ActionEnum::Swipe => "Swipe".to_string(),
693 ActionEnum::MultiSwipe => "MultiSwipe".to_string(),
694 ActionEnum::TouchDown => "TouchDown".to_string(),
695 ActionEnum::TouchMove => "TouchMove".to_string(),
696 ActionEnum::TouchUp => "TouchUp".to_string(),
697 ActionEnum::ClickKey => "ClickKey".to_string(),
698 ActionEnum::LongPressKey => "LongPressKey".to_string(),
699 ActionEnum::KeyDown => "KeyDown".to_string(),
700 ActionEnum::KeyUp => "KeyUp".to_string(),
701 ActionEnum::InputText => "InputText".to_string(),
702 ActionEnum::StartApp => "StartApp".to_string(),
703 ActionEnum::StopApp => "StopApp".to_string(),
704 ActionEnum::StopTask => "StopTask".to_string(),
705 ActionEnum::Scroll => "Scroll".to_string(),
706 ActionEnum::Command => "Command".to_string(),
707 ActionEnum::Shell => "Shell".to_string(),
708 ActionEnum::Custom => "Custom".to_string(),
709 ActionEnum::Other(s) => s,
710 }
711 }
712}
713
714impl ActionEnum {
715 pub fn as_str(&self) -> &str {
716 match self {
717 Self::DoNothing => "DoNothing",
718 Self::Click => "Click",
719 Self::LongPress => "LongPress",
720 Self::Swipe => "Swipe",
721 Self::MultiSwipe => "MultiSwipe",
722 Self::TouchDown => "TouchDown",
723 Self::TouchMove => "TouchMove",
724 Self::TouchUp => "TouchUp",
725 Self::ClickKey => "ClickKey",
726 Self::LongPressKey => "LongPressKey",
727 Self::KeyDown => "KeyDown",
728 Self::KeyUp => "KeyUp",
729 Self::InputText => "InputText",
730 Self::StartApp => "StartApp",
731 Self::StopApp => "StopApp",
732 Self::StopTask => "StopTask",
733 Self::Scroll => "Scroll",
734 Self::Command => "Command",
735 Self::Shell => "Shell",
736 Self::Custom => "Custom",
737 Self::Other(s) => s.as_str(),
738 }
739 }
740}
741
742#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
744#[non_exhaustive]
745pub enum NotificationType {
746 Starting,
747 Succeeded,
748 Failed,
749 Unknown,
750}
751
752impl NotificationType {
753 pub fn from_message(msg: &str) -> Self {
754 if msg.ends_with(".Starting") {
755 Self::Starting
756 } else if msg.ends_with(".Succeeded") {
757 Self::Succeeded
758 } else if msg.ends_with(".Failed") {
759 Self::Failed
760 } else {
761 Self::Unknown
762 }
763 }
764}
765
766#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
769pub struct BoxAndScore {
770 #[serde(rename = "box")]
771 pub box_rect: (i32, i32, i32, i32),
772 pub score: f64,
773}
774
775#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
776pub struct BoxAndCount {
777 #[serde(rename = "box")]
778 pub box_rect: (i32, i32, i32, i32),
779 pub count: i32,
780}
781
782pub type TemplateMatchResult = BoxAndScore;
783pub type FeatureMatchResult = BoxAndCount;
784pub type ColorMatchResult = BoxAndCount;
785
786#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
787pub struct OCRResult {
788 #[serde(flatten)]
789 pub base: BoxAndScore,
790 pub text: String,
791}
792
793#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
794pub struct NeuralNetworkResult {
795 #[serde(flatten)]
796 pub base: BoxAndScore,
797 pub cls_index: i32,
798 pub label: String,
799}
800
801pub type NeuralNetworkClassifyResult = NeuralNetworkResult;
802pub type NeuralNetworkDetectResult = NeuralNetworkResult;
803
804#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
805pub struct CustomRecognitionResult {
806 #[serde(rename = "box")]
807 pub box_rect: (i32, i32, i32, i32),
808 pub detail: serde_json::Value,
809}