Merge pull request #133 from KMKfw/topic-misc-perf

Slight perf improvements, heavily improved logging/debugging output
This commit is contained in:
Josh Klar 2019-07-12 17:01:26 -07:00 committed by GitHub
commit f6a39acd26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 216 additions and 142 deletions

View File

@ -15,16 +15,18 @@
# chain to import _every single thing_ KMK eventually uses in a normal # chain to import _every single thing_ KMK eventually uses in a normal
# workflow, in order from fewest to least nested dependencies. # workflow, in order from fewest to least nested dependencies.
# First, stuff that has no dependencies, or only C/MPY deps # First, system-provided deps
import busio # isort:skip
import collections # isort:skip import collections # isort:skip
import gc # isort:skip
import supervisor # isort:skip
# Now "light" KMK stuff with few/no external deps
import kmk.consts # isort:skip import kmk.consts # isort:skip
import kmk.kmktime # isort:skip import kmk.kmktime # isort:skip
import kmk.types # isort:skip import kmk.types # isort:skip
import kmk.util # isort:skip import kmk.util # isort:skip
import busio # isort:skip
import supervisor # isort:skip
from kmk.consts import LeaderMode, UnicodeMode # isort:skip from kmk.consts import LeaderMode, UnicodeMode # isort:skip
from kmk.hid import USB_HID # isort:skip from kmk.hid import USB_HID # isort:skip
from kmk.internal_state import InternalState # isort:skip from kmk.internal_state import InternalState # isort:skip
@ -48,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
@ -100,6 +103,76 @@ class Firmware:
self._state = InternalState(self) self._state = InternalState(self)
def __repr__(self):
return (
'Firmware('
'debug_enabled={} '
'keymap=truncated '
'coord_mapping=truncated '
'row_pins=truncated '
'col_pins=truncated '
'diode_orientation={} '
'matrix_scanner={} '
'unicode_mode={} '
'tap_time={} '
'leader_mode={} '
'leader_dictionary=truncated '
'leader_timeout={} '
'hid_helper={} '
'extra_data_pin={} '
'split_offsets={} '
'split_flip={} '
'split_side={} '
'split_type={} '
'split_master_left={} '
'is_master={} '
'uart={} '
'uart_flip={} '
'uart_pin={}'
')'
).format(
self.debug_enabled,
# self.keymap,
# self.coord_mapping,
# self.row_pins,
# self.col_pins,
self.diode_orientation,
self.matrix_scanner,
self.unicode_mode,
self.tap_time,
self.leader_mode,
# self.leader_dictionary,
self.leader_timeout,
self.hid_helper.__name__,
self.extra_data_pin,
self.split_offsets,
self.split_flip,
self.split_side,
self.split_type,
self.split_master_left,
self.is_master,
self.uart,
self.uart_flip,
self.uart_pin,
)
def _print_debug_cycle(self, init=False):
pre_alloc = gc.mem_alloc()
pre_free = gc.mem_free()
if self.debug_enabled:
if init:
print('KMKInit()')
print(self)
print(self._state)
print('GCStats(pre_alloc={} pre_free={} alloc={} free={})'.format(
pre_alloc,
pre_free,
gc.mem_alloc(),
gc.mem_free(),
))
def _send_hid(self): def _send_hid(self):
self._hid_helper_inst.create_report(self._state.keys_pressed).send() self._hid_helper_inst.create_report(self._state.keys_pressed).send()
self._state.resolve_hid() self._state.resolve_hid()
@ -155,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)
@ -183,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)
@ -211,13 +285,13 @@ class Firmware:
if not isinstance(k, tuple): if not isinstance(k, tuple):
del self.leader_dictionary[k] del self.leader_dictionary[k]
if self.debug_enabled: gc.collect()
print("Firin' lazers. Keyboard is booted.") self._print_debug_cycle(init=True)
while True: while True:
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)
@ -226,7 +300,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:
@ -246,5 +320,5 @@ class Firmware:
if self._state.hid_pending: if self._state.hid_pending:
self._send_hid() self._send_hid()
if self.debug_enabled and state_changed: if state_changed:
print('New State: {}'.format(self._state._to_dict())) self._print_debug_cycle()

View File

@ -3,24 +3,31 @@ from kmk.kmktime import ticks_diff, ticks_ms
def df_pressed(key, state, *args, **kwargs): def df_pressed(key, state, *args, **kwargs):
"""Switches the default layer""" """Switches the default layer"""
state.active_layers[0] = key.meta.layer state.active_layers[-1] = key.meta.layer
state.reversed_active_layers = list(reversed(state.active_layers))
return state return state
def mo_pressed(key, state, *args, **kwargs): 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.append(key.meta.layer) state.active_layers.insert(0, key.meta.layer)
state.reversed_active_layers = list(reversed(state.active_layers))
return state return state
def mo_released(key, state, KC, *args, **kwargs): def mo_released(key, state, KC, *args, **kwargs):
state.active_layers = [ # remove the first instance of the target layer
layer for layer in state.active_layers # from the active list
if layer != key.meta.layer # under almost all normal use cases, this will
] # disable the layer (but preserve it if it was triggered
state.reversed_active_layers = list(reversed(state.active_layers)) # as a default layer, etc.)
# this also resolves an issue where using DF() on a layer
# triggered by MO() and then defaulting to the MO()'s layer
# would result in no layers active
try:
del_idx = state.active_layers.index(key.meta.layer)
del state.active_layers[del_idx]
except ValueError:
pass
return state return state
@ -62,23 +69,21 @@ def lt_released(key, state, *args, **kwargs):
def tg_pressed(key, state, *args, **kwargs): 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)"""
if key.meta.layer in state.active_layers:
state.active_layers = [
layer for layer in state.active_layers
if layer != key.meta.layer
]
else:
state.active_layers.append(key.meta.layer)
state.reversed_active_layers = list(reversed(state.active_layers)) # See mo_released for implementation details around this
try:
del_idx = state.active_layers.index(key.meta.layer)
del state.active_layers[del_idx]
except ValueError:
state.active_layers.insert(0, key.meta.layer)
return state return state
def to_pressed(key, state, *args, **kwargs): def to_pressed(key, state, *args, **kwargs):
"""Activates layer and deactivates all other layers""" """Activates layer and deactivates all other layers"""
state.active_layers = [key.meta.layer] state.active_layers.clear()
state.reversed_active_layers = list(reversed(state.active_layers)) state.active_layers.insert(0, key.meta.layer)
return state return state

View File

@ -38,9 +38,9 @@ def bootloader(*args, **kwargs):
def debug_pressed(key, state, KC, *args, **kwargs): def debug_pressed(key, state, KC, *args, **kwargs):
if state.config.debug_enabled: if state.config.debug_enabled:
print('Disabling debug mode, bye!') print('DebugDisable()')
else: else:
print('Enabling debug mode. Welcome to the jungle.') print('DebugEnable()')
state.config.debug_enabled = not state.config.debug_enabled state.config.debug_enabled = not state.config.debug_enabled

View File

@ -21,6 +21,12 @@ class USB_HID:
self.post_init() self.post_init()
def __repr__(self):
return '{}(REPORT_BYTES={})'.format(
self.__class__.__name__,
self.REPORT_BYTES,
)
def post_init(self): def post_init(self):
pass pass

View File

@ -12,8 +12,12 @@ class InternalState:
leader_last_len = 0 leader_last_len = 0
hid_pending = False hid_pending = False
leader_mode_history = [] leader_mode_history = []
# 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]
reversed_active_layers = list(reversed(active_layers))
start_time = { start_time = {
'lt': None, 'lt': None,
'tg': None, 'tg': None,
@ -30,21 +34,35 @@ class InternalState:
self.config = config self.config = config
def __repr__(self): def __repr__(self):
return 'InternalState({})'.format(self._to_dict()) return (
'InternalState('
def _to_dict(self): 'keys_pressed={} '
ret = { 'coord_keys_pressed={} '
'keys_pressed': self.keys_pressed, 'leader_pending={} '
'active_layers': self.active_layers, 'leader_last_len={} '
'leader_mode_history': self.leader_mode_history, 'hid_pending={} '
'leader_mode': self.config.leader_mode, 'leader_mode_history={} '
'start_time': self.start_time, 'active_layers={} '
'tapping': self.tapping, 'start_time={} '
'tap_dance_counts': self.tap_dance_counts, 'timeouts={} '
'timeouts': self.timeouts, 'tapping={} '
} 'tap_dance_counts={} '
'tap_side_effects={}'
return ret ')'
).format(
self.keys_pressed,
self.coord_keys_pressed,
self.leader_pending,
self.leader_last_len,
self.hid_pending,
self.leader_mode_history,
self.active_layers,
self.start_time,
self.timeouts,
self.tapping,
self.tap_dance_counts,
self.tap_side_effects,
)
def _find_key_in_map(self, row, col): def _find_key_in_map(self, row, col):
ic = intify_coordinate(row, col) ic = intify_coordinate(row, col)
@ -54,7 +72,7 @@ class InternalState:
except ValueError: except ValueError:
if self.config.debug_enabled: if self.config.debug_enabled:
print( print(
'No coord_mapping index for value {}, row={} col={}'.format( 'CoordMappingNotFound(ic={}, row={}, col={})'.format(
ic, ic,
row, row,
col, col,
@ -63,16 +81,14 @@ class InternalState:
return None return None
# Later-added layers have priority. Sift through the layers for layer in self.active_layers:
# in reverse order until we find a valid keycode object
for layer in self.reversed_active_layers:
layer_key = self.config.keymap[layer][idx] layer_key = self.config.keymap[layer][idx]
if not layer_key or layer_key == KC.TRNS: if not layer_key or layer_key == KC.TRNS:
continue continue
if self.config.debug_enabled: if self.config.debug_enabled:
print('Resolved key: {}'.format(layer_key)) print('KeyResolution(key={})'.format(layer_key))
return layer_key return layer_key
@ -112,15 +128,17 @@ class InternalState:
def matrix_changed(self, row, col, is_pressed): def matrix_changed(self, row, col, is_pressed):
if self.config.debug_enabled: if self.config.debug_enabled:
print('Matrix changed (col, row, pressed?): {}, {}, {}'.format( print('MatrixChange(col={} row={} pressed={})'.format(
col, row, is_pressed, col,
row,
is_pressed,
)) ))
int_coord = intify_coordinate(row, col) int_coord = intify_coordinate(row, col)
kc_changed = self._find_key_in_map(row, col) kc_changed = self._find_key_in_map(row, col)
if kc_changed is None: if kc_changed is None:
print('No key accessible for col, row: {}, {}'.format(row, col)) 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))

32
kmk/key_validators.py Normal file
View 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)

View File

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

View File

@ -6,7 +6,7 @@ from kmk.keys import KC
keyboard = Firmware() keyboard = Firmware()
keyboard.debug_enabled = True keyboard.debug_enabled = False
keyboard.unicode_mode = UnicodeMode.LINUX keyboard.unicode_mode = UnicodeMode.LINUX
keyboard.tap_time = 750 keyboard.tap_time = 750