massive cleanup

This commit is contained in:
Kyle Brown
2020-10-30 15:43:16 -07:00
parent 4cc99d487d
commit 7fe461d537
15 changed files with 445 additions and 297 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)
)

View File

@@ -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

View File

@@ -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

55
kmk/extensions/modtap.py Normal file
View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
)

View File

@@ -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

View File

@@ -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

View File

@@ -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()