@leejungkiin/awkit 1.7.1 → 1.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. package/bin/awk.js +576 -84
  2. package/core/CLAUDE.md +1 -1
  3. package/core/GEMINI.md +148 -167
  4. package/core/GEMINI.md.bak +149 -116
  5. package/core/skill-runtime-manifest.json +3 -0
  6. package/docs/Claude Fable 5.md +3826 -0
  7. package/docs/android_kotlin_system_instruction.md +210 -0
  8. package/docs/brainstorm_ponytail_integration.md +146 -0
  9. package/docs/brainstorm_smart_setup.md +113 -0
  10. package/docs/deep-research-report (1).md +293 -0
  11. package/docs/history/GEMINI.v1.md +135 -0
  12. package/docs/history/brainstorm_antigravity_unified_architecture.v1.md +105 -0
  13. package/docs/history/implementation_plan.v1.md +58 -0
  14. package/package.json +4 -1
  15. package/scripts/artifact-storage.js +130 -0
  16. package/scripts/automation-gate.js +35 -2
  17. package/scripts/claude-plan.js +76 -0
  18. package/scripts/dependency-manager.js +210 -0
  19. package/scripts/exec-rtk.js +11 -5
  20. package/scripts/i18n-helper.js +381 -0
  21. package/scripts/multi-model-pipeline.js +144 -0
  22. package/skill-packs/mobile-ios/pack.json +4 -2
  23. package/skill-packs/reverse-engineering/pack.json +1 -0
  24. package/skills/CATALOG.md +20 -0
  25. package/skills/GEMINI.md +9 -1
  26. package/skills/TRIGGER_INDEX.md +10 -0
  27. package/skills/ai-music/SKILL.md +275 -0
  28. package/skills/android-re-analyzer/SKILL.md +238 -0
  29. package/skills/android-re-analyzer/references/api-extraction-patterns.md +119 -0
  30. package/skills/android-re-analyzer/references/call-flow-analysis.md +176 -0
  31. package/skills/android-re-analyzer/references/fernflower-usage.md +115 -0
  32. package/skills/android-re-analyzer/references/jadx-usage.md +116 -0
  33. package/skills/android-re-analyzer/references/setup-guide.md +221 -0
  34. package/skills/android-re-analyzer/scripts/check-deps.sh +129 -0
  35. package/skills/android-re-analyzer/scripts/decompile.sh +375 -0
  36. package/skills/android-re-analyzer/scripts/find-api-calls.sh +118 -0
  37. package/skills/android-re-analyzer/scripts/install-dep.sh +448 -0
  38. package/skills/animal-island-ui-style/SKILL.md +1450 -0
  39. package/skills/app-store-review-agent/SKILL.md +164 -0
  40. package/skills/app-store-review-agent/references/guidelines/README.md +154 -0
  41. package/skills/app-store-review-agent/references/guidelines/by-app-type/ai_apps.md +37 -0
  42. package/skills/app-store-review-agent/references/guidelines/by-app-type/all_apps.md +50 -0
  43. package/skills/app-store-review-agent/references/guidelines/by-app-type/crypto_finance.md +31 -0
  44. package/skills/app-store-review-agent/references/guidelines/by-app-type/games.md +31 -0
  45. package/skills/app-store-review-agent/references/guidelines/by-app-type/health_fitness.md +31 -0
  46. package/skills/app-store-review-agent/references/guidelines/by-app-type/kids.md +27 -0
  47. package/skills/app-store-review-agent/references/guidelines/by-app-type/macos.md +38 -0
  48. package/skills/app-store-review-agent/references/guidelines/by-app-type/social_ugc.md +32 -0
  49. package/skills/app-store-review-agent/references/guidelines/by-app-type/subscription_iap.md +34 -0
  50. package/skills/app-store-review-agent/references/guidelines/by-app-type/vpn.md +18 -0
  51. package/skills/app-store-review-agent/references/rules/design/minimum_functionality.md +96 -0
  52. package/skills/app-store-review-agent/references/rules/design/sign_in_with_apple.md +54 -0
  53. package/skills/app-store-review-agent/references/rules/entitlements/unused_entitlements.md +83 -0
  54. package/skills/app-store-review-agent/references/rules/metadata/accurate_metadata.md +54 -0
  55. package/skills/app-store-review-agent/references/rules/metadata/apple_trademark.md +99 -0
  56. package/skills/app-store-review-agent/references/rules/metadata/china_storefront.md +72 -0
  57. package/skills/app-store-review-agent/references/rules/metadata/competitor_terms.md +56 -0
  58. package/skills/app-store-review-agent/references/rules/metadata/subscription_metadata.md +81 -0
  59. package/skills/app-store-review-agent/references/rules/privacy/privacy_manifest.md +84 -0
  60. package/skills/app-store-review-agent/references/rules/privacy/unnecessary_data.md +60 -0
  61. package/skills/app-store-review-agent/references/rules/subscription/misleading_pricing.md +63 -0
  62. package/skills/app-store-review-agent/references/rules/subscription/missing_tos_pp.md +54 -0
  63. package/skills/awf-ponytail/SKILL.md +91 -0
  64. package/skills/awf-ponytail-review/SKILL.md +67 -0
  65. package/skills/awf-session-restore/SKILL.md +3 -3
  66. package/skills/brainstorm-agent/SKILL.md +11 -2
  67. package/skills/brainstorm-agent/templates/brief-template.md +8 -0
  68. package/skills/claude-planner/SKILL.md +47 -0
  69. package/skills/code-review/SKILL.md +87 -0
  70. package/skills/expo-game-development/SKILL.md +163 -0
  71. package/skills/flutter/LICENSE.txt +202 -0
  72. package/skills/flutter/SKILL.md +127 -0
  73. package/skills/flutter-project-creater/LICENSE.txt +202 -0
  74. package/skills/flutter-project-creater/SKILL.md +106 -0
  75. package/skills/game-developer/SKILL.md +163 -0
  76. package/skills/game-developer/references/ecs-patterns.md +501 -0
  77. package/skills/game-developer/references/multiplayer-networking.md +475 -0
  78. package/skills/game-developer/references/performance-optimization.md +422 -0
  79. package/skills/game-developer/references/unity-patterns.md +271 -0
  80. package/skills/game-developer/references/unreal-cpp.md +352 -0
  81. package/skills/generate-gui-assets/SKILL.md +305 -0
  82. package/skills/generate-gui-assets/agents/openai.yaml +4 -0
  83. package/skills/generate-gui-assets/references/catalog-schema.md +58 -0
  84. package/skills/generate-gui-assets/references/extraction-techniques.md +21 -0
  85. package/skills/generate-gui-assets/references/prompt-patterns.md +58 -0
  86. package/skills/generate-gui-assets/scripts/__pycache__/clean_chroma_edges.cpython-311.pyc +0 -0
  87. package/skills/generate-gui-assets/scripts/build_gui_contact_sheet.py +51 -0
  88. package/skills/generate-gui-assets/scripts/clean_chroma_edges.py +262 -0
  89. package/skills/generate-gui-assets/scripts/copy_approved_icons.py +64 -0
  90. package/skills/generate-gui-assets/scripts/prepare_gui_asset_run.py +91 -0
  91. package/skills/generate-gui-assets/scripts/suggest_grid_options.py +63 -0
  92. package/skills/generate-gui-assets/scripts/validate_gui_catalog.py +50 -0
  93. package/skills/godot-game-development/SKILL.md +142 -0
  94. package/skills/hatch-pet/LICENSE.txt +201 -0
  95. package/skills/hatch-pet/SKILL.md +420 -0
  96. package/skills/hatch-pet/agents/openai.yaml +4 -0
  97. package/skills/hatch-pet/references/animation-rows.md +29 -0
  98. package/skills/hatch-pet/references/codex-pet-contract.md +35 -0
  99. package/skills/hatch-pet/references/qa-rubric.md +60 -0
  100. package/skills/hatch-pet/scripts/__pycache__/clean_chroma_edges.cpython-311.pyc +0 -0
  101. package/skills/hatch-pet/scripts/clean_chroma_edges.py +262 -0
  102. package/skills/hatch-pet/scripts/compose_atlas.py +150 -0
  103. package/skills/hatch-pet/scripts/derive_running_left_from_running_right.py +143 -0
  104. package/skills/hatch-pet/scripts/extract_strip_frames.py +323 -0
  105. package/skills/hatch-pet/scripts/finalize_pet_run.py +382 -0
  106. package/skills/hatch-pet/scripts/generate_pet_images.py +287 -0
  107. package/skills/hatch-pet/scripts/inspect_frames.py +246 -0
  108. package/skills/hatch-pet/scripts/make_contact_sheet.py +96 -0
  109. package/skills/hatch-pet/scripts/package_custom_pet.py +108 -0
  110. package/skills/hatch-pet/scripts/pet_job_status.py +117 -0
  111. package/skills/hatch-pet/scripts/prepare_pet_run.py +673 -0
  112. package/skills/hatch-pet/scripts/queue_pet_repairs.py +172 -0
  113. package/skills/hatch-pet/scripts/record_imagegen_result.py +250 -0
  114. package/skills/hatch-pet/scripts/render_animation_videos.py +134 -0
  115. package/skills/hatch-pet/scripts/render_animation_videos.sh +5 -0
  116. package/skills/hatch-pet/scripts/validate_atlas.py +139 -0
  117. package/skills/i18n-orchestrator/SKILL.md +37 -0
  118. package/skills/ios-simulator-skill/SKILL.md +390 -0
  119. package/skills/ios-simulator-skill/scripts/accessibility_audit.py +300 -0
  120. package/skills/ios-simulator-skill/scripts/app_launcher.py +326 -0
  121. package/skills/ios-simulator-skill/scripts/app_state_capture.py +400 -0
  122. package/skills/ios-simulator-skill/scripts/appearance.py +385 -0
  123. package/skills/ios-simulator-skill/scripts/build_and_test.py +348 -0
  124. package/skills/ios-simulator-skill/scripts/clipboard.py +103 -0
  125. package/skills/ios-simulator-skill/scripts/common/__init__.py +61 -0
  126. package/skills/ios-simulator-skill/scripts/common/cache_utils.py +289 -0
  127. package/skills/ios-simulator-skill/scripts/common/device_utils.py +462 -0
  128. package/skills/ios-simulator-skill/scripts/common/env_config.py +35 -0
  129. package/skills/ios-simulator-skill/scripts/common/hang_pipeline.py +862 -0
  130. package/skills/ios-simulator-skill/scripts/common/hang_sessions.py +490 -0
  131. package/skills/ios-simulator-skill/scripts/common/idb_utils.py +180 -0
  132. package/skills/ios-simulator-skill/scripts/common/screenshot_utils.py +338 -0
  133. package/skills/ios-simulator-skill/scripts/container.py +668 -0
  134. package/skills/ios-simulator-skill/scripts/gesture.py +394 -0
  135. package/skills/ios-simulator-skill/scripts/hang_watcher.py +1533 -0
  136. package/skills/ios-simulator-skill/scripts/keyboard.py +391 -0
  137. package/skills/ios-simulator-skill/scripts/localization_audit.py +483 -0
  138. package/skills/ios-simulator-skill/scripts/location.py +467 -0
  139. package/skills/ios-simulator-skill/scripts/log_monitor.py +493 -0
  140. package/skills/ios-simulator-skill/scripts/model_inspector.py +645 -0
  141. package/skills/ios-simulator-skill/scripts/navigator.py +461 -0
  142. package/skills/ios-simulator-skill/scripts/privacy_manager.py +310 -0
  143. package/skills/ios-simulator-skill/scripts/push_notification.py +240 -0
  144. package/skills/ios-simulator-skill/scripts/screen_mapper.py +296 -0
  145. package/skills/ios-simulator-skill/scripts/sim_health_check.sh +245 -0
  146. package/skills/ios-simulator-skill/scripts/sim_list.py +299 -0
  147. package/skills/ios-simulator-skill/scripts/simctl_boot.py +312 -0
  148. package/skills/ios-simulator-skill/scripts/simctl_create.py +316 -0
  149. package/skills/ios-simulator-skill/scripts/simctl_delete.py +357 -0
  150. package/skills/ios-simulator-skill/scripts/simctl_erase.py +351 -0
  151. package/skills/ios-simulator-skill/scripts/simctl_shutdown.py +290 -0
  152. package/skills/ios-simulator-skill/scripts/simulator_selector.py +375 -0
  153. package/skills/ios-simulator-skill/scripts/status_bar.py +250 -0
  154. package/skills/ios-simulator-skill/scripts/test_recorder.py +323 -0
  155. package/skills/ios-simulator-skill/scripts/visual_diff.py +235 -0
  156. package/skills/ios-simulator-skill/scripts/xcode/__init__.py +13 -0
  157. package/skills/ios-simulator-skill/scripts/xcode/builder.py +397 -0
  158. package/skills/ios-simulator-skill/scripts/xcode/cache.py +204 -0
  159. package/skills/ios-simulator-skill/scripts/xcode/config.py +178 -0
  160. package/skills/ios-simulator-skill/scripts/xcode/reporter.py +343 -0
  161. package/skills/ios-simulator-skill/scripts/xcode/xcresult.py +451 -0
  162. package/skills/ios-visual-qa-strategist/SKILL.md +111 -0
  163. package/skills/ios-visual-qa-strategist/agents/openai.yaml +4 -0
  164. package/skills/ios-visual-qa-strategist/references/ios-tool-selection.md +61 -0
  165. package/skills/ios-visual-qa-strategist/references/minimal-capture-policy.md +56 -0
  166. package/skills/ios-visual-qa-strategist/references/visual-reasoning-heuristics.md +53 -0
  167. package/skills/orchestrator/SKILL.md +0 -20
  168. package/skills/persistent-storage/SKILL.md +55 -0
  169. package/skills/short-maker/SKILL.md +23 -0
  170. package/skills/short-maker/scripts/effects.js +56 -0
  171. package/skills/short-maker/scripts/shortmaker-bridge.js +332 -0
  172. package/skills/short-maker/scripts/videomix.js +601 -0
  173. package/skills/short-maker/templates/hyperframes/cinematic-character.template.html +172 -0
  174. package/skills/short-maker/templates/hyperframes/index.template.html +194 -0
  175. package/skills/smali-to-kotlin/SKILL.md +128 -0
  176. package/skills/smali-to-kotlin/examples/getting-started/tech-stack.md +58 -0
  177. package/skills/smali-to-kotlin/examples/pipeline/data-ui-parity.md +118 -0
  178. package/skills/smali-to-kotlin/examples/pipeline/scanner-and-bootstrap.md +106 -0
  179. package/skills/smali-to-kotlin/library-patterns.md +189 -0
  180. package/skills/smali-to-kotlin/phase-0-discovery.md +128 -0
  181. package/skills/smali-to-kotlin/phase-1-architecture.md +166 -0
  182. package/skills/smali-to-kotlin/phase-2-blueprint-ui.md +347 -0
  183. package/skills/smali-to-kotlin/phase-2-blueprint.md +228 -0
  184. package/skills/smali-to-kotlin/phase-3-build.md +248 -0
  185. package/skills/smali-to-kotlin/phase-3-logic-build.md +268 -0
  186. package/skills/smali-to-kotlin/smali-reading-guide.md +310 -0
  187. package/skills/smali-to-kotlin/templates/app-map.md +101 -0
  188. package/skills/smali-to-kotlin/templates/architecture.md +142 -0
  189. package/skills/smali-to-kotlin/templates/blueprint.md +145 -0
  190. package/skills/spec-gate/SKILL.md +6 -2
  191. package/skills/symphony-enforcer/SKILL.md +8 -0
  192. package/skills/symphony-enforcer/examples/mindful-stop.md +2 -0
  193. package/skills/symphony-enforcer/examples/three-phase.md +16 -0
  194. package/skills/symphony-enforcer/examples/trigger-points.md +7 -1
  195. package/skills/unity-game-development/SKILL.md +231 -0
  196. package/skills/video-edit/SKILL.md +36 -0
  197. package/skills/video-edit/scripts/video_edit.py +324 -0
  198. package/templates/project-identity/android.json +2 -2
  199. package/templates/project-identity/backend-nestjs.json +2 -2
  200. package/templates/project-identity/expo.json +2 -2
  201. package/templates/project-identity/ios.json +2 -2
  202. package/templates/project-identity/web-nextjs.json +2 -2
  203. package/templates/setup-mapping.json +48 -0
  204. package/templates/specs/design-template.md +161 -71
  205. package/templates/specs/requirements-template.md +65 -133
  206. package/templates/specs/task-spec-template.xml +3 -0
  207. package/workflows/_uncategorized/critic.md +40 -0
  208. package/workflows/_uncategorized/git-rebase-flow.md +81 -0
  209. package/workflows/_uncategorized/image-gen.md +118 -0
  210. package/workflows/_uncategorized/multi-model-pipeline.md +60 -0
  211. package/workflows/_uncategorized/pixel-gen.md +86 -0
  212. package/workflows/_uncategorized/pixel-setup.md +90 -0
  213. package/workflows/_uncategorized/ponytail-review.md +59 -0
  214. package/workflows/_uncategorized/reverse-android-build.md +222 -0
  215. package/workflows/_uncategorized/reverse-android-design.md +139 -0
  216. package/workflows/_uncategorized/reverse-android-discover.md +150 -0
  217. package/workflows/_uncategorized/reverse-android-scan.md +158 -0
  218. package/workflows/_uncategorized/reverse-android.md +143 -0
  219. package/workflows/_uncategorized/reverse-ios-build.md +240 -0
  220. package/workflows/_uncategorized/reverse-ios-design.md +112 -0
  221. package/workflows/_uncategorized/reverse-ios-discover.md +120 -0
  222. package/workflows/_uncategorized/reverse-ios-scan.md +155 -0
  223. package/workflows/_uncategorized/reverse-ios.md +152 -0
  224. package/workflows/_uncategorized/safety-router.md +34 -0
  225. package/workflows/_uncategorized/teach.md +89 -0
  226. package/workflows/_uncategorized/verify-ui.md +53 -0
  227. package/workflows/_uncategorized/visualize-screenshots.md +34 -0
  228. package/workflows/ads/ads-analyst.md +201 -0
  229. package/workflows/ads/ads-audit.md +106 -0
  230. package/workflows/ads/ads-optimize.md +97 -0
  231. package/workflows/ads/ads-targeting.md +241 -0
  232. package/workflows/ads/adsExpert.md +160 -0
  233. package/workflows/ads/smali-ads-config.md +400 -0
  234. package/workflows/ads/smali-ads-flow.md +331 -0
  235. package/workflows/ads/smali-ads-interstitial.md +377 -0
  236. package/workflows/ads/smali-ads-native.md +382 -0
  237. package/workflows/context/teach.md +89 -0
  238. package/workflows/gitnexus.md +8 -8
  239. package/workflows/lifecycle/brainstorm.md +43 -0
  240. package/workflows/lifecycle/code.md +5 -0
  241. package/workflows/lifecycle/init.md +23 -5
  242. package/workflows/lifecycle/multi-model-pipeline.md +60 -0
  243. package/workflows/quality/ponytail-review.md +59 -0
  244. package/workflows/roles/critic.md +40 -0
  245. package/workflows/roles/safety-router.md +34 -0
@@ -0,0 +1,391 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ iOS Keyboard Controller - Text Entry and Hardware Buttons
4
+
5
+ Handles keyboard input, special keys, and hardware button simulation.
6
+ Token-efficient text entry and navigation control.
7
+
8
+ This script provides text input and hardware button control for iOS simulator
9
+ automation. It handles both typing text strings and pressing special keys like
10
+ return, delete, tab, etc. Also controls hardware buttons like home and lock.
11
+
12
+ Key Features:
13
+ - Type text strings into focused elements
14
+ - Press special keys (return, delete, tab, space, arrows)
15
+ - Hardware button simulation (home, lock, volume, screenshot)
16
+ - Character-by-character typing with delays (for animations)
17
+ - Multiple key press support
18
+ - iOS HID key code mapping for reliability
19
+
20
+ Usage Examples:
21
+ # Type text into focused field
22
+ python scripts/keyboard.py --type "hello@example.com" --udid <device-id>
23
+
24
+ # Press return key to submit
25
+ python scripts/keyboard.py --key return --udid <device-id>
26
+
27
+ # Press delete 3 times
28
+ python scripts/keyboard.py --key delete --key delete --key delete --udid <device-id>
29
+
30
+ # Press home button
31
+ python scripts/keyboard.py --button home --udid <device-id>
32
+
33
+ # Press lock button
34
+ python scripts/keyboard.py --button lock --udid <device-id>
35
+
36
+ # Type with delay between characters (for animations)
37
+ python scripts/keyboard.py --type "slow typing" --delay 0.1 --udid <device-id>
38
+
39
+ Output Format:
40
+ Typed: "hello@example.com"
41
+ Pressed return
42
+ Pressed home button
43
+
44
+ Special Keys Supported:
45
+ - return/enter: Submit forms, new lines (HID code 40)
46
+ - delete/backspace: Remove characters (HID code 42)
47
+ - tab: Navigate between fields (HID code 43)
48
+ - space: Space character (HID code 44)
49
+ - escape: Cancel/dismiss (HID code 41)
50
+ - up/down/left/right: Arrow keys (HID codes 82/81/80/79)
51
+
52
+ Hardware Buttons Supported:
53
+ - home: Return to home screen
54
+ - lock/power: Lock device
55
+ - volume-up/volume-down: Volume control
56
+ - ringer: Toggle mute
57
+ - screenshot: Capture screen
58
+
59
+ Technical Details:
60
+ - Uses `idb ui text` for typing text strings
61
+ - Uses `idb ui key <code>` for special keys with iOS HID codes
62
+ - HID codes from Apple's UIKeyboardHIDUsage specification
63
+ - Hardware buttons use `xcrun simctl` button actions
64
+ - Text entry works on currently focused element
65
+ - Special keys are integers (40=Return, 42=Delete, etc.)
66
+ """
67
+
68
+ import argparse
69
+ import subprocess
70
+ import sys
71
+ import time
72
+
73
+ from common import resolve_udid
74
+
75
+
76
+ class KeyboardController:
77
+ """Controls keyboard and hardware buttons on iOS simulator."""
78
+
79
+ # Special key mappings to iOS HID key codes
80
+ # See: https://developer.apple.com/documentation/uikit/uikeyboardhidusage
81
+ SPECIAL_KEYS = {
82
+ "return": 40,
83
+ "enter": 40,
84
+ "delete": 42,
85
+ "backspace": 42,
86
+ "tab": 43,
87
+ "space": 44,
88
+ "escape": 41,
89
+ "up": 82,
90
+ "down": 81,
91
+ "left": 80,
92
+ "right": 79,
93
+ }
94
+
95
+ # Hardware button mappings
96
+ HARDWARE_BUTTONS = {
97
+ "home": "HOME",
98
+ "lock": "LOCK",
99
+ "volume-up": "VOLUME_UP",
100
+ "volume-down": "VOLUME_DOWN",
101
+ "ringer": "RINGER",
102
+ "power": "LOCK", # Alias
103
+ "screenshot": "SCREENSHOT",
104
+ }
105
+
106
+ def __init__(self, udid: str | None = None):
107
+ """Initialize keyboard controller."""
108
+ self.udid = udid
109
+
110
+ def type_text(self, text: str, delay: float = 0.0) -> bool:
111
+ """
112
+ Type text into current focus.
113
+
114
+ Args:
115
+ text: Text to type
116
+ delay: Delay between characters (for slow typing effect)
117
+
118
+ Returns:
119
+ Success status
120
+ """
121
+ if delay > 0:
122
+ # Type character by character with delay
123
+ for char in text:
124
+ if not self._type_single(char):
125
+ return False
126
+ time.sleep(delay)
127
+ return True
128
+ # Type all at once (efficient)
129
+ return self._type_single(text)
130
+
131
+ def _type_single(self, text: str) -> bool:
132
+ """Type text using IDB."""
133
+ cmd = ["idb", "ui", "text", text]
134
+ if self.udid:
135
+ cmd.extend(["--udid", self.udid])
136
+
137
+ try:
138
+ subprocess.run(cmd, capture_output=True, check=True)
139
+ return True
140
+ except subprocess.CalledProcessError:
141
+ return False
142
+
143
+ def press_key(self, key: str, count: int = 1) -> bool:
144
+ """
145
+ Press a special key.
146
+
147
+ Args:
148
+ key: Key name (return, delete, tab, etc.)
149
+ count: Number of times to press
150
+
151
+ Returns:
152
+ Success status
153
+ """
154
+ # Map key name to IDB key code
155
+ key_code = self.SPECIAL_KEYS.get(key.lower())
156
+ if not key_code:
157
+ # Try as literal integer key code
158
+ try:
159
+ key_code = int(key)
160
+ except ValueError:
161
+ return False
162
+
163
+ cmd = ["idb", "ui", "key", str(key_code)]
164
+ if self.udid:
165
+ cmd.extend(["--udid", self.udid])
166
+
167
+ try:
168
+ for _ in range(count):
169
+ subprocess.run(cmd, capture_output=True, check=True)
170
+ if count > 1:
171
+ time.sleep(0.1) # Small delay for multiple presses
172
+ return True
173
+ except subprocess.CalledProcessError:
174
+ return False
175
+
176
+ def press_key_sequence(self, keys: list[str]) -> bool:
177
+ """
178
+ Press a sequence of keys.
179
+
180
+ Args:
181
+ keys: List of key names
182
+
183
+ Returns:
184
+ Success status
185
+ """
186
+ cmd_base = ["idb", "ui", "key-sequence"]
187
+
188
+ # Map keys to codes
189
+ mapped_keys = []
190
+ for key in keys:
191
+ mapped = self.SPECIAL_KEYS.get(key.lower())
192
+ if mapped is None:
193
+ # Try as integer
194
+ try:
195
+ mapped = int(key)
196
+ except ValueError:
197
+ return False
198
+ mapped_keys.append(str(mapped))
199
+
200
+ cmd = cmd_base + mapped_keys
201
+
202
+ if self.udid:
203
+ cmd.extend(["--udid", self.udid])
204
+
205
+ try:
206
+ subprocess.run(cmd, capture_output=True, check=True)
207
+ return True
208
+ except subprocess.CalledProcessError:
209
+ return False
210
+
211
+ def press_hardware_button(self, button: str) -> bool:
212
+ """
213
+ Press hardware button.
214
+
215
+ Args:
216
+ button: Button name (home, lock, volume-up, etc.)
217
+
218
+ Returns:
219
+ Success status
220
+ """
221
+ button_code = self.HARDWARE_BUTTONS.get(button.lower())
222
+ if not button_code:
223
+ return False
224
+
225
+ cmd = ["idb", "ui", "button", button_code]
226
+ if self.udid:
227
+ cmd.extend(["--udid", self.udid])
228
+
229
+ try:
230
+ subprocess.run(cmd, capture_output=True, check=True)
231
+ return True
232
+ except subprocess.CalledProcessError:
233
+ return False
234
+
235
+ def clear_text(self, select_all: bool = True) -> bool:
236
+ """
237
+ Clear text in current field.
238
+
239
+ Args:
240
+ select_all: Use Cmd+A to select all first
241
+
242
+ Returns:
243
+ Success status
244
+ """
245
+ if select_all:
246
+ # Select all then delete
247
+ # Note: This might need adjustment for iOS keyboard shortcuts
248
+ success = self.press_key_combo(["cmd", "a"])
249
+ if success:
250
+ return self.press_key("delete")
251
+ else:
252
+ # Just delete multiple times
253
+ return self.press_key("delete", count=50)
254
+ return None
255
+
256
+ def press_key_combo(self, keys: list[str]) -> bool:
257
+ """
258
+ Press key combination (like Cmd+A).
259
+
260
+ Args:
261
+ keys: List of keys to press together
262
+
263
+ Returns:
264
+ Success status
265
+ """
266
+ # IDB doesn't directly support key combos
267
+ # This is a workaround - may need platform-specific handling
268
+ if "cmd" in keys or "command" in keys:
269
+ # Handle common shortcuts
270
+ if "a" in keys:
271
+ # Select all - might work with key sequence
272
+ return self.press_key_sequence(["command", "a"])
273
+ if "c" in keys:
274
+ return self.press_key_sequence(["command", "c"])
275
+ if "v" in keys:
276
+ return self.press_key_sequence(["command", "v"])
277
+ if "x" in keys:
278
+ return self.press_key_sequence(["command", "x"])
279
+
280
+ # Try as sequence
281
+ return self.press_key_sequence(keys)
282
+
283
+ def dismiss_keyboard(self) -> bool:
284
+ """Dismiss on-screen keyboard."""
285
+ # Common ways to dismiss keyboard on iOS
286
+ # Try Done button first, then Return
287
+ success = self.press_key("return")
288
+ if not success:
289
+ # Try tapping outside (would need coordinate)
290
+ pass
291
+ return success
292
+
293
+
294
+ def main():
295
+ """Main entry point."""
296
+ parser = argparse.ArgumentParser(description="Control keyboard and hardware buttons")
297
+
298
+ # Text input
299
+ parser.add_argument("--type", help="Type text into current focus")
300
+ parser.add_argument("--slow", action="store_true", help="Type slowly (character by character)")
301
+
302
+ # Special keys
303
+ parser.add_argument("--key", help="Press special key (return, delete, tab, space, etc.)")
304
+ parser.add_argument("--key-sequence", help="Press key sequence (comma-separated)")
305
+ parser.add_argument("--count", type=int, default=1, help="Number of times to press key")
306
+
307
+ # Hardware buttons
308
+ parser.add_argument(
309
+ "--button",
310
+ choices=["home", "lock", "volume-up", "volume-down", "ringer", "screenshot"],
311
+ help="Press hardware button",
312
+ )
313
+
314
+ # Other operations
315
+ parser.add_argument("--clear", action="store_true", help="Clear current text field")
316
+ parser.add_argument("--dismiss", action="store_true", help="Dismiss keyboard")
317
+
318
+ parser.add_argument(
319
+ "--udid",
320
+ help="Device UDID (auto-detects booted simulator if not provided)",
321
+ )
322
+
323
+ args = parser.parse_args()
324
+
325
+ # Resolve UDID with auto-detection
326
+ try:
327
+ udid = resolve_udid(args.udid)
328
+ except RuntimeError as e:
329
+ print(f"Error: {e}")
330
+ sys.exit(1)
331
+
332
+ controller = KeyboardController(udid=udid)
333
+
334
+ # Execute requested action
335
+ if args.type:
336
+ delay = 0.1 if args.slow else 0.0
337
+ if controller.type_text(args.type, delay):
338
+ if args.slow:
339
+ print(f'Typed: "{args.type}" (slowly)')
340
+ else:
341
+ print(f'Typed: "{args.type}"')
342
+ else:
343
+ print("Failed to type text")
344
+ sys.exit(1)
345
+
346
+ elif args.key:
347
+ if controller.press_key(args.key, args.count):
348
+ if args.count > 1:
349
+ print(f"Pressed {args.key} ({args.count}x)")
350
+ else:
351
+ print(f"Pressed {args.key}")
352
+ else:
353
+ print(f"Failed to press {args.key}")
354
+ sys.exit(1)
355
+
356
+ elif args.key_sequence:
357
+ keys = args.key_sequence.split(",")
358
+ if controller.press_key_sequence(keys):
359
+ print(f"Pressed sequence: {' -> '.join(keys)}")
360
+ else:
361
+ print("Failed to press key sequence")
362
+ sys.exit(1)
363
+
364
+ elif args.button:
365
+ if controller.press_hardware_button(args.button):
366
+ print(f"Pressed {args.button} button")
367
+ else:
368
+ print(f"Failed to press {args.button}")
369
+ sys.exit(1)
370
+
371
+ elif args.clear:
372
+ if controller.clear_text():
373
+ print("Cleared text field")
374
+ else:
375
+ print("Failed to clear text")
376
+ sys.exit(1)
377
+
378
+ elif args.dismiss:
379
+ if controller.dismiss_keyboard():
380
+ print("Dismissed keyboard")
381
+ else:
382
+ print("Failed to dismiss keyboard")
383
+ sys.exit(1)
384
+
385
+ else:
386
+ parser.print_help()
387
+ sys.exit(1)
388
+
389
+
390
+ if __name__ == "__main__":
391
+ main()