""" Android InputMethod 组件 — InputMethodService, Keyboard, KeyboardView, Key 等 方法签名完全对齐 Android SDK """ import sys from typing import Any, Callable, Dict, List, Optional, Tuple from .._core import Stub, AndroidOnlyError, android_context # ═══════════════════════════════════════════════════════════════ # InputMethod # ═══════════════════════════════════════════════════════════════ class InputMethod(Stub): """InputMethod — 输入法接口""" def __init__(self): super().__init__() def createSession(self, callback: Any) -> Optional["InputMethodSession"]: """创建输入法会话""" return None def startInput(self, input_connection: Any, editor_info: Any) -> None: """开始输入""" pass def restartInput(self, input_connection: Any, editor_info: Any) -> None: """重启输入""" pass def dispatchKeyEvent(self, event: Any) -> None: """分发按键事件""" pass def dispatchTrackballEvent(self, event: Any) -> None: """分发轨迹球事件""" pass def dispatchGenericMotionEvent(self, event: Any) -> None: """分发通用运动事件""" pass # ═══════════════════════════════════════════════════════════════ # InputMethodSession # ═══════════════════════════════════════════════════════════════ class InputMethodSession(Stub): """InputMethodSession — 输入法会话接口""" def __init__(self): super().__init__() def finishInput(self): """结束输入""" pass def updateSelection(self, old_sel_start: int, old_sel_end: int, new_sel_start: int, new_sel_end: int, candidates_start: int, candidates_end: int): """更新选区""" pass def updateCursor(self, old_cursor: Any, new_cursor: Any): """更新光标""" pass def displayCompletions(self, completions: List["CompletionInfo"]): """显示补全""" pass def appPrivateCommand(self, action: str, data: Any): """应用私有命令""" pass def viewClicked(self, focus_changed: bool): """视图点击""" pass def updateExtractedText(self, token: int, extracted_text: Any): """更新提取文本""" pass def dispatchKeyEvent(self, key_code: int, event: Any) -> None: """分发按键事件""" pass def dispatchTrackballEvent(self, event: Any) -> None: pass def dispatchGenericMotionEvent(self, event: Any) -> None: pass def toggleSoftInput(self, show_flags: int, hide_flags: int): """切换软键盘""" pass def notifyImeHidden(self): """通知输入法隐藏""" pass def removeImeSurface(self): """移除输入法界面""" pass # ═══════════════════════════════════════════════════════════════ # AbstractInputMethodService # ═══════════════════════════════════════════════════════════════ class AbstractInputMethodService(Stub): """AbstractInputMethodService — 抽象输入法服务基类""" def __init__(self): super().__init__() self._input_method: Optional[InputMethod] = None self._input_method_session: Optional[InputMethodSession] = None def onCreate(self): """服务创建""" pass def onDestroy(self): """服务销毁""" pass def onBind(self, intent: Any) -> Any: """绑定""" return None def onUnbind(self, intent: Any) -> bool: """解绑""" return False def onCreateInputMethod(self) -> InputMethod: """创建输入法实例""" return InputMethod() def onCreateInputMethodSession(self) -> InputMethodSession: """创建输入法会话""" return InputMethodSession() def getKeyDispatcherState(self) -> Any: """获取按键调度状态""" return None # ═══════════════════════════════════════════════════════════════ # InputMethodImpl # ═══════════════════════════════════════════════════════════════ class InputMethodImpl(InputMethod): """InputMethodImpl — 输入法实现""" def __init__(self): super().__init__() self._session: Optional[InputMethodSession] = None def createSession(self, callback: Any) -> Optional["InputMethodSession"]: self._session = InputMethodSessionImpl() return self._session def startInput(self, input_connection: Any, editor_info: Any): sys.stderr.write("[InputMethodImpl] startInput\n") def restartInput(self, input_connection: Any, editor_info: Any): sys.stderr.write("[InputMethodImpl] restartInput\n") def dispatchKeyEvent(self, event: Any): sys.stderr.write("[InputMethodImpl] dispatchKeyEvent\n") def dispatchTrackballEvent(self, event: Any): pass def dispatchGenericMotionEvent(self, event: Any): pass # ═══════════════════════════════════════════════════════════════ # InputMethodSessionImpl # ═══════════════════════════════════════════════════════════════ class InputMethodSessionImpl(InputMethodSession): """InputMethodSessionImpl — 输入法会话实现""" def __init__(self): super().__init__() def finishInput(self): sys.stderr.write("[InputMethodSessionImpl] finishInput\n") def updateSelection(self, old_sel_start: int, old_sel_end: int, new_sel_start: int, new_sel_end: int, candidates_start: int, candidates_end: int): pass def displayCompletions(self, completions: List["CompletionInfo"]): pass def dispatchKeyEvent(self, key_code: int, event: Any): pass # ═══════════════════════════════════════════════════════════════ # InputMethodService # ═══════════════════════════════════════════════════════════════ class InputMethodService(AbstractInputMethodService): """InputMethodService — 输入法服务""" SHOW_EXPLICIT = 0x0001 SHOW_IMPLICIT = 0x0002 def __init__(self): super().__init__() self._input_view: Optional[Any] = None self._candidates_view: Optional[Any] = None self._input_connection: Optional[Any] = None self._input_editor_info: Optional["EditorInfo"] = None self._input_binding: Optional["InputBinding"] = None self._input_view_shown: bool = False self._fullscreen_mode: bool = False self._extract_to_fullscreen_mode: bool = False self._is_fullscreen: bool = False self._keyboard: Optional["Keyboard"] = None self._settings_observer: Any = None self._candidates_view_shown: bool = False self._show_input_requested: bool = False self._token: Any = None self._window_visible: bool = False self._input_started: bool = False def onCreate(self): """创建服务""" sys.stderr.write("[InputMethodService] onCreate\n") def onCreateInputView(self) -> Optional[Any]: """创建输入视图""" return None def onCreateCandidatesView(self) -> Optional[Any]: """创建候选视图""" return None def onStartInputView(self, info: "EditorInfo", restarting: bool): """开始输入视图""" pass def onFinishInputView(self, finishing_input: bool): """结束输入视图""" pass def onStartInput(self, attribute: "EditorInfo", restarting: bool): """开始输入""" self._input_editor_info = attribute self._input_started = True def onFinishInput(self): """结束输入""" self._input_started = False def onBindInput(self, binding: "InputBinding"): """绑定输入""" self._input_binding = binding def onUnbindInput(self) -> bool: """解绑输入""" self._input_binding = None return False def onDestroy(self): """销毁""" self._input_view = None self._candidates_view = None self._input_connection = None def showWindow(self, show_flags: int): """显示窗口""" self._window_visible = True sys.stderr.write(f"[InputMethodService] showWindow: flags={show_flags}\n") def hideWindow(self): """隐藏窗口""" self._window_visible = False def setInputView(self, view: Any): """设置输入视图""" self._input_view = view def setCandidatesView(self, view: Any): """设置候选视图""" self._candidates_view = view def updateInputViewShown(self): """更新输入视图显示状态""" pass def updateFullscreenMode(self): """更新全屏模式""" pass def updateExtractToFullscreenMode(self): """更新提取全屏模式""" pass def requestHideSelf(self, flags: int): """请求隐藏自身""" sys.stderr.write(f"[InputMethodService] requestHideSelf: flags={flags}\n") def switchInputMethod(self, id: str): """切换输入法""" sys.stderr.write(f"[InputMethodService] switchInputMethod: id={id}\n") def sendDefaultEditorAction(self, from_enter_key: bool): """发送默认编辑器动作""" pass def sendDownUpKeyEvents(self, key_event_code: int): """发送按键按下和释放事件""" pass def getCurrentInputBinding(self) -> Optional["InputBinding"]: """获取当前输入绑定""" return self._input_binding def getCurrentInputEditorInfo(self) -> Optional["EditorInfo"]: """获取当前编辑器信息""" return self._input_editor_info def getCurrentInputConnection(self) -> Optional["InputConnection"]: """获取当前输入连接""" return self._input_connection def getTextForImeAction(self, ime_options: int) -> str: """获取IME动作的文本""" action_map = { 0x0001: "None", 0x0002: "Go", 0x0003: "Search", 0x0004: "Send", 0x0005: "Next", 0x0006: "Done", 0x0007: "Previous", } action = ime_options & 0x000000FF return action_map.get(action, "Unknown") def doStartInput(self, input_connection: Any, editor_info: "EditorInfo", restarting: bool): """执行启动输入""" self._input_connection = input_connection self._input_editor_info = editor_info self.onStartInput(editor_info, restarting) if self._window_visible: self.onStartInputView(editor_info, restarting) def doFinishInput(self): """执行结束输入""" self.onFinishInput() self.onFinishInputView(True) def onEvaluateInputViewShown(self) -> bool: """评估是否显示输入视图""" return self._input_view is not None def onEvaluateFullscreenMode(self) -> bool: """评估是否全屏模式""" return self._fullscreen_mode def onConfigureWindow(self, win: Any, is_fullscreen: bool, is_candidates: bool): """配置窗口""" pass def isInputViewShown(self) -> bool: """输入视图是否已显示""" return self._input_view_shown def updateWindow(self, show_input: bool = False): """更新窗口""" pass def setExtractView(self, view: Any): """设置提取视图""" pass def getExtractView(self) -> Optional[Any]: """获取提取视图""" return None def getInputView(self) -> Optional[Any]: """获取输入视图""" return self._input_view def getCandidatesView(self) -> Optional[Any]: """获取候选视图""" return self._candidates_view def isFullscreenMode(self) -> bool: """是否全屏模式""" return self._is_fullscreen def onDisplayCompletions(self, completions: List["CompletionInfo"]): """显示补全""" pass def onUpdateSelection(self, old_sel_start: int, old_sel_end: int, new_sel_start: int, new_sel_end: int, candidates_start: int, candidates_end: int): """更新选区""" pass def onViewClicked(self, focus_changed: bool): """视图点击""" pass def onWindowShown(self): """窗口显示""" self._window_visible = True def onWindowHidden(self): """窗口隐藏""" self._window_visible = False def setKeyboard(self, keyboard: "Keyboard"): """设置键盘""" self._keyboard = keyboard def getKeyboard(self) -> Optional["Keyboard"]: """获取键盘""" return self._keyboard # ═══════════════════════════════════════════════════════════════ # Key # ═══════════════════════════════════════════════════════════════ class Key(Stub): """Key — 键盘按键""" def __init__(self, row: "KeyboardRow" = None): super().__init__() self.codes: List[int] = [] self.label: Optional[str] = None self.icon: Any = None self.sticky: bool = False self.modifier: bool = False self.repeatable: bool = False self.edgeFlags: int = 0 self.popupCharacters: Optional[str] = None self.popupResId: int = 0 self._x: int = 0 self._y: int = 0 self._width: int = 0 self._height: int = 0 self._gap: int = 0 self._row: Optional["KeyboardRow"] = row self._pressed: bool = False self._on: bool = False def getCode(self) -> int: """获取按键码""" return self.codes[0] if self.codes else 0 def isPressed(self) -> bool: """是否按下""" return self._pressed def setPressed(self, pressed: bool): """设置按下状态""" self._pressed = pressed def isOn(self) -> bool: """是否开启""" return self._on def setOn(self, on_state: bool): """设置开启状态""" self._on = on_state def squaredDistance(self, x: int, y: int) -> int: """计算距离平方""" center_x = self._x + self._width // 2 center_y = self._y + self._height // 2 return (x - center_x) ** 2 + (y - center_y) ** 2 def hitTest(self, x: int, y: int) -> bool: """命中测试""" return (self._x <= x <= self._x + self._width and self._y <= y <= self._y + self._height) def getX(self) -> int: return self._x def getY(self) -> int: return self._y def getWidth(self) -> int: return self._width def getHeight(self) -> int: return self._height def toString(self) -> str: return f"Key(code={self.getCode()}, label={self.label})" # ═══════════════════════════════════════════════════════════════ # KeyboardRow # ═══════════════════════════════════════════════════════════════ class KeyboardRow(Stub): """KeyboardRow — 键盘行""" def __init__(self, keyboard: "Keyboard" = None): super().__init__() self._keys: List[Key] = [] self._keyboard: Optional["Keyboard"] = keyboard self._default_width: int = 0 self._default_height: int = 0 self._row_edge_flags: int = 0 self._mode: str = "" def getKeys(self) -> List[Key]: return list(self._keys) def addKey(self, key: Key): self._keys.append(key) def getKeyboard(self) -> Optional["Keyboard"]: return self._keyboard def getDefaultWidth(self) -> int: return self._default_width def getDefaultHeight(self) -> int: return self._default_height def toString(self) -> str: return f"KeyboardRow(keys={len(self._keys)})" # ═══════════════════════════════════════════════════════════════ # Keyboard # ═══════════════════════════════════════════════════════════════ class Keyboard(Stub): """Keyboard — 键盘布局""" def __init__(self, context: Any = None, xml_layout_res_id: int = 0): super().__init__() self._keys: List[Key] = [] self._rows: List[KeyboardRow] = [] self._modifier_keys: List[Key] = [] self._height: int = 0 self._min_width: int = 0 self._key_width: int = 0 self._key_height: int = 0 self._horizontal_gap: int = 0 self._vertical_gap: int = 0 self._shift_keys: List[Key] = [] self._alt_keys: List[Key] = [] def getKeys(self) -> List[Key]: return list(self._keys) def getHeight(self) -> int: return self._height def getMinWidth(self) -> int: return self._min_width def getKeyWidth(self) -> int: return self._key_width def getKeyHeight(self) -> int: return self._key_height def getHorizontalGap(self) -> int: return self._horizontal_gap def getVerticalGap(self) -> int: return self._vertical_gap def getModifierKeys(self) -> List[Key]: return list(self._modifier_keys) def getNearestKeys(self, x: int, y: int) -> List[Key]: """获取最近的按键""" nearest: List[Key] = [] for key in self._keys: if key.hitTest(x, y): nearest.append(key) return nearest def setKeys(self, keys: List[Key]): """设置按键列表""" self._keys = keys def getRows(self) -> List[KeyboardRow]: return list(self._rows) def setShifted(self, shift_state: bool): """设置Shift状态""" pass def isShifted(self) -> bool: """是否Shift状态""" return False def getShiftKeyIndex(self) -> int: """获取Shift按键索引""" for i, key in enumerate(self._keys): if key.modifier: return i return -1 def setVerticalGap(self, gap: int): self._vertical_gap = gap def setHorizontalGap(self, gap: int): self._horizontal_gap = gap def setKeyWidth(self, width: int): self._key_width = width def setKeyHeight(self, height: int): self._key_height = height def toString(self) -> str: return f"Keyboard(keys={len(self._keys)}, rows={len(self._rows)})" # ═══════════════════════════════════════════════════════════════ # KeyboardView # ═══════════════════════════════════════════════════════════════ class KeyboardView(Stub): """KeyboardView — 键盘视图""" class OnKeyboardActionListener(Stub): """OnKeyboardActionListener — 键盘动作监听器""" def onKey(self, primary_code: int): pass def onPress(self, primary_code: int): pass def onRelease(self, primary_code: int): pass def onText(self, text: str): pass def swipeLeft(self): pass def swipeRight(self): pass def swipeDown(self): pass def swipeUp(self): pass def __init__(self, context: Any = None, attrs: Any = None): super().__init__() self._keyboard: Optional[Keyboard] = None self._on_keyboard_action_listener: Optional["KeyboardView.OnKeyboardActionListener"] = None self._preview_enabled: bool = True self._proximity_correction_enabled: bool = True self._vertical_correction: int = 0 self._key_text_color: int = 0xFF000000 self._key_text_size: int = 20 self._shadow_color: int = 0x00000000 self._shadow_radius: float = 0.0 self._background_color: int = 0xFF888888 def setKeyboard(self, keyboard: Keyboard): self._keyboard = keyboard def getKeyboard(self) -> Optional[Keyboard]: return self._keyboard def onDraw(self, canvas: Any): """绘制键盘""" pass def setOnKeyboardActionListener(self, listener: "KeyboardView.OnKeyboardActionListener"): self._on_keyboard_action_listener = listener def getOnKeyboardActionListener(self) -> Optional["KeyboardView.OnKeyboardActionListener"]: return self._on_keyboard_action_listener def setPreviewEnabled(self, preview_enabled: bool): self._preview_enabled = preview_enabled def isPreviewEnabled(self) -> bool: return self._preview_enabled def setProximityCorrectionEnabled(self, enabled: bool): self._proximity_correction_enabled = enabled def isProximityCorrectionEnabled(self) -> bool: return self._proximity_correction_enabled def setVerticalCorrection(self, vertical_correction: int): self._vertical_correction = vertical_correction def getVerticalCorrection(self) -> int: return self._vertical_correction def setKeyTextColor(self, color: int): self._key_text_color = color def setKeyTextSize(self, size: int): self._key_text_size = size def setShadowColor(self, color: int): self._shadow_color = color def setShadowRadius(self, radius: float): self._shadow_radius = radius def setBackgroundColor(self, color: int): self._background_color = color def invalidateAllKeys(self): """使所有按键失效""" pass def invalidateKey(self, key_index: int): """使指定按键失效""" pass def onClick(self, key: Key): """点击按键""" if self._on_keyboard_action_listener and key.codes: self._on_keyboard_action_listener.onKey(key.codes[0]) def onLongPress(self, key: Key) -> bool: """长按按键""" if key.popupCharacters: return True return False def closing(self): """关闭""" pass def handleBack(self) -> bool: """处理返回键""" return False def setKeys(self, keys: List[Key]): """设置按键""" if self._keyboard: self._keyboard.setKeys(keys) # ═══════════════════════════════════════════════════════════════ # KeyEventCallback # ═══════════════════════════════════════════════════════════════ class KeyEventCallback(Stub): """KeyEventCallback — 按键事件回调""" def onKeyDown(self, key_code: int, event: Any) -> bool: """按键按下""" return False def onKeyLongPress(self, key_code: int, event: Any) -> bool: """按键长按""" return False def onKeyUp(self, key_code: int, event: Any) -> bool: """按键释放""" return False def onKeyMultiple(self, key_code: int, count: int, event: Any) -> bool: """按键重复""" return False # ═══════════════════════════════════════════════════════════════ # __all__ # ═══════════════════════════════════════════════════════════════ __all__ = [ "InputMethodService", "InputMethodImpl", "InputMethodSessionImpl", "AbstractInputMethodService", "InputMethod", "InputMethodSession", "Keyboard", "KeyboardView", "Key", "KeyEventCallback", "KeyboardRow", ]