382 lines
12 KiB
Python
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})"
|
|
|