feat: Added iOS support
This commit is contained in:
299
phone_agent/xctest/input.py
Normal file
299
phone_agent/xctest/input.py
Normal file
@@ -0,0 +1,299 @@
|
||||
"""Input utilities for iOS device text input via WebDriverAgent."""
|
||||
|
||||
import time
|
||||
|
||||
|
||||
def _get_wda_session_url(wda_url: str, session_id: str | None, endpoint: str) -> str:
|
||||
"""
|
||||
Get the correct WDA URL for a session endpoint.
|
||||
|
||||
Args:
|
||||
wda_url: Base WDA URL.
|
||||
session_id: Optional session ID.
|
||||
endpoint: The endpoint path.
|
||||
|
||||
Returns:
|
||||
Full URL for the endpoint.
|
||||
"""
|
||||
base = wda_url.rstrip("/")
|
||||
if session_id:
|
||||
return f"{base}/session/{session_id}/{endpoint}"
|
||||
else:
|
||||
# Try to use WDA endpoints without session when possible
|
||||
return f"{base}/{endpoint}"
|
||||
|
||||
|
||||
def type_text(
|
||||
text: str,
|
||||
wda_url: str = "http://localhost:8100",
|
||||
session_id: str | None = None,
|
||||
frequency: int = 60,
|
||||
) -> None:
|
||||
"""
|
||||
Type text into the currently focused input field.
|
||||
|
||||
Args:
|
||||
text: The text to type.
|
||||
wda_url: WebDriverAgent URL.
|
||||
session_id: Optional WDA session ID.
|
||||
frequency: Typing frequency (keys per minute). Default is 60.
|
||||
|
||||
Note:
|
||||
The input field must be focused before calling this function.
|
||||
Use tap() to focus on the input field first.
|
||||
"""
|
||||
try:
|
||||
import requests
|
||||
|
||||
url = _get_wda_session_url(wda_url, session_id, "wda/keys")
|
||||
|
||||
# Send text to WDA
|
||||
response = requests.post(
|
||||
url, json={"value": list(text), "frequency": frequency}, timeout=30, verify=False
|
||||
)
|
||||
|
||||
if response.status_code not in (200, 201):
|
||||
print(f"Warning: Text input may have failed. Status: {response.status_code}")
|
||||
|
||||
except ImportError:
|
||||
print("Error: requests library required. Install: pip install requests")
|
||||
except Exception as e:
|
||||
print(f"Error typing text: {e}")
|
||||
|
||||
|
||||
def clear_text(
|
||||
wda_url: str = "http://localhost:8100",
|
||||
session_id: str | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Clear text in the currently focused input field.
|
||||
|
||||
Args:
|
||||
wda_url: WebDriverAgent URL.
|
||||
session_id: Optional WDA session ID.
|
||||
|
||||
Note:
|
||||
This sends a clear command to the active element.
|
||||
The input field must be focused before calling this function.
|
||||
"""
|
||||
try:
|
||||
import requests
|
||||
|
||||
# First, try to get the active element
|
||||
url = _get_wda_session_url(wda_url, session_id, "element/active")
|
||||
|
||||
response = requests.get(url, timeout=10, verify=False)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
element_id = data.get("value", {}).get("ELEMENT") or data.get("value", {}).get("element-6066-11e4-a52e-4f735466cecf")
|
||||
|
||||
if element_id:
|
||||
# Clear the element
|
||||
clear_url = _get_wda_session_url(wda_url, session_id, f"element/{element_id}/clear")
|
||||
requests.post(clear_url, timeout=10, verify=False)
|
||||
return
|
||||
|
||||
# Fallback: send backspace commands
|
||||
_clear_with_backspace(wda_url, session_id)
|
||||
|
||||
except ImportError:
|
||||
print("Error: requests library required. Install: pip install requests")
|
||||
except Exception as e:
|
||||
print(f"Error clearing text: {e}")
|
||||
|
||||
|
||||
def _clear_with_backspace(
|
||||
wda_url: str = "http://localhost:8100",
|
||||
session_id: str | None = None,
|
||||
max_backspaces: int = 100,
|
||||
) -> None:
|
||||
"""
|
||||
Clear text by sending backspace keys.
|
||||
|
||||
Args:
|
||||
wda_url: WebDriverAgent URL.
|
||||
session_id: Optional WDA session ID.
|
||||
max_backspaces: Maximum number of backspaces to send.
|
||||
"""
|
||||
try:
|
||||
import requests
|
||||
|
||||
url = _get_wda_session_url(wda_url, session_id, "wda/keys")
|
||||
|
||||
# Send backspace character multiple times
|
||||
backspace_char = "\u0008" # Backspace Unicode character
|
||||
requests.post(
|
||||
url,
|
||||
json={"value": [backspace_char] * max_backspaces},
|
||||
timeout=10,
|
||||
verify=False,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error clearing with backspace: {e}")
|
||||
|
||||
|
||||
def send_keys(
|
||||
keys: list[str],
|
||||
wda_url: str = "http://localhost:8100",
|
||||
session_id: str | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Send a sequence of keys.
|
||||
|
||||
Args:
|
||||
keys: List of keys to send.
|
||||
wda_url: WebDriverAgent URL.
|
||||
session_id: Optional WDA session ID.
|
||||
|
||||
Example:
|
||||
>>> send_keys(["H", "e", "l", "l", "o"])
|
||||
>>> send_keys(["\n"]) # Send enter key
|
||||
"""
|
||||
try:
|
||||
import requests
|
||||
|
||||
url = _get_wda_session_url(wda_url, session_id, "wda/keys")
|
||||
|
||||
requests.post(url, json={"value": keys}, timeout=10, verify=False)
|
||||
|
||||
except ImportError:
|
||||
print("Error: requests library required. Install: pip install requests")
|
||||
except Exception as e:
|
||||
print(f"Error sending keys: {e}")
|
||||
|
||||
|
||||
def press_enter(
|
||||
wda_url: str = "http://localhost:8100",
|
||||
session_id: str | None = None,
|
||||
delay: float = 0.5,
|
||||
) -> None:
|
||||
"""
|
||||
Press the Enter/Return key.
|
||||
|
||||
Args:
|
||||
wda_url: WebDriverAgent URL.
|
||||
session_id: Optional WDA session ID.
|
||||
delay: Delay in seconds after pressing enter.
|
||||
"""
|
||||
send_keys(["\n"], wda_url, session_id)
|
||||
time.sleep(delay)
|
||||
|
||||
|
||||
def hide_keyboard(
|
||||
wda_url: str = "http://localhost:8100",
|
||||
session_id: str | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Hide the on-screen keyboard.
|
||||
|
||||
Args:
|
||||
wda_url: WebDriverAgent URL.
|
||||
session_id: Optional WDA session ID.
|
||||
"""
|
||||
try:
|
||||
import requests
|
||||
|
||||
url = f"{wda_url.rstrip('/')}/wda/keyboard/dismiss"
|
||||
|
||||
requests.post(url, timeout=10, verify=False)
|
||||
|
||||
except ImportError:
|
||||
print("Error: requests library required. Install: pip install requests")
|
||||
except Exception as e:
|
||||
print(f"Error hiding keyboard: {e}")
|
||||
|
||||
|
||||
def is_keyboard_shown(
|
||||
wda_url: str = "http://localhost:8100",
|
||||
session_id: str | None = None,
|
||||
) -> bool:
|
||||
"""
|
||||
Check if the on-screen keyboard is currently shown.
|
||||
|
||||
Args:
|
||||
wda_url: WebDriverAgent URL.
|
||||
session_id: Optional WDA session ID.
|
||||
|
||||
Returns:
|
||||
True if keyboard is shown, False otherwise.
|
||||
"""
|
||||
try:
|
||||
import requests
|
||||
|
||||
url = _get_wda_session_url(wda_url, session_id, "wda/keyboard/shown")
|
||||
|
||||
response = requests.get(url, timeout=5, verify=False)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
return data.get("value", False)
|
||||
|
||||
except ImportError:
|
||||
print("Error: requests library required. Install: pip install requests")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def set_pasteboard(
|
||||
text: str,
|
||||
wda_url: str = "http://localhost:8100",
|
||||
) -> None:
|
||||
"""
|
||||
Set the device pasteboard (clipboard) content.
|
||||
|
||||
Args:
|
||||
text: Text to set in pasteboard.
|
||||
wda_url: WebDriverAgent URL.
|
||||
|
||||
Note:
|
||||
This can be useful for inputting large amounts of text.
|
||||
After setting pasteboard, you can simulate paste gesture.
|
||||
"""
|
||||
try:
|
||||
import requests
|
||||
|
||||
url = f"{wda_url.rstrip('/')}/wda/setPasteboard"
|
||||
|
||||
requests.post(
|
||||
url, json={"content": text, "contentType": "plaintext"}, timeout=10, verify=False
|
||||
)
|
||||
|
||||
except ImportError:
|
||||
print("Error: requests library required. Install: pip install requests")
|
||||
except Exception as e:
|
||||
print(f"Error setting pasteboard: {e}")
|
||||
|
||||
|
||||
def get_pasteboard(
|
||||
wda_url: str = "http://localhost:8100",
|
||||
) -> str | None:
|
||||
"""
|
||||
Get the device pasteboard (clipboard) content.
|
||||
|
||||
Args:
|
||||
wda_url: WebDriverAgent URL.
|
||||
|
||||
Returns:
|
||||
Pasteboard content or None if failed.
|
||||
"""
|
||||
try:
|
||||
import requests
|
||||
|
||||
url = f"{wda_url.rstrip('/')}/wda/getPasteboard"
|
||||
|
||||
response = requests.post(url, timeout=10, verify=False)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
return data.get("value")
|
||||
|
||||
except ImportError:
|
||||
print("Error: requests library required. Install: pip install requests")
|
||||
except Exception as e:
|
||||
print(f"Error getting pasteboard: {e}")
|
||||
|
||||
return None
|
||||
Reference in New Issue
Block a user