Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #10 and change License #11

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ jobs:
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Increase swapfile
run: |
sudo swapoff -a
sudo fallocate -l 15G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
sudo swapon --show
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,6 @@ cython_debug/
#.idea/
/.idea
/.vs

# AI Weights
*.pt
674 changes: 0 additions & 674 deletions LICENSE

This file was deleted.

1 change: 1 addition & 0 deletions cdp_patches/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
elif system_name == "Linux":
is_windows = False
else:
is_windows = False
warnings.warn("Unknown system (You´re probably using MacOS, which is currently not supported).", RuntimeWarning)

__all__ = ["VERSION", "is_windows"]
43 changes: 27 additions & 16 deletions cdp_patches/input/async_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@
import time
from typing import Any, Generator, Literal, Optional, Union

from pywinauto.mouse import press

if sys.version_info.minor >= 10:
from typing import TypeAlias
else:
TypeAlias = "TypeAlias" # type: ignore[assignment]

from cdp_patches import is_windows
from cdp_patches.input.exceptions import WindowClosedException
from cdp_patches.input.utils import _mk_kwargs

if is_windows:
from pywinauto.application import ProcessNotFoundError
Expand Down Expand Up @@ -113,43 +116,51 @@ 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], emulate_behaviour: Optional[bool] = True, timeout: Optional[float] = None) -> None:
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
) -> None:
x, y = int(x), int(y)

await self.down(button=button, x=x, y=y, emulate_behaviour=emulate_behaviour, timeout=timeout)
await self.down(button=button, x=x, y=y, emulate_behaviour=emulate_behaviour, timeout=timeout, pressed=pressed)
if self.emulate_behaviour and emulate_behaviour:
await self._sleep_timeout(timeout=timeout)
await self.up(button=button, x=x, y=y)
await self.up(button=button, x=x, y=y, pressed=pressed)
self.last_x, self.last_y = x, y

async def double_click(
self, button: Literal["left", "right", "middle"], x: Union[int, float], y: Union[int, float], 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
) -> None:
x, y = int(x), int(y)

await self.click(button=button, x=x, y=y, timeout=timeout, emulate_behaviour=emulate_behaviour)
press_timeout = click_timeout = timeout or self.sleep_timeout
if self.emulate_behaviour and emulate_behaviour:
await self._sleep_timeout(random.uniform(0.14, 0.21))
# await self._sleep_timeout(timeout=timeout)
await self.click(button=button, x=x, y=y, emulate_behaviour=False, timeout=timeout)
click_timeout = random.uniform(0.14, 0.21)
self._base.move(x=x, y=y)

kwargs = _mk_kwargs(pressed)
self._base.double_click(button=button, x=x, y=y, press_timeout=press_timeout, click_timeout=click_timeout, **kwargs)
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], emulate_behaviour: Optional[bool] = True, timeout: Optional[float] = None) -> None:
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
) -> 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)
self._base.down(button=button, x=x, y=y)
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)
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]) -> None:
async def up(self, button: Literal["left", "right", "middle"], x: Union[int, float], y: Union[int, float], pressed: str = "") -> None:
x, y = int(x), int(y)

self._base.up(button=button, x=x, y=y)
kwargs = _mk_kwargs(pressed)
self._base.up(button=button, x=x, y=y, **kwargs)
self.last_x, self.last_y = x, y

async def move(self, x: Union[int, float], y: Union[int, float], emulate_behaviour: Optional[bool] = True, timeout: Optional[float] = None) -> None:
async def move(self, x: Union[int, float], y: Union[int, float], emulate_behaviour: Optional[bool] = True, timeout: Optional[float] = None, pressed: str = "") -> None:
kwargs = _mk_kwargs(pressed)
async with self._move_lock:
x, y = int(x), int(y)

Expand All @@ -158,11 +169,11 @@ async def move(self, x: Union[int, float], y: Union[int, float], emulate_behavio

# Move Mouse to new random locations
for i, (human_x, human_y) in enumerate(humanized_points.points):
self._base.move(x=int(human_x), y=int(human_y))
self._base.move(x=int(human_x), y=int(human_y), **kwargs)
await self._sleep_timeout(timeout=timeout)

else:
self._base.move(x=x, y=y)
self._base.move(x=x, y=y, **kwargs)
self.last_x, self.last_y = x, y

async def scroll(self, direction: Literal["up", "down", "left", "right"], amount: int) -> None:
Expand Down
6 changes: 3 additions & 3 deletions cdp_patches/input/browsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@
try:
from selenium.webdriver import Chrome as SeleniumChrome
except ImportError:
SeleniumChrome: Type["SeleniumChrome"] = "SeleniumChrome" # type: ignore[no-redef]
SeleniumChrome: Type["SeleniumChrome"] = type("SeleniumChrome", (object,), {}) # type: ignore[no-redef]

try:
from selenium_driverless.sync.webdriver import Chrome as DriverlessSyncChrome
from selenium_driverless.webdriver import Chrome as DriverlessAsyncChrome
except ImportError:
DriverlessAsyncChrome: Type["DriverlessAsyncChrome"] = "DriverlessAsyncChrome" # type: ignore[no-redef]
DriverlessSyncChrome: Type["DriverlessSyncChrome"] = "DriverlessSyncChrome" # type: ignore[no-redef]
DriverlessAsyncChrome: Type["DriverlessAsyncChrome"] = type("DriverlessAsyncChrome", (object,), {}) # type: ignore[no-redef]
DriverlessSyncChrome: Type["DriverlessSyncChrome"] = type("DriverlessSyncChrome", (object,), {}) # type: ignore[no-redef]

all_browsers = Union[AsyncContext, AsyncBrowser, SyncContext, SyncBrowser, BotrightContext, SeleniumChrome, DriverlessAsyncChrome, DriverlessSyncChrome]
sync_browsers = Union[SeleniumChrome, SyncContext, SyncBrowser, DriverlessSyncChrome]
Expand Down
2 changes: 2 additions & 0 deletions cdp_patches/input/os_base/linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
43 changes: 35 additions & 8 deletions cdp_patches/input/os_base/windows.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import asyncio
import ctypes
import re
import time
import warnings
from typing import List, Literal, Union

from pywinauto import application, timings
from pywinauto import application, timings, win32defines, win32functions, win32structures
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 cdp_patches.input.exceptions import WindowClosedException

Expand Down Expand Up @@ -127,17 +128,43 @@ async def async_get_window(self, timeout: float = 1) -> WindowSpecification:

return self.browser_window

def down(self, button: Literal["left", "right", "middle"], x: int, y: int) -> None:
def down(self, button: Literal["left", "right", "middle"], x: int, y: int, pressed: str = "") -> None:
if not pressed:
pressed = button
self.ensure_window()
self.browser_window.press_mouse(button=button, coords=(int(x * self.scale_factor), int(y * self.scale_factor)))
self.browser_window.press_mouse(button=button, pressed=pressed, coords=(int(x * self.scale_factor), int(y * self.scale_factor)))

def up(self, button: Literal["left", "right", "middle"], x: int, y: int) -> None:
def double_click(self, button: Literal["left", "right", "middle"], x: int, y: int, pressed: str = "", press_timeout: float = 0.01, click_timeout: float = 0.15) -> None:
if not pressed:
pressed = button
flags, click_point = _calc_flags_and_coords(pressed, [x, y])

self.ensure_window()

if button.lower() == "left":
click = (win32defines.WM_LBUTTONDOWN, win32defines.WM_LBUTTONUP)
elif button.lower() == "right":
click = (win32defines.WM_RBUTTONDOWN, win32defines.WM_RBUTTONUP)
else:
click = (win32defines.WM_MBUTTONDOWN, win32defines.WM_MBUTTONUP)

# figure out the flags and pack coordinates
for i in range(2):
for msg in click:
win32functions.PostMessage(self.browser_window, msg, win32structures.WPARAM(flags), win32structures.LPARAM(click_point))
time.sleep(press_timeout)
# wait until the thread can accept another message
win32functions.WaitGuiThreadIdle(self.browser_window.handle)
if not i:
time.sleep(click_timeout)

def up(self, button: Literal["left", "right", "middle"], x: int, y: int, pressed: str = "") -> None:
self.ensure_window()
self.browser_window.release_mouse(button=button, coords=(int(x * self.scale_factor), int(y * self.scale_factor)))
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) -> None:
def move(self, x: int, y: int, pressed: str = "") -> None:
self.ensure_window()
self.browser_window.move_mouse(coords=(int(x * self.scale_factor), int(y * self.scale_factor)), pressed="left")
self.browser_window.move_mouse(coords=(int(x * self.scale_factor), int(y * self.scale_factor)), pressed=pressed)

def scroll(self, direction: Literal["up", "down", "left", "right"], amount: int) -> None:
self.ensure_window()
Expand Down
43 changes: 26 additions & 17 deletions cdp_patches/input/sync_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

from cdp_patches import is_windows
from cdp_patches.input.exceptions import WindowClosedException
from cdp_patches.input.utils import _mk_kwargs

if is_windows:
from pywinauto.application import ProcessNotFoundError
Expand Down Expand Up @@ -111,41 +112,49 @@ def _sleep_timeout(self, timeout: Optional[float] = None) -> None:
# while time.perf_counter() - start < timeout:
# pass

def click(self, button: Literal["left", "right", "middle"], x: Union[int, float], y: Union[int, float], emulate_behaviour: Optional[bool] = True, timeout: Optional[float] = 0.07) -> None:
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
) -> None:
x, y = int(x), int(y)

self.down(button=button, x=x, y=y, emulate_behaviour=emulate_behaviour, timeout=timeout)
self.down(button=button, x=x, y=y, emulate_behaviour=emulate_behaviour, timeout=timeout, pressed=pressed)
if self.emulate_behaviour and emulate_behaviour:
self._sleep_timeout(timeout=timeout)
self.up(button=button, x=x, y=y)
self.up(button=button, x=x, y=y, pressed=pressed)
self.last_x, self.last_y = x, y

def double_click(self, button: Literal["left", "right", "middle"], x: Union[int, float], y: Union[int, float], emulate_behaviour: Optional[bool] = True, timeout: Optional[float] = None) -> None:
def double_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
) -> None:
x, y = int(x), int(y)

self.click(button=button, x=x, y=y, timeout=timeout, emulate_behaviour=emulate_behaviour)
if emulate_behaviour and self.emulate_behaviour:
self._sleep_timeout(random.uniform(0.14, 0.21))
# self._sleep_timeout(timeout=timeout)
self.click(button=button, x=x, y=y, emulate_behaviour=False, timeout=timeout)
press_timeout = click_timeout = timeout or self.sleep_timeout
if self.emulate_behaviour and emulate_behaviour:
click_timeout = random.uniform(0.14, 0.21)
self._base.move(x=x, y=y)

kwargs = _mk_kwargs(pressed)
self._base.double_click(button=button, x=x, y=y, press_timeout=press_timeout, click_timeout=click_timeout, **kwargs)
self.last_x, self.last_y = x, y

def down(self, button: Literal["left", "right", "middle"], x: Union[int, float], y: Union[int, float], emulate_behaviour: Optional[bool] = True, timeout: Optional[float] = None) -> None:
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
) -> 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)
self._base.down(button=button, x=x, y=y)
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))
self.last_x, self.last_y = x, y

def up(self, button: Literal["left", "right", "middle"], x: Union[int, float], y: Union[int, float]) -> None:
def up(self, button: Literal["left", "right", "middle"], x: Union[int, float], y: Union[int, float], pressed: str = "") -> None:
x, y = int(x), int(y)

self._base.up(button=button, x=x, y=y)
self._base.up(button=button, x=x, y=y, **_mk_kwargs(pressed))
self.last_x, self.last_y = x, y

def move(self, x: Union[int, float], y: Union[int, float], emulate_behaviour: Optional[bool] = True, timeout: Optional[float] = None) -> None:
def move(self, x: Union[int, float], y: Union[int, float], pressed: str = "", emulate_behaviour: Optional[bool] = True, timeout: Optional[float] = None) -> None:
kwargs = _mk_kwargs(pressed)
with self._move_lock:
x, y = int(x), int(y)

Expand All @@ -154,10 +163,10 @@ def move(self, x: Union[int, float], y: Union[int, float], emulate_behaviour: Op

# Move Mouse to new random locations
for i, (human_x, human_y) in enumerate(humanized_points.points):
self._base.move(x=int(human_x), y=int(human_y))
self._base.move(x=int(human_x), y=int(human_y), **kwargs)
self._sleep_timeout(timeout=timeout)

self._base.move(x=x, y=y)
self._base.move(x=x, y=y, **kwargs)
self.last_x, self.last_y = x, y

def scroll(self, direction: Literal["up", "down", "left", "right"], amount: int) -> None:
Expand Down
12 changes: 12 additions & 0 deletions cdp_patches/input/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from typing import Optional

from cdp_patches import is_windows


def _mk_kwargs(pressed: Optional[str]) -> dict[str, str]:
kwargs = {}
if pressed is not None:
if not is_windows:
raise NotImplementedError("specifying pressed buttons currently only supported for windows")
kwargs["pressed"] = pressed
return kwargs
3 changes: 1 addition & 2 deletions requirements-test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,4 @@ playwright==1.44.0
selenium==4.22.0
selenium_driverless==1.9.3.1
twisted==24.3.0
types-requests==2.31.*
webdriver_manager==4.0.1
types-requests==2.31.*
6 changes: 6 additions & 0 deletions tests/assets/input/mouse-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,10 @@
for (let i = 0; i < 5; i++)
box.classList.toggle('button-' + i, buttons & (1 << i));
}

window.last_hover_elem = undefined
document.body.addEventListener("mousemove", ()=>{
var elem = document.querySelector('button:hover')
if (typeof elem !== 'undefined'){window.last_hover_elem = elem}
})
})();
Loading
Loading