possible leader fix
This commit is contained in:
@@ -1,128 +0,0 @@
|
||||
from kmk.extensions import Extension, InvalidExtensionEnvironment
|
||||
from kmk.handlers.stock import passthrough as handler_passthrough
|
||||
from kmk.keys import KC, make_key
|
||||
|
||||
|
||||
class LeaderMode:
|
||||
TIMEOUT = 0
|
||||
TIMEOUT_ACTIVE = 1
|
||||
ENTER = 2
|
||||
ENTER_ACTIVE = 3
|
||||
|
||||
|
||||
class Leader(Extension):
|
||||
def __init__(self, mode=LeaderMode.TIMEOUT, timeout=1000, sequences=None):
|
||||
if sequences is None:
|
||||
raise InvalidExtensionEnvironment(
|
||||
'sequences must be a dictionary, not None'
|
||||
)
|
||||
|
||||
self._mode = mode
|
||||
self._timeout = timeout
|
||||
self._sequences = self._compile_sequences(sequences)
|
||||
|
||||
self._leader_pending = None
|
||||
self._assembly_last_len = 0
|
||||
self._sequence_assembly = []
|
||||
|
||||
make_key(
|
||||
names=('LEADER', 'LEAD'),
|
||||
on_press=self._key_leader_pressed,
|
||||
on_release=handler_passthrough,
|
||||
)
|
||||
|
||||
def on_runtime_enable(self, keyboard):
|
||||
return
|
||||
|
||||
def on_runtime_disable(self, keyboard):
|
||||
return
|
||||
|
||||
def during_bootup(self, keyboard):
|
||||
return
|
||||
|
||||
def before_matrix_scan(self, keyboard):
|
||||
return
|
||||
|
||||
def after_matrix_scan(self, keyboard, matrix_update):
|
||||
if self._mode % 2 == 1:
|
||||
keys_pressed = keyboard.keys_pressed
|
||||
|
||||
if self._assembly_last_len and self._sequence_assembly:
|
||||
history_set = set(self._sequence_assembly)
|
||||
|
||||
keys_pressed = keys_pressed - history_set
|
||||
|
||||
self._assembly_last_len = len(keyboard.keys_pressed)
|
||||
|
||||
for key in keys_pressed:
|
||||
if self._mode == LeaderMode.ENTER_ACTIVE and key == KC.ENT:
|
||||
self._handle_leader_sequence(keyboard)
|
||||
elif key in (KC.ESC, KC.GESC):
|
||||
# Clean self and turn leader mode off.
|
||||
self._exit_leader_mode(keyboard)
|
||||
break
|
||||
elif key == KC.LEAD:
|
||||
break
|
||||
else:
|
||||
# Add key if not needing to escape
|
||||
# This needs replaced later with a proper debounce
|
||||
self._sequence_assembly.append(key)
|
||||
|
||||
keyboard.hid_pending = False
|
||||
|
||||
def before_hid_send(self, keyboard):
|
||||
return
|
||||
|
||||
def after_hid_send(self, keyboard):
|
||||
return
|
||||
|
||||
def on_powersave_enable(self, keyboard):
|
||||
return
|
||||
|
||||
def on_powersave_disable(self, keyboard):
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
def _compile_sequences(sequences):
|
||||
|
||||
for k, v in sequences.items():
|
||||
if not isinstance(k, tuple):
|
||||
new_key = tuple(KC[c] for c in k)
|
||||
sequences[new_key] = v
|
||||
|
||||
for k, v in sequences.items():
|
||||
if not isinstance(k, tuple):
|
||||
del sequences[k]
|
||||
|
||||
return sequences
|
||||
|
||||
def _handle_leader_sequence(self, keyboard):
|
||||
lmh = tuple(self._sequence_assembly)
|
||||
# Will get caught in infinite processing loops if we don't
|
||||
# exit leader mode before processing the target key
|
||||
self._exit_leader_mode(keyboard)
|
||||
|
||||
if lmh in self._sequences:
|
||||
# Stack depth exceeded if try to use add_key here with a unicode sequence
|
||||
keyboard.process_key(self._sequences[lmh], True)
|
||||
|
||||
keyboard.set_timeout(
|
||||
False, lambda: keyboard.remove_key(self._sequences[lmh])
|
||||
)
|
||||
|
||||
def _exit_leader_mode(self, keyboard):
|
||||
self._sequence_assembly.clear()
|
||||
self._mode -= 1
|
||||
self._assembly_last_len = 0
|
||||
keyboard.keys_pressed.clear()
|
||||
|
||||
def _key_leader_pressed(self, key, keyboard):
|
||||
if self._mode % 2 == 0:
|
||||
keyboard.keys_pressed.discard(key)
|
||||
# All leader modes are one number higher when activating
|
||||
self._mode += 1
|
||||
|
||||
if self._mode == LeaderMode.TIMEOUT_ACTIVE:
|
||||
keyboard.set_timeout(
|
||||
self._timeout, lambda: self._handle_leader_sequence(keyboard)
|
||||
)
|
@@ -97,9 +97,6 @@ def generate_codepoint_keysym_seq(codepoint, expected_length=4):
|
||||
# Not sure how to send emojis on Mac/Windows like that,
|
||||
# though, since (for example) the Canadian flag is assembled
|
||||
# from two five-character codepoints, 1f1e8 and 1f1e6
|
||||
#
|
||||
# As a bonus, this function can be pretty useful for
|
||||
# leader dictionary keys as strings.
|
||||
seq = [KC.N0 for _ in range(max(len(codepoint), expected_length))]
|
||||
|
||||
for idx, codepoint_fragment in enumerate(reversed(codepoint)):
|
||||
@@ -108,10 +105,6 @@ def generate_codepoint_keysym_seq(codepoint, expected_length=4):
|
||||
return seq
|
||||
|
||||
|
||||
def generate_leader_dictionary_seq(string):
|
||||
return tuple(generate_codepoint_keysym_seq(string, 1))
|
||||
|
||||
|
||||
def unicode_codepoint_sequence(codepoints):
|
||||
kc_seqs = (generate_codepoint_keysym_seq(codepoint) for codepoint in codepoints)
|
||||
|
||||
|
@@ -5,7 +5,7 @@ def passthrough(key, state, *args, **kwargs):
|
||||
return state
|
||||
|
||||
|
||||
def default_pressed(key, state, KC, coord_int=None, coord_raw=None):
|
||||
def default_pressed(key, state, KC, coord_int=None, coord_raw=None, *args, **kwargs):
|
||||
state.hid_pending = True
|
||||
|
||||
if coord_int is not None:
|
||||
@@ -16,7 +16,7 @@ def default_pressed(key, state, KC, coord_int=None, coord_raw=None):
|
||||
return state
|
||||
|
||||
|
||||
def default_released(key, state, KC, coord_int=None, coord_raw=None):
|
||||
def default_released(key, state, KC, coord_int=None, coord_raw=None, *args, **kwargs):
|
||||
state.hid_pending = True
|
||||
state.keys_pressed.discard(key)
|
||||
|
||||
|
Reference in New Issue
Block a user