- android/ 167个模块 (app/content/os/view/widget/graphics/media/hardware/net/telephony/provider等) - java/ 35个模块 (lang/io/util/net/nio/security/crypto/sql/beans/rmi/awt等) - javax/ 4个模块 (net/crypto/security/sql) - org/ 5个模块 (json/w3c_dom/xml_sax/xml_pull/apache_http) - dalvik/ 1个模块 (system) - ~3053个类/接口,方法签名完全对齐Android SDK - 桌面跨平台运行 (Windows/macOS/Linux) - 修复所有导入错误和Python关键字冲突
1078 lines
30 KiB
Python
1078 lines
30 KiB
Python
"""
|
|
Android InputMethod Service 组件 — InputMethodService, AbstractInputMethodService, Keyboard, Key, KeyboardView 等
|
|
方法签名完全对齐 Android SDK (android.inputmethodservice 包)
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import time
|
|
from typing import Any, Callable, Dict, List, Optional, Set, Tuple
|
|
|
|
from .._core import Stub, AndroidOnlyError
|
|
from ..java.lang import RuntimeException
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# 常量
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
KEYCODE_UNKNOWN = 0
|
|
KEYCODE_SOFT_LEFT = 1
|
|
KEYCODE_SOFT_RIGHT = 2
|
|
KEYCODE_HOME = 3
|
|
KEYCODE_BACK = 4
|
|
KEYCODE_CALL = 5
|
|
KEYCODE_ENDCALL = 6
|
|
KEYCODE_0 = 7
|
|
KEYCODE_1 = 8
|
|
KEYCODE_2 = 9
|
|
KEYCODE_3 = 10
|
|
KEYCODE_4 = 11
|
|
KEYCODE_5 = 12
|
|
KEYCODE_6 = 13
|
|
KEYCODE_7 = 14
|
|
KEYCODE_8 = 15
|
|
KEYCODE_9 = 16
|
|
KEYCODE_STAR = 17
|
|
KEYCODE_POUND = 18
|
|
KEYCODE_DPAD_UP = 19
|
|
KEYCODE_DPAD_DOWN = 20
|
|
KEYCODE_DPAD_LEFT = 21
|
|
KEYCODE_DPAD_RIGHT = 22
|
|
KEYCODE_DPAD_CENTER = 23
|
|
KEYCODE_VOLUME_UP = 24
|
|
KEYCODE_VOLUME_DOWN = 25
|
|
KEYCODE_POWER = 26
|
|
KEYCODE_CAMERA = 27
|
|
KEYCODE_CLEAR = 28
|
|
KEYCODE_A = 29
|
|
KEYCODE_B = 30
|
|
KEYCODE_C = 31
|
|
KEYCODE_D = 32
|
|
KEYCODE_E = 33
|
|
KEYCODE_F = 34
|
|
KEYCODE_G = 35
|
|
KEYCODE_H = 36
|
|
KEYCODE_I = 37
|
|
KEYCODE_J = 38
|
|
KEYCODE_K = 39
|
|
KEYCODE_L = 40
|
|
KEYCODE_M = 41
|
|
KEYCODE_N = 42
|
|
KEYCODE_O = 43
|
|
KEYCODE_P = 44
|
|
KEYCODE_Q = 45
|
|
KEYCODE_R = 46
|
|
KEYCODE_S = 47
|
|
KEYCODE_T = 48
|
|
KEYCODE_U = 49
|
|
KEYCODE_V = 50
|
|
KEYCODE_W = 51
|
|
KEYCODE_X = 52
|
|
KEYCODE_Y = 53
|
|
KEYCODE_Z = 54
|
|
KEYCODE_COMMA = 55
|
|
KEYCODE_PERIOD = 56
|
|
KEYCODE_ALT_LEFT = 57
|
|
KEYCODE_ALT_RIGHT = 58
|
|
KEYCODE_SHIFT_LEFT = 59
|
|
KEYCODE_SHIFT_RIGHT = 60
|
|
KEYCODE_TAB = 61
|
|
KEYCODE_SPACE = 62
|
|
KEYCODE_SYM = 63
|
|
KEYCODE_EXPLORER = 64
|
|
KEYCODE_ENVELOPE = 65
|
|
KEYCODE_ENTER = 66
|
|
KEYCODE_DEL = 67
|
|
KEYCODE_GRAVE = 68
|
|
KEYCODE_MINUS = 69
|
|
KEYCODE_EQUALS = 70
|
|
KEYCODE_LEFT_BRACKET = 71
|
|
KEYCODE_RIGHT_BRACKET = 72
|
|
KEYCODE_BACKSLASH = 73
|
|
KEYCODE_SEMICOLON = 74
|
|
KEYCODE_APOSTROPHE = 75
|
|
KEYCODE_SLASH = 76
|
|
KEYCODE_AT = 77
|
|
KEYCODE_NUM = 78
|
|
KEYCODE_HEADSETHOOK = 79
|
|
KEYCODE_FOCUS = 80
|
|
KEYCODE_PLUS = 81
|
|
KEYCODE_MENU = 82
|
|
KEYCODE_NOTIFICATION = 83
|
|
KEYCODE_SEARCH = 84
|
|
KEYCODE_MEDIA_PLAY_PAUSE = 85
|
|
KEYCODE_MEDIA_STOP = 86
|
|
KEYCODE_MEDIA_NEXT = 87
|
|
KEYCODE_MEDIA_PREVIOUS = 88
|
|
KEYCODE_MEDIA_REWIND = 89
|
|
KEYCODE_MEDIA_FAST_FORWARD = 90
|
|
KEYCODE_MUTE = 91
|
|
KEYCODE_PAGE_UP = 92
|
|
KEYCODE_PAGE_DOWN = 93
|
|
KEYCODE_PICTSYMBOLS = 94
|
|
KEYCODE_SWITCH_CHARSET = 95
|
|
KEYCODE_BUTTON_A = 96
|
|
KEYCODE_BUTTON_B = 97
|
|
KEYCODE_BUTTON_C = 98
|
|
KEYCODE_BUTTON_X = 99
|
|
KEYCODE_BUTTON_Y = 100
|
|
KEYCODE_BUTTON_Z = 101
|
|
KEYCODE_BUTTON_L1 = 102
|
|
KEYCODE_BUTTON_R1 = 103
|
|
KEYCODE_BUTTON_L2 = 104
|
|
KEYCODE_BUTTON_R2 = 105
|
|
KEYCODE_BUTTON_THUMBL = 106
|
|
KEYCODE_BUTTON_THUMBR = 107
|
|
KEYCODE_BUTTON_START = 108
|
|
KEYCODE_BUTTON_SELECT = 109
|
|
KEYCODE_BUTTON_MODE = 110
|
|
KEYCODE_ESCAPE = 111
|
|
KEYCODE_FORWARD_DEL = 112
|
|
KEYCODE_CTRL_LEFT = 113
|
|
KEYCODE_CTRL_RIGHT = 114
|
|
KEYCODE_CAPS_LOCK = 115
|
|
KEYCODE_SCROLL_LOCK = 116
|
|
KEYCODE_META_LEFT = 117
|
|
KEYCODE_META_RIGHT = 118
|
|
KEYCODE_FUNCTION = 119
|
|
KEYCODE_SYSRQ = 120
|
|
KEYCODE_BREAK = 121
|
|
KEYCODE_MOVE_HOME = 122
|
|
KEYCODE_MOVE_END = 123
|
|
KEYCODE_INSERT = 124
|
|
KEYCODE_FORWARD = 125
|
|
KEYCODE_MEDIA_PLAY = 126
|
|
KEYCODE_MEDIA_PAUSE = 127
|
|
KEYCODE_MEDIA_CLOSE = 128
|
|
KEYCODE_MEDIA_EJECT = 129
|
|
KEYCODE_MEDIA_RECORD = 130
|
|
KEYCODE_F1 = 131
|
|
KEYCODE_F2 = 132
|
|
KEYCODE_F3 = 133
|
|
KEYCODE_F4 = 134
|
|
KEYCODE_F5 = 135
|
|
KEYCODE_F6 = 136
|
|
KEYCODE_F7 = 137
|
|
KEYCODE_F8 = 138
|
|
KEYCODE_F9 = 139
|
|
KEYCODE_F10 = 140
|
|
KEYCODE_F11 = 141
|
|
KEYCODE_F12 = 142
|
|
KEYCODE_NUM_LOCK = 143
|
|
KEYCODE_NUMPAD_0 = 144
|
|
KEYCODE_NUMPAD_1 = 145
|
|
KEYCODE_NUMPAD_2 = 146
|
|
KEYCODE_NUMPAD_3 = 147
|
|
KEYCODE_NUMPAD_4 = 148
|
|
KEYCODE_NUMPAD_5 = 149
|
|
KEYCODE_NUMPAD_6 = 150
|
|
KEYCODE_NUMPAD_7 = 151
|
|
KEYCODE_NUMPAD_8 = 152
|
|
KEYCODE_NUMPAD_9 = 153
|
|
KEYCODE_NUMPAD_DIVIDE = 154
|
|
KEYCODE_NUMPAD_MULTIPLY = 155
|
|
KEYCODE_NUMPAD_SUBTRACT = 156
|
|
KEYCODE_NUMPAD_ADD = 157
|
|
KEYCODE_NUMPAD_DOT = 158
|
|
KEYCODE_NUMPAD_COMMA = 159
|
|
KEYCODE_NUMPAD_ENTER = 160
|
|
KEYCODE_NUMPAD_EQUALS = 161
|
|
KEYCODE_NUMPAD_LEFT_PAREN = 162
|
|
KEYCODE_NUMPAD_RIGHT_PAREN = 163
|
|
KEYCODE_VOLUME_MUTE = 164
|
|
KEYCODE_INFO = 165
|
|
KEYCODE_CHANNEL_UP = 166
|
|
KEYCODE_CHANNEL_DOWN = 167
|
|
KEYCODE_ZOOM_IN = 168
|
|
KEYCODE_ZOOM_OUT = 169
|
|
KEYCODE_TV = 170
|
|
KEYCODE_WINDOW = 171
|
|
KEYCODE_GUIDE = 172
|
|
KEYCODE_DVR = 173
|
|
KEYCODE_BOOKMARK = 174
|
|
KEYCODE_CAPTIONS = 175
|
|
KEYCODE_SETTINGS = 176
|
|
KEYCODE_TV_POWER = 177
|
|
KEYCODE_TV_INPUT = 178
|
|
KEYCODE_STB_POWER = 179
|
|
KEYCODE_STB_INPUT = 180
|
|
KEYCODE_AVR_POWER = 181
|
|
KEYCODE_AVR_INPUT = 182
|
|
KEYCODE_PROG_RED = 183
|
|
KEYCODE_PROG_GREEN = 184
|
|
KEYCODE_PROG_YELLOW = 185
|
|
KEYCODE_PROG_BLUE = 186
|
|
KEYCODE_APP_SWITCH = 187
|
|
KEYCODE_BUTTON_1 = 188
|
|
KEYCODE_BUTTON_2 = 189
|
|
KEYCODE_BUTTON_3 = 190
|
|
KEYCODE_BUTTON_4 = 191
|
|
KEYCODE_BUTTON_5 = 192
|
|
KEYCODE_BUTTON_6 = 193
|
|
KEYCODE_BUTTON_7 = 194
|
|
KEYCODE_BUTTON_8 = 195
|
|
KEYCODE_BUTTON_9 = 196
|
|
KEYCODE_BUTTON_10 = 197
|
|
KEYCODE_BUTTON_11 = 198
|
|
KEYCODE_BUTTON_12 = 199
|
|
KEYCODE_BUTTON_13 = 200
|
|
KEYCODE_BUTTON_14 = 201
|
|
KEYCODE_BUTTON_15 = 202
|
|
KEYCODE_BUTTON_16 = 203
|
|
KEYCODE_LANGUAGE_SWITCH = 204
|
|
KEYCODE_MANNER_MODE = 205
|
|
KEYCODE_3D_MODE = 206
|
|
KEYCODE_CONTACTS = 207
|
|
KEYCODE_CALENDAR = 208
|
|
KEYCODE_MUSIC = 209
|
|
KEYCODE_CALCULATOR = 210
|
|
KEYCODE_ZENKAKU_HANKAKU = 211
|
|
KEYCODE_EISU = 212
|
|
KEYCODE_MUHENKAN = 213
|
|
KEYCODE_HENKAN = 214
|
|
KEYCODE_KATAKANA_HIRAGANA = 215
|
|
KEYCODE_YEN = 216
|
|
KEYCODE_RO = 217
|
|
KEYCODE_KANA = 218
|
|
KEYCODE_ASSIST = 219
|
|
KEYCODE_BRIGHTNESS_DOWN = 220
|
|
KEYCODE_BRIGHTNESS_UP = 221
|
|
KEYCODE_MEDIA_AUDIO_TRACK = 222
|
|
KEYCODE_SLEEP = 223
|
|
KEYCODE_WAKEUP = 224
|
|
KEYCODE_PAIRING = 225
|
|
KEYCODE_MEDIA_TOP_MENU = 226
|
|
KEYCODE_11 = 227
|
|
KEYCODE_12 = 228
|
|
KEYCODE_LAST_CHANNEL = 229
|
|
KEYCODE_TV_DATA_SERVICE = 230
|
|
KEYCODE_VOICE_ASSIST = 231
|
|
KEYCODE_TV_RADIO_SERVICE = 232
|
|
KEYCODE_TV_TELETEXT = 233
|
|
KEYCODE_TV_NUMBER_ENTRY = 234
|
|
KEYCODE_TV_TERRESTRIAL_ANALOG = 235
|
|
KEYCODE_TV_TERRESTRIAL_DIGITAL = 236
|
|
KEYCODE_TV_SATELLITE = 237
|
|
KEYCODE_TV_SATELLITE_BS = 238
|
|
KEYCODE_TV_SATELLITE_CS = 239
|
|
KEYCODE_TV_SATELLITE_SERVICE = 240
|
|
KEYCODE_TV_NETWORK = 241
|
|
KEYCODE_TV_ANTENNA_CABLE = 242
|
|
KEYCODE_TV_INPUT_HDMI_1 = 243
|
|
KEYCODE_TV_INPUT_HDMI_2 = 244
|
|
KEYCODE_TV_INPUT_HDMI_3 = 245
|
|
KEYCODE_TV_INPUT_HDMI_4 = 246
|
|
KEYCODE_TV_INPUT_COMPOSITE_1 = 247
|
|
KEYCODE_TV_INPUT_COMPOSITE_2 = 248
|
|
KEYCODE_TV_INPUT_COMPONENT_1 = 249
|
|
KEYCODE_TV_INPUT_COMPONENT_2 = 250
|
|
KEYCODE_TV_INPUT_VGA_1 = 251
|
|
KEYCODE_TV_AUDIO_DESCRIPTION = 252
|
|
KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP = 253
|
|
KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN = 254
|
|
KEYCODE_TV_ZOOM_MODE = 255
|
|
KEYCODE_TV_CONTENTS_MENU = 256
|
|
KEYCODE_TV_MEDIA_CONTEXT_MENU = 257
|
|
KEYCODE_TV_TIMER_PROGRAMMING = 258
|
|
KEYCODE_HELP = 259
|
|
KEYCODE_NAVIGATE_PREVIOUS = 260
|
|
KEYCODE_NAVIGATE_NEXT = 261
|
|
KEYCODE_NAVIGATE_IN = 262
|
|
KEYCODE_NAVIGATE_OUT = 263
|
|
KEYCODE_STEM_PRIMARY = 264
|
|
KEYCODE_STEM_1 = 265
|
|
KEYCODE_STEM_2 = 266
|
|
KEYCODE_STEM_3 = 267
|
|
KEYCODE_DPAD_UP_LEFT = 268
|
|
KEYCODE_DPAD_DOWN_LEFT = 269
|
|
KEYCODE_DPAD_UP_RIGHT = 270
|
|
KEYCODE_DPAD_DOWN_RIGHT = 271
|
|
KEYCODE_MEDIA_SKIP_FORWARD = 272
|
|
KEYCODE_MEDIA_SKIP_BACKWARD = 273
|
|
KEYCODE_MEDIA_STEP_FORWARD = 274
|
|
KEYCODE_MEDIA_STEP_BACKWARD = 275
|
|
KEYCODE_MEDIA_TOP_MENU_2 = 276
|
|
KEYCODE_SOFT_SLEEP = 277
|
|
KEYCODE_CUT = 278
|
|
KEYCODE_COPY = 279
|
|
KEYCODE_PASTE = 280
|
|
KEYCODE_SYSTEM_NAVIGATION_UP = 281
|
|
KEYCODE_SYSTEM_NAVIGATION_DOWN = 282
|
|
KEYCODE_SYSTEM_NAVIGATION_LEFT = 283
|
|
KEYCODE_SYSTEM_NAVIGATION_RIGHT = 284
|
|
KEYCODE_ALL_APPS = 285
|
|
KEYCODE_REFRESH = 286
|
|
KEYCODE_THUMBS_UP = 287
|
|
KEYCODE_THUMBS_DOWN = 288
|
|
KEYCODE_PROFILE_SWITCH = 289
|
|
KEYCODE_VIDEO_APP_1 = 290
|
|
KEYCODE_VIDEO_APP_2 = 291
|
|
KEYCODE_VIDEO_APP_3 = 292
|
|
KEYCODE_VIDEO_APP_4 = 293
|
|
KEYCODE_VIDEO_APP_5 = 294
|
|
KEYCODE_VIDEO_APP_6 = 295
|
|
KEYCODE_VIDEO_APP_7 = 296
|
|
KEYCODE_VIDEO_APP_8 = 297
|
|
KEYCODE_FEATURED_APP_1 = 298
|
|
KEYCODE_FEATURED_APP_2 = 299
|
|
KEYCODE_FEATURED_APP_3 = 300
|
|
KEYCODE_FEATURED_APP_4 = 301
|
|
KEYCODE_DEMO_APP_1 = 302
|
|
KEYCODE_DEMO_APP_2 = 303
|
|
KEYCODE_DEMO_APP_3 = 304
|
|
KEYCODE_DEMO_APP_4 = 305
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# Key
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class Key(Stub):
|
|
"""Key — 键盘按键"""
|
|
|
|
KEY_FLAG_ALT = 1
|
|
KEY_FLAG_SHIFT = 2
|
|
KEY_FLAG_CAPS_LOCK = 4
|
|
KEY_FLAG_CTRL = 8
|
|
KEY_FLAG_META = 16
|
|
KEY_FLAG_FUNCTION = 32
|
|
KEY_FLAG_MODIFIER = 64
|
|
KEY_FLAG_REPEAT = 128
|
|
KEY_FLAG_LONGPRESS = 256
|
|
KEY_FLAG_CLUSTER = 512
|
|
KEY_FLAG_CANCELED = 1024
|
|
KEY_FLAG_EDGE = 2048
|
|
KEY_FLAG_GESTURE = 4096
|
|
KEY_FLAG_VIRTUAL = 8192
|
|
|
|
KEY_TYPE_NORMAL = 0
|
|
KEY_TYPE_MODIFIER = 1
|
|
KEY_TYPE_SPACE = 2
|
|
KEY_TYPE_DONE = 3
|
|
KEY_TYPE_DELETE = 4
|
|
KEY_TYPE_ACTION = 5
|
|
KEY_TYPE_CANCEL = 6
|
|
KEY_TYPE_MODE_CHANGE = 7
|
|
KEY_TYPE_SHIFT = 8
|
|
KEY_TYPE_ALT = 9
|
|
KEY_TYPE_CTRL = 10
|
|
KEY_TYPE_FUNCTION = 11
|
|
KEY_TYPE_EMOJI = 12
|
|
KEY_TYPE_LANGUAGE = 13
|
|
|
|
def __init__(self, key_code: int = KEYCODE_UNKNOWN, label: str = "",
|
|
type: int = KEY_TYPE_NORMAL):
|
|
super().__init__()
|
|
self._key_code = key_code
|
|
self._label = label
|
|
self._type = type
|
|
self._text: str = ""
|
|
self._icon: Any = None
|
|
self._x: int = 0
|
|
self._y: int = 0
|
|
self._width: int = 0
|
|
self._height: int = 0
|
|
self._gap: int = 0
|
|
self._sticky: bool = False
|
|
self._modifier: bool = False
|
|
self._enabled: bool = True
|
|
self._repeating: bool = False
|
|
self._edge_flags: int = 0
|
|
self._popup_characters: str = ""
|
|
self._secondary_labels: List[str] = []
|
|
|
|
def getKeyCode(self) -> int:
|
|
return self._key_code
|
|
|
|
def setKeyCode(self, key_code: int):
|
|
self._key_code = key_code
|
|
|
|
def getLabel(self) -> str:
|
|
return self._label
|
|
|
|
def setLabel(self, label: str):
|
|
self._label = label
|
|
|
|
def getType(self) -> int:
|
|
return self._type
|
|
|
|
def setType(self, type_: int):
|
|
self._type = type_
|
|
|
|
def getText(self) -> str:
|
|
return self._text
|
|
|
|
def setText(self, text: str):
|
|
self._text = text
|
|
|
|
def getIcon(self) -> Any:
|
|
return self._icon
|
|
|
|
def setIcon(self, icon: Any):
|
|
self._icon = icon
|
|
|
|
def getX(self) -> int:
|
|
return self._x
|
|
|
|
def setX(self, x: int):
|
|
self._x = x
|
|
|
|
def getY(self) -> int:
|
|
return self._y
|
|
|
|
def setY(self, y: int):
|
|
self._y = y
|
|
|
|
def getWidth(self) -> int:
|
|
return self._width
|
|
|
|
def setWidth(self, width: int):
|
|
self._width = width
|
|
|
|
def getHeight(self) -> int:
|
|
return self._height
|
|
|
|
def setHeight(self, height: int):
|
|
self._height = height
|
|
|
|
def getGap(self) -> int:
|
|
return self._gap
|
|
|
|
def setGap(self, gap: int):
|
|
self._gap = gap
|
|
|
|
def isSticky(self) -> bool:
|
|
return self._sticky
|
|
|
|
def setSticky(self, sticky: bool):
|
|
self._sticky = sticky
|
|
|
|
def isModifier(self) -> bool:
|
|
return self._modifier
|
|
|
|
def setModifier(self, modifier: bool):
|
|
self._modifier = modifier
|
|
|
|
def isEnabled(self) -> bool:
|
|
return self._enabled
|
|
|
|
def setEnabled(self, enabled: bool):
|
|
self._enabled = enabled
|
|
|
|
def isRepeating(self) -> bool:
|
|
return self._repeating
|
|
|
|
def setRepeating(self, repeating: bool):
|
|
self._repeating = repeating
|
|
|
|
def getPopupCharacters(self) -> str:
|
|
return self._popup_characters
|
|
|
|
def setPopupCharacters(self, chars: str):
|
|
self._popup_characters = chars
|
|
|
|
def getSecondaryLabels(self) -> List[str]:
|
|
return list(self._secondary_labels)
|
|
|
|
def setSecondaryLabels(self, labels: List[str]):
|
|
self._secondary_labels = list(labels)
|
|
|
|
def isShiftKey(self) -> bool:
|
|
return self._type == Key.KEY_TYPE_SHIFT
|
|
|
|
def isAltKey(self) -> bool:
|
|
return self._type == Key.KEY_TYPE_ALT
|
|
|
|
def isCtrlKey(self) -> bool:
|
|
return self._type == Key.KEY_TYPE_CTRL
|
|
|
|
def isFunctionKey(self) -> bool:
|
|
return self._type == Key.KEY_TYPE_FUNCTION
|
|
|
|
def toString(self) -> str:
|
|
return f"Key(code={self._key_code}, label={self._label}, type={self._type})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# Keyboard
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class Keyboard(Stub):
|
|
"""Keyboard — 键盘布局"""
|
|
|
|
KEYBOARD_TYPE_ALPHA = 0
|
|
KEYBOARD_TYPE_NUMERIC = 1
|
|
KEYBOARD_TYPE_PHONE = 2
|
|
KEYBOARD_TYPE_SYMBOLS = 3
|
|
KEYBOARD_TYPE_EMOJI = 4
|
|
KEYBOARD_TYPE_URL = 5
|
|
KEYBOARD_TYPE_EMAIL = 6
|
|
KEYBOARD_TYPE_IME = 7
|
|
|
|
EDGE_LEFT = 1
|
|
EDGE_RIGHT = 2
|
|
EDGE_TOP = 4
|
|
EDGE_BOTTOM = 8
|
|
|
|
def __init__(self, context: Any = None, layout_id: int = 0,
|
|
keyboard_type: int = KEYBOARD_TYPE_ALPHA):
|
|
super().__init__()
|
|
self._context = context
|
|
self._layout_id = layout_id
|
|
self._keyboard_type = keyboard_type
|
|
self._keys: List[Key] = []
|
|
self._shift_keys: List[Key] = []
|
|
self._alt_keys: List[Key] = []
|
|
self._ctrl_keys: List[Key] = []
|
|
self._function_keys: List[Key] = []
|
|
self._modifier_keys: List[Key] = []
|
|
self._key_width: int = 0
|
|
self._key_height: int = 0
|
|
self._horizontal_gap: int = 0
|
|
self._vertical_gap: int = 0
|
|
self._default_row_height: int = 0
|
|
self._rows: int = 0
|
|
self._columns: int = 0
|
|
self._label: str = ""
|
|
self._is_shifted: bool = False
|
|
self._is_alt: bool = False
|
|
self._is_ctrl: bool = False
|
|
self._is_function: bool = False
|
|
|
|
def getKeys(self) -> List[Key]:
|
|
return list(self._keys)
|
|
|
|
def setKeys(self, keys: List[Key]):
|
|
self._keys = list(keys)
|
|
|
|
def addKey(self, key: Key):
|
|
self._keys.append(key)
|
|
|
|
def removeKey(self, key: Key):
|
|
self._keys = [k for k in self._keys if k is not key]
|
|
|
|
def getKeyByCode(self, key_code: int) -> Optional[Key]:
|
|
for k in self._keys:
|
|
if k.getKeyCode() == key_code:
|
|
return k
|
|
return None
|
|
|
|
def getShiftKeys(self) -> List[Key]:
|
|
return list(self._shift_keys)
|
|
|
|
def getAltKeys(self) -> List[Key]:
|
|
return list(self._alt_keys)
|
|
|
|
def getModifierKeys(self) -> List[Key]:
|
|
return list(self._modifier_keys)
|
|
|
|
def getKeyWidth(self) -> int:
|
|
return self._key_width
|
|
|
|
def setKeyWidth(self, width: int):
|
|
self._key_width = width
|
|
|
|
def getKeyHeight(self) -> int:
|
|
return self._key_height
|
|
|
|
def setKeyHeight(self, height: int):
|
|
self._key_height = height
|
|
|
|
def getHorizontalGap(self) -> int:
|
|
return self._horizontal_gap
|
|
|
|
def setHorizontalGap(self, gap: int):
|
|
self._horizontal_gap = gap
|
|
|
|
def getVerticalGap(self) -> int:
|
|
return self._vertical_gap
|
|
|
|
def setVerticalGap(self, gap: int):
|
|
self._vertical_gap = gap
|
|
|
|
def getRows(self) -> int:
|
|
return self._rows
|
|
|
|
def setRows(self, rows: int):
|
|
self._rows = rows
|
|
|
|
def getColumns(self) -> int:
|
|
return self._columns
|
|
|
|
def setColumns(self, cols: int):
|
|
self._columns = cols
|
|
|
|
def getLabel(self) -> str:
|
|
return self._label
|
|
|
|
def setLabel(self, label: str):
|
|
self._label = label
|
|
|
|
def isShifted(self) -> bool:
|
|
return self._is_shifted
|
|
|
|
def setShifted(self, shifted: bool):
|
|
self._is_shifted = shifted
|
|
|
|
def getKeyboardType(self) -> int:
|
|
return self._keyboard_type
|
|
|
|
def setKeyboardType(self, type_: int):
|
|
self._keyboard_type = type_
|
|
|
|
def toString(self) -> str:
|
|
return f"Keyboard(keys={len(self._keys)}, type={self._keyboard_type})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# KeyboardView
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class KeyboardView(Stub):
|
|
"""KeyboardView — 键盘视图"""
|
|
|
|
def __init__(self, context: Any = None, keyboard: Keyboard = None):
|
|
super().__init__()
|
|
self._context = context
|
|
self._keyboard = keyboard
|
|
self._is_visible: bool = False
|
|
self._is_preview_enabled: bool = True
|
|
self._is_proximity_correction_enabled: bool = True
|
|
self._key_text_size: float = 20.0
|
|
self._key_text_color: int = 0xFF000000
|
|
self._background_color: int = 0xFFEEEEEE
|
|
self._preview_background_color: int = 0xFFCCCCCC
|
|
self._on_key_listener: Optional[Callable] = None
|
|
self._on_key_action_listener: Optional[Callable] = None
|
|
self._pressed_keys: Set[Key] = set()
|
|
self._keyboard_width: int = 0
|
|
self._keyboard_height: int = 0
|
|
|
|
def setKeyboard(self, keyboard: Keyboard):
|
|
self._keyboard = keyboard
|
|
|
|
def getKeyboard(self) -> Optional[Keyboard]:
|
|
return self._keyboard
|
|
|
|
def setVisibility(self, visible: bool):
|
|
self._is_visible = visible
|
|
|
|
def isVisible(self) -> bool:
|
|
return self._is_visible
|
|
|
|
def setPreviewEnabled(self, enabled: bool):
|
|
self._is_preview_enabled = enabled
|
|
|
|
def isPreviewEnabled(self) -> bool:
|
|
return self._is_preview_enabled
|
|
|
|
def setProximityCorrectionEnabled(self, enabled: bool):
|
|
self._is_proximity_correction_enabled = enabled
|
|
|
|
def isProximityCorrectionEnabled(self) -> bool:
|
|
return self._is_proximity_correction_enabled
|
|
|
|
def setKeyTextSize(self, size: float):
|
|
self._key_text_size = size
|
|
|
|
def getKeyTextSize(self) -> float:
|
|
return self._key_text_size
|
|
|
|
def setKeyTextColor(self, color: int):
|
|
self._key_text_color = color
|
|
|
|
def getKeyTextColor(self) -> int:
|
|
return self._key_text_color
|
|
|
|
def setBackgroundColor(self, color: int):
|
|
self._background_color = color
|
|
|
|
def getBackgroundColor(self) -> int:
|
|
return self._background_color
|
|
|
|
def setOnKeyboardActionListener(self, listener: Callable):
|
|
self._on_key_listener = listener
|
|
|
|
def setOnKeyListener(self, listener: Callable):
|
|
self._on_key_action_listener = listener
|
|
|
|
def simulateKeyPress(self, key: Key):
|
|
"""模拟按键按下"""
|
|
self._pressed_keys.add(key)
|
|
if self._on_key_listener:
|
|
self._on_key_listener.onKey(key.getKeyCode(), key)
|
|
|
|
def simulateKeyRelease(self, key: Key):
|
|
"""模拟按键释放"""
|
|
self._pressed_keys.discard(key)
|
|
|
|
def isKeyPressed(self, key: Key) -> bool:
|
|
return key in self._pressed_keys
|
|
|
|
def invalidate(self):
|
|
"""重绘键盘"""
|
|
pass
|
|
|
|
def setKeyboardWidth(self, width: int):
|
|
self._keyboard_width = width
|
|
|
|
def setKeyboardHeight(self, height: int):
|
|
self._keyboard_height = height
|
|
|
|
def getKeyboardWidth(self) -> int:
|
|
return self._keyboard_width
|
|
|
|
def getKeyboardHeight(self) -> int:
|
|
return self._keyboard_height
|
|
|
|
def clampY(self, y: int) -> int:
|
|
return max(0, min(y, self._keyboard_height))
|
|
|
|
def toString(self) -> str:
|
|
return f"KeyboardView(visible={self._is_visible})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# AbstractInputMethodService
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class AbstractInputMethodService(Stub):
|
|
"""AbstractInputMethodService — 抽象输入法服务基类"""
|
|
|
|
SERVICE_INTERFACE = "android.inputmethodservice.AbstractInputMethodService"
|
|
SERVICE_META_DATA = "android.inputmethod"
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._keyboard_view: Optional[KeyboardView] = None
|
|
self._keyboard: Optional[Keyboard] = None
|
|
self._is_fullscreen: bool = False
|
|
self._is_extracted_view_visible: bool = False
|
|
self._is_input_view_visible: bool = False
|
|
self._is_candidates_view_visible: bool = False
|
|
self._input_view_started: bool = False
|
|
|
|
def onCreate(self):
|
|
pass
|
|
|
|
def onDestroy(self):
|
|
self._keyboard = None
|
|
self._keyboard_view = None
|
|
|
|
def onCreateInputView(self) -> Optional[KeyboardView]:
|
|
return self._keyboard_view
|
|
|
|
def onCreateCandidatesView(self) -> Any:
|
|
return None
|
|
|
|
def onStartInputView(self, info: Any, restarting: bool):
|
|
self._is_input_view_visible = True
|
|
self._input_view_started = True
|
|
|
|
def onFinishInputView(self, finishing_input: bool):
|
|
self._is_input_view_visible = False
|
|
|
|
def onStartCandidatesView(self, info: Any, restarting: bool):
|
|
self._is_candidates_view_visible = True
|
|
|
|
def onFinishCandidatesView(self, finishing_input: bool):
|
|
self._is_candidates_view_visible = False
|
|
|
|
def onStartInput(self, input_connection: Any, editor_info: Any, restarting: bool):
|
|
pass
|
|
|
|
def onFinishInput(self):
|
|
pass
|
|
|
|
def setKeyboard(self, keyboard: Keyboard):
|
|
self._keyboard = keyboard
|
|
if self._keyboard_view:
|
|
self._keyboard_view.setKeyboard(keyboard)
|
|
|
|
def getKeyboard(self) -> Optional[Keyboard]:
|
|
return self._keyboard
|
|
|
|
def setKeyboardView(self, keyboard_view: KeyboardView):
|
|
self._keyboard_view = keyboard_view
|
|
|
|
def getKeyboardView(self) -> Optional[KeyboardView]:
|
|
return self._keyboard_view
|
|
|
|
def sendKeyChar(self, char: str):
|
|
pass
|
|
|
|
def sendDownUpKeyEvents(self, key_event_code: int):
|
|
pass
|
|
|
|
def switchToNextKeyboard(self):
|
|
pass
|
|
|
|
def switchToPreviousKeyboard(self):
|
|
pass
|
|
|
|
def hideWindow(self):
|
|
self._is_input_view_visible = False
|
|
self._is_candidates_view_visible = False
|
|
|
|
def showWindow(self, show_flags: int):
|
|
pass
|
|
|
|
def requestHideSelf(self, flags: int):
|
|
pass
|
|
|
|
def requestShowSelf(self, flags: int):
|
|
pass
|
|
|
|
def isFullscreen(self) -> bool:
|
|
return self._is_fullscreen
|
|
|
|
def setFullscreen(self, fullscreen: bool):
|
|
self._is_fullscreen = fullscreen
|
|
|
|
def toString(self) -> str:
|
|
return f"AbstractInputMethodService(fullscreen={self._is_fullscreen})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# InputMethodService
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class InputMethodService(AbstractInputMethodService):
|
|
"""InputMethodService — 输入法服务"""
|
|
|
|
BACK_DISPOSITION_DEFAULT = 0
|
|
BACK_DISPOSITION_WILL_DISMISS = 1
|
|
BACK_DISPOSITION_WILL_NOT_DISMISS = 2
|
|
|
|
SHOW_INPUT_METHOD_PICKER = 1
|
|
SHOW_EXPLICIT = 2
|
|
SHOW_FORCED = 4
|
|
|
|
HIDE_EXPLICIT = 1
|
|
HIDE_NOT_ALWAYS = 2
|
|
HIDE_IMPLICIT_ONLY = 4
|
|
HIDE_BY_COMMAND = 8
|
|
|
|
KEYGUARD_DISABLE_NONE = 0
|
|
KEYGUARD_DISABLE_FEATURES_NONE = 0
|
|
KEYGUARD_DISABLE_FEATURES_ALL = 0x7FFFFFFF
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._back_disposition: int = InputMethodService.BACK_DISPOSITION_DEFAULT
|
|
self._is_input_view_shown: bool = False
|
|
self._is_candidates_view_shown: bool = False
|
|
self._extract_view: Any = None
|
|
self._input_connection: Any = None
|
|
self._current_input_editor_info: Any = None
|
|
self._settings_observer: Any = None
|
|
|
|
def onInitializeInterface(self):
|
|
pass
|
|
|
|
def onBindInput(self):
|
|
pass
|
|
|
|
def onUnbindInput(self):
|
|
pass
|
|
|
|
def onStartInput(self, attribute: Any, restarting: bool):
|
|
super().onStartInput(attribute, attribute, restarting)
|
|
|
|
def onFinishInput(self):
|
|
super().onFinishInput()
|
|
|
|
def onDisplayCompletions(self, completions: List[Any]):
|
|
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 onUpdateExtractedText(self, token: int, extracted_text: Any):
|
|
pass
|
|
|
|
def onExtractedTextClicked(self):
|
|
pass
|
|
|
|
def onExtractingInputChanged(self, editor_info: Any):
|
|
pass
|
|
|
|
def onConfigureWindow(self, win: Any, is_fullscreen: bool, is_obscured: bool):
|
|
pass
|
|
|
|
def onEvaluateFullscreenMode(self) -> bool:
|
|
return self._is_fullscreen
|
|
|
|
def onEvaluateInputViewShown(self) -> bool:
|
|
return True
|
|
|
|
def onComputeInsets(self, out_insets: Any):
|
|
pass
|
|
|
|
def onKeyDown(self, key_code: int, event: Any) -> bool:
|
|
return False
|
|
|
|
def onKeyUp(self, key_code: int, event: Any) -> bool:
|
|
return False
|
|
|
|
def onKeyLongPress(self, key_code: int, event: Any) -> bool:
|
|
return False
|
|
|
|
def onKeyMultiple(self, key_code: int, count: int, event: Any) -> bool:
|
|
return False
|
|
|
|
def onTrackballEvent(self, event: Any) -> bool:
|
|
return False
|
|
|
|
def onGenericMotionEvent(self, event: Any) -> bool:
|
|
return False
|
|
|
|
def onWindowShown(self):
|
|
pass
|
|
|
|
def onWindowHidden(self):
|
|
pass
|
|
|
|
def setBackDisposition(self, disposition: int):
|
|
self._back_disposition = disposition
|
|
|
|
def getBackDisposition(self) -> int:
|
|
return self._back_disposition
|
|
|
|
def switchInputMethod(self, id: str):
|
|
pass
|
|
|
|
def changeInputMethodSubtype(self, subtype: Any):
|
|
pass
|
|
|
|
def getCurrentInputBinding(self) -> Any:
|
|
return None
|
|
|
|
def getCurrentInputConnection(self) -> Any:
|
|
return self._input_connection
|
|
|
|
def getCurrentInputEditorInfo(self) -> Any:
|
|
return self._current_input_editor_info
|
|
|
|
def getCurrentInputStarted(self) -> bool:
|
|
return self._input_view_started
|
|
|
|
def getLayoutInflater(self) -> Any:
|
|
return None
|
|
|
|
def getWindow(self) -> Any:
|
|
return None
|
|
|
|
def isInputViewShown(self) -> bool:
|
|
return self._is_input_view_shown
|
|
|
|
def setInputView(self, view: Any):
|
|
self._is_input_view_shown = view is not None
|
|
|
|
def showStatusIcon(self, icon_id: int):
|
|
pass
|
|
|
|
def hideStatusIcon(self):
|
|
pass
|
|
|
|
def sendDefaultEditorAction(self, from_enter_key: bool):
|
|
pass
|
|
|
|
def sendDownUpKeyEvents(self, key_event_code: int):
|
|
pass
|
|
|
|
def sendKeyChar(self, char: str):
|
|
pass
|
|
|
|
def updateFullscreenMode(self):
|
|
pass
|
|
|
|
def updateInputViewShown(self):
|
|
pass
|
|
|
|
def exposeCompletions(self, completions: List[Any]):
|
|
self.onDisplayCompletions(completions)
|
|
|
|
def toString(self) -> str:
|
|
return f"InputMethodService(backDisposition={self._back_disposition})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# InputMethodServiceKeyboardHelper
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class InputMethodServiceKeyboardHelper(Stub):
|
|
"""InputMethodServiceKeyboardHelper — 输入法键盘辅助类"""
|
|
|
|
@staticmethod
|
|
def createDefaultQWERTYKeyboard(context: Any) -> Keyboard:
|
|
kb = Keyboard(context, 0, Keyboard.KEYBOARD_TYPE_ALPHA)
|
|
row1_chars = "qwertyuiop"
|
|
row2_chars = "asdfghjkl"
|
|
row3_chars = "zxcvbnm"
|
|
for i, c in enumerate(row1_chars):
|
|
k = Key(ord(c.upper()), c, Key.KEY_TYPE_NORMAL)
|
|
k.setWidth(50)
|
|
k.setHeight(60)
|
|
k.setX(i * 55)
|
|
kb.addKey(k)
|
|
shift_key = Key(KEYCODE_SHIFT_LEFT, "Shift", Key.KEY_TYPE_SHIFT)
|
|
shift_key.setWidth(70)
|
|
shift_key.setHeight(60)
|
|
kb.addKey(shift_key)
|
|
space_key = Key(KEYCODE_SPACE, " ", Key.KEY_TYPE_SPACE)
|
|
space_key.setWidth(200)
|
|
space_key.setHeight(60)
|
|
kb.addKey(space_key)
|
|
del_key = Key(KEYCODE_DEL, "Del", Key.KEY_TYPE_DELETE)
|
|
del_key.setWidth(70)
|
|
del_key.setHeight(60)
|
|
kb.addKey(del_key)
|
|
enter_key = Key(KEYCODE_ENTER, "Enter", Key.KEY_TYPE_DONE)
|
|
enter_key.setWidth(80)
|
|
enter_key.setHeight(60)
|
|
kb.addKey(enter_key)
|
|
return kb
|
|
|
|
@staticmethod
|
|
def createNumericKeyboard(context: Any) -> Keyboard:
|
|
kb = Keyboard(context, 0, Keyboard.KEYBOARD_TYPE_NUMERIC)
|
|
for i in range(10):
|
|
k = Key(KEYCODE_0 + i, str(i), Key.KEY_TYPE_NORMAL)
|
|
k.setWidth(60)
|
|
k.setHeight(60)
|
|
kb.addKey(k)
|
|
return kb
|
|
|
|
@staticmethod
|
|
def createPhoneKeyboard(context: Any) -> Keyboard:
|
|
kb = Keyboard(context, 0, Keyboard.KEYBOARD_TYPE_PHONE)
|
|
layout = [["1", "2", "3"], ["4", "5", "6"], ["7", "8", "9"], ["*", "0", "#"]]
|
|
for row_idx, row in enumerate(layout):
|
|
for col_idx, c in enumerate(row):
|
|
k = Key(KEYCODE_0 + int(c) if c.isdigit() else (
|
|
KEYCODE_STAR if c == "*" else KEYCODE_POUND), c, Key.KEY_TYPE_NORMAL)
|
|
k.setWidth(80)
|
|
k.setHeight(60)
|
|
k.setX(col_idx * 85)
|
|
k.setY(row_idx * 65)
|
|
kb.addKey(k)
|
|
return kb
|
|
|
|
@staticmethod
|
|
def createSymbolKeyboard(context: Any) -> Keyboard:
|
|
kb = Keyboard(context, 0, Keyboard.KEYBOARD_TYPE_SYMBOLS)
|
|
symbols = "~!@#$%^&*()_+-=[]{}|;':\",./<>?"
|
|
for i, c in enumerate(symbols):
|
|
k = Key(KEYCODE_UNKNOWN, c, Key.KEY_TYPE_NORMAL)
|
|
k.setWidth(45)
|
|
k.setHeight(55)
|
|
kb.addKey(k)
|
|
return kb
|
|
|
|
@staticmethod
|
|
def createKeyboardView(context: Any, keyboard: Keyboard) -> KeyboardView:
|
|
return KeyboardView(context, keyboard) |