72 lines
3.0 KiB
Python
72 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
||
"""Диагностика открытия HID-устройства через IOKit напрямую (ctypes).
|
||
|
||
Берёт путь устройства из hidapi (DevSrvsID:<entry_id> = registry entry ID),
|
||
открывает сервис через IORegistryEntryIDMatching + IOHIDDeviceCreate (как
|
||
делает сам hidapi) и печатает точный код IOReturn от IOHIDDeviceOpen:
|
||
- 0x00000000 — успех (права есть, проблема в hidapi)
|
||
- 0xE00002C1 — kIOReturnNotPrivileged (нет разрешения Input Monitoring)
|
||
- другой код — иная причина (см. коды IOKit, iokit_common_err).
|
||
"""
|
||
import ctypes
|
||
import ctypes.util
|
||
import re
|
||
import sys
|
||
|
||
import hid
|
||
|
||
iokit = ctypes.CDLL(ctypes.util.find_library("IOKit"))
|
||
cf = ctypes.CDLL(ctypes.util.find_library("CoreFoundation"))
|
||
|
||
# прототипы функций
|
||
iokit.IOServiceGetMatchingService.argtypes = [ctypes.c_int, ctypes.c_void_p]
|
||
iokit.IOServiceGetMatchingService.restype = ctypes.c_uint
|
||
iokit.IORegistryEntryIDMatching.argtypes = [ctypes.c_longlong]
|
||
iokit.IORegistryEntryIDMatching.restype = ctypes.c_void_p
|
||
iokit.IOObjectRelease.argtypes = [ctypes.c_uint]
|
||
iokit.IOObjectRelease.restype = ctypes.c_int
|
||
iokit.IOHIDDeviceCreate.argtypes = [ctypes.c_void_p, ctypes.c_uint]
|
||
iokit.IOHIDDeviceCreate.restype = ctypes.c_void_p
|
||
iokit.IOHIDDeviceOpen.argtypes = [ctypes.c_void_p, ctypes.c_int]
|
||
iokit.IOHIDDeviceOpen.restype = ctypes.c_int
|
||
iokit.IOHIDDeviceClose.argtypes = [ctypes.c_void_p, ctypes.c_int]
|
||
iokit.IOHIDDeviceClose.restype = ctypes.c_int
|
||
cf.CFRelease.argtypes = [ctypes.c_void_p]
|
||
|
||
|
||
def main():
|
||
"""Найти iface0 клавиатуры через hidapi и открыть её сервис в IOKit."""
|
||
paths = [i["path"].decode() for i in hid.enumerate(0x0C45, 0x8006)
|
||
if i["interface_number"] == 0]
|
||
if not paths:
|
||
raise SystemExit("устройство 0C45:8006 не найдено через hidapi")
|
||
m = re.fullmatch(r"DevSrvsID:(\d+)", paths[0])
|
||
if not m:
|
||
raise SystemExit(f"неожиданный формат пути: {paths[0]!r}")
|
||
entry_id = int(m.group(1))
|
||
|
||
service = iokit.IOServiceGetMatchingService(
|
||
0, iokit.IORegistryEntryIDMatching(entry_id))
|
||
if not service:
|
||
raise SystemExit(f"сервис с entry_id {entry_id} не найден в реестре")
|
||
print(f"сервис найден: {service:#x}")
|
||
|
||
dev = iokit.IOHIDDeviceCreate(None, service)
|
||
iokit.IOObjectRelease(service)
|
||
if not dev:
|
||
raise SystemExit("IOHIDDeviceCreate вернул NULL")
|
||
print("IOHIDDeviceCreate: ok")
|
||
|
||
r = iokit.IOHIDDeviceOpen(dev, 0) # kIOHIDOptionsTypeNone
|
||
meaning = {0x00000000: "OK (права есть)",
|
||
0xE00002C1: "NotPrivileged — нет разрешения Input Monitoring",
|
||
}.get(r, "см. коды IOKit (iokit_common_err)")
|
||
print(f"IOHIDDeviceOpen: {r:#010x} ({meaning})")
|
||
if r == 0:
|
||
iokit.IOHIDDeviceClose(dev, 0)
|
||
cf.CFRelease(dev)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|