implement fast and late reset for combos
This commit is contained in:
parent
229b7afcb0
commit
400042f799
@ -4,22 +4,35 @@ from kmk.modules import Module
|
||||
|
||||
|
||||
class Combo:
|
||||
timeout = 50
|
||||
fast_reset = False
|
||||
per_key_timeout = False
|
||||
_timeout = None
|
||||
timeout = 50
|
||||
_remaining = []
|
||||
_timeout = None
|
||||
|
||||
def __init__(self, match, result, timeout=None, per_key_timeout=None):
|
||||
def __init__(
|
||||
self,
|
||||
match,
|
||||
result,
|
||||
fast_reset=None,
|
||||
per_key_timeout=None,
|
||||
timeout=None,
|
||||
):
|
||||
'''
|
||||
match: tuple of keys (KC.A, KC.B)
|
||||
result: key KC.C
|
||||
'''
|
||||
self.match = match
|
||||
self.result = result
|
||||
if timeout:
|
||||
self.timeout = timeout
|
||||
if per_key_timeout:
|
||||
if fast_reset is not None:
|
||||
self.fast_reset = fast_reset
|
||||
if per_key_timeout is not None:
|
||||
self.per_key_timeout = per_key_timeout
|
||||
if timeout is not None:
|
||||
self.timeout = timeout
|
||||
|
||||
def __repr__(self):
|
||||
return f'{self.__class__.__name__}({[k.code for k in self.match]})'
|
||||
|
||||
def matches(self, key):
|
||||
raise NotImplementedError
|
||||
@ -38,8 +51,9 @@ class Chord(Combo):
|
||||
|
||||
|
||||
class Sequence(Combo):
|
||||
timeout = 1000
|
||||
fast_reset = True
|
||||
per_key_timeout = True
|
||||
timeout = 1000
|
||||
|
||||
def matches(self, key):
|
||||
try:
|
||||
@ -147,13 +161,57 @@ class Combos(Module):
|
||||
if key in combo.match:
|
||||
# Deactivate combo if it matches current key.
|
||||
self.deactivate(keyboard, combo)
|
||||
self.reset_combo(keyboard, combo)
|
||||
|
||||
if combo.fast_reset:
|
||||
self.reset_combo(keyboard, combo)
|
||||
self._key_buffer = []
|
||||
else:
|
||||
combo._remaining.insert(0, key)
|
||||
self._matching.append(combo)
|
||||
|
||||
key = combo.result
|
||||
break
|
||||
|
||||
# Don't propagate key-release events for keys that have been buffered.
|
||||
# Append release events only if corresponding press is in buffer.
|
||||
else:
|
||||
# Non-active but matching combos can either activate on key release
|
||||
# if they're the only match, or "un-match" the released key but stay
|
||||
# matching if they're a repeatable combo.
|
||||
for combo in self._matching.copy():
|
||||
if key not in combo.match:
|
||||
continue
|
||||
|
||||
# Combo matches, but first key released before timeout.
|
||||
elif not combo._remaining:
|
||||
keyboard.cancel_timeout(combo._timeout)
|
||||
self._matching.remove(combo)
|
||||
self.activate(keyboard, combo)
|
||||
self._key_buffer = []
|
||||
keyboard._send_hid()
|
||||
self.deactivate(keyboard, combo)
|
||||
if combo.fast_reset:
|
||||
self.reset_combo(keyboard, combo)
|
||||
else:
|
||||
combo._remaining.insert(0, key)
|
||||
self._matching.append(combo)
|
||||
|
||||
# Skip combos that allow tapping.
|
||||
elif combo.fast_reset:
|
||||
continue
|
||||
|
||||
# This was the last key released of a repeatable combo.
|
||||
elif len(combo._remaining) == len(combo.match) - 1:
|
||||
self._matching.remove(combo)
|
||||
self.reset_combo(keyboard, combo)
|
||||
self.send_key_buffer(keyboard)
|
||||
self._key_buffer = []
|
||||
|
||||
# Anything between first and last key released.
|
||||
else:
|
||||
combo._remaining.insert(0, key)
|
||||
|
||||
# Don't propagate key-release events for keys that have been
|
||||
# buffered. Append release events only if corresponding press is in
|
||||
# buffer.
|
||||
pressed = self._key_buffer.count((int_coord, key, True))
|
||||
released = self._key_buffer.count((int_coord, key, False))
|
||||
if (pressed - released) > 0:
|
||||
@ -170,13 +228,8 @@ class Combos(Module):
|
||||
|
||||
if not combo._remaining:
|
||||
self.activate(keyboard, combo)
|
||||
if any([not pressed for (int_coord, key, pressed) in self._key_buffer]):
|
||||
# At least one of the combo keys has already been released:
|
||||
# "tap" the combo result.
|
||||
keyboard._send_hid()
|
||||
self.deactivate(keyboard, combo)
|
||||
self.reset(keyboard)
|
||||
self._key_buffer = []
|
||||
self.reset(keyboard)
|
||||
else:
|
||||
if not self._matching:
|
||||
# This was the last pending combo: flush key buffer.
|
||||
@ -216,4 +269,5 @@ class Combos(Module):
|
||||
def reset(self, keyboard):
|
||||
self._matching = []
|
||||
for combo in self.combos:
|
||||
self.reset_combo(keyboard, combo)
|
||||
if combo not in self._active:
|
||||
self.reset_combo(keyboard, combo)
|
||||
|
Loading…
x
Reference in New Issue
Block a user