aboutsummaryrefslogtreecommitdiff
path: root/docs/feature_tap_dance.md
diff options
context:
space:
mode:
authorRyan <fauxpark@gmail.com>2021-03-25 06:46:22 +1100
committerGitHub <noreply@github.com>2021-03-24 19:46:22 +0000
commit653ecf91c23e1e1f4827648007905e6d5ac56196 (patch)
tree3e1ffab16923b504d2b547735cf6caa2e7218c2d /docs/feature_tap_dance.md
parentb7870ae78cadf9a77316e0c004e8db0cbbba581e (diff)
downloadqmk_firmware-653ecf91c23e1e1f4827648007905e6d5ac56196.tar.gz
qmk_firmware-653ecf91c23e1e1f4827648007905e6d5ac56196.zip
More Tap Dance docs improvements (#12358)
Diffstat (limited to 'docs/feature_tap_dance.md')
-rw-r--r--docs/feature_tap_dance.md162
1 files changed, 84 insertions, 78 deletions
diff --git a/docs/feature_tap_dance.md b/docs/feature_tap_dance.md
index d2da39ad2..7396e791c 100644
--- a/docs/feature_tap_dance.md
+++ b/docs/feature_tap_dance.md
@@ -76,7 +76,7 @@ qk_tap_dance_action_t tap_dance_actions[] = {
76 [TD_ESC_CAPS] = ACTION_TAP_DANCE_DOUBLE(KC_ESC, KC_CAPS), 76 [TD_ESC_CAPS] = ACTION_TAP_DANCE_DOUBLE(KC_ESC, KC_CAPS),
77}; 77};
78 78
79// Add tap dance item in place of a key code 79// Add tap dance item to your keymap in place of a keycode
80const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { 80const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
81 // ... 81 // ...
82 TD(TD_ESC_CAPS) 82 TD(TD_ESC_CAPS)
@@ -206,20 +206,22 @@ You will need a few things that can be used for 'Quad Function Tap-Dance'.
206You'll need to add these to the top of your `keymap.c` file, before your keymap. 206You'll need to add these to the top of your `keymap.c` file, before your keymap.
207 207
208```c 208```c
209typedef enum {
210 TD_NONE,
211 TD_UNKNOWN,
212 TD_SINGLE_TAP,
213 TD_SINGLE_HOLD,
214 TD_DOUBLE_TAP,
215 TD_DOUBLE_HOLD,
216 TD_DOUBLE_SINGLE_TAP, // Send two single taps
217 TD_TRIPLE_TAP,
218 TD_TRIPLE_HOLD
219} td_state_t;
220
209typedef struct { 221typedef struct {
210 bool is_press_action; 222 bool is_press_action;
211 uint8_t state; 223 td_state_t state;
212} tap; 224} td_tap_t;
213
214enum {
215 SINGLE_TAP = 1,
216 SINGLE_HOLD,
217 DOUBLE_TAP,
218 DOUBLE_HOLD,
219 DOUBLE_SINGLE_TAP, // Send two single taps
220 TRIPLE_TAP,
221 TRIPLE_HOLD
222};
223 225
224// Tap dance enums 226// Tap dance enums
225enum { 227enum {
@@ -227,7 +229,7 @@ enum {
227 SOME_OTHER_DANCE 229 SOME_OTHER_DANCE
228}; 230};
229 231
230uint8_t cur_dance(qk_tap_dance_state_t *state); 232td_state_t cur_dance(qk_tap_dance_state_t *state);
231 233
232// For the x tap dance. Put it here so it can be used in any keymap 234// For the x tap dance. Put it here so it can be used in any keymap
233void x_finished(qk_tap_dance_state_t *state, void *user_data); 235void x_finished(qk_tap_dance_state_t *state, void *user_data);
@@ -261,61 +263,61 @@ Now, at the bottom of your `keymap.c` file, you'll need to add the following:
261 * Letters used in common words as a double. For example 'p' in 'pepper'. If a tap dance function existed on the 263 * Letters used in common words as a double. For example 'p' in 'pepper'. If a tap dance function existed on the
262 * letter 'p', the word 'pepper' would be quite frustating to type. 264 * letter 'p', the word 'pepper' would be quite frustating to type.
263 * 265 *
264 * For the third point, there does exist the 'DOUBLE_SINGLE_TAP', however this is not fully tested 266 * For the third point, there does exist the 'TD_DOUBLE_SINGLE_TAP', however this is not fully tested
265 * 267 *
266 */ 268 */
267uint8_t cur_dance(qk_tap_dance_state_t *state) { 269td_state_t cur_dance(qk_tap_dance_state_t *state) {
268 if (state->count == 1) { 270 if (state->count == 1) {
269 if (state->interrupted || !state->pressed) return SINGLE_TAP; 271 if (state->interrupted || !state->pressed) return TD_SINGLE_TAP;
270 // Key has not been interrupted, but the key is still held. Means you want to send a 'HOLD'. 272 // Key has not been interrupted, but the key is still held. Means you want to send a 'HOLD'.
271 else return SINGLE_HOLD; 273 else return TD_SINGLE_HOLD;
272 } else if (state->count == 2) { 274 } else if (state->count == 2) {
273 // DOUBLE_SINGLE_TAP is to distinguish between typing "pepper", and actually wanting a double tap 275 // TD_DOUBLE_SINGLE_TAP is to distinguish between typing "pepper", and actually wanting a double tap
274 // action when hitting 'pp'. Suggested use case for this return value is when you want to send two 276 // action when hitting 'pp'. Suggested use case for this return value is when you want to send two
275 // keystrokes of the key, and not the 'double tap' action/macro. 277 // keystrokes of the key, and not the 'double tap' action/macro.
276 if (state->interrupted) return DOUBLE_SINGLE_TAP; 278 if (state->interrupted) return TD_DOUBLE_SINGLE_TAP;
277 else if (state->pressed) return DOUBLE_HOLD; 279 else if (state->pressed) return TD_DOUBLE_HOLD;
278 else return DOUBLE_TAP; 280 else return TD_DOUBLE_TAP;
279 } 281 }
280 282
281 // Assumes no one is trying to type the same letter three times (at least not quickly). 283 // Assumes no one is trying to type the same letter three times (at least not quickly).
282 // If your tap dance key is 'KC_W', and you want to type "www." quickly - then you will need to add 284 // If your tap dance key is 'KC_W', and you want to type "www." quickly - then you will need to add
283 // an exception here to return a 'TRIPLE_SINGLE_TAP', and define that enum just like 'DOUBLE_SINGLE_TAP' 285 // an exception here to return a 'TD_TRIPLE_SINGLE_TAP', and define that enum just like 'TD_DOUBLE_SINGLE_TAP'
284 if (state->count == 3) { 286 if (state->count == 3) {
285 if (state->interrupted || !state->pressed) return TRIPLE_TAP; 287 if (state->interrupted || !state->pressed) return TD_TRIPLE_TAP;
286 else return TRIPLE_HOLD; 288 else return TD_TRIPLE_HOLD;
287 } else return 8; // Magic number. At some point this method will expand to work for more presses 289 } else return TD_UNKNOWN;
288} 290}
289 291
290// Create an instance of 'tap' for the 'x' tap dance. 292// Create an instance of 'td_tap_t' for the 'x' tap dance.
291static tap xtap_state = { 293static td_tap_t xtap_state = {
292 .is_press_action = true, 294 .is_press_action = true,
293 .state = 0 295 .state = TD_NONE
294}; 296};
295 297
296void x_finished(qk_tap_dance_state_t *state, void *user_data) { 298void x_finished(qk_tap_dance_state_t *state, void *user_data) {
297 xtap_state.state = cur_dance(state); 299 xtap_state.state = cur_dance(state);
298 switch (xtap_state.state) { 300 switch (xtap_state.state) {
299 case SINGLE_TAP: register_code(KC_X); break; 301 case TD_SINGLE_TAP: register_code(KC_X); break;
300 case SINGLE_HOLD: register_code(KC_LCTRL); break; 302 case TD_SINGLE_HOLD: register_code(KC_LCTRL); break;
301 case DOUBLE_TAP: register_code(KC_ESC); break; 303 case TD_DOUBLE_TAP: register_code(KC_ESC); break;
302 case DOUBLE_HOLD: register_code(KC_LALT); break; 304 case TD_DOUBLE_HOLD: register_code(KC_LALT); break;
303 // Last case is for fast typing. Assuming your key is `f`: 305 // Last case is for fast typing. Assuming your key is `f`:
304 // For example, when typing the word `buffer`, and you want to make sure that you send `ff` and not `Esc`. 306 // For example, when typing the word `buffer`, and you want to make sure that you send `ff` and not `Esc`.
305 // 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. 307 // 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.
306 case DOUBLE_SINGLE_TAP: tap_code(KC_X); register_code(KC_X); 308 case TD_DOUBLE_SINGLE_TAP: tap_code(KC_X); register_code(KC_X);
307 } 309 }
308} 310}
309 311
310void x_reset(qk_tap_dance_state_t *state, void *user_data) { 312void x_reset(qk_tap_dance_state_t *state, void *user_data) {
311 switch (xtap_state.state) { 313 switch (xtap_state.state) {
312 case SINGLE_TAP: unregister_code(KC_X); break; 314 case TD_SINGLE_TAP: unregister_code(KC_X); break;
313 case SINGLE_HOLD: unregister_code(KC_LCTRL); break; 315 case TD_SINGLE_HOLD: unregister_code(KC_LCTRL); break;
314 case DOUBLE_TAP: unregister_code(KC_ESC); break; 316 case TD_DOUBLE_TAP: unregister_code(KC_ESC); break;
315 case DOUBLE_HOLD: unregister_code(KC_LALT); 317 case TD_DOUBLE_HOLD: unregister_code(KC_LALT);
316 case DOUBLE_SINGLE_TAP: unregister_code(KC_X); 318 case TD_DOUBLE_SINGLE_TAP: unregister_code(KC_X);
317 } 319 }
318 xtap_state.state = 0; 320 xtap_state.state = TD_NONE;
319} 321}
320 322
321qk_tap_dance_action_t tap_dance_actions[] = { 323qk_tap_dance_action_t tap_dance_actions[] = {
@@ -343,9 +345,11 @@ enum td_keycodes {
343 345
344// Define a type containing as many tapdance states as you need 346// Define a type containing as many tapdance states as you need
345typedef enum { 347typedef enum {
346 SINGLE_TAP, 348 TD_NONE,
347 SINGLE_HOLD, 349 TD_UNKNOWN,
348 DOUBLE_SINGLE_TAP 350 TD_SINGLE_TAP,
351 TD_SINGLE_HOLD,
352 TD_DOUBLE_SINGLE_TAP
349} td_state_t; 353} td_state_t;
350 354
351// Create a global instance of the tapdance state type 355// Create a global instance of the tapdance state type
@@ -354,7 +358,7 @@ static td_state_t td_state;
354// Declare your tapdance functions: 358// Declare your tapdance functions:
355 359
356// Function to determine the current tapdance state 360// Function to determine the current tapdance state
357uint8_t cur_dance(qk_tap_dance_state_t *state); 361td_state_t cur_dance(qk_tap_dance_state_t *state);
358 362
359// `finished` and `reset` functions for each tapdance keycode 363// `finished` and `reset` functions for each tapdance keycode
360void altlp_finished(qk_tap_dance_state_t *state, void *user_data); 364void altlp_finished(qk_tap_dance_state_t *state, void *user_data);
@@ -365,14 +369,14 @@ Below your `LAYOUT`, define each of the tapdance functions:
365 369
366```c 370```c
367// Determine the tapdance state to return 371// Determine the tapdance state to return
368uint8_t cur_dance(qk_tap_dance_state_t *state) { 372td_state_t cur_dance(qk_tap_dance_state_t *state) {
369 if (state->count == 1) { 373 if (state->count == 1) {
370 if (state->interrupted || !state->pressed) return SINGLE_TAP; 374 if (state->interrupted || !state->pressed) return TD_SINGLE_TAP;
371 else return SINGLE_HOLD; 375 else return TD_SINGLE_HOLD;
372 } 376 }
373 377
374 if (state->count == 2) return DOUBLE_SINGLE_TAP; 378 if (state->count == 2) return TD_DOUBLE_SINGLE_TAP;
375 else return 3; // Any number higher than the maximum state value you return above 379 else return TD_UNKNOWN; // Any number higher than the maximum state value you return above
376} 380}
377 381
378// Handle the possible states for each tapdance keycode you define: 382// Handle the possible states for each tapdance keycode you define:
@@ -380,13 +384,13 @@ uint8_t cur_dance(qk_tap_dance_state_t *state) {
380void altlp_finished(qk_tap_dance_state_t *state, void *user_data) { 384void altlp_finished(qk_tap_dance_state_t *state, void *user_data) {
381 td_state = cur_dance(state); 385 td_state = cur_dance(state);
382 switch (td_state) { 386 switch (td_state) {
383 case SINGLE_TAP: 387 case TD_SINGLE_TAP:
384 register_code16(KC_LPRN); 388 register_code16(KC_LPRN);
385 break; 389 break;
386 case SINGLE_HOLD: 390 case TD_SINGLE_HOLD:
387 register_mods(MOD_BIT(KC_LALT)); // For a layer-tap key, use `layer_on(_MY_LAYER)` here 391 register_mods(MOD_BIT(KC_LALT)); // For a layer-tap key, use `layer_on(_MY_LAYER)` here
388 break; 392 break;
389 case DOUBLE_SINGLE_TAP: // Allow nesting of 2 parens `((` within tapping term 393 case TD_DOUBLE_SINGLE_TAP: // Allow nesting of 2 parens `((` within tapping term
390 tap_code16(KC_LPRN); 394 tap_code16(KC_LPRN);
391 register_code16(KC_LPRN); 395 register_code16(KC_LPRN);
392 } 396 }
@@ -394,13 +398,13 @@ void altlp_finished(qk_tap_dance_state_t *state, void *user_data) {
394 398
395void altlp_reset(qk_tap_dance_state_t *state, void *user_data) { 399void altlp_reset(qk_tap_dance_state_t *state, void *user_data) {
396 switch (td_state) { 400 switch (td_state) {
397 case SINGLE_TAP: 401 case TD_SINGLE_TAP:
398 unregister_code16(KC_LPRN); 402 unregister_code16(KC_LPRN);
399 break; 403 break;
400 case SINGLE_HOLD: 404 case TD_SINGLE_HOLD:
401 unregister_mods(MOD_BIT(KC_LALT)); // For a layer-tap key, use `layer_off(_MY_LAYER)` here 405 unregister_mods(MOD_BIT(KC_LALT)); // For a layer-tap key, use `layer_off(_MY_LAYER)` here
402 break; 406 break;
403 case DOUBLE_SINGLE_TAP: 407 case TD_DOUBLE_SINGLE_TAP:
404 unregister_code16(KC_LPRN); 408 unregister_code16(KC_LPRN);
405 } 409 }
406} 410}
@@ -420,17 +424,19 @@ Tap Dance can be used to mimic MO(layer) and TG(layer) functionality. For this e
420The first step is to include the following code towards the beginning of your `keymap.c`: 424The first step is to include the following code towards the beginning of your `keymap.c`:
421 425
422```c 426```c
427// Define a type for as many tap dance states as you need
428typedef enum {
429 TD_NONE,
430 TD_UNKNOWN,
431 TD_SINGLE_TAP,
432 TD_SINGLE_HOLD,
433 TD_DOUBLE_TAP
434} td_state_t;
435
423typedef struct { 436typedef struct {
424 bool is_press_action; 437 bool is_press_action;
425 uint8_t state; 438 td_state_t state;
426} tap; 439} td_tap_t;
427
428// Define a type for as many tap dance states as you need
429enum {
430 SINGLE_TAP = 1,
431 SINGLE_HOLD,
432 DOUBLE_TAP
433};
434 440
435enum { 441enum {
436 QUOT_LAYR, // Our custom tap dance key; add any other tap dance keys to this enum 442 QUOT_LAYR, // Our custom tap dance key; add any other tap dance keys to this enum
@@ -439,7 +445,7 @@ enum {
439// Declare the functions to be used with your tap dance key(s) 445// Declare the functions to be used with your tap dance key(s)
440 446
441// Function associated with all tap dances 447// Function associated with all tap dances
442uint8_t cur_dance(qk_tap_dance_state_t *state); 448td_state_t cur_dance(qk_tap_dance_state_t *state);
443 449
444// Functions associated with individual tap dances 450// Functions associated with individual tap dances
445void ql_finished(qk_tap_dance_state_t *state, void *user_data); 451void ql_finished(qk_tap_dance_state_t *state, void *user_data);
@@ -450,31 +456,31 @@ Towards the bottom of your `keymap.c`, include the following code:
450 456
451```c 457```c
452// Determine the current tap dance state 458// Determine the current tap dance state
453uint8_t cur_dance(qk_tap_dance_state_t *state) { 459td_state_t cur_dance(qk_tap_dance_state_t *state) {
454 if (state->count == 1) { 460 if (state->count == 1) {
455 if (!state->pressed) return SINGLE_TAP; 461 if (!state->pressed) return TD_SINGLE_TAP;
456 else return SINGLE_HOLD; 462 else return TD_SINGLE_HOLD;
457 } else if (state->count == 2) return DOUBLE_TAP; 463 } else if (state->count == 2) return TD_DOUBLE_TAP;
458 else return 8; 464 else return TD_UNKNOWN;
459} 465}
460 466
461// Initialize tap structure associated with example tap dance key 467// Initialize tap structure associated with example tap dance key
462static tap ql_tap_state = { 468static td_tap_t ql_tap_state = {
463 .is_press_action = true, 469 .is_press_action = true,
464 .state = 0 470 .state = TD_NONE
465}; 471};
466 472
467// Functions that control what our tap dance key does 473// Functions that control what our tap dance key does
468void ql_finished(qk_tap_dance_state_t *state, void *user_data) { 474void ql_finished(qk_tap_dance_state_t *state, void *user_data) {
469 ql_tap_state.state = cur_dance(state); 475 ql_tap_state.state = cur_dance(state);
470 switch (ql_tap_state.state) { 476 switch (ql_tap_state.state) {
471 case SINGLE_TAP: 477 case TD_SINGLE_TAP:
472 tap_code(KC_QUOT); 478 tap_code(KC_QUOT);
473 break; 479 break;
474 case SINGLE_HOLD: 480 case TD_SINGLE_HOLD:
475 layer_on(_MY_LAYER); 481 layer_on(_MY_LAYER);
476 break; 482 break;
477 case DOUBLE_TAP: 483 case TD_DOUBLE_TAP:
478 // Check to see if the layer is already set 484 // Check to see if the layer is already set
479 if (layer_state_is(_MY_LAYER)) { 485 if (layer_state_is(_MY_LAYER)) {
480 // If already set, then switch it off 486 // If already set, then switch it off
@@ -489,10 +495,10 @@ void ql_finished(qk_tap_dance_state_t *state, void *user_data) {
489 495
490void ql_reset(qk_tap_dance_state_t *state, void *user_data) { 496void ql_reset(qk_tap_dance_state_t *state, void *user_data) {
491 // If the key was held down and now is released then switch off the layer 497 // If the key was held down and now is released then switch off the layer
492 if (ql_tap_state.state == SINGLE_HOLD) { 498 if (ql_tap_state.state == TD_SINGLE_HOLD) {
493 layer_off(_MY_LAYER); 499 layer_off(_MY_LAYER);
494 } 500 }
495 ql_tap_state.state = 0; 501 ql_tap_state.state = TD_NONE;
496} 502}
497 503
498// Associate our tap dance key with its functionality 504// Associate our tap dance key with its functionality
@@ -505,7 +511,7 @@ The above code is similar to that used in previous examples. The one point to no
505 511
506The use of `cur_dance()` and `ql_tap_state` mirrors the above examples. 512The use of `cur_dance()` and `ql_tap_state` mirrors the above examples.
507 513
508The `case:SINGLE_TAP` in `ql_finished` is similar to the above examples. The `SINGLE_HOLD` case works in conjunction with `ql_reset()` to switch to `_MY_LAYER` while the tap dance key is held, and to switch away from `_MY_LAYER` when the key is released. This mirrors the use of `MO(_MY_LAYER)`. The `DOUBLE_TAP` case works by checking whether `_MY_LAYER` is the active layer, and toggling it on or off accordingly. This mirrors the use of `TG(_MY_LAYER)`. 514The `case: TD_SINGLE_TAP` in `ql_finished` is similar to the above examples. The `TD_SINGLE_HOLD` case works in conjunction with `ql_reset()` to switch to `_MY_LAYER` while the tap dance key is held, and to switch away from `_MY_LAYER` when the key is released. This mirrors the use of `MO(_MY_LAYER)`. The `TD_DOUBLE_TAP` case works by checking whether `_MY_LAYER` is the active layer, and toggling it on or off accordingly. This mirrors the use of `TG(_MY_LAYER)`.
509 515
510`tap_dance_actions[]` works similar to the above examples. Note that I used `ACTION_TAP_DANCE_FN_ADVANCED_TIME()` instead of `ACTION_TAP_DANCE_FN_ADVANCED()`. This is because I like my `TAPPING_TERM` to be short (\~175ms) for my non-tap-dance keys but find that this is too quick for me to reliably complete tap dance actions - thus the increased time of 275ms here. 516`tap_dance_actions[]` works similar to the above examples. Note that I used `ACTION_TAP_DANCE_FN_ADVANCED_TIME()` instead of `ACTION_TAP_DANCE_FN_ADVANCED()`. This is because I like my `TAPPING_TERM` to be short (\~175ms) for my non-tap-dance keys but find that this is too quick for me to reliably complete tap dance actions - thus the increased time of 275ms here.
511 517