diff --git a/docs/keycodes.md b/docs/keycodes.md index ea905e1..a8d4fa0 100644 --- a/docs/keycodes.md +++ b/docs/keycodes.md @@ -230,23 +230,3 @@ |`KC.RALT(kc)`|Hold Right Alt and press `kc` | |`KC.RGUI(kc)`|Hold Right GUI and press `kc` | - -## [Mod-Tap Keys] NOT IMPLEMENTED AT THIS TIME - -|Key |Aliases |Description | -|------------|---------------------------------------|-------------------------------------------------------| -|`LCTL_T(kc)`|`CTL_T(kc)` |Left Control when held, `kc` when tapped | -|`RCTL_T(kc)`| |Right Control when held, `kc` when tapped | -|`LSFT_T(kc)`|`SFT_T(kc)` |Left Shift when held, `kc` when tapped | -|`RSFT_T(kc)`| |Right Shift when held, `kc` when tapped | -|`LALT_T(kc)`|`ALT_T(kc)` |Left Alt when held, `kc` when tapped | -|`RALT_T(kc)`|`ALGR_T(kc)` |Right Alt when held, `kc` when tapped | -|`LGUI_T(kc)`|`LCMD_T(kc)`, `RWIN_T(kc)`, `GUI_T(kc)`|Left GUI when held, `kc` when tapped | -|`RGUI_T(kc)`|`RCMD_T(kc)`, `RWIN_T(kc)` |Right GUI when held, `kc` when tapped | -|`C_S_T(kc)` | |Left Control and Shift when held, `kc` when tapped | -|`MEH_T(kc)` | |Left Control, Shift and Alt when held, `kc` when tapped| -|`LCAG_T(kc)`| |Left Control, Alt and GUI when held, `kc` when tapped | -|`RCAG_T(kc)`| |Right Control, Alt and GUI when held, `kc` when tapped | -|`ALL_T(kc)` | |Left Control, Shift, Alt and GUI when held, `kc` when tapped - more info [here](http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/)| -|`SGUI_T(kc)`|`SCMD_T(kc)`, `SWIN_T(kc)` |Left Shift and GUI when held, `kc` when tapped | -|`LCA_T(kc)` | |Left Control and Alt when held, `kc` when tapped | diff --git a/docs/modtap.md b/docs/modtap.md new file mode 100644 index 0000000..7db2dec --- /dev/null +++ b/docs/modtap.md @@ -0,0 +1,30 @@ +# ModTap +One key if you tap it, one or more modifiers if you hold it! + + +## Helpful examples +Just copy the example from New Keycode above your keymap and change KC.SOMETHING to the key that you want when tapped. +After that, just use the new keycode anywhere in your keymap. + +|New Keycode | Description | +|-------------------------------------------------------|-----------------------------------------------------------------| +|LCTL = KC.MT(KC.SOMETHING, KC.LCTRL) |`LCTRL` if held `kc` if tapped | +|LSFT = KC.MT(KC.SOMETHING, KC.LSFT) |`LSHIFT` if held `kc` if tapped | +|LALT = KC.MT(KC.SOMETHING, KC.LALT) |`LALT` if held `kc` if tapped | +|LGUI = KC.MT(KC.SOMETHING, KC.LGUI) |`LGUI` if held `kc` if tapped | +|RCTL = KC.MT(KC.SOMETHING, KC.RCTRL) |`RCTRL` if held `kc` if tapped | +|RSFT = KC.MT(KC.SOMETHING, KC.RSFT) |`RSHIFT` if held `kc` if tapped | +|RALT = KC.MT(KC.SOMETHING, KC.RALT) |`RALT` if held `kc` if tapped | +|RGUI = KC.MT(KC.SOMETHING, KC.RGUI) |`RGUI` if held `kc` if tapped | +|SGUI = KC.MT(KC.SOMETHING, KC.LSHFT(KC.LGUI)) |`LSHIFT` and `LGUI` if held `kc` if tapped | +|LCA = KC.MT(KC.SOMETHING, KC.LCTRL(KC.LALT)) |`LCTRL` and `LALT` if held `kc` if tapped | +|LCAG = KC.MT(KC.SOMETHING, KC.LCTRL(KC.LALT(KC.LGUI))) |`LCTRL` and `LALT` and `LGUI` if held `kc` if tapped | +|MEH = KC.MT(KC.SOMETHING, KC.LCTRL(KC.LSFT(KC.LALT))) |`CTRL` and `LSHIFT` and `LALT` if held `kc` if tapped | +|HYPR = KC.MT(KC.SOMETHING, KC.HYPR) |`LCTRL` and `LSHIFT` and `LALT` and `LGUI` if held `kc` if tapped| + +```python +SHFT_HOME = KC.MT(KC.HOME, KC.LSFT) + +keyboard.keymap = [[ ...., SHFT_HOME, ....], ....] +``` + diff --git a/kmk/firmware.py b/kmk/firmware.py index 1bfcb54..7bb3c14 100644 --- a/kmk/firmware.py +++ b/kmk/firmware.py @@ -22,9 +22,19 @@ import kmk.kmktime # isort:skip import kmk.types # isort:skip import kmk.util # isort:skip +import busio # isort:skip +import gc # isort:skip + +import supervisor # isort:skip +from kmk.consts import LeaderMode, UnicodeMode # isort:skip +from kmk.hid import USB_HID # isort:skip +from kmk.internal_state import InternalState # isort:skip +from kmk.keys import KC # isort:skip +from kmk.matrix import MatrixScanner # isort:skip + # Now handlers that will be used in keys later -import kmk.handlers.layers -import kmk.handlers.stock +import kmk.handlers.layers # isort:skip +import kmk.handlers.stock # isort:skip # Now stuff that depends on the above (and so on) import kmk.keys # isort:skip @@ -39,16 +49,6 @@ import kmk.internal_state # isort:skip # Thanks for sticking around. Now let's do real work, starting below -import busio -import gc - -import supervisor -from kmk.consts import LeaderMode, UnicodeMode -from kmk.hid import USB_HID -from kmk.internal_state import InternalState -from kmk.keys import KC -from kmk.matrix import MatrixScanner - class Firmware: debug_enabled = False diff --git a/kmk/handlers/modtap.py b/kmk/handlers/modtap.py new file mode 100644 index 0000000..c88dad4 --- /dev/null +++ b/kmk/handlers/modtap.py @@ -0,0 +1,23 @@ +from kmk.kmktime import ticks_diff, ticks_ms + + +def mt_pressed(key, state, *args, **kwargs): + # Sets the timer start and acts like a modifier otherwise + state.keys_pressed.add(key.meta.mods) + + state.start_time['mod_tap'] = ticks_ms() + return state + + +def mt_released(key, state, *args, **kwargs): + # On keyup, check timer, and press key if needed. + state.keys_pressed.discard(key.meta.mods) + timer_name = 'mod_tap' + if state.start_time[timer_name] and ( + ticks_diff(ticks_ms(), state.start_time[timer_name]) < state.config.tap_time + ): + state.hid_pending = True + state.tap_key(key.meta.kc) + + state.start_time[timer_name] = None + return state diff --git a/kmk/keys.py b/kmk/keys.py index f6ef0a2..a542d91 100644 --- a/kmk/keys.py +++ b/kmk/keys.py @@ -1,9 +1,10 @@ import gc import kmk.handlers.layers as layers +import kmk.handlers.modtap as modtap import kmk.handlers.stock as handlers from kmk.consts import UnicodeMode -from kmk.types import (AttrDict, KeySeqSleepMeta, LayerKeyMeta, +from kmk.types import (AttrDict, KeySeqSleepMeta, LayerKeyMeta, ModTapKeyMeta, TapDanceKeyMeta, UnicodeModeKeyMeta) FIRST_KMK_INTERNAL_KEY = 1000 @@ -679,6 +680,22 @@ make_argumented_key( ) +def mod_tap_validator(kc, mods=None): + ''' + Validates that mod tap keys are correctly used + ''' + return ModTapKeyMeta(kc=kc, mods=mods) + + +# ModTap +make_argumented_key( + validator=mod_tap_validator, + names=('MT',), + on_press=modtap.mt_pressed, + on_release=modtap.mt_released, +) + + gc.collect() diff --git a/kmk/types.py b/kmk/types.py index 123f806..73a6d60 100644 --- a/kmk/types.py +++ b/kmk/types.py @@ -32,6 +32,12 @@ class LayerKeyMeta: self.kc = kc +class ModTapKeyMeta: + def __init__(self, kc=None, mods=None): + self.mods = mods + self.kc = kc + + class KeySequenceMeta: def __init__(self, seq): self.seq = seq