From 0d847f99efa3efcbd19bd75087774004693ac771 Mon Sep 17 00:00:00 2001 From: Josh Klar Date: Mon, 8 Oct 2018 05:04:06 -0700 Subject: [PATCH] Make some events (and especially macros) faster by caching BareEvents and many key events in RAM --- kmk/common/event_defs.py | 42 +++++++++---------- kmk/common/keycodes.py | 23 +++++++---- kmk/common/macros/simple.py | 21 ++++++++-- kmk/common/macros/unicode.py | 80 ++++++++++++++++++++++++------------ 4 files changed, 106 insertions(+), 60 deletions(-) diff --git a/kmk/common/event_defs.py b/kmk/common/event_defs.py index 96e94bf..a7b025a 100644 --- a/kmk/common/event_defs.py +++ b/kmk/common/event_defs.py @@ -32,6 +32,20 @@ KeycodeUpDown = namedtuple('KeycodeUpDown', ('type', 'keycode')) NewMatrix = namedtuple('NewMatrix', ('type', 'matrix')) BareEvent = namedtuple('BareEvent', ('type',)) +hid_report_event = BareEvent( + type=HID_REPORT_EVENT, +) + + +macro_complete_event = BareEvent( + type=MACRO_COMPLETE_EVENT, +) + + +pending_keycode_pop_event = BareEvent( + type=PENDING_KEYCODE_POP_EVENT, +) + def init_firmware(keymap, row_pins, col_pins, diode_orientation): return InitFirmware( @@ -88,24 +102,6 @@ def new_matrix_event(matrix): ) -def hid_report_event(): - return BareEvent( - type=HID_REPORT_EVENT, - ) - - -def macro_complete_event(): - return BareEvent( - type=MACRO_COMPLETE_EVENT, - ) - - -def pending_keycode_pop_event(): - return BareEvent( - type=PENDING_KEYCODE_POP_EVENT, - ) - - def matrix_changed(new_pressed): def _key_pressed(dispatch, get_state): dispatch(new_matrix_event(new_pressed)) @@ -113,7 +109,7 @@ def matrix_changed(new_pressed): state = get_state() if state.hid_pending: - dispatch(hid_report_event()) + dispatch(hid_report_event) if Keycodes.KMK.KC_RESET in state.keys_pressed: reset_bootloader() @@ -122,13 +118,13 @@ def matrix_changed(new_pressed): for key in state.pending_keys: if not key.no_press: dispatch(keycode_down_event(key)) - dispatch(hid_report_event()) + dispatch(hid_report_event) if not key.no_release: dispatch(keycode_up_event(key)) - dispatch(hid_report_event()) + dispatch(hid_report_event) - dispatch(pending_keycode_pop_event()) + dispatch(pending_keycode_pop_event) if state.macro_pending: macro = state.macro_pending @@ -136,6 +132,6 @@ def matrix_changed(new_pressed): for event in macro(state): dispatch(event) - dispatch(macro_complete_event()) + dispatch(macro_complete_event) return _key_pressed diff --git a/kmk/common/keycodes.py b/kmk/common/keycodes.py index 56b0e90..99571c3 100644 --- a/kmk/common/keycodes.py +++ b/kmk/common/keycodes.py @@ -85,15 +85,22 @@ class ModifierKeycode(Keycode): if modified_code is None and no_press is None and no_release is None: return self - new_keycode = Keycode( - modified_code.code, - {self.code}, - no_press=no_press, - no_release=no_release, - ) + if modified_code is not None: + new_keycode = Keycode( + modified_code.code, + {self.code}, + no_press=no_press, + no_release=no_release, + ) - if modified_code.has_modifiers: - new_keycode.has_modifiers |= modified_code.has_modifiers + if modified_code.has_modifiers: + new_keycode.has_modifiers |= modified_code.has_modifiers + else: + new_keycode = Keycode( + self.code, + no_press=no_press, + no_release=no_release, + ) return new_keycode diff --git a/kmk/common/macros/simple.py b/kmk/common/macros/simple.py index 0bb77ba..a0f6a35 100644 --- a/kmk/common/macros/simple.py +++ b/kmk/common/macros/simple.py @@ -5,6 +5,21 @@ from kmk.common.event_defs import (hid_report_event, keycode_down_event, from kmk.common.keycodes import Keycodes, Macro, RawKeycodes, char_lookup from kmk.common.kmktime import sleep_ms +kc_lookup_cache = {} + + +def lookup_kc_with_cache(char): + found_code = kc_lookup_cache.get( + char, + getattr(Keycodes.Common, 'KC_{}'.format(char.upper())), + ) + + kc_lookup_cache[char] = found_code + kc_lookup_cache[char.upper()] = found_code + kc_lookup_cache[char.lower()] = found_code + + return found_code + def simple_key_sequence(seq): def _simple_key_sequence(state): @@ -15,11 +30,11 @@ def simple_key_sequence(seq): if not getattr(key, 'no_press', None): yield keycode_down_event(key) - yield hid_report_event() + yield hid_report_event if not getattr(key, 'no_release', None): yield keycode_up_event(key) - yield hid_report_event() + yield hid_report_event return Macro(keydown=_simple_key_sequence) @@ -33,7 +48,7 @@ def send_string(message): if char in char_lookup: kc = char_lookup[char] elif char in string.ascii_letters + string.digits: - kc = getattr(Keycodes.Common, 'KC_{}'.format(char.upper())) + kc = lookup_kc_with_cache(char) if char.isupper(): kc = Keycodes.Modifiers.KC_LSHIFT(kc) diff --git a/kmk/common/macros/unicode.py b/kmk/common/macros/unicode.py index 4416459..bbe7b99 100644 --- a/kmk/common/macros/unicode.py +++ b/kmk/common/macros/unicode.py @@ -2,10 +2,20 @@ from kmk.common.consts import UnicodeModes from kmk.common.event_defs import (hid_report_event, keycode_down_event, keycode_up_event) from kmk.common.keycodes import Common, Macro, Modifiers -from kmk.common.macros.simple import simple_key_sequence +from kmk.common.macros.simple import lookup_kc_with_cache, simple_key_sequence from kmk.common.util import get_wide_ordinal IBUS_KEY_COMBO = Modifiers.KC_LCTRL(Modifiers.KC_LSHIFT(Common.KC_U)) +IBUS_KEY_DOWN = keycode_down_event(IBUS_KEY_COMBO) +IBUS_KEY_UP = keycode_up_event(IBUS_KEY_COMBO) +RALT_DOWN = keycode_down_event(Modifiers.KC_RALT) +RALT_UP = keycode_up_event(Modifiers.KC_RALT) +U_DOWN = keycode_down_event(Common.KC_U) +U_UP = keycode_up_event(Common.KC_U) +ENTER_DOWN = keycode_down_event(Common.KC_ENTER) +ENTER_UP = keycode_up_event(Common.KC_ENTER) +RALT_DOWN_NO_RELEASE = keycode_down_event(Modifiers.KC_RALT(no_release=True)) +RALT_UP_NO_PRESS = keycode_up_event(Modifiers.KC_RALT(no_press=True)) def generate_codepoint_keysym_seq(codepoint): @@ -20,7 +30,7 @@ def generate_codepoint_keysym_seq(codepoint): seq = [Common.KC_0 for _ in range(max(len(codepoint), 4))] for idx, codepoint_fragment in enumerate(reversed(codepoint)): - seq[-(idx + 1)] = getattr(Common, 'KC_{}'.format(codepoint_fragment.upper())) + seq[-(idx + 1)] = lookup_kc_with_cache(codepoint_fragment) return seq @@ -37,45 +47,63 @@ def unicode_string_sequence(unistring): def unicode_codepoint_sequence(codepoints): + kc_seqs = ( + generate_codepoint_keysym_seq(codepoint) + for codepoint in codepoints + ) + + kc_macros = [ + simple_key_sequence(kc_seq) + for kc_seq in kc_seqs + ] + def _unicode_sequence(state): if state.unicode_mode == UnicodeModes.IBUS: - yield from _ibus_unicode_sequence(codepoints, state) + yield from _ibus_unicode_sequence(kc_macros, state) elif state.unicode_mode == UnicodeModes.RALT: - yield from _ralt_unicode_sequence(codepoints, state) + yield from _ralt_unicode_sequence(kc_macros, state) elif state.unicode_mode == UnicodeModes.WINC: - yield from _winc_unicode_sequence(codepoints, state) + yield from _winc_unicode_sequence(kc_macros, state) return Macro(keydown=_unicode_sequence) -def _ralt_unicode_sequence(codepoints, state): - for codepoint in codepoints: - yield keycode_down_event(Modifiers.RALT(no_release=True)) - yield from simple_key_sequence(generate_codepoint_keysym_seq(codepoint)).keydown(state) - yield keycode_up_event(Modifiers.RALT(no_press=True)) +def _ralt_unicode_sequence(kc_macros, state): + for kc_macro in kc_macros: + yield RALT_DOWN_NO_RELEASE + yield hid_report_event + yield from kc_macro.keydown(state) + yield RALT_UP_NO_PRESS + yield hid_report_event -def _ibus_unicode_sequence(codepoints, state): - for codepoint in codepoints: - yield keycode_down_event(IBUS_KEY_COMBO) - yield hid_report_event() - yield keycode_up_event(IBUS_KEY_COMBO) - yield hid_report_event() - - seq = generate_codepoint_keysym_seq(codepoint) - seq.append(Common.KC_ENTER) - - yield from simple_key_sequence(seq).keydown(state) +def _ibus_unicode_sequence(kc_macros, state): + for kc_macro in kc_macros: + yield IBUS_KEY_DOWN + yield hid_report_event + yield IBUS_KEY_UP + yield hid_report_event + yield from kc_macro.keydown(state) + yield ENTER_DOWN + yield hid_report_event + yield ENTER_UP + yield hid_report_event -def _winc_unicode_sequence(codepoints, state): +def _winc_unicode_sequence(kc_macros, state): ''' Send unicode sequence using WinCompose: http://wincompose.info/ https://github.com/SamHocevar/wincompose ''' - for codepoint in codepoints: - yield keycode_down_event(Modifiers.RALT()) - yield keycode_down_event(Common.KC_U()) - yield from simple_key_sequence(generate_codepoint_keysym_seq(codepoint)).keydown(state) + for kc_macro in kc_macros: + yield RALT_DOWN + yield hid_report_event + yield RALT_UP + yield hid_report_event + yield U_DOWN + yield hid_report_event + yield U_UP + yield hid_report_event + yield from kc_macro.keydown(state)