Support a simple macro of a sequence of keycodes (basis for SEND_STRING)
This commit is contained in:
parent
99573de217
commit
bdd4f86472
@ -9,6 +9,9 @@ KEY_DOWN_EVENT = const(2)
|
||||
INIT_FIRMWARE_EVENT = const(3)
|
||||
NEW_MATRIX_EVENT = const(4)
|
||||
HID_REPORT_EVENT = const(5)
|
||||
KEYCODE_UP_EVENT = const(6)
|
||||
KEYCODE_DOWN_EVENT = const(7)
|
||||
MACRO_COMPLETE_EVENT = const(8)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -39,6 +42,28 @@ def key_down_event(row, col):
|
||||
}
|
||||
|
||||
|
||||
def keycode_up_event(keycode):
|
||||
'''
|
||||
Press a key by Keycode object, bypassing the keymap. Used mostly for
|
||||
macros.
|
||||
'''
|
||||
return {
|
||||
'type': KEYCODE_UP_EVENT,
|
||||
'keycode': keycode,
|
||||
}
|
||||
|
||||
|
||||
def keycode_down_event(keycode):
|
||||
'''
|
||||
Release a key by Keycode object, bypassing the keymap. Used mostly for
|
||||
macros.
|
||||
'''
|
||||
return {
|
||||
'type': KEYCODE_DOWN_EVENT,
|
||||
'keycode': keycode,
|
||||
}
|
||||
|
||||
|
||||
def new_matrix_event(matrix):
|
||||
return {
|
||||
'type': NEW_MATRIX_EVENT,
|
||||
@ -52,6 +77,13 @@ def hid_report_event():
|
||||
}
|
||||
|
||||
|
||||
def macro_complete_event(macro):
|
||||
return {
|
||||
'type': MACRO_COMPLETE_EVENT,
|
||||
'macro': macro,
|
||||
}
|
||||
|
||||
|
||||
def matrix_changed(new_matrix):
|
||||
def _key_pressed(dispatch, get_state):
|
||||
state = get_state()
|
||||
@ -94,4 +126,12 @@ def matrix_changed(new_matrix):
|
||||
except ImportError:
|
||||
logger.warning('Tried to reset to bootloader, but not supported on this chip?')
|
||||
|
||||
while get_state().macros_pending:
|
||||
macro = get_state().macros_pending[0]
|
||||
|
||||
for event in macro():
|
||||
dispatch(event)
|
||||
|
||||
dispatch(macro_complete_event(macro))
|
||||
|
||||
return _key_pressed
|
||||
|
@ -4,9 +4,11 @@ import sys
|
||||
from kmk.common.consts import DiodeOrientation
|
||||
from kmk.common.event_defs import (HID_REPORT_EVENT, INIT_FIRMWARE_EVENT,
|
||||
KEY_DOWN_EVENT, KEY_UP_EVENT,
|
||||
NEW_MATRIX_EVENT)
|
||||
KEYCODE_DOWN_EVENT, KEYCODE_UP_EVENT,
|
||||
MACRO_COMPLETE_EVENT, NEW_MATRIX_EVENT)
|
||||
from kmk.common.internal_keycodes import process_internal_key_event
|
||||
from kmk.common.keycodes import FIRST_KMK_INTERNAL_KEYCODE, Keycodes
|
||||
from kmk.macros import KMKMacro
|
||||
|
||||
|
||||
class ReduxStore:
|
||||
@ -52,6 +54,7 @@ class ReduxStore:
|
||||
class InternalState:
|
||||
modifiers_pressed = frozenset()
|
||||
keys_pressed = frozenset()
|
||||
macros_pending = []
|
||||
keymap = []
|
||||
row_pins = []
|
||||
col_pins = []
|
||||
@ -133,6 +136,20 @@ def kmk_reducer(state=None, action=None, logger=None):
|
||||
matrix=action['matrix'],
|
||||
)
|
||||
|
||||
if action['type'] == KEYCODE_UP_EVENT:
|
||||
return state.update(
|
||||
keys_pressed=frozenset(
|
||||
key for key in state.keys_pressed if key != action['keycode']
|
||||
),
|
||||
)
|
||||
|
||||
if action['type'] == KEYCODE_DOWN_EVENT:
|
||||
return state.update(
|
||||
keys_pressed=(
|
||||
state.keys_pressed | {action['keycode']}
|
||||
),
|
||||
)
|
||||
|
||||
if action['type'] == KEY_UP_EVENT:
|
||||
row = action['row']
|
||||
col = action['col']
|
||||
@ -144,6 +161,14 @@ def kmk_reducer(state=None, action=None, logger=None):
|
||||
if not changed_key:
|
||||
return state
|
||||
|
||||
if isinstance(changed_key, KMKMacro):
|
||||
if changed_key.keyup:
|
||||
return state.update(
|
||||
macros_pending=state.macros_pending + [changed_key.keyup],
|
||||
)
|
||||
|
||||
return state
|
||||
|
||||
newstate = state.update(
|
||||
keys_pressed=frozenset(
|
||||
key for key in state.keys_pressed if key != changed_key
|
||||
@ -166,6 +191,14 @@ def kmk_reducer(state=None, action=None, logger=None):
|
||||
if not changed_key:
|
||||
return state
|
||||
|
||||
if isinstance(changed_key, KMKMacro):
|
||||
if changed_key.keydown:
|
||||
return state.update(
|
||||
macros_pending=state.macros_pending + [changed_key.keydown],
|
||||
)
|
||||
|
||||
return state
|
||||
|
||||
newstate = state.update(
|
||||
keys_pressed=(
|
||||
state.keys_pressed | {changed_key}
|
||||
@ -196,6 +229,14 @@ def kmk_reducer(state=None, action=None, logger=None):
|
||||
if action['type'] == HID_REPORT_EVENT:
|
||||
return state
|
||||
|
||||
if action['type'] == MACRO_COMPLETE_EVENT:
|
||||
return state.update(
|
||||
macros_pending=[
|
||||
m for m in state.macros_pending
|
||||
if m != action['macro']
|
||||
],
|
||||
)
|
||||
|
||||
# On unhandled events, log and do not mutate state
|
||||
logger.warning('Unhandled event! Returning state unmodified.')
|
||||
return state
|
||||
|
10
kmk/macros/__init__.py
Normal file
10
kmk/macros/__init__.py
Normal file
@ -0,0 +1,10 @@
|
||||
class KMKMacro:
|
||||
def __init__(self, keydown=None, keyup=None):
|
||||
self.keydown = keydown
|
||||
self.keyup = keyup
|
||||
|
||||
def on_keydown(self):
|
||||
return self.keydown() if self.keydown else None
|
||||
|
||||
def on_keyup(self):
|
||||
return self.keyup() if self.keyup else None
|
14
kmk/macros/simple.py
Normal file
14
kmk/macros/simple.py
Normal file
@ -0,0 +1,14 @@
|
||||
from kmk.common.event_defs import (hid_report_event, keycode_down_event,
|
||||
keycode_up_event)
|
||||
from kmk.macros import KMKMacro
|
||||
|
||||
|
||||
def simple_key_sequence(seq):
|
||||
def _simple_key_sequence():
|
||||
for key in seq:
|
||||
yield keycode_down_event(key)
|
||||
yield hid_report_event()
|
||||
yield keycode_up_event(key)
|
||||
yield hid_report_event()
|
||||
|
||||
return KMKMacro(keydown=_simple_key_sequence)
|
@ -73,7 +73,6 @@ class HIDHelper:
|
||||
# device, or keys will get stuck (mostly when releasing
|
||||
# media/consumer keys)
|
||||
self.send()
|
||||
delay(10)
|
||||
|
||||
self.report_device[0] = needed_reporting_device
|
||||
|
||||
@ -99,6 +98,17 @@ class HIDHelper:
|
||||
self.logger.debug('Sending HID report: {}'.format(self._evt))
|
||||
self._hid.send(self._evt)
|
||||
|
||||
# Without this delay, events get clobbered and you'll likely end up with
|
||||
# a string like `heloooooooooooooooo` rather than `hello`. This number
|
||||
# may be able to be shrunken down. It may also make sense to use
|
||||
# time.sleep_us or time.sleep_ms or time.sleep (platform dependent)
|
||||
# on non-Pyboards.
|
||||
#
|
||||
# It'd be real awesome if pyb.USB_HID.send/recv would support
|
||||
# uselect.poll or uselect.select to more safely determine when
|
||||
# it is safe to write to the host again...
|
||||
delay(10)
|
||||
|
||||
return self
|
||||
|
||||
def send_string(self, message):
|
||||
@ -128,13 +138,6 @@ class HIDHelper:
|
||||
self.add_key(kc)
|
||||
self.send()
|
||||
|
||||
# Without this delay, events get clobbered and you'll likely end up with
|
||||
# a string like `heloooooooooooooooo` rather than `hello`. This number
|
||||
# may be able to be shrunken down. It may also make sense to use
|
||||
# time.sleep_us or time.sleep_ms or time.sleep (platform dependent)
|
||||
# on non-Pyboards.
|
||||
delay(10)
|
||||
|
||||
# Release all keys or we'll forever hold whatever the last keyadd was
|
||||
self.clear_all()
|
||||
self.send()
|
||||
|
@ -3,6 +3,7 @@ import machine
|
||||
from kmk.common.consts import DiodeOrientation
|
||||
from kmk.common.keycodes import KC
|
||||
from kmk.entrypoints.handwire.pyboard import main
|
||||
from kmk.macros.simple import simple_key_sequence
|
||||
|
||||
p = machine.Pin.board
|
||||
cols = (p.X10, p.X11, p.X12)
|
||||
@ -10,6 +11,21 @@ rows = (p.X1, p.X2, p.X3)
|
||||
|
||||
diode_orientation = DiodeOrientation.COLUMNS
|
||||
|
||||
MACRO_TEST_STRING = simple_key_sequence([
|
||||
KC.LSHIFT(KC.H),
|
||||
KC.E,
|
||||
KC.L,
|
||||
KC.L,
|
||||
KC.O,
|
||||
|
||||
KC.SPACE,
|
||||
|
||||
KC.LSHIFT(KC.K),
|
||||
KC.LSHIFT(KC.M),
|
||||
KC.LSHIFT(KC.K),
|
||||
KC.EXCLAIM,
|
||||
])
|
||||
|
||||
keymap = [
|
||||
[
|
||||
[KC.MO(1), KC.GESC, KC.RESET],
|
||||
@ -24,6 +40,6 @@ keymap = [
|
||||
[
|
||||
[KC.VOLU, KC.MUTE, KC.Z],
|
||||
[KC.TRNS, KC.PIPE, KC.MEDIA_PLAY_PAUSE],
|
||||
[KC.VOLD, KC.P, KC.Q],
|
||||
[KC.VOLD, KC.P, MACRO_TEST_STRING],
|
||||
],
|
||||
]
|
||||
|
Loading…
x
Reference in New Issue
Block a user