@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.
- package/bin/awk.js +576 -84
- package/core/CLAUDE.md +1 -1
- package/core/GEMINI.md +148 -167
- package/core/GEMINI.md.bak +149 -116
- package/core/skill-runtime-manifest.json +3 -0
- package/docs/Claude Fable 5.md +3826 -0
- package/docs/android_kotlin_system_instruction.md +210 -0
- package/docs/brainstorm_ponytail_integration.md +146 -0
- package/docs/brainstorm_smart_setup.md +113 -0
- package/docs/deep-research-report (1).md +293 -0
- package/docs/history/GEMINI.v1.md +135 -0
- package/docs/history/brainstorm_antigravity_unified_architecture.v1.md +105 -0
- package/docs/history/implementation_plan.v1.md +58 -0
- package/package.json +4 -1
- package/scripts/artifact-storage.js +130 -0
- package/scripts/automation-gate.js +35 -2
- package/scripts/claude-plan.js +76 -0
- package/scripts/dependency-manager.js +210 -0
- package/scripts/exec-rtk.js +11 -5
- package/scripts/i18n-helper.js +381 -0
- package/scripts/multi-model-pipeline.js +144 -0
- package/skill-packs/mobile-ios/pack.json +4 -2
- package/skill-packs/reverse-engineering/pack.json +1 -0
- package/skills/CATALOG.md +20 -0
- package/skills/GEMINI.md +9 -1
- package/skills/TRIGGER_INDEX.md +10 -0
- package/skills/ai-music/SKILL.md +275 -0
- package/skills/android-re-analyzer/SKILL.md +238 -0
- package/skills/android-re-analyzer/references/api-extraction-patterns.md +119 -0
- package/skills/android-re-analyzer/references/call-flow-analysis.md +176 -0
- package/skills/android-re-analyzer/references/fernflower-usage.md +115 -0
- package/skills/android-re-analyzer/references/jadx-usage.md +116 -0
- package/skills/android-re-analyzer/references/setup-guide.md +221 -0
- package/skills/android-re-analyzer/scripts/check-deps.sh +129 -0
- package/skills/android-re-analyzer/scripts/decompile.sh +375 -0
- package/skills/android-re-analyzer/scripts/find-api-calls.sh +118 -0
- package/skills/android-re-analyzer/scripts/install-dep.sh +448 -0
- package/skills/animal-island-ui-style/SKILL.md +1450 -0
- package/skills/app-store-review-agent/SKILL.md +164 -0
- package/skills/app-store-review-agent/references/guidelines/README.md +154 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/ai_apps.md +37 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/all_apps.md +50 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/crypto_finance.md +31 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/games.md +31 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/health_fitness.md +31 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/kids.md +27 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/macos.md +38 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/social_ugc.md +32 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/subscription_iap.md +34 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/vpn.md +18 -0
- package/skills/app-store-review-agent/references/rules/design/minimum_functionality.md +96 -0
- package/skills/app-store-review-agent/references/rules/design/sign_in_with_apple.md +54 -0
- package/skills/app-store-review-agent/references/rules/entitlements/unused_entitlements.md +83 -0
- package/skills/app-store-review-agent/references/rules/metadata/accurate_metadata.md +54 -0
- package/skills/app-store-review-agent/references/rules/metadata/apple_trademark.md +99 -0
- package/skills/app-store-review-agent/references/rules/metadata/china_storefront.md +72 -0
- package/skills/app-store-review-agent/references/rules/metadata/competitor_terms.md +56 -0
- package/skills/app-store-review-agent/references/rules/metadata/subscription_metadata.md +81 -0
- package/skills/app-store-review-agent/references/rules/privacy/privacy_manifest.md +84 -0
- package/skills/app-store-review-agent/references/rules/privacy/unnecessary_data.md +60 -0
- package/skills/app-store-review-agent/references/rules/subscription/misleading_pricing.md +63 -0
- package/skills/app-store-review-agent/references/rules/subscription/missing_tos_pp.md +54 -0
- package/skills/awf-ponytail/SKILL.md +91 -0
- package/skills/awf-ponytail-review/SKILL.md +67 -0
- package/skills/awf-session-restore/SKILL.md +3 -3
- package/skills/brainstorm-agent/SKILL.md +11 -2
- package/skills/brainstorm-agent/templates/brief-template.md +8 -0
- package/skills/claude-planner/SKILL.md +47 -0
- package/skills/code-review/SKILL.md +87 -0
- package/skills/expo-game-development/SKILL.md +163 -0
- package/skills/flutter/LICENSE.txt +202 -0
- package/skills/flutter/SKILL.md +127 -0
- package/skills/flutter-project-creater/LICENSE.txt +202 -0
- package/skills/flutter-project-creater/SKILL.md +106 -0
- package/skills/game-developer/SKILL.md +163 -0
- package/skills/game-developer/references/ecs-patterns.md +501 -0
- package/skills/game-developer/references/multiplayer-networking.md +475 -0
- package/skills/game-developer/references/performance-optimization.md +422 -0
- package/skills/game-developer/references/unity-patterns.md +271 -0
- package/skills/game-developer/references/unreal-cpp.md +352 -0
- package/skills/generate-gui-assets/SKILL.md +305 -0
- package/skills/generate-gui-assets/agents/openai.yaml +4 -0
- package/skills/generate-gui-assets/references/catalog-schema.md +58 -0
- package/skills/generate-gui-assets/references/extraction-techniques.md +21 -0
- package/skills/generate-gui-assets/references/prompt-patterns.md +58 -0
- package/skills/generate-gui-assets/scripts/__pycache__/clean_chroma_edges.cpython-311.pyc +0 -0
- package/skills/generate-gui-assets/scripts/build_gui_contact_sheet.py +51 -0
- package/skills/generate-gui-assets/scripts/clean_chroma_edges.py +262 -0
- package/skills/generate-gui-assets/scripts/copy_approved_icons.py +64 -0
- package/skills/generate-gui-assets/scripts/prepare_gui_asset_run.py +91 -0
- package/skills/generate-gui-assets/scripts/suggest_grid_options.py +63 -0
- package/skills/generate-gui-assets/scripts/validate_gui_catalog.py +50 -0
- package/skills/godot-game-development/SKILL.md +142 -0
- package/skills/hatch-pet/LICENSE.txt +201 -0
- package/skills/hatch-pet/SKILL.md +420 -0
- package/skills/hatch-pet/agents/openai.yaml +4 -0
- package/skills/hatch-pet/references/animation-rows.md +29 -0
- package/skills/hatch-pet/references/codex-pet-contract.md +35 -0
- package/skills/hatch-pet/references/qa-rubric.md +60 -0
- package/skills/hatch-pet/scripts/__pycache__/clean_chroma_edges.cpython-311.pyc +0 -0
- package/skills/hatch-pet/scripts/clean_chroma_edges.py +262 -0
- package/skills/hatch-pet/scripts/compose_atlas.py +150 -0
- package/skills/hatch-pet/scripts/derive_running_left_from_running_right.py +143 -0
- package/skills/hatch-pet/scripts/extract_strip_frames.py +323 -0
- package/skills/hatch-pet/scripts/finalize_pet_run.py +382 -0
- package/skills/hatch-pet/scripts/generate_pet_images.py +287 -0
- package/skills/hatch-pet/scripts/inspect_frames.py +246 -0
- package/skills/hatch-pet/scripts/make_contact_sheet.py +96 -0
- package/skills/hatch-pet/scripts/package_custom_pet.py +108 -0
- package/skills/hatch-pet/scripts/pet_job_status.py +117 -0
- package/skills/hatch-pet/scripts/prepare_pet_run.py +673 -0
- package/skills/hatch-pet/scripts/queue_pet_repairs.py +172 -0
- package/skills/hatch-pet/scripts/record_imagegen_result.py +250 -0
- package/skills/hatch-pet/scripts/render_animation_videos.py +134 -0
- package/skills/hatch-pet/scripts/render_animation_videos.sh +5 -0
- package/skills/hatch-pet/scripts/validate_atlas.py +139 -0
- package/skills/i18n-orchestrator/SKILL.md +37 -0
- package/skills/ios-simulator-skill/SKILL.md +390 -0
- package/skills/ios-simulator-skill/scripts/accessibility_audit.py +300 -0
- package/skills/ios-simulator-skill/scripts/app_launcher.py +326 -0
- package/skills/ios-simulator-skill/scripts/app_state_capture.py +400 -0
- package/skills/ios-simulator-skill/scripts/appearance.py +385 -0
- package/skills/ios-simulator-skill/scripts/build_and_test.py +348 -0
- package/skills/ios-simulator-skill/scripts/clipboard.py +103 -0
- package/skills/ios-simulator-skill/scripts/common/__init__.py +61 -0
- package/skills/ios-simulator-skill/scripts/common/cache_utils.py +289 -0
- package/skills/ios-simulator-skill/scripts/common/device_utils.py +462 -0
- package/skills/ios-simulator-skill/scripts/common/env_config.py +35 -0
- package/skills/ios-simulator-skill/scripts/common/hang_pipeline.py +862 -0
- package/skills/ios-simulator-skill/scripts/common/hang_sessions.py +490 -0
- package/skills/ios-simulator-skill/scripts/common/idb_utils.py +180 -0
- package/skills/ios-simulator-skill/scripts/common/screenshot_utils.py +338 -0
- package/skills/ios-simulator-skill/scripts/container.py +668 -0
- package/skills/ios-simulator-skill/scripts/gesture.py +394 -0
- package/skills/ios-simulator-skill/scripts/hang_watcher.py +1533 -0
- package/skills/ios-simulator-skill/scripts/keyboard.py +391 -0
- package/skills/ios-simulator-skill/scripts/localization_audit.py +483 -0
- package/skills/ios-simulator-skill/scripts/location.py +467 -0
- package/skills/ios-simulator-skill/scripts/log_monitor.py +493 -0
- package/skills/ios-simulator-skill/scripts/model_inspector.py +645 -0
- package/skills/ios-simulator-skill/scripts/navigator.py +461 -0
- package/skills/ios-simulator-skill/scripts/privacy_manager.py +310 -0
- package/skills/ios-simulator-skill/scripts/push_notification.py +240 -0
- package/skills/ios-simulator-skill/scripts/screen_mapper.py +296 -0
- package/skills/ios-simulator-skill/scripts/sim_health_check.sh +245 -0
- package/skills/ios-simulator-skill/scripts/sim_list.py +299 -0
- package/skills/ios-simulator-skill/scripts/simctl_boot.py +312 -0
- package/skills/ios-simulator-skill/scripts/simctl_create.py +316 -0
- package/skills/ios-simulator-skill/scripts/simctl_delete.py +357 -0
- package/skills/ios-simulator-skill/scripts/simctl_erase.py +351 -0
- package/skills/ios-simulator-skill/scripts/simctl_shutdown.py +290 -0
- package/skills/ios-simulator-skill/scripts/simulator_selector.py +375 -0
- package/skills/ios-simulator-skill/scripts/status_bar.py +250 -0
- package/skills/ios-simulator-skill/scripts/test_recorder.py +323 -0
- package/skills/ios-simulator-skill/scripts/visual_diff.py +235 -0
- package/skills/ios-simulator-skill/scripts/xcode/__init__.py +13 -0
- package/skills/ios-simulator-skill/scripts/xcode/builder.py +397 -0
- package/skills/ios-simulator-skill/scripts/xcode/cache.py +204 -0
- package/skills/ios-simulator-skill/scripts/xcode/config.py +178 -0
- package/skills/ios-simulator-skill/scripts/xcode/reporter.py +343 -0
- package/skills/ios-simulator-skill/scripts/xcode/xcresult.py +451 -0
- package/skills/ios-visual-qa-strategist/SKILL.md +111 -0
- package/skills/ios-visual-qa-strategist/agents/openai.yaml +4 -0
- package/skills/ios-visual-qa-strategist/references/ios-tool-selection.md +61 -0
- package/skills/ios-visual-qa-strategist/references/minimal-capture-policy.md +56 -0
- package/skills/ios-visual-qa-strategist/references/visual-reasoning-heuristics.md +53 -0
- package/skills/orchestrator/SKILL.md +0 -20
- package/skills/persistent-storage/SKILL.md +55 -0
- package/skills/short-maker/SKILL.md +23 -0
- package/skills/short-maker/scripts/effects.js +56 -0
- package/skills/short-maker/scripts/shortmaker-bridge.js +332 -0
- package/skills/short-maker/scripts/videomix.js +601 -0
- package/skills/short-maker/templates/hyperframes/cinematic-character.template.html +172 -0
- package/skills/short-maker/templates/hyperframes/index.template.html +194 -0
- package/skills/smali-to-kotlin/SKILL.md +128 -0
- package/skills/smali-to-kotlin/examples/getting-started/tech-stack.md +58 -0
- package/skills/smali-to-kotlin/examples/pipeline/data-ui-parity.md +118 -0
- package/skills/smali-to-kotlin/examples/pipeline/scanner-and-bootstrap.md +106 -0
- package/skills/smali-to-kotlin/library-patterns.md +189 -0
- package/skills/smali-to-kotlin/phase-0-discovery.md +128 -0
- package/skills/smali-to-kotlin/phase-1-architecture.md +166 -0
- package/skills/smali-to-kotlin/phase-2-blueprint-ui.md +347 -0
- package/skills/smali-to-kotlin/phase-2-blueprint.md +228 -0
- package/skills/smali-to-kotlin/phase-3-build.md +248 -0
- package/skills/smali-to-kotlin/phase-3-logic-build.md +268 -0
- package/skills/smali-to-kotlin/smali-reading-guide.md +310 -0
- package/skills/smali-to-kotlin/templates/app-map.md +101 -0
- package/skills/smali-to-kotlin/templates/architecture.md +142 -0
- package/skills/smali-to-kotlin/templates/blueprint.md +145 -0
- package/skills/spec-gate/SKILL.md +6 -2
- package/skills/symphony-enforcer/SKILL.md +8 -0
- package/skills/symphony-enforcer/examples/mindful-stop.md +2 -0
- package/skills/symphony-enforcer/examples/three-phase.md +16 -0
- package/skills/symphony-enforcer/examples/trigger-points.md +7 -1
- package/skills/unity-game-development/SKILL.md +231 -0
- package/skills/video-edit/SKILL.md +36 -0
- package/skills/video-edit/scripts/video_edit.py +324 -0
- package/templates/project-identity/android.json +2 -2
- package/templates/project-identity/backend-nestjs.json +2 -2
- package/templates/project-identity/expo.json +2 -2
- package/templates/project-identity/ios.json +2 -2
- package/templates/project-identity/web-nextjs.json +2 -2
- package/templates/setup-mapping.json +48 -0
- package/templates/specs/design-template.md +161 -71
- package/templates/specs/requirements-template.md +65 -133
- package/templates/specs/task-spec-template.xml +3 -0
- package/workflows/_uncategorized/critic.md +40 -0
- package/workflows/_uncategorized/git-rebase-flow.md +81 -0
- package/workflows/_uncategorized/image-gen.md +118 -0
- package/workflows/_uncategorized/multi-model-pipeline.md +60 -0
- package/workflows/_uncategorized/pixel-gen.md +86 -0
- package/workflows/_uncategorized/pixel-setup.md +90 -0
- package/workflows/_uncategorized/ponytail-review.md +59 -0
- package/workflows/_uncategorized/reverse-android-build.md +222 -0
- package/workflows/_uncategorized/reverse-android-design.md +139 -0
- package/workflows/_uncategorized/reverse-android-discover.md +150 -0
- package/workflows/_uncategorized/reverse-android-scan.md +158 -0
- package/workflows/_uncategorized/reverse-android.md +143 -0
- package/workflows/_uncategorized/reverse-ios-build.md +240 -0
- package/workflows/_uncategorized/reverse-ios-design.md +112 -0
- package/workflows/_uncategorized/reverse-ios-discover.md +120 -0
- package/workflows/_uncategorized/reverse-ios-scan.md +155 -0
- package/workflows/_uncategorized/reverse-ios.md +152 -0
- package/workflows/_uncategorized/safety-router.md +34 -0
- package/workflows/_uncategorized/teach.md +89 -0
- package/workflows/_uncategorized/verify-ui.md +53 -0
- package/workflows/_uncategorized/visualize-screenshots.md +34 -0
- package/workflows/ads/ads-analyst.md +201 -0
- package/workflows/ads/ads-audit.md +106 -0
- package/workflows/ads/ads-optimize.md +97 -0
- package/workflows/ads/ads-targeting.md +241 -0
- package/workflows/ads/adsExpert.md +160 -0
- package/workflows/ads/smali-ads-config.md +400 -0
- package/workflows/ads/smali-ads-flow.md +331 -0
- package/workflows/ads/smali-ads-interstitial.md +377 -0
- package/workflows/ads/smali-ads-native.md +382 -0
- package/workflows/context/teach.md +89 -0
- package/workflows/gitnexus.md +8 -8
- package/workflows/lifecycle/brainstorm.md +43 -0
- package/workflows/lifecycle/code.md +5 -0
- package/workflows/lifecycle/init.md +23 -5
- package/workflows/lifecycle/multi-model-pipeline.md +60 -0
- package/workflows/quality/ponytail-review.md +59 -0
- package/workflows/roles/critic.md +40 -0
- 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()
|