859 lines
32 KiB
Python
859 lines
32 KiB
Python
"""
|
|
Android View InputMethod 组件 — InputMethodManager, EditorInfo,
|
|
InputConnection, ExtractedText 等
|
|
方法签名完全对齐 Android SDK
|
|
"""
|
|
|
|
import sys
|
|
from typing import Any, Dict, List, Optional, Tuple
|
|
|
|
from .._core import Stub, AndroidOnlyError, android_context
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# InputMethodManager
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class InputMethodManager(Stub):
|
|
"""InputMethodManager — 输入法管理器"""
|
|
|
|
SHOW_IMPLICIT = 0x0001
|
|
SHOW_FORCED = 0x0002
|
|
HIDE_IMPLICIT_ONLY = 0x0001
|
|
HIDE_NOT_ALWAYS = 0x0002
|
|
RESULT_SHOWN = 2
|
|
RESULT_HIDDEN = 3
|
|
RESULT_UNCHANGED_SHOWN = 4
|
|
RESULT_UNCHANGED_HIDDEN = 5
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._active: bool = False
|
|
self._current_input_connection: Optional["InputConnection"] = None
|
|
self._is_accepting_text: bool = True
|
|
self._fullscreen_mode: bool = False
|
|
self._cursor_x: int = 0
|
|
self._cursor_y: int = 0
|
|
self._selection_start: int = -1
|
|
self._selection_end: int = -1
|
|
self._composing_start: int = -1
|
|
self._composing_end: int = -1
|
|
|
|
def showSoftInput(self, view: Any, flags: int,
|
|
result_receiver: Any = None) -> bool:
|
|
self._active = True
|
|
sys.stderr.write(f"[InputMethodManager] showSoftInput: flags={flags}\n")
|
|
return True
|
|
|
|
def hideSoftInputFromWindow(self, window_token: Any, flags: int,
|
|
result_receiver: Any = None) -> bool:
|
|
self._active = False
|
|
sys.stderr.write(f"[InputMethodManager] hideSoftInputFromWindow: flags={flags}\n")
|
|
return True
|
|
|
|
def toggleSoftInput(self, show_flags: int, hide_flags: int):
|
|
self._active = not self._active
|
|
sys.stderr.write(f"[InputMethodManager] toggleSoftInput: "
|
|
f"show={show_flags}, hide={hide_flags}\n")
|
|
|
|
def restartInput(self, view: Any):
|
|
sys.stderr.write("[InputMethodManager] restartInput\n")
|
|
|
|
def startInput(self, view: Any) -> bool:
|
|
sys.stderr.write("[InputMethodManager] startInput\n")
|
|
return True
|
|
|
|
def updateSelection(self, view: Any, sel_start: int, sel_end: int,
|
|
composing_start: int, composing_end: int):
|
|
self._selection_start = sel_start
|
|
self._selection_end = sel_end
|
|
self._composing_start = composing_start
|
|
self._composing_end = composing_end
|
|
|
|
def updateCursorAnchorInfo(self, view: Any, cursor_anchor_info: "CursorAnchorInfo"):
|
|
self._cursor_x = cursor_anchor_info.getInsertionMarkerBaseline()
|
|
self._cursor_y = cursor_anchor_info.getInsertionMarkerTop()
|
|
|
|
def displayCompletions(self, view: Any, completions: List["CompletionInfo"]):
|
|
sys.stderr.write(f"[InputMethodManager] displayCompletions: "
|
|
f"{len(completions) if completions else 0} items\n")
|
|
|
|
def sendKeyChar(self, key_char: str):
|
|
sys.stderr.write(f"[InputMethodManager] sendKeyChar: '{key_char}'\n")
|
|
|
|
def clearMetaKeyStates(self, view: Any, states: int):
|
|
sys.stderr.write(f"[InputMethodManager] clearMetaKeyStates: {states}\n")
|
|
|
|
def isAcceptingText(self) -> bool:
|
|
return self._is_accepting_text
|
|
|
|
def isActive(self) -> bool:
|
|
return self._active
|
|
|
|
def isFullscreenMode(self) -> bool:
|
|
return self._fullscreen_mode
|
|
|
|
def setFullscreenMode(self, fullscreen: bool):
|
|
self._fullscreen_mode = fullscreen
|
|
|
|
def getCurrentInputMethodSubtype(self) -> Optional["InputMethodSubtype"]:
|
|
return None
|
|
|
|
def getShortcutInputMethodsAndSubtypes(self) -> List[Any]:
|
|
return []
|
|
|
|
def showStatusIcon(self, icon: Any):
|
|
pass
|
|
|
|
def hideStatusIcon(self):
|
|
pass
|
|
|
|
def registerSuggestionSpansForNotification(self, spans: List[Any], sender: Any):
|
|
pass
|
|
|
|
def notifySuggestionPicked(self, suggestion: Any):
|
|
pass
|
|
|
|
def windowDismissed(self, window_token: Any):
|
|
self._active = False
|
|
|
|
def toString(self) -> str:
|
|
return f"InputMethodManager(active={self._active})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# EditorInfo
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class EditorInfo(Stub):
|
|
"""EditorInfo — 编辑器信息"""
|
|
|
|
TYPE_CLASS_TEXT = 0x0001
|
|
TYPE_CLASS_NUMBER = 0x0002
|
|
TYPE_CLASS_PHONE = 0x0004
|
|
TYPE_CLASS_DATETIME = 0x0008
|
|
|
|
TYPE_TEXT_VARIATION_NORMAL = 0x0000
|
|
TYPE_TEXT_VARIATION_URI = 0x0010
|
|
TYPE_TEXT_VARIATION_EMAIL_ADDRESS = 0x0020
|
|
TYPE_TEXT_VARIATION_EMAIL_SUBJECT = 0x0030
|
|
TYPE_TEXT_VARIATION_SHORT_MESSAGE = 0x0040
|
|
TYPE_TEXT_VARIATION_LONG_MESSAGE = 0x0050
|
|
TYPE_TEXT_VARIATION_PERSON_NAME = 0x0060
|
|
TYPE_TEXT_VARIATION_POSTAL_ADDRESS = 0x0070
|
|
TYPE_TEXT_VARIATION_PASSWORD = 0x0080
|
|
TYPE_TEXT_VARIATION_VISIBLE_PASSWORD = 0x0090
|
|
TYPE_TEXT_VARIATION_WEB_EDIT_TEXT = 0x00A0
|
|
TYPE_TEXT_VARIATION_FILTER = 0x00B0
|
|
TYPE_TEXT_VARIATION_PHONETIC = 0x00C0
|
|
TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS = 0x00D0
|
|
TYPE_TEXT_VARIATION_WEB_PASSWORD = 0x00E0
|
|
|
|
TYPE_NUMBER_VARIATION_NORMAL = 0x0000
|
|
TYPE_NUMBER_VARIATION_PASSWORD = 0x0010
|
|
|
|
TYPE_DATETIME_VARIATION_NORMAL = 0x0000
|
|
TYPE_DATETIME_VARIATION_DATE = 0x0010
|
|
TYPE_DATETIME_VARIATION_TIME = 0x0020
|
|
|
|
TYPE_NULL = 0x0000
|
|
|
|
IME_ACTION_NONE = 0x0001
|
|
IME_ACTION_GO = 0x0002
|
|
IME_ACTION_SEARCH = 0x0003
|
|
IME_ACTION_SEND = 0x0004
|
|
IME_ACTION_NEXT = 0x0005
|
|
IME_ACTION_DONE = 0x0006
|
|
IME_ACTION_PREVIOUS = 0x0007
|
|
|
|
IME_FLAG_NO_EXTRACT_UI = 0x10000001
|
|
IME_FLAG_NO_ACCESSORY_ACTION = 0x20000000
|
|
IME_FLAG_NO_ENTER_ACTION = 0x40000000
|
|
IME_FLAG_NAVIGATE_NEXT = 0x08000000
|
|
IME_FLAG_NAVIGATE_PREVIOUS = 0x04000000
|
|
IME_FLAG_NO_FULLSCREEN = 0x02000000
|
|
IME_FLAG_FORCE_ASCII = 0x80000000
|
|
|
|
IME_MASK_ACTION = 0x000000FF
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.inputType: int = EditorInfo.TYPE_CLASS_TEXT
|
|
self.imeOptions: int = EditorInfo.IME_ACTION_NONE
|
|
self.actionLabel: Optional[str] = None
|
|
self.actionId: int = 0
|
|
self.initialSelStart: int = -1
|
|
self.initialSelEnd: int = -1
|
|
self.initialCapsMode: int = 0
|
|
self.hintText: Optional[str] = None
|
|
self.label: Optional[str] = None
|
|
self.packageName: Optional[str] = None
|
|
self.fieldId: int = 0
|
|
self.fieldName: Optional[str] = None
|
|
self.extras: Optional[Any] = None
|
|
|
|
def toString(self) -> str:
|
|
return (f"EditorInfo(inputType={hex(self.inputType)}, "
|
|
f"imeOptions={hex(self.imeOptions)}, "
|
|
f"actionLabel={self.actionLabel})")
|
|
|
|
def dump(self, printer: Any, prefix: str):
|
|
sys.stderr.write(f"{prefix}EditorInfo: inputType={hex(self.inputType)}\n")
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# InputConnection
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class InputConnection(Stub):
|
|
"""InputConnection — 输入连接接口"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._text: str = ""
|
|
self._selection_start: int = 0
|
|
self._selection_end: int = 0
|
|
self._composing_start: int = -1
|
|
self._composing_end: int = -1
|
|
self._batch_edit_count: int = 0
|
|
|
|
def getTextBeforeCursor(self, length: int, flags: int) -> Optional[str]:
|
|
end = self._selection_start
|
|
start = max(0, end - length)
|
|
return self._text[start:end]
|
|
|
|
def getTextAfterCursor(self, length: int, flags: int) -> Optional[str]:
|
|
start = self._selection_end
|
|
end = min(len(self._text), start + length)
|
|
return self._text[start:end]
|
|
|
|
def getExtractedText(self, request: "ExtractedTextRequest",
|
|
flags: int) -> Optional["ExtractedText"]:
|
|
result = ExtractedText()
|
|
result.text = self._text
|
|
result.startOffset = 0
|
|
result.selectionStart = self._selection_start
|
|
result.selectionEnd = self._selection_end
|
|
result.flags = 0
|
|
return result
|
|
|
|
def commitText(self, text: Any, new_cursor_position: int) -> bool:
|
|
if isinstance(text, str):
|
|
committed = text
|
|
else:
|
|
committed = str(text) if text else ""
|
|
|
|
before = self._text[:self._selection_start]
|
|
after = self._text[self._selection_end:]
|
|
self._text = before + committed + after
|
|
|
|
if new_cursor_position > 0:
|
|
self._selection_start = len(before) + new_cursor_position - 1
|
|
else:
|
|
self._selection_start = len(before) + len(committed) + new_cursor_position
|
|
self._selection_end = self._selection_start
|
|
self._composing_start = -1
|
|
self._composing_end = -1
|
|
return True
|
|
|
|
def setComposingText(self, text: Any, new_cursor_position: int) -> bool:
|
|
if self._composing_start < 0:
|
|
self._composing_start = self._selection_start
|
|
self._composing_end = self._selection_end
|
|
|
|
before = self._text[:self._composing_start]
|
|
after = self._text[self._composing_end:]
|
|
|
|
if isinstance(text, str):
|
|
composing = text
|
|
else:
|
|
composing = str(text) if text else ""
|
|
|
|
self._text = before + composing + after
|
|
self._composing_end = self._composing_start + len(composing)
|
|
self._selection_start = self._composing_end + new_cursor_position
|
|
self._selection_end = self._selection_start
|
|
return True
|
|
|
|
def setSelection(self, start: int, end: int) -> bool:
|
|
self._selection_start = max(0, min(start, len(self._text)))
|
|
self._selection_end = max(0, min(end, len(self._text)))
|
|
return True
|
|
|
|
def deleteSurroundingText(self, before_length: int, after_length: int) -> bool:
|
|
start = max(0, self._selection_start - before_length)
|
|
end = min(len(self._text), self._selection_end + after_length)
|
|
self._text = self._text[:start] + self._text[end:]
|
|
new_cursor = max(0, self._selection_start - before_length)
|
|
self._selection_start = new_cursor
|
|
self._selection_end = new_cursor
|
|
return True
|
|
|
|
def commitCompletion(self, completion: "CompletionInfo") -> bool:
|
|
sys.stderr.write(f"[InputConnection] commitCompletion: "
|
|
f"{completion.getText()}\n")
|
|
return True
|
|
|
|
def commitCorrection(self, correction: "CorrectionInfo") -> bool:
|
|
sys.stderr.write(f"[InputConnection] commitCorrection: "
|
|
f"{correction.getNewText()}\n")
|
|
return True
|
|
|
|
def getSelectedText(self, flags: int) -> Optional[str]:
|
|
if self._selection_start == self._selection_end:
|
|
return ""
|
|
return self._text[self._selection_start:self._selection_end]
|
|
|
|
def finishComposingText(self) -> bool:
|
|
self._composing_start = -1
|
|
self._composing_end = -1
|
|
return True
|
|
|
|
def beginBatchEdit(self) -> bool:
|
|
self._batch_edit_count += 1
|
|
return True
|
|
|
|
def endBatchEdit(self) -> bool:
|
|
if self._batch_edit_count > 0:
|
|
self._batch_edit_count -= 1
|
|
return True
|
|
|
|
def sendKeyEvent(self, event: Any) -> bool:
|
|
sys.stderr.write(f"[InputConnection] sendKeyEvent\n")
|
|
return True
|
|
|
|
def clearMetaKeyStates(self, states: int) -> bool:
|
|
return True
|
|
|
|
def performEditorAction(self, action_code: int) -> bool:
|
|
sys.stderr.write(f"[InputConnection] performEditorAction: {action_code}\n")
|
|
return True
|
|
|
|
def performContextMenuAction(self, id: int) -> bool:
|
|
sys.stderr.write(f"[InputConnection] performContextMenuAction: {id}\n")
|
|
return True
|
|
|
|
def commitContent(self, input_content: "InputContentInfo",
|
|
flags: int, opts: Optional[Any] = None) -> bool:
|
|
sys.stderr.write("[InputConnection] commitContent\n")
|
|
return True
|
|
|
|
def requestCursorUpdates(self, cursor_update_mode: int) -> bool:
|
|
return True
|
|
|
|
def closeConnection(self):
|
|
pass
|
|
|
|
def reportFullscreenMode(self, enabled: bool):
|
|
pass
|
|
|
|
def getSurroundingText(self, before_length: int, after_length: int,
|
|
flags: int) -> Optional["SurroundingText"]:
|
|
start = max(0, self._selection_start - before_length)
|
|
end = min(len(self._text), self._selection_end + after_length)
|
|
return SurroundingText(
|
|
text=self._text[start:end],
|
|
selection_start=self._selection_start - start,
|
|
selection_end=self._selection_end - start,
|
|
offset=start,
|
|
)
|
|
|
|
def takeSnapshot(self) -> Optional[Any]:
|
|
"""获取输入快照"""
|
|
return None
|
|
|
|
def setComposingRegion(self, start: int, end: int) -> bool:
|
|
self._composing_start = start
|
|
self._composing_end = end
|
|
return True
|
|
|
|
def getCursorCapsMode(self, req_modes: int) -> int:
|
|
return 0
|
|
|
|
def getTextBeforeCursor(self, length: int, flags: int) -> Optional[str]:
|
|
end = self._selection_start
|
|
start = max(0, end - length)
|
|
return self._text[start:end]
|
|
|
|
def getTextAfterCursor(self, length: int, flags: int) -> Optional[str]:
|
|
start = self._selection_end
|
|
end = min(len(self._text), start + length)
|
|
return self._text[start:end]
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# ExtractedText
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class ExtractedText(Stub):
|
|
"""ExtractedText — 提取的文本"""
|
|
|
|
FLAG_SINGLE_LINE = 0x0001
|
|
FLAG_SELECTING = 0x0002
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.text: Optional[str] = None
|
|
self.startOffset: int = 0
|
|
self.partialStartOffset: int = -1
|
|
self.partialEndOffset: int = -1
|
|
self.selectionStart: int = -1
|
|
self.selectionEnd: int = -1
|
|
self.flags: int = 0
|
|
|
|
def toString(self) -> str:
|
|
return (f"ExtractedText(startOffset={self.startOffset}, "
|
|
f"text={self.text}, "
|
|
f"selection=({self.selectionStart}, {self.selectionEnd}))")
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# ExtractedTextRequest
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class ExtractedTextRequest(Stub):
|
|
"""ExtractedTextRequest — 提取文本请求"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.token: int = 0
|
|
self.flags: int = 0
|
|
self.hintMaxLines: int = 0
|
|
self.hintMaxChars: int = 0
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# InputBinding
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class InputBinding(Stub):
|
|
"""InputBinding — 输入绑定"""
|
|
|
|
def __init__(self, connection: Optional["InputConnection"] = None,
|
|
uid: int = -1, pid: int = -1,
|
|
private_ime_options: str = ""):
|
|
super().__init__()
|
|
self._connection: Optional["InputConnection"] = connection
|
|
self._uid: int = uid
|
|
self._pid: int = pid
|
|
self._private_ime_options: str = private_ime_options
|
|
|
|
def getConnection(self) -> Optional["InputConnection"]:
|
|
return self._connection
|
|
|
|
def getUid(self) -> int:
|
|
return self._uid
|
|
|
|
def getPid(self) -> int:
|
|
return self._pid
|
|
|
|
def getPrivateImeOptions(self) -> str:
|
|
return self._private_ime_options
|
|
|
|
def toString(self) -> str:
|
|
return (f"InputBinding(uid={self._uid}, pid={self._pid}, "
|
|
f"connection={self._connection})")
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# InputMethodSubtype
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class InputMethodSubtype(Stub):
|
|
"""InputMethodSubtype — 输入法子类型"""
|
|
|
|
SUBTYPE_ID_NONE = -1
|
|
|
|
def __init__(self, locale: str = "", mode: str = "",
|
|
extra_value: str = "", is_auxiliary: bool = False,
|
|
overrides_ime_theme: bool = False,
|
|
subtype_id: int = SUBTYPE_ID_NONE):
|
|
super().__init__()
|
|
self._locale: str = locale
|
|
self._mode: str = mode
|
|
self._extra_value: str = extra_value
|
|
self._is_auxiliary: bool = is_auxiliary
|
|
self._overrides_ime_theme: bool = overrides_ime_theme
|
|
self._subtype_id: int = subtype_id
|
|
self._display_name_res: int = 0
|
|
self._icon_res: int = 0
|
|
|
|
def getLocale(self) -> str:
|
|
return self._locale
|
|
|
|
def getMode(self) -> str:
|
|
return self._mode
|
|
|
|
def getExtraValue(self) -> str:
|
|
return self._extra_value
|
|
|
|
def getSubtypeId(self) -> int:
|
|
return self._subtype_id
|
|
|
|
def containsExtraValueKey(self, key: str) -> bool:
|
|
if not self._extra_value:
|
|
return False
|
|
pairs = self._extra_value.split(",")
|
|
for pair in pairs:
|
|
kv = pair.split("=", 1)
|
|
if len(kv) == 2 and kv[0].strip() == key:
|
|
return True
|
|
return False
|
|
|
|
def getDisplayName(self, context: Any, package_name: str,
|
|
app_info: Any) -> str:
|
|
return self._locale or self._mode
|
|
|
|
def isAuxiliary(self) -> bool:
|
|
return self._is_auxiliary
|
|
|
|
def overridesImeTheme(self) -> bool:
|
|
return self._overrides_ime_theme
|
|
|
|
def hashCode(self) -> int:
|
|
return hash((self._locale, self._mode, self._extra_value)) & 0x7FFFFFFF
|
|
|
|
def equals(self, other: Any) -> bool:
|
|
if isinstance(other, InputMethodSubtype):
|
|
return (self._locale == other._locale and
|
|
self._mode == other._mode and
|
|
self._extra_value == other._extra_value)
|
|
return False
|
|
|
|
def toString(self) -> str:
|
|
return (f"InputMethodSubtype(locale={self._locale}, "
|
|
f"mode={self._mode})")
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CursorAnchorInfo
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CursorAnchorInfo(Stub):
|
|
"""CursorAnchorInfo — 光标锚点信息"""
|
|
|
|
FLAG_HAS_VISIBLE_REGION = 0x01
|
|
FLAG_IS_RTL = 0x02
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._insertion_marker_baseline: float = 0.0
|
|
self._insertion_marker_top: float = 0.0
|
|
self._insertion_marker_bottom: float = 0.0
|
|
self._matrix: Optional[Any] = None
|
|
self._character_bounds: Dict[int, Tuple[float, float, float, float]] = {}
|
|
self._character_bounds_flags: Dict[int, int] = {}
|
|
self._composing_text: Optional[str] = None
|
|
self._composing_text_start: int = -1
|
|
|
|
def getInsertionMarkerBaseline(self) -> float:
|
|
return self._insertion_marker_baseline
|
|
|
|
def setInsertionMarkerBaseline(self, baseline: float):
|
|
self._insertion_marker_baseline = baseline
|
|
|
|
def getInsertionMarkerTop(self) -> float:
|
|
return self._insertion_marker_top
|
|
|
|
def setInsertionMarkerTop(self, top: float):
|
|
self._insertion_marker_top = top
|
|
|
|
def getInsertionMarkerBottom(self) -> float:
|
|
return self._insertion_marker_bottom
|
|
|
|
def setInsertionMarkerBottom(self, bottom: float):
|
|
self._insertion_marker_bottom = bottom
|
|
|
|
def getMatrix(self) -> Optional[Any]:
|
|
return self._matrix
|
|
|
|
def setMatrix(self, matrix: Any):
|
|
self._matrix = matrix
|
|
|
|
def getCharacterBounds(self, index: int) -> Optional[Tuple[float, float, float, float]]:
|
|
return self._character_bounds.get(index)
|
|
|
|
def setCharacterBounds(self, index: int, left: float, top: float,
|
|
right: float, bottom: float, flags: int):
|
|
self._character_bounds[index] = (left, top, right, bottom)
|
|
self._character_bounds_flags[index] = flags
|
|
|
|
def getCharacterBoundsFlags(self, index: int) -> int:
|
|
return self._character_bounds_flags.get(index, 0)
|
|
|
|
def getComposingText(self) -> Optional[str]:
|
|
return self._composing_text
|
|
|
|
def getComposingTextStart(self) -> int:
|
|
return self._composing_text_start
|
|
|
|
def toString(self) -> str:
|
|
return (f"CursorAnchorInfo(baseline={self._insertion_marker_baseline}, "
|
|
f"top={self._insertion_marker_top})")
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CorrectionInfo
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CorrectionInfo(Stub):
|
|
"""CorrectionInfo — 校正信息"""
|
|
|
|
def __init__(self, old_text: str = "", new_text: str = ""):
|
|
super().__init__()
|
|
self._old_text: str = old_text
|
|
self._new_text: str = new_text
|
|
|
|
def getOldText(self) -> str:
|
|
return self._old_text
|
|
|
|
def getNewText(self) -> str:
|
|
return self._new_text
|
|
|
|
def toString(self) -> str:
|
|
return f"CorrectionInfo('{self._old_text}' -> '{self._new_text}')"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CompletionInfo
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CompletionInfo(Stub):
|
|
"""CompletionInfo — 补全信息"""
|
|
|
|
def __init__(self, id: int = 0, position: int = 0,
|
|
text: str = "", label: str = ""):
|
|
super().__init__()
|
|
self._id: int = id
|
|
self._position: int = position
|
|
self._text: str = text
|
|
self._label: str = label
|
|
|
|
def getId(self) -> int:
|
|
return self._id
|
|
|
|
def getPosition(self) -> int:
|
|
return self._position
|
|
|
|
def getText(self) -> str:
|
|
return self._text
|
|
|
|
def getLabel(self) -> str:
|
|
return self._label
|
|
|
|
def toString(self) -> str:
|
|
return f"CompletionInfo(id={self._id}, text='{self._text}')"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# SurroundingText
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class SurroundingText(Stub):
|
|
"""SurroundingText — 周围文本"""
|
|
|
|
def __init__(self, text: str = "", selection_start: int = 0,
|
|
selection_end: int = 0, offset: int = 0):
|
|
super().__init__()
|
|
self._text: str = text
|
|
self._selection_start: int = selection_start
|
|
self._selection_end: int = selection_end
|
|
self._offset: int = offset
|
|
|
|
def getText(self) -> str:
|
|
return self._text
|
|
|
|
def getSelectionStart(self) -> int:
|
|
return self._selection_start
|
|
|
|
def getSelectionEnd(self) -> int:
|
|
return self._selection_end
|
|
|
|
def getOffset(self) -> int:
|
|
return self._offset
|
|
|
|
def toString(self) -> str:
|
|
return (f"SurroundingText(text='{self._text}', "
|
|
f"selection=({self._selection_start}, {self._selection_end}), "
|
|
f"offset={self._offset})")
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# InputContentInfo
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class InputContentInfo(Stub):
|
|
"""InputContentInfo — 输入内容信息"""
|
|
|
|
def __init__(self, uri: Any = None, description: Any = None,
|
|
link_uri: Any = None):
|
|
super().__init__()
|
|
self._uri: Any = uri
|
|
self._description: Any = description
|
|
self._link_uri: Any = link_uri
|
|
|
|
def getUri(self) -> Any:
|
|
return self._uri
|
|
|
|
def getDescription(self) -> Any:
|
|
return self._description
|
|
|
|
def getLinkUri(self) -> Any:
|
|
return self._link_uri
|
|
|
|
def requestPermission(self):
|
|
pass
|
|
|
|
def releasePermission(self):
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return (f"InputContentInfo(uri={self._uri}, "
|
|
f"description={self._description})")
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# InputConnectionWrapper
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class InputConnectionWrapper(InputConnection):
|
|
"""InputConnectionWrapper — 输入连接包装器"""
|
|
|
|
def __init__(self, target: InputConnection, mutable: bool = True):
|
|
super().__init__()
|
|
self._target: InputConnection = target
|
|
self._mutable: bool = mutable
|
|
|
|
def setTarget(self, target: InputConnection):
|
|
if self._mutable:
|
|
self._target = target
|
|
|
|
def getTarget(self) -> InputConnection:
|
|
return self._target
|
|
|
|
def getTextBeforeCursor(self, length: int, flags: int) -> Optional[str]:
|
|
return self._target.getTextBeforeCursor(length, flags)
|
|
|
|
def getTextAfterCursor(self, length: int, flags: int) -> Optional[str]:
|
|
return self._target.getTextAfterCursor(length, flags)
|
|
|
|
def getSelectedText(self, flags: int) -> Optional[str]:
|
|
return self._target.getSelectedText(flags)
|
|
|
|
def getSurroundingText(self, before_length: int, after_length: int,
|
|
flags: int) -> Optional["SurroundingText"]:
|
|
return self._target.getSurroundingText(before_length, after_length, flags)
|
|
|
|
def getCursorCapsMode(self, req_modes: int) -> int:
|
|
return self._target.getCursorCapsMode(req_modes)
|
|
|
|
def getExtractedText(self, request: "ExtractedTextRequest",
|
|
flags: int) -> Optional["ExtractedText"]:
|
|
return self._target.getExtractedText(request, flags)
|
|
|
|
def commitText(self, text: Any, new_cursor_position: int) -> bool:
|
|
return self._target.commitText(text, new_cursor_position)
|
|
|
|
def commitCompletion(self, completion: "CompletionInfo") -> bool:
|
|
return self._target.commitCompletion(completion)
|
|
|
|
def commitCorrection(self, correction: "CorrectionInfo") -> bool:
|
|
return self._target.commitCorrection(correction)
|
|
|
|
def commitContent(self, input_content: "InputContentInfo",
|
|
flags: int, opts: Optional[Any] = None) -> bool:
|
|
return self._target.commitContent(input_content, flags, opts)
|
|
|
|
def setComposingText(self, text: Any, new_cursor_position: int) -> bool:
|
|
return self._target.setComposingText(text, new_cursor_position)
|
|
|
|
def setComposingRegion(self, start: int, end: int) -> bool:
|
|
return self._target.setComposingRegion(start, end)
|
|
|
|
def finishComposingText(self) -> bool:
|
|
return self._target.finishComposingText()
|
|
|
|
def setSelection(self, start: int, end: int) -> bool:
|
|
return self._target.setSelection(start, end)
|
|
|
|
def performEditorAction(self, action_code: int) -> bool:
|
|
return self._target.performEditorAction(action_code)
|
|
|
|
def performContextMenuAction(self, id: int) -> bool:
|
|
return self._target.performContextMenuAction(id)
|
|
|
|
def beginBatchEdit(self) -> bool:
|
|
return self._target.beginBatchEdit()
|
|
|
|
def endBatchEdit(self) -> bool:
|
|
return self._target.endBatchEdit()
|
|
|
|
def sendKeyEvent(self, event: Any) -> bool:
|
|
return self._target.sendKeyEvent(event)
|
|
|
|
def clearMetaKeyStates(self, states: int) -> bool:
|
|
return self._target.clearMetaKeyStates(states)
|
|
|
|
def deleteSurroundingText(self, before_length: int, after_length: int) -> bool:
|
|
return self._target.deleteSurroundingText(before_length, after_length)
|
|
|
|
def requestCursorUpdates(self, cursor_update_mode: int) -> bool:
|
|
return self._target.requestCursorUpdates(cursor_update_mode)
|
|
|
|
def closeConnection(self):
|
|
self._target.closeConnection()
|
|
|
|
def reportFullscreenMode(self, enabled: bool):
|
|
self._target.reportFullscreenMode(enabled)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# BaseInputConnection
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class BaseInputConnection(InputConnection):
|
|
"""BaseInputConnection — 输入连接基类"""
|
|
|
|
def __init__(self, view: Any, full_editor: bool = True):
|
|
super().__init__()
|
|
self._view = view
|
|
self._full_editor = full_editor
|
|
self._text: str = ""
|
|
self._selection_start: int = 0
|
|
self._selection_end: int = 0
|
|
self._composing_start: int = -1
|
|
self._composing_end: int = -1
|
|
|
|
def getEditable(self) -> Optional[Any]:
|
|
return None
|
|
|
|
def reportFullscreenMode(self, enabled: bool):
|
|
pass
|
|
|
|
def requestCursorUpdates(self, cursor_update_mode: int) -> bool:
|
|
return self._full_editor
|
|
|
|
def closeConnection(self):
|
|
pass
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# __all__
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
__all__ = [
|
|
"InputMethodManager",
|
|
"EditorInfo",
|
|
"InputConnection",
|
|
"ExtractedText",
|
|
"ExtractedTextRequest",
|
|
"InputBinding",
|
|
"InputMethodSubtype",
|
|
"CursorAnchorInfo",
|
|
"CorrectionInfo",
|
|
"CompletionInfo",
|
|
"SurroundingText",
|
|
"InputContentInfo",
|
|
"InputConnectionWrapper",
|
|
"BaseInputConnection",
|
|
] |