diff --git a/cdp_patches/input/async_input.py b/cdp_patches/input/async_input.py index f47c93e..a3b07d4 100644 --- a/cdp_patches/input/async_input.py +++ b/cdp_patches/input/async_input.py @@ -115,11 +115,18 @@ async def _sleep_timeout(self, timeout: Optional[float] = None) -> None: await asyncio.sleep(timeout) async def click( - self, button: Literal["left", "right", "middle"], x: Union[int, float], y: Union[int, float], pressed: str = "", emulate_behaviour: Optional[bool] = True, timeout: Optional[float] = None + self, + button: Literal["left", "right", "middle"], + x: Union[int, float], + y: Union[int, float], + pressed: str = "", + emulate_behaviour: Optional[bool] = True, + timeout: Optional[float] = None, + double_down: Optional[bool] = False, ) -> None: x, y = int(x), int(y) - await self.down(button=button, x=x, y=y, emulate_behaviour=emulate_behaviour, timeout=timeout, pressed=pressed) + await self.down(button=button, x=x, y=y, emulate_behaviour=emulate_behaviour, timeout=timeout, pressed=pressed, double_down=double_down) if self.emulate_behaviour and emulate_behaviour: await self._sleep_timeout(timeout=timeout) await self.up(button=button, x=x, y=y, pressed=pressed) @@ -130,24 +137,34 @@ async def double_click( ) -> None: x, y = int(x), int(y) - await self.click(button=button, x=x, y=y, timeout=timeout, emulate_behaviour=emulate_behaviour, pressed="__double_click__") + await self.click(button=button, x=x, y=y, timeout=timeout, emulate_behaviour=emulate_behaviour, pressed=pressed) if self.emulate_behaviour and emulate_behaviour: # await self._sleep_timeout(random.uniform(0.14, 0.21)) # await self._sleep_timeout(timeout=timeout) pass - await self.click(button=button, x=x, y=y, emulate_behaviour=False, timeout=timeout, pressed="__double_click__") + await self.click(button=button, x=x, y=y, emulate_behaviour=False, timeout=timeout, pressed=pressed, double_down=True) self.last_x, self.last_y = x, y async def down( - self, button: Literal["left", "right", "middle"], x: Union[int, float], y: Union[int, float], pressed: str = "", emulate_behaviour: Optional[bool] = True, timeout: Optional[float] = None + self, + button: Literal["left", "right", "middle"], + x: Union[int, float], + y: Union[int, float], + pressed: str = "", + emulate_behaviour: Optional[bool] = True, + timeout: Optional[float] = None, + double_down: Optional[bool] = False, ) -> None: x, y = int(x), int(y) if self.emulate_behaviour and emulate_behaviour: await self.move(x=x, y=y, timeout=timeout, emulate_behaviour=emulate_behaviour, pressed=pressed) kwargs = _mk_kwargs(pressed) - self._base.down(button=button, x=x, y=y, **kwargs) + if double_down: + self._base.double_down(button=button, x=x, y=y, **kwargs) + else: + self._base.down(button=button, x=x, y=y, **kwargs) self.last_x, self.last_y = x, y async def up(self, button: Literal["left", "right", "middle"], x: Union[int, float], y: Union[int, float], pressed: str = "") -> None: diff --git a/cdp_patches/input/os_base/linux.py b/cdp_patches/input/os_base/linux.py index d099b5f..fd843b0 100644 --- a/cdp_patches/input/os_base/linux.py +++ b/cdp_patches/input/os_base/linux.py @@ -224,6 +224,8 @@ def down(self, button: Literal["left", "right", "middle"], x: int, y: int) -> No fake_input(self.display, X.ButtonPress, self._translate_button(button)) self.display.sync() + double_down = down + def up(self, button: Literal["left", "right", "middle"], x: int, y: int) -> None: self.ensure_window() self.move(x=x, y=y) diff --git a/cdp_patches/input/os_base/windows.py b/cdp_patches/input/os_base/windows.py index ef8bf41..8c0c6e6 100644 --- a/cdp_patches/input/os_base/windows.py +++ b/cdp_patches/input/os_base/windows.py @@ -7,7 +7,8 @@ from pywinauto import application, timings from pywinauto.application import WindowSpecification from pywinauto.base_wrapper import ElementNotVisible -from pywinauto.controls.hwndwrapper import HwndWrapper, InvalidWindowHandle +from pywinauto.controls.hwndwrapper import HwndWrapper, InvalidWindowHandle, _calc_flags_and_coords +from pywinauto.windows import win32defines, win32functions, win32structures from cdp_patches.input.exceptions import WindowClosedException @@ -130,20 +131,29 @@ async def async_get_window(self, timeout: float = 1) -> WindowSpecification: def down(self, button: Literal["left", "right", "middle"], x: int, y: int, pressed: str = "") -> None: if not pressed: pressed = button - if pressed == "__double_click__": - pressed = "" self.ensure_window() self.browser_window.press_mouse(button=button, pressed=pressed, coords=(int(x * self.scale_factor), int(y * self.scale_factor))) + def double_down(self, button: Literal["left", "right", "middle"], x: int, y: int, pressed: str = ""): + if not pressed: + pressed = button + self.ensure_window() + + if button == "left": + msg = win32defines.WM_LBUTTONDBLCLK + elif button == "right": + msg = win32defines.WM_RBUTTONDBLCLK + else: + msg = win32defines.WM_MBUTTONDBLCLK + + flags, click_point = _calc_flags_and_coords(pressed, [x, y]) + win32functions.PostMessage(self.browser_window, msg, win32structures.WPARAM(flags), win32structures.LPARAM(click_point)) + def up(self, button: Literal["left", "right", "middle"], x: int, y: int, pressed: str = "") -> None: - if pressed == "__double_click__": - pressed = "" self.ensure_window() self.browser_window.release_mouse(button=button, pressed=pressed, coords=(int(x * self.scale_factor), int(y * self.scale_factor))) def move(self, x: int, y: int, pressed: str = "") -> None: - if pressed == "__double_click__": - pressed = "" self.ensure_window() self.browser_window.move_mouse(coords=(int(x * self.scale_factor), int(y * self.scale_factor)), pressed=pressed) diff --git a/cdp_patches/input/sync_input.py b/cdp_patches/input/sync_input.py index 59e54b3..c2956f0 100644 --- a/cdp_patches/input/sync_input.py +++ b/cdp_patches/input/sync_input.py @@ -113,11 +113,18 @@ def _sleep_timeout(self, timeout: Optional[float] = None) -> None: # pass def click( - self, button: Literal["left", "right", "middle"], x: Union[int, float], y: Union[int, float], pressed: str = "", emulate_behaviour: Optional[bool] = True, timeout: Optional[float] = 0.07 + self, + button: Literal["left", "right", "middle"], + x: Union[int, float], + y: Union[int, float], + pressed: str = "", + emulate_behaviour: Optional[bool] = True, + timeout: Optional[float] = 0.07, + double_down: Optional[bool] = False, ) -> None: x, y = int(x), int(y) - self.down(button=button, x=x, y=y, emulate_behaviour=emulate_behaviour, timeout=timeout, pressed=pressed) + self.down(button=button, x=x, y=y, emulate_behaviour=emulate_behaviour, timeout=timeout, pressed=pressed, double_down=double_down) if self.emulate_behaviour and emulate_behaviour: self._sleep_timeout(timeout=timeout) self.up(button=button, x=x, y=y, pressed=pressed) @@ -128,23 +135,33 @@ def double_click( ) -> None: x, y = int(x), int(y) - self.click(button=button, x=x, y=y, timeout=timeout, emulate_behaviour=emulate_behaviour, pressed="__double_click__") + self.click(button=button, x=x, y=y, timeout=timeout, emulate_behaviour=emulate_behaviour, pressed=pressed) if emulate_behaviour and self.emulate_behaviour: # self._sleep_timeout(random.uniform(0.14, 0.21)) # self._sleep_timeout(timeout=timeout) pass - self.click(button=button, x=x, y=y, emulate_behaviour=False, timeout=timeout, pressed="__double_click__") + self.click(button=button, x=x, y=y, emulate_behaviour=False, timeout=timeout, pressed=pressed, double_down=True) self.last_x, self.last_y = x, y def down( - self, button: Literal["left", "right", "middle"], x: Union[int, float], y: Union[int, float], pressed: str = "", emulate_behaviour: Optional[bool] = True, timeout: Optional[float] = None + self, + button: Literal["left", "right", "middle"], + x: Union[int, float], + y: Union[int, float], + pressed: str = "", + emulate_behaviour: Optional[bool] = True, + timeout: Optional[float] = None, + double_down: Optional[bool] = False, ) -> None: x, y = int(x), int(y) if self.emulate_behaviour and emulate_behaviour: self.move(x=x, y=y, emulate_behaviour=emulate_behaviour, timeout=timeout, pressed=pressed) - self._base.down(button=button, x=x, y=y, **_mk_kwargs(pressed)) + if double_down: + self._base.double_down(button=button, x=x, y=y, **_mk_kwargs(pressed)) + else: + self._base.down(button=button, x=x, y=y, **_mk_kwargs(pressed)) self.last_x, self.last_y = x, y def up(self, button: Literal["left", "right", "middle"], x: Union[int, float], y: Union[int, float], pressed: str = "") -> None: diff --git a/tests/conftest.py b/tests/conftest.py index 8673e09..7485c6b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,7 @@ import os import signal import subprocess +import sys import tempfile from typing import AsyncGenerator, Generator, List @@ -167,7 +168,12 @@ async def async_driver() -> AsyncGenerator[async_webdriver.Chrome, None]: @pytest.fixture def chrome_proc() -> Generator[subprocess.Popen[bytes], None, None]: - with tempfile.TemporaryDirectory(ignore_cleanup_errors=True) as tempdir: + if sys.version_info.minor >= 10: + options = {"ignore_cleanup_errors": True} + else: + options = {} + + with tempfile.TemporaryDirectory(**options) as tempdir: # type: ignore[call-overload] path = find_chrome_executable() proc = subprocess.Popen([path, f"--remote-debugging-port={random_port()}", f"--user-data-dir={tempdir}", "--no-first-run"]) try: