[Docs] Clarify Zadig usage in FAQ Docs (#6360)
[jackhill/qmk/firmware.git] / docs / feature_tap_dance.md
CommitLineData
7b0356d1 1# Tap Dance: A Single Key Can Do 3, 5, or 100 Different Things
995c3141 2
d8e29b53 3<!-- FIXME: Break this up into multiple sections -->
4
995c3141
JH
5Hit the semicolon key once, send a semicolon. Hit it twice, rapidly -- send a colon. Hit it three times, and your keyboard's LEDs do a wild dance. That's just one example of what Tap Dance can do. It's one of the nicest community-contributed features in the firmware, conceived and created by [algernon](https://github.com/algernon) in [#451](https://github.com/qmk/qmk_firmware/pull/451). Here's how algernon describes the feature:
6
7With this feature one can specify keys that behave differently, based on the amount of times they have been tapped, and when interrupted, they get handled before the interrupter.
8
a87b36d7 9To make it clear how this is different from `ACTION_FUNCTION_TAP`, let's explore a certain setup! We want one key to send `Space` on single tap, but `Enter` on double-tap.
995c3141 10
a87b36d7 11With `ACTION_FUNCTION_TAP`, it is quite a rain-dance to set this up, and has the problem that when the sequence is interrupted, the interrupting key will be sent first. Thus, `SPC a` will result in `a SPC` being sent, if they are typed within `TAPPING_TERM`. With the tap dance feature, that'll come out as `SPC a`, correctly.
995c3141
JH
12
13The implementation hooks into two parts of the system, to achieve this: into `process_record_quantum()`, and the matrix scan. We need the latter to be able to time out a tap sequence even when a key is not being pressed, so `SPC` alone will time out and register after `TAPPING_TERM` time.
14
15But lets start with how to use it, first!
16
03de0c85 17First, you will need `TAP_DANCE_ENABLE=yes` in your `rules.mk`, because the feature is disabled by default. This adds a little less than 1k to the firmware size. Next, you will want to define some tap-dance keys, which is easiest to do with the `TD()` macro, that - similar to `F()`, takes a number, which will later be used as an index into the `tap_dance_actions` array.
995c3141 18
a87b36d7 19This array specifies what actions shall be taken when a tap-dance key is in action. Currently, there are five possible options:
995c3141
JH
20
21* `ACTION_TAP_DANCE_DOUBLE(kc1, kc2)`: Sends the `kc1` keycode when tapped once, `kc2` otherwise. When the key is held, the appropriate keycode is registered: `kc1` when pressed and held, `kc2` when tapped once, then pressed and held.
bfb5922f 22* `ACTION_TAP_DANCE_DUAL_ROLE(kc, layer)`: Sends the `kc` keycode when tapped once, or moves to `layer`. (this functions like the `TO` layer keycode).
995c3141 23* `ACTION_TAP_DANCE_FN(fn)`: Calls the specified function - defined in the user keymap - with the final tap count of the tap dance action.
a87b36d7 24* `ACTION_TAP_DANCE_FN_ADVANCED(on_each_tap_fn, on_dance_finished_fn, on_dance_reset_fn)`: Calls the first specified function - defined in the user keymap - on every tap, the second function when the dance action finishes (like the previous option), and the last function when the tap dance action resets.
25* `ACTION_TAP_DANCE_FN_ADVANCED_TIME(on_each_tap_fn, on_dance_finished_fn, on_dance_reset_fn, tap_specific_tapping_term)`: This functions identically to the `ACTION_TAP_DANCE_FN_ADVANCED` function, but uses a custom tapping term for it, instead of the predefined `TAPPING_TERM`.
995c3141 26
e36d6bbb 27The first option is enough for a lot of cases, that just want dual roles. For example, `ACTION_TAP_DANCE_DOUBLE(KC_SPC, KC_ENT)` will result in `Space` being sent on single-tap, `Enter` otherwise.
995c3141 28
d210ac7a
DJ
29!> Keep in mind that only [basic keycodes](keycodes_basic.md) are supported here. Custom keycodes are not supported.
30
995c3141
JH
31And that's the bulk of it!
32
33And now, on to the explanation of how it works!
34
35The main entry point is `process_tap_dance()`, called from `process_record_quantum()`, which is run for every keypress, and our handler gets to run early. This function checks whether the key pressed is a tap-dance key. If it is not, and a tap-dance was in action, we handle that first, and enqueue the newly pressed key. If it is a tap-dance key, then we check if it is the same as the already active one (if there's one active, that is). If it is not, we fire off the old one first, then register the new one. If it was the same, we increment the counter and the timer.
36
37This means that you have `TAPPING_TERM` time to tap the key again, you do not have to input all the taps within that timeframe. This allows for longer tap counts, with minimal impact on responsiveness.
38
39Our next stop is `matrix_scan_tap_dance()`. This handles the timeout of tap-dance keys.
40
41For the sake of flexibility, tap-dance actions can be either a pair of keycodes, or a user function. The latter allows one to handle higher tap counts, or do extra things, like blink the LEDs, fiddle with the backlighting, and so on. This is accomplished by using an union, and some clever macros.
42
d8e29b53 43# Examples
44
45## Simple Example
995c3141
JH
46
47Here's a simple example for a single definition:
48
03de0c85 491. In your `rules.mk`, add `TAP_DANCE_ENABLE = yes`
995c3141
JH
502. In your `config.h` (which you can copy from `qmk_firmware/keyboards/planck/config.h` to your keymap directory), add `#define TAPPING_TERM 200`
513. In your `keymap.c` file, define the variables and definitions, then add to your keymap:
52
53```c
54//Tap Dance Declarations
55enum {
56 TD_ESC_CAPS = 0
57};
58
59//Tap Dance Definitions
60qk_tap_dance_action_t tap_dance_actions[] = {
61 //Tap once for Esc, twice for Caps Lock
62 [TD_ESC_CAPS] = ACTION_TAP_DANCE_DOUBLE(KC_ESC, KC_CAPS)
63// Other declarations would go here, separated by commas, if you have them
64};
65
66//In Layer declaration, add tap dance item in place of a key code
67TD(TD_ESC_CAPS)
68```
69
383e508b 70## Complex Examples
d8e29b53 71
383e508b
DG
72This section details several complex tap dance examples.
73All the enums used in the examples are declared like this:
995c3141
JH
74
75```c
383e508b 76// Enums defined for all examples:
995c3141
JH
77enum {
78 CT_SE = 0,
79 CT_CLN,
80 CT_EGG,
81 CT_FLSH,
383e508b 82 X_TAP_DANCE
995c3141 83};
383e508b 84```
7b0356d1 85### Example 1: Send `:` on Single Tap, `;` on Double Tap
383e508b 86```c
995c3141
JH
87void dance_cln_finished (qk_tap_dance_state_t *state, void *user_data) {
88 if (state->count == 1) {
89 register_code (KC_RSFT);
90 register_code (KC_SCLN);
91 } else {
92 register_code (KC_SCLN);
93 }
94}
95
96void dance_cln_reset (qk_tap_dance_state_t *state, void *user_data) {
97 if (state->count == 1) {
98 unregister_code (KC_RSFT);
99 unregister_code (KC_SCLN);
100 } else {
101 unregister_code (KC_SCLN);
102 }
103}
104
383e508b
DG
105//All tap dance functions would go here. Only showing this one.
106qk_tap_dance_action_t tap_dance_actions[] = {
107 [CT_CLN] = ACTION_TAP_DANCE_FN_ADVANCED (NULL, dance_cln_finished, dance_cln_reset)
108};
109```
7b0356d1 110### Example 2: Send "Safety Dance!" After 100 Taps
383e508b 111```c
995c3141
JH
112void dance_egg (qk_tap_dance_state_t *state, void *user_data) {
113 if (state->count >= 100) {
114 SEND_STRING ("Safety dance!");
115 reset_tap_dance (state);
116 }
117}
118
383e508b
DG
119qk_tap_dance_action_t tap_dance_actions[] = {
120 [CT_EGG] = ACTION_TAP_DANCE_FN (dance_egg)
121};
122```
123
7b0356d1 124### Example 3: Turn LED Lights On Then Off, One at a Time
383e508b
DG
125
126```c
995c3141
JH
127// on each tap, light up one led, from right to left
128// on the forth tap, turn them off from right to left
129void dance_flsh_each(qk_tap_dance_state_t *state, void *user_data) {
130 switch (state->count) {
131 case 1:
132 ergodox_right_led_3_on();
133 break;
134 case 2:
135 ergodox_right_led_2_on();
136 break;
137 case 3:
138 ergodox_right_led_1_on();
139 break;
140 case 4:
141 ergodox_right_led_3_off();
142 _delay_ms(50);
143 ergodox_right_led_2_off();
144 _delay_ms(50);
145 ergodox_right_led_1_off();
146 }
147}
148
149// on the fourth tap, set the keyboard on flash state
150void dance_flsh_finished(qk_tap_dance_state_t *state, void *user_data) {
151 if (state->count >= 4) {
152 reset_keyboard();
153 reset_tap_dance(state);
154 }
155}
156
af37bb2f 157// if the flash state didn't happen, then turn off LEDs, left to right
995c3141
JH
158void dance_flsh_reset(qk_tap_dance_state_t *state, void *user_data) {
159 ergodox_right_led_1_off();
160 _delay_ms(50);
161 ergodox_right_led_2_off();
162 _delay_ms(50);
163 ergodox_right_led_3_off();
164}
165
383e508b 166//All tap dances now put together. Example 3 is "CT_FLASH"
995c3141
JH
167qk_tap_dance_action_t tap_dance_actions[] = {
168 [CT_SE] = ACTION_TAP_DANCE_DOUBLE (KC_SPC, KC_ENT)
169 ,[CT_CLN] = ACTION_TAP_DANCE_FN_ADVANCED (NULL, dance_cln_finished, dance_cln_reset)
170 ,[CT_EGG] = ACTION_TAP_DANCE_FN (dance_egg)
171 ,[CT_FLSH] = ACTION_TAP_DANCE_FN_ADVANCED (dance_flsh_each, dance_flsh_finished, dance_flsh_reset)
172};
173```
383e508b
DG
174
175### Example 4: 'Quad Function Tap-Dance'
176
725aa5b8 177By [DanielGGordon](https://github.com/danielggordon)
383e508b
DG
178
179Allow one key to have 4 (or more) functions, depending on number of presses, and if the key is held or tapped.
180Below is a specific example:
181* Tap = Send `x`
182* Hold = Send `Control`
183* Double Tap = Send `Escape`
184* Double Tap and Hold = Send `Alt`
185
e6be4484
DG
186## Setup
187
641bbeb4 188You will need a few things that can be used for 'Quad Function Tap-Dance'.
e6be4484 189
641bbeb4 190You'll need to add these to the top of your `keymap.c` file, before your keymap.
e6be4484 191
383e508b 192```c
e6be4484
DG
193typedef struct {
194 bool is_press_action;
195 int state;
bb86d8a0 196} tap;
e6be4484 197
383e508b
DG
198enum {
199 SINGLE_TAP = 1,
200 SINGLE_HOLD = 2,
201 DOUBLE_TAP = 3,
bb53635f 202 DOUBLE_HOLD = 4,
e6be4484
DG
203 DOUBLE_SINGLE_TAP = 5, //send two single taps
204 TRIPLE_TAP = 6,
205 TRIPLE_HOLD = 7
383e508b
DG
206};
207
e6be4484
DG
208//Tap dance enums
209enum {
bb86d8a0
EO
210 X_CTL = 0,
211 SOME_OTHER_DANCE
212};
e6be4484
DG
213
214int cur_dance (qk_tap_dance_state_t *state);
215
216//for the x tap dance. Put it here so it can be used in any keymap
217void x_finished (qk_tap_dance_state_t *state, void *user_data);
218void x_reset (qk_tap_dance_state_t *state, void *user_data);
e6be4484 219
641bbeb4 220```
383e508b 221
641bbeb4 222Now, at the bottom of your `keymap.c` file, you'll need to add the following:
e6be4484
DG
223
224```c
e6be4484
DG
225/* Return an integer that corresponds to what kind of tap dance should be executed.
226 *
227 * How to figure out tap dance state: interrupted and pressed.
228 *
229 * Interrupted: If the state of a dance dance is "interrupted", that means that another key has been hit
230 * under the tapping term. This is typically indicitive that you are trying to "tap" the key.
231 *
232 * Pressed: Whether or not the key is still being pressed. If this value is true, that means the tapping term
233 * has ended, but the key is still being pressed down. This generally means the key is being "held".
234 *
235 * One thing that is currenlty not possible with qmk software in regards to tap dance is to mimic the "permissive hold"
236 * feature. In general, advanced tap dances do not work well if they are used with commonly typed letters.
237 * For example "A". Tap dances are best used on non-letter keys that are not hit while typing letters.
238 *
239 * Good places to put an advanced tap dance:
240 * z,q,x,j,k,v,b, any function key, home/end, comma, semi-colon
241 *
242 * Criteria for "good placement" of a tap dance key:
243 * Not a key that is hit frequently in a sentence
244 * Not a key that is used frequently to double tap, for example 'tab' is often double tapped in a terminal, or
245 * in a web form. So 'tab' would be a poor choice for a tap dance.
246 * Letters used in common words as a double. For example 'p' in 'pepper'. If a tap dance function existed on the
247 * letter 'p', the word 'pepper' would be quite frustating to type.
248 *
249 * For the third point, there does exist the 'DOUBLE_SINGLE_TAP', however this is not fully tested
250 *
251 */
383e508b 252int cur_dance (qk_tap_dance_state_t *state) {
725aa5b8 253 if (state->count == 1) {
e6be4484
DG
254 if (state->interrupted || !state->pressed) return SINGLE_TAP;
255 //key has not been interrupted, but they key is still held. Means you want to send a 'HOLD'.
725aa5b8
DG
256 else return SINGLE_HOLD;
257 }
4c1164c4 258 else if (state->count == 2) {
e6be4484
DG
259 /*
260 * DOUBLE_SINGLE_TAP is to distinguish between typing "pepper", and actually wanting a double tap
261 * action when hitting 'pp'. Suggested use case for this return value is when you want to send two
262 * keystrokes of the key, and not the 'double tap' action/macro.
263 */
725aa5b8
DG
264 if (state->interrupted) return DOUBLE_SINGLE_TAP;
265 else if (state->pressed) return DOUBLE_HOLD;
266 else return DOUBLE_TAP;
bb53635f 267 }
e6be4484
DG
268 //Assumes no one is trying to type the same letter three times (at least not quickly).
269 //If your tap dance key is 'KC_W', and you want to type "www." quickly - then you will need to add
270 //an exception here to return a 'TRIPLE_SINGLE_TAP', and define that enum just like 'DOUBLE_SINGLE_TAP'
271 if (state->count == 3) {
272 if (state->interrupted || !state->pressed) return TRIPLE_TAP;
273 else return TRIPLE_HOLD;
274 }
275 else return 8; //magic number. At some point this method will expand to work for more presses
383e508b 276}
725aa5b8 277
383e508b 278//instanalize an instance of 'tap' for the 'x' tap dance.
bb53635f 279static tap xtap_state = {
383e508b
DG
280 .is_press_action = true,
281 .state = 0
282};
283
284void x_finished (qk_tap_dance_state_t *state, void *user_data) {
285 xtap_state.state = cur_dance(state);
286 switch (xtap_state.state) {
287 case SINGLE_TAP: register_code(KC_X); break;
288 case SINGLE_HOLD: register_code(KC_LCTRL); break;
289 case DOUBLE_TAP: register_code(KC_ESC); break;
725aa5b8
DG
290 case DOUBLE_HOLD: register_code(KC_LALT); break;
291 case DOUBLE_SINGLE_TAP: register_code(KC_X); unregister_code(KC_X); register_code(KC_X);
292 //Last case is for fast typing. Assuming your key is `f`:
293 //For example, when typing the word `buffer`, and you want to make sure that you send `ff` and not `Esc`.
294 //In order to type `ff` when typing fast, the next character will have to be hit within the `TAPPING_TERM`, which by default is 200ms.
383e508b
DG
295 }
296}
297
298void x_reset (qk_tap_dance_state_t *state, void *user_data) {
299 switch (xtap_state.state) {
300 case SINGLE_TAP: unregister_code(KC_X); break;
301 case SINGLE_HOLD: unregister_code(KC_LCTRL); break;
302 case DOUBLE_TAP: unregister_code(KC_ESC); break;
303 case DOUBLE_HOLD: unregister_code(KC_LALT);
725aa5b8 304 case DOUBLE_SINGLE_TAP: unregister_code(KC_X);
383e508b
DG
305 }
306 xtap_state.state = 0;
307}
e6be4484
DG
308
309qk_tap_dance_action_t tap_dance_actions[] = {
310 [X_CTL] = ACTION_TAP_DANCE_FN_ADVANCED(NULL,x_finished, x_reset)
311};
383e508b 312```
e6be4484 313
641bbeb4
DJ
314And then simply use `TD(X_CTL)` anywhere in your keymap.
315
316If you want to implement this in your userspace, then you may want to check out how [DanielGGordon](https://github.com/qmk/qmk_firmware/tree/master/users/gordon) has implemented this in their userspace.
6d4f6f3f
DP
317
318### Example 5: Using tap dance for advanced mod-tap and layer-tap keys
319
320Tap dance can be used to emulate `MT()` and `LT()` behavior when the tapped code is not a basic keycode. This is useful to send tapped keycodes that normally require `Shift`, such as parentheses or curly braces—or other modified keycodes, such as `Control + X`.
321
322Below your layers and custom keycodes, add the following:
323
324```c
325// tapdance keycodes
326enum td_keycodes {
327 ALT_LP // Our example key: `LALT` when held, `(` when tapped. Add additional keycodes for each tapdance.
328};
329
330// define a type containing as many tapdance states as you need
331typedef enum {
332 SINGLE_TAP,
333 SINGLE_HOLD,
334 DOUBLE_SINGLE_TAP
335} td_state_t;
336
337// create a global instance of the tapdance state type
338static td_state_t td_state;
339
340// declare your tapdance functions:
341
342// function to determine the current tapdance state
343int cur_dance (qk_tap_dance_state_t *state);
344
345// `finished` and `reset` functions for each tapdance keycode
346void altlp_finished (qk_tap_dance_state_t *state, void *user_data);
347void altlp_reset (qk_tap_dance_state_t *state, void *user_data);
348```
349
350Below your `LAYOUT`, define each of the tapdance functions:
351
352```c
353// determine the tapdance state to return
354int cur_dance (qk_tap_dance_state_t *state) {
355 if (state->count == 1) {
356 if (state->interrupted || !state->pressed) { return SINGLE_TAP; }
357 else { return SINGLE_HOLD; }
358 }
359 if (state->count == 2) { return DOUBLE_SINGLE_TAP; }
360 else { return 3; } // any number higher than the maximum state value you return above
361}
362
363// handle the possible states for each tapdance keycode you define:
364
365void altlp_finished (qk_tap_dance_state_t *state, void *user_data) {
366 td_state = cur_dance(state);
367 switch (td_state) {
368 case SINGLE_TAP:
369 register_code16(KC_LPRN);
370 break;
371 case SINGLE_HOLD:
372 register_mods(MOD_BIT(KC_LALT)); // for a layer-tap key, use `layer_on(_MY_LAYER)` here
373 break;
374 case DOUBLE_SINGLE_TAP: // allow nesting of 2 parens `((` within tapping term
375 tap_code16(KC_LPRN);
376 register_code16(KC_LPRN);
377 }
378}
379
380void altlp_reset (qk_tap_dance_state_t *state, void *user_data) {
381 switch (td_state) {
382 case SINGLE_TAP:
383 unregister_code16(KC_LPRN);
384 break;
385 case SINGLE_HOLD:
386 unregister_mods(MOD_BIT(KC_LALT)); // for a layer-tap key, use `layer_off(_MY_LAYER)` here
387 break;
388 case DOUBLE_SINGLE_TAP:
389 unregister_code16(KC_LPRN);
390 }
391}
392
393// define `ACTION_TAP_DANCE_FN_ADVANCED()` for each tapdance keycode, passing in `finished` and `reset` functions
394qk_tap_dance_action_t tap_dance_actions[] = {
395 [ALT_LP] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, altlp_finished, altlp_reset)
396};
397```
398
399Wrap each tapdance keycode in `TD()` when including it in your keymap, e.g. `TD(ALT_LP)`.