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