1. 新增is_window_active接口并在xdotool后端实现,用于校验窗口焦点 2. 为xdotool后端添加主窗口ID缓存,减少重复xdotool调用 3. 精简click命令流程,移除--sync参数避免VNC环境死等 4. 简化post_verify执行逻辑,减少不必要的点击操作 5. 为缓存命中分支添加会话校验回退机制,处理窗口失焦/消失场景
71 lines
2.3 KiB
Python
71 lines
2.3 KiB
Python
"""L1 Backend 抽象层基类:定义 BackendProtocol 与 WindowGeometry。
|
||
|
||
所有具体后端(xdotool / OpenCV / CDP)均实现 BackendProtocol,
|
||
上层 Actions / Flow 通过 Protocol 解耦具体实现,便于切换或回滚。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from abc import ABC, abstractmethod
|
||
from dataclasses import dataclass
|
||
|
||
|
||
@dataclass
|
||
class WindowGeometry:
|
||
"""窗口几何信息(绝对坐标 + 宽高)。
|
||
|
||
所有字段默认值 0,避免构造时必填字段顺序问题。
|
||
"""
|
||
|
||
x: int = 0
|
||
y: int = 0
|
||
width: int = 0
|
||
height: int = 0
|
||
|
||
|
||
class BackendProtocol(ABC):
|
||
"""UI 自动化后端协议(L1 抽象)。
|
||
|
||
子类必须实现所有 abstract 方法;capabilities 属性提供该后端
|
||
支持的能力集合(如 click / type / key / screenshot / window)。
|
||
"""
|
||
|
||
@abstractmethod
|
||
async def click(self, x: int, y: int) -> None:
|
||
"""在绝对坐标 (x, y) 处左键单击。"""
|
||
|
||
@abstractmethod
|
||
async def type_text(self, text: str) -> None:
|
||
"""输入文本(不解析修饰键组合,原样输入)。"""
|
||
|
||
@abstractmethod
|
||
async def key_press(self, key: str, repeat: int = 1) -> None:
|
||
"""按键,支持 repeat 重复。"""
|
||
|
||
@abstractmethod
|
||
async def screenshot(self) -> bytes:
|
||
"""截图并返回 PNG 字节流(不落盘)。"""
|
||
|
||
@abstractmethod
|
||
async def get_window_geometry(self, window_title: str) -> WindowGeometry:
|
||
"""按窗口标题查找窗口并返回几何信息。"""
|
||
|
||
@abstractmethod
|
||
async def activate_window(self, window_title: str) -> None:
|
||
"""激活指定窗口(使其获得焦点)。"""
|
||
|
||
async def is_window_active(self, window_title: str) -> bool:
|
||
"""校验指定标题的窗口是否是当前活动窗口(拥有焦点)。
|
||
|
||
默认实现返回 True(信任 activate_window 的结果)。
|
||
XdotoolBackend 覆盖为真正调用 getactivewindow 对比。
|
||
用于纯坐标模式下 _verify_session_still_open 校验窗口焦点,
|
||
避免 cache_hit 分支命中已失焦的会话。
|
||
"""
|
||
return True
|
||
|
||
@property
|
||
def capabilities(self) -> set[str]:
|
||
"""返回后端支持的能力集合。子类可覆盖。"""
|
||
return {"click", "type", "key", "screenshot", "window"}
|