From 9bbf112ddafe5ad188c39f78c805484e1d30dcd1 Mon Sep 17 00:00:00 2001 From: floatingstarZ Date: Tue, 16 Dec 2025 19:54:59 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96HDC=E6=96=87=E6=9C=AC?= =?UTF-8?q?=E8=BE=93=E5=85=A5=EF=BC=9A=E6=94=AF=E6=8C=81=E5=A4=9A=E8=A1=8C?= =?UTF-8?q?=E6=96=87=E6=9C=AC=E5=92=8C=E7=AE=80=E5=8C=96=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在hdc/input.py中实现多行文本支持,使用HarmonyOS keyEvent 2054处理换行 - 移除type_text函数的x/y坐标参数,简化接口 - 将多行文本处理逻辑从handler.py移至hdc/input.py,统一处理 - 优化parse_action函数,支持Type动作的text参数提取 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- phone_agent/actions/handler.py | 24 ++++++--------- phone_agent/hdc/input.py | 53 +++++++++++++++++++++------------- 2 files changed, 42 insertions(+), 35 deletions(-) diff --git a/phone_agent/actions/handler.py b/phone_agent/actions/handler.py index 905101b..0bef1c3 100644 --- a/phone_agent/actions/handler.py +++ b/phone_agent/actions/handler.py @@ -163,20 +163,8 @@ class ActionHandler: time.sleep(TIMING_CONFIG.action.text_clear_delay) # Handle multiline text by splitting on newlines - if '\n' in text: - lines = text.split('\n') - for i, line in enumerate(lines): - if line: # Only type non-empty lines - device_factory.type_text(line, self.device_id) - time.sleep(0.01) - - # Send ENTER key between lines (not after the last line) - if i < len(lines) - 1: - self._send_keyevent("KEYCODE_ENTER") - time.sleep(0.01) - else: - device_factory.type_text(text, self.device_id) - time.sleep(TIMING_CONFIG.action.text_input_delay) + device_factory.type_text(text, self.device_id) + time.sleep(TIMING_CONFIG.action.text_input_delay) # Restore original keyboard device_factory.restore_keyboard(original_ime, self.device_id) @@ -357,7 +345,13 @@ def parse_action(response: str) -> dict[str, Any]: print(f"Parsing action: {response}") try: response = response.strip() - if response.startswith("do"): + if response.startswith('do(action="Type"') or response.startswith( + 'do(action="Type_Name"' + ): + text = response.split("text=", 1)[1][1:-2] + action = {"_metadata": "do", "action": "Type", "text": text} + return action + elif response.startswith("do"): # Use AST parsing instead of eval for safety try: # Escape special characters (newlines, tabs, etc.) for valid Python syntax diff --git a/phone_agent/hdc/input.py b/phone_agent/hdc/input.py index c0db132..920cf7d 100644 --- a/phone_agent/hdc/input.py +++ b/phone_agent/hdc/input.py @@ -7,28 +7,53 @@ from typing import Optional from phone_agent.hdc.connection import _run_hdc_command -def type_text(text: str, device_id: str | None = None, x: int = None, y: int = None) -> None: +def type_text(text: str, device_id: str | None = None) -> None: """ Type text into the currently focused input field. Args: - text: The text to type. + text: The text to type. Supports multi-line text with newline characters. device_id: Optional HDC device ID for multi-device setups. - x: Optional X coordinate for input field (deprecated, kept for compatibility). - y: Optional Y coordinate for input field (deprecated, kept for compatibility). Note: HarmonyOS uses: hdc shell uitest uiInput text "文本内容" This command works without coordinates when input field is focused. + For multi-line text, the function splits by newlines and sends ENTER keyEvents. + ENTER key code in HarmonyOS: 2054 Recommendation: Click on the input field first to focus it, then use this function. """ hdc_prefix = _get_hdc_prefix(device_id) - # Escape special characters for shell (keep quotes for proper text handling) - # The text will be wrapped in quotes in the command - escaped_text = text.replace('"', '\\"').replace("$", "\\$") + # Handle multi-line text by splitting on newlines + if '\n' in text: + lines = text.split('\n') + for i, line in enumerate(lines): + if line: # Only process non-empty lines + # Escape special characters for shell + escaped_line = line.replace('"', '\\"').replace("$", "\\$") + + _run_hdc_command( + hdc_prefix + ["shell", "uitest", "uiInput", "text", escaped_line], + capture_output=True, + text=True, + ) + + # Send ENTER key event after each line except the last one + if i < len(lines) - 1: + try: + _run_hdc_command( + hdc_prefix + ["shell", "uitest", "uiInput", "keyEvent", "2054"], + capture_output=True, + text=True, + ) + except Exception as e: + print(f"[HDC] ENTER keyEvent failed: {e}") + else: + # Single line text - original logic + # Escape special characters for shell (keep quotes for proper text handling) + # The text will be wrapped in quotes in the command + escaped_text = text.replace('"', '\\"').replace("$", "\\$") - try: # HarmonyOS uitest uiInput text command # Format: hdc shell uitest uiInput text "文本内容" _run_hdc_command( @@ -36,18 +61,6 @@ def type_text(text: str, device_id: str | None = None, x: int = None, y: int = N capture_output=True, text=True, ) - except Exception as e: - print(f"[HDC] Text input failed: {e}") - # Fallback: try with coordinates if provided (for older HarmonyOS versions) - if x is not None and y is not None: - try: - _run_hdc_command( - hdc_prefix + ["shell", "uitest", "uiInput", "inputText", str(x), str(y), escaped_text], - capture_output=True, - text=True, - ) - except Exception: - pass def clear_text(device_id: str | None = None) -> None: