Files
ai-agent-book/chapter9/browser-use-rpa/browser-use/browser_use/actor/mouse.py
T
liqiang b119135836
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
2026-08-20 13:12:50 +00:00

142 lines
4.4 KiB
Python

"""Mouse class for mouse operations."""
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from cdp_use.cdp.input.commands import DispatchMouseEventParameters, SynthesizeScrollGestureParameters
from cdp_use.cdp.input.types import MouseButton
from browser_use.browser.session import BrowserSession
class Mouse:
"""Mouse operations for a target."""
def __init__(self, browser_session: 'BrowserSession', session_id: str | None = None, target_id: str | None = None):
self._browser_session = browser_session
self._client = browser_session.cdp_client
self._session_id = session_id
self._target_id = target_id
async def click(self, x: int, y: int, button: 'MouseButton' = 'left', click_count: int = 1) -> None:
"""Click at the specified coordinates."""
# Mouse press
press_params: 'DispatchMouseEventParameters' = {
'type': 'mousePressed',
'x': x,
'y': y,
'button': button,
'clickCount': click_count,
}
await self._client.send.Input.dispatchMouseEvent(
press_params,
session_id=self._session_id,
)
# Mouse release
release_params: 'DispatchMouseEventParameters' = {
'type': 'mouseReleased',
'x': x,
'y': y,
'button': button,
'clickCount': click_count,
}
await self._client.send.Input.dispatchMouseEvent(
release_params,
session_id=self._session_id,
)
async def down(self, button: 'MouseButton' = 'left', click_count: int = 1) -> None:
"""Press mouse button down."""
params: 'DispatchMouseEventParameters' = {
'type': 'mousePressed',
'x': 0, # Will use last mouse position
'y': 0,
'button': button,
'clickCount': click_count,
}
await self._client.send.Input.dispatchMouseEvent(
params,
session_id=self._session_id,
)
async def up(self, button: 'MouseButton' = 'left', click_count: int = 1) -> None:
"""Release mouse button."""
params: 'DispatchMouseEventParameters' = {
'type': 'mouseReleased',
'x': 0, # Will use last mouse position
'y': 0,
'button': button,
'clickCount': click_count,
}
await self._client.send.Input.dispatchMouseEvent(
params,
session_id=self._session_id,
)
async def move(self, x: int, y: int, steps: int = 1) -> None:
"""Move mouse to the specified coordinates."""
# TODO: Implement smooth movement with multiple steps if needed
_ = steps # Acknowledge parameter for future use
params: 'DispatchMouseEventParameters' = {'type': 'mouseMoved', 'x': x, 'y': y}
await self._client.send.Input.dispatchMouseEvent(params, session_id=self._session_id)
async def scroll(self, x: int = 0, y: int = 0, delta_x: int | None = None, delta_y: int | None = None) -> None:
"""Scroll the page using robust CDP methods."""
if not self._session_id:
raise RuntimeError('Session ID is required for scroll operations')
# Activate the target first (critical for CDP calls to work)
if self._target_id:
try:
await self._client.send.Target.activateTarget(params={'targetId': self._target_id})
except Exception:
pass
# Method 1: Try mouse wheel event (most reliable)
try:
# Get viewport dimensions
layout_metrics = await self._client.send.Page.getLayoutMetrics(session_id=self._session_id)
viewport_width = layout_metrics['layoutViewport']['clientWidth']
viewport_height = layout_metrics['layoutViewport']['clientHeight']
# Use provided coordinates or center of viewport
scroll_x = x if x > 0 else viewport_width / 2
scroll_y = y if y > 0 else viewport_height / 2
# Calculate scroll deltas (positive = down/right)
scroll_delta_x = delta_x or 0
scroll_delta_y = delta_y or 0
# Dispatch mouse wheel event
await self._client.send.Input.dispatchMouseEvent(
params={
'type': 'mouseWheel',
'x': scroll_x,
'y': scroll_y,
'deltaX': scroll_delta_x,
'deltaY': scroll_delta_y,
},
session_id=self._session_id,
)
return
except Exception:
pass
# Method 2: Fallback to synthesizeScrollGesture
try:
params: 'SynthesizeScrollGestureParameters' = {'x': x, 'y': y, 'xDistance': delta_x or 0, 'yDistance': delta_y or 0}
await self._client.send.Input.synthesizeScrollGesture(
params,
session_id=self._session_id,
)
except Exception:
# Method 3: JavaScript fallback
scroll_js = f'window.scrollBy({delta_x or 0}, {delta_y or 0})'
await self._client.send.Runtime.evaluate(
params={'expression': scroll_js, 'returnByValue': True},
session_id=self._session_id,
)