Поддержка MacOS (проверено в Tahoe)

This commit is contained in:
2026-09-06 17:13:34 +08:00
parent 57c4e80f0d
commit 4515b39090
24 changed files with 590 additions and 65 deletions
+71
View File
@@ -0,0 +1,71 @@
#!/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()