Merge pull request #74 from KMKfw/topic-leader-timer

Add LeaderMode.TIMEOUT (QMK default Leader mode)
This commit is contained in:
Josh Klar 2018-10-19 01:55:26 -07:00 committed by GitHub
commit 3cb9b762e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 77 additions and 50 deletions

View File

@ -150,7 +150,7 @@ class UnicodeModes:
class LeaderMode: class LeaderMode:
DEFAULT = 0 TIMEOUT = 0
DEFAULT_ACTIVE = 1 TIMEOUT_ACTIVE = 1
ENTER = 2 ENTER = 2
ENTER_ACTIVE = 3 ENTER_ACTIVE = 3

View File

@ -55,6 +55,7 @@ class Firmware:
tap_time = 300 tap_time = 300
leader_mode = LeaderMode.ENTER leader_mode = LeaderMode.ENTER
leader_dictionary = {} leader_dictionary = {}
leader_timeout = 1000
hid_helper = USB_HID hid_helper = USB_HID
@ -94,28 +95,30 @@ class Firmware:
print("Firin' lazers. Keyboard is booted.") print("Firin' lazers. Keyboard is booted.")
while True: while True:
for update in self.matrix.scan_for_changes(): update = self.matrix.scan_for_changes()
if update is not None: if update is not None:
self._state.matrix_changed( self._state.matrix_changed(
update[0], update[0],
update[1], update[1],
update[2], update[2],
) )
if self._state.hid_pending: if self._state.hid_pending:
self._send_hid() self._send_hid()
for key in self._state.pending_keys: if self.debug_enabled:
self._send_key(key) print('New State: {}'.format(self._state._to_dict()))
self._state.pending_key_handled()
if self._state.macro_pending: self._state.process_timeouts()
for key in self._state.macro_pending(self):
self._send_key(key)
self._state.resolve_macro() for key in self._state.pending_keys:
self._send_key(key)
self._state.pending_key_handled()
if self.debug_enabled: if self._state.macro_pending:
print('New State: {}'.format(self._state._to_dict())) for key in self._state.macro_pending(self):
self._send_key(key)
self._state.resolve_macro()
gc.collect() gc.collect()

View File

@ -1,3 +1,4 @@
from kmk.consts import LeaderMode
from kmk.keycodes import FIRST_KMK_INTERNAL_KEYCODE, Keycodes, RawKeycodes from kmk.keycodes import FIRST_KMK_INTERNAL_KEYCODE, Keycodes, RawKeycodes
from kmk.kmktime import sleep_ms, ticks_diff, ticks_ms from kmk.kmktime import sleep_ms, ticks_diff, ticks_ms
from kmk.util import intify_coordinate from kmk.util import intify_coordinate
@ -26,12 +27,10 @@ class InternalState:
'lm': None, 'lm': None,
'leader': None, 'leader': None,
} }
timeouts = {}
def __init__(self, config): def __init__(self, config):
self.config = config self.config = config
self.leader_mode = config.leader_mode
self.internal_key_handlers = { self.internal_key_handlers = {
RawKeycodes.KC_DF: self._layer_df, RawKeycodes.KC_DF: self._layer_df,
RawKeycodes.KC_MO: self._layer_mo, RawKeycodes.KC_MO: self._layer_mo,
@ -56,6 +55,7 @@ class InternalState:
'keys_pressed': self.keys_pressed, 'keys_pressed': self.keys_pressed,
'active_layers': self.active_layers, 'active_layers': self.active_layers,
'leader_mode_history': self.leader_mode_history, 'leader_mode_history': self.leader_mode_history,
'leader_mode': self.config.leader_mode,
'start_time': self.start_time, 'start_time': self.start_time,
} }
@ -75,6 +75,21 @@ class InternalState:
return layer_key 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): def matrix_changed(self, row, col, is_pressed):
if self.config.debug_enabled: if self.config.debug_enabled:
print('Matrix changed (col, row, pressed?): {}, {}, {}'.format( print('Matrix changed (col, row, pressed?): {}, {}, {}'.format(
@ -88,24 +103,24 @@ class InternalState:
print('No key accessible for col, row: {}, {}'.format(row, col)) print('No key accessible for col, row: {}, {}'.format(row, col))
return self return self
if is_pressed:
self.keys_pressed.add(kc_changed)
self.coord_keys_pressed[int_coord] = kc_changed
else:
self.keys_pressed.discard(kc_changed)
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: if kc_changed.code >= FIRST_KMK_INTERNAL_KEYCODE:
self._process_internal_key_event( self._process_internal_key_event(
kc_changed, kc_changed,
is_pressed, is_pressed,
) )
else: else:
if is_pressed:
self.keys_pressed.add(kc_changed)
self.coord_keys_pressed[int_coord] = kc_changed
else:
self.keys_pressed.discard(kc_changed)
self.keys_pressed.discard(self.coord_keys_pressed[int_coord])
self.coord_keys_pressed[int_coord] = None
self.hid_pending = True self.hid_pending = True
if self.leader_mode % 2 == 1: if self.config.leader_mode % 2 == 1:
self._process_leader_mode() self._process_leader_mode()
return self return self
@ -304,13 +319,24 @@ class InternalState:
return self return self
def _begin_leader_mode(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) self.keys_pressed.discard(Keycodes.KMK.KC_LEAD)
# All leader modes are one number higher when activating # 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 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): def _process_leader_mode(self):
keys_pressed = self.keys_pressed keys_pressed = self.keys_pressed
@ -322,15 +348,11 @@ class InternalState:
self.leader_last_len = len(self.keys_pressed) self.leader_last_len = len(self.keys_pressed)
for key in keys_pressed: for key in keys_pressed:
if key == Keycodes.Common.KC_ENT: if (
# Process the action and remove the extra KC.ENT that was added to get here self.config.leader_mode == LeaderMode.ENTER_ACTIVE and
key == Keycodes.Common.KC_ENT
lmh = tuple(self.leader_mode_history) ):
self._handle_leader_sequence()
if lmh in self.config.leader_dictionary:
self.macro_pending = self.config.leader_dictionary[lmh].keydown
self._exit_leader_mode()
break break
elif key == Keycodes.Common.KC_ESC or key == Keycodes.KMK.KC_GESC: elif key == Keycodes.Common.KC_ESC or key == Keycodes.KMK.KC_GESC:
# Clean self and turn leader mode off. # Clean self and turn leader mode off.
@ -348,7 +370,7 @@ class InternalState:
def _exit_leader_mode(self): def _exit_leader_mode(self):
self.leader_mode_history.clear() self.leader_mode_history.clear()
self.leader_mode -= 1 self.config.leader_mode -= 1
self.leader_last_len = 0 self.leader_last_len = 0
self.keys_pressed.clear() self.keys_pressed.clear()
return self return self

View File

@ -98,12 +98,13 @@ class MatrixScanner:
self.report[2] = new_val self.report[2] = new_val
self.state[ba_idx] = new_val self.state[ba_idx] = new_val
any_changed = True any_changed = True
break
yield self.report
ba_idx += 1 ba_idx += 1
opin.value(False) opin.value(False)
if any_changed:
break
if not any_changed: if any_changed:
yield None return self.report

View File

@ -1,5 +1,5 @@
from kmk.boards.klarank import Firmware 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 KC
from kmk.keycodes import generate_leader_dictionary_seq as glds from kmk.keycodes import generate_leader_dictionary_seq as glds
from kmk.macros.simple import send_string 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.") 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 = { keyboard.leader_dictionary = {
glds('hello'): send_string('hello world from kmk macros'), glds('hello'): send_string('hello world from kmk macros'),
glds('wpm'): WPM, glds('wpm'): WPM,