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)
|
INIT_FIRMWARE_EVENT = const(3)
|
||||||
NEW_MATRIX_EVENT = const(4)
|
NEW_MATRIX_EVENT = const(4)
|
||||||
HID_REPORT_EVENT = const(5)
|
HID_REPORT_EVENT = const(5)
|
||||||
|
KEYCODE_UP_EVENT = const(6)
|
||||||
|
KEYCODE_DOWN_EVENT = const(7)
|
||||||
|
MACRO_COMPLETE_EVENT = const(8)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
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):
|
def new_matrix_event(matrix):
|
||||||
return {
|
return {
|
||||||
'type': NEW_MATRIX_EVENT,
|
'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 matrix_changed(new_matrix):
|
||||||
def _key_pressed(dispatch, get_state):
|
def _key_pressed(dispatch, get_state):
|
||||||
state = get_state()
|
state = get_state()
|
||||||
@ -94,4 +126,12 @@ def matrix_changed(new_matrix):
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
logger.warning('Tried to reset to bootloader, but not supported on this chip?')
|
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
|
return _key_pressed
|
||||||
|
@ -4,9 +4,11 @@ import sys
|
|||||||
from kmk.common.consts import DiodeOrientation
|
from kmk.common.consts import DiodeOrientation
|
||||||
from kmk.common.event_defs import (HID_REPORT_EVENT, INIT_FIRMWARE_EVENT,
|
from kmk.common.event_defs import (HID_REPORT_EVENT, INIT_FIRMWARE_EVENT,
|
||||||
KEY_DOWN_EVENT, KEY_UP_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.internal_keycodes import process_internal_key_event
|
||||||
from kmk.common.keycodes import FIRST_KMK_INTERNAL_KEYCODE, Keycodes
|
from kmk.common.keycodes import FIRST_KMK_INTERNAL_KEYCODE, Keycodes
|
||||||
|
from kmk.macros import KMKMacro
|
||||||
|
|
||||||
|
|
||||||
class ReduxStore:
|
class ReduxStore:
|
||||||
@ -52,6 +54,7 @@ class ReduxStore:
|
|||||||
class InternalState:
|
class InternalState:
|
||||||
modifiers_pressed = frozenset()
|
modifiers_pressed = frozenset()
|
||||||
keys_pressed = frozenset()
|
keys_pressed = frozenset()
|
||||||
|
macros_pending = []
|
||||||
keymap = []
|
keymap = []
|
||||||
row_pins = []
|
row_pins = []
|
||||||
col_pins = []
|
col_pins = []
|
||||||
@ -133,6 +136,20 @@ def kmk_reducer(state=None, action=None, logger=None):
|
|||||||
matrix=action['matrix'],
|
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:
|
if action['type'] == KEY_UP_EVENT:
|
||||||
row = action['row']
|
row = action['row']
|
||||||
col = action['col']
|
col = action['col']
|
||||||
@ -144,6 +161,14 @@ def kmk_reducer(state=None, action=None, logger=None):
|
|||||||
if not changed_key:
|
if not changed_key:
|
||||||
return state
|
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(
|
newstate = state.update(
|
||||||
keys_pressed=frozenset(
|
keys_pressed=frozenset(
|
||||||
key for key in state.keys_pressed if key != changed_key
|
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:
|
if not changed_key:
|
||||||
return state
|
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(
|
newstate = state.update(
|
||||||
keys_pressed=(
|
keys_pressed=(
|
||||||
state.keys_pressed | {changed_key}
|
state.keys_pressed | {changed_key}
|
||||||
@ -196,6 +229,14 @@ def kmk_reducer(state=None, action=None, logger=None):
|
|||||||
if action['type'] == HID_REPORT_EVENT:
|
if action['type'] == HID_REPORT_EVENT:
|
||||||
return state
|
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
|
# On unhandled events, log and do not mutate state
|
||||||
logger.warning('Unhandled event! Returning state unmodified.')
|
logger.warning('Unhandled event! Returning state unmodified.')
|
||||||
return state
|
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
|
# device, or keys will get stuck (mostly when releasing
|
||||||
# media/consumer keys)
|
# media/consumer keys)
|
||||||
self.send()
|
self.send()
|
||||||
delay(10)
|
|
||||||
|
|
||||||
self.report_device[0] = needed_reporting_device
|
self.report_device[0] = needed_reporting_device
|
||||||
|
|
||||||
@ -99,6 +98,17 @@ class HIDHelper:
|
|||||||
self.logger.debug('Sending HID report: {}'.format(self._evt))
|
self.logger.debug('Sending HID report: {}'.format(self._evt))
|
||||||
self._hid.send(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
|
return self
|
||||||
|
|
||||||
def send_string(self, message):
|
def send_string(self, message):
|
||||||
@ -128,13 +138,6 @@ class HIDHelper:
|
|||||||
self.add_key(kc)
|
self.add_key(kc)
|
||||||
self.send()
|
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
|
# Release all keys or we'll forever hold whatever the last keyadd was
|
||||||
self.clear_all()
|
self.clear_all()
|
||||||
self.send()
|
self.send()
|
||||||
|
@ -3,6 +3,7 @@ import machine
|
|||||||
from kmk.common.consts import DiodeOrientation
|
from kmk.common.consts import DiodeOrientation
|
||||||
from kmk.common.keycodes import KC
|
from kmk.common.keycodes import KC
|
||||||
from kmk.entrypoints.handwire.pyboard import main
|
from kmk.entrypoints.handwire.pyboard import main
|
||||||
|
from kmk.macros.simple import simple_key_sequence
|
||||||
|
|
||||||
p = machine.Pin.board
|
p = machine.Pin.board
|
||||||
cols = (p.X10, p.X11, p.X12)
|
cols = (p.X10, p.X11, p.X12)
|
||||||
@ -10,6 +11,21 @@ rows = (p.X1, p.X2, p.X3)
|
|||||||
|
|
||||||
diode_orientation = DiodeOrientation.COLUMNS
|
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 = [
|
keymap = [
|
||||||
[
|
[
|
||||||
[KC.MO(1), KC.GESC, KC.RESET],
|
[KC.MO(1), KC.GESC, KC.RESET],
|
||||||
@ -24,6 +40,6 @@ keymap = [
|
|||||||
[
|
[
|
||||||
[KC.VOLU, KC.MUTE, KC.Z],
|
[KC.VOLU, KC.MUTE, KC.Z],
|
||||||
[KC.TRNS, KC.PIPE, KC.MEDIA_PLAY_PAUSE],
|
[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