kmk_firmware/kmk/leader_mode.py

87 lines
2.5 KiB
Python

import logging
from kmk.keycodes import Keycodes
class LeaderHelper:
"""
Acts as a hid to absorb keypress, and perform macros when a timer
or enter key is pressed depending on the mode set.
"""
def __init__(self, store, log_level=logging.NOTSET):
self.logger = logging.getLogger(__name__)
self.logger.setLevel(log_level)
self.store = store
self.store.subscribe(
lambda state, action: self._subscription(state, action),
)
def _subscription(self, state, action):
"""
Subscribes to the state machine, and dispatches actions based
based on incoming keypresses, or when a timer runs out depending
on the mode.
:param state:
:param action:
:return state:
"""
if state.leader_mode % 2 == 1:
keys_pressed = state.keys_pressed
if state.leader_last_len and state.leader_mode_history:
history_set = set(state.leader_mode_history)
keys_pressed = keys_pressed - history_set
state.leader_last_len = len(state.keys_pressed)
for key in keys_pressed:
if key == Keycodes.Common.KC_ENT:
# Process the action and remove the extra KC.ENT that was added to get here
state = process(state)
return clean_exit(state)
elif key == Keycodes.Common.KC_ESC:
# Clean state and turn leader mode off.
return clean_exit(state)
elif key == Keycodes.KMK.KC_LEAD:
return state
else:
# Add key if not needing to escape
# This needs replaced later with a proper debounce
state.leader_mode_history.append(key)
return state
return state
def clean_exit(state):
"""
Cleans up the state and hands the HID control back.
:param state:
:return state:
"""
state.leader_mode_history = []
state.leader_mode -= 1
state.leader_last_len = 0
state.keys_pressed.clear()
return state
def process(state):
"""
Checks if there are iny matching sequences of keys, and
performs the macro specified by the user.
:param state:
:param leader_dictionary:
:return state:
"""
lmh = tuple(state.leader_mode_history)
if lmh in state.LEADER_DICTIONARY:
state.macro_pending = state.LEADER_DICTIONARY[lmh].keydown
state.keys_pressed.clear()
return state