437
									
								
								kmk/keys.py
									
									
									
									
									
								
							
							
						
						
									
										437
									
								
								kmk/keys.py
									
									
									
									
									
								
							@@ -1,4 +1,3 @@
 | 
			
		||||
import gc
 | 
			
		||||
from micropython import const
 | 
			
		||||
 | 
			
		||||
import kmk.handlers.stock as handlers
 | 
			
		||||
@@ -20,189 +19,58 @@ ALL_NUMBERS = '1234567890'
 | 
			
		||||
# since KC.1 isn't valid Python, alias to KC.N1
 | 
			
		||||
ALL_NUMBER_ALIASES = tuple(f'N{x}' for x in ALL_NUMBERS)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# this is a bit of an FP style thing - combining a pipe operator a-la F# with
 | 
			
		||||
# a bootleg Maybe monad to clean up these make_key sequences
 | 
			
		||||
def left_pipe_until_some(candidate, functor, *args_iter):
 | 
			
		||||
    for args in args_iter:
 | 
			
		||||
        result = functor(candidate, *args)
 | 
			
		||||
        if result is not None:
 | 
			
		||||
            return result
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def first_truthy(candidate, *funcs):
 | 
			
		||||
    for func in funcs:
 | 
			
		||||
        result = func(candidate)
 | 
			
		||||
        if result is not None:
 | 
			
		||||
            return result
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def maybe_make_mod_key(candidate, code, names):
 | 
			
		||||
def maybe_make_key(code, names, *args, **kwargs):
 | 
			
		||||
    def closure(candidate):
 | 
			
		||||
        if candidate in names:
 | 
			
		||||
        return make_mod_key(code=code, names=names)
 | 
			
		||||
            return make_key(code=code, names=names, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    return closure
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def maybe_make_key(candidate, code, names):
 | 
			
		||||
def maybe_make_argumented_key(
 | 
			
		||||
    validator=lambda *validator_args, **validator_kwargs: object(),
 | 
			
		||||
    names=tuple(),  # NOQA
 | 
			
		||||
    *constructor_args,
 | 
			
		||||
    **constructor_kwargs,
 | 
			
		||||
):
 | 
			
		||||
    def closure(candidate):
 | 
			
		||||
        if candidate in names:
 | 
			
		||||
        return make_key(code=code, names=names)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def maybe_make_shifted_key(candidate, code, names):
 | 
			
		||||
    if candidate in names:
 | 
			
		||||
        return make_shifted_key(code=code, names=names)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def maybe_make_consumer_key(candidate, code, names):
 | 
			
		||||
    if candidate in names:
 | 
			
		||||
        return make_consumer_key(code=code, names=names)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class KeyAttrDict:
 | 
			
		||||
    __cache = {}
 | 
			
		||||
 | 
			
		||||
    def __iter__(self):
 | 
			
		||||
        return self.__cache.__iter__()
 | 
			
		||||
 | 
			
		||||
    def __setitem__(self, key, value):
 | 
			
		||||
        if DEBUG_OUTPUT:
 | 
			
		||||
            print(f'__setitem__ {key}, {value}')
 | 
			
		||||
        self.__cache.__setitem__(key, value)
 | 
			
		||||
 | 
			
		||||
    def __getattr__(self, key):
 | 
			
		||||
        if DEBUG_OUTPUT:
 | 
			
		||||
            print(f'__getattr__ {key}')
 | 
			
		||||
        return self.__getitem__(key)
 | 
			
		||||
 | 
			
		||||
    def get(self, key, default=None):
 | 
			
		||||
        try:
 | 
			
		||||
            return self.__getitem__(key)
 | 
			
		||||
        except Exception:
 | 
			
		||||
            return default
 | 
			
		||||
 | 
			
		||||
    def clear(self):
 | 
			
		||||
        self.__cache.clear()
 | 
			
		||||
 | 
			
		||||
    def __getitem__(self, key):
 | 
			
		||||
        if DEBUG_OUTPUT:
 | 
			
		||||
            print(f'__getitem__ {key}')
 | 
			
		||||
        try:
 | 
			
		||||
            return self.__cache[key]
 | 
			
		||||
        except Exception:
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
        key_upper = key.upper()
 | 
			
		||||
 | 
			
		||||
        # Try all the other weird special cases to get them out of our way:
 | 
			
		||||
        # This need to be done before or ALPHAS because NO will be parsed as alpha
 | 
			
		||||
        # Internal, diagnostic, or auxiliary/enhanced keys
 | 
			
		||||
 | 
			
		||||
        # NO and TRNS are functionally identical in how they (don't) mutate
 | 
			
		||||
        # the state, but are tracked semantically separately, so create
 | 
			
		||||
        # two keys with the exact same functionality
 | 
			
		||||
        if key in ('NO', 'XXXXXXX'):
 | 
			
		||||
            make_key(
 | 
			
		||||
                names=('NO', 'XXXXXXX'),
 | 
			
		||||
                on_press=handlers.passthrough,
 | 
			
		||||
                on_release=handlers.passthrough,
 | 
			
		||||
            return make_argumented_key(
 | 
			
		||||
                validator, names, *constructor_args, **constructor_kwargs
 | 
			
		||||
            )
 | 
			
		||||
        elif key in ('TRANSPARENT', 'TRNS'):
 | 
			
		||||
            make_key(
 | 
			
		||||
                names=('TRANSPARENT', 'TRNS'),
 | 
			
		||||
                on_press=handlers.passthrough,
 | 
			
		||||
                on_release=handlers.passthrough,
 | 
			
		||||
 | 
			
		||||
    return closure
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def maybe_make_alpha_key(candidate):
 | 
			
		||||
    if len(candidate) != 1:
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    candidate_upper = candidate.upper()
 | 
			
		||||
    if candidate_upper in ALL_ALPHAS:
 | 
			
		||||
        return make_key(
 | 
			
		||||
            code=4 + ALL_ALPHAS.index(candidate_upper),
 | 
			
		||||
            names=(candidate_upper, candidate.lower()),
 | 
			
		||||
        )
 | 
			
		||||
        # Basic ASCII letters/numbers don't need anything fancy, so check those
 | 
			
		||||
        # in the laziest way
 | 
			
		||||
        elif key_upper in ALL_ALPHAS:
 | 
			
		||||
            make_key(
 | 
			
		||||
                code=4 + ALL_ALPHAS.index(key_upper),
 | 
			
		||||
                names=(
 | 
			
		||||
                    key_upper,
 | 
			
		||||
                    key.lower(),
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
        elif key in ALL_NUMBERS or key in ALL_NUMBER_ALIASES:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def maybe_make_numeric_key(candidate):
 | 
			
		||||
    if candidate in ALL_NUMBERS or candidate in ALL_NUMBER_ALIASES:
 | 
			
		||||
        try:
 | 
			
		||||
                offset = ALL_NUMBERS.index(key)
 | 
			
		||||
            offset = ALL_NUMBERS.index(candidate)
 | 
			
		||||
        except ValueError:
 | 
			
		||||
                offset = ALL_NUMBER_ALIASES.index(key)
 | 
			
		||||
            offset = ALL_NUMBER_ALIASES.index(candidate)
 | 
			
		||||
 | 
			
		||||
            names = (ALL_NUMBERS[offset], ALL_NUMBER_ALIASES[offset])
 | 
			
		||||
            make_key(code=30 + offset, names=names)
 | 
			
		||||
        elif key in ('RESET',):
 | 
			
		||||
            make_key(names=('RESET',), on_press=handlers.reset)
 | 
			
		||||
        elif key in ('RELOAD', 'RLD'):
 | 
			
		||||
            make_key(names=('RELOAD', 'RLD'), on_press=handlers.reload)
 | 
			
		||||
        elif key in ('BOOTLOADER',):
 | 
			
		||||
            make_key(names=('BOOTLOADER',), on_press=handlers.bootloader)
 | 
			
		||||
        elif key in ('DEBUG', 'DBG'):
 | 
			
		||||
            make_key(
 | 
			
		||||
                names=('DEBUG', 'DBG'),
 | 
			
		||||
                on_press=handlers.debug_pressed,
 | 
			
		||||
                on_release=handlers.passthrough,
 | 
			
		||||
            )
 | 
			
		||||
        elif key in ('BKDL',):
 | 
			
		||||
            make_key(
 | 
			
		||||
                names=('BKDL',),
 | 
			
		||||
                on_press=handlers.bkdl_pressed,
 | 
			
		||||
                on_release=handlers.bkdl_released,
 | 
			
		||||
            )
 | 
			
		||||
        elif key in ('GESC', 'GRAVE_ESC'):
 | 
			
		||||
            make_key(
 | 
			
		||||
                names=('GESC', 'GRAVE_ESC'),
 | 
			
		||||
                on_press=handlers.gesc_pressed,
 | 
			
		||||
                on_release=handlers.gesc_released,
 | 
			
		||||
        return make_key(
 | 
			
		||||
            code=30 + offset,
 | 
			
		||||
            names=(ALL_NUMBERS[offset], ALL_NUMBER_ALIASES[offset]),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        # A dummy key to trigger a sleep_ms call in a sequence of other keys in a
 | 
			
		||||
        # simple sequence macro.
 | 
			
		||||
        elif key in ('MACRO_SLEEP_MS', 'SLEEP_IN_SEQ'):
 | 
			
		||||
            make_argumented_key(
 | 
			
		||||
                validator=key_seq_sleep_validator,
 | 
			
		||||
                names=('MACRO_SLEEP_MS', 'SLEEP_IN_SEQ'),
 | 
			
		||||
                on_press=handlers.sleep_pressed,
 | 
			
		||||
            )
 | 
			
		||||
        elif key in ('UC_MODE_NOOP', 'UC_DISABLE'):
 | 
			
		||||
            make_key(
 | 
			
		||||
                names=('UC_MODE_NOOP', 'UC_DISABLE'),
 | 
			
		||||
                meta=UnicodeModeKeyMeta(UnicodeMode.NOOP),
 | 
			
		||||
                on_press=handlers.uc_mode_pressed,
 | 
			
		||||
            )
 | 
			
		||||
        elif key in ('UC_MODE_LINUX', 'UC_MODE_IBUS'):
 | 
			
		||||
            make_key(
 | 
			
		||||
                names=('UC_MODE_LINUX', 'UC_MODE_IBUS'),
 | 
			
		||||
                meta=UnicodeModeKeyMeta(UnicodeMode.IBUS),
 | 
			
		||||
                on_press=handlers.uc_mode_pressed,
 | 
			
		||||
            )
 | 
			
		||||
        elif key in ('UC_MODE_MACOS', 'UC_MODE_OSX', 'US_MODE_RALT'):
 | 
			
		||||
            make_key(
 | 
			
		||||
                names=('UC_MODE_MACOS', 'UC_MODE_OSX', 'US_MODE_RALT'),
 | 
			
		||||
                meta=UnicodeModeKeyMeta(UnicodeMode.RALT),
 | 
			
		||||
                on_press=handlers.uc_mode_pressed,
 | 
			
		||||
            )
 | 
			
		||||
        elif key in ('UC_MODE_WINC',):
 | 
			
		||||
            make_key(
 | 
			
		||||
                names=('UC_MODE_WINC',),
 | 
			
		||||
                meta=UnicodeModeKeyMeta(UnicodeMode.WINC),
 | 
			
		||||
                on_press=handlers.uc_mode_pressed,
 | 
			
		||||
            )
 | 
			
		||||
        elif key in ('UC_MODE',):
 | 
			
		||||
            make_argumented_key(
 | 
			
		||||
                validator=unicode_mode_key_validator,
 | 
			
		||||
                names=('UC_MODE',),
 | 
			
		||||
                on_press=handlers.uc_mode_pressed,
 | 
			
		||||
            )
 | 
			
		||||
        elif key in ('HID_SWITCH', 'HID'):
 | 
			
		||||
            make_key(names=('HID_SWITCH', 'HID'), on_press=handlers.hid_switch)
 | 
			
		||||
        elif key in ('BLE_REFRESH',):
 | 
			
		||||
            make_key(names=('BLE_REFRESH',), on_press=handlers.ble_refresh)
 | 
			
		||||
        else:
 | 
			
		||||
            maybe_key = first_truthy(
 | 
			
		||||
                key,
 | 
			
		||||
                # Modifiers
 | 
			
		||||
                lambda key: left_pipe_until_some(
 | 
			
		||||
                    key,
 | 
			
		||||
                    maybe_make_mod_key,
 | 
			
		||||
 | 
			
		||||
def maybe_make_mod_key(candidate):
 | 
			
		||||
    # MEH = LCTL | LALT | LSFT
 | 
			
		||||
    # HYPR = LCTL | LALT | LSFT | LGUI
 | 
			
		||||
    mods = (
 | 
			
		||||
        (0x01, ('LEFT_CONTROL', 'LCTRL', 'LCTL')),
 | 
			
		||||
        (0x02, ('LEFT_SHIFT', 'LSHIFT', 'LSFT')),
 | 
			
		||||
        (0x04, ('LEFT_ALT', 'LALT', 'LOPT')),
 | 
			
		||||
@@ -211,15 +79,17 @@ class KeyAttrDict:
 | 
			
		||||
        (0x20, ('RIGHT_SHIFT', 'RSHIFT', 'RSFT')),
 | 
			
		||||
        (0x40, ('RIGHT_ALT', 'RALT', 'ROPT')),
 | 
			
		||||
        (0x80, ('RIGHT_SUPER', 'RGUI', 'RCMD', 'RWIN')),
 | 
			
		||||
                    # MEH = LCTL | LALT | LSFT# MEH = LCTL |
 | 
			
		||||
        (0x07, ('MEH',)),
 | 
			
		||||
                    # HYPR = LCTL | LALT | LSFT | LGUI
 | 
			
		||||
        (0x0F, ('HYPER', 'HYPR')),
 | 
			
		||||
                ),
 | 
			
		||||
                lambda key: left_pipe_until_some(
 | 
			
		||||
                    key,
 | 
			
		||||
                    maybe_make_key,
 | 
			
		||||
                    # More ASCII standard keys
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    for code, names in mods:
 | 
			
		||||
        if candidate in names:
 | 
			
		||||
            return make_mod_key(code=code, names=names)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def maybe_make_more_ascii(candidate):
 | 
			
		||||
    codes = (
 | 
			
		||||
        (40, ('ENTER', 'ENT', '\n')),
 | 
			
		||||
        (41, ('ESCAPE', 'ESC')),
 | 
			
		||||
        (42, ('BACKSPACE', 'BSPACE', 'BSPC', 'BKSP')),
 | 
			
		||||
@@ -236,7 +106,15 @@ class KeyAttrDict:
 | 
			
		||||
        (54, ('COMMA', 'COMM', ',')),
 | 
			
		||||
        (55, ('DOT', '.')),
 | 
			
		||||
        (56, ('SLASH', 'SLSH', '/')),
 | 
			
		||||
                    # Function Keys
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    for code, names in codes:
 | 
			
		||||
        if candidate in names:
 | 
			
		||||
            return make_key(code=code, names=names)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def maybe_make_fn_key(candidate):
 | 
			
		||||
    codes = (
 | 
			
		||||
        (58, ('F1',)),
 | 
			
		||||
        (59, ('F2',)),
 | 
			
		||||
        (60, ('F3',)),
 | 
			
		||||
@@ -261,7 +139,15 @@ class KeyAttrDict:
 | 
			
		||||
        (113, ('F22',)),
 | 
			
		||||
        (114, ('F23',)),
 | 
			
		||||
        (115, ('F24',)),
 | 
			
		||||
                    # Lock Keys, Navigation, etc.
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    for code, names in codes:
 | 
			
		||||
        if candidate in names:
 | 
			
		||||
            return make_key(code=code, names=names)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def maybe_make_navlock_key(candidate):
 | 
			
		||||
    codes = (
 | 
			
		||||
        (57, ('CAPS_LOCK', 'CAPSLOCK', 'CLCK', 'CAPS')),
 | 
			
		||||
        # FIXME: Investigate whether this key actually works, and
 | 
			
		||||
        #        uncomment when/if it does.
 | 
			
		||||
@@ -282,11 +168,16 @@ class KeyAttrDict:
 | 
			
		||||
        (80, ('LEFT',)),
 | 
			
		||||
        (81, ('DOWN',)),
 | 
			
		||||
        (82, ('UP',)),
 | 
			
		||||
                    # Numpad
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    for code, names in codes:
 | 
			
		||||
        if candidate in names:
 | 
			
		||||
            return make_key(code=code, names=names)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def maybe_make_numpad_key(candidate):
 | 
			
		||||
    codes = (
 | 
			
		||||
        (83, ('NUM_LOCK', 'NUMLOCK', 'NLCK')),
 | 
			
		||||
                    # FIXME: Investigate whether this key actually works, and
 | 
			
		||||
                    #        uncomment when/if it does.
 | 
			
		||||
                    # (131, names=('LOCKING_NUM', 'LNUM')),
 | 
			
		||||
        (84, ('KP_SLASH', 'NUMPAD_SLASH', 'PSLS')),
 | 
			
		||||
        (85, ('KP_ASTERISK', 'NUMPAD_ASTERISK', 'PAST')),
 | 
			
		||||
        (86, ('KP_MINUS', 'NUMPAD_MINUS', 'PMNS')),
 | 
			
		||||
@@ -306,14 +197,15 @@ class KeyAttrDict:
 | 
			
		||||
        (103, ('KP_EQUAL', 'PEQL', 'NUMPAD_EQUAL')),
 | 
			
		||||
        (133, ('KP_COMMA', 'PCMM', 'NUMPAD_COMMA')),
 | 
			
		||||
        (134, ('KP_EQUAL_AS400', 'NUMPAD_EQUAL_AS400')),
 | 
			
		||||
                ),
 | 
			
		||||
                # Making life better for folks on tiny keyboards especially: exposes
 | 
			
		||||
                # the 'shifted' keys as raw keys. Under the hood we're still
 | 
			
		||||
                # sending Shift+(whatever key is normally pressed) to get these, so
 | 
			
		||||
                # for example `KC_AT` will hold shift and press 2.
 | 
			
		||||
                lambda key: left_pipe_until_some(
 | 
			
		||||
                    key,
 | 
			
		||||
                    maybe_make_shifted_key,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    for code, names in codes:
 | 
			
		||||
        if candidate in names:
 | 
			
		||||
            return make_key(code=code, names=names)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def maybe_make_shifted_key(candidate, *args, **kwargs):
 | 
			
		||||
    codes = (
 | 
			
		||||
        (30, ('EXCLAIM', 'EXLM', '!')),
 | 
			
		||||
        (31, ('AT', '@')),
 | 
			
		||||
        (32, ('HASH', 'POUND', '#')),
 | 
			
		||||
@@ -335,11 +227,15 @@ class KeyAttrDict:
 | 
			
		||||
        (54, ('LEFT_ANGLE_BRACKET', 'LABK', '<')),
 | 
			
		||||
        (55, ('RIGHT_ANGLE_BRACKET', 'RABK', '>')),
 | 
			
		||||
        (56, ('QUESTION', 'QUES', '?')),
 | 
			
		||||
                ),
 | 
			
		||||
                # International
 | 
			
		||||
                lambda key: left_pipe_until_some(
 | 
			
		||||
                    key,
 | 
			
		||||
                    maybe_make_key,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    for code, names in codes:
 | 
			
		||||
        if candidate in names:
 | 
			
		||||
            return make_shifted_key(code=code, names=names, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def maybe_make_international_key(candidate, *args, **kwargs):
 | 
			
		||||
    codes = (
 | 
			
		||||
        (50, ('NONUS_HASH', 'NUHS')),
 | 
			
		||||
        (100, ('NONUS_BSLASH', 'NUBS')),
 | 
			
		||||
        (101, ('APP', 'APPLICATION', 'SEL', 'WINMENU')),
 | 
			
		||||
@@ -361,15 +257,148 @@ class KeyAttrDict:
 | 
			
		||||
        (150, ('LANG7',)),
 | 
			
		||||
        (151, ('LANG8',)),
 | 
			
		||||
        (152, ('LANG9',)),
 | 
			
		||||
                ),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    for code, names in codes:
 | 
			
		||||
        if candidate in names:
 | 
			
		||||
            return make_key(code=code, names=names, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
KEY_GENERATORS = (
 | 
			
		||||
    # NO and TRNS are functionally identical in how they (don't) mutate
 | 
			
		||||
    # the state, but are tracked semantically separately, so create
 | 
			
		||||
    # two keys with the exact same functionality
 | 
			
		||||
    maybe_make_key(
 | 
			
		||||
        None,
 | 
			
		||||
        ('NO', 'XXXXXXX'),
 | 
			
		||||
        on_press=handlers.passthrough,
 | 
			
		||||
        on_release=handlers.passthrough,
 | 
			
		||||
    ),
 | 
			
		||||
    maybe_make_key(
 | 
			
		||||
        None,
 | 
			
		||||
        ('TRANSPARENT', 'TRNS'),
 | 
			
		||||
        on_press=handlers.passthrough,
 | 
			
		||||
        on_release=handlers.passthrough,
 | 
			
		||||
    ),
 | 
			
		||||
    maybe_make_alpha_key,
 | 
			
		||||
    maybe_make_numeric_key,
 | 
			
		||||
    maybe_make_key(None, ('RESET',), on_press=handlers.reset),
 | 
			
		||||
    maybe_make_key(None, ('RELOAD', 'RLD'), on_press=handlers.reload),
 | 
			
		||||
    maybe_make_key(None, ('BOOTLOADER',), on_press=handlers.bootloader),
 | 
			
		||||
    maybe_make_key(
 | 
			
		||||
        None,
 | 
			
		||||
        ('DEBUG', 'DBG'),
 | 
			
		||||
        on_press=handlers.debug_pressed,
 | 
			
		||||
        on_release=handlers.passthrough,
 | 
			
		||||
    ),
 | 
			
		||||
    maybe_make_key(
 | 
			
		||||
        None,
 | 
			
		||||
        ('BKDL',),
 | 
			
		||||
        on_press=handlers.bkdl_pressed,
 | 
			
		||||
        on_release=handlers.bkdl_released,
 | 
			
		||||
    ),
 | 
			
		||||
    maybe_make_key(
 | 
			
		||||
        None,
 | 
			
		||||
        ('GESC', 'GRAVE_ESC'),
 | 
			
		||||
        on_press=handlers.gesc_pressed,
 | 
			
		||||
        on_release=handlers.gesc_released,
 | 
			
		||||
    ),
 | 
			
		||||
    # A dummy key to trigger a sleep_ms call in a sequence of other keys in a
 | 
			
		||||
    # simple sequence macro.
 | 
			
		||||
    maybe_make_argumented_key(
 | 
			
		||||
        key_seq_sleep_validator,
 | 
			
		||||
        ('MACRO_SLEEP_MS', 'SLEEP_IN_SEQ'),
 | 
			
		||||
        on_press=handlers.sleep_pressed,
 | 
			
		||||
    ),
 | 
			
		||||
    maybe_make_key(
 | 
			
		||||
        None,
 | 
			
		||||
        ('UC_MODE_NOOP', 'UC_DISABLE'),
 | 
			
		||||
        on_press=handlers.uc_mode_pressed,
 | 
			
		||||
        meta=UnicodeModeKeyMeta(UnicodeMode.NOOP),
 | 
			
		||||
    ),
 | 
			
		||||
    maybe_make_key(
 | 
			
		||||
        None,
 | 
			
		||||
        ('UC_MODE_LINUX', 'UC_MODE_IBUS'),
 | 
			
		||||
        on_press=handlers.uc_mode_pressed,
 | 
			
		||||
        meta=UnicodeModeKeyMeta(UnicodeMode.IBUS),
 | 
			
		||||
    ),
 | 
			
		||||
    maybe_make_key(
 | 
			
		||||
        None,
 | 
			
		||||
        ('UC_MODE_MACOS', 'UC_MODE_OSX', 'US_MODE_RALT'),
 | 
			
		||||
        on_press=handlers.uc_mode_pressed,
 | 
			
		||||
        meta=UnicodeModeKeyMeta(UnicodeMode.RALT),
 | 
			
		||||
    ),
 | 
			
		||||
    maybe_make_key(
 | 
			
		||||
        None,
 | 
			
		||||
        ('UC_MODE_WINC',),
 | 
			
		||||
        on_press=handlers.uc_mode_pressed,
 | 
			
		||||
        meta=UnicodeModeKeyMeta(UnicodeMode.WINC),
 | 
			
		||||
    ),
 | 
			
		||||
    maybe_make_argumented_key(
 | 
			
		||||
        unicode_mode_key_validator, ('UC_MODE',), on_press=handlers.uc_mode_pressed
 | 
			
		||||
    ),
 | 
			
		||||
    maybe_make_key(None, ('HID_SWITCH', 'HID'), on_press=handlers.hid_switch),
 | 
			
		||||
    maybe_make_key(None, ('BLE_REFRESH',), on_press=handlers.ble_refresh),
 | 
			
		||||
    maybe_make_mod_key,
 | 
			
		||||
    # More ASCII standard keys
 | 
			
		||||
    maybe_make_more_ascii,
 | 
			
		||||
    # Function Keys
 | 
			
		||||
    maybe_make_fn_key,
 | 
			
		||||
    # Lock Keys, Navigation, etc.
 | 
			
		||||
    maybe_make_navlock_key,
 | 
			
		||||
    # Numpad
 | 
			
		||||
    # FIXME: Investigate whether this key actually works, and
 | 
			
		||||
    #        uncomment when/if it does.
 | 
			
		||||
    # maybe_make_key(131, ('LOCKING_NUM', 'LNUM')),
 | 
			
		||||
    maybe_make_numpad_key,
 | 
			
		||||
    # Making life better for folks on tiny keyboards especially: exposes
 | 
			
		||||
    # the 'shifted' keys as raw keys. Under the hood we're still
 | 
			
		||||
    # sending Shift+(whatever key is normally pressed) to get these, so
 | 
			
		||||
    # for example `KC_AT` will hold shift and press 2.
 | 
			
		||||
    maybe_make_shifted_key,
 | 
			
		||||
    # International
 | 
			
		||||
    maybe_make_international_key,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class KeyAttrDict:
 | 
			
		||||
    __cache = {}
 | 
			
		||||
 | 
			
		||||
    def __iter__(self):
 | 
			
		||||
        return self.__cache.__iter__()
 | 
			
		||||
 | 
			
		||||
    def __setitem__(self, key, value):
 | 
			
		||||
        self.__cache.__setitem__(key, value)
 | 
			
		||||
 | 
			
		||||
    def __getattr__(self, key):
 | 
			
		||||
        return self.__getitem__(key)
 | 
			
		||||
 | 
			
		||||
    def get(self, key, default=None):
 | 
			
		||||
        try:
 | 
			
		||||
            return self.__getitem__(key)
 | 
			
		||||
        except Exception:
 | 
			
		||||
            return default
 | 
			
		||||
 | 
			
		||||
    def clear(self):
 | 
			
		||||
        self.__cache.clear()
 | 
			
		||||
 | 
			
		||||
    def __getitem__(self, key):
 | 
			
		||||
        try:
 | 
			
		||||
            return self.__cache[key]
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
        for func in KEY_GENERATORS:
 | 
			
		||||
            maybe_key = func(key)
 | 
			
		||||
            if maybe_key:
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
        else:
 | 
			
		||||
            raise ValueError(f'Invalid key: {key}')
 | 
			
		||||
 | 
			
		||||
        if DEBUG_OUTPUT:
 | 
			
		||||
            print(f'{key}: {maybe_key}')
 | 
			
		||||
 | 
			
		||||
            if not maybe_key:
 | 
			
		||||
                raise ValueError(f'Invalid key: {key}')
 | 
			
		||||
 | 
			
		||||
        return self.__cache[key]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -646,8 +675,6 @@ def make_key(code=None, names=tuple(), type=KEY_SIMPLE, **kwargs):  # NOQA
 | 
			
		||||
    for name in names:
 | 
			
		||||
        KC[name] = key
 | 
			
		||||
 | 
			
		||||
    gc.collect()
 | 
			
		||||
 | 
			
		||||
    return key
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user