Clean some code up; force GC on every cycle
This commit is contained in:
parent
2947f81489
commit
17094a2988
@ -50,6 +50,7 @@ import kmk.internal_state # isort:skip
|
|||||||
|
|
||||||
# Thanks for sticking around. Now let's do real work, starting below
|
# Thanks for sticking around. Now let's do real work, starting below
|
||||||
|
|
||||||
|
from kmk.kmktime import sleep_ms
|
||||||
from kmk.util import intify_coordinate as ic
|
from kmk.util import intify_coordinate as ic
|
||||||
|
|
||||||
|
|
||||||
@ -156,13 +157,18 @@ class Firmware:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _print_debug_cycle(self, init=False):
|
def _print_debug_cycle(self, init=False):
|
||||||
|
pre_alloc = gc.mem_alloc()
|
||||||
|
pre_free = gc.mem_free()
|
||||||
|
|
||||||
if self.debug_enabled:
|
if self.debug_enabled:
|
||||||
if init:
|
if init:
|
||||||
print('KMKInit()')
|
print('KMKInit()')
|
||||||
|
|
||||||
print(self)
|
print(self)
|
||||||
print(self._state)
|
print(self._state)
|
||||||
print('GCStats(alloc={} free={})'.format(
|
print('GCStats(pre_alloc={} pre_free={} alloc={} free={})'.format(
|
||||||
|
pre_alloc,
|
||||||
|
pre_free,
|
||||||
gc.mem_alloc(),
|
gc.mem_alloc(),
|
||||||
gc.mem_free(),
|
gc.mem_free(),
|
||||||
))
|
))
|
||||||
@ -222,21 +228,8 @@ class Firmware:
|
|||||||
self.uart.write('DEB')
|
self.uart.write('DEB')
|
||||||
self.uart.write(message, '\n')
|
self.uart.write(message, '\n')
|
||||||
|
|
||||||
def _master_half(self):
|
|
||||||
if self.is_master is not None:
|
|
||||||
return self.is_master
|
|
||||||
|
|
||||||
# Working around https://github.com/adafruit/circuitpython/issues/1769
|
|
||||||
try:
|
|
||||||
self._hid_helper_inst.create_report([]).send()
|
|
||||||
self.is_master = True
|
|
||||||
except OSError:
|
|
||||||
self.is_master = False
|
|
||||||
|
|
||||||
return self.is_master
|
|
||||||
|
|
||||||
def init_uart(self, pin, timeout=20):
|
def init_uart(self, pin, timeout=20):
|
||||||
if self._master_half():
|
if self.is_master:
|
||||||
return busio.UART(tx=None, rx=pin, timeout=timeout)
|
return busio.UART(tx=None, rx=pin, timeout=timeout)
|
||||||
else:
|
else:
|
||||||
return busio.UART(tx=pin, rx=None, timeout=timeout)
|
return busio.UART(tx=pin, rx=None, timeout=timeout)
|
||||||
@ -250,13 +243,27 @@ class Firmware:
|
|||||||
self._hid_helper_inst = self.hid_helper()
|
self._hid_helper_inst = self.hid_helper()
|
||||||
|
|
||||||
# Split keyboard Init
|
# Split keyboard Init
|
||||||
if self.split_flip and not self._master_half():
|
if self.split_type is not None:
|
||||||
self.col_pins = list(reversed(self.col_pins))
|
try:
|
||||||
|
# Working around https://github.com/adafruit/circuitpython/issues/1769
|
||||||
|
self._hid_helper_inst.create_report([]).send()
|
||||||
|
self.is_master = True
|
||||||
|
|
||||||
if self.split_side == "Left":
|
# Sleep 2s so master portion doesn't "appear" to boot quicker than
|
||||||
self.split_master_left = self._master_half()
|
# dependent portions (which will take ~2s to time out on the HID send)
|
||||||
elif self.split_side == "Right":
|
sleep_ms(2000)
|
||||||
self.split_master_left = not self._master_half()
|
except OSError:
|
||||||
|
self.is_master = False
|
||||||
|
|
||||||
|
if self.split_flip and not self.is_master:
|
||||||
|
self.col_pins = list(reversed(self.col_pins))
|
||||||
|
|
||||||
|
if self.split_side == "Left":
|
||||||
|
self.split_master_left = self.is_master
|
||||||
|
elif self.split_side == "Right":
|
||||||
|
self.split_master_left = not self.is_master
|
||||||
|
else:
|
||||||
|
self.is_master = True
|
||||||
|
|
||||||
if self.uart_pin is not None:
|
if self.uart_pin is not None:
|
||||||
self.uart = self.init_uart(self.uart_pin)
|
self.uart = self.init_uart(self.uart_pin)
|
||||||
@ -278,12 +285,17 @@ class Firmware:
|
|||||||
if not isinstance(k, tuple):
|
if not isinstance(k, tuple):
|
||||||
del self.leader_dictionary[k]
|
del self.leader_dictionary[k]
|
||||||
|
|
||||||
|
gc.collect()
|
||||||
self._print_debug_cycle(init=True)
|
self._print_debug_cycle(init=True)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
# Generally speaking, the less stuff GC has to clean out,
|
||||||
|
# the faster it'll run. Start every cycle with a clean
|
||||||
|
# garbage bin to avoid random hiccups during keypress handling
|
||||||
|
gc.collect()
|
||||||
state_changed = False
|
state_changed = False
|
||||||
|
|
||||||
if self.split_type is not None and self._master_half:
|
if self.split_type is not None and self.is_master:
|
||||||
update = self._receive_from_slave()
|
update = self._receive_from_slave()
|
||||||
if update is not None:
|
if update is not None:
|
||||||
self._handle_matrix_report(update)
|
self._handle_matrix_report(update)
|
||||||
@ -292,7 +304,7 @@ class Firmware:
|
|||||||
update = self.matrix.scan_for_changes()
|
update = self.matrix.scan_for_changes()
|
||||||
|
|
||||||
if update is not None:
|
if update is not None:
|
||||||
if self._master_half():
|
if self.is_master:
|
||||||
self._handle_matrix_report(update)
|
self._handle_matrix_report(update)
|
||||||
state_changed = True
|
state_changed = True
|
||||||
else:
|
else:
|
||||||
|
@ -144,7 +144,6 @@ class InternalState:
|
|||||||
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:
|
||||||
|
32
kmk/key_validators.py
Normal file
32
kmk/key_validators.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
from kmk.types import (KeySeqSleepMeta, LayerKeyMeta, ModTapKeyMeta,
|
||||||
|
TapDanceKeyMeta, UnicodeModeKeyMeta)
|
||||||
|
|
||||||
|
|
||||||
|
def key_seq_sleep_validator(ms):
|
||||||
|
return KeySeqSleepMeta(ms)
|
||||||
|
|
||||||
|
|
||||||
|
def layer_key_validator(layer, kc=None):
|
||||||
|
'''
|
||||||
|
Validates the syntax (but not semantics) of a layer key call. We won't
|
||||||
|
have access to the keymap here, so we can't verify much of anything useful
|
||||||
|
here (like whether the target layer actually exists). The spirit of this
|
||||||
|
existing is mostly that Python will catch extraneous args/kwargs and error
|
||||||
|
out.
|
||||||
|
'''
|
||||||
|
return LayerKeyMeta(layer=layer, kc=kc)
|
||||||
|
|
||||||
|
|
||||||
|
def mod_tap_validator(kc, mods=None):
|
||||||
|
'''
|
||||||
|
Validates that mod tap keys are correctly used
|
||||||
|
'''
|
||||||
|
return ModTapKeyMeta(kc=kc, mods=mods)
|
||||||
|
|
||||||
|
|
||||||
|
def tap_dance_key_validator(*codes):
|
||||||
|
return TapDanceKeyMeta(codes)
|
||||||
|
|
||||||
|
|
||||||
|
def unicode_mode_key_validator(mode):
|
||||||
|
return UnicodeModeKeyMeta(mode)
|
71
kmk/keys.py
71
kmk/keys.py
@ -1,11 +1,11 @@
|
|||||||
import gc
|
|
||||||
|
|
||||||
import kmk.handlers.layers as layers
|
import kmk.handlers.layers as layers
|
||||||
import kmk.handlers.modtap as modtap
|
import kmk.handlers.modtap as modtap
|
||||||
import kmk.handlers.stock as handlers
|
import kmk.handlers.stock as handlers
|
||||||
from kmk.consts import UnicodeMode
|
from kmk.consts import UnicodeMode
|
||||||
from kmk.types import (AttrDict, KeySeqSleepMeta, LayerKeyMeta, ModTapKeyMeta,
|
from kmk.key_validators import (key_seq_sleep_validator, layer_key_validator,
|
||||||
TapDanceKeyMeta, UnicodeModeKeyMeta)
|
mod_tap_validator, tap_dance_key_validator,
|
||||||
|
unicode_mode_key_validator)
|
||||||
|
from kmk.types import AttrDict, UnicodeModeKeyMeta
|
||||||
|
|
||||||
FIRST_KMK_INTERNAL_KEY = 1000
|
FIRST_KMK_INTERNAL_KEY = 1000
|
||||||
NEXT_AVAILABLE_KEY = 1000
|
NEXT_AVAILABLE_KEY = 1000
|
||||||
@ -367,8 +367,6 @@ def make_argumented_key(
|
|||||||
return _argumented_key
|
return _argumented_key
|
||||||
|
|
||||||
|
|
||||||
gc.collect()
|
|
||||||
|
|
||||||
# Modifiers
|
# Modifiers
|
||||||
make_mod_key(code=0x01, names=('LEFT_CONTROL', 'LCTRL', 'LCTL'))
|
make_mod_key(code=0x01, names=('LEFT_CONTROL', 'LCTRL', 'LCTL'))
|
||||||
make_mod_key(code=0x02, names=('LEFT_SHIFT', 'LSHIFT', 'LSFT'))
|
make_mod_key(code=0x02, names=('LEFT_SHIFT', 'LSHIFT', 'LSFT'))
|
||||||
@ -383,8 +381,6 @@ make_mod_key(code=0x07, names=('MEH',))
|
|||||||
# HYPR = LCTL | LALT | LSFT | LGUI
|
# HYPR = LCTL | LALT | LSFT | LGUI
|
||||||
make_mod_key(code=0x0F, names=('HYPER', 'HYPR'))
|
make_mod_key(code=0x0F, names=('HYPER', 'HYPR'))
|
||||||
|
|
||||||
gc.collect()
|
|
||||||
|
|
||||||
# Basic ASCII letters
|
# Basic ASCII letters
|
||||||
make_key(code=4, names=('A',))
|
make_key(code=4, names=('A',))
|
||||||
make_key(code=5, names=('B',))
|
make_key(code=5, names=('B',))
|
||||||
@ -413,8 +409,6 @@ make_key(code=27, names=('X',))
|
|||||||
make_key(code=28, names=('Y',))
|
make_key(code=28, names=('Y',))
|
||||||
make_key(code=29, names=('Z',))
|
make_key(code=29, names=('Z',))
|
||||||
|
|
||||||
gc.collect()
|
|
||||||
|
|
||||||
# Numbers
|
# Numbers
|
||||||
# Aliases to play nicely with AttrDict, since KC.1 isn't a valid
|
# Aliases to play nicely with AttrDict, since KC.1 isn't a valid
|
||||||
# attribute key in Python, but KC.N1 is
|
# attribute key in Python, but KC.N1 is
|
||||||
@ -429,8 +423,6 @@ make_key(code=37, names=('8', 'N8'))
|
|||||||
make_key(code=38, names=('9', 'N9'))
|
make_key(code=38, names=('9', 'N9'))
|
||||||
make_key(code=39, names=('0', 'N0'))
|
make_key(code=39, names=('0', 'N0'))
|
||||||
|
|
||||||
gc.collect()
|
|
||||||
|
|
||||||
# More ASCII standard keys
|
# More ASCII standard keys
|
||||||
make_key(code=40, names=('ENTER', 'ENT', "\n"))
|
make_key(code=40, names=('ENTER', 'ENT', "\n"))
|
||||||
make_key(code=41, names=('ESCAPE', 'ESC'))
|
make_key(code=41, names=('ESCAPE', 'ESC'))
|
||||||
@ -449,8 +441,6 @@ make_key(code=54, names=('COMMA', 'COMM', ','))
|
|||||||
make_key(code=55, names=('DOT', '.'))
|
make_key(code=55, names=('DOT', '.'))
|
||||||
make_key(code=56, names=('SLASH', 'SLSH'))
|
make_key(code=56, names=('SLASH', 'SLSH'))
|
||||||
|
|
||||||
gc.collect()
|
|
||||||
|
|
||||||
# Function Keys
|
# Function Keys
|
||||||
make_key(code=58, names=('F1',))
|
make_key(code=58, names=('F1',))
|
||||||
make_key(code=59, names=('F2',))
|
make_key(code=59, names=('F2',))
|
||||||
@ -477,8 +467,6 @@ make_key(code=113, names=('F22',))
|
|||||||
make_key(code=114, names=('F23',))
|
make_key(code=114, names=('F23',))
|
||||||
make_key(code=115, names=('F24',))
|
make_key(code=115, names=('F24',))
|
||||||
|
|
||||||
gc.collect()
|
|
||||||
|
|
||||||
# Lock Keys, Navigation, etc.
|
# Lock Keys, Navigation, etc.
|
||||||
make_key(code=57, names=('CAPS_LOCK', 'CAPSLOCK', 'CLCK', 'CAPS'))
|
make_key(code=57, names=('CAPS_LOCK', 'CAPSLOCK', 'CLCK', 'CAPS'))
|
||||||
# FIXME: Investigate whether this key actually works, and
|
# FIXME: Investigate whether this key actually works, and
|
||||||
@ -501,8 +489,6 @@ make_key(code=80, names=('LEFT',))
|
|||||||
make_key(code=81, names=('DOWN',))
|
make_key(code=81, names=('DOWN',))
|
||||||
make_key(code=82, names=('UP',))
|
make_key(code=82, names=('UP',))
|
||||||
|
|
||||||
gc.collect()
|
|
||||||
|
|
||||||
# Numpad
|
# Numpad
|
||||||
make_key(code=83, names=('NUM_LOCK', 'NUMLOCK', 'NLCK'))
|
make_key(code=83, names=('NUM_LOCK', 'NUMLOCK', 'NLCK'))
|
||||||
# FIXME: Investigate whether this key actually works, and
|
# FIXME: Investigate whether this key actually works, and
|
||||||
@ -528,8 +514,6 @@ make_key(code=103, names=('KP_EQUAL', 'PEQL', 'NUMPAD_EQUAL'))
|
|||||||
make_key(code=133, names=('KP_COMMA', 'PCMM', 'NUMPAD_COMMA'))
|
make_key(code=133, names=('KP_COMMA', 'PCMM', 'NUMPAD_COMMA'))
|
||||||
make_key(code=134, names=('KP_EQUAL_AS400', 'NUMPAD_EQUAL_AS400'))
|
make_key(code=134, names=('KP_EQUAL_AS400', 'NUMPAD_EQUAL_AS400'))
|
||||||
|
|
||||||
gc.collect()
|
|
||||||
|
|
||||||
# Making life better for folks on tiny keyboards especially: exposes
|
# Making life better for folks on tiny keyboards especially: exposes
|
||||||
# the "shifted" keys as raw keys. Under the hood we're still
|
# the "shifted" keys as raw keys. Under the hood we're still
|
||||||
# sending Shift+(whatever key is normally pressed) to get these, so
|
# sending Shift+(whatever key is normally pressed) to get these, so
|
||||||
@ -556,8 +540,6 @@ make_shifted_key('COMMA', names=('LEFT_ANGLE_BRACKET', 'LABK', '<'))
|
|||||||
make_shifted_key('DOT', names=('RIGHT_ANGLE_BRACKET', 'RABK', '>'))
|
make_shifted_key('DOT', names=('RIGHT_ANGLE_BRACKET', 'RABK', '>'))
|
||||||
make_shifted_key('SLSH', names=('QUESTION', 'QUES', '?'))
|
make_shifted_key('SLSH', names=('QUESTION', 'QUES', '?'))
|
||||||
|
|
||||||
gc.collect()
|
|
||||||
|
|
||||||
# International
|
# International
|
||||||
make_key(code=50, names=('NONUS_HASH', 'NUHS'))
|
make_key(code=50, names=('NONUS_HASH', 'NUHS'))
|
||||||
make_key(code=100, names=('NONUS_BSLASH', 'NUBS'))
|
make_key(code=100, names=('NONUS_BSLASH', 'NUBS'))
|
||||||
@ -582,8 +564,6 @@ 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',))
|
||||||
|
|
||||||
gc.collect()
|
|
||||||
|
|
||||||
# Consumer ("media") keys. Most known keys aren't supported here. A much
|
# Consumer ("media") keys. Most known keys aren't supported here. A much
|
||||||
# longer list used to exist in this file, but the codes were almost certainly
|
# longer list used to exist in this file, but the codes were almost certainly
|
||||||
# incorrect, conflicting with each other, or otherwise "weird". We'll add them
|
# incorrect, conflicting with each other, or otherwise "weird". We'll add them
|
||||||
@ -605,8 +585,6 @@ 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
|
||||||
|
|
||||||
gc.collect()
|
|
||||||
|
|
||||||
# Internal, diagnostic, or auxiliary/enhanced keys
|
# Internal, diagnostic, or auxiliary/enhanced keys
|
||||||
|
|
||||||
# NO and TRNS are functionally identical in how they (don't) mutate
|
# NO and TRNS are functionally identical in how they (don't) mutate
|
||||||
@ -631,18 +609,6 @@ make_key(
|
|||||||
on_release=handlers.passthrough,
|
on_release=handlers.passthrough,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def layer_key_validator(layer, kc=None):
|
|
||||||
'''
|
|
||||||
Validates the syntax (but not semantics) of a layer key call. We won't
|
|
||||||
have access to the keymap here, so we can't verify much of anything useful
|
|
||||||
here (like whether the target layer actually exists). The spirit of this
|
|
||||||
existing is mostly that Python will catch extraneous args/kwargs and error
|
|
||||||
out.
|
|
||||||
'''
|
|
||||||
return LayerKeyMeta(layer=layer, kc=kc)
|
|
||||||
|
|
||||||
|
|
||||||
# Layers
|
# Layers
|
||||||
make_argumented_key(
|
make_argumented_key(
|
||||||
validator=layer_key_validator,
|
validator=layer_key_validator,
|
||||||
@ -684,15 +650,6 @@ make_argumented_key(
|
|||||||
on_release=layers.tt_released,
|
on_release=layers.tt_released,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def mod_tap_validator(kc, mods=None):
|
|
||||||
'''
|
|
||||||
Validates that mod tap keys are correctly used
|
|
||||||
'''
|
|
||||||
return ModTapKeyMeta(kc=kc, mods=mods)
|
|
||||||
|
|
||||||
|
|
||||||
# ModTap
|
|
||||||
make_argumented_key(
|
make_argumented_key(
|
||||||
validator=mod_tap_validator,
|
validator=mod_tap_validator,
|
||||||
names=('MT',),
|
names=('MT',),
|
||||||
@ -700,14 +657,6 @@ make_argumented_key(
|
|||||||
on_release=modtap.mt_released,
|
on_release=modtap.mt_released,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
gc.collect()
|
|
||||||
|
|
||||||
|
|
||||||
def key_seq_sleep_validator(ms):
|
|
||||||
return KeySeqSleepMeta(ms)
|
|
||||||
|
|
||||||
|
|
||||||
# A dummy key to trigger a sleep_ms call in a sequence of other keys in a
|
# A dummy key to trigger a sleep_ms call in a sequence of other keys in a
|
||||||
# simple sequence macro.
|
# simple sequence macro.
|
||||||
make_argumented_key(
|
make_argumented_key(
|
||||||
@ -716,8 +665,6 @@ make_argumented_key(
|
|||||||
on_press=handlers.sleep_pressed,
|
on_press=handlers.sleep_pressed,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Switch unicode modes at runtime
|
|
||||||
make_key(
|
make_key(
|
||||||
names=('UC_MODE_NOOP', 'UC_DISABLE'),
|
names=('UC_MODE_NOOP', 'UC_DISABLE'),
|
||||||
meta=UnicodeModeKeyMeta(UnicodeMode.NOOP),
|
meta=UnicodeModeKeyMeta(UnicodeMode.NOOP),
|
||||||
@ -738,22 +685,14 @@ make_key(
|
|||||||
meta=UnicodeModeKeyMeta(UnicodeMode.WINC),
|
meta=UnicodeModeKeyMeta(UnicodeMode.WINC),
|
||||||
on_press=handlers.uc_mode_pressed,
|
on_press=handlers.uc_mode_pressed,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def unicode_mode_key_validator(mode):
|
|
||||||
return UnicodeModeKeyMeta(mode)
|
|
||||||
|
|
||||||
|
|
||||||
make_argumented_key(
|
make_argumented_key(
|
||||||
validator=unicode_mode_key_validator,
|
validator=unicode_mode_key_validator,
|
||||||
names=('UC_MODE',),
|
names=('UC_MODE',),
|
||||||
on_press=handlers.uc_mode_pressed,
|
on_press=handlers.uc_mode_pressed,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Tap Dance
|
|
||||||
make_argumented_key(
|
make_argumented_key(
|
||||||
validator=lambda *codes: TapDanceKeyMeta(codes),
|
validator=tap_dance_key_validator,
|
||||||
names=('TAP_DANCE', 'TD'),
|
names=('TAP_DANCE', 'TD'),
|
||||||
on_press=handlers.td_pressed,
|
on_press=handlers.td_pressed,
|
||||||
on_release=handlers.td_released,
|
on_release=handlers.td_released,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user