新增模块覆盖: 系统层 (14): system, security, print, opengl, renderscript, transition, test, service_notification, service_controls, service_quicksettings, service_wallpaper, service_autofill, service_dreams, service_vr 应用层 (13): app_admin, app_backup, app_job, app_usage, app_role, app_people, appwidget, companion, credentials, mtp, sip, telecom, speech 硬件媒体层 (15): hardware_display, hardware_fingerprint, hardware_usb, hardware_input, media_audiofx, media_browse, media_session, media_tv, media_midi, media_projection, uwb, se, view_autofill, view_textclassifier, view_translation 总计 94 个模块,75,342 行代码
254 lines
9.0 KiB
Python
254 lines
9.0 KiB
Python
"""
|
|
Android hardware.input 组件 — InputManager, InputDevice, MotionRange 等
|
|
方法签名完全对齐 Android SDK
|
|
"""
|
|
|
|
import sys
|
|
from typing import Any, Callable, Dict, List, Optional
|
|
|
|
from .._core import Stub, AndroidOnlyError
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# InputManager
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class InputManager(Stub):
|
|
"""InputManager — 输入管理器"""
|
|
|
|
ACTION_QUERY_KEYBOARD_LAYOUTS = "android.hardware.input.action.QUERY_KEYBOARD_LAYOUTS"
|
|
|
|
# ═══════════════════════════════════════════════════════════
|
|
# InputDeviceListener
|
|
# ═══════════════════════════════════════════════════════════
|
|
|
|
class InputDeviceListener(Stub):
|
|
"""InputManager.InputDeviceListener — 输入设备监听器"""
|
|
|
|
def onInputDeviceAdded(self, deviceId: int):
|
|
pass
|
|
|
|
def onInputDeviceRemoved(self, deviceId: int):
|
|
pass
|
|
|
|
def onInputDeviceChanged(self, deviceId: int):
|
|
pass
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._devices: Dict[int, InputDevice] = {}
|
|
self._listeners: Dict[int, InputManager.InputDeviceListener] = {}
|
|
self._next_id = 1
|
|
self._init_default_devices()
|
|
|
|
def _init_default_devices(self):
|
|
# Keyboard
|
|
kb = InputDevice(
|
|
deviceId=0, name="Virtual Keyboard",
|
|
descriptor="keyboard_v1", sources=InputDevice.SOURCE_KEYBOARD,
|
|
vendorId=0x1, productId=0x1,
|
|
keyboardType=InputDevice.KEYBOARD_TYPE_ALPHABETIC,
|
|
hasMicrophone=False, isVirtual=True
|
|
)
|
|
self._devices[0] = kb
|
|
|
|
# Mouse
|
|
mouse = InputDevice(
|
|
deviceId=1, name="Virtual Mouse",
|
|
descriptor="mouse_v1", sources=InputDevice.SOURCE_MOUSE,
|
|
vendorId=0x2, productId=0x2,
|
|
keyboardType=InputDevice.KEYBOARD_TYPE_NONE,
|
|
hasMicrophone=False, isVirtual=True
|
|
)
|
|
self._devices[1] = mouse
|
|
|
|
# Trackpad
|
|
tp = InputDevice(
|
|
deviceId=2, name="Virtual Trackpad",
|
|
descriptor="trackpad_v1", sources=InputDevice.SOURCE_TOUCHPAD,
|
|
vendorId=0x3, productId=0x3,
|
|
keyboardType=InputDevice.KEYBOARD_TYPE_NONE,
|
|
hasMicrophone=False, isVirtual=False
|
|
)
|
|
self._devices[2] = tp
|
|
|
|
def getDevice(self, deviceId: int) -> Optional["InputDevice"]:
|
|
return self._devices.get(deviceId)
|
|
|
|
def getDeviceIds(self) -> List[int]:
|
|
return list(self._devices.keys())
|
|
|
|
def registerInputDeviceListener(self, listener: InputDeviceListener, handler: Any = None):
|
|
lid = id(listener)
|
|
self._listeners[lid] = listener
|
|
|
|
def unregisterInputDeviceListener(self, listener: InputDeviceListener):
|
|
lid = id(listener)
|
|
self._listeners.pop(lid, None)
|
|
|
|
def getInputDevice(self, deviceId: int) -> Optional["InputDevice"]:
|
|
return self.getDevice(deviceId)
|
|
|
|
def isInTabletMode(self) -> bool:
|
|
return False
|
|
|
|
def getCurrentKeyboardLayoutForInputDevice(self, device: "InputDevice") -> Optional[str]:
|
|
return None
|
|
|
|
def setKeyboardLayoutForInputDevice(self, device: "InputDevice",
|
|
keyboardLayoutDescriptor: str):
|
|
pass
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# InputDevice
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class InputDevice(Stub):
|
|
"""InputDevice — 输入设备"""
|
|
|
|
KEYBOARD_TYPE_ALPHABETIC = 2
|
|
KEYBOARD_TYPE_NON_ALPHABETIC = 1
|
|
KEYBOARD_TYPE_NONE = 0
|
|
|
|
SOURCE_CLASS_JOYSTICK = 16
|
|
SOURCE_CLASS_MASK = 0x000000FF
|
|
SOURCE_CLASS_NONE = 0x00000000
|
|
SOURCE_CLASS_POINTER = 0x00000002
|
|
SOURCE_CLASS_POSITION = 0x00000008
|
|
SOURCE_CLASS_TRACKBALL = 0x00000004
|
|
SOURCE_CLASS_BUTTON = 0x00000001
|
|
|
|
SOURCE_GAMEPAD = 0x00000401
|
|
SOURCE_HDMI = 0x02000000
|
|
SOURCE_JOYSTICK = 0x01000010
|
|
SOURCE_KEYBOARD = 0x00000101
|
|
SOURCE_MOUSE = 0x00002002
|
|
SOURCE_MOUSE_RELATIVE = 0x00002000
|
|
SOURCE_ROTARY_ENCODER = 0x00800000
|
|
SOURCE_STYLUS = 0x00004002
|
|
SOURCE_TOUCHPAD = 0x00100008
|
|
SOURCE_TOUCHSCREEN = 0x00001002
|
|
SOURCE_TOUCH_NAVIGATION = 0x00200008
|
|
SOURCE_TRACKBALL = 0x00010004
|
|
SOURCE_UNKNOWN = 0x00000000
|
|
SOURCE_ANY = 0xFFFFFFFE
|
|
|
|
# ═══════════════════════════════════════════════════════════
|
|
# MotionRange
|
|
# ═══════════════════════════════════════════════════════════
|
|
|
|
class MotionRange(Stub):
|
|
"""InputDevice.MotionRange — 运动范围"""
|
|
|
|
def __init__(self, axis: int = 0, source: int = 0,
|
|
min: float = 0.0, max: float = 1.0,
|
|
flat: float = 0.0, fuzz: float = 0.0,
|
|
resolution: float = 0.0):
|
|
super().__init__()
|
|
self._axis = axis
|
|
self._source = source
|
|
self._min = min
|
|
self._max = max
|
|
self._flat = flat
|
|
self._fuzz = fuzz
|
|
self._resolution = resolution
|
|
|
|
def getAxis(self) -> int:
|
|
return self._axis
|
|
|
|
def getSource(self) -> int:
|
|
return self._source
|
|
|
|
def getMin(self) -> float:
|
|
return self._min
|
|
|
|
def getMax(self) -> float:
|
|
return self._max
|
|
|
|
def getFlat(self) -> float:
|
|
return self._flat
|
|
|
|
def getFuzz(self) -> float:
|
|
return self._fuzz
|
|
|
|
def getRange(self) -> float:
|
|
return self._max - self._min
|
|
|
|
def getResolution(self) -> float:
|
|
return self._resolution
|
|
|
|
def toString(self) -> str:
|
|
return f"MotionRange(axis={self._axis}, source={self._source}," \
|
|
f" range=[{self._min}, {self._max}])"
|
|
|
|
def __init__(self, deviceId: int = 0, name: str = "", descriptor: str = "",
|
|
sources: int = 0, vendorId: int = 0, productId: int = 0,
|
|
controllerNumber: int = 0, keyboardType: int = KEYBOARD_TYPE_NONE,
|
|
hasMicrophone: bool = False, isVirtual: bool = False):
|
|
super().__init__()
|
|
self._device_id = deviceId
|
|
self._name = name
|
|
self._descriptor = descriptor
|
|
self._sources = sources
|
|
self._vendor_id = vendorId
|
|
self._product_id = productId
|
|
self._controller_number = controllerNumber
|
|
self._keyboard_type = keyboardType
|
|
self._has_microphone = hasMicrophone
|
|
self._is_virtual = isVirtual
|
|
self._motion_ranges: List[InputDevice.MotionRange] = []
|
|
|
|
def getId(self) -> int:
|
|
return self._device_id
|
|
|
|
def getName(self) -> str:
|
|
return self._name
|
|
|
|
def getDescriptor(self) -> str:
|
|
return self._descriptor
|
|
|
|
def getSources(self) -> int:
|
|
return self._sources
|
|
|
|
def getVendorId(self) -> int:
|
|
return self._vendor_id
|
|
|
|
def getProductId(self) -> int:
|
|
return self._product_id
|
|
|
|
def getControllerNumber(self) -> int:
|
|
return self._controller_number
|
|
|
|
def getKeyCharacterMap(self) -> Any:
|
|
return None
|
|
|
|
def getMotionRange(self, axis: int = -1, source: int = -1) -> List[MotionRange]:
|
|
results = []
|
|
for mr in self._motion_ranges:
|
|
if axis >= 0 and mr.getAxis() != axis:
|
|
continue
|
|
if source >= 0 and mr.getSource() != source:
|
|
continue
|
|
results.append(mr)
|
|
return results
|
|
|
|
def hasMicrophone(self) -> bool:
|
|
return self._has_microphone
|
|
|
|
def isVirtual(self) -> bool:
|
|
return self._is_virtual
|
|
|
|
def toString(self) -> str:
|
|
return f"InputDevice(id={self._device_id}, name={self._name}," \
|
|
f" sources={self._sources:#x})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# __all__
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
__all__ = [
|
|
"InputManager",
|
|
"InputDevice",
|
|
] |