implement multiple-choice for holdtap repeat
This commit is contained in:
parent
72735e0b5d
commit
178afdfeb1
@ -31,7 +31,7 @@ keyboard.modules.append(modtap)
|
||||
## Custom HoldTap Behavior
|
||||
The full ModTap signature is as follows:
|
||||
```python
|
||||
KC.MT(KC.TAP, KC.HOLD, prefer_hold=True, tap_interrupted=False, tap_time=None, repeat=False)
|
||||
KC.MT(KC.TAP, KC.HOLD, prefer_hold=True, tap_interrupted=False, tap_time=None, repeat=HoldTapRepeat.NONE)
|
||||
```
|
||||
* `prefer_hold`: decides which keycode the ModTap key resolves to when another
|
||||
key is pressed before the timeout finishes. When `True` the hold keycode is
|
||||
@ -42,9 +42,10 @@ KC.MT(KC.TAP, KC.HOLD, prefer_hold=True, tap_interrupted=False, tap_time=None, r
|
||||
* `tap_time`: length of the tap timeout in milliseconds.
|
||||
* `repeat`: decides how to interpret repeated presses if they happen within
|
||||
`tap_time` after a release.
|
||||
When `True` the repeated press sends the previous keycode, no matter
|
||||
how long the key remains pressed the second time.
|
||||
This allows to hold the tap keycode, or repeatedly tap the hold keycode.
|
||||
When `False` repeated presses are independent.
|
||||
* `TAP`: repeat tap action, if previous action was a tap.
|
||||
* `HOLD`: repeat hold action, if previous action was a hold.
|
||||
* `ALL`: repeat all of the above.
|
||||
* `NONE`: no repeat action (default), everything works as expected.
|
||||
The `HoldTapRepeat` enum must be imported from `kmk.modules.holdtap`.
|
||||
|
||||
Each of these parameters can be set for every ModTap key individually.
|
||||
|
@ -15,6 +15,13 @@ class ActivationType:
|
||||
REPEAT = const(4)
|
||||
|
||||
|
||||
class HoldTapRepeat:
|
||||
NONE = const(0)
|
||||
TAP = const(1)
|
||||
HOLD = const(2)
|
||||
ALL = const(3)
|
||||
|
||||
|
||||
class HoldTapKeyState:
|
||||
def __init__(self, timeout_key, *args, **kwargs):
|
||||
self.timeout_key = timeout_key
|
||||
@ -31,7 +38,7 @@ class HoldTapKeyMeta:
|
||||
prefer_hold=True,
|
||||
tap_interrupted=False,
|
||||
tap_time=None,
|
||||
repeat=False,
|
||||
repeat=HoldTapRepeat.NONE,
|
||||
):
|
||||
self.tap = tap
|
||||
self.hold = hold
|
||||
@ -155,13 +162,17 @@ class HoldTap(Module):
|
||||
|
||||
state = self.key_states[key]
|
||||
keyboard.cancel_timeout(state.timeout_key)
|
||||
repeat = key.meta.repeat & HoldTapRepeat.TAP
|
||||
|
||||
if state.activated == ActivationType.HOLD_TIMEOUT:
|
||||
# release hold
|
||||
self.ht_deactivate_hold(key, keyboard, *args, **kwargs)
|
||||
repeat = key.meta.repeat & HoldTapRepeat.HOLD
|
||||
elif state.activated == ActivationType.INTERRUPTED:
|
||||
# release tap
|
||||
self.ht_deactivate_on_interrupt(key, keyboard, *args, **kwargs)
|
||||
if key.meta.prefer_hold:
|
||||
repeat = key.meta.repeat & HoldTapRepeat.HOLD
|
||||
elif state.activated == ActivationType.PRESSED:
|
||||
# press and release tap because key released within tap time
|
||||
self.ht_activate_tap(key, keyboard, *args, **kwargs)
|
||||
@ -174,15 +185,16 @@ class HoldTap(Module):
|
||||
self.ht_deactivate_tap(key, keyboard, *args, **kwargs)
|
||||
|
||||
# don't delete the key state right now in this case
|
||||
tap_time = 0
|
||||
if key.meta.repeat:
|
||||
if repeat:
|
||||
if key.meta.tap_time is None:
|
||||
tap_time = self.tap_time
|
||||
else:
|
||||
tap_time = key.meta.tap_time
|
||||
state.timeout_key = keyboard.set_timeout(
|
||||
tap_time, lambda: self.key_states.pop(key)
|
||||
)
|
||||
state.timeout_key = keyboard.set_timeout(
|
||||
tap_time, lambda: self.key_states.pop(key)
|
||||
)
|
||||
else:
|
||||
del self.key_states[key]
|
||||
|
||||
return keyboard
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import unittest
|
||||
|
||||
from kmk.keys import KC
|
||||
from kmk.modules.holdtap import HoldTapRepeat
|
||||
from kmk.modules.layers import Layers
|
||||
from kmk.modules.modtap import ModTap
|
||||
from kmk.modules.oneshot import OneShot
|
||||
@ -275,7 +276,13 @@ class TestHoldTap(unittest.TestCase):
|
||||
def test_holdtap_repeat(self):
|
||||
keyboard = KeyboardTest(
|
||||
[ModTap()],
|
||||
[[KC.MT(KC.A, KC.B, repeat=True, tap_time=50)]],
|
||||
[
|
||||
[
|
||||
KC.MT(KC.A, KC.B, repeat=HoldTapRepeat.ALL, tap_time=50),
|
||||
KC.MT(KC.A, KC.B, repeat=HoldTapRepeat.TAP, tap_time=50),
|
||||
KC.MT(KC.A, KC.B, repeat=HoldTapRepeat.HOLD, tap_time=50),
|
||||
]
|
||||
],
|
||||
debug_enabled=False,
|
||||
)
|
||||
|
||||
@ -331,6 +338,18 @@ class TestHoldTap(unittest.TestCase):
|
||||
[{KC.A}, {}, {KC.B}, {}, {KC.A}, {}],
|
||||
)
|
||||
|
||||
keyboard.test(
|
||||
'tap repeat / no hold repeat ',
|
||||
[(1, True), t_after, (1, False), (1, True), (1, False)],
|
||||
[{KC.B}, {}, {KC.A}, {}],
|
||||
)
|
||||
|
||||
keyboard.test(
|
||||
'hold repeat / no tap repeat ',
|
||||
[(2, True), (2, False), (2, True), t_after, (2, False)],
|
||||
[{KC.A}, {}, {KC.B}, {}],
|
||||
)
|
||||
|
||||
def test_oneshot(self):
|
||||
keyboard = KeyboardTest(
|
||||
[Layers(), ModTap(), OneShot()],
|
||||
|
Loading…
Reference in New Issue
Block a user