""" Android text.method 包 — KeyListener, MovementMethod, TransformationMethod 等 方法签名完全对齐 Android SDK """ from __future__ import annotations import sys import time from typing import Any, Dict, List, Optional, Set, Tuple from .._core import Stub, AndroidOnlyError from ..java.lang import RuntimeException IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {}) __all__ = [ "KeyListener", "MetaKeyKeyListener", "NumberKeyListener", "DigitsKeyListener", "TextKeyListener", "MovementMethod", "ArrowKeyMovementMethod", "LinkMovementMethod", "Touch", "BaseMovementMethod", "ScrollingMovementMethod", "WordIterator", "PasswordTransformationMethod", "TransformationMethod", "TransformationMethod2", "SingleLineTransformationMethod", "HideReturnsTransformationMethod", "TimeDisplayTruncationMethod", "DateTimeKeyListener", "DateKeyListener", "TimeKeyListener", ] # ═══════════════════════════════════════════════════════════════ # KeyListener # ═══════════════════════════════════════════════════════════════ class KeyListener(Stub): """KeyListener — 按键监听器接口 (桌面存根)""" META_SHIFT_MASK = 0x1 META_ALT_MASK = 0x2 META_SYM_MASK = 0x4 META_CTRL_MASK = 0x1000 META_META_MASK = 0x10000 META_CAPS_LOCK = 0x100000 META_ALT_LOCK = 0x200000 META_SYM_LOCK = 0x400000 META_SELECTING = 0x800000 META_SHIFTING = 0x1000000 def __init__(self): super().__init__() self._input_type = 0 self._meta_state = 0 def clearMetaKeyState(self, view: Any, content: Any, states: int) -> None: """清除元键状态""" self._meta_state = self._meta_state & ~states def getInputType(self) -> int: """获取输入类型""" return self._input_type def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool: """按键按下事件""" return False def onKeyUp(self, view: Any, content: Any, keyCode: int, event: Any) -> bool: """按键释放事件""" return False def onKeyOther(self, view: Any, content: Any, event: Any) -> bool: """其他按键事件""" return False @staticmethod def metaStateHasNoModifiers(metaState: int) -> bool: """检查元状态是否没有修饰键""" return (metaState & 0x0000FFFF) == 0 @staticmethod def metaStateHasModifiers(metaState: int, modifiers: int) -> bool: """检查元状态是否有指定修饰键""" return (metaState & modifiers) != 0 @staticmethod def metaStateFilterDirectionLocked(metaState: int) -> int: """过滤方向锁定""" return metaState & ~(KeyListener.META_CAPS_LOCK | KeyListener.META_ALT_LOCK | KeyListener.META_SYM_LOCK) def __repr__(self) -> str: return f"KeyListener(inputType={self._input_type})" # ═══════════════════════════════════════════════════════════════ # MetaKeyKeyListener # ═══════════════════════════════════════════════════════════════ class MetaKeyKeyListener(KeyListener): """MetaKeyKeyListener — 元键按键监听器 (桌面存根)""" def __init__(self): super().__init__() self._locked_meta: Dict[int, int] = {} def clearMetaKeyState(self, view: Any, content: Any, states: int) -> None: """清除元键状态""" self._meta_state = self._meta_state & ~states for state_bit in [KeyListener.META_CAPS_LOCK, KeyListener.META_ALT_LOCK, KeyListener.META_SYM_LOCK]: if states & state_bit: self._locked_meta.pop(state_bit, None) @staticmethod def resetMetaState(content: Any) -> None: """重置元状态""" if hasattr(content, '_meta_state'): content._meta_state = 0 def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool: """按键按下事件处理""" return super().onKeyDown(view, content, keyCode, event) def onKeyUp(self, view: Any, content: Any, keyCode: int, event: Any) -> bool: """按键释放事件处理""" return super().onKeyUp(view, content, keyCode, event) @staticmethod def adjustMetaAfterKeypress(content: Any) -> None: """按键后调整元状态""" pass def handleKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool: """处理按键按下 (内部)""" return self.onKeyDown(view, content, keyCode, event) def handleKeyUp(self, view: Any, content: Any, keyCode: int, event: Any) -> bool: """处理按键释放 (内部)""" return self.onKeyUp(view, content, keyCode, event) @staticmethod def getMetaState(content: Any) -> int: """获取元状态""" return getattr(content, '_meta_state', 0) @staticmethod def getMetaState_ex(content: Any, meta: int) -> bool: """检查特定元状态""" state = getattr(content, '_meta_state', 0) return (state & meta) != 0 @staticmethod def isMetaTracker(content: Any) -> bool: """检查是否是元追踪器""" return hasattr(content, '_meta_state') @staticmethod def isSelectingMetaTracker(content: Any) -> bool: """检查是否是选择元追踪器""" return hasattr(content, '_meta_state') and (getattr(content, '_meta_state', 0) & KeyListener.META_SELECTING) != 0 @staticmethod def peekMetaState(content: Any) -> int: """窥视元状态""" return getattr(content, '_meta_state', 0) def resetLockedMeta(self, content: Any) -> None: """重置锁定元键""" self._locked_meta.clear() def clearLockedMeta(self, content: Any) -> None: """清除锁定元键""" self._locked_meta.clear() @staticmethod def releaseAllMetaKeys(content: Any) -> None: """释放所有元键""" if hasattr(content, '_meta_state'): content._meta_state = 0 def toString(self) -> str: return f"MetaKeyKeyListener(metaState={self._meta_state}, locked={self._locked_meta})" # ═══════════════════════════════════════════════════════════════ # NumberKeyListener # ═══════════════════════════════════════════════════════════════ class NumberKeyListener(MetaKeyKeyListener): """NumberKeyListener — 数字按键监听器 (桌面存根)""" _ACCEPTED_CHARS: str = "" def __init__(self): super().__init__() self._input_type = 0x0002 # TYPE_CLASS_NUMBER def getAcceptedChars(self) -> List[str]: """获取接受的字符列表""" return list(self._ACCEPTED_CHARS) def filter(self, source: str, start: int, end: int, dest: str, dstart: int, dend: int) -> str: """过滤输入,只保留接受的字符""" result = "" for i in range(start, end): ch = source[i] if i < len(source) else '' if ch in self._ACCEPTED_CHARS: result += ch return result if result != source[start:end] else "" def lookup(self, key: int, event: Any) -> Optional[str]: """查找按键映射的字符""" key_map = { 7: '0', 8: '1', 9: '2', 10: '3', 11: '4', 12: '5', 13: '6', 14: '7', 15: '8', 16: '9', } return key_map.get(key) def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool: """按键按下事件""" char = self.lookup(keyCode, event) if char and char in self._ACCEPTED_CHARS: return True return False # ═══════════════════════════════════════════════════════════════ # DigitsKeyListener # ═══════════════════════════════════════════════════════════════ class DigitsKeyListener(NumberKeyListener): """DigitsKeyListener — 数字按键监听器 (桌面存根)""" _instances: Dict[str, "DigitsKeyListener"] = {} def __init__(self, accepted: str = "0123456789"): super().__init__() self._ACCEPTED_CHARS = accepted self._input_type = 0x0002 @staticmethod def getInstance(locale: Any = None, sign: bool = False, decimal: bool = False) -> "DigitsKeyListener": """获取实例""" key = f"{locale}_{sign}_{decimal}" if key not in DigitsKeyListener._instances: accepted = "0123456789" if sign: accepted += "-" if decimal: accepted += "." DigitsKeyListener._instances[key] = DigitsKeyListener(accepted) return DigitsKeyListener._instances[key] def getAcceptedChars(self) -> List[str]: return list(self._ACCEPTED_CHARS) def filter(self, source: str, start: int, end: int, dest: str, dstart: int, dend: int) -> str: return super().filter(source, start, end, dest, dstart, dend) # ═══════════════════════════════════════════════════════════════ # TextKeyListener # ═══════════════════════════════════════════════════════════════ class TextKeyListener(MetaKeyKeyListener): """TextKeyListener — 文本按键监听器 (桌面存根)""" CAP_MODE_CHARACTERS = 0x1 CAP_MODE_WORDS = 0x2 CAP_MODE_SENTENCES = 0x4 _instance: Optional["TextKeyListener"] = None def __init__(self): super().__init__() self._input_type = 0x0001 # TYPE_CLASS_TEXT self._auto_cap_mode = 0 @staticmethod def getInstance() -> "TextKeyListener": """获取单例实例""" if TextKeyListener._instance is None: TextKeyListener._instance = TextKeyListener() return TextKeyListener._instance def clear(self, view: Any, content: Any) -> None: """清除内容""" if hasattr(content, 'clear'): content.clear() def release(self, view: Any) -> None: """释放资源""" pass def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool: return True def onKeyUp(self, view: Any, content: Any, keyCode: int, event: Any) -> bool: return True def toString(self) -> str: return f"TextKeyListener(capMode={self._auto_cap_mode})" # ═══════════════════════════════════════════════════════════════ # MovementMethod # ═══════════════════════════════════════════════════════════════ class MovementMethod(Stub): """MovementMethod — 移动方法接口 (桌面存根)""" def __init__(self): super().__init__() self._movement_meta_state = 0 def initialize(self, view: Any, content: Any) -> None: """初始化""" pass def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool: """按键按下""" return False def onKeyUp(self, view: Any, content: Any, keyCode: int, event: Any) -> bool: """按键释放""" return False def onTakeFocus(self, view: Any, content: Any, direction: int) -> bool: """获取焦点""" return False def canSelectArbitrarily(self) -> bool: """能否任意选择""" return False def dispatchTouchEvent(self, view: Any, content: Any, event: Any) -> bool: """分发触摸事件""" return False def onGenericMotionEvent(self, view: Any, content: Any, event: Any) -> bool: """通用运动事件""" return False def getMovementMetaState(self) -> int: """获取移动元状态""" return self._movement_meta_state def setMovementMetaState(self, state: int) -> None: """设置移动元状态""" self._movement_meta_state = state def toString(self) -> str: return f"{self.__class__.__name__}@MovementMethod" # ═══════════════════════════════════════════════════════════════ # ArrowKeyMovementMethod # ═══════════════════════════════════════════════════════════════ class ArrowKeyMovementMethod(MovementMethod): """ArrowKeyMovementMethod — 箭头键移动方法 (桌面存根)""" _instance: Optional["ArrowKeyMovementMethod"] = None def __init__(self): super().__init__() @staticmethod def getInstance() -> "ArrowKeyMovementMethod": if ArrowKeyMovementMethod._instance is None: ArrowKeyMovementMethod._instance = ArrowKeyMovementMethod() return ArrowKeyMovementMethod._instance def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool: return True def canSelectArbitrarily(self) -> bool: return True # ═══════════════════════════════════════════════════════════════ # LinkMovementMethod # ═══════════════════════════════════════════════════════════════ class LinkMovementMethod(MovementMethod): """LinkMovementMethod — 链接移动方法 (桌面存根)""" _instance: Optional["LinkMovementMethod"] = None def __init__(self): super().__init__() @staticmethod def getInstance() -> "LinkMovementMethod": if LinkMovementMethod._instance is None: LinkMovementMethod._instance = LinkMovementMethod() return LinkMovementMethod._instance def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool: return True def canSelectArbitrarily(self) -> bool: return False # ═══════════════════════════════════════════════════════════════ # Touch # ═══════════════════════════════════════════════════════════════ class Touch(Stub): """Touch — 触摸工具类 (桌面存根)""" def __init__(self): super().__init__() self._initial_scroll_x = 0 self._initial_scroll_y = 0 @staticmethod def getInitialScrollX(widget: Any, content: Any) -> int: """获取初始滚动 X""" return getattr(widget, '_initial_scroll_x', 0) @staticmethod def getInitialScrollY(widget: Any, content: Any) -> int: """获取初始滚动 Y""" return getattr(widget, '_initial_scroll_y', 0) @staticmethod def scrollTo(widget: Any, content: Any, x: int, y: int) -> None: """滚动到指定位置""" if hasattr(widget, '_scroll_x'): widget._scroll_x = x if hasattr(widget, '_scroll_y'): widget._scroll_y = y # ═══════════════════════════════════════════════════════════════ # BaseMovementMethod # ═══════════════════════════════════════════════════════════════ class BaseMovementMethod(MovementMethod): """BaseMovementMethod — 基本移动方法 (桌面存根)""" def __init__(self): super().__init__() def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool: return False def canSelectArbitrarily(self) -> bool: return False # ═══════════════════════════════════════════════════════════════ # ScrollingMovementMethod # ═══════════════════════════════════════════════════════════════ class ScrollingMovementMethod(BaseMovementMethod): """ScrollingMovementMethod — 滚动移动方法 (桌面存根)""" _instance: Optional["ScrollingMovementMethod"] = None def __init__(self): super().__init__() @staticmethod def getInstance() -> "ScrollingMovementMethod": if ScrollingMovementMethod._instance is None: ScrollingMovementMethod._instance = ScrollingMovementMethod() return ScrollingMovementMethod._instance def onKeyDown(self, view: Any, content: Any, keyCode: int, event: Any) -> bool: return True # ═══════════════════════════════════════════════════════════════ # WordIterator # ═══════════════════════════════════════════════════════════════ class WordIterator(Stub): """WordIterator — 单词迭代器 (桌面存根)""" def __init__(self, locale: Optional[Any] = None): super().__init__() self._locale = locale self._text = "" self._cursor = 0 def setText(self, text: str, start: int, end: int) -> None: """设置文本""" self._text = text[start:end] if end <= len(text) else text[start:] self._cursor = 0 def next(self) -> int: """下一个单词边界""" self._cursor += 1 return self._cursor def prev(self) -> int: """上一个单词边界""" self._cursor -= 1 return max(self._cursor, 0) def getEnd(self) -> int: """获取结束位置""" return len(self._text) def getBegin(self) -> int: """获取开始位置""" return 0 def isBoundary(self, offset: int) -> bool: """检查是否是单词边界""" return True # ═══════════════════════════════════════════════════════════════ # TransformationMethod / PasswordTransformationMethod # ═══════════════════════════════════════════════════════════════ class TransformationMethod(Stub): """TransformationMethod — 变换方法接口 (桌面存根)""" def __init__(self): super().__init__() def getTransformation(self, source: Any, view: Any) -> Any: """获取变换后的文本""" return source def onFocusChanged(self, view: Any, source: Any, focused: bool, direction: int, previouslyFocused: Any) -> None: """焦点变化事件""" pass class TransformationMethod2(TransformationMethod): """TransformationMethod2 — 带长度变化通知的变换方法""" def __init__(self): super().__init__() self._length_changes_allowed = True def setLengthChangesAllowed(self, allowLengthChanges: bool) -> None: """设置是否允许长度变化""" self._length_changes_allowed = allowLengthChanges class PasswordTransformationMethod(TransformationMethod): """PasswordTransformationMethod — 密码变换方法 (桌面存根)""" _instance: Optional["PasswordTransformationMethod"] = None def __init__(self): super().__init__() @staticmethod def getInstance() -> "PasswordTransformationMethod": if PasswordTransformationMethod._instance is None: PasswordTransformationMethod._instance = PasswordTransformationMethod() return PasswordTransformationMethod._instance def getTransformation(self, source: Any, view: Any) -> Any: """将文本转换为掩码字符""" text = str(source) if source else "" return "\u2022" * len(text) # bullet character def onFocusChanged(self, view: Any, source: Any, focused: bool, direction: int, previouslyFocused: Any) -> None: pass class SingleLineTransformationMethod(TransformationMethod): """SingleLineTransformationMethod — 单行变换方法 (桌面存根)""" _instance: Optional["SingleLineTransformationMethod"] = None def __init__(self): super().__init__() @staticmethod def getInstance() -> "SingleLineTransformationMethod": if SingleLineTransformationMethod._instance is None: SingleLineTransformationMethod._instance = SingleLineTransformationMethod() return SingleLineTransformationMethod._instance def getTransformation(self, source: Any, view: Any) -> Any: """移除换行符""" text = str(source) if source else "" return text.replace("\n", " ").replace("\r", "") class HideReturnsTransformationMethod(SingleLineTransformationMethod): """HideReturnsTransformationMethod — 隐藏回车变换方法 (桌面存根)""" _instance: Optional["HideReturnsTransformationMethod"] = None def __init__(self): super().__init__() @staticmethod def getInstance() -> "HideReturnsTransformationMethod": if HideReturnsTransformationMethod._instance is None: HideReturnsTransformationMethod._instance = HideReturnsTransformationMethod() return HideReturnsTransformationMethod._instance def getTransformation(self, source: Any, view: Any) -> Any: text = str(source) if source else "" return text.replace("\r", "") class TimeDisplayTruncationMethod(TransformationMethod): """TimeDisplayTruncationMethod — 时间显示截断方法 (桌面存根)""" def __init__(self, max_digits: int = 4): super().__init__() self._max_digits = max_digits def getTransformation(self, source: Any, view: Any) -> Any: text = str(source) if source else "" if len(text) > self._max_digits: return text[:self._max_digits] return text # ═══════════════════════════════════════════════════════════════ # DateTimeKeyListener / DateKeyListener / TimeKeyListener # ═══════════════════════════════════════════════════════════════ class DateTimeKeyListener(NumberKeyListener): """DateTimeKeyListener — 日期时间按键监听器 (桌面存根)""" def __init__(self, locale: Optional[Any] = None): super().__init__() self._locale = locale self._ACCEPTED_CHARS = "0123456789/: " class DateKeyListener(NumberKeyListener): """DateKeyListener — 日期按键监听器 (桌面存根)""" _instance: Optional["DateKeyListener"] = None def __init__(self, locale: Optional[Any] = None): super().__init__() self._locale = locale self._ACCEPTED_CHARS = "0123456789/" @staticmethod def getInstance(locale: Any = None) -> "DateKeyListener": if DateKeyListener._instance is None: DateKeyListener._instance = DateKeyListener(locale) return DateKeyListener._instance class TimeKeyListener(NumberKeyListener): """TimeKeyListener — 时间按键监听器 (桌面存根)""" _instance: Optional["TimeKeyListener"] = None def __init__(self, locale: Optional[Any] = None): super().__init__() self._locale = locale self._ACCEPTED_CHARS = "0123456789:" @staticmethod def getInstance(locale: Any = None) -> "TimeKeyListener": if TimeKeyListener._instance is None: TimeKeyListener._instance = TimeKeyListener(locale) return TimeKeyListener._instance