fix(acr-wedge): use AppleScript on macOS for keystroke injection
pyautogui's Quartz-based keystroke path often fails on newer macOS because the Python CLI binary doesn't auto-surface in System Settings > Accessibility. User reported the daemon detected taps fine but keystrokes never landed in any window. Switch to AppleScript / System Events on macOS. Permission attaches to whatever terminal/app launched the Python process (Terminal.app, iTerm, etc.) — a familiar named app the user can grant Accessibility to in one click. Combined keystroke + Return in a single osascript call to keep latency ~100ms per tap. Fall back to pyautogui if osascript fails (handles edge cases) and on non-macOS platforms.
This commit is contained in:
@@ -112,23 +112,62 @@ def read_uid(connection):
|
||||
return ":".join(f"{b:02X}" for b in data)
|
||||
|
||||
|
||||
def _emit_macos(uid):
|
||||
"""Type via AppleScript / System Events.
|
||||
|
||||
Permission attaches to the terminal/app that launched this Python
|
||||
process — typically Terminal.app, iTerm, or another known GUI app
|
||||
that the user can easily find in Accessibility settings. More
|
||||
reliable than pyautogui's Quartz path which often fails to surface
|
||||
Python in the Accessibility list on newer macOS.
|
||||
"""
|
||||
import subprocess
|
||||
script = (
|
||||
'tell application "System Events"\n'
|
||||
f' keystroke "{uid}"\n'
|
||||
' key code 36\n' # Return
|
||||
'end tell'
|
||||
)
|
||||
result = subprocess.run(
|
||||
["osascript", "-e", script],
|
||||
capture_output=True, text=True, check=False, timeout=3,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(f"osascript failed: {result.stderr.strip()}")
|
||||
|
||||
|
||||
def _emit_other(uid):
|
||||
"""Type via pyautogui (works on Linux, Windows, and as macOS fallback)."""
|
||||
import pyautogui
|
||||
pyautogui.typewrite(uid, interval=0.005)
|
||||
pyautogui.press("enter")
|
||||
|
||||
|
||||
def emit_uid(uid, type_keys=True, verbose=False):
|
||||
"""Type UID + Enter into the focused window via pyautogui."""
|
||||
"""Type UID + Enter into the focused window."""
|
||||
if verbose:
|
||||
print(f"[wedge] TAP {uid}")
|
||||
if not type_keys:
|
||||
return
|
||||
|
||||
if sys.platform == "darwin":
|
||||
try:
|
||||
import pyautogui
|
||||
_emit_macos(uid)
|
||||
return
|
||||
except Exception as e:
|
||||
if verbose:
|
||||
print(f"[wedge] osascript path failed ({e}); falling back to pyautogui")
|
||||
|
||||
try:
|
||||
_emit_other(uid)
|
||||
except ImportError:
|
||||
print(
|
||||
"[wedge] pyautogui is not installed; cannot type. "
|
||||
"Run: pip3 install pyautogui (or use --no-type for detect-only)",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return
|
||||
pyautogui.typewrite(uid, interval=0.005)
|
||||
pyautogui.press("enter")
|
||||
except Exception as e:
|
||||
print(f"[wedge] type error: {e}", file=sys.stderr)
|
||||
|
||||
|
||||
def run_loop(args):
|
||||
|
||||
Reference in New Issue
Block a user