From 8e8dccf3a72c1c44d3db17ed1227b1580fbb20a2 Mon Sep 17 00:00:00 2001 From: "regicidal.plutophage" <36969337+regicidalplutophage@users.noreply.github.com> Date: Wed, 18 Dec 2024 16:33:08 +0000 Subject: [PATCH] hid watchdog --- kmk/hid.py | 119 ++++++++++++++++++++++++-------------------- kmk/kmk_keyboard.py | 23 +++++++++ 2 files changed, 87 insertions(+), 55 deletions(-) diff --git a/kmk/hid.py b/kmk/hid.py index 7d65409a2..cbd36c7f4 100644 --- a/kmk/hid.py +++ b/kmk/hid.py @@ -5,6 +5,8 @@ from storage import getmount from kmk.keys import ConsumerKey, KeyboardKey, ModifierKey, MouseKey + +# from kmk.scheduler import create_task from kmk.utils import Debug, clamp try: @@ -55,13 +57,47 @@ class HIDUsagePage: class AbstractHID: - REPORT_BYTES = 8 + report_bytes_default = 8 + REPORT_BYTES = report_bytes_default + hid_devices = {} def __init__(self, **kwargs): + self._nkro = False + self._mouse = True + self._pan = False + self.make_device_list() + + self._cc_report = bytearray(HID_REPORT_SIZES[HIDReportTypes.CONSUMER] + 1) + self._cc_report[0] = HIDReportTypes.CONSUMER + self._cc_pending = False + + self.test_nkro() + self.test_mouse() + + def make_device_list(self): + self.devices = {} + + for device in self.hid_devices: + if not hasattr(device, 'send_report'): + continue + us = device.usage + up = device.usage_page + + if up == HIDUsagePage.CONSUMER and us == HIDUsage.CONSUMER: + self.devices[HIDReportTypes.CONSUMER] = device + elif up == HIDUsagePage.KEYBOARD and us == HIDUsage.KEYBOARD: + self.devices[HIDReportTypes.KEYBOARD] = device + elif up == HIDUsagePage.MOUSE and us == HIDUsage.MOUSE: + self.devices[HIDReportTypes.MOUSE] = device + elif up == HIDUsagePage.SYSCONTROL and us == HIDUsage.SYSCONTROL: + self.devices[HIDReportTypes.SYSCONTROL] = device + + def test_nkro(self): + if self._nkro: + return self._evt = bytearray(self.REPORT_BYTES) self._evt[0] = HIDReportTypes.KEYBOARD - self._nkro = False # bodgy NKRO autodetect try: @@ -87,9 +123,9 @@ def __init__(self, **kwargs): self.report_mods = memoryview(self._evt)[1:2] self.report_non_mods = memoryview(self._evt)[3:] - self._cc_report = bytearray(HID_REPORT_SIZES[HIDReportTypes.CONSUMER] + 1) - self._cc_report[0] = HIDReportTypes.CONSUMER - self._cc_pending = False + def test_mouse(self): + if not self._mouse or self._pan: + return self._pd_report = bytearray(HID_REPORT_SIZES[HIDReportTypes.MOUSE] + 1) self._pd_report[0] = HIDReportTypes.MOUSE @@ -103,12 +139,17 @@ def __init__(self, **kwargs): except ValueError: self._pd_report = bytearray(6) self._pd_report[0] = HIDReportTypes.MOUSE + self._pan = True if debug.enabled: debug('use pan') except KeyError: + self._mouse = False if debug.enabled: debug('mouse disabled') + def watchdog(self): + return + def __repr__(self): return f'{self.__class__.__name__}(REPORT_BYTES={self.REPORT_BYTES})' @@ -254,27 +295,22 @@ def has_key(self, key): class USBHID(AbstractHID): - REPORT_BYTES = 9 + report_bytes_default = 9 + REPORT_BYTES = report_bytes_default def __init__(self, **kwargs): - - self.devices = {} - - for device in usb_hid.devices: - us = device.usage - up = device.usage_page - - if up == HIDUsagePage.CONSUMER and us == HIDUsage.CONSUMER: - self.devices[HIDReportTypes.CONSUMER] = device - elif up == HIDUsagePage.KEYBOARD and us == HIDUsage.KEYBOARD: - self.devices[HIDReportTypes.KEYBOARD] = device - elif up == HIDUsagePage.MOUSE and us == HIDUsage.MOUSE: - self.devices[HIDReportTypes.MOUSE] = device - elif up == HIDUsagePage.SYSCONTROL and us == HIDUsage.SYSCONTROL: - self.devices[HIDReportTypes.SYSCONTROL] = device - + self.hid = usb_hid + self.hid_devices = self.hid.devices + self.usb_status = None super().__init__(**kwargs) + def watchdog(self): + if self.usb_status != supervisor.runtime.usb_connected: + self.usb_status = supervisor.runtime.usb_connected + self.make_device_list() + self.test_nkro() + self.test_mouse() + def hid_send(self, evt): if not supervisor.runtime.usb_connected: return @@ -291,11 +327,12 @@ class BLEHID(AbstractHID): MAX_CONNECTIONS = const(2) def __init__(self, ble_name=str(getmount('/').label), **kwargs): - + self.ble_status = None self.ble_name = ble_name self.ble = BLERadio() self.ble.name = self.ble_name self.hid = HIDService() + self.hid_devices = self.hid.devices self.hid.protocol_mode = 0 # Boot protocol super().__init__(**kwargs) @@ -307,38 +344,10 @@ def __init__(self, ble_name=str(getmount('/').label), **kwargs): if not self.ble.connected or not self.hid.devices: self.start_advertising() - @property - def devices(self): - '''Search through the provided list of devices to find the ones with the - send_report attribute.''' - if not self.ble.connected: - return {} - - result = {} - - for device in self.hid.devices: - if not hasattr(device, 'send_report'): - continue - us = device.usage - up = device.usage_page - - if up == HIDUsagePage.CONSUMER and us == HIDUsage.CONSUMER: - result[HIDReportTypes.CONSUMER] = device - continue - - if up == HIDUsagePage.KEYBOARD and us == HIDUsage.KEYBOARD: - result[HIDReportTypes.KEYBOARD] = device - continue - - if up == HIDUsagePage.MOUSE and us == HIDUsage.MOUSE: - result[HIDReportTypes.MOUSE] = device - continue - - if up == HIDUsagePage.SYSCONTROL and us == HIDUsage.SYSCONTROL: - result[HIDReportTypes.SYSCONTROL] = device - continue - - return result + def watchdog(self): + if self.ble_status != self.ble.connected: + self.ble_status = self.ble.connected + self.make_device_list() def hid_send(self, evt): if not self.ble.connected: diff --git a/kmk/kmk_keyboard.py b/kmk/kmk_keyboard.py index 96d69059f..91c241021 100644 --- a/kmk/kmk_keyboard.py +++ b/kmk/kmk_keyboard.py @@ -34,6 +34,20 @@ class Sandbox: class KMKKeyboard: + def __init__( + self, + keymap=[], + coord_mapping=None, + matrix=None, + modules=[], + extensions=[], + ): + self.keymap = keymap + self.coord_mapping = coord_mapping + self.matrix = matrix + self.modules = modules + self.extensions = extensions + ##### # User-configurable keymap = [] @@ -185,6 +199,14 @@ def _process_resume_buffer(self): self._resume_buffer_x = buffer + @property + def debug_enabled(self) -> bool: + return debug.enabled + + @debug_enabled.setter + def debug_enabled(self, enabled: bool): + debug.enabled = enabled + def pre_process_key( self, key: Key, @@ -286,6 +308,7 @@ def _init_hid(self) -> None: else: self._hid_helper = AbstractHID self._hid_helper = self._hid_helper(**self._go_args) + self._watchdog = create_task(self._hid_helper.watchdog, period_ms=200) self._hid_send_enabled = True if debug.enabled: