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 # The below methods should be implemented by subclasses
def on_runtime_enable(self, keyboard): def on_runtime_enable(self, keyboard):
pass raise NotImplementedError
def on_runtime_disable(self, keyboard): def on_runtime_disable(self, keyboard):
pass raise NotImplementedError
def during_bootup(self, keyboard): def during_bootup(self, keyboard):
pass raise NotImplementedError
def before_matrix_scan(self, keyboard): def before_matrix_scan(self, keyboard):
''' '''
Return value will be injected as an extra matrix update Return value will be injected as an extra matrix update
''' '''
pass raise NotImplementedError
def after_matrix_scan(self, keyboard, matrix_update): def after_matrix_scan(self, keyboard, matrix_update):
''' '''
Return value will be replace matrix update if supplied Return value will be replace matrix update if supplied
''' '''
pass raise NotImplementedError
def before_hid_send(self, keyboard): def before_hid_send(self, keyboard):
pass raise NotImplementedError
def after_hid_send(self, keyboard): 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.extensions import Extension
from kmk.keys import make_key from kmk.keys import make_key
class International(Extension): class International(Extension):
'''Adds international keys'''
def __init__(self): def __init__(self):
# International # International
make_key(code=50, names=('NONUS_HASH', 'NUHS')) make_key(code=50, names=('NONUS_HASH', 'NUHS'))
@@ -27,3 +30,24 @@ class International(Extension):
make_key(code=150, names=('LANG7',)) make_key(code=150, names=('LANG7',))
make_key(code=151, names=('LANG8',)) make_key(code=151, names=('LANG8',))
make_key(code=152, names=('LANG9',)) 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 from micropython import const
import kmk.handlers.modtap as modtap
from kmk.extensions import Extension 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.keys import make_argumented_key
from kmk.kmktime import accurate_ticks, accurate_ticks_diff from kmk.kmktime import accurate_ticks, accurate_ticks_diff
class LayerType: class LayerType:
# These number must be reserved for layer timers. '''Defines layer type values for readability'''
MO = const(0) MO = const(0)
DF = const(1) DF = const(1)
LM = const(2) LM = const(2)
@@ -18,47 +19,42 @@ class LayerType:
class Layers(Extension): class Layers(Extension):
'''Gives access to the keys used to enable the layer system'''
def __init__(self): def __init__(self):
# Layers # Layers
make_argumented_key( make_argumented_key(
validator=layer_key_validator, validator=layer_key_validator,
names=('MO',), names=('MO',),
on_press=self.mo_pressed, on_press=self._mo_pressed,
on_release=self.mo_released, on_release=self._mo_released,
) )
make_argumented_key( 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( make_argumented_key(
validator=layer_key_validator, validator=layer_key_validator,
names=('LM',), names=('LM',),
on_press=self.lm_pressed, on_press=self._lm_pressed,
on_release=self.lm_released, on_release=self._lm_released,
) )
make_argumented_key( make_argumented_key(
validator=layer_key_validator, validator=layer_key_validator,
names=('LT',), names=('LT',),
on_press=self.lt_pressed, on_press=self._lt_pressed,
on_release=self.lt_released, on_release=self._lt_released,
) )
make_argumented_key( 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( 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( make_argumented_key(
validator=layer_key_validator, validator=layer_key_validator,
names=('TT',), names=('TT',),
on_press=self.tt_pressed, on_press=self._tt_pressed,
on_release=self.tt_released, on_release=self._tt_released,
)
make_argumented_key(
validator=mod_tap_validator,
names=('MT',),
on_press=modtap.mt_pressed,
on_release=modtap.mt_released,
) )
start_time = { start_time = {
@@ -68,21 +64,45 @@ class Layers(Extension):
LayerType.LM: None, 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 Switches the default layer
''' '''
state._active_layers[-1] = key.meta.layer state.active_layers[-1] = key.meta.layer
return state 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 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 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 # remove the first instance of the target layer
# from the active list # from the active list
# under almost all normal use cases, this will # 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 # triggered by MO() and then defaulting to the MO()'s layer
# would result in no layers active # would result in no layers active
try: try:
del_idx = state._active_layers.index(key.meta.layer) del_idx = state.active_layers.index(key.meta.layer)
del state._active_layers[del_idx] del state.active_layers[del_idx]
except ValueError: except ValueError:
pass pass
return state 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 As MO(layer) but with mod active
''' '''
state._hid_pending = True state.hid_pending = True
# Sets the timer start and acts like MO otherwise # Sets the timer start and acts like MO otherwise
state._keys_pressed.add(key.meta.kc) state.keys_pressed.add(key.meta.kc)
return self.mo_pressed(key, state, *args, **kwargs) 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 As MO(layer) but with mod active
''' '''
state._hid_pending = True state.hid_pending = True
state._keys_pressed.discard(key.meta.kc) state.keys_pressed.discard(key.meta.kc)
return self.mo_released(key, state, *args, **kwargs) 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 # Sets the timer start and acts like MO otherwise
self.start_time[LayerType.LT] = accurate_ticks() 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. # On keyup, check timer, and press key if needed.
if self.start_time[LayerType.LT] and ( if self.start_time[LayerType.LT] and (
accurate_ticks_diff( accurate_ticks_diff(
accurate_ticks(), self.start_time[LayerType.LT], state.tap_time accurate_ticks(), self.start_time[LayerType.LT], state.tap_time
) )
): ):
state._hid_pending = True state.hid_pending = True
state._tap_key(key.meta.kc) 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 self.start_time[LayerType.LT] = None
return state 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) Toggles the layer (enables it if not active, and vise versa)
''' '''
# See mo_released for implementation details around this # See mo_released for implementation details around this
try: try:
del_idx = state._active_layers.index(key.meta.layer) del_idx = state.active_layers.index(key.meta.layer)
del state._active_layers[del_idx] del state.active_layers[del_idx]
except ValueError: except ValueError:
state._active_layers.insert(0, key.meta.layer) state.active_layers.insert(0, key.meta.layer)
return state 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 Activates layer and deactivates all other layers
''' '''
state._active_layers.clear() state.active_layers.clear()
state._active_layers.insert(0, key.meta.layer) state.active_layers.insert(0, key.meta.layer)
return state 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 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: if self.start_time[LayerType.TT] is None:
# Sets the timer start and acts like MO otherwise # Sets the timer start and acts like MO otherwise
self.start_time[LayerType.TT] = accurate_ticks() 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( elif accurate_ticks_diff(
accurate_ticks(), self.start_time[LayerType.TT], state.tap_time accurate_ticks(), self.start_time[LayerType.TT], state.tap_time
): ):
self.start_time[LayerType.TT] = None 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( if self.start_time[LayerType.TT] is None or not accurate_ticks_diff(
accurate_ticks(), self.start_time[LayerType.TT], state.tap_time 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 # On first press, works like MO. On second press, does nothing unless let up within
# time window, then acts like TG. # time window, then acts like TG.
self.start_time[LayerType.TT] = None self.start_time[LayerType.TT] = None
return self.mo_released(key, state, *args, **kwargs) return self._mo_released(key, state, *args, **kwargs)
return state return state

View File

@@ -31,24 +31,35 @@ class Leader(Extension):
on_release=handler_passthrough, 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: 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: if self._assembly_last_len and self._sequence_assembly:
history_set = set(self._sequence_assembly) history_set = set(self._sequence_assembly)
keys_pressed = keys_pressed - history_set 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: for key in keys_pressed:
if self._mode == LeaderMode.ENTER_ACTIVE and key == KC.ENT: if self._mode == LeaderMode.ENTER_ACTIVE and key == KC.ENT:
self._handle_leader_sequence(keyboard_state) self._handle_leader_sequence(keyboard)
break elif key in (KC.ESC, KC.GESC):
elif key == KC.ESC or key == KC.GESC:
# Clean self and turn leader mode off. # Clean self and turn leader mode off.
self._exit_leader_mode(keyboard_state) self._exit_leader_mode(keyboard)
break break
elif key == KC.LEAD: elif key == KC.LEAD:
break break
@@ -57,9 +68,16 @@ class Leader(Extension):
# This needs replaced later with a proper debounce # This needs replaced later with a proper debounce
self._sequence_assembly.append(key) 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(): for k, v in sequences.items():
if not isinstance(k, tuple): if not isinstance(k, tuple):
@@ -72,33 +90,33 @@ class Leader(Extension):
return sequences return sequences
def _handle_leader_sequence(self, keyboard_state): def _handle_leader_sequence(self, keyboard):
lmh = tuple(self._sequence_assembly) lmh = tuple(self._sequence_assembly)
# Will get caught in infinite processing loops if we don't # Will get caught in infinite processing loops if we don't
# exit leader mode before processing the target key # exit leader mode before processing the target key
self._exit_leader_mode(keyboard_state) self._exit_leader_mode(keyboard)
if lmh in self._sequences: if lmh in self._sequences:
# Stack depth exceeded if try to use add_key here with a unicode sequence # 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( keyboard.set_timeout(
False, lambda: keyboard_state._remove_key(self._sequences[lmh]) 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._sequence_assembly.clear()
self._mode -= 1 self._mode -= 1
self._assembly_last_len = 0 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: 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 # All leader modes are one number higher when activating
self._mode += 1 self._mode += 1
if self._mode == LeaderMode.TIMEOUT_ACTIVE: if self._mode == LeaderMode.TIMEOUT_ACTIVE:
keyboard_state._set_timeout( keyboard.set_timeout(
self._timeout, lambda: self._handle_leader_sequence(keyboard_state) self._timeout, lambda: self._handle_leader_sequence(keyboard)
) )

View File

@@ -66,10 +66,23 @@ class LED(Extension):
def _to_dict(self): 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} )' 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): def on_runtime_enable(self, keyboard):
self._pos = 0 return
self._effect_init = False
return self 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): def after_hid_send(self, keyboard):
if self._enabled and self.animation_mode: if self._enabled and self.animation_mode:
@@ -77,6 +90,11 @@ class LED(Extension):
return keyboard return keyboard
def _init_effect(self):
self._pos = 0
self._effect_init = False
return self
def set_brightness(self, percent): def set_brightness(self, percent):
self._led.duty_cycle = int(percent / 100 * 65535) self._led.duty_cycle = int(percent / 100 * 65535)
@@ -161,8 +179,6 @@ class LED(Extension):
else: else:
self.off() self.off()
return self
def _key_led_tog(self, key, state, *args, **kwargs): def _key_led_tog(self, key, state, *args, **kwargs):
if self.animation_mode == AnimationModes.STATIC_STANDBY: if self.animation_mode == AnimationModes.STATIC_STANDBY:
self.animation_mode = AnimationModes.STATIC 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=184, names=('MEDIA_EJECT', 'EJCT')) # 0xB8
make_consumer_key(code=179, names=('MEDIA_FAST_FORWARD', 'MFFD')) # 0xB3 make_consumer_key(code=179, names=('MEDIA_FAST_FORWARD', 'MFFD')) # 0xB3
make_consumer_key(code=180, names=('MEDIA_REWIND', 'MRWD')) # 0xB4 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.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 from kmk.kmktime import sleep_ms, ticks_diff, ticks_ms
class Power(Extension): class Power(Extension):
def __init__(self, powersave_pin=None, enable=False, is_target=True): def __init__(self, powersave_pin=None, enable=False, is_target=True):
self.enable = enable self.enable = enable
self.powersave_pin = powersave_pin self.powersave_pin = powersave_pin # Powersave pin board object
self.is_target = is_target self.is_target = is_target
self._powersave_start = ticks_ms() self._powersave_start = ticks_ms()
self._usb_last_scan = ticks_ms() - 5000 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): def __repr__(self):
return f'Power({self._to_dict()})' return f'Power({self._to_dict()})'
def _to_dict(self): 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): def during_bootup(self, keyboard):
self._detect_i2c()
self.enable = not bool(self.usb_scan) 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(): if self.usb_rescan_timer():
self.enable = not bool(self.usb_scan) 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: if matrix_update:
self.psave_time_reset() self.psave_time_reset()
else: else:
self.psleep() self.psleep()
def before_hid_send(self, keyboard):
return
def after_hid_send(self, keyboard):
return
def enable_powersave(self): def enable_powersave(self):
'''Enables power saving features'''
print('Psave True') print('Psave True')
if self.powersave_pin: if self.powersave_pin:
import digitalio
# Allows power save to prevent RGB drain. # Allows power save to prevent RGB drain.
# Example here https://docs.nicekeyboards.com/#/nice!nano/pinout_schematic # Example here https://docs.nicekeyboards.com/#/nice!nano/pinout_schematic
if not self._psp: if not self._psp:
self._psp = digitalio.DigitalInOut(self.powersave_pin) self._psp = digitalio.DigitalInOut(self.powersave_pin)
self._psp.direction = digitalio.Direction.OUTPUT self._psp.direction = digitalio.Direction.OUTPUT
self._psp.value = True self._psp.value = True
# TODO Allow a hook to stop RGB/OLED to deinit or this causes a lockup
self.enable = True self.enable = True
return self
def disable_powersave(self): def disable_powersave(self):
'''Disables power saving features'''
print('Psave False') print('Psave False')
if self.powersave_pin: if self.powersave_pin:
import digitalio
# Allows power save to prevent RGB drain. # Allows power save to prevent RGB drain.
# Example here https://docs.nicekeyboards.com/#/nice!nano/pinout_schematic # Example here https://docs.nicekeyboards.com/#/nice!nano/pinout_schematic
if not self._psp: if not self._psp:
self._psp = digitalio.DigitalInOut(self.powersave_pin) self._psp = digitalio.DigitalInOut(self.powersave_pin)
self._psp.direction = digitalio.Direction.OUTPUT self._psp.direction = digitalio.Direction.OUTPUT
self._psp.value = False self._psp.value = False
# TODO Allow a hook to stop RGB/OLED to reinit
self.enable = False self.enable = False
return self
def psleep(self): def psleep(self):
''' '''
Sleeps longer and longer to save power the more time in between updates. 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) 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) 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) sleep_ms(8)
elif ticks_diff(ticks_ms(), self.powersave_start) >= 240000: elif ticks_diff(ticks_ms(), self._powersave_start) >= 240000:
sleep_ms(250) sleep_ms(250)
def psave_time_reset(self): def psave_time_reset(self):
self.powersave_start = ticks_ms() self._powersave_start = ticks_ms()
return self
def usb_rescan_timer(self): 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): def usb_time_reset(self):
self.usb_last_scan = ticks_ms() self._usb_last_scan = ticks_ms()
return self
def usb_scan(self): def usb_scan(self):
# TODO Add USB detection here. Currently lies that it's connected # TODO Add USB detection here. Currently lies that it's connected
# https://github.com/adafruit/circuitpython/pull/3513
return True 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, 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): def after_hid_send(self, keyboard):
if self.animation_mode: if self.animation_mode:
self.loopcounter += 1 self.loopcounter += 1
@@ -150,7 +168,8 @@ class RGB(Extension):
return keyboard return keyboard
def time_ms(self): @staticmethod
def time_ms():
return int(time.monotonic() * 1000) return int(time.monotonic() * 1000)
def hsv_to_rgb(self, hue, sat, val): def hsv_to_rgb(self, hue, sat, val):
@@ -230,8 +249,6 @@ class RGB(Extension):
else: else:
self.set_rgb(self.hsv_to_rgb(hue, sat, val), index) self.set_rgb(self.hsv_to_rgb(hue, sat, val), index)
return self
def set_hsv_fill(self, hue, sat, val): def set_hsv_fill(self, hue, sat, val):
''' '''
Takes HSV values and displays it on all LEDs/Neopixels 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)) self.set_rgb_fill(self.hsv_to_rgbw(hue, sat, val))
else: else:
self.set_rgb_fill(self.hsv_to_rgb(hue, sat, val)) self.set_rgb_fill(self.hsv_to_rgb(hue, sat, val))
return self
def set_rgb(self, rgb, index): def set_rgb(self, rgb, index):
''' '''
@@ -257,8 +273,6 @@ class RGB(Extension):
if not self.disable_auto_write: if not self.disable_auto_write:
self.neopixel.show() self.neopixel.show()
return self
def set_rgb_fill(self, rgb): def set_rgb_fill(self, rgb):
''' '''
Takes an RGB or RGBW and displays it on all LEDs/Neopixels 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: if not self.disable_auto_write:
self.neopixel.show() self.neopixel.show()
return self
def increase_hue(self, step=None): def increase_hue(self, step=None):
''' '''
Increases hue by step amount rolling at 360 and returning to 0 Increases hue by step amount rolling at 360 and returning to 0
@@ -284,8 +296,6 @@ class RGB(Extension):
if self._check_update(): if self._check_update():
self._do_update() self._do_update()
return self
def decrease_hue(self, step=None): def decrease_hue(self, step=None):
''' '''
Decreases hue by step amount rolling at 0 and returning to 360 Decreases hue by step amount rolling at 0 and returning to 360
@@ -302,8 +312,6 @@ class RGB(Extension):
if self._check_update(): if self._check_update():
self._do_update() self._do_update()
return self
def increase_sat(self, step=None): def increase_sat(self, step=None):
''' '''
Increases saturation by step amount stopping at 100 Increases saturation by step amount stopping at 100
@@ -320,8 +328,6 @@ class RGB(Extension):
if self._check_update(): if self._check_update():
self._do_update() self._do_update()
return self
def decrease_sat(self, step=None): def decrease_sat(self, step=None):
''' '''
Decreases saturation by step amount stopping at 0 Decreases saturation by step amount stopping at 0
@@ -338,8 +344,6 @@ class RGB(Extension):
if self._check_update(): if self._check_update():
self._do_update() self._do_update()
return self
def increase_val(self, step=None): def increase_val(self, step=None):
''' '''
Increases value by step amount stopping at 100 Increases value by step amount stopping at 100
@@ -355,8 +359,6 @@ class RGB(Extension):
if self._check_update(): if self._check_update():
self._do_update() self._do_update()
return self
def decrease_val(self, step=None): def decrease_val(self, step=None):
''' '''
Decreases value by step amount stopping at 0 Decreases value by step amount stopping at 0
@@ -372,8 +374,6 @@ class RGB(Extension):
if self._check_update(): if self._check_update():
self._do_update() self._do_update()
return self
def increase_ani(self): def increase_ani(self):
''' '''
Increases animation speed by 1 amount stopping at 10 Increases animation speed by 1 amount stopping at 10
@@ -386,8 +386,6 @@ class RGB(Extension):
if self._check_update(): if self._check_update():
self._do_update() self._do_update()
return self
def decrease_ani(self): def decrease_ani(self):
''' '''
Decreases animation speed by 1 amount stopping at 0 Decreases animation speed by 1 amount stopping at 0
@@ -400,8 +398,6 @@ class RGB(Extension):
if self._check_update(): if self._check_update():
self._do_update() self._do_update()
return self
def off(self): def off(self):
''' '''
Turns off all LEDs/Neopixels without changing stored values Turns off all LEDs/Neopixels without changing stored values
@@ -409,8 +405,6 @@ class RGB(Extension):
if self.neopixel: if self.neopixel:
self.set_hsv_fill(0, 0, 0) self.set_hsv_fill(0, 0, 0)
return self
def show(self): def show(self):
''' '''
Turns on all LEDs/Neopixels without changing stored values Turns on all LEDs/Neopixels without changing stored values
@@ -418,8 +412,6 @@ class RGB(Extension):
if self.neopixel: if self.neopixel:
self.neopixel.show() self.neopixel.show()
return self
def animate(self): def animate(self):
''' '''
Activates a "step" in the animation based on the active mode Activates a "step" in the animation based on the active mode
@@ -448,8 +440,6 @@ class RGB(Extension):
else: else:
self.off() self.off()
return self
def _animation_step(self): def _animation_step(self):
interval = self.time_ms() - self.time interval = self.time_ms() - self.time
if interval >= max(self.intervals): if interval >= max(self.intervals):
@@ -471,7 +461,6 @@ class RGB(Extension):
self.pos = 0 self.pos = 0
self.reverse_animation = False self.reverse_animation = False
self.effect_init = False self.effect_init = False
return self
def _check_update(self): def _check_update(self):
return bool(self.animation_mode == AnimationModes.STATIC_STANDBY) return bool(self.animation_mode == AnimationModes.STATIC_STANDBY)
@@ -483,7 +472,6 @@ class RGB(Extension):
def effect_static(self): def effect_static(self):
self.set_hsv_fill(self.hue, self.sat, self.val) self.set_hsv_fill(self.hue, self.sat, self.val)
self.animation_mode = AnimationModes.STATIC_STANDBY self.animation_mode = AnimationModes.STATIC_STANDBY
return self
def effect_breathing(self): def effect_breathing(self):
# http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/ # 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.pos = (self.pos + self.animation_speed) % 256
self.set_hsv_fill(self.hue, self.sat, self.val) self.set_hsv_fill(self.hue, self.sat, self.val)
return self
def effect_breathing_rainbow(self): def effect_breathing_rainbow(self):
self.increase_hue(self.animation_speed) self.increase_hue(self.animation_speed)
self.effect_breathing() self.effect_breathing()
return self
def effect_rainbow(self): def effect_rainbow(self):
self.increase_hue(self.animation_speed) self.increase_hue(self.animation_speed)
self.set_hsv_fill(self.hue, self.sat, self.val) self.set_hsv_fill(self.hue, self.sat, self.val)
return self
def effect_swirl(self): def effect_swirl(self):
self.increase_hue(self.animation_speed) self.increase_hue(self.animation_speed)
self.disable_auto_write = True # Turn off instantly showing self.disable_auto_write = True # Turn off instantly showing
@@ -521,7 +503,6 @@ class RGB(Extension):
# Show final results # Show final results
self.disable_auto_write = False # Resume showing changes self.disable_auto_write = False # Resume showing changes
self.show() self.show()
return self
def effect_knight(self): def effect_knight(self):
# Determine which LEDs should be lit up # Determine which LEDs should be lit up
@@ -546,8 +527,6 @@ class RGB(Extension):
self.disable_auto_write = False # Resume showing changes self.disable_auto_write = False # Resume showing changes
self.show() self.show()
return self
def _rgb_tog(self, key, state, *args, **kwargs): def _rgb_tog(self, key, state, *args, **kwargs):
if self.animation_mode == AnimationModes.STATIC: if self.animation_mode == AnimationModes.STATIC:
self.animation_mode = AnimationModes.STATIC_STANDBY self.animation_mode = AnimationModes.STATIC_STANDBY
@@ -556,69 +535,54 @@ class RGB(Extension):
self.animation_mode = AnimationModes.STATIC self.animation_mode = AnimationModes.STATIC
self._do_update() self._do_update()
self.enable = not self.enable self.enable = not self.enable
return state
def _rgb_hui(self, key, state, *args, **kwargs): def _rgb_hui(self, key, state, *args, **kwargs):
self.increase_hue() self.increase_hue()
return state
def _rgb_hud(self, key, state, *args, **kwargs): def _rgb_hud(self, key, state, *args, **kwargs):
self.decrease_hue() self.decrease_hue()
return state
def _rgb_sai(self, key, state, *args, **kwargs): def _rgb_sai(self, key, state, *args, **kwargs):
self.increase_sat() self.increase_sat()
return state
def _rgb_sad(self, key, state, *args, **kwargs): def _rgb_sad(self, key, state, *args, **kwargs):
self.decrease_sat() self.decrease_sat()
return state
def _rgb_vai(self, key, state, *args, **kwargs): def _rgb_vai(self, key, state, *args, **kwargs):
self.increase_val() self.increase_val()
return state
def _rgb_vad(self, key, state, *args, **kwargs): def _rgb_vad(self, key, state, *args, **kwargs):
self.decrease_val() self.decrease_val()
return state
def _rgb_ani(self, key, state, *args, **kwargs): def _rgb_ani(self, key, state, *args, **kwargs):
self.increase_ani() self.increase_ani()
return state
def _rgb_and(self, key, state, *args, **kwargs): def _rgb_and(self, key, state, *args, **kwargs):
self.decrease_ani() self.decrease_ani()
return state
def _rgb_mode_static(self, key, state, *args, **kwargs): def _rgb_mode_static(self, key, state, *args, **kwargs):
self.effect_init = True self.effect_init = True
self.animation_mode = AnimationModes.STATIC self.animation_mode = AnimationModes.STATIC
return state
def _rgb_mode_breathe(self, key, state, *args, **kwargs): def _rgb_mode_breathe(self, key, state, *args, **kwargs):
self.effect_init = True self.effect_init = True
self.animation_mode = AnimationModes.BREATHING self.animation_mode = AnimationModes.BREATHING
return state
def _rgb_mode_breathe_rainbow(self, key, state, *args, **kwargs): def _rgb_mode_breathe_rainbow(self, key, state, *args, **kwargs):
self.effect_init = True self.effect_init = True
self.animation_mode = AnimationModes.BREATHING_RAINBOW self.animation_mode = AnimationModes.BREATHING_RAINBOW
return state
def _rgb_mode_rainbow(self, key, state, *args, **kwargs): def _rgb_mode_rainbow(self, key, state, *args, **kwargs):
self.effect_init = True self.effect_init = True
self.animation_mode = AnimationModes.RAINBOW self.animation_mode = AnimationModes.RAINBOW
return state
def _rgb_mode_swirl(self, key, state, *args, **kwargs): def _rgb_mode_swirl(self, key, state, *args, **kwargs):
self.effect_init = True self.effect_init = True
self.animation_mode = AnimationModes.SWIRL self.animation_mode = AnimationModes.SWIRL
return state
def _rgb_mode_knight(self, key, state, *args, **kwargs): def _rgb_mode_knight(self, key, state, *args, **kwargs):
self.effect_init = True self.effect_init = True
self.animation_mode = AnimationModes.KNIGHT self.animation_mode = AnimationModes.KNIGHT
return state
def _rgb_reset(self, key, state, *args, **kwargs): def _rgb_reset(self, key, state, *args, **kwargs):
self.hue = self.hue_default self.hue = self.hue_default
@@ -627,4 +591,3 @@ class RGB(Extension):
if self.animation_mode == AnimationModes.STATIC_STANDBY: if self.animation_mode == AnimationModes.STATIC_STANDBY:
self.animation_mode = AnimationModes.STATIC self.animation_mode = AnimationModes.STATIC
self._do_update() self._do_update()
return state

View File

@@ -37,6 +37,12 @@ class Split(Extension):
self.uart_pin = uart_pin self.uart_pin = uart_pin
self.uart_timeout = uart_timeout self.uart_timeout = uart_timeout
def on_runtime_enable(self, keyboard):
return
def on_runtime_disable(self, keyboard):
return
def during_bootup(self, keyboard): def during_bootup(self, keyboard):
try: try:
# Working around https://github.com/adafruit/circuitpython/issues/1769 # Working around https://github.com/adafruit/circuitpython/issues/1769
@@ -75,14 +81,21 @@ class Split(Extension):
for cidx in range(cols_to_calc): for cidx in range(cols_to_calc):
keyboard.coord_mapping.append(intify_coordinate(ridx, cidx)) 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: if self._is_target:
return self._receive() 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: if matrix_update is not None and not self._is_target:
self._send(matrix_update) self._send(matrix_update)
def before_hid_send(self, keyboard):
return
def after_hid_send(self, keyboard):
return
def _send(self, update): def _send(self, update):
if self.split_target_left: if self.split_target_left:
update[1] += self.split_offset 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): def sequence_press_handler(key, state, KC, *args, **kwargs):
old_keys_pressed = state._keys_pressed oldkeys_pressed = state.keys_pressed
state._keys_pressed = set() state.keys_pressed = set()
for ikey in key.meta.seq: for ikey in key.meta.seq:
if not getattr(ikey, 'no_press', None): if not getattr(ikey, 'no_press', None):
state._process_key(ikey, True) state.process_key(ikey, True)
state._send_hid() state._send_hid()
if not getattr(ikey, 'no_release', None): if not getattr(ikey, 'no_release', None):
state._process_key(ikey, False) state.process_key(ikey, False)
state._send_hid() state._send_hid()
state._keys_pressed = old_keys_pressed state.keys_pressed = oldkeys_pressed
return state return state
@@ -104,15 +104,15 @@ def unicode_codepoint_sequence(codepoints):
def _unicode_sequence(key, state, *args, **kwargs): def _unicode_sequence(key, state, *args, **kwargs):
if state.unicode_mode == UnicodeMode.IBUS: if state.unicode_mode == UnicodeMode.IBUS:
state._process_key( state.process_key(
simple_key_sequence(_ibus_unicode_sequence(kc_macros, state)), True simple_key_sequence(_ibus_unicode_sequence(kc_macros, state)), True
) )
elif state.unicode_mode == UnicodeMode.RALT: elif state.unicode_mode == UnicodeMode.RALT:
state._process_key( state.process_key(
simple_key_sequence(_ralt_unicode_sequence(kc_macros, state)), True simple_key_sequence(_ralt_unicode_sequence(kc_macros, state)), True
) )
elif state.unicode_mode == UnicodeMode.WINC: elif state.unicode_mode == UnicodeMode.WINC:
state._process_key( state.process_key(
simple_key_sequence(_winc_unicode_sequence(kc_macros, state)), True 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): 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: 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 return state
def default_released(key, state, KC, coord_int=None, coord_raw=None): def default_released(key, state, KC, coord_int=None, coord_raw=None):
state._hid_pending = True state.hid_pending = True
state._keys_pressed.discard(key) state.keys_pressed.discard(key)
if coord_int is not None: if coord_int is not None:
state._keys_pressed.discard(state._coord_keys_pressed.get(coord_int, None)) state.keys_pressed.discard(state._coordkeys_pressed.get(coord_int, None))
state._coord_keys_pressed[coord_int] = None state._coordkeys_pressed[coord_int] = None
return state return state
def reset(*args, **kwargs): def reset(*args, **kwargs):
try: import microcontroller
import machine
machine.reset() microcontroller.reset()
except ImportError:
import microcontroller
microcontroller.reset()
def bootloader(*args, **kwargs): def bootloader(*args, **kwargs):
try: import microcontroller
import machine
machine.bootloader() microcontroller.on_next_reset(microcontroller.RunMode.BOOTLOADER)
microcontroller.reset()
except ImportError:
import microcontroller
microcontroller.on_next_reset(microcontroller.RunMode.BOOTLOADER)
microcontroller.reset()
def debug_pressed(key, state, KC, *args, **kwargs): 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): def gesc_pressed(key, state, KC, *args, **kwargs):
GESC_TRIGGERS = {KC.LSHIFT, KC.RSHIFT, KC.LGUI, KC.RGUI} 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 # First, release GUI if already pressed
state._send_hid() state._send_hid()
# if Shift is held, KC_GRAVE will become KC_TILDE on OS level # if Shift is held, KC_GRAVE will become KC_TILDE on OS level
state._keys_pressed.add(KC.GRAVE) state.keys_pressed.add(KC.GRAVE)
state._hid_pending = True state.hid_pending = True
return state return state
# else return KC_ESC # else return KC_ESC
state._keys_pressed.add(KC.ESCAPE) state.keys_pressed.add(KC.ESCAPE)
state._hid_pending = True state.hid_pending = True
return state return state
def gesc_released(key, state, KC, *args, **kwargs): def gesc_released(key, state, KC, *args, **kwargs):
state._keys_pressed.discard(KC.ESCAPE) state.keys_pressed.discard(KC.ESCAPE)
state._keys_pressed.discard(KC.GRAVE) state.keys_pressed.discard(KC.GRAVE)
state._hid_pending = True state.hid_pending = True
return state return state
def bkdl_pressed(key, state, KC, *args, **kwargs): def bkdl_pressed(key, state, KC, *args, **kwargs):
BKDL_TRIGGERS = {KC.LGUI, KC.RGUI} BKDL_TRIGGERS = {KC.LGUI, KC.RGUI}
if BKDL_TRIGGERS.intersection(state._keys_pressed): if BKDL_TRIGGERS.intersection(state.keys_pressed):
state._send_hid() state._send_hid()
state._keys_pressed.add(KC.DEL) state.keys_pressed.add(KC.DEL)
state._hid_pending = True state.hid_pending = True
return state return state
# else return KC_ESC # else return KC_ESC
state._keys_pressed.add(KC.BKSP) state.keys_pressed.add(KC.BKSP)
state._hid_pending = True state.hid_pending = True
return state return state
def bkdl_released(key, state, KC, *args, **kwargs): def bkdl_released(key, state, KC, *args, **kwargs):
state._keys_pressed.discard(KC.BKSP) state.keys_pressed.discard(KC.BKSP)
state._keys_pressed.discard(KC.DEL) state.keys_pressed.discard(KC.DEL)
state._hid_pending = True state.hid_pending = True
return state return state

View File

@@ -60,7 +60,7 @@ class Key:
def __repr__(self): def __repr__(self):
return 'Key(code={}, has_modifiers={})'.format(self.code, self.has_modifiers) 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: for fn in self._pre_press_handlers:
if not fn(self, state, KC, coord_int, coord_raw): if not fn(self, state, KC, coord_int, coord_raw):
return None return None
@@ -72,7 +72,7 @@ class Key:
return ret 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: for fn in self._pre_release_handlers:
if not fn(self, state, KC, coord_int, coord_raw): if not fn(self, state, KC, coord_int, coord_raw):
return None return None

View File

@@ -28,22 +28,22 @@ class KMKKeyboard:
##### #####
# Internal State # Internal State
_keys_pressed = set() keys_pressed = set()
_coord_keys_pressed = {} _coordkeys_pressed = {}
hid_type = HIDModes.USB hid_type = HIDModes.USB
_hid_helper = None _hid_helper = None
_hid_pending = False hid_pending = False
_state_layer_key = None state_layer_key = None
_matrix_update = None matrix_update = None
_matrix_modify = None _matrix_modify = None
_state_changed = False state_changed = False
_old_timeouts_len = None _old_timeouts_len = None
_new_timeouts_len = None _new_timeouts_len = None
# this should almost always be PREpended to, replaces # this should almost always be PREpended to, replaces
# former use of reversed_active_layers which had pointless # former use of reversed_active_layers which had pointless
# overhead (the underlying list was never used anyway) # overhead (the underlying list was never used anyway)
_active_layers = [0] active_layers = [0]
_timeouts = {} _timeouts = {}
_tapping = False _tapping = False
@@ -64,7 +64,7 @@ class KMKKeyboard:
'tap_time={} ' 'tap_time={} '
'_hid_helper={} ' '_hid_helper={} '
'keys_pressed={} ' 'keys_pressed={} '
'coord_keys_pressed={} ' 'coordkeys_pressed={} '
'hid_pending={} ' 'hid_pending={} '
'active_layers={} ' 'active_layers={} '
'timeouts={} ' 'timeouts={} '
@@ -82,12 +82,12 @@ class KMKKeyboard:
self.matrix_scanner, self.matrix_scanner,
self.unicode_mode, self.unicode_mode,
self.tap_time, self.tap_time,
self._hid_helper.__name__, self._hid_helper,
# internal state # internal state
self._keys_pressed, self.keys_pressed,
self._coord_keys_pressed, self._coordkeys_pressed,
self._hid_pending, self.hid_pending,
self._active_layers, self.active_layers,
self._timeouts, self._timeouts,
self._tapping, self._tapping,
self._tap_dance_counts, self._tap_dance_counts,
@@ -102,13 +102,13 @@ class KMKKeyboard:
print(self) print(self)
def _send_hid(self): def _send_hid(self):
self._hid_helper.create_report(self._keys_pressed).send() self._hid_helper.create_report(self.keys_pressed).send()
self._hid_pending = False self.hid_pending = False
def _handle_matrix_report(self, update=None): def _handle_matrix_report(self, update=None):
if update is not None: if update is not None:
self._on_matrix_changed(update[0], update[1], update[2]) self._on_matrix_changed(update[0], update[1], update[2])
self._state_changed = True self.state_changed = True
##### #####
# SPLICE: INTERNAL STATE # SPLICE: INTERNAL STATE
@@ -116,7 +116,7 @@ class KMKKeyboard:
##### #####
def _find_key_in_map(self, int_coord, row, col): def _find_key_in_map(self, int_coord, row, col):
self._state_layer_key = None self.state_layer_key = None
try: try:
idx = self.coord_mapping.index(int_coord) idx = self.coord_mapping.index(int_coord)
except ValueError: except ValueError:
@@ -129,16 +129,16 @@ class KMKKeyboard:
return None return None
for layer in self._active_layers: for layer in self.active_layers:
self._state_layer_key = self.keymap[layer][idx] 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 continue
if self.debug_enabled: 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): def _on_matrix_changed(self, row, col, is_pressed):
if self.debug_enabled: if self.debug_enabled:
@@ -151,31 +151,31 @@ class KMKKeyboard:
print('MatrixUndefinedCoordinate(col={} row={})'.format(col, row)) print('MatrixUndefinedCoordinate(col={} row={})'.format(col, row))
return self 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): if self._tapping and not isinstance(key.meta, TapDanceKeyMeta):
self._process_tap_dance(key, is_pressed) self._process_tap_dance(key, is_pressed)
else: else:
if is_pressed: if is_pressed:
key._on_press(self, coord_int, coord_raw) key.on_press(self, coord_int, coord_raw)
else: else:
key._on_release(self, coord_int, coord_raw) key.on_release(self, coord_int, coord_raw)
return self return self
def _remove_key(self, keycode): def remove_key(self, keycode):
self._keys_pressed.discard(keycode) self.keys_pressed.discard(keycode)
return self._process_key(keycode, False) return self.process_key(keycode, False)
def _add_key(self, keycode): def add_key(self, keycode):
self._keys_pressed.add(keycode) self.keys_pressed.add(keycode)
return self._process_key(keycode, True) return self.process_key(keycode, True)
def _tap_key(self, keycode): def tap_key(self, keycode):
self._add_key(keycode) self.add_key(keycode)
# On the next cycle, we'll remove the key. # 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 return self
@@ -196,7 +196,7 @@ class KMKKeyboard:
or not self._tap_dance_counts[changed_key] or not self._tap_dance_counts[changed_key]
): ):
self._tap_dance_counts[changed_key] = 1 self._tap_dance_counts[changed_key] = 1
self._set_timeout( self.set_timeout(
self.tap_time, lambda: self._end_tap_dance(changed_key) self.tap_time, lambda: self._end_tap_dance(changed_key)
) )
self._tapping = True self._tapping = True
@@ -220,19 +220,19 @@ class KMKKeyboard:
v = self._tap_dance_counts[td_key] - 1 v = self._tap_dance_counts[td_key] - 1
if v >= 0: if v >= 0:
if td_key in self._keys_pressed: if td_key in self.keys_pressed:
key_to_press = td_key.codes[v] 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._tap_side_effects[td_key] = key_to_press
self._hid_pending = True self.hid_pending = True
else: else:
if self._tap_side_effects[td_key]: 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._tap_side_effects[td_key] = None
self._hid_pending = True self.hid_pending = True
self._cleanup_tap_dance(td_key) self._cleanup_tap_dance(td_key)
else: else:
self._tap_key(td_key.codes[v]) self.tap_key(td_key.codes[v])
self._cleanup_tap_dance(td_key) self._cleanup_tap_dance(td_key)
return self return self
@@ -242,7 +242,7 @@ class KMKKeyboard:
self._tapping = any(count > 0 for count in self._tap_dance_counts.values()) self._tapping = any(count > 0 for count in self._tap_dance_counts.values())
return self return self
def _set_timeout(self, after_ticks, callback): def set_timeout(self, after_ticks, callback):
if after_ticks is False: if after_ticks is False:
# We allow passing False as an implicit "run this on the next process timeouts cycle" # We allow passing False as an implicit "run this on the next process timeouts cycle"
timeout_key = ticks_ms() timeout_key = ticks_ms()
@@ -366,7 +366,7 @@ class KMKKeyboard:
self._print_debug_cycle(init=True) self._print_debug_cycle(init=True)
while True: while True:
self._state_changed = False self.state_changed = False
for ext in self.extensions: for ext in self.extensions:
try: try:
@@ -374,20 +374,20 @@ class KMKKeyboard:
except Exception as err: except Exception as err:
print('Failed to run pre matrix function: ', 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: for ext in self.extensions:
try: try:
self._matrix_modify = ext.after_matrix_scan( self._matrix_modify = ext.after_matrix_scan(
self, self._matrix_update self, self.matrix_update
) )
if self._matrix_modify is not None: if self._matrix_modify is not None:
self._matrix_update = self._matrix_modify self.matrix_update = self._matrix_modify
except Exception as err: except Exception as err:
print('Failed to run post matrix function: ', err) print('Failed to run post matrix function: ', err)
self._handle_matrix_report(self._matrix_update) self._handle_matrix_report(self.matrix_update)
self._matrix_update = None self.matrix_update = None
for ext in self.extensions: for ext in self.extensions:
try: try:
@@ -395,7 +395,7 @@ class KMKKeyboard:
except Exception as err: except Exception as err:
print('Failed to run pre hid function: ', err) print('Failed to run pre hid function: ', err)
if self._hid_pending: if self.hid_pending:
self._send_hid() self._send_hid()
self._old_timeouts_len = len(self._timeouts) self._old_timeouts_len = len(self._timeouts)
@@ -403,8 +403,8 @@ class KMKKeyboard:
self._new_timeouts_len = len(self._timeouts) self._new_timeouts_len = len(self._timeouts)
if self._old_timeouts_len != self._new_timeouts_len: if self._old_timeouts_len != self._new_timeouts_len:
self._state_changed = True self.state_changed = True
if self._hid_pending: if self.hid_pending:
self._send_hid() self._send_hid()
for ext in self.extensions: for ext in self.extensions:
@@ -413,5 +413,5 @@ class KMKKeyboard:
except Exception as err: except Exception as err:
print('Failed to run post hid function: ', err) print('Failed to run post hid function: ', err)
if self._state_changed: if self.state_changed:
self._print_debug_cycle() self._print_debug_cycle()