511e36b660
After each capture the controller asks the vision model to locate a 'Next' control (returned as normalized screen coordinates), clicks it via OS input, scrolls to top, and continues the loop. Configurable via SCREEN_LEADS_AUTO_NEXT / _NEXT_LOAD_PAUSE / _MAX_AUTO_NEXT, with a per-run safety cap. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
58 lines
1.5 KiB
Python
58 lines
1.5 KiB
Python
"""OS-level scrolling of the focused window via pyautogui.
|
|
|
|
We drive real scroll input rather than the DOM, so it works over a plain
|
|
screenshot pipeline on any OS. Needs Accessibility permission on macOS and an
|
|
X11 session on Linux.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import time
|
|
|
|
from config import SCROLL_AMOUNT, SCROLL_PAUSE
|
|
|
|
|
|
class ScrollError(RuntimeError):
|
|
pass
|
|
|
|
|
|
def _pyautogui():
|
|
try:
|
|
import pyautogui
|
|
|
|
pyautogui.FAILSAFE = False
|
|
return pyautogui
|
|
except Exception as e: # pragma: no cover
|
|
raise ScrollError(
|
|
f"pyautogui not available ({e}). On macOS grant Accessibility; "
|
|
f"on Linux use X11."
|
|
)
|
|
|
|
|
|
def scroll_to_top() -> None:
|
|
pg = _pyautogui()
|
|
# A large upward scroll reliably returns most pages to the top.
|
|
for _ in range(10):
|
|
pg.scroll(SCROLL_AMOUNT)
|
|
time.sleep(SCROLL_PAUSE)
|
|
|
|
|
|
def scroll_down(amount: int = SCROLL_AMOUNT) -> None:
|
|
pg = _pyautogui()
|
|
pg.scroll(-abs(amount))
|
|
time.sleep(SCROLL_PAUSE)
|
|
|
|
|
|
def click_at_fraction(x_frac: float, y_frac: float) -> None:
|
|
"""Click at a position given as fractions (0..1) of the logical screen.
|
|
|
|
Fractions are resolution- and Retina-independent: pyautogui reports the
|
|
logical screen size, and the capture covers the same primary display, so a
|
|
fraction of the screenshot maps directly to a fraction of the screen.
|
|
"""
|
|
pg = _pyautogui()
|
|
w, h = pg.size()
|
|
x = int(max(0.0, min(1.0, x_frac)) * w)
|
|
y = int(max(0.0, min(1.0, y_frac)) * h)
|
|
pg.moveTo(x, y, duration=0.2)
|
|
pg.click()
|