diff --git a/tools/fusion_clock_acr_wedge/wedge.py b/tools/fusion_clock_acr_wedge/wedge.py index 2af41e0d..61028019 100644 --- a/tools/fusion_clock_acr_wedge/wedge.py +++ b/tools/fusion_clock_acr_wedge/wedge.py @@ -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: + _emit_macos(uid) + return + except Exception as e: + if verbose: + print(f"[wedge] osascript path failed ({e}); falling back to pyautogui") + try: - import pyautogui + _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):