Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor key meta #995

Merged
merged 15 commits into from
Jul 1, 2024
2 changes: 1 addition & 1 deletion docs/en/sticky_mod.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ sticky_mod = StickyMod()
keyboard.modules.append(sticky_mod)
keyboard.keymap = [
[
KC.SM(kc=KC.TAB, mod=KC.LALT),
KC.SM(key=KC.TAB, mod=KC.LALT),
KC.SM(KC.TAB, KC.LSFT(KC.LALT)),
],
]
Expand Down
36 changes: 15 additions & 21 deletions kmk/extensions/led.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,21 @@
from math import e, exp, pi, sin

from kmk.extensions import Extension, InvalidExtensionEnvironment
from kmk.keys import make_argumented_key, make_key
from kmk.keys import Key, make_argumented_key, make_key
from kmk.utils import clamp


class LEDKeyMeta:
def __init__(self, *leds):
class LEDKey(Key):
def __init__(self, *leds, brightness=None, **kwargs):
super().__init__(**kwargs)
self.leds = leds
self.brightness = None


def led_set_key(brightness, *leds):
return LEDKey(*leds, brightness=brightness)


class AnimationModes:
OFF = 0
STATIC = 1
Expand Down Expand Up @@ -63,22 +68,22 @@ def __init__(

make_argumented_key(
names=('LED_TOG',),
validator=self._led_key_validator,
constructor=LEDKey,
on_press=self._key_led_tog,
)
make_argumented_key(
names=('LED_INC',),
validator=self._led_key_validator,
constructor=LEDKey,
on_press=self._key_led_inc,
)
make_argumented_key(
names=('LED_DEC',),
validator=self._led_key_validator,
constructor=LEDKey,
on_press=self._key_led_dec,
)
make_argumented_key(
names=('LED_SET',),
validator=self._led_set_key_validator,
constructor=led_set_key,
on_press=self._key_led_set,
)
make_key(names=('LED_ANI',), on_press=self._key_led_ani)
Expand Down Expand Up @@ -216,17 +221,6 @@ def animate(self):
else:
self.off()

def _led_key_validator(self, *leds):
if leds:
for led in leds:
assert self._leds[led]
return LEDKeyMeta(*leds)

def _led_set_key_validator(self, brightness, *leds):
meta = self._led_key_validator(*leds)
meta.brightness = brightness
return meta

def _key_led_tog(self, *args, **kwargs):
if self.animation_mode == AnimationModes.STATIC_STANDBY:
self.animation_mode = AnimationModes.STATIC
Expand All @@ -236,13 +230,13 @@ def _key_led_tog(self, *args, **kwargs):
self._enabled = not self._enabled

def _key_led_inc(self, key, *args, **kwargs):
self.increase_brightness(leds=key.meta.leds)
self.increase_brightness(leds=key.leds)

def _key_led_dec(self, key, *args, **kwargs):
self.decrease_brightness(leds=key.meta.leds)
self.decrease_brightness(leds=key.leds)

def _key_led_set(self, key, *args, **kwargs):
self.set_brightness(percent=key.meta.brightness, leds=key.meta.leds)
self.set_brightness(percent=key.brightness, leds=key.leds)

def _key_led_ani(self, *args, **kwargs):
self.increase_ani()
Expand Down
29 changes: 17 additions & 12 deletions kmk/extensions/media_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,23 @@ def __init__(self):
# adding the old Apple-specific consumer codes, but again, PRs welcome if the
# lack of them impacts you.

make_key(code=0xE2, names=('AUDIO_MUTE', 'MUTE'), key_type=ConsumerKey)
make_key(code=0xE9, names=('AUDIO_VOL_UP', 'VOLU'), key_type=ConsumerKey)
make_key(code=0xEA, names=('AUDIO_VOL_DOWN', 'VOLD'), key_type=ConsumerKey)
make_key(code=0x6F, names=('BRIGHTNESS_UP', 'BRIU'), key_type=ConsumerKey)
make_key(code=0x70, names=('BRIGHTNESS_DOWN', 'BRID'), key_type=ConsumerKey)
make_key(code=0xB5, names=('MEDIA_NEXT_TRACK', 'MNXT'), key_type=ConsumerKey)
make_key(code=0xB6, names=('MEDIA_PREV_TRACK', 'MPRV'), key_type=ConsumerKey)
make_key(code=0xB7, names=('MEDIA_STOP', 'MSTP'), key_type=ConsumerKey)
make_key(code=0xCD, names=('MEDIA_PLAY_PAUSE', 'MPLY'), key_type=ConsumerKey)
make_key(code=0xB8, names=('MEDIA_EJECT', 'EJCT'), key_type=ConsumerKey)
make_key(code=0xB3, names=('MEDIA_FAST_FORWARD', 'MFFD'), key_type=ConsumerKey)
make_key(code=0xB4, names=('MEDIA_REWIND', 'MRWD'), key_type=ConsumerKey)
codes = (
(0xE2, ('AUDIO_MUTE', 'MUTE')),
(0xE9, ('AUDIO_VOL_UP', 'VOLU')),
(0xEA, ('AUDIO_VOL_DOWN', 'VOLD')),
(0x6F, ('BRIGHTNESS_UP', 'BRIU')),
(0x70, ('BRIGHTNESS_DOWN', 'BRID')),
(0xB5, ('MEDIA_NEXT_TRACK', 'MNXT')),
(0xB6, ('MEDIA_PREV_TRACK', 'MPRV')),
(0xB7, ('MEDIA_STOP', 'MSTP')),
(0xCD, ('MEDIA_PLAY_PAUSE', 'MPLY')),
(0xB8, ('MEDIA_EJECT', 'EJCT')),
(0xB3, ('MEDIA_FAST_FORWARD', 'MFFD')),
(0xB4, ('MEDIA_REWIND', 'MRWD')),
)

for code, names in codes:
make_key(names=names, constructor=ConsumerKey, code=code)

def on_runtime_enable(self, sandbox):
return
Expand Down
79 changes: 28 additions & 51 deletions kmk/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,31 +44,28 @@ class AX:


def maybe_make_key(
code: Optional[int],
names: Tuple[str, ...],
*args,
**kwargs,
) -> Callable[[str], Key]:
def closure(candidate):
if candidate in names:
return make_key(code=code, names=names, *args, **kwargs)
return make_key(names=names, *args, **kwargs)

return closure


def maybe_make_argumented_key(
validator=lambda *validator_args, **validator_kwargs: object(),
names: Tuple[str, ...] = tuple(), # NOQA
*constructor_args,
**constructor_kwargs,
names: Tuple[str, ...],
constructor: [Key, Callable[[...], Key]],
**kwargs,
) -> Callable[[str], Key]:
def closure(candidate):
if candidate in names:
return make_argumented_key(
validator,
names,
*constructor_args,
**constructor_kwargs,
names=names,
constructor=constructor,
**kwargs,
)

return closure
Expand Down Expand Up @@ -99,9 +96,9 @@ def maybe_make_alpha_key(candidate: str) -> Optional[Key]:
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()),
key_type=KeyboardKey,
constructor=KeyboardKey,
code=4 + ALL_ALPHAS.index(candidate_upper),
)


Expand All @@ -113,9 +110,9 @@ def maybe_make_numeric_key(candidate: str) -> Optional[Key]:
offset = ALL_NUMBER_ALIASES.index(candidate)

return make_key(
code=30 + offset,
names=(ALL_NUMBERS[offset], ALL_NUMBER_ALIASES[offset]),
key_type=KeyboardKey,
constructor=KeyboardKey,
code=30 + offset,
)


Expand All @@ -137,7 +134,7 @@ def maybe_make_mod_key(candidate: str) -> Optional[Key]:

for code, names in mods:
if candidate in names:
return make_key(code=code, names=names, key_type=ModifierKey)
return make_key(names=names, constructor=ModifierKey, code=code)


def maybe_make_more_ascii(candidate: str) -> Optional[Key]:
Expand All @@ -162,7 +159,7 @@ def maybe_make_more_ascii(candidate: str) -> Optional[Key]:

for code, names in codes:
if candidate in names:
return make_key(code=code, names=names, key_type=KeyboardKey)
return make_key(names=names, constructor=KeyboardKey, code=code)


def maybe_make_fn_key(candidate: str) -> Optional[Key]:
Expand Down Expand Up @@ -195,7 +192,7 @@ def maybe_make_fn_key(candidate: str) -> Optional[Key]:

for code, names in codes:
if candidate in names:
return make_key(code=code, names=names, key_type=KeyboardKey)
return make_key(names=names, constructor=KeyboardKey, code=code)


def maybe_make_navlock_key(candidate: str) -> Optional[Key]:
Expand Down Expand Up @@ -224,7 +221,7 @@ def maybe_make_navlock_key(candidate: str) -> Optional[Key]:

for code, names in codes:
if candidate in names:
return make_key(code=code, names=names, key_type=KeyboardKey)
return make_key(names=names, constructor=KeyboardKey, code=code)


def maybe_make_numpad_key(candidate: str) -> Optional[Key]:
Expand Down Expand Up @@ -253,7 +250,7 @@ def maybe_make_numpad_key(candidate: str) -> Optional[Key]:

for code, names in codes:
if candidate in names:
return make_key(code=code, names=names, key_type=KeyboardKey)
return make_key(names=names, constructor=KeyboardKey, code=code)


def maybe_make_shifted_key(candidate: str) -> Optional[Key]:
Expand Down Expand Up @@ -284,7 +281,7 @@ def maybe_make_shifted_key(candidate: str) -> Optional[Key]:
for code, names in codes:
if candidate in names:
return make_key(
code=code, names=names, key_type=ModifiedKey, modifier=KC.LSFT
names=names, constructor=ModifiedKey, code=code, modifier=KC.LSFT
)


Expand Down Expand Up @@ -315,7 +312,7 @@ def maybe_make_international_key(candidate: str) -> Optional[Key]:

for code, names in codes:
if candidate in names:
return make_key(code=code, names=names, key_type=KeyboardKey)
return make_key(names=names, constructor=KeyboardKey, code=code)


def maybe_make_firmware_key(candidate: str) -> Optional[Key]:
Expand All @@ -341,13 +338,11 @@ def maybe_make_firmware_key(candidate: str) -> Optional[Key]:
maybe_make_numeric_key,
maybe_make_firmware_key,
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,
Expand Down Expand Up @@ -444,9 +439,7 @@ def __init__(
self,
on_press: Callable[[object, Key, Keyboard, ...], None] = handlers.passthrough,
on_release: Callable[[object, Key, Keyboard, ...], None] = handlers.passthrough,
meta: object = object(),
):
self.meta = meta
self._on_press = on_press
self._on_release = on_release

Expand All @@ -463,8 +456,6 @@ def on_release(self, keyboard: Keyboard, coord_int: Optional[int] = None) -> Non
class _DefaultKey(Key):
'''Meta class implementing handlers for Keys with HID codes.'''

meta = None

def __init__(self, code: Optional[int] = None):
self.code = code

Expand Down Expand Up @@ -499,7 +490,6 @@ def __call__(self, key: Key) -> Key:


class ModifiedKey(Key):
meta = None
code = -1

def __init__(self, code: [Key, int], modifier: [ModifierKey]):
Expand Down Expand Up @@ -545,18 +535,13 @@ class MouseKey(_DefaultKey):


def make_key(
code: Optional[int] = None,
names: Tuple[str, ...] = tuple(), # NOQA
key_type: Key = Key,
names: Tuple[str, ...],
constructor: Key = Key,
**kwargs,
) -> Key:
'''
Create a new key, aliased by `names` in the KC lookup table.

If a code is not specified, the key is assumed to be a custom
internal key to be handled in a state callback rather than
sent directly to the OS.

Names are globally unique. If a later key is created with
the same name as an existing entry in `KC`, it will overwrite
the existing entry.
Expand All @@ -566,10 +551,7 @@ def make_key(
All **kwargs are passed to the Key constructor
'''

if code is None:
key = key_type(**kwargs)
else:
key = key_type(code, **kwargs)
key = constructor(**kwargs)

for name in names:
KC[name] = key
Expand All @@ -580,20 +562,15 @@ def make_key(
# Argumented keys are implicitly internal, so auto-gen of code
# is almost certainly the best plan here
def make_argumented_key(
validator: object = lambda *validator_args, **validator_kwargs: object(),
names: Tuple[str, ...] = tuple(), # NOQA
*constructor_args,
**constructor_kwargs,
names: Tuple[str, ...],
constructor: [Key, Callable[[...], Key]],
**_kwargs,
) -> Key:

def _argumented_key(*user_args, **user_kwargs) -> Key:
return Key(
*constructor_args,
meta=validator(*user_args, **user_kwargs),
**constructor_kwargs,
)
def argumented_key(*args, **kwargs) -> Key:
return constructor(*args, **kwargs, **_kwargs)

for name in names:
KC[name] = _argumented_key
KC[name] = argumented_key

return _argumented_key
return argumented_key
Loading