From 5e8c360de776abf51673e73ae3796e8915ca0fd3 Mon Sep 17 00:00:00 2001 From: Kyle Brown Date: Fri, 23 Oct 2020 19:21:42 -0700 Subject: [PATCH] Moved layers to extension --- kmk/boards/converter/keebio/nyquist_r2.py | 4 +- kmk/extensions/layers.py | 164 ++++++++++++++++++++++ kmk/handlers/layers.py | 124 ---------------- kmk/keys.py | 46 ------ 4 files changed, 167 insertions(+), 171 deletions(-) create mode 100644 kmk/extensions/layers.py delete mode 100644 kmk/handlers/layers.py diff --git a/kmk/boards/converter/keebio/nyquist_r2.py b/kmk/boards/converter/keebio/nyquist_r2.py index 9f1ad4e..14c14c8 100644 --- a/kmk/boards/converter/keebio/nyquist_r2.py +++ b/kmk/boards/converter/keebio/nyquist_r2.py @@ -1,5 +1,6 @@ import board +from kmk.extensions.layers import Layers from kmk.extensions.rgb import RGB from kmk.extensions.split import Split from kmk.kmk_keyboard import KMKKeyboard as _KMKKeyboard @@ -29,5 +30,6 @@ class KMKKeyboard(_KMKKeyboard): val_default=40, animation_speed=1, ) + layers_ext = Layers() split = Split(uart_pin=board.SCL, split_offsets=[6, 6, 6, 6, 6]) - extensions = [rgb_ext, split] + extensions = [rgb_ext, split, layers_ext] diff --git a/kmk/extensions/layers.py b/kmk/extensions/layers.py new file mode 100644 index 0000000..be60de6 --- /dev/null +++ b/kmk/extensions/layers.py @@ -0,0 +1,164 @@ +import kmk.handlers.modtap as modtap +from kmk.extensions import Extension +from kmk.key_validators import layer_key_validator, mod_tap_validator +from kmk.keys import make_argumented_key +from kmk.kmktime import ticks_diff, ticks_ms + + +class Layers(Extension): + def __init__(self): + # Layers + make_argumented_key( + validator=layer_key_validator, + names=('MO',), + on_press=self.mo_pressed, + on_release=self.mo_released, + ) + make_argumented_key( + 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, + ) + make_argumented_key( + validator=layer_key_validator, + names=('LT',), + on_press=self.lt_pressed, + on_release=self.lt_released, + ) + make_argumented_key( + 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 + ) + 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, + ) + + def df_pressed(self, key, state, *args, **kwargs): + ''' + Switches the default layer + ''' + state._active_layers[-1] = key.meta.layer + return state + + def mo_pressed(self, key, state, *args, **kwargs): + ''' + Momentarily activates layer, switches off when you let go + ''' + state._active_layers.insert(0, key.meta.layer) + return state + + def mo_released(self, 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 + # disable the layer (but preserve it if it was triggered + # as a default layer, etc.) + # this also resolves an issue where using DF() on a layer + # 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] + except ValueError: + pass + + return state + + def lm_pressed(self, key, state, *args, **kwargs): + ''' + As MO(layer) but with mod active + ''' + state._hid_pending = True + # Sets the timer start and acts like MO otherwise + state._start_time['lm'] = ticks_ms() + state._keys_pressed.add(key.meta.kc) + return self.mo_pressed(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) + state._start_time['lm'] = None + return self.mo_released(key, state, *args, **kwargs) + + def lt_pressed(self, key, state, *args, **kwargs): + # Sets the timer start and acts like MO otherwise + state._start_time['lt'] = ticks_ms() + return self.mo_pressed(key, state, *args, **kwargs) + + def lt_released(self, key, state, *args, **kwargs): + # On keyup, check timer, and press key if needed. + if state._start_time['lt'] and ( + ticks_diff(ticks_ms(), state._start_time['lt']) < state.tap_time + ): + state._hid_pending = True + state._tap_key(key.meta.kc) + + self.mo_released(key, state, *args, **kwargs) + state._start_time['lt'] = None + return state + + def tg_pressed(self, 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] + except ValueError: + state._active_layers.insert(0, key.meta.layer) + + return state + + def to_pressed(self, key, state, *args, **kwargs): + ''' + Activates layer and deactivates all other layers + ''' + state._active_layers.clear() + state._active_layers.insert(0, key.meta.layer) + + return state + + 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 state._start_time['tt'] is None: + # Sets the timer start and acts like MO otherwise + state._start_time['tt'] = ticks_ms() + return self.mo_pressed(key, state, *args, **kwargs) + elif ticks_diff(ticks_ms(), state._start_time['tt']) < state.tap_time: + state._start_time['tt'] = None + return self.tg_pressed(key, state, *args, **kwargs) + + def tt_released(self, key, state, *args, **kwargs): + tap_timed_out = ( + ticks_diff(ticks_ms(), state._start_time['tt']) >= state.tap_time + ) + if state._start_time['tt'] is None or tap_timed_out: + # On first press, works like MO. On second press, does nothing unless let up within + # time window, then acts like TG. + state._start_time['tt'] = None + return self.mo_released(key, state, *args, **kwargs) + + return state diff --git a/kmk/handlers/layers.py b/kmk/handlers/layers.py deleted file mode 100644 index fa33fc1..0000000 --- a/kmk/handlers/layers.py +++ /dev/null @@ -1,124 +0,0 @@ -from kmk.kmktime import ticks_diff, ticks_ms - - -def df_pressed(key, state, *args, **kwargs): - ''' - Switches the default layer - ''' - state._active_layers[-1] = key.meta.layer - return state - - -def mo_pressed(key, state, *args, **kwargs): - ''' - Momentarily activates layer, switches off when you let go - ''' - state._active_layers.insert(0, key.meta.layer) - return state - - -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 - # disable the layer (but preserve it if it was triggered - # as a default layer, etc.) - # this also resolves an issue where using DF() on a layer - # 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] - except ValueError: - pass - - return state - - -def lm_pressed(key, state, *args, **kwargs): - ''' - As MO(layer) but with mod active - ''' - state._hid_pending = True - # Sets the timer start and acts like MO otherwise - state._start_time['lm'] = ticks_ms() - state._keys_pressed.add(key.meta.kc) - return mo_pressed(key, state, *args, **kwargs) - - -def lm_released(key, state, *args, **kwargs): - ''' - As MO(layer) but with mod active - ''' - state._hid_pending = True - state._keys_pressed.discard(key.meta.kc) - state._start_time['lm'] = None - return mo_released(key, state, *args, **kwargs) - - -def lt_pressed(key, state, *args, **kwargs): - # Sets the timer start and acts like MO otherwise - state._start_time['lt'] = ticks_ms() - return mo_pressed(key, state, *args, **kwargs) - - -def lt_released(key, state, *args, **kwargs): - # On keyup, check timer, and press key if needed. - if state._start_time['lt'] and ( - ticks_diff(ticks_ms(), state._start_time['lt']) < state.tap_time - ): - state._hid_pending = True - state._tap_key(key.meta.kc) - - mo_released(key, state, *args, **kwargs) - state._start_time['lt'] = None - return state - - -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] - except ValueError: - state._active_layers.insert(0, key.meta.layer) - - return state - - -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) - - return state - - -def tt_pressed(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 state._start_time['tt'] is None: - # Sets the timer start and acts like MO otherwise - state._start_time['tt'] = ticks_ms() - return mo_pressed(key, state, *args, **kwargs) - elif ticks_diff(ticks_ms(), state._start_time['tt']) < state.tap_time: - state._start_time['tt'] = None - return tg_pressed(key, state, *args, **kwargs) - - -def tt_released(key, state, *args, **kwargs): - tap_timed_out = ticks_diff(ticks_ms(), state._start_time['tt']) >= state.tap_time - if state._start_time['tt'] is None or tap_timed_out: - # On first press, works like MO. On second press, does nothing unless let up within - # time window, then acts like TG. - state._start_time['tt'] = None - return mo_released(key, state, *args, **kwargs) - - return state diff --git a/kmk/keys.py b/kmk/keys.py index 327f607..d7058eb 100644 --- a/kmk/keys.py +++ b/kmk/keys.py @@ -1,13 +1,9 @@ from micropython import const -import kmk.handlers.layers as layers -import kmk.handlers.modtap as modtap import kmk.handlers.stock as handlers from kmk.consts import UnicodeMode from kmk.key_validators import ( key_seq_sleep_validator, - layer_key_validator, - mod_tap_validator, tap_dance_key_validator, unicode_mode_key_validator, ) @@ -613,48 +609,6 @@ make_key( on_release=handlers.gesc_released, ) -# Layers -make_argumented_key( - validator=layer_key_validator, - names=('MO',), - on_press=layers.mo_pressed, - on_release=layers.mo_released, -) -make_argumented_key( - validator=layer_key_validator, names=('DF',), on_press=layers.df_pressed -) -make_argumented_key( - validator=layer_key_validator, - names=('LM',), - on_press=layers.lm_pressed, - on_release=layers.lm_released, -) -make_argumented_key( - validator=layer_key_validator, - names=('LT',), - on_press=layers.lt_pressed, - on_release=layers.lt_released, -) -make_argumented_key( - validator=layer_key_validator, names=('TG',), on_press=layers.tg_pressed -) -make_argumented_key( - validator=layer_key_validator, names=('TO',), on_press=layers.to_pressed -) -make_argumented_key( - validator=layer_key_validator, - names=('TT',), - on_press=layers.tt_pressed, - on_release=layers.tt_released, -) - -make_argumented_key( - validator=mod_tap_validator, - names=('MT',), - on_press=modtap.mt_pressed, - on_release=modtap.mt_released, -) - # A dummy key to trigger a sleep_ms call in a sequence of other keys in a # simple sequence macro. make_argumented_key(