Allow pre/post on_press/on_release handlers to be attached to all keys (example provided)

This commit is contained in:
Josh Klar 2019-02-18 15:08:07 -08:00
parent 4ab673ba80
commit 848afb7801
No known key found for this signature in database
GPG Key ID: 220F99BD7DB7A99E
3 changed files with 146 additions and 9 deletions

View File

@ -107,9 +107,9 @@ class InternalState:
self._process_tap_dance(key, is_pressed) self._process_tap_dance(key, is_pressed)
else: else:
if is_pressed: if is_pressed:
key.on_press(self, coord_int, coord_raw) key._on_press(self, coord_int, coord_raw)
else: else:
key.on_release(self, coord_int, coord_raw) key._on_release(self, coord_int, coord_raw)
if self.config.leader_mode % 2 == 1: if self.config.leader_mode % 2 == 1:
self._process_leader_mode() self._process_leader_mode()

View File

@ -35,8 +35,12 @@ class Key:
self.no_press = bool(no_press) self.no_press = bool(no_press)
self.no_release = bool(no_press) self.no_release = bool(no_press)
self._on_press = on_press self._pre_press_handlers = []
self._on_release = on_release self._post_press_handlers = []
self._pre_release_handlers = []
self._post_release_handlers = []
self._handle_press = on_press
self._handle_release = on_release
self.meta = meta self.meta = meta
def __call__(self, no_press=None, no_release=None): def __call__(self, no_press=None, no_release=None):
@ -53,11 +57,136 @@ class Key:
def __repr__(self): def __repr__(self):
return 'Key(code={}, has_modifiers={})'.format(self.code, self.has_modifiers) return 'Key(code={}, has_modifiers={})'.format(self.code, self.has_modifiers)
def on_press(self, state, coord_int, coord_raw): def _on_press(self, state, coord_int, coord_raw):
return self._on_press(self, state, KC, coord_int, coord_raw) for fn in self._pre_press_handlers:
fn(self, state, KC, coord_int, coord_raw)
def on_release(self, state, coord_int, coord_raw): ret = self._handle_press(self, state, KC, coord_int, coord_raw)
return self._on_release(self, state, KC, coord_int, coord_raw)
for fn in self._post_press_handlers:
fn(self, state, KC, coord_int, coord_raw)
return ret
def _on_release(self, state, coord_int, coord_raw):
for fn in self._pre_release_handlers:
fn(self, state, KC, coord_int, coord_raw)
ret = self._handle_release(self, state, KC, coord_int, coord_raw)
for fn in self._post_release_handlers:
fn(self, state, KC, coord_int, coord_raw)
return ret
def clone(self):
'''
Return a shallow clone of the current key without any pre/post press/release
handlers attached. Almost exclusively useful for creating non-colliding keys
to use such handlers.
'''
return type(self)(
code=self.code,
has_modifiers=self.has_modifiers,
no_press=self.no_press,
no_release=self.no_release,
on_press=self._handle_press,
on_release=self._handle_release,
meta=self.meta,
)
def before_press_handler(self, fn):
'''
Attach a callback to be run prior to the on_press handler for this key.
Receives the following:
- self (this Key instance)
- state (the current InternalState)
- KC (the global KC lookup table, for convenience)
- coord_int (an internal integer representation of the matrix coordinate
for the pressed key - this is likely not useful to end users, but is
provided for consistency with the internal handlers)
- coord_raw (an X,Y tuple of the matrix coordinate - also likely not useful)
The return value of the provided callback is discarded. Exceptions are _not_
caught, and will likely crash KMK if not handled within your function.
These handlers are run in attachment order: handlers provided by earlier
calls of this method will be executed before those provided by later calls.
'''
self._pre_press_handlers.append(fn)
return self
def after_press_handler(self, fn):
'''
Attach a callback to be run after the on_release handler for this key.
Receives the following:
- self (this Key instance)
- state (the current InternalState)
- KC (the global KC lookup table, for convenience)
- coord_int (an internal integer representation of the matrix coordinate
for the pressed key - this is likely not useful to end users, but is
provided for consistency with the internal handlers)
- coord_raw (an X,Y tuple of the matrix coordinate - also likely not useful)
The return value of the provided callback is discarded. Exceptions are _not_
caught, and will likely crash KMK if not handled within your function.
These handlers are run in attachment order: handlers provided by earlier
calls of this method will be executed before those provided by later calls.
'''
self._post_press_handlers.append(fn)
return self
def before_release_handler(self, fn):
'''
Attach a callback to be run prior to the on_release handler for this
key. Receives the following:
- self (this Key instance)
- state (the current InternalState)
- KC (the global KC lookup table, for convenience)
- coord_int (an internal integer representation of the matrix coordinate
for the pressed key - this is likely not useful to end users, but is
provided for consistency with the internal handlers)
- coord_raw (an X,Y tuple of the matrix coordinate - also likely not useful)
The return value of the provided callback is discarded. Exceptions are _not_
caught, and will likely crash KMK if not handled within your function.
These handlers are run in attachment order: handlers provided by earlier
calls of this method will be executed before those provided by later calls.
'''
self._pre_release_handlers.append(fn)
return self
def after_release_handler(self, fn):
'''
Attach a callback to be run after the on_release handler for this key.
Receives the following:
- self (this Key instance)
- state (the current InternalState)
- KC (the global KC lookup table, for convenience)
- coord_int (an internal integer representation of the matrix coordinate
for the pressed key - this is likely not useful to end users, but is
provided for consistency with the internal handlers)
- coord_raw (an X,Y tuple of the matrix coordinate - also likely not useful)
The return value of the provided callback is discarded. Exceptions are _not_
caught, and will likely crash KMK if not handled within your function.
These handlers are run in attachment order: handlers provided by earlier
calls of this method will be executed before those provided by later calls.
'''
self._post_release_handlers.append(fn)
return self
class ModifierKey(Key): class ModifierKey(Key):

View File

@ -89,8 +89,16 @@ def shrek_is_life(*args, **kwargs):
print('⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⠿⠿⠿⠿⠛⠉') print('⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⠿⠿⠿⠿⠛⠉')
# Spew shrek when hitting a fully custom key
# This won't modify internal state at all
SHREK_IS_LOVE = make_key(on_press=shrek_is_life) SHREK_IS_LOVE = make_key(on_press=shrek_is_life)
# Also spew shrek every time I try to use Alt. It's a dev board, after all.
KC.LALT.before_press_handler(shrek_is_life)
# But also give me a normal alt if I want it. Shrek isn't ALWAYS life.
BORING_ALT = KC.LALT.clone()
keyboard.keymap = [ keyboard.keymap = [
[ [
@ -117,7 +125,7 @@ keyboard.keymap = [
[ [
[KC.GRV, KC.EXLM, KC.AT, KC.HASH, KC.DLR, KC.PERC, KC.CIRC, KC.AMPR, KC.ASTR, KC.LPRN, KC.RPRN, KC.SLSH], [KC.GRV, KC.EXLM, KC.AT, KC.HASH, KC.DLR, KC.PERC, KC.CIRC, KC.AMPR, KC.ASTR, KC.LPRN, KC.RPRN, KC.SLSH],
[KC.TAB, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, KC.MINS], [KC.TAB, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, KC.MINS],
[KC.LGUI, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx], [KC.LGUI, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, BORING_ALT],
[KC.LCTL, KC.DBG, HELLA_TD, xxxxxxx, _______, _______, xxxxxxx, xxxxxxx, KC.MUTE, KC.VOLD, KC.VOLU, xxxxxxx], [KC.LCTL, KC.DBG, HELLA_TD, xxxxxxx, _______, _______, xxxxxxx, xxxxxxx, KC.MUTE, KC.VOLD, KC.VOLU, xxxxxxx],
], ],
] ]