From ffd47c478fa49b8afb20ee4fcdc03e7e0ad40940 Mon Sep 17 00:00:00 2001 From: Josh Klar Date: Mon, 3 Sep 2018 15:21:34 -0700 Subject: [PATCH] Move all remaining state into the single store, woot! --- kmk/common/event_defs.py | 19 ++++++- kmk/common/internal_state.py | 104 ++++++++++++++++++++++++++++------- kmk/common/keymap.py | 22 +++++--- kmk/firmware.py | 28 +++++++++- 4 files changed, 139 insertions(+), 34 deletions(-) diff --git a/kmk/common/event_defs.py b/kmk/common/event_defs.py index 12cb1de..04a1f7a 100644 --- a/kmk/common/event_defs.py +++ b/kmk/common/event_defs.py @@ -2,17 +2,32 @@ from micropython import const KEY_UP_EVENT = const(1) KEY_DOWN_EVENT = const(2) +INIT_FIRMWARE_EVENT = const(3) -def key_up_event(keycode): +def init_firmware(keymap, row_pins, col_pins, diode_orientation): + return { + 'type': INIT_FIRMWARE_EVENT, + 'keymap': keymap, + 'row_pins': row_pins, + 'col_pins': col_pins, + 'diode_orientation': diode_orientation, + } + + +def key_up_event(keycode, row, col): return { 'type': KEY_UP_EVENT, 'keycode': keycode, + 'row': row, + 'col': col, } -def key_down_event(keycode): +def key_down_event(keycode, row, col): return { 'type': KEY_DOWN_EVENT, 'keycode': keycode, + 'row': row, + 'col': col, } diff --git a/kmk/common/internal_state.py b/kmk/common/internal_state.py index 0a408ed..a7790b0 100644 --- a/kmk/common/internal_state.py +++ b/kmk/common/internal_state.py @@ -1,6 +1,9 @@ import logging +import sys -from kmk.common.event_defs import KEY_DOWN_EVENT, KEY_UP_EVENT +from kmk.common.consts import DiodeOrientation +from kmk.common.event_defs import (INIT_FIRMWARE_EVENT, KEY_DOWN_EVENT, + KEY_UP_EVENT) class ReduxStore: @@ -9,38 +12,69 @@ class ReduxStore: self.logger = logging.getLogger(__name__) self.logger.setLevel(log_level) self.state = self.reducer(logger=self.logger) + self.callbacks = [] def dispatch(self, action): self.logger.debug('Dispatching action: {}'.format(action)) self.state = self.reducer(self.state, action) self.logger.debug('Dispatching complete: {}'.format(action)) + self.logger.debug('Calling subscriptions') + + for cb in self.callbacks: + if cb is not None: + try: + cb(self.state, action) + except Exception as e: + self.logger.error('Callback failed, moving on') + print(sys.print_exception(e), file=sys.stderr) + + self.logger.debug('Callbacks complete') + def get_state(self): return self.state + def subscribe(self, callback): + self.callbacks.append(callback) + return len(self.callbacks) - 1 + + def unsubscribe(self, idx): + self.callbacks[idx] = None + class InternalState: modifiers_pressed = frozenset() keys_pressed = frozenset() + keymap = [] + row_pins = [] + col_pins = [] + matrix = [] + diode_orientation = DiodeOrientation.COLUMNS + + @property + def __dict__(self): + return { + 'keys_pressed': self.keys_pressed, + 'modifiers_pressed': self.modifiers_pressed, + 'keymap': self.keymap, + 'col_pins': self.col_pins, + 'row_pins': self.row_pins, + 'diode_orientation': self.diode_orientation, + } def __repr__(self): - return 'InternalState(mods={}, keys={})'.format( - self.modifiers_pressed, - self.keys_pressed, - ) + return 'InternalState({})'.format(self.__dict__) - def copy(self, modifiers_pressed=None, keys_pressed=None): + def copy(self, **kwargs): new_state = InternalState() - if modifiers_pressed is None: - new_state.modifiers_pressed = self.modifiers_pressed.copy() - else: - new_state.modifiers_pressed = modifiers_pressed + for k, v in self.__dict__.items(): + if hasattr(new_state, k): + setattr(new_state, k, v) - if keys_pressed is None: - new_state.keys_pressed = self.keys_pressed.copy() - else: - new_state.keys_pressed = keys_pressed + for k, v in kwargs.items(): + if hasattr(new_state, k): + setattr(new_state, k, v) return new_state @@ -59,11 +93,41 @@ def kmk_reducer(state=None, action=None, logger=None): return state if action['type'] == KEY_UP_EVENT: - return state.copy(keys_pressed=frozenset( - key for key in state.keys_pressed if key != action['keycode'] - )) + return state.copy( + keys_pressed=frozenset( + key for key in state.keys_pressed if key != action['keycode'] + ), + matrix=[ + r if ridx != action['row'] else [ + c if cidx != action['col'] else False + for cidx, c in enumerate(r) + ] + for ridx, r in enumerate(state.matrix) + ], + ) if action['type'] == KEY_DOWN_EVENT: - return state.copy(keys_pressed=( - state.keys_pressed | {action['keycode']} - )) + return state.copy( + keys_pressed=( + state.keys_pressed | {action['keycode']} + ), + matrix=[ + r if ridx != action['row'] else [ + c if cidx != action['col'] else True + for cidx, c in enumerate(r) + ] + for ridx, r in enumerate(state.matrix) + ], + ) + + if action['type'] == INIT_FIRMWARE_EVENT: + return state.copy( + keymap=action['keymap'], + row_pins=action['row_pins'], + col_pins=action['col_pins'], + diode_orientation=action['diode_orientation'], + matrix=[ + [False for c in action['col_pins']] + for r in action['row_pins'] + ], + ) diff --git a/kmk/common/keymap.py b/kmk/common/keymap.py index da018ee..c135552 100644 --- a/kmk/common/keymap.py +++ b/kmk/common/keymap.py @@ -4,18 +4,22 @@ from kmk.common.event_defs import key_down_event, key_up_event class Keymap: def __init__(self, map): self.map = map - self.state = [ - [False for _ in row] - for row in self.map - ] def parse(self, matrix, store): + state = store.get_state() + for ridx, row in enumerate(matrix): for cidx, col in enumerate(row): - if col != self.state[ridx][cidx]: + if col != state.matrix[ridx][cidx]: if col: - store.dispatch(key_down_event(self.map[ridx][cidx])) + store.dispatch(key_down_event( + row=ridx, + col=cidx, + keycode=self.map[ridx][cidx], + )) else: - store.dispatch(key_up_event(self.map[ridx][cidx])) - - self.state = matrix + store.dispatch(key_up_event( + row=ridx, + col=cidx, + keycode=self.map[ridx][cidx], + )) diff --git a/kmk/firmware.py b/kmk/firmware.py index b9071fa..907919c 100644 --- a/kmk/firmware.py +++ b/kmk/firmware.py @@ -1,5 +1,6 @@ import logging +from kmk.common.event_defs import init_firmware from kmk.common.internal_state import ReduxStore, kmk_reducer from kmk.common.keymap import Keymap @@ -14,10 +15,31 @@ class Firmware: self, keymap, row_pins, col_pins, diode_orientation, log_level=logging.NOTSET, ): - self.raw_keymap = keymap - self.keymap = Keymap(keymap) - self.matrix = MatrixScanner(col_pins, row_pins, diode_orientation) + self.cached_state = None self.store = ReduxStore(kmk_reducer, log_level=log_level) + self.store.subscribe( + lambda state, action: self._subscription(state, action), + ) + self.store.dispatch(init_firmware( + keymap=keymap, + row_pins=row_pins, + col_pins=col_pins, + diode_orientation=diode_orientation, + )) + + def _subscription(self, state, action): + if self.cached_state is None or self.cached_state.keymap != state.keymap: + self.keymap = Keymap(state.keymap) + + if self.cached_state is None or any( + getattr(self.cached_state, k) != getattr(state, k) + for k in state.__dict__.keys() + ): + self.matrix = MatrixScanner( + state.col_pins, + state.row_pins, + state.diode_orientation, + ) def go(self): while True: