From 7fe461d5375521136cb7c234523851191f771b34 Mon Sep 17 00:00:00 2001 From: Kyle Brown Date: Fri, 30 Oct 2020 15:43:16 -0700 Subject: [PATCH] massive cleanup --- kmk/extensions/__init__.py | 14 ++-- kmk/extensions/international.py | 24 ++++++ kmk/extensions/layers.py | 132 +++++++++++++++++++------------- kmk/extensions/leader.py | 58 +++++++++----- kmk/extensions/led.py | 28 +++++-- kmk/extensions/media_keys.py | 21 +++++ kmk/extensions/modtap.py | 55 +++++++++++++ kmk/extensions/power.py | 99 ++++++++++++++++++------ kmk/extensions/rgb.py | 77 +++++-------------- kmk/extensions/split.py | 17 +++- kmk/handlers/modtap.py | 23 ------ kmk/handlers/sequences.py | 16 ++-- kmk/handlers/stock.py | 68 +++++++--------- kmk/keys.py | 4 +- kmk/kmk_keyboard.py | 106 ++++++++++++------------- 15 files changed, 445 insertions(+), 297 deletions(-) create mode 100644 kmk/extensions/modtap.py delete mode 100644 kmk/handlers/modtap.py diff --git a/kmk/extensions/__init__.py b/kmk/extensions/__init__.py index ba76d6a..d3cbde1 100644 --- a/kmk/extensions/__init__.py +++ b/kmk/extensions/__init__.py @@ -18,28 +18,28 @@ class Extension: # The below methods should be implemented by subclasses def on_runtime_enable(self, keyboard): - pass + raise NotImplementedError def on_runtime_disable(self, keyboard): - pass + raise NotImplementedError def during_bootup(self, keyboard): - pass + raise NotImplementedError def before_matrix_scan(self, keyboard): ''' Return value will be injected as an extra matrix update ''' - pass + raise NotImplementedError def after_matrix_scan(self, keyboard, matrix_update): ''' Return value will be replace matrix update if supplied ''' - pass + raise NotImplementedError def before_hid_send(self, keyboard): - pass + raise NotImplementedError def after_hid_send(self, keyboard): - pass + raise NotImplementedError diff --git a/kmk/extensions/international.py b/kmk/extensions/international.py index 59fd037..8b41831 100644 --- a/kmk/extensions/international.py +++ b/kmk/extensions/international.py @@ -1,8 +1,11 @@ +'''Adds international keys''' from kmk.extensions import Extension from kmk.keys import make_key class International(Extension): + '''Adds international keys''' + def __init__(self): # International make_key(code=50, names=('NONUS_HASH', 'NUHS')) @@ -27,3 +30,24 @@ class International(Extension): make_key(code=150, names=('LANG7',)) make_key(code=151, names=('LANG8',)) make_key(code=152, names=('LANG9',)) + + 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): + return + + def before_hid_send(self, keyboard): + return + + def after_hid_send(self, keyboard): + return diff --git a/kmk/extensions/layers.py b/kmk/extensions/layers.py index 8cd7321..9dd7456 100644 --- a/kmk/extensions/layers.py +++ b/kmk/extensions/layers.py @@ -1,14 +1,15 @@ +'''One layer isn't enough. Adds keys to get to more of them''' from micropython import const -import kmk.handlers.modtap as modtap from kmk.extensions import Extension -from kmk.key_validators import layer_key_validator, mod_tap_validator +from kmk.key_validators import layer_key_validator from kmk.keys import make_argumented_key from kmk.kmktime import accurate_ticks, accurate_ticks_diff class LayerType: - # These number must be reserved for layer timers. + '''Defines layer type values for readability''' + MO = const(0) DF = const(1) LM = const(2) @@ -18,47 +19,42 @@ class LayerType: class Layers(Extension): + '''Gives access to the keys used to enable the layer system''' + def __init__(self): # Layers make_argumented_key( validator=layer_key_validator, names=('MO',), - on_press=self.mo_pressed, - on_release=self.mo_released, + on_press=self._mo_pressed, + on_release=self._mo_released, ) make_argumented_key( - validator=layer_key_validator, names=('DF',), on_press=self.df_pressed + validator=layer_key_validator, names=('DF',), on_press=self._df_pressed ) make_argumented_key( validator=layer_key_validator, names=('LM',), - on_press=self.lm_pressed, - on_release=self.lm_released, + on_press=self._lm_pressed, + on_release=self._lm_released, ) make_argumented_key( validator=layer_key_validator, names=('LT',), - on_press=self.lt_pressed, - on_release=self.lt_released, + on_press=self._lt_pressed, + on_release=self._lt_released, ) make_argumented_key( - validator=layer_key_validator, names=('TG',), on_press=self.tg_pressed + validator=layer_key_validator, names=('TG',), on_press=self._tg_pressed ) make_argumented_key( - validator=layer_key_validator, names=('TO',), on_press=self.to_pressed + validator=layer_key_validator, names=('TO',), on_press=self._to_pressed ) make_argumented_key( validator=layer_key_validator, names=('TT',), - on_press=self.tt_pressed, - on_release=self.tt_released, - ) - - make_argumented_key( - validator=mod_tap_validator, - names=('MT',), - on_press=modtap.mt_pressed, - on_release=modtap.mt_released, + on_press=self._tt_pressed, + on_release=self._tt_released, ) start_time = { @@ -68,21 +64,45 @@ class Layers(Extension): LayerType.LM: None, } - def df_pressed(self, key, state, *args, **kwargs): + 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): + return + + def before_hid_send(self, keyboard): + return + + def _after_hid_send(self, keyboard): + return + + @staticmethod + def _df_pressed(key, state, *args, **kwargs): ''' Switches the default layer ''' - state._active_layers[-1] = key.meta.layer + state.active_layers[-1] = key.meta.layer return state - def mo_pressed(self, key, state, *args, **kwargs): + @staticmethod + def _mo_pressed(key, state, *args, **kwargs): ''' Momentarily activates layer, switches off when you let go ''' - state._active_layers.insert(0, key.meta.layer) + state.active_layers.insert(0, key.meta.layer) return state - def mo_released(self, key, state, KC, *args, **kwargs): + @staticmethod + def _mo_released(key, state, KC, *args, **kwargs): # remove the first instance of the target layer # from the active list # under almost all normal use cases, this will @@ -92,93 +112,95 @@ class Layers(Extension): # triggered by MO() and then defaulting to the MO()'s layer # would result in no layers active try: - del_idx = state._active_layers.index(key.meta.layer) - del state._active_layers[del_idx] + del_idx = state.active_layers.index(key.meta.layer) + del state.active_layers[del_idx] except ValueError: pass return state - def lm_pressed(self, key, state, *args, **kwargs): + def _lm_pressed(self, key, state, *args, **kwargs): ''' As MO(layer) but with mod active ''' - state._hid_pending = True + state.hid_pending = True # Sets the timer start and acts like MO otherwise - state._keys_pressed.add(key.meta.kc) - return self.mo_pressed(key, state, *args, **kwargs) + state.keys_pressed.add(key.meta.kc) + return self._mo_pressed(key, state, *args, **kwargs) - def lm_released(self, key, state, *args, **kwargs): + def _lm_released(self, key, state, *args, **kwargs): ''' As MO(layer) but with mod active ''' - state._hid_pending = True - state._keys_pressed.discard(key.meta.kc) - return self.mo_released(key, state, *args, **kwargs) + state.hid_pending = True + state.keys_pressed.discard(key.meta.kc) + return self._mo_released(key, state, *args, **kwargs) - def lt_pressed(self, key, state, *args, **kwargs): + def _lt_pressed(self, key, state, *args, **kwargs): # Sets the timer start and acts like MO otherwise self.start_time[LayerType.LT] = accurate_ticks() - return self.mo_pressed(key, state, *args, **kwargs) + return self._mo_pressed(key, state, *args, **kwargs) - def lt_released(self, key, state, *args, **kwargs): + def _lt_released(self, key, state, *args, **kwargs): # On keyup, check timer, and press key if needed. if self.start_time[LayerType.LT] and ( accurate_ticks_diff( accurate_ticks(), self.start_time[LayerType.LT], state.tap_time ) ): - state._hid_pending = True - state._tap_key(key.meta.kc) + state.hid_pending = True + state.tap_key(key.meta.kc) - self.mo_released(key, state, *args, **kwargs) + self._mo_released(key, state, *args, **kwargs) self.start_time[LayerType.LT] = None return state - def tg_pressed(self, key, state, *args, **kwargs): + @staticmethod + def _tg_pressed(key, state, *args, **kwargs): ''' Toggles the layer (enables it if not active, and vise versa) ''' # See mo_released for implementation details around this try: - del_idx = state._active_layers.index(key.meta.layer) - del state._active_layers[del_idx] + del_idx = state.active_layers.index(key.meta.layer) + del state.active_layers[del_idx] except ValueError: - state._active_layers.insert(0, key.meta.layer) + state.active_layers.insert(0, key.meta.layer) return state - def to_pressed(self, key, state, *args, **kwargs): + @staticmethod + def _to_pressed(key, state, *args, **kwargs): ''' Activates layer and deactivates all other layers ''' - state._active_layers.clear() - state._active_layers.insert(0, key.meta.layer) + state.active_layers.clear() + state.active_layers.insert(0, key.meta.layer) return state - def tt_pressed(self, key, state, *args, **kwargs): + def _tt_pressed(self, key, state, *args, **kwargs): ''' Momentarily activates layer if held, toggles it if tapped repeatedly ''' - # TODO Make this work with tap dance to function more correctly, but technically works. if self.start_time[LayerType.TT] is None: # Sets the timer start and acts like MO otherwise self.start_time[LayerType.TT] = accurate_ticks() - return self.mo_pressed(key, state, *args, **kwargs) + return self._mo_pressed(key, state, *args, **kwargs) elif accurate_ticks_diff( accurate_ticks(), self.start_time[LayerType.TT], state.tap_time ): self.start_time[LayerType.TT] = None - return self.tg_pressed(key, state, *args, **kwargs) + return self._tg_pressed(key, state, *args, **kwargs) + return None - def tt_released(self, key, state, *args, **kwargs): + def _tt_released(self, key, state, *args, **kwargs): if self.start_time[LayerType.TT] is None or not accurate_ticks_diff( accurate_ticks(), self.start_time[LayerType.TT], state.tap_time ): # On first press, works like MO. On second press, does nothing unless let up within # time window, then acts like TG. self.start_time[LayerType.TT] = None - return self.mo_released(key, state, *args, **kwargs) + return self._mo_released(key, state, *args, **kwargs) return state diff --git a/kmk/extensions/leader.py b/kmk/extensions/leader.py index 8b84348..36efe97 100644 --- a/kmk/extensions/leader.py +++ b/kmk/extensions/leader.py @@ -31,24 +31,35 @@ class Leader(Extension): on_release=handler_passthrough, ) - def after_matrix_scan(self, keyboard_state, *args): + 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): if self._mode % 2 == 1: - keys_pressed = keyboard_state._keys_pressed + keys_pressed = keyboard.keys_pressed if self._assembly_last_len and self._sequence_assembly: history_set = set(self._sequence_assembly) keys_pressed = keys_pressed - history_set - self._assembly_last_len = len(keyboard_state._keys_pressed) + self._assembly_last_len = len(keyboard.keys_pressed) for key in keys_pressed: if self._mode == LeaderMode.ENTER_ACTIVE and key == KC.ENT: - self._handle_leader_sequence(keyboard_state) - break - elif key == KC.ESC or key == KC.GESC: + self._handle_leader_sequence(keyboard) + elif key in (KC.ESC, KC.GESC): # Clean self and turn leader mode off. - self._exit_leader_mode(keyboard_state) + self._exit_leader_mode(keyboard) break elif key == KC.LEAD: break @@ -57,9 +68,16 @@ class Leader(Extension): # This needs replaced later with a proper debounce self._sequence_assembly.append(key) - keyboard_state._hid_pending = False + keyboard.hid_pending = False - def _compile_sequences(self, sequences): + def before_hid_send(self, keyboard): + return + + def after_hid_send(self, keyboard): + return + + @staticmethod + def _compile_sequences(sequences): for k, v in sequences.items(): if not isinstance(k, tuple): @@ -72,33 +90,33 @@ class Leader(Extension): return sequences - def _handle_leader_sequence(self, keyboard_state): + def _handle_leader_sequence(self, keyboard): lmh = tuple(self._sequence_assembly) # Will get caught in infinite processing loops if we don't # exit leader mode before processing the target key - self._exit_leader_mode(keyboard_state) + self._exit_leader_mode(keyboard) if lmh in self._sequences: # Stack depth exceeded if try to use add_key here with a unicode sequence - keyboard_state._process_key(self._sequences[lmh], True) + keyboard.process_key(self._sequences[lmh], True) - keyboard_state._set_timeout( - False, lambda: keyboard_state._remove_key(self._sequences[lmh]) + keyboard.set_timeout( + False, lambda: keyboard.remove_key(self._sequences[lmh]) ) - def _exit_leader_mode(self, keyboard_state): + def _exit_leader_mode(self, keyboard): self._sequence_assembly.clear() self._mode -= 1 self._assembly_last_len = 0 - keyboard_state._keys_pressed.clear() + keyboard.keys_pressed.clear() - def _key_leader_pressed(self, key, keyboard_state, *args, **kwargs): + def _key_leader_pressed(self, key, keyboard): if self._mode % 2 == 0: - keyboard_state._keys_pressed.discard(key) + keyboard.keys_pressed.discard(key) # All leader modes are one number higher when activating self._mode += 1 if self._mode == LeaderMode.TIMEOUT_ACTIVE: - keyboard_state._set_timeout( - self._timeout, lambda: self._handle_leader_sequence(keyboard_state) + keyboard.set_timeout( + self._timeout, lambda: self._handle_leader_sequence(keyboard) ) diff --git a/kmk/extensions/led.py b/kmk/extensions/led.py index 80d0ebb..d805120 100644 --- a/kmk/extensions/led.py +++ b/kmk/extensions/led.py @@ -66,10 +66,23 @@ class LED(Extension): def _to_dict(self): return f'LED(_brightness={self._brightness} _pos={self._pos} brightness_step={self.brightness_step} brightness_limit={self.brightness_limit} animation_mode={self.animation_mode} animation_speed={self.animation_speed} breathe_center={self.breathe_center} val={self.val} )' - def _init_effect(self): - self._pos = 0 - self._effect_init = False - return self + 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): + return + + def before_hid_send(self, keyboard): + return def after_hid_send(self, keyboard): if self._enabled and self.animation_mode: @@ -77,6 +90,11 @@ class LED(Extension): return keyboard + def _init_effect(self): + self._pos = 0 + self._effect_init = False + return self + def set_brightness(self, percent): self._led.duty_cycle = int(percent / 100 * 65535) @@ -161,8 +179,6 @@ class LED(Extension): else: self.off() - return self - def _key_led_tog(self, key, state, *args, **kwargs): if self.animation_mode == AnimationModes.STATIC_STANDBY: self.animation_mode = AnimationModes.STATIC diff --git a/kmk/extensions/media_keys.py b/kmk/extensions/media_keys.py index d763919..600fadd 100644 --- a/kmk/extensions/media_keys.py +++ b/kmk/extensions/media_keys.py @@ -26,3 +26,24 @@ class MediaKeys(Extension): make_consumer_key(code=184, names=('MEDIA_EJECT', 'EJCT')) # 0xB8 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): + 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): + return + + def before_hid_send(self, keyboard): + return + + def after_hid_send(self, keyboard): + return diff --git a/kmk/extensions/modtap.py b/kmk/extensions/modtap.py new file mode 100644 index 0000000..e035c9c --- /dev/null +++ b/kmk/extensions/modtap.py @@ -0,0 +1,55 @@ +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 + + +class ModTap(Extension): + def __init__(self): + self._mod_tap_timer = None + make_argumented_key( + validator=mod_tap_validator, + names=('MT',), + on_press=self.mt_pressed, + 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): + return + + def before_hid_send(self, keyboard): + return + + def after_hid_send(self, keyboard): + return + + def mt_pressed(self, key, state, *args, **kwargs): + '''Sets the timer start and acts like a modifier otherwise''' + state.keys_pressed.add(key.meta.mods) + + self._mod_tap_timer = accurate_ticks() + return state + + def mt_released(self, key, state, *args, **kwargs): + ''' On keyup, check timer, and press key if needed.''' + state.keys_pressed.discard(key.meta.mods) + if self._mod_tap_timer and ( + accurate_ticks_diff(accurate_ticks(), self._mod_tap_timer, state.tap_time) + ): + state.hid_pending = True + state.tap_key(key.meta.kc) + + self._mod_tap_timer = None + return state diff --git a/kmk/extensions/power.py b/kmk/extensions/power.py index fae4ab6..01bf148 100644 --- a/kmk/extensions/power.py +++ b/kmk/extensions/power.py @@ -1,93 +1,144 @@ +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 class Power(Extension): def __init__(self, powersave_pin=None, enable=False, is_target=True): self.enable = enable - self.powersave_pin = powersave_pin + self.powersave_pin = powersave_pin # Powersave pin board object self.is_target = is_target self._powersave_start = ticks_ms() self._usb_last_scan = ticks_ms() - 5000 - self._psp = None + self._psp = None # Powersave pin object + self._i2c = None + + make_key( + names=('PS_TOG',), on_press=self._ps_tog, on_release=handler_passthrough + ) + make_key( + names=('PS_ENB',), on_press=self._ps_enable, on_release=handler_passthrough + ) + make_key( + names=('PS_DIS',), on_press=self._ps_disable, on_release=handler_passthrough + ) def __repr__(self): return f'Power({self._to_dict()})' def _to_dict(self): - return f'Power( enable={self.enable} powersave_pin={self.powersave_pin} is_target={self.is_target} _powersave_start={self._powersave_start} _usb_last_scan={self._usb_last_scan} _psp={self._psp} )' + return f'''Power( + enable={self.enable} + powersave_pin={self.powersave_pin} + is_target={self.is_target} + _powersave_start={self._powersave_start} + _usb_last_scan={self._usb_last_scan} + _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._detect_i2c() self.enable = not bool(self.usb_scan) - def before_matrix_scan(self, keyboard_state): + def before_matrix_scan(self, keyboard): if self.usb_rescan_timer(): self.enable = not bool(self.usb_scan) - def after_matrix_scan(self, keyboard_state, matrix_update): + def after_matrix_scan(self, keyboard, matrix_update): if matrix_update: self.psave_time_reset() else: self.psleep() + def before_hid_send(self, keyboard): + return + + def after_hid_send(self, keyboard): + return + def enable_powersave(self): + '''Enables power saving features''' print('Psave True') if self.powersave_pin: - import digitalio - # Allows power save to prevent RGB drain. # Example here https://docs.nicekeyboards.com/#/nice!nano/pinout_schematic + if not self._psp: self._psp = digitalio.DigitalInOut(self.powersave_pin) self._psp.direction = digitalio.Direction.OUTPUT self._psp.value = True - # TODO Allow a hook to stop RGB/OLED to deinit or this causes a lockup self.enable = True - return self - def disable_powersave(self): + '''Disables power saving features''' print('Psave False') if self.powersave_pin: - import digitalio - # Allows power save to prevent RGB drain. # Example here https://docs.nicekeyboards.com/#/nice!nano/pinout_schematic + if not self._psp: self._psp = digitalio.DigitalInOut(self.powersave_pin) self._psp.direction = digitalio.Direction.OUTPUT self._psp.value = False - # TODO Allow a hook to stop RGB/OLED to reinit self.enable = False - return self - def psleep(self): ''' Sleeps longer and longer to save power the more time in between updates. ''' - if ticks_diff(ticks_ms(), self.powersave_start) <= 20000 and self.is_target: + if ticks_diff(ticks_ms(), self._powersave_start) <= 20000 and self.is_target: sleep_ms(1) - elif ticks_diff(ticks_ms(), self.powersave_start) <= 40000 and self.is_target: + elif ticks_diff(ticks_ms(), self._powersave_start) <= 40000 and self.is_target: sleep_ms(4) - elif ticks_diff(ticks_ms(), self.powersave_start) <= 60000 and self.is_target: + elif ticks_diff(ticks_ms(), self._powersave_start) <= 60000 and self.is_target: sleep_ms(8) - elif ticks_diff(ticks_ms(), self.powersave_start) >= 240000: + elif ticks_diff(ticks_ms(), self._powersave_start) >= 240000: sleep_ms(250) def psave_time_reset(self): - self.powersave_start = ticks_ms() - return self + self._powersave_start = ticks_ms() def usb_rescan_timer(self): - return bool(ticks_diff(ticks_ms(), self.usb_last_scan) > 5000) + return bool(ticks_diff(ticks_ms(), self._usb_last_scan) > 5000) def usb_time_reset(self): - self.usb_last_scan = ticks_ms() - return self + self._usb_last_scan = ticks_ms() def usb_scan(self): # TODO Add USB detection here. Currently lies that it's connected + # https://github.com/adafruit/circuitpython/pull/3513 return True + + def _detect_i2c(self): + '''Detects i2c devices and disables cutting power to them''' + # TODO Figure out how this could deinit/reinit instead. + self._i2c = board.I2C() + devices = self._i2c.scan() + if devices != []: + self.powersave_pin = None + + def _ps_tog(self): + if self.enable: + self.enable_powersave() + else: + self.disable_powersave() + + def _ps_enable(self): + if not self.enable: + self.enable_powersave() + + def _ps_disable(self): + if self.enable: + self.disable_powersave() diff --git a/kmk/extensions/rgb.py b/kmk/extensions/rgb.py index 6c98b57..24e711d 100644 --- a/kmk/extensions/rgb.py +++ b/kmk/extensions/rgb.py @@ -141,6 +141,24 @@ class RGB(Extension): on_release=handler_passthrough, ) + 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): + return + + def before_hid_send(self, keyboard): + return + def after_hid_send(self, keyboard): if self.animation_mode: self.loopcounter += 1 @@ -150,7 +168,8 @@ class RGB(Extension): return keyboard - def time_ms(self): + @staticmethod + def time_ms(): return int(time.monotonic() * 1000) def hsv_to_rgb(self, hue, sat, val): @@ -230,8 +249,6 @@ class RGB(Extension): else: self.set_rgb(self.hsv_to_rgb(hue, sat, val), index) - return self - def set_hsv_fill(self, hue, sat, val): ''' Takes HSV values and displays it on all LEDs/Neopixels @@ -244,7 +261,6 @@ class RGB(Extension): self.set_rgb_fill(self.hsv_to_rgbw(hue, sat, val)) else: self.set_rgb_fill(self.hsv_to_rgb(hue, sat, val)) - return self def set_rgb(self, rgb, index): ''' @@ -257,8 +273,6 @@ class RGB(Extension): if not self.disable_auto_write: self.neopixel.show() - return self - def set_rgb_fill(self, rgb): ''' Takes an RGB or RGBW and displays it on all LEDs/Neopixels @@ -269,8 +283,6 @@ class RGB(Extension): if not self.disable_auto_write: self.neopixel.show() - return self - def increase_hue(self, step=None): ''' Increases hue by step amount rolling at 360 and returning to 0 @@ -284,8 +296,6 @@ class RGB(Extension): if self._check_update(): self._do_update() - return self - def decrease_hue(self, step=None): ''' Decreases hue by step amount rolling at 0 and returning to 360 @@ -302,8 +312,6 @@ class RGB(Extension): if self._check_update(): self._do_update() - return self - def increase_sat(self, step=None): ''' Increases saturation by step amount stopping at 100 @@ -320,8 +328,6 @@ class RGB(Extension): if self._check_update(): self._do_update() - return self - def decrease_sat(self, step=None): ''' Decreases saturation by step amount stopping at 0 @@ -338,8 +344,6 @@ class RGB(Extension): if self._check_update(): self._do_update() - return self - def increase_val(self, step=None): ''' Increases value by step amount stopping at 100 @@ -355,8 +359,6 @@ class RGB(Extension): if self._check_update(): self._do_update() - return self - def decrease_val(self, step=None): ''' Decreases value by step amount stopping at 0 @@ -372,8 +374,6 @@ class RGB(Extension): if self._check_update(): self._do_update() - return self - def increase_ani(self): ''' Increases animation speed by 1 amount stopping at 10 @@ -386,8 +386,6 @@ class RGB(Extension): if self._check_update(): self._do_update() - return self - def decrease_ani(self): ''' Decreases animation speed by 1 amount stopping at 0 @@ -400,8 +398,6 @@ class RGB(Extension): if self._check_update(): self._do_update() - return self - def off(self): ''' Turns off all LEDs/Neopixels without changing stored values @@ -409,8 +405,6 @@ class RGB(Extension): if self.neopixel: self.set_hsv_fill(0, 0, 0) - return self - def show(self): ''' Turns on all LEDs/Neopixels without changing stored values @@ -418,8 +412,6 @@ class RGB(Extension): if self.neopixel: self.neopixel.show() - return self - def animate(self): ''' Activates a "step" in the animation based on the active mode @@ -448,8 +440,6 @@ class RGB(Extension): else: self.off() - return self - def _animation_step(self): interval = self.time_ms() - self.time if interval >= max(self.intervals): @@ -471,7 +461,6 @@ class RGB(Extension): self.pos = 0 self.reverse_animation = False self.effect_init = False - return self def _check_update(self): return bool(self.animation_mode == AnimationModes.STATIC_STANDBY) @@ -483,7 +472,6 @@ class RGB(Extension): def effect_static(self): self.set_hsv_fill(self.hue, self.sat, self.val) self.animation_mode = AnimationModes.STATIC_STANDBY - return self def effect_breathing(self): # http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/ @@ -496,20 +484,14 @@ class RGB(Extension): self.pos = (self.pos + self.animation_speed) % 256 self.set_hsv_fill(self.hue, self.sat, self.val) - return self - def effect_breathing_rainbow(self): self.increase_hue(self.animation_speed) self.effect_breathing() - return self - def effect_rainbow(self): self.increase_hue(self.animation_speed) self.set_hsv_fill(self.hue, self.sat, self.val) - return self - def effect_swirl(self): self.increase_hue(self.animation_speed) self.disable_auto_write = True # Turn off instantly showing @@ -521,7 +503,6 @@ class RGB(Extension): # Show final results self.disable_auto_write = False # Resume showing changes self.show() - return self def effect_knight(self): # Determine which LEDs should be lit up @@ -546,8 +527,6 @@ class RGB(Extension): self.disable_auto_write = False # Resume showing changes self.show() - return self - def _rgb_tog(self, key, state, *args, **kwargs): if self.animation_mode == AnimationModes.STATIC: self.animation_mode = AnimationModes.STATIC_STANDBY @@ -556,69 +535,54 @@ class RGB(Extension): self.animation_mode = AnimationModes.STATIC self._do_update() self.enable = not self.enable - return state def _rgb_hui(self, key, state, *args, **kwargs): self.increase_hue() - return state def _rgb_hud(self, key, state, *args, **kwargs): self.decrease_hue() - return state def _rgb_sai(self, key, state, *args, **kwargs): self.increase_sat() - return state def _rgb_sad(self, key, state, *args, **kwargs): self.decrease_sat() - return state def _rgb_vai(self, key, state, *args, **kwargs): self.increase_val() - return state def _rgb_vad(self, key, state, *args, **kwargs): self.decrease_val() - return state def _rgb_ani(self, key, state, *args, **kwargs): self.increase_ani() - return state def _rgb_and(self, key, state, *args, **kwargs): self.decrease_ani() - return state def _rgb_mode_static(self, key, state, *args, **kwargs): self.effect_init = True self.animation_mode = AnimationModes.STATIC - return state def _rgb_mode_breathe(self, key, state, *args, **kwargs): self.effect_init = True self.animation_mode = AnimationModes.BREATHING - return state def _rgb_mode_breathe_rainbow(self, key, state, *args, **kwargs): self.effect_init = True self.animation_mode = AnimationModes.BREATHING_RAINBOW - return state def _rgb_mode_rainbow(self, key, state, *args, **kwargs): self.effect_init = True self.animation_mode = AnimationModes.RAINBOW - return state def _rgb_mode_swirl(self, key, state, *args, **kwargs): self.effect_init = True self.animation_mode = AnimationModes.SWIRL - return state def _rgb_mode_knight(self, key, state, *args, **kwargs): self.effect_init = True self.animation_mode = AnimationModes.KNIGHT - return state def _rgb_reset(self, key, state, *args, **kwargs): self.hue = self.hue_default @@ -627,4 +591,3 @@ class RGB(Extension): if self.animation_mode == AnimationModes.STATIC_STANDBY: self.animation_mode = AnimationModes.STATIC self._do_update() - return state diff --git a/kmk/extensions/split.py b/kmk/extensions/split.py index b9059ef..aa9404b 100644 --- a/kmk/extensions/split.py +++ b/kmk/extensions/split.py @@ -37,6 +37,12 @@ class Split(Extension): self.uart_pin = uart_pin 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 @@ -75,14 +81,21 @@ class Split(Extension): for cidx in range(cols_to_calc): keyboard.coord_mapping.append(intify_coordinate(ridx, cidx)) - def before_matrix_scan(self, keyboard_state): + def before_matrix_scan(self, keyboard): if self._is_target: return self._receive() + return None - def after_matrix_scan(self, keyboard_state, matrix_update): + def after_matrix_scan(self, keyboard, matrix_update): if matrix_update is not None and not self._is_target: self._send(matrix_update) + def before_hid_send(self, keyboard): + return + + def after_hid_send(self, keyboard): + return + def _send(self, update): if self.split_target_left: update[1] += self.split_offset diff --git a/kmk/handlers/modtap.py b/kmk/handlers/modtap.py deleted file mode 100644 index 9d3dc5f..0000000 --- a/kmk/handlers/modtap.py +++ /dev/null @@ -1,23 +0,0 @@ -from kmk.kmktime import ticks_diff, ticks_ms - - -def mt_pressed(key, state, *args, **kwargs): - # Sets the timer start and acts like a modifier otherwise - state._keys_pressed.add(key.meta.mods) - - state._start_time['mod_tap'] = ticks_ms() - return state - - -def mt_released(key, state, *args, **kwargs): - # On keyup, check timer, and press key if needed. - state._keys_pressed.discard(key.meta.mods) - timer_name = 'mod_tap' - if state._start_time[timer_name] and ( - ticks_diff(ticks_ms(), state._start_time[timer_name]) < state.tap_time - ): - state._hid_pending = True - state._tap_key(key.meta.kc) - - state._start_time[timer_name] = None - return state diff --git a/kmk/handlers/sequences.py b/kmk/handlers/sequences.py index b079421..8cff830 100644 --- a/kmk/handlers/sequences.py +++ b/kmk/handlers/sequences.py @@ -12,18 +12,18 @@ def get_wide_ordinal(char): def sequence_press_handler(key, state, KC, *args, **kwargs): - old_keys_pressed = state._keys_pressed - state._keys_pressed = set() + oldkeys_pressed = state.keys_pressed + state.keys_pressed = set() for ikey in key.meta.seq: if not getattr(ikey, 'no_press', None): - state._process_key(ikey, True) + state.process_key(ikey, True) state._send_hid() if not getattr(ikey, 'no_release', None): - state._process_key(ikey, False) + state.process_key(ikey, False) state._send_hid() - state._keys_pressed = old_keys_pressed + state.keys_pressed = oldkeys_pressed return state @@ -104,15 +104,15 @@ def unicode_codepoint_sequence(codepoints): def _unicode_sequence(key, state, *args, **kwargs): if state.unicode_mode == UnicodeMode.IBUS: - state._process_key( + state.process_key( simple_key_sequence(_ibus_unicode_sequence(kc_macros, state)), True ) elif state.unicode_mode == UnicodeMode.RALT: - state._process_key( + state.process_key( simple_key_sequence(_ralt_unicode_sequence(kc_macros, state)), True ) elif state.unicode_mode == UnicodeMode.WINC: - state._process_key( + state.process_key( simple_key_sequence(_winc_unicode_sequence(kc_macros, state)), True ) diff --git a/kmk/handlers/stock.py b/kmk/handlers/stock.py index c6c6fda..3f9b69d 100644 --- a/kmk/handlers/stock.py +++ b/kmk/handlers/stock.py @@ -6,50 +6,38 @@ def passthrough(key, state, *args, **kwargs): def default_pressed(key, state, KC, coord_int=None, coord_raw=None): - state._hid_pending = True + state.hid_pending = True if coord_int is not None: - state._coord_keys_pressed[coord_int] = key + state._coordkeys_pressed[coord_int] = key - state._keys_pressed.add(key) + state.keys_pressed.add(key) return state def default_released(key, state, KC, coord_int=None, coord_raw=None): - state._hid_pending = True - state._keys_pressed.discard(key) + state.hid_pending = True + state.keys_pressed.discard(key) if coord_int is not None: - state._keys_pressed.discard(state._coord_keys_pressed.get(coord_int, None)) - state._coord_keys_pressed[coord_int] = None + state.keys_pressed.discard(state._coordkeys_pressed.get(coord_int, None)) + state._coordkeys_pressed[coord_int] = None return state def reset(*args, **kwargs): - try: - import machine + import microcontroller - machine.reset() - - except ImportError: - import microcontroller - - microcontroller.reset() + microcontroller.reset() def bootloader(*args, **kwargs): - try: - import machine + import microcontroller - machine.bootloader() - - except ImportError: - import microcontroller - - microcontroller.on_next_reset(microcontroller.RunMode.BOOTLOADER) - microcontroller.reset() + microcontroller.on_next_reset(microcontroller.RunMode.BOOTLOADER) + microcontroller.reset() def debug_pressed(key, state, KC, *args, **kwargs): @@ -66,48 +54,48 @@ def debug_pressed(key, state, KC, *args, **kwargs): def gesc_pressed(key, state, KC, *args, **kwargs): GESC_TRIGGERS = {KC.LSHIFT, KC.RSHIFT, KC.LGUI, KC.RGUI} - if GESC_TRIGGERS.intersection(state._keys_pressed): + if GESC_TRIGGERS.intersection(state.keys_pressed): # First, release GUI if already pressed state._send_hid() # if Shift is held, KC_GRAVE will become KC_TILDE on OS level - state._keys_pressed.add(KC.GRAVE) - state._hid_pending = True + state.keys_pressed.add(KC.GRAVE) + state.hid_pending = True return state # else return KC_ESC - state._keys_pressed.add(KC.ESCAPE) - state._hid_pending = True + state.keys_pressed.add(KC.ESCAPE) + state.hid_pending = True return state def gesc_released(key, state, KC, *args, **kwargs): - state._keys_pressed.discard(KC.ESCAPE) - state._keys_pressed.discard(KC.GRAVE) - state._hid_pending = True + state.keys_pressed.discard(KC.ESCAPE) + state.keys_pressed.discard(KC.GRAVE) + state.hid_pending = True return state def bkdl_pressed(key, state, KC, *args, **kwargs): BKDL_TRIGGERS = {KC.LGUI, KC.RGUI} - if BKDL_TRIGGERS.intersection(state._keys_pressed): + if BKDL_TRIGGERS.intersection(state.keys_pressed): state._send_hid() - state._keys_pressed.add(KC.DEL) - state._hid_pending = True + state.keys_pressed.add(KC.DEL) + state.hid_pending = True return state # else return KC_ESC - state._keys_pressed.add(KC.BKSP) - state._hid_pending = True + state.keys_pressed.add(KC.BKSP) + state.hid_pending = True return state def bkdl_released(key, state, KC, *args, **kwargs): - state._keys_pressed.discard(KC.BKSP) - state._keys_pressed.discard(KC.DEL) - state._hid_pending = True + state.keys_pressed.discard(KC.BKSP) + state.keys_pressed.discard(KC.DEL) + state.hid_pending = True return state diff --git a/kmk/keys.py b/kmk/keys.py index d7058eb..0e32283 100644 --- a/kmk/keys.py +++ b/kmk/keys.py @@ -60,7 +60,7 @@ class Key: def __repr__(self): return 'Key(code={}, has_modifiers={})'.format(self.code, self.has_modifiers) - def _on_press(self, state, coord_int, coord_raw): + def on_press(self, state, coord_int, coord_raw): for fn in self._pre_press_handlers: if not fn(self, state, KC, coord_int, coord_raw): return None @@ -72,7 +72,7 @@ class Key: return ret - def _on_release(self, state, coord_int, coord_raw): + def on_release(self, state, coord_int, coord_raw): for fn in self._pre_release_handlers: if not fn(self, state, KC, coord_int, coord_raw): return None diff --git a/kmk/kmk_keyboard.py b/kmk/kmk_keyboard.py index cfad3e7..2561222 100644 --- a/kmk/kmk_keyboard.py +++ b/kmk/kmk_keyboard.py @@ -28,22 +28,22 @@ class KMKKeyboard: ##### # Internal State - _keys_pressed = set() - _coord_keys_pressed = {} + keys_pressed = set() + _coordkeys_pressed = {} hid_type = HIDModes.USB _hid_helper = None - _hid_pending = False - _state_layer_key = None - _matrix_update = None + hid_pending = False + state_layer_key = None + matrix_update = None _matrix_modify = None - _state_changed = False + state_changed = False _old_timeouts_len = None _new_timeouts_len = None # 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 = [0] _timeouts = {} _tapping = False @@ -64,7 +64,7 @@ class KMKKeyboard: 'tap_time={} ' '_hid_helper={} ' 'keys_pressed={} ' - 'coord_keys_pressed={} ' + 'coordkeys_pressed={} ' 'hid_pending={} ' 'active_layers={} ' 'timeouts={} ' @@ -82,12 +82,12 @@ class KMKKeyboard: self.matrix_scanner, self.unicode_mode, self.tap_time, - self._hid_helper.__name__, + self._hid_helper, # internal state - self._keys_pressed, - self._coord_keys_pressed, - self._hid_pending, - self._active_layers, + self.keys_pressed, + self._coordkeys_pressed, + self.hid_pending, + self.active_layers, self._timeouts, self._tapping, self._tap_dance_counts, @@ -102,13 +102,13 @@ class KMKKeyboard: print(self) def _send_hid(self): - self._hid_helper.create_report(self._keys_pressed).send() - self._hid_pending = False + self._hid_helper.create_report(self.keys_pressed).send() + self.hid_pending = False def _handle_matrix_report(self, update=None): if update is not None: self._on_matrix_changed(update[0], update[1], update[2]) - self._state_changed = True + self.state_changed = True ##### # SPLICE: INTERNAL STATE @@ -116,7 +116,7 @@ class KMKKeyboard: ##### def _find_key_in_map(self, int_coord, row, col): - self._state_layer_key = None + self.state_layer_key = None try: idx = self.coord_mapping.index(int_coord) except ValueError: @@ -129,16 +129,16 @@ class KMKKeyboard: return None - for layer in self._active_layers: - self._state_layer_key = self.keymap[layer][idx] + for layer in self.active_layers: + self.state_layer_key = self.keymap[layer][idx] - if not self._state_layer_key or self._state_layer_key == KC.TRNS: + if not self.state_layer_key or self.state_layer_key == KC.TRNS: continue if self.debug_enabled: - print('KeyResolution(key={})'.format(self._state_layer_key)) + print('KeyResolution(key={})'.format(self.state_layer_key)) - return self._state_layer_key + return self.state_layer_key def _on_matrix_changed(self, row, col, is_pressed): if self.debug_enabled: @@ -151,31 +151,31 @@ class KMKKeyboard: print('MatrixUndefinedCoordinate(col={} row={})'.format(col, row)) return self - return self._process_key(kc_changed, is_pressed, int_coord, (row, col)) + 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, is_pressed, coord_int=None, coord_raw=None): if self._tapping and not isinstance(key.meta, TapDanceKeyMeta): self._process_tap_dance(key, is_pressed) else: if is_pressed: - key._on_press(self, coord_int, coord_raw) + key.on_press(self, coord_int, coord_raw) else: - key._on_release(self, coord_int, coord_raw) + key.on_release(self, coord_int, coord_raw) return self - def _remove_key(self, keycode): - self._keys_pressed.discard(keycode) - return self._process_key(keycode, False) + def remove_key(self, keycode): + self.keys_pressed.discard(keycode) + return self.process_key(keycode, False) - def _add_key(self, keycode): - self._keys_pressed.add(keycode) - return self._process_key(keycode, True) + def add_key(self, keycode): + self.keys_pressed.add(keycode) + return self.process_key(keycode, True) - def _tap_key(self, keycode): - self._add_key(keycode) + def tap_key(self, keycode): + self.add_key(keycode) # On the next cycle, we'll remove the key. - self._set_timeout(False, lambda: self._remove_key(keycode)) + self.set_timeout(False, lambda: self.remove_key(keycode)) return self @@ -196,7 +196,7 @@ class KMKKeyboard: or not self._tap_dance_counts[changed_key] ): self._tap_dance_counts[changed_key] = 1 - self._set_timeout( + self.set_timeout( self.tap_time, lambda: self._end_tap_dance(changed_key) ) self._tapping = True @@ -220,19 +220,19 @@ class KMKKeyboard: v = self._tap_dance_counts[td_key] - 1 if v >= 0: - if td_key in self._keys_pressed: + if td_key in self.keys_pressed: key_to_press = td_key.codes[v] - self._add_key(key_to_press) + self.add_key(key_to_press) self._tap_side_effects[td_key] = key_to_press - self._hid_pending = True + self.hid_pending = True else: if self._tap_side_effects[td_key]: - self._remove_key(self._tap_side_effects[td_key]) + self.remove_key(self._tap_side_effects[td_key]) self._tap_side_effects[td_key] = None - self._hid_pending = True + self.hid_pending = True self._cleanup_tap_dance(td_key) else: - self._tap_key(td_key.codes[v]) + self.tap_key(td_key.codes[v]) self._cleanup_tap_dance(td_key) return self @@ -242,7 +242,7 @@ class KMKKeyboard: 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, callback): if after_ticks is False: # We allow passing False as an implicit "run this on the next process timeouts cycle" timeout_key = ticks_ms() @@ -366,7 +366,7 @@ class KMKKeyboard: self._print_debug_cycle(init=True) while True: - self._state_changed = False + self.state_changed = False for ext in self.extensions: try: @@ -374,20 +374,20 @@ class KMKKeyboard: except Exception as err: print('Failed to run pre matrix function: ', err) - self._matrix_update = self.matrix.scan_for_changes() + self.matrix_update = self.matrix.scan_for_changes() for ext in self.extensions: try: self._matrix_modify = ext.after_matrix_scan( - self, self._matrix_update + self, self.matrix_update ) if self._matrix_modify is not None: - self._matrix_update = self._matrix_modify + self.matrix_update = self._matrix_modify except Exception as err: print('Failed to run post matrix function: ', err) - self._handle_matrix_report(self._matrix_update) - self._matrix_update = None + self._handle_matrix_report(self.matrix_update) + self.matrix_update = None for ext in self.extensions: try: @@ -395,7 +395,7 @@ class KMKKeyboard: except Exception as err: print('Failed to run pre hid function: ', err) - if self._hid_pending: + if self.hid_pending: self._send_hid() self._old_timeouts_len = len(self._timeouts) @@ -403,8 +403,8 @@ class KMKKeyboard: self._new_timeouts_len = len(self._timeouts) if self._old_timeouts_len != self._new_timeouts_len: - self._state_changed = True - if self._hid_pending: + self.state_changed = True + if self.hid_pending: self._send_hid() for ext in self.extensions: @@ -413,5 +413,5 @@ class KMKKeyboard: except Exception as err: print('Failed to run post hid function: ', err) - if self._state_changed: + if self.state_changed: self._print_debug_cycle()