diff --git a/libs/computer-server/computer_server/handlers/macos.py b/libs/computer-server/computer_server/handlers/macos.py index d8e2dcbb..180f083a 100644 --- a/libs/computer-server/computer_server/handlers/macos.py +++ b/libs/computer-server/computer_server/handlers/macos.py @@ -542,7 +542,7 @@ class MacOSAutomationHandler(BaseAutomationHandler): try: if x is not None and y is not None: pyautogui.moveTo(x, y) - pyautogui.doubleClick() + pyautogui.doubleClick(interval=0.1) return {"success": True} except Exception as e: return {"success": False, "error": str(e)} diff --git a/libs/computer/computer/interface/macos.py b/libs/computer/computer/interface/macos.py index dcacb13c..bab8b66b 100644 --- a/libs/computer/computer/interface/macos.py +++ b/libs/computer/computer/interface/macos.py @@ -377,17 +377,49 @@ class MacOSComputerInterface(BaseComputerInterface): """ await self.press(key) - async def hotkey(self, *keys: str) -> None: - await self._send_command("hotkey", {"keys": list(keys)}) + async def hotkey(self, *keys: "KeyType") -> None: + """Press multiple keys simultaneously. + + Args: + *keys: Multiple keys to press simultaneously. Each key can be any of: + - A Key enum value (recommended), e.g. Key.COMMAND + - A direct key value string, e.g. 'command' + - A single character string, e.g. 'a' + + Examples: + ```python + # Using enums (recommended) + await interface.hotkey(Key.COMMAND, Key.C) # Copy + await interface.hotkey(Key.COMMAND, Key.V) # Paste + + # Using mixed formats + await interface.hotkey(Key.COMMAND, 'a') # Select all + ``` + + Raises: + ValueError: If any key type is invalid or not recognized + """ + actual_keys = [] + for key in keys: + if isinstance(key, Key): + actual_keys.append(key.value) + elif isinstance(key, str): + # Try to convert to enum if it matches a known key + key_or_enum = Key.from_string(key) + actual_keys.append(key_or_enum.value if isinstance(key_or_enum, Key) else key_or_enum) + else: + raise ValueError(f"Invalid key type: {type(key)}. Must be Key enum or string.") + + await self._send_command("hotkey", {"keys": actual_keys}) # Scrolling Actions async def scroll_down(self, clicks: int = 1) -> None: for _ in range(clicks): - await self.hotkey("pagedown") + await self.hotkey(Key.PAGE_DOWN) async def scroll_up(self, clicks: int = 1) -> None: for _ in range(clicks): - await self.hotkey("pageup") + await self.hotkey(Key.PAGE_UP) # Screen Actions async def screenshot(