Add LeaderMode.TIMEOUT (QMK default Leader mode)
This allows leader sequences to "time out" rather than requiring an Enter keypress to end. This also rolls back some unnecessary changes from #72 to the matrix scanner for performance reasons. In theory we can use this in the future for Tap Dance support (#40) Resolves #1 Resolves #37
This commit is contained in:
parent
aa4b164067
commit
2d1290a12c
@ -150,7 +150,7 @@ class UnicodeModes:
|
||||
|
||||
|
||||
class LeaderMode:
|
||||
DEFAULT = 0
|
||||
DEFAULT_ACTIVE = 1
|
||||
TIMEOUT = 0
|
||||
TIMEOUT_ACTIVE = 1
|
||||
ENTER = 2
|
||||
ENTER_ACTIVE = 3
|
||||
|
@ -55,6 +55,7 @@ class Firmware:
|
||||
tap_time = 300
|
||||
leader_mode = LeaderMode.ENTER
|
||||
leader_dictionary = {}
|
||||
leader_timeout = 1000
|
||||
|
||||
hid_helper = USB_HID
|
||||
|
||||
@ -94,7 +95,7 @@ class Firmware:
|
||||
print("Firin' lazers. Keyboard is booted.")
|
||||
|
||||
while True:
|
||||
for update in self.matrix.scan_for_changes():
|
||||
update = self.matrix.scan_for_changes()
|
||||
if update is not None:
|
||||
self._state.matrix_changed(
|
||||
update[0],
|
||||
@ -105,6 +106,11 @@ class Firmware:
|
||||
if self._state.hid_pending:
|
||||
self._send_hid()
|
||||
|
||||
if self.debug_enabled:
|
||||
print('New State: {}'.format(self._state._to_dict()))
|
||||
|
||||
self._state.process_timeouts()
|
||||
|
||||
for key in self._state.pending_keys:
|
||||
self._send_key(key)
|
||||
self._state.pending_key_handled()
|
||||
@ -115,7 +121,4 @@ class Firmware:
|
||||
|
||||
self._state.resolve_macro()
|
||||
|
||||
if self.debug_enabled:
|
||||
print('New State: {}'.format(self._state._to_dict()))
|
||||
|
||||
gc.collect()
|
||||
|
@ -1,3 +1,4 @@
|
||||
from kmk.consts import LeaderMode
|
||||
from kmk.keycodes import FIRST_KMK_INTERNAL_KEYCODE, Keycodes, RawKeycodes
|
||||
from kmk.kmktime import sleep_ms, ticks_diff, ticks_ms
|
||||
from kmk.util import intify_coordinate
|
||||
@ -26,12 +27,10 @@ class InternalState:
|
||||
'lm': None,
|
||||
'leader': None,
|
||||
}
|
||||
timeouts = {}
|
||||
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
|
||||
self.leader_mode = config.leader_mode
|
||||
|
||||
self.internal_key_handlers = {
|
||||
RawKeycodes.KC_DF: self._layer_df,
|
||||
RawKeycodes.KC_MO: self._layer_mo,
|
||||
@ -56,6 +55,7 @@ class InternalState:
|
||||
'keys_pressed': self.keys_pressed,
|
||||
'active_layers': self.active_layers,
|
||||
'leader_mode_history': self.leader_mode_history,
|
||||
'leader_mode': self.config.leader_mode,
|
||||
'start_time': self.start_time,
|
||||
}
|
||||
|
||||
@ -75,6 +75,21 @@ class InternalState:
|
||||
|
||||
return layer_key
|
||||
|
||||
def set_timeout(self, after_ticks, callback):
|
||||
timeout_key = ticks_ms() + after_ticks
|
||||
self.timeouts[timeout_key] = callback
|
||||
return self
|
||||
|
||||
def process_timeouts(self):
|
||||
current_time = ticks_ms()
|
||||
|
||||
for k, v in self.timeouts.items():
|
||||
if k <= current_time:
|
||||
v()
|
||||
del self.timeouts[k]
|
||||
|
||||
return self
|
||||
|
||||
def matrix_changed(self, row, col, is_pressed):
|
||||
if self.config.debug_enabled:
|
||||
print('Matrix changed (col, row, pressed?): {}, {}, {}'.format(
|
||||
@ -88,12 +103,6 @@ class InternalState:
|
||||
print('No key accessible for col, row: {}, {}'.format(row, col))
|
||||
return self
|
||||
|
||||
if kc_changed.code >= FIRST_KMK_INTERNAL_KEYCODE:
|
||||
self._process_internal_key_event(
|
||||
kc_changed,
|
||||
is_pressed,
|
||||
)
|
||||
else:
|
||||
if is_pressed:
|
||||
self.keys_pressed.add(kc_changed)
|
||||
self.coord_keys_pressed[int_coord] = kc_changed
|
||||
@ -102,9 +111,15 @@ class InternalState:
|
||||
self.keys_pressed.discard(self.coord_keys_pressed[int_coord])
|
||||
self.coord_keys_pressed[int_coord] = None
|
||||
|
||||
if kc_changed.code >= FIRST_KMK_INTERNAL_KEYCODE:
|
||||
self._process_internal_key_event(
|
||||
kc_changed,
|
||||
is_pressed,
|
||||
)
|
||||
else:
|
||||
self.hid_pending = True
|
||||
|
||||
if self.leader_mode % 2 == 1:
|
||||
if self.config.leader_mode % 2 == 1:
|
||||
self._process_leader_mode()
|
||||
|
||||
return self
|
||||
@ -304,13 +319,24 @@ class InternalState:
|
||||
return self
|
||||
|
||||
def _begin_leader_mode(self):
|
||||
if self.leader_mode % 2 == 0:
|
||||
if self.config.leader_mode % 2 == 0:
|
||||
self.keys_pressed.discard(Keycodes.KMK.KC_LEAD)
|
||||
# All leader modes are one number higher when activating
|
||||
self.leader_mode += 1
|
||||
self.config.leader_mode += 1
|
||||
|
||||
if self.config.leader_mode == LeaderMode.TIMEOUT_ACTIVE:
|
||||
self.set_timeout(self.config.leader_timeout, self._handle_leader_sequence)
|
||||
|
||||
return self
|
||||
|
||||
def _handle_leader_sequence(self):
|
||||
lmh = tuple(self.leader_mode_history)
|
||||
|
||||
if lmh in self.config.leader_dictionary:
|
||||
self.macro_pending = self.config.leader_dictionary[lmh].keydown
|
||||
|
||||
return self._exit_leader_mode()
|
||||
|
||||
def _process_leader_mode(self):
|
||||
keys_pressed = self.keys_pressed
|
||||
|
||||
@ -322,15 +348,11 @@ class InternalState:
|
||||
self.leader_last_len = len(self.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
|
||||
|
||||
lmh = tuple(self.leader_mode_history)
|
||||
|
||||
if lmh in self.config.leader_dictionary:
|
||||
self.macro_pending = self.config.leader_dictionary[lmh].keydown
|
||||
|
||||
self._exit_leader_mode()
|
||||
if (
|
||||
self.config.leader_mode == LeaderMode.ENTER_ACTIVE and
|
||||
key == Keycodes.Common.KC_ENT
|
||||
):
|
||||
self._handle_leader_sequence()
|
||||
break
|
||||
elif key == Keycodes.Common.KC_ESC or key == Keycodes.KMK.KC_GESC:
|
||||
# Clean self and turn leader mode off.
|
||||
@ -348,7 +370,7 @@ class InternalState:
|
||||
|
||||
def _exit_leader_mode(self):
|
||||
self.leader_mode_history.clear()
|
||||
self.leader_mode -= 1
|
||||
self.config.leader_mode -= 1
|
||||
self.leader_last_len = 0
|
||||
self.keys_pressed.clear()
|
||||
return self
|
||||
|
@ -98,12 +98,13 @@ class MatrixScanner:
|
||||
self.report[2] = new_val
|
||||
self.state[ba_idx] = new_val
|
||||
any_changed = True
|
||||
|
||||
yield self.report
|
||||
break
|
||||
|
||||
ba_idx += 1
|
||||
|
||||
opin.value(False)
|
||||
if any_changed:
|
||||
break
|
||||
|
||||
if not any_changed:
|
||||
yield None
|
||||
if any_changed:
|
||||
return self.report
|
||||
|
@ -1,5 +1,5 @@
|
||||
from kmk.boards.klarank import Firmware
|
||||
from kmk.consts import UnicodeModes
|
||||
from kmk.consts import LeaderMode, UnicodeModes
|
||||
from kmk.keycodes import KC
|
||||
from kmk.keycodes import generate_leader_dictionary_seq as glds
|
||||
from kmk.macros.simple import send_string
|
||||
@ -45,6 +45,7 @@ emoticons = cuss({
|
||||
|
||||
WPM = send_string("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Bibendum arcu vitae elementum curabitur vitae nunc sed. Facilisis sed odio morbi quis.")
|
||||
|
||||
keyboard.leader_mode = LeaderMode.TIMEOUT
|
||||
keyboard.leader_dictionary = {
|
||||
glds('hello'): send_string('hello world from kmk macros'),
|
||||
glds('wpm'): WPM,
|
||||
|
Loading…
x
Reference in New Issue
Block a user