解决issue154中的model_output有换行的问题以及多行文本输出。解决subprocessing编码问题
This commit is contained in:
@@ -169,8 +169,21 @@ class ActionHandler:
|
|||||||
clear_text(self.device_id)
|
clear_text(self.device_id)
|
||||||
time.sleep(TIMING_CONFIG.action.text_clear_delay)
|
time.sleep(TIMING_CONFIG.action.text_clear_delay)
|
||||||
|
|
||||||
type_text(text, self.device_id)
|
# Handle multiline text by splitting on newlines
|
||||||
time.sleep(TIMING_CONFIG.action.text_input_delay)
|
if '\n' in text:
|
||||||
|
lines = text.split('\n')
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if line: # Only type non-empty lines
|
||||||
|
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:
|
||||||
|
type_text(text, self.device_id)
|
||||||
|
time.sleep(TIMING_CONFIG.action.text_input_delay)
|
||||||
|
|
||||||
# Restore original keyboard
|
# Restore original keyboard
|
||||||
restore_keyboard(original_ime, self.device_id)
|
restore_keyboard(original_ime, self.device_id)
|
||||||
@@ -256,6 +269,16 @@ class ActionHandler:
|
|||||||
# This action signals that user input is needed
|
# This action signals that user input is needed
|
||||||
return ActionResult(True, False, message="User interaction required")
|
return ActionResult(True, False, message="User interaction required")
|
||||||
|
|
||||||
|
def _send_keyevent(self, keycode: str) -> None:
|
||||||
|
"""Send a keyevent to the device."""
|
||||||
|
import subprocess
|
||||||
|
adb_prefix = ["adb", "-s", self.device_id] if self.device_id else ["adb"]
|
||||||
|
subprocess.run(
|
||||||
|
adb_prefix + ["shell", "input", "keyevent", keycode],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _default_confirmation(message: str) -> bool:
|
def _default_confirmation(message: str) -> bool:
|
||||||
"""Default confirmation callback using console input."""
|
"""Default confirmation callback using console input."""
|
||||||
@@ -281,11 +304,17 @@ def parse_action(response: str) -> dict[str, Any]:
|
|||||||
Raises:
|
Raises:
|
||||||
ValueError: If the response cannot be parsed.
|
ValueError: If the response cannot be parsed.
|
||||||
"""
|
"""
|
||||||
|
print(f"Parsing action: {response}")
|
||||||
try:
|
try:
|
||||||
response = response.strip()
|
response = response.strip()
|
||||||
if response.startswith("do"):
|
if response.startswith("do"):
|
||||||
# Use AST parsing instead of eval for safety
|
# Use AST parsing instead of eval for safety
|
||||||
try:
|
try:
|
||||||
|
# Escape special characters (newlines, tabs, etc.) for valid Python syntax
|
||||||
|
response = response.replace('\n', '\\n')
|
||||||
|
response = response.replace('\r', '\\r')
|
||||||
|
response = response.replace('\t', '\\t')
|
||||||
|
|
||||||
tree = ast.parse(response, mode="eval")
|
tree = ast.parse(response, mode="eval")
|
||||||
if not isinstance(tree.body, ast.Call):
|
if not isinstance(tree.body, ast.Call):
|
||||||
raise ValueError("Expected a function call")
|
raise ValueError("Expected a function call")
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ class ADBConnection:
|
|||||||
if address:
|
if address:
|
||||||
cmd.append(address)
|
cmd.append(address)
|
||||||
|
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=5)
|
result = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", timeout=5)
|
||||||
|
|
||||||
output = result.stdout + result.stderr
|
output = result.stdout + result.stderr
|
||||||
return True, output.strip() or "Disconnected"
|
return True, output.strip() or "Disconnected"
|
||||||
@@ -241,7 +241,7 @@ class ADBConnection:
|
|||||||
cmd.extend(["-s", device_id])
|
cmd.extend(["-s", device_id])
|
||||||
cmd.extend(["tcpip", str(port)])
|
cmd.extend(["tcpip", str(port)])
|
||||||
|
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
|
result = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", timeout=10)
|
||||||
|
|
||||||
output = result.stdout + result.stderr
|
output = result.stdout + result.stderr
|
||||||
|
|
||||||
@@ -270,7 +270,7 @@ class ADBConnection:
|
|||||||
cmd.extend(["-s", device_id])
|
cmd.extend(["-s", device_id])
|
||||||
cmd.extend(["shell", "ip", "route"])
|
cmd.extend(["shell", "ip", "route"])
|
||||||
|
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=5)
|
result = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", timeout=5)
|
||||||
|
|
||||||
# Parse IP from route output
|
# Parse IP from route output
|
||||||
for line in result.stdout.split("\n"):
|
for line in result.stdout.split("\n"):
|
||||||
@@ -286,6 +286,7 @@ class ADBConnection:
|
|||||||
cmd[:-1] + ["shell", "ip", "addr", "show", "wlan0"],
|
cmd[:-1] + ["shell", "ip", "addr", "show", "wlan0"],
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
|
encoding="utf-8",
|
||||||
timeout=5,
|
timeout=5,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,11 @@ def get_current_app(device_id: str | None = None) -> str:
|
|||||||
adb_prefix = _get_adb_prefix(device_id)
|
adb_prefix = _get_adb_prefix(device_id)
|
||||||
|
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
adb_prefix + ["shell", "dumpsys", "window"], capture_output=True, text=True
|
adb_prefix + ["shell", "dumpsys", "window"], capture_output=True, text=True, encoding="utf-8"
|
||||||
)
|
)
|
||||||
output = result.stdout
|
output = result.stdout
|
||||||
|
if not output:
|
||||||
|
raise ValueError("No output from dumpsys window")
|
||||||
|
|
||||||
# Parse window focus info
|
# Parse window focus info
|
||||||
for line in output.split("\n"):
|
for line in output.split("\n"):
|
||||||
|
|||||||
Reference in New Issue
Block a user