autool/DroidBot/core/abstract_input_event.py
2026-06-17 19:44:18 +08:00

382 lines
12 KiB
Python

"""
Abstract Input Event Base Class
Platform-agnostic input event interface.
"""
from abc import ABC, abstractmethod
from typing import Optional, Dict, Any, List
from enum import Enum
import json
class EventType(Enum):
"""事件类型枚举 - 仅包含跨平台通用事件"""
# 基础交互事件
TOUCH = "touch"
LONG_TOUCH = "long_touch"
SWIPE = "swipe"
SCROLL = "scroll"
# 文本输入事件
SET_TEXT = "set_text"
# 按键事件
KEY = "key"
# 应用控制事件(平台无关)
LAUNCH_APP = "launch_app" # 启动应用
KILL_APP = "kill_app" # 强制终止应用
INTENT = "intent" # Android Intent事件
# 特殊事件
MANUAL = "manual"
EXIT = "exit"
# 选择事件
SELECT = "select"
UNSELECT = "unselect"
class AbstractInputEvent(ABC):
"""
输入事件抽象基类
定义了所有输入事件的标准接口,包括:
- 事件发送
- 事件序列化
- 事件字符串表示
"""
def __init__(self, event_type: EventType):
"""
初始化输入事件
:param event_type: 事件类型
"""
self.event_type = event_type
self.log_lines = None
# ==================== 事件发送 ====================
@abstractmethod
def send(self, device: 'AbstractDevice') -> bool:
"""
发送事件到设备
:param device: 设备对象
:return: 是否发送成功
"""
pass
# ==================== 序列化 ====================
@abstractmethod
def to_dict(self) -> Dict[str, Any]:
"""
序列化为字典
:return: 事件信息字典
"""
pass
def to_json(self) -> str:
"""
序列化为 JSON 字符串
:return: JSON 字符串
"""
return json.dumps(self.to_dict())
def __str__(self) -> str:
return self.to_json()
# ==================== 事件描述 ====================
@abstractmethod
def get_event_str(self, state: Optional['AbstractDeviceState'] = None) -> str:
"""
获取事件的字符串描述
:param state: 可选的设备状态对象
:return: 事件描述字符串
"""
pass
# ==================== 视图信息 ====================
def get_views(self) -> List[Dict[str, Any]]:
"""
获取事件关联的视图列表
:return: 视图字典列表
"""
return []
# ==================== 基础事件类型 ====================
class BaseTouchEvent(AbstractInputEvent):
"""触摸事件基类"""
def __init__(self, x: Optional[int] = None, y: Optional[int] = None,
view: Optional[Dict[str, Any]] = None):
"""
初始化触摸事件
:param x: X 坐标
:param y: Y 坐标
:param view: 目标视图(如果提供,将使用视图中心点)
"""
super().__init__(EventType.TOUCH)
self.x = x
self.y = y
self.view = view
# 如果提供了视图,使用视图中心点
if view is not None and (x is None or y is None):
from .abstract_device_state import AbstractDeviceState
center = AbstractDeviceState.get_view_center(view)
self.x = int(center[0])
self.y = int(center[1])
def send(self, device: 'AbstractDevice') -> bool:
"""发送事件 - 需要由平台特定子类实现"""
raise NotImplementedError("BaseTouchEvent.send() must be implemented by platform-specific subclass")
def to_dict(self) -> Dict[str, Any]:
return {
"event_type": self.event_type.value,
"x": self.x,
"y": self.y,
"view": self.view
}
def get_event_str(self, state: Optional['AbstractDeviceState'] = None) -> str:
if self.view is not None:
view_str = self.view.get('view_str', str(self.view))
return f"Touch({view_str})"
return f"Touch({self.x}, {self.y})"
class BaseLongTouchEvent(AbstractInputEvent):
"""长按事件基类"""
def __init__(self, x: Optional[int] = None, y: Optional[int] = None,
view: Optional[Dict[str, Any]] = None, duration: int = 2000):
"""
初始化长按事件
:param x: X 坐标
:param y: Y 坐标
:param view: 目标视图
:param duration: 长按持续时间(毫秒)
"""
super().__init__(EventType.LONG_TOUCH)
self.x = x
self.y = y
self.view = view
self.duration = duration
if view is not None and (x is None or y is None):
from .abstract_device_state import AbstractDeviceState
center = AbstractDeviceState.get_view_center(view)
self.x = int(center[0])
self.y = int(center[1])
def send(self, device: 'AbstractDevice') -> bool:
"""发送事件 - 需要由平台特定子类实现"""
raise NotImplementedError("BaseLongTouchEvent.send() must be implemented by platform-specific subclass")
def to_dict(self) -> Dict[str, Any]:
return {
"event_type": self.event_type.value,
"x": self.x,
"y": self.y,
"duration": self.duration,
"view": self.view
}
def get_event_str(self, state: Optional['AbstractDeviceState'] = None) -> str:
if self.view is not None:
view_str = self.view.get('view_str', str(self.view))
return f"LongTouch({view_str})"
return f"LongTouch({self.x}, {self.y}, {self.duration}ms)"
class BaseSwipeEvent(AbstractInputEvent):
"""滑动事件基类"""
def __init__(self, start_x: int, start_y: int, end_x: int, end_y: int,
duration: int = 500, view: Optional[Dict[str, Any]] = None):
"""
初始化滑动事件
:param start_x: 起始 X 坐标
:param start_y: 起始 Y 坐标
:param end_x: 结束 X 坐标
:param end_y: 结束 Y 坐标
:param duration: 滑动持续时间(毫秒)
:param view: 关联的视图字典(可选)
"""
super().__init__(EventType.SWIPE)
self.start_x = start_x
self.start_y = start_y
self.end_x = end_x
self.end_y = end_y
self.duration = duration
self.view = view
def send(self, device: 'AbstractDevice') -> bool:
"""发送事件 - 需要由平台特定子类实现"""
raise NotImplementedError("BaseSwipeEvent.send() must be implemented by platform-specific subclass")
def to_dict(self) -> Dict[str, Any]:
return {
"event_type": self.event_type.value,
"start_x": self.start_x,
"start_y": self.start_y,
"end_x": self.end_x,
"end_y": self.end_y,
"duration": self.duration,
"view": self.view
}
def get_event_str(self, state: Optional['AbstractDeviceState'] = None) -> str:
if self.view is not None:
view_str = self.view.get('view_str', str(self.view))
return f"Swipe({view_str}, {self.start_x},{self.start_y} -> {self.end_x},{self.end_y})"
return f"Swipe({self.start_x},{self.start_y} -> {self.end_x},{self.end_y})"
class BaseScrollEvent(AbstractInputEvent):
"""滚动事件基类"""
DIRECTION_UP = "up"
DIRECTION_DOWN = "down"
DIRECTION_LEFT = "left"
DIRECTION_RIGHT = "right"
def __init__(self, direction: str = "down", view: Optional[Dict[str, Any]] = None):
"""
初始化滚动事件
:param direction: 滚动方向 ('up', 'down', 'left', 'right')
:param view: 目标视图(可选)
"""
super().__init__(EventType.SCROLL)
self.direction = direction
self.view = view
def send(self, device: 'AbstractDevice') -> bool:
"""发送事件 - 需要由平台特定子类实现"""
raise NotImplementedError("BaseScrollEvent.send() must be implemented by platform-specific subclass")
def to_dict(self) -> Dict[str, Any]:
return {
"event_type": self.event_type.value,
"direction": self.direction,
"view": self.view
}
def get_event_str(self, state: Optional['AbstractDeviceState'] = None) -> str:
if self.view is not None:
view_str = self.view.get('view_str', str(self.view))
return f"Scroll({view_str}, {self.direction})"
return f"Scroll({self.direction})"
class BaseSetTextEvent(AbstractInputEvent):
"""文本输入事件基类"""
def __init__(self, text: str, view: Optional[Dict[str, Any]] = None):
"""
初始化文本输入事件
:param text: 要输入的文本
:param view: 目标视图
"""
super().__init__(EventType.SET_TEXT)
self.text = text
self.view = view
def send(self, device: 'AbstractDevice') -> bool:
"""发送事件 - 需要由平台特定子类实现"""
raise NotImplementedError("BaseSetTextEvent.send() must be implemented by platform-specific subclass")
def to_dict(self) -> Dict[str, Any]:
return {
"event_type": self.event_type.value,
"text": self.text,
"view": self.view
}
def get_event_str(self, state: Optional['AbstractDeviceState'] = None) -> str:
if self.view is not None:
view_str = self.view.get('view_str', str(self.view))
return f"SetText({view_str}, '{self.text}')"
return f"SetText('{self.text}')"
class BaseKeyEvent(AbstractInputEvent):
"""按键事件基类"""
# 通用按键名称
KEY_BACK = "BACK"
KEY_HOME = "HOME"
KEY_MENU = "MENU"
KEY_ENTER = "ENTER"
KEY_ESCAPE = "ESCAPE"
def __init__(self, key_name: str):
"""
初始化按键事件
:param key_name: 按键名称
"""
super().__init__(EventType.KEY)
self.key_name = key_name
def send(self, device: 'AbstractDevice') -> bool:
"""发送事件 - 需要由平台特定子类实现"""
raise NotImplementedError("BaseKeyEvent.send() must be implemented by platform-specific subclass")
def to_dict(self) -> Dict[str, Any]:
return {
"event_type": self.event_type.value,
"key_name": self.key_name
}
def get_event_str(self, state: Optional['AbstractDeviceState'] = None) -> str:
return f"Key({self.key_name})"
class BaseKillAppEvent(AbstractInputEvent):
"""终止应用事件基类"""
def __init__(self, app=None):
"""
初始化终止应用事件
:param app: 要终止的应用
"""
super().__init__(EventType.KILL_APP)
self.app = app
def send(self, device: 'AbstractDevice') -> bool:
"""发送事件 - 需要由平台特定子类实现"""
raise NotImplementedError("BaseKillAppEvent.send() must be implemented by platform-specific subclass")
def to_dict(self) -> Dict[str, Any]:
return {
"event_type": self.event_type.value,
"app": str(self.app) if self.app else None
}
def get_event_str(self, state: Optional['AbstractDeviceState'] = None) -> str:
return f"KillApp({self.app})"