diff --git a/kmk/key_validators.py b/kmk/key_validators.py index e150412..52625ab 100644 --- a/kmk/key_validators.py +++ b/kmk/key_validators.py @@ -1,3 +1,5 @@ +from typing import List, Optional, Tuple +from kmk.keys import Key from kmk.types import ( KeySeqSleepMeta, LayerKeyMeta, @@ -11,7 +13,7 @@ def key_seq_sleep_validator(ms: float) -> KeySeqSleepMeta: return KeySeqSleepMeta(ms) -def layer_key_validator(layer, kc=None): +def layer_key_validator(layer: int, kc: Key = None) -> LayerKeyMeta: ''' Validates the syntax (but not semantics) of a layer key call. We won't have access to the keymap here, so we can't verify much of anything useful @@ -22,16 +24,16 @@ def layer_key_validator(layer, kc=None): return LayerKeyMeta(layer=layer, kc=kc) -def mod_tap_validator(kc, mods=None): +def mod_tap_validator(kc: Key, mods: Optional[List[Key]] = None) -> ModTapKeyMeta: ''' Validates that mod tap keys are correctly used ''' return ModTapKeyMeta(kc=kc, mods=mods) -def tap_dance_key_validator(*codes): +def tap_dance_key_validator(*codes: Key) -> TapDanceKeyMeta: return TapDanceKeyMeta(codes) -def unicode_mode_key_validator(mode): +def unicode_mode_key_validator(mode: int) -> UnicodeModeKeyMeta: return UnicodeModeKeyMeta(mode) diff --git a/kmk/kmk_keyboard.py b/kmk/kmk_keyboard.py index acb199c..60a0d08 100644 --- a/kmk/kmk_keyboard.py +++ b/kmk/kmk_keyboard.py @@ -1,73 +1,77 @@ +from __future__ import annotations + +from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type, Union + from kmk.consts import KMK_RELEASE, UnicodeMode -from kmk.hid import BLEHID, USBHID, AbstractHID, HIDModes -from kmk.keys import KC +from kmk.hid import AbstractHID, BLEHID, USBHID, HIDModes +from kmk.keys import KC, Key, KeyAttrDict from kmk.kmktime import ticks_ms from kmk.matrix import MatrixScanner, intify_coordinate from kmk.types import TapDanceKeyMeta class Sandbox: - matrix_update = None - secondary_matrix_update = None - active_layers = None + matrix_update: Optional[bytearray] = None + secondary_matrix_update: Optional[bytearray] = None + active_layers: Optional[List[int]] = None class KMKKeyboard: ##### # User-configurable - debug_enabled = False + debug_enabled: bool = False - keymap = [] - coord_mapping = None + keymap: List[KeyAttrDict] = [] + coord_mapping: Optional[List[int]] = None - row_pins = None - col_pins = None - diode_orientation = None - matrix = None - matrix_scanner = MatrixScanner - uart_buffer = [] + row_pins: Optional[Tuple[Any, ...]] = None + col_pins: Optional[Tuple[Any, ...]] = None + diode_orientation: Optional[int] = None + matrix: Optional[MatrixScanner] = None + matrix_scanner: Type[MatrixScanner] = MatrixScanner + uart_buffer: List[Any] = [] - unicode_mode = UnicodeMode.NOOP - tap_time = 300 + unicode_mode: int = UnicodeMode.NOOP + tap_time: int = 300 - modules = [] - extensions = [] - sandbox = Sandbox() + modules: List[Type[Any]] = [] + extensions: List[Type[Any]] = [] + sandbox: Sandbox = Sandbox() ##### # Internal State - keys_pressed = set() - _coordkeys_pressed = {} - hid_type = HIDModes.USB - secondary_hid_type = None - _hid_helper = None - hid_pending = False - state_layer_key = None - matrix_update = None - secondary_matrix_update = None - _matrix_modify = None - state_changed = False - _old_timeouts_len = None - _new_timeouts_len = None - _trigger_powersave_enable = False - _trigger_powersave_disable = False - i2c_deinit_count = 0 + keys_pressed: Set[Key] = set() + _coordkeys_pressed: Dict[Any, Any] = {} + hid_type: int = HIDModes.USB + secondary_hid_type: Optional[int] = None + _hid_helper: Optional[Union[Type[AbstractHID], Type[BLEHID], Type[USBHID]]] = None + hid_pending: bool = False + state_layer_key: Optional[Key] = None + matrix_update: Optional[Union[bytearray, None]] = None + secondary_matrix_update: Optional[Union[bytearray, None]] = None + _matrix_modify: Optional[Any] = None + state_changed: bool = False + _old_timeouts_len: Optional[int] = None + _new_timeouts_len: Optional[int] = None + _trigger_powersave_enable: bool = False + _trigger_powersave_disable: bool = False + i2c_deinit_count: int = 0 # this should almost always be PREpended to, replaces # former use of reversed_active_layers which had pointless # overhead (the underlying list was never used anyway) - active_layers = [0] + active_layers: List[int] = [0] - _timeouts = {} - _tapping = False - _tap_dance_counts = {} - _tap_side_effects = {} + _timeouts: Dict[float, Callable[[], Key]] = {} + _tapping: bool = False + _tap_dance_counts: Dict[Union[Key, TapDanceKeyMeta], Union[int, None]] = {} + _tap_side_effects: Dict[Union[Key, TapDanceKeyMeta], Union[Key, None]] = {} # on some M4 setups (such as klardotsh/klarank_feather_m4, CircuitPython # 6.0rc1) this runs out of RAM every cycle and takes down the board. no # real known fix yet other than turning off debug, but M4s have always been # tight on RAM so.... - def __repr__(self): + def __repr__(self) -> str: return ( 'KMKKeyboard(' 'debug_enabled={} ' @@ -103,22 +107,22 @@ class KMKKeyboard: self._tap_side_effects, ) - def _print_debug_cycle(self, init=False): + def _print_debug_cycle(self, init: bool = False) -> None: if self.debug_enabled: if init: print('KMKInit(release={})'.format(KMK_RELEASE)) print(self) - def _send_hid(self): + def _send_hid(self) -> None: self._hid_helper.create_report(self.keys_pressed).send() self.hid_pending = False - def _handle_matrix_report(self, update=None): + def _handle_matrix_report(self, update: bytearray = None) -> None: if update is not None: self._on_matrix_changed(update[0], update[1], update[2]) self.state_changed = True - def _find_key_in_map(self, int_coord, row, col): + def _find_key_in_map(self, int_coord: int, row: int, col: int) -> Union[Key, None]: self.state_layer_key = None try: idx = self.coord_mapping.index(int_coord) @@ -143,7 +147,7 @@ class KMKKeyboard: return self.state_layer_key - def _on_matrix_changed(self, row, col, is_pressed): + def _on_matrix_changed(self, row: int, col: int, is_pressed: int) -> KMKKeyboard: if self.debug_enabled: print('MatrixChange(col={} row={} pressed={})'.format(col, row, is_pressed)) @@ -156,7 +160,7 @@ class KMKKeyboard: return self.process_key(kc_changed, is_pressed, int_coord, (row, col)) - def process_key(self, key, is_pressed, coord_int=None, coord_raw=None): + def process_key(self, key: Union[Key, TapDanceKeyMeta], is_pressed: int, coord_int: Optional[int] = None, coord_raw: Tuple[int, int] = None) -> KMKKeyboard: if self._tapping and not isinstance(key.meta, TapDanceKeyMeta): self._process_tap_dance(key, is_pressed) else: @@ -167,22 +171,22 @@ class KMKKeyboard: return self - def remove_key(self, keycode): + def remove_key(self, keycode: Key) -> KMKKeyboard: self.keys_pressed.discard(keycode) return self.process_key(keycode, False) - def add_key(self, keycode): + def add_key(self, keycode: Key) -> KMKKeyboard: self.keys_pressed.add(keycode) return self.process_key(keycode, True) - def tap_key(self, keycode): + def tap_key(self, keycode: Key) -> KMKKeyboard: self.add_key(keycode) # On the next cycle, we'll remove the key. self.set_timeout(False, lambda: self.remove_key(keycode)) return self - def _process_tap_dance(self, changed_key, is_pressed): + def _process_tap_dance(self, changed_key: Union[Key, TapDanceKeyMeta], is_pressed: int) -> KMKKeyboard: if is_pressed: if not isinstance(changed_key.meta, TapDanceKeyMeta): # If we get here, changed_key is not a TapDanceKey and thus @@ -219,7 +223,7 @@ class KMKKeyboard: return self - def _end_tap_dance(self, td_key): + def _end_tap_dance(self, td_key: Union[Key, TapDanceKeyMeta]) -> KMKKeyboard: v = self._tap_dance_counts[td_key] - 1 if v >= 0: @@ -240,12 +244,12 @@ class KMKKeyboard: return self - def _cleanup_tap_dance(self, td_key): + def _cleanup_tap_dance(self, td_key: Union[Key, TapDanceKeyMeta]) -> KMKKeyboard: self._tap_dance_counts[td_key] = 0 self._tapping = any(count > 0 for count in self._tap_dance_counts.values()) return self - def set_timeout(self, after_ticks, callback): + def set_timeout(self, after_ticks: float, callback: Callable[[], Key]) -> float: if after_ticks is False: # We allow passing False as an implicit "run this on the next process timeouts cycle" timeout_key = ticks_ms() @@ -258,11 +262,11 @@ class KMKKeyboard: self._timeouts[timeout_key] = callback return timeout_key - def _cancel_timeout(self, timeout_key): + def _cancel_timeout(self, timeout_key: float) -> None: if timeout_key in self._timeouts: del self._timeouts[timeout_key] - def _process_timeouts(self): + def _process_timeouts(self) -> KMKKeyboard: if not self._timeouts: return self @@ -279,7 +283,7 @@ class KMKKeyboard: return self - def _init_sanity_check(self): + def _init_sanity_check(self) -> KMKKeyboard: ''' Ensure the provided configuration is *probably* bootable ''' @@ -293,7 +297,7 @@ class KMKKeyboard: return self - def _init_coord_mapping(self): + def _init_coord_mapping(self) -> None: ''' Attempt to sanely guess a coord_mapping if one is not provided. No-op if `kmk.extensions.split.Split` is used, it provides equivalent @@ -315,7 +319,7 @@ class KMKKeyboard: for cidx in range(cols_to_calc): self.coord_mapping.append(intify_coordinate(ridx, cidx)) - def _init_hid(self): + def _init_hid(self) -> None: if self.hid_type == HIDModes.NOOP: self._hid_helper = AbstractHID elif self.hid_type == HIDModes.USB: @@ -326,7 +330,7 @@ class KMKKeyboard: self._hid_helper = AbstractHID self._hid_helper = self._hid_helper() - def _init_matrix(self): + def _init_matrix(self) -> KMKKeyboard: self.matrix = MatrixScanner( cols=self.col_pins, rows=self.row_pins, @@ -336,7 +340,7 @@ class KMKKeyboard: return self - def before_matrix_scan(self): + def before_matrix_scan(self) -> None: for module in self.modules: try: module.before_matrix_scan(self) @@ -351,7 +355,7 @@ class KMKKeyboard: if self.debug_enabled: print('Failed to run pre matrix function in extension: ', err, ext) - def after_matrix_scan(self): + def after_matrix_scan(self) -> None: for module in self.modules: try: module.after_matrix_scan(self) @@ -366,7 +370,7 @@ class KMKKeyboard: if self.debug_enabled: print('Failed to run post matrix function in extension: ', err, ext) - def before_hid_send(self): + def before_hid_send(self) -> None: for module in self.modules: try: module.before_hid_send(self) @@ -381,7 +385,7 @@ class KMKKeyboard: if self.debug_enabled: print('Failed to run pre hid function in extension: ', err, ext) - def after_hid_send(self): + def after_hid_send(self) -> None: for module in self.modules: try: module.after_hid_send(self) @@ -396,7 +400,7 @@ class KMKKeyboard: if self.debug_enabled: print('Failed to run post hid function in extension: ', err, ext) - def powersave_enable(self): + def powersave_enable(self) -> None: for module in self.modules: try: module.on_powersave_enable(self) @@ -411,7 +415,7 @@ class KMKKeyboard: if self.debug_enabled: print('Failed to run post hid function in extension: ', err, ext) - def powersave_disable(self): + def powersave_disable(self) -> None: for module in self.modules: try: module.on_powersave_disable(self) @@ -425,7 +429,7 @@ class KMKKeyboard: if self.debug_enabled: print('Failed to run post hid function in extension: ', err, ext) - def go(self, hid_type=HIDModes.USB, secondary_hid_type=None, **kwargs): + def go(self, hid_type: int = HIDModes.USB, secondary_hid_type: Optional[int] = None, **kwargs: Dict[Any, Any]) -> None: self.hid_type = hid_type self.secondary_hid_type = secondary_hid_type diff --git a/kmk/modules/encoder.py b/kmk/modules/encoder.py index e5f0d30..61d6e3e 100644 --- a/kmk/modules/encoder.py +++ b/kmk/modules/encoder.py @@ -2,14 +2,14 @@ import digitalio from typing import Any, ClassVar, Dict, List, Optional, Tuple, Union -from kmk.keys import KeyAttrDict +from kmk.keys import Key from kmk.kmk_keyboard import KMKKeyboard from kmk.kmktime import ticks_ms from kmk.modules import Module EncoderMap = Tuple[ - List[Tuple[KeyAttrDict, KeyAttrDict, int]], - List[Tuple[KeyAttrDict, KeyAttrDict, int]], + List[Tuple[Key, Key, int]], + List[Tuple[Key, Key, int]], List[Tuple[None, None, int]], ] diff --git a/kmk/types.py b/kmk/types.py index a2a0062..bd8e454 100644 --- a/kmk/types.py +++ b/kmk/types.py @@ -1,7 +1,6 @@ from typing import List, Optional, Tuple -from kmk.consts import UnicodeMode -from kmk.keys import KeyAttrDict +from kmk.keys import Key class AttrDict(dict): @@ -18,20 +17,20 @@ class AttrDict(dict): class LayerKeyMeta: - def __init__(self, layer: int, kc: Optional[KeyAttrDict] = None) -> None: + def __init__(self, layer: int, kc: Optional[Key] = None) -> None: self.layer: int = layer - self.kc: Optional[KeyAttrDict] = kc + self.kc: Optional[Key] = kc class ModTapKeyMeta: - def __init__(self, kc: Optional[KeyAttrDict] = None, mods: Optional[List[KeyAttrDict]] = None) -> None: - self.mods: Optional[List[KeyAttrDict]] = mods - self.kc: Optional[KeyAttrDict] = kc + def __init__(self, kc: Optional[Key] = None, mods: Optional[List[Key]] = None) -> None: + self.mods: Optional[List[Key]] = mods + self.kc: Optional[Key] = kc class KeySequenceMeta: - def __init__(self, seq: List[KeyAttrDict]): - self.seq: List[KeyAttrDict] = seq + def __init__(self, seq: List[Key]): + self.seq: List[Key] = seq class KeySeqSleepMeta: @@ -40,10 +39,10 @@ class KeySeqSleepMeta: class UnicodeModeKeyMeta: - def __init__(self, mode: UnicodeMode): - self.mode = mode + def __init__(self, mode: int): + self.mode: int = mode class TapDanceKeyMeta: - def __init__(self, codes: Tuple[KeyAttrDict, ...]): - self.codes = codes + def __init__(self, codes: Tuple[Key, ...]): + self.codes: Tuple[Key, ...] = codes