9bec905fce
Wow, what a trip this was. Layer support is now fully implemented. Other changes here mostly revolve around the event dispatching model: more floating state (hidden in clases wherever) has been purged, with the reducer (now mutable, comments inline) serving, as it should, as the sole source of truth. Thunk support has been added to our fake Redux clone, allowing Action Creators to handle sequences of events (which is arguably a cleaner way of handling matrix changes when not all matrix changes should result in a new HID report - in the case of internal keys). A whole class has been deprecated (Keymap) which only served as another arbitor of state: instead, the MatrixScanner has been made smarter and handles diffing internally, dispatching an Action when needed (and allowing the reducer to parse the keymap and figure out what key is pressed - this is the infinitely cleaner solution when layers come into play).
70 lines
2.4 KiB
Python
70 lines
2.4 KiB
Python
import machine
|
|
|
|
from kmk.common.abstract.matrix_scanner import AbstractMatrixScanner
|
|
from kmk.common.consts import DiodeOrientation
|
|
from kmk.common.event_defs import matrix_changed
|
|
|
|
|
|
class MatrixScanner(AbstractMatrixScanner):
|
|
def __init__(self, cols, rows, active_layers, diode_orientation=DiodeOrientation.COLUMNS):
|
|
# A pin cannot be both a row and column, detect this by combining the
|
|
# two tuples into a set and validating that the length did not drop
|
|
#
|
|
# repr() hackery is because MicroPython Pin objects are not hashable.
|
|
# Technically we support passing either a string (hashable) or the
|
|
# Pin object directly here, so the hackaround is necessary.
|
|
unique_pins = {repr(c) for c in cols} | {repr(r) for r in rows}
|
|
if len(unique_pins) != len(cols) + len(rows):
|
|
raise ValueError('Cannot use a pin as both a column and row')
|
|
|
|
self.cols = [machine.Pin(pin) for pin in cols]
|
|
self.rows = [machine.Pin(pin) for pin in rows]
|
|
self.diode_orientation = diode_orientation
|
|
self.active_layers = active_layers
|
|
|
|
if self.diode_orientation == DiodeOrientation.COLUMNS:
|
|
self.outputs = self.cols
|
|
self.inputs = self.rows
|
|
elif self.diode_orientation == DiodeOrientation.ROWS:
|
|
self.outputs = self.rows
|
|
self.inputs = self.cols
|
|
else:
|
|
raise ValueError('Invalid DiodeOrientation: {}'.format(
|
|
self.diode_orientation,
|
|
))
|
|
|
|
for pin in self.outputs:
|
|
pin.init(machine.Pin.OUT)
|
|
pin.off()
|
|
|
|
for pin in self.inputs:
|
|
pin.init(machine.Pin.IN, machine.Pin.PULL_DOWN)
|
|
pin.off()
|
|
|
|
def _normalize_matrix(self, matrix):
|
|
return super()._normalize_matrix(matrix)
|
|
|
|
def raw_scan(self):
|
|
matrix = []
|
|
|
|
for opin in self.outputs:
|
|
opin.value(1)
|
|
matrix.append([bool(ipin.value()) for ipin in self.inputs])
|
|
opin.value(0)
|
|
|
|
return self._normalize_matrix(matrix)
|
|
|
|
def scan_for_changes(self, old_matrix):
|
|
matrix = self.raw_scan()
|
|
|
|
if any(
|
|
any(
|
|
col != old_matrix[ridx][cidx]
|
|
for cidx, col in enumerate(row)
|
|
)
|
|
for ridx, row in enumerate(matrix)
|
|
):
|
|
return matrix_changed(matrix)
|
|
|
|
return None # The default, but for explicitness
|