smix_input/lib.rs
1#![doc = include_str!("../README.md")]
2#![deny(missing_docs)]
3#![deny(rustdoc::broken_intra_doc_links)]
4#![doc(html_root_url = "https://docs.smix.dev/smix-input")]
5
6//! Small wire-only types shared by smix-driver / smix-authoring-ir /
7//! smix-runner-client. Kept as a separate crate so cement (CLI / MCP /
8//! SDK / recorder) can depend on them without dragging in heavier
9//! driver / runner deps.
10
11use serde::{Deserialize, Serialize};
12
13/// Maestro yaml `direction:` semantic: the direction names what
14/// content the caller wants to **see** (navigation through content),
15/// NOT the finger gesture direction. `Down` = "navigate down through
16/// content" = reveal what's BELOW the current viewport (visually content
17/// moves up, finger gestures up). Mirrors maestro CLI `direction: DOWN`
18/// semantics.
19///
20/// The name "SwipeDirection" predates this convention and now
21/// reads as a slight misnomer (the value is the *navigation* direction,
22/// not the *swipe gesture* direction). Renaming the enum would ripple
23/// across every adapter/driver/runner crate without semantic gain;
24/// instead the docstring carries the contract. Both runners (swift
25/// XCUITest + Kotlin UiAutomator) map this enum's wire string to the
26/// inverse finger gesture (e.g. `Down` → finger up via swipeUp / coord
27/// y 70→30) so the same yaml flow yields the same visual behavior on
28/// both platforms.
29#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
30#[serde(rename_all = "camelCase")]
31pub enum SwipeDirection {
32 /// Navigate up = see what's above (content moves down; finger gestures down).
33 Up,
34 /// Navigate down = see what's below (content moves up; finger gestures up).
35 Down,
36 /// Navigate left = see what's to the left (content moves right; finger gestures right).
37 Left,
38 /// Navigate right = see what's to the right (content moves left; finger gestures left).
39 Right,
40}
41
42impl SwipeDirection {
43 /// camelCase wire string (mirrors `roleSchema` style).
44 #[must_use]
45 pub fn as_str(self) -> &'static str {
46 match self {
47 SwipeDirection::Up => "up",
48 SwipeDirection::Down => "down",
49 SwipeDirection::Left => "left",
50 SwipeDirection::Right => "right",
51 }
52 }
53}
54
55impl std::fmt::Display for SwipeDirection {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 f.write_str(self.as_str())
58 }
59}
60
61/// Keyboard key name for `press_key` / `record` (camelCase on the wire).
62///
63/// The subset is intentional — these are the keys SDK users reliably
64/// exercise in iOS-sim contexts. Arrow keys are included because
65/// focus-traversal flows need them.
66#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
67#[serde(rename_all = "camelCase")]
68pub enum KeyName {
69 /// Return / Enter key — submits a form or confirms an action.
70 Return,
71 /// Delete / Backspace key — deletes the character before the cursor.
72 Delete,
73 /// Tab key — moves focus to the next focusable element.
74 Tab,
75 /// Space key — inserts a space character.
76 Space,
77 /// Escape key — dismisses a modal or cancels an action.
78 Escape,
79 /// Up-arrow key — moves selection / focus / caret upward.
80 ArrowUp,
81 /// Down-arrow key — moves selection / focus / caret downward.
82 ArrowDown,
83 /// Left-arrow key — moves selection / focus / caret leftward.
84 ArrowLeft,
85 /// Right-arrow key — moves selection / focus / caret rightward.
86 ArrowRight,
87 /// iOS hardware Home button — XCUIDevice.shared.perform(.homeButton).
88 /// Maps 1:1 to maestro `pressKey: home`.
89 Home,
90 /// iOS hardware Lock button — XCUIDevice.shared.perform(.lockButton).
91 /// Maps 1:1 to maestro `pressKey: lock`.
92 Lock,
93 /// iOS hardware Volume Up button — XCUIDevice.Button.volumeUp.
94 /// Maps 1:1 to maestro `pressKey: volume up`.
95 VolumeUp,
96 /// iOS hardware Volume Down button — XCUIDevice.Button.volumeDown.
97 /// Maps 1:1 to maestro `pressKey: volume down`.
98 VolumeDown,
99}
100
101impl KeyName {
102 /// camelCase wire string.
103 #[must_use]
104 pub fn as_str(self) -> &'static str {
105 match self {
106 KeyName::Return => "return",
107 KeyName::Delete => "delete",
108 KeyName::Tab => "tab",
109 KeyName::Space => "space",
110 KeyName::Escape => "escape",
111 KeyName::ArrowUp => "arrowUp",
112 KeyName::ArrowDown => "arrowDown",
113 KeyName::ArrowLeft => "arrowLeft",
114 KeyName::ArrowRight => "arrowRight",
115 KeyName::Home => "home",
116 KeyName::Lock => "lock",
117 KeyName::VolumeUp => "volumeUp",
118 KeyName::VolumeDown => "volumeDown",
119 }
120 }
121}
122
123impl std::fmt::Display for KeyName {
124 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125 f.write_str(self.as_str())
126 }
127}