refactor(core): 重构分辨率获取逻辑

This commit is contained in:
XcantloadX 2025-01-15 16:48:51 +08:00
parent 18ac6af3f4
commit 25b5ff897d
3 changed files with 49 additions and 10 deletions

View File

@ -151,7 +151,7 @@ def cropped(
def _screenshot_hook(img: MatLike) -> MatLike:
return crop(img, x1, y1, x2, y2)
def _click_hook(x: int, y: int) -> tuple[int, int]:
h, w = device.screen_size # 竖屏下宽高反转
w, h = device.screen_size
x_px = int(x1 * w + x)
y_px = int(y1 * h + y)
return x_px, y_px

View File

@ -1,5 +1,6 @@
import logging
from typing import Callable, cast
from typing_extensions import override
import numpy as np
import cv2
@ -18,9 +19,11 @@ class AdbDevice(DeviceABC):
super().__init__()
self.device = device
@override
def launch_app(self, package_name: str) -> None:
self.device.shell(f"monkey -p {package_name} 1")
@override
def click(self, arg1=None, arg2=None) -> None:
if arg1 is None:
self.__click_last()
@ -55,11 +58,13 @@ class AdbDevice(DeviceABC):
def __click_clickable(self, clickable: ClickableObjectProtocol) -> None:
self.click(clickable.rect)
@override
def swipe(self, x1: int, y1: int, x2: int, y2: int, duration: float|None = None) -> None:
if duration is not None:
logger.warning("Swipe duration is not supported with AdbDevice. Ignoring duration.")
self.device.shell(f"input touchscreen swipe {x1} {y1} {x2} {y2}")
@override
def screenshot(self) -> MatLike:
if self.screenshot_hook_before is not None:
logger.debug("execute screenshot hook before")
@ -72,6 +77,7 @@ class AdbDevice(DeviceABC):
img = self.screenshot_hook_after(img)
return img
@override
def screenshot_raw(self) -> MatLike:
return cv2.cvtColor(np.array(self.device.screenshot()), cv2.COLOR_RGB2BGR)
@ -79,19 +85,31 @@ class AdbDevice(DeviceABC):
def screen_size(self) -> tuple[int, int]:
ret = cast(str, self.device.shell("wm size")).strip('Physical size: ')
spiltted = tuple(map(int, ret.split("x")))
spiltted = tuple(sorted(spiltted, reverse=True))
landscape = self.orientation == 'landscape'
spiltted = tuple(sorted(spiltted, reverse=landscape))
if len(spiltted) != 2:
raise ValueError(f"Invalid screen size: {ret}")
return spiltted
@staticmethod
def list_devices() -> list[str]:
raise NotImplementedError
@override
def start_app(self, package_name: str) -> None:
self.device.shell(f"monkey -p {package_name} 1")
@override
def detect_orientation(self):
# 判断方向https://stackoverflow.com/questions/10040624/check-if-device-is-landscape-via-adb
# 但是上面这种方法不准确
# 因此这里直接通过截图判断方向
img = self.screenshot()
if img.shape[0] > img.shape[1]:
return 'portrait'
return 'landscape'
@override
def current_package(self) -> str:
raise NotImplementedError

View File

@ -1,5 +1,5 @@
from time import sleep
from typing import Callable, Protocol, TYPE_CHECKING, overload, runtime_checkable
from typing import Callable, Protocol, TYPE_CHECKING, overload, runtime_checkable, Literal
from abc import ABC
from cv2.typing import MatLike
@ -74,6 +74,12 @@ class DeviceABC(ABC):
"""点击前调用的函数。返回修改后的点击坐标。"""
self.last_find: Rect | ClickableObjectProtocol | None = None
"""上次 image 对象或 ocr 对象的寻找结果"""
self.orientation: Literal['portrait', 'landscape'] = 'portrait'
"""
设备当前方向默认为竖屏
横屏时为 'landscape'竖屏时为 'portrait'
"""
@staticmethod
def list_devices() -> list[str]:
@ -121,7 +127,11 @@ class DeviceABC(ABC):
def click_center(self) -> None:
"""
点击屏幕中心
点击屏幕中心
此方法会受到 `self.orientation` 的影响
调用前确保 `orientation` 属性与设备方向一致
否则点击位置会不正确
"""
x, y = self.screen_size[0] // 2, self.screen_size[1] // 2
self.click(x, y)
@ -214,10 +224,13 @@ class DeviceABC(ABC):
"""
屏幕尺寸格式为 `(width, height)`
**注意** `width` 总为分辨率中较长的那一边
并不会随横竖屏变化即此属性返回的总是
横屏下的分辨率如果当前设备 APP 为竖屏运行
需要反转元组顺序
**注意** 此属性返回的分辨率会随设备方向变化
如果 `self.orientation` `landscape`则返回的分辨率是横屏下的分辨率
否则返回竖屏下的分辨率
`self.orientation` 属性默认为竖屏如果需要自动检测
调用 `self.detect_orientation()` 方法
如果已知方向也可以直接设置 `self.orientation` 属性
"""
...
@ -227,6 +240,14 @@ class DeviceABC(ABC):
"""
...
def detect_orientation(self) -> Literal['portrait', 'landscape'] | None:
"""
检测当前设备方向并设置 `self.orientation` 属性
:return: 检测到的方向如果无法检测到则返回 None
"""
...
def start_app(self, package_name: str) -> None:
"""
启动某个 APP