Browse Source

fix(docs): Update tap-dance and hold-tap documentation

Co-Authored-By: Cem Aksoylar <caksoylar@users.noreply.github.com>
xmkb
Kurtis Lew 2 years ago committed by Julia Luna
parent
commit
16499b80b8
Signed by: xenua
GPG Key ID: 6A0C04FA9A7D7582
  1. BIN
      docs/docs/assets/hold-tap/case1_2.png
  2. 21
      docs/docs/assets/hold-tap/case1_2.svg
  3. BIN
      docs/docs/assets/hold-tap/case_hold_preferred.png
  4. 23
      docs/docs/assets/hold-tap/case_hold_preferred.svg
  5. BIN
      docs/docs/assets/hold-tap/comparison.png
  6. 131
      docs/docs/assets/hold-tap/comparison.svg
  7. 140
      docs/docs/assets/tap-dance/timing_diagram.svg
  8. 132
      docs/docs/behaviors/hold-tap.md
  9. 11
      docs/docs/behaviors/layers.md
  10. 9
      docs/docs/behaviors/mod-tap.md
  11. 83
      docs/docs/behaviors/tap-dance.md

BIN
docs/docs/assets/hold-tap/case1_2.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

21
docs/docs/assets/hold-tap/case1_2.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 50 KiB

BIN
docs/docs/assets/hold-tap/case_hold_preferred.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

23
docs/docs/assets/hold-tap/case_hold_preferred.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 25 KiB

BIN
docs/docs/assets/hold-tap/comparison.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

131
docs/docs/assets/hold-tap/comparison.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 900 KiB

140
docs/docs/assets/tap-dance/timing_diagram.svg

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 226 KiB

132
docs/docs/behaviors/hold-tap.md

@ -3,6 +3,9 @@ title: Hold-Tap Behavior @@ -3,6 +3,9 @@ title: Hold-Tap Behavior
sidebar_label: Hold-Tap
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## Summary
Hold-tap is the basis for other behaviors such as layer-tap and mod-tap.
@ -13,11 +16,11 @@ Simply put, the hold-tap key will output the 'hold' behavior if it's held for a @@ -13,11 +16,11 @@ Simply put, the hold-tap key will output the 'hold' behavior if it's held for a
The graph below shows how the hold-tap decides between a 'tap' and a 'hold'.
![Simple behavior](../assets/hold-tap/case1_2.png)
![Simple behavior](../assets/hold-tap/case1_2.svg)
By default, the hold-tap is configured to also select the 'hold' functionality if another key is tapped while it's active:
![Hold preferred behavior](../assets/hold-tap/case1_2.png)
![Hold preferred behavior](../assets/hold-tap/case_hold_preferred.svg)
We call this the 'hold-preferred' flavor of hold-taps. While this flavor may work very well for a ctrl/escape key, it's not very well suited for home-row mods or layer-taps. That's why there are two more flavors to choose from: 'tap-preferred' and 'balanced'.
@ -30,11 +33,11 @@ We call this the 'hold-preferred' flavor of hold-taps. While this flavor may wor @@ -30,11 +33,11 @@ We call this the 'hold-preferred' flavor of hold-taps. While this flavor may wor
When the hold-tap key is released and the hold behavior has not been triggered, the tap behavior will trigger.
![Hold-tap comparison](../assets/hold-tap/comparison.png)
![Hold-tap comparison](../assets/hold-tap/comparison.svg)
### Basic usage
For basic usage, please see [mod-tap](mod-tap.md) and [layer-tap](layers.md) pages.
For basic usage, please see the [mod-tap](mod-tap.md) and [layer-tap](layers.md#layer-tap) pages.
### Advanced Configuration
@ -50,9 +53,9 @@ In QMK, unlike ZMK, this functionality is enabled by default, and you turn it of @@ -50,9 +53,9 @@ In QMK, unlike ZMK, this functionality is enabled by default, and you turn it of
#### `global-quick-tap`
If global quick tap is enabled, then `quick-tap-ms` will apply not only when the given hold-tap is tapped but for any key tap before it. This effectively disables the hold tap when typing quickly, which can be quite useful for home row mods. It can also have the effect of removing the input delay when typing quickly.
If `global-quick-tap` is enabled, then `quick-tap-ms` will apply not only when the given hold-tap is tapped, but for any key tapped before it. This effectively disables the hold-tap when typing quickly, which can be quite useful for homerow mods. It can also have the effect of removing the input delay when typing quickly.
For example, the following hold-tap configuration enables global quick tap with a 125 millisecond term.
For example, the following hold-tap configuration enables `global-quick-tap` with a 125 millisecond `quick-tap-ms` term.
```
gqt: global-quick-tap {
@ -69,11 +72,11 @@ gqt: global-quick-tap { @@ -69,11 +72,11 @@ gqt: global-quick-tap {
If you press `&kp A` and then `&gqt LEFT_SHIFT B` **within** 125 ms, then `ab` will be output. Importantly, `b` will be output immediately since it was within the `quick-tap-ms`. This quick-tap behavior will work for any key press, whether it is within a behavior like hold-tap, or a simple `&kp`. This means the `&gqt LEFT_SHIFT B` binding will only have its underlying hold-tap behavior if it is pressed 125 ms **after** a key press.
Note that the higher the `quick-tap-ms` the harder it will be to use the hold behavior, making this less applicable for something like capitalizing letter while typing normally. However, if the hold behavior isn't used during fast typing, then it can be an effective way to mitigate misfires.
Note that the greater the value of `quick-tap-ms` is, the harder it will be to invoke the hold behavior, making this feature less applicable for use-cases like capitalizing letters while typing normally. However, if the hold behavior isn't used during fast typing, then it can be an effective way to mitigate misfires.
#### `retro-tap`
If retro tap is enabled, the tap behavior is triggered when releasing the hold-tap key if no other key was pressed in the meantime.
If `retro-tap` is enabled, the tap behavior is triggered when releasing the hold-tap key if no other key was pressed in the meantime.
For example, if you press `&mt LEFT_SHIFT A` and then release it without pressing another key, it will output `a`.
@ -85,16 +88,20 @@ For example, if you press `&mt LEFT_SHIFT A` and then release it without pressin @@ -85,16 +88,20 @@ For example, if you press `&mt LEFT_SHIFT A` and then release it without pressin
#### Positional hold-tap and `hold-trigger-key-positions`
- Including `hold-trigger-key-positions` in your hold-tap definition turns on the positional hold-tap feature.
- With positional hold-tap enabled, if you press any key **NOT** listed in `hold-trigger-key-positions` before `tapping-term-ms` expires, it will produce a tap.
- In all other situations, positional hold-tap will not modify the behavior of your hold-tap.
- Positional hold-tap is useful with home-row modifiers. If you have a home-row modifier key in the left hand for example, by including only keys positions from the right hand in `hold-trigger-key-positions`, you will only get hold behaviors during cross-hand key combinations.
- Note that `hold-trigger-key-positions` is an array of key position indexes. Key positions are numbered according to your keymap, starting with 0. So if the first key in your keymap is Q, this key is in position 0. The next key (probably W) will be in position 1, et cetera.
- See the following example, which uses a hold-tap behavior definition, configured with the `hold-preferred` flavor, and with positional hold-tap enabled:
Including `hold-trigger-key-positions` in your hold-tap definition turns on the positional hold-tap feature. With positional hold-tap enabled, if you press any key **NOT** listed in `hold-trigger-key-positions` before `tapping-term-ms` expires, it will produce a tap.
In all other situations, positional hold-tap will not modify the behavior of your hold-tap. Positional hold-tap is useful when used with home-row modifiers: for example, if you have a home-row modifier key in the left hand, by including only key positions from the right hand in `hold-trigger-key-positions`, you will only get hold behaviors during cross-hand key combinations.
:::info
Note that `hold-trigger-key-positions` is an array of key position indexes. Key positions are numbered sequentially according to your keymap, starting with 0. So if the first key in your keymap is Q, this key is in position 0. The next key (probably W) will be in position 1, et cetera.
:::
See the following example, which uses a hold-tap behavior definition, configured with the `hold-preferred` flavor, and with positional hold-tap enabled:
```
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
/ {
behaviors {
pht: positional_hold_tap {
@ -125,15 +132,26 @@ For example, if you press `&mt LEFT_SHIFT A` and then release it without pressin @@ -125,15 +132,26 @@ For example, if you press `&mt LEFT_SHIFT A` and then release it without pressin
- The sequence `(pht_down, W_down, W_up, pht_up)` produces `W`. The normal hold behavior (LEFT_SHIFT) **is NOT** modified into a tap behavior (Q) by positional hold-tap because the first key pressed after the hold-tap key is the `W key`, which is in position 1, which **IS** included in `hold-trigger-key-positions`.
- If the `LEFT_SHIFT / Q key` is held by itself for longer than `tapping-term-ms`, a hold behavior is produced. This is because positional hold-tap only modifies the behavior of a hold-tap if another key is pressed before the `tapping-term-ms` period expires.
#### Home row mods
### Example Use-Cases
<Tabs
defaultValue="homerow_mods"
values={[
{label: 'Homerow Mods', value: 'homerow_mods'},
{label: 'Autoshift', value: 'autoshift'},
{label: 'Toggle-on-Tap, Momentary-on-Hold Layers', value: 'tog_mo'},
]}>
<TabItem value="homerow_mods">
The following are suggested hold-tap configurations that work well with home row mods:
##### Option 1: cross-hand only modifiers, using `tap-unless-interrupted` and positional hold-tap (`hold-trigger-key-positions`)
```
```dtsi title="Homerow Mods: Cross-hand Example"
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
/ {
behaviors {
lh_pht: left_hand_positional_hold_tap {
@ -162,7 +180,7 @@ The following are suggested hold-tap configurations that work well with home row @@ -162,7 +180,7 @@ The following are suggested hold-tap configurations that work well with home row
##### Option 2: `tap-preferred`
```
```dtsi title="Homerow Mods: Tap-Preferred Example"
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
@ -188,12 +206,11 @@ The following are suggested hold-tap configurations that work well with home row @@ -188,12 +206,11 @@ The following are suggested hold-tap configurations that work well with home row
};
};
};
```
##### Option 3: `balanced`
```
```dtsi title="Homerow Mods: Balanced Example"
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
@ -219,9 +236,84 @@ The following are suggested hold-tap configurations that work well with home row @@ -219,9 +236,84 @@ The following are suggested hold-tap configurations that work well with home row
};
};
};
```
</TabItem>
<TabItem value="autoshift">
A popular method of implementing Autoshift in ZMK involves a C-preprocessor macro, commonly defined as `AS(keycode)`. This macro applies the `LSHIFT` modifier to the specified `keycode` when `AS(keycode)` is held, and simply performs a [keypress](key-press.md), `&kp keycode`, when the `AS(keycode)` binding is tapped. This simplifies the use of Autoshift in a keymap, as the complete hold-tap bindings for each desired Autoshift key, as in `&as LS(<keycode 1>) <keycode 1> &as LS(<keycode 2>) <keycode 2> ... &as LS(<keycode n>) <keycode n>`, can be quite cumbersome to use when applied to a large portion of the keymap.
```dtsi title="Hold-Tap Example: Autoshift"
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#define AS(keycode) &as LS(keycode) keycode // Autoshift Macro
/ {
behaviors {
as: auto_shift {
compatible = "zmk,behavior-hold-tap";
label = "AUTO_SHIFT";
#binding-cells = <2>;
tapping_term_ms = <135>;
quick_tap_ms = <0>;
flavor = "tap-preferred";
bindings = <&kp>, <&kp>;
};
};
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
AS(Q) AS(W) AS(E) AS(R) AS(T) AS(Y) // Autoshift applied for QWERTY keys
>;
};
};
};
```
</TabItem>
<TabItem value="tog_mo">
This hold-tap example implements a [toggle-layer](layers.md/#toggle-layer) when the keybind is tapped and a [momentary-layer](layers.md/#momentary-layer) when it is held. Similarly to the Autoshift and Sticky Hold use-cases, a `TOG_MO(layer)` macro is defined such that the `&tog` and `&mo` behaviors can target a single layer.
```dtsi title="Hold-Tap Example: Toggle layer on Tap, Momentary layer on Hold"
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#define TOG_MO(layer) &tog_mo layer layer // Macro to apply toggle-layer-on-tap/momentary-layer-on-hold to a specific layer
/ {
behaviors {
tog_mo: behavior_mo_tog {
compatible = "zmk,behavior-hold-tap";
label = "mo_tog";
#binding-cells = <2>;
flavor = "hold-preferred";
tapping-term-ms = <200>;
bindings = <&tog>, <&mo>;
};
};
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
&tog_mo 2 1 // &mo 2 on hold, &tog 1 on tap
TOG_MO(3) // &mo 3 on hold, &tog 3 on tap
>;
};
};
};
```
#### Comparison to QMK
</TabItem>
</Tabs>
### Comparison to QMK
The hold-preferred flavor works similar to the `HOLD_ON_OTHER_KEY_PRESS` setting in QMK. The 'balanced' flavor is similar to the `PERMISSIVE_HOLD` setting, and the `tap-preferred` flavor is similar to `IGNORE_MOD_TAP_INTERRUPT`.

11
docs/docs/behaviors/layers.md

@ -43,7 +43,7 @@ Example: @@ -43,7 +43,7 @@ Example:
## Layer-tap
The "layer-tap" behavior enables a layer when a key is held, and output another key when the key is only tapped for a short time. For more information on the inner workings of layer-tap, see [hold-tap](hold-tap.md).
The "layer-tap" behavior enables a layer when a key is held, and outputs a [keypress](key-press.md) when the key is only tapped for a short time.
### Behavior Binding
@ -57,6 +57,15 @@ Example: @@ -57,6 +57,15 @@ Example:
&lt LOWER SPACE
```
:::info
Functionally, the layer-tap is a [hold-tap](hold-tap.md) of the ["tap-preferred" flavor](hold-tap.md/#flavors) and a [`tapping-term-ms`](hold-tap.md/#tapping-term-ms) of 200 that takes in a [`momentary layer`](#momentary-layer) and a [keypress](key-press.md) as its "hold" and "tap" parameters, respectively.
For users who want to send a different [keycode](../codes/index.mdx) depending on if the same key is held or tapped, see [Mod-Tap](mod-tap.md).
Similarly, for users looking to create a keybind like the layer-tap that depending on how long the key is held, invokes behaviors like [sticky keys](sticky-key.md) or [key toggles](key-toggle.md), see [Hold-Tap](hold-tap.md).
:::
## To Layer
The "to layer" behavior enables a layer and disables _all_ other layers _except_ the default layer.

9
docs/docs/behaviors/mod-tap.md

@ -44,6 +44,11 @@ You can configure a different tapping term in your keymap: @@ -44,6 +44,11 @@ You can configure a different tapping term in your keymap:
};
```
### Additional information
:::info
Under the hood, the mod-tap is simply a [hold-tap](hold-tap.md) of the ["hold-preferred" flavor](hold-tap.md/#flavors) with a [`tapping-term-ms`](hold-tap.md/#tapping-term-ms) of 200 that takes in two [keypresses](key-press.md) as its "hold" and "tap" parameters. This means that the mod-tap can be used to invoke **any** [keycode](../codes/index.mdx), and is not limited to only activating [modifier keys](../codes/modifiers.mdx) when it is held.
The mod-tap is a [hold-tap](hold-tap.md) under the hood with the "hold-preferred" flavor and tapping-term-ms 200.
For users who want to momentarily access a specific [layer](../features/keymaps#layers) while a key is held and send a keycode when the same key is tapped, see [Layer-Tap](layers.md/#layer-tap).
Similarly, for users looking to create a keybind like the mod-tap that invokes behaviors _other_ than [keypresses](key-press.md), like [sticky keys](sticky-key.md) or [key toggles](key-toggle.md), see [Hold-Tap](hold-tap.md).
:::

83
docs/docs/behaviors/tap-dance.md

@ -3,39 +3,41 @@ title: Tap-Dance Behavior @@ -3,39 +3,41 @@ title: Tap-Dance Behavior
sidebar_label: Tap-Dance
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## Summary
A tap-dance key invokes a different behavior (e.g. `kp`) corresponding
to how many times it is pressed. For example, you could configure a
tap-dance key that acts as `LSHIFT` if tapped once, or Caps _Lock_ if tapped twice.
The expandability of the number of [`bindings`](#bindings) attached to a
particular tap-dance is a great way to add more functionality to a single key,
especially for keyboards with a limited number of keys.
Tap-dances are completely custom, so for every unique tap-dance key,
a new tap-dance must be defined in your keymap's `behaviors`.
A tap-dance key invokes a different behavior (e.g. `kp`) corresponding to how many times it is pressed. For example, you could configure a tap-dance key that acts as `LSHIFT` if tapped once, or Caps _Lock_ if tapped twice. The expandability of the number of [`bindings`](#bindings) attached to a particular tap-dance is a great way to add more functionality to a single key, especially for keyboards with a limited number of keys. Tap-dances are completely custom, so for every unique tap-dance key,a new tap-dance must be defined in your keymap's `behaviors`.
Tap-dances are designed to resolve immediately when interrupted by another keypress.
Meaning, when a keybind is pressed other than any active tap-dances,
the tap-dance will activate according to the current value of its
counter before the interrupting keybind is registered.
Tap-dances are designed to resolve immediately when interrupted by another keypress. Meaning, when a keybind is pressed other than any active tap-dances, the tap-dance will activate according to the current value of its counter before the interrupting keybind is registered.
### Configuration
#### `tapping-term-ms`
Defines the maximum elapsed time after the last tap-dance keybind press
before a binding is selected from [`bindings`](#bindings).
Default value is `200`ms.
Defines the maximum elapsed time after the last tap-dance keybind press before a binding is selected from [`bindings`](#bindings). Default value is `200`ms.
#### `bindings`
An array of one or more keybinds. This list can include [any ZMK keycode](../codes/) and bindings for ZMK behaviors.
An array of one or more keybinds. This list can include [any ZMK keycode](../codes/) and any listed ZMK behavior, like [hold-taps](hold-tap.md), or [sticky keys](sticky-key.md). The index of a keybind in the `bindings` array corresponds to the number of times the tap-dance binding is pressed. For example, in the [basic tap-dance counter](#basic-example-counter) shown below, `&kp N2` is the second binding in the array of `bindings`: we then see an output of `2` when the `td0` binding is pressed twice.
#### Example Usage
The number of bindings in this array also determines the tap-dance's maximum number of keypresses. When a tap-dance reaches its maximum number of keypresses, it will immediately invoke the last behavior in its list of `bindings`, rather than waiting for [`tapping-term-ms`](#tapping-term-ms) to expire before the output is displayed.
This example configures a tap-dance named `td0` that outputs the number of times it is pressed from 1-3.
### Example Usage
```
<Tabs
defaultValue="basic"
values={[
{label: 'Basic Example: Counter', value: 'basic'},
{label: 'Advanced Example: Mod-Tap Nested inside Tap-Dance', value: 'advanced'},
]}>
<TabItem value="basic">
This example configures a tap-dance named `td0` that outputs the number of times its binding is pressed from 1-3.
```title="Basic Tap-Dance Example: Counter"
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
@ -67,10 +69,41 @@ The following image describes the behavior of this particular tap-dance. @@ -67,10 +69,41 @@ The following image describes the behavior of this particular tap-dance.
![Timing Diagram](../assets/tap-dance/timing_diagram.svg)
:::note
Alphanumeric [`key press`](key-press.md) bindings, like those used for `td0`,
will release as soon as an interrupting key press occurs.
For instance, if a modifier key like `LSHIFT` were to replace the `N1`
binding in the last example above, it would remain pressed until `td0`'s
binding is released and the output would instead be `J`. Any following
alphanumeric key presses would be capitalized as long as `td0` is held down.
Alphanumeric [`key press`](key-press.md) bindings, like those used for `td0`, will release as soon as an interrupting key press occurs. For instance, if a modifier key like `LSHIFT` were to replace the `N1` binding in the last example above, it would remain pressed until `td0`'s binding is released and the output would instead be `J`. Any following alphanumeric key presses would be capitalized as long as `td0` is held down.
:::
</TabItem>
<TabItem value="advanced">
This example configures a mod-tap inside a tap-dance named `td_mt` that outputs `CAPSLOCK` on a single tap, `LSHIFT` on a single press and hold, and `LCTRL` when the tap-dance is pressed twice.
```title="Advanced Tap-Dance Example: Nested Mod-Tap"
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
/ {
behaviors {
td_mt: tap_dance_mod_tap {
compatible = "zmk,behavior-tap-dance";
label = "TAP_DANCE_MOD_TAP";
#binding-cells = <0>;
tapping-term-ms = <200>;
bindings = <&mt LSHIFT CAPSLOCK>, <&kp LCTRL>;
};
};
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
&td_mt
>;
};
};
};
```
</TabItem>
</Tabs>

Loading…
Cancel
Save