From 8839c1c7ec8373d3bdfca0c46e570d5328ebd7eb Mon Sep 17 00:00:00 2001 From: Kyle Brown Date: Thu, 12 Nov 2020 14:33:39 -0800 Subject: [PATCH] prelim module support --- boards/crkbd/main.py | 7 +- kmk/extensions/__init__.py | 6 +- kmk/extensions/international.py | 18 +-- kmk/extensions/led.py | 23 ++-- kmk/extensions/media_keys.py | 18 +-- kmk/extensions/rgb.py | 22 ++-- kmk/kmk_keyboard.py | 153 ++++++++++++++++------- kmk/modules/__init__.py | 40 ++++++ kmk/{extensions => modules}/ble_split.py | 27 ++-- kmk/{extensions => modules}/layers.py | 12 +- kmk/{extensions => modules}/modtap.py | 32 +++-- kmk/{extensions => modules}/power.py | 12 +- kmk/{extensions => modules}/split.py | 24 ++-- 13 files changed, 235 insertions(+), 159 deletions(-) create mode 100644 kmk/modules/__init__.py rename kmk/{extensions => modules}/ble_split.py (93%) rename kmk/{extensions => modules}/layers.py (96%) rename kmk/{extensions => modules}/modtap.py (61%) rename kmk/{extensions => modules}/power.py (95%) rename kmk/{extensions => modules}/split.py (88%) diff --git a/boards/crkbd/main.py b/boards/crkbd/main.py index a46268e..d39e4d8 100644 --- a/boards/crkbd/main.py +++ b/boards/crkbd/main.py @@ -1,8 +1,8 @@ from kb import KMKKeyboard, rgb_pixel_pin -from kmk.extensions.ble_split import BLE_Split -from kmk.extensions.layers import Layers from kmk.extensions.rgb import RGB from kmk.keys import KC +from kmk.modules.ble_split import BLE_Split +from kmk.modules.layers import Layers keyboard = KMKKeyboard() @@ -33,7 +33,8 @@ split = BLE_Split(split_side=split_side) layers_ext = Layers() -keyboard.extensions = [layers_ext, split, rgb] +keyboard.modules = [layers_ext, split] +keyboard.extensions = [rgb] keyboard.keymap = [ [ #QWERTY diff --git a/kmk/extensions/__init__.py b/kmk/extensions/__init__.py index 822d945..1eba5e5 100644 --- a/kmk/extensions/__init__.py +++ b/kmk/extensions/__init__.py @@ -8,12 +8,12 @@ class Extension: def enable(self, keyboard): self._enabled = True - self.on_runtime_enable(self, keyboard) + self.on_runtime_enable(keyboard) def disable(self, keyboard): self._enabled = False - self.on_runtime_disable(self, keyboard) + self.on_runtime_disable(keyboard) # The below methods should be implemented by subclasses @@ -32,7 +32,7 @@ class Extension: ''' raise NotImplementedError - def after_matrix_scan(self, keyboard, matrix_update): + def after_matrix_scan(self, keyboard): ''' Return value will be replace matrix update if supplied ''' diff --git a/kmk/extensions/international.py b/kmk/extensions/international.py index d698819..eab8087 100644 --- a/kmk/extensions/international.py +++ b/kmk/extensions/international.py @@ -31,29 +31,29 @@ class International(Extension): make_key(code=151, names=('LANG8',)) make_key(code=152, names=('LANG9',)) - def on_runtime_enable(self, keyboard): + def on_runtime_enable(self, sandbox): return - def on_runtime_disable(self, keyboard): + def on_runtime_disable(self, sandbox): return - def during_bootup(self, keyboard): + def during_bootup(self, sandbox): return - def before_matrix_scan(self, keyboard): + def before_matrix_scan(self, sandbox): return - def after_matrix_scan(self, keyboard, matrix_update): + def after_matrix_scan(self, sandbox): return - def before_hid_send(self, keyboard): + def before_hid_send(self, sandbox): return - def after_hid_send(self, keyboard): + def after_hid_send(self, sandbox): return - def on_powersave_enable(self, keyboard): + def on_powersave_enable(self, sandbox): return - def on_powersave_disable(self, keyboard): + def on_powersave_disable(self, sandbox): return diff --git a/kmk/extensions/led.py b/kmk/extensions/led.py index 52b0ac9..2149890 100644 --- a/kmk/extensions/led.py +++ b/kmk/extensions/led.py @@ -75,34 +75,33 @@ class LED(Extension): 'val': self.val, } - def on_runtime_enable(self, keyboard): + def on_runtime_enable(self, sandbox): return - def on_runtime_disable(self, keyboard): + def on_runtime_disable(self, sandbox): return - def during_bootup(self, keyboard): + def during_bootup(self, sandbox): return - def before_matrix_scan(self, keyboard): + def before_matrix_scan(self, sandbox): return - def after_matrix_scan(self, keyboard, matrix_update): + def after_matrix_scan(self, sandbox): return - def before_hid_send(self, keyboard): + def before_hid_send(self, sandbox): return - def after_hid_send(self, keyboard): + def after_hid_send(self, sandbox): if self._enabled and self.animation_mode: self.animate() - - return keyboard - - def on_powersave_enable(self, keyboard): return - def on_powersave_disable(self, keyboard): + def on_powersave_enable(self, sandbox): + return + + def on_powersave_disable(self, sandbox): return def _init_effect(self): diff --git a/kmk/extensions/media_keys.py b/kmk/extensions/media_keys.py index 916e1fd..84de64b 100644 --- a/kmk/extensions/media_keys.py +++ b/kmk/extensions/media_keys.py @@ -27,29 +27,29 @@ class MediaKeys(Extension): make_consumer_key(code=179, names=('MEDIA_FAST_FORWARD', 'MFFD')) # 0xB3 make_consumer_key(code=180, names=('MEDIA_REWIND', 'MRWD')) # 0xB4 - def on_runtime_enable(self, keyboard): + def on_runtime_enable(self, sandbox): return - def on_runtime_disable(self, keyboard): + def on_runtime_disable(self, sandbox): return - def during_bootup(self, keyboard): + def during_bootup(self, sandbox): return - def before_matrix_scan(self, keyboard): + def before_matrix_scan(self, sandbox): return - def after_matrix_scan(self, keyboard, matrix_update): + def after_matrix_scan(self, sandbox): return - def before_hid_send(self, keyboard): + def before_hid_send(self, sandbox): return - def after_hid_send(self, keyboard): + def after_hid_send(self, sandbox): return - def on_powersave_enable(self, keyboard): + def on_powersave_enable(self, sandbox): return - def on_powersave_disable(self, keyboard): + def on_powersave_disable(self, sandbox): return diff --git a/kmk/extensions/rgb.py b/kmk/extensions/rgb.py index 4b65a85..8272758 100644 --- a/kmk/extensions/rgb.py +++ b/kmk/extensions/rgb.py @@ -141,37 +141,37 @@ class RGB(Extension): on_release=handler_passthrough, ) - def on_runtime_enable(self, keyboard): + def on_runtime_enable(self, sandbox): return - def on_runtime_disable(self, keyboard): + def on_runtime_disable(self, sandbox): return - def during_bootup(self, keyboard): + def during_bootup(self, sandbox): return - def before_matrix_scan(self, keyboard): + def before_matrix_scan(self, sandbox): return - def after_matrix_scan(self, keyboard, matrix_update): + def after_matrix_scan(self, sandbox): return - def before_hid_send(self, keyboard): + def before_hid_send(self, sandbox): return - def after_hid_send(self, keyboard): + def after_hid_send(self, sandbox): if self.animation_mode: self.loopcounter += 1 if self.loopcounter >= 7: self.animate() self.loopcounter = 0 - return keyboard - - def on_powersave_enable(self, keyboard): return - def on_powersave_disable(self, keyboard): + def on_powersave_enable(self, sandbox): + return + + def on_powersave_disable(self, sandbox): self._do_update() @staticmethod diff --git a/kmk/kmk_keyboard.py b/kmk/kmk_keyboard.py index 6df6519..915b2aa 100644 --- a/kmk/kmk_keyboard.py +++ b/kmk/kmk_keyboard.py @@ -26,7 +26,13 @@ class KMKKeyboard: unicode_mode = UnicodeMode.NOOP tap_time = 300 + modules = [] extensions = [] + sandbox = { + 'matrix_update': None, + 'secondary_matrix_update': None, + 'active_layers': [0], + } ##### # Internal State @@ -298,9 +304,8 @@ class KMKKeyboard: and do an isinstance check, but instead do string detection ''' if any( - x.__class__.__module__ - in {'kmk.extensions.split', 'kmk.extensions.ble_split'} - for x in self.extensions + x.__class__.__module__ in {'kmk.modules.split', 'kmk.modules.ble_split'} + for x in self.modules ): return @@ -335,6 +340,95 @@ class KMKKeyboard: return self + def before_matrix_scan(self): + for module in self.modules: + try: + module.before_matrix_scan(self) + except Exception as err: + if self.debug_enabled: + print('Failed to run pre matrix function in module: ', err, module) + + for ext in self.extensions: + try: + ext.before_matrix_scan(self.sandbox) + except Exception as err: + if self.debug_enabled: + print('Failed to run pre matrix function in extension: ', err, ext) + + def after_matrix_scan(self): + for module in self.modules: + try: + module.after_matrix_scan(self) + except Exception as err: + if self.debug_enabled: + print('Failed to run post matrix function in module: ', err, module) + + for ext in self.extensions: + try: + ext.after_matrix_scan(self.sandbox) + except Exception as err: + if self.debug_enabled: + print('Failed to run post matrix function in extension: ', err, ext) + + def before_hid_send(self): + for module in self.modules: + try: + module.before_hid_send(self) + except Exception as err: + if self.debug_enabled: + print('Failed to run pre hid function in module: ', err, module) + + for ext in self.extensions: + try: + ext.before_hid_send(self.sandbox) + except Exception as err: + if self.debug_enabled: + print('Failed to run pre hid function in extension: ', err, ext) + + def after_hid_send(self): + for module in self.modules: + try: + module.after_hid_send(self) + except Exception as err: + if self.debug_enabled: + print('Failed to run post hid function in module: ', err, module) + + for ext in self.extensions: + try: + ext.after_hid_send(self.sandbox) + except Exception as err: + if self.debug_enabled: + print('Failed to run post hid function in extension: ', err, ext) + + def powersave_enable(self): + for module in self.modules: + try: + module.on_powersave_enable(self) + except Exception as err: + if self.debug_enabled: + print('Failed to run post hid function in module: ', err, module) + + for ext in self.extensions: + try: + ext.on_powersave_enable(self.sandbox) + except Exception as err: + if self.debug_enabled: + print('Failed to run post hid function in extension: ', err, ext) + + def powersave_disable(self): + for module in self.extensions: + try: + module.on_powersave_disable(self) + except Exception as err: + if self.debug_enabled: + print('Failed to run post hid function in module: ', err, module) + for ext in self.extensions: + try: + ext.on_powersave_disable(self.sandbox) + except Exception as err: + if self.debug_enabled: + print('Failed to run post hid function in extension: ', err, ext) + def go(self, hid_type=HIDModes.USB, **kwargs): self.hid_type = hid_type @@ -346,7 +440,8 @@ class KMKKeyboard: try: ext.during_bootup(self) except Exception: - print('Failed to load extention', ext) + if self.debug_enabled: + print('Failed to load extention', ext) self._init_matrix() @@ -354,39 +449,23 @@ class KMKKeyboard: while True: self.state_changed = False + self.sandbox.active_layers = self.active_layers - for ext in self.extensions: - try: - ret = ext.before_matrix_scan(self) - if ret is not None: - if len(ret) == 3: - # f len is 3, assume matrix update - self.secondary_matrix_update = ret - except Exception as err: - print('Failed to run pre matrix function: ', err, ext) + self.before_matrix_scan() - self.matrix_update = self.matrix.scan_for_changes() + self.matrix_update = ( + self.sandbox.matrix_update + ) = self.matrix.scan_for_changes() + self.sandbox.secondary_matrix_update = self.secondary_matrix_update - for ext in self.extensions: - try: - self._matrix_modify = ext.after_matrix_scan( - self, self.matrix_update - ) - if self._matrix_modify is not None: - self.matrix_update = self._matrix_modify - except Exception as err: - print('Failed to run post matrix function: ', err, ext) + self.after_matrix_scan() self._handle_matrix_report(self.secondary_matrix_update) self.secondary_matrix_update = None self._handle_matrix_report(self.matrix_update) self.matrix_update = None - for ext in self.extensions: - try: - ext.before_hid_send(self) - except Exception as err: - print('Failed to run pre hid function: ', err, ext) + self.before_hid_send() if self.hid_pending: self._send_hid() @@ -400,25 +479,13 @@ class KMKKeyboard: if self.hid_pending: self._send_hid() - for ext in self.extensions: - try: - ext.after_hid_send(self) - except Exception as err: - print('Failed to run post hid function: ', err, ext) + self.after_hid_send() if self._trigger_powersave_enable: - for ext in self.extensions: - try: - ext.on_powersave_enable(self) - except Exception as err: - print('Failed to run post hid function: ', err, ext) + self.powersave_enable() if self._trigger_powersave_disable: - for ext in self.extensions: - try: - ext.on_powersave_disable(self) - except Exception as err: - print('Failed to run post hid function: ', err, ext) + self.powersave_disable() if self.state_changed: self._print_debug_cycle() diff --git a/kmk/modules/__init__.py b/kmk/modules/__init__.py new file mode 100644 index 0000000..e78b6c9 --- /dev/null +++ b/kmk/modules/__init__.py @@ -0,0 +1,40 @@ +class InvalidExtensionEnvironment(Exception): + pass + + +class Module: + ''' + Modules differ from extensions in that they not only can read the state, but + are allowed to modify the state. The will be loaded on boot, and are not + allowed to be unloaded as they are required to continue functioning in a + consistant manner. + ''' + + # The below methods should be implemented by subclasses + + def during_bootup(self, keyboard): + raise NotImplementedError + + def before_matrix_scan(self, keyboard): + ''' + Return value will be injected as an extra matrix update + ''' + raise NotImplementedError + + def after_matrix_scan(self, keyboard): + ''' + Return value will be replace matrix update if supplied + ''' + raise NotImplementedError + + def before_hid_send(self, keyboard): + raise NotImplementedError + + def after_hid_send(self, keyboard): + raise NotImplementedError + + def on_powersave_enable(self, keyboard): + raise NotImplementedError + + def on_powersave_disable(self, keyboard): + raise NotImplementedError diff --git a/kmk/extensions/ble_split.py b/kmk/modules/ble_split.py similarity index 93% rename from kmk/extensions/ble_split.py rename to kmk/modules/ble_split.py index 9d26812..e549e08 100644 --- a/kmk/extensions/ble_split.py +++ b/kmk/modules/ble_split.py @@ -2,14 +2,14 @@ from adafruit_ble import BLERadio from adafruit_ble.advertising.standard import ProvideServicesAdvertisement from adafruit_ble.services.nordic import UARTService -from kmk.extensions import Extension from kmk.hid import HIDModes from kmk.kmktime import ticks_diff, ticks_ms from kmk.matrix import intify_coordinate +from kmk.modules import Module from storage import getmount -class BLE_Split(Extension): +class BLE_Split(Module): '''Enables splitting keyboards wirelessly''' def __init__( @@ -46,12 +46,6 @@ class BLE_Split(Extension): '_split_side': self.split_side, } - def on_runtime_enable(self, keyboard): - return - - def on_runtime_disable(self, keyboard): - return - def during_bootup(self, keyboard): self._debug_enabled = keyboard.debug_enabled self._ble.name = str(getmount('/').label) @@ -83,13 +77,12 @@ class BLE_Split(Extension): def before_matrix_scan(self, keyboard): self._check_all_connections() - return self._receive() + return self._receive(keyboard) - def after_matrix_scan(self, keyboard, matrix_update): - if matrix_update: - matrix_update = self._send(matrix_update) - return matrix_update - return None + def after_matrix_scan(self, keyboard): + if keyboard.matrix_update: + keyboard.matrix_update = self._send(keyboard.matrix_update) + return def before_hid_send(self, keyboard): return @@ -195,12 +188,12 @@ class BLE_Split(Extension): self._uart = None return update - def _receive(self): + def _receive(self, keyboard): if self._uart is not None and self._uart.in_waiting > 0 or self._uart_buffer: while self._uart.in_waiting >= 3: self._uart_buffer.append(self._uart.read(3)) if self._uart_buffer: - update = bytearray(self._uart_buffer.pop(0)) - return update + keyboard.secondary_matrix_update = bytearray(self._uart_buffer.pop(0)) + return return None diff --git a/kmk/extensions/layers.py b/kmk/modules/layers.py similarity index 96% rename from kmk/extensions/layers.py rename to kmk/modules/layers.py index aaf4840..69f614e 100644 --- a/kmk/extensions/layers.py +++ b/kmk/modules/layers.py @@ -1,10 +1,10 @@ '''One layer isn't enough. Adds keys to get to more of them''' from micropython import const -from kmk.extensions import Extension from kmk.key_validators import layer_key_validator from kmk.keys import make_argumented_key from kmk.kmktime import accurate_ticks, accurate_ticks_diff +from kmk.modules import Module class LayerType: @@ -18,7 +18,7 @@ class LayerType: TT = const(5) -class Layers(Extension): +class Layers(Module): '''Gives access to the keys used to enable the layer system''' def __init__(self): @@ -63,19 +63,13 @@ class Layers(Extension): on_release=self._tt_released, ) - def on_runtime_enable(self, keyboard): - return - - def on_runtime_disable(self, keyboard): - return - def during_bootup(self, keyboard): return def before_matrix_scan(self, keyboard): return - def after_matrix_scan(self, keyboard, matrix_update): + def after_matrix_scan(self, keyboard): return def before_hid_send(self, keyboard): diff --git a/kmk/extensions/modtap.py b/kmk/modules/modtap.py similarity index 61% rename from kmk/extensions/modtap.py rename to kmk/modules/modtap.py index a4ddd8f..ef0ac55 100644 --- a/kmk/extensions/modtap.py +++ b/kmk/modules/modtap.py @@ -1,10 +1,10 @@ -from kmk.extensions import Extension from kmk.key_validators import mod_tap_validator from kmk.keys import make_argumented_key from kmk.kmktime import accurate_ticks, accurate_ticks_diff +from kmk.modules import Module -class ModTap(Extension): +class ModTap(Module): def __init__(self): self._mod_tap_timer = None make_argumented_key( @@ -14,19 +14,13 @@ class ModTap(Extension): on_release=self.mt_released, ) - def on_runtime_enable(self, keyboard): - return - - def on_runtime_disable(self, keyboard): - return - def during_bootup(self, keyboard): return def before_matrix_scan(self, keyboard): return - def after_matrix_scan(self, keyboard, matrix_update): + def after_matrix_scan(self, keyboard): return def before_hid_send(self, keyboard): @@ -41,21 +35,23 @@ class ModTap(Extension): def on_powersave_disable(self, keyboard): return - def mt_pressed(self, key, state, *args, **kwargs): + def mt_pressed(self, key, keyboard, *args, **kwargs): '''Sets the timer start and acts like a modifier otherwise''' - state.keys_pressed.add(key.meta.mods) + keyboard.keys_pressed.add(key.meta.mods) self._mod_tap_timer = accurate_ticks() - return state + return keyboard - def mt_released(self, key, state, *args, **kwargs): + def mt_released(self, key, keyboard, *args, **kwargs): ''' On keyup, check timer, and press key if needed.''' - state.keys_pressed.discard(key.meta.mods) + keyboard.keys_pressed.discard(key.meta.mods) if self._mod_tap_timer and ( - accurate_ticks_diff(accurate_ticks(), self._mod_tap_timer, state.tap_time) + accurate_ticks_diff( + accurate_ticks(), self._mod_tap_timer, keyboard.tap_time + ) ): - state.hid_pending = True - state.tap_key(key.meta.kc) + keyboard.hid_pending = True + keyboard.tap_key(key.meta.kc) self._mod_tap_timer = None - return state + return keyboard diff --git a/kmk/extensions/power.py b/kmk/modules/power.py similarity index 95% rename from kmk/extensions/power.py rename to kmk/modules/power.py index 90c925c..93bbc41 100644 --- a/kmk/extensions/power.py +++ b/kmk/modules/power.py @@ -1,13 +1,13 @@ import board import digitalio -from kmk.extensions import Extension from kmk.handlers.stock import passthrough as handler_passthrough from kmk.keys import make_key from kmk.kmktime import sleep_ms, ticks_diff, ticks_ms +from kmk.modules import Module -class Power(Extension): +class Power(Module): def __init__(self, powersave_pin=None): self.enable = False self.powersave_pin = powersave_pin # Powersave pin board object @@ -39,15 +39,8 @@ class Power(Extension): '_psp': self._psp, } - def on_runtime_enable(self, keyboard): - return - - def on_runtime_disable(self, keyboard): - self.disable_powersave() - def during_bootup(self, keyboard): self._i2c_scan() - return def before_matrix_scan(self, keyboard): return @@ -55,7 +48,6 @@ class Power(Extension): def after_matrix_scan(self, keyboard, matrix_update): if matrix_update or keyboard.secondary_matrix_update: self.psave_time_reset() - return def before_hid_send(self, keyboard): return diff --git a/kmk/extensions/split.py b/kmk/modules/split.py similarity index 88% rename from kmk/extensions/split.py rename to kmk/modules/split.py index 9529dde..878862b 100644 --- a/kmk/extensions/split.py +++ b/kmk/modules/split.py @@ -1,7 +1,7 @@ import busio -from kmk.extensions import Extension from kmk.matrix import intify_coordinate +from kmk.modules import Module from storage import getmount @@ -11,7 +11,7 @@ class SplitType: ONEWIRE = 3 # unused -class Split(Extension): +class Split(Module): def __init__( self, is_target=True, @@ -40,12 +40,6 @@ class Split(Extension): self.uart_pin2 = uart_pin2 self.uart_timeout = uart_timeout - def on_runtime_enable(self, keyboard): - return - - def on_runtime_disable(self, keyboard): - return - def during_bootup(self, keyboard): try: # Working around https://github.com/adafruit/circuitpython/issues/1769 @@ -94,12 +88,12 @@ class Split(Extension): def before_matrix_scan(self, keyboard): if self._is_target or self.uart_pin2: - return self._receive() + return self._receive(keyboard) return None - def after_matrix_scan(self, keyboard, matrix_update): - if matrix_update is not None and not self._is_target: - self._send(matrix_update) + def after_matrix_scan(self, keyboard): + if keyboard.matrix_update is not None and not self._is_target: + self._send(keyboard.matrix_update) def before_hid_send(self, keyboard): return @@ -121,7 +115,7 @@ class Split(Extension): if self._uart is not None: self._uart.write(update) - def _receive(self): + def _receive(self, keyboard): if self._uart is not None and self._uart.in_waiting > 0 or self._uart_buffer: if self._uart.in_waiting >= 60: # This is a dirty hack to prevent crashes in unrealistic cases @@ -132,8 +126,8 @@ class Split(Extension): while self._uart.in_waiting >= 3: self._uart_buffer.append(self._uart.read(3)) if self._uart_buffer: - update = bytearray(self._uart_buffer.pop(0)) + keyboard.secondary_matrix_update = bytearray(self._uart_buffer.pop(0)) - return update + return return None