X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=docs%2Ffeature_tap_dance.md;h=b5e5218b093d01c7ad8c99bf79c76efbebf2d345;hb=3538955778c253e68779605cc67c27e15d195729;hp=93d190883147dd261f80844be8bd5ad9f07655ce;hpb=bb86d8a00c117759cd5b71b20d5974d41ffb455c;p=qmk_firmware.git diff --git a/docs/feature_tap_dance.md b/docs/feature_tap_dance.md index 93d190883..b5e5218b0 100644 --- a/docs/feature_tap_dance.md +++ b/docs/feature_tap_dance.md @@ -26,6 +26,8 @@ This array specifies what actions shall be taken when a tap-dance key is in acti The 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. +!> Keep in mind that only [basic keycodes](keycodes_basic.md) are supported here. Custom keycodes are not supported. + And that's the bulk of it! And now, on to the explanation of how it works! @@ -183,29 +185,11 @@ Below is a specific example: ## Setup -You will need a few things that can be used for 'Quad Function Tap-Dance'. The suggested setup is to create a user directory for yourself. This directory will contain rules.mk `.c` and `.h`. This directory should be called ``, and located in the top level `users` directory. There should already be a few examples to look at there. +You will need a few things that can be used for 'Quad Function Tap-Dance'. -### In `/qmk_firmware/users//rules.mk` +You'll need to add these to the top of your `keymap.c` file, before your keymap. -Put the following: ```c -TAP_DANCE_ENABLE = yes -SRC += your_name.c -``` - -Pretty simple. It is a nice way to keep some rules common on all your keymaps. - - -### In `/qmk_firmware/users//.h` - -You will need a few things in this file: - -```c -#pragma once - -#include "quantum.h" -#include "process_keycode/process_tap_dance.h" - typedef struct { bool is_press_action; int state; @@ -232,18 +216,12 @@ int cur_dance (qk_tap_dance_state_t *state); //for the x tap dance. Put it here so it can be used in any keymap void x_finished (qk_tap_dance_state_t *state, void *user_data); void x_reset (qk_tap_dance_state_t *state, void *user_data); -``` -### In `/qmk_firmware/users//.c` +``` -And then in your user's `.c` file you implement the functions above: +Now, at the bottom of your `keymap.c` file, you'll need to add the following: ```c -#include ".h" -#include "quantum.h" -#include "action.h" -#include "process_keycode/process_tap_dance.h" - /* Return an integer that corresponds to what kind of tap dance should be executed. * * How to figure out tap dance state: interrupted and pressed. @@ -333,4 +311,89 @@ qk_tap_dance_action_t tap_dance_actions[] = { }; ``` -And then simply use `TD(X_CTL)` anywhere in your keymap after including `.h`. +And then simply use `TD(X_CTL)` anywhere in your keymap. + +If 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. + +### Example 5: Using tap dance for advanced mod-tap and layer-tap keys + +Tap 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`. + +Below your layers and custom keycodes, add the following: + +```c +// tapdance keycodes +enum td_keycodes { + ALT_LP // Our example key: `LALT` when held, `(` when tapped. Add additional keycodes for each tapdance. +}; + +// define a type containing as many tapdance states as you need +typedef enum { + SINGLE_TAP, + SINGLE_HOLD, + DOUBLE_SINGLE_TAP +} td_state_t; + +// create a global instance of the tapdance state type +static td_state_t td_state; + +// declare your tapdance functions: + +// function to determine the current tapdance state +int cur_dance (qk_tap_dance_state_t *state); + +// `finished` and `reset` functions for each tapdance keycode +void altlp_finished (qk_tap_dance_state_t *state, void *user_data); +void altlp_reset (qk_tap_dance_state_t *state, void *user_data); +``` + +Below your `LAYOUT`, define each of the tapdance functions: + +```c +// determine the tapdance state to return +int cur_dance (qk_tap_dance_state_t *state) { + if (state->count == 1) { + if (state->interrupted || !state->pressed) { return SINGLE_TAP; } + else { return SINGLE_HOLD; } + } + if (state->count == 2) { return DOUBLE_SINGLE_TAP; } + else { return 3; } // any number higher than the maximum state value you return above +} + +// handle the possible states for each tapdance keycode you define: + +void altlp_finished (qk_tap_dance_state_t *state, void *user_data) { + td_state = cur_dance(state); + switch (td_state) { + case SINGLE_TAP: + register_code16(KC_LPRN); + break; + case SINGLE_HOLD: + register_mods(MOD_BIT(KC_LALT)); // for a layer-tap key, use `layer_on(_MY_LAYER)` here + break; + case DOUBLE_SINGLE_TAP: // allow nesting of 2 parens `((` within tapping term + tap_code16(KC_LPRN); + register_code16(KC_LPRN); + } +} + +void altlp_reset (qk_tap_dance_state_t *state, void *user_data) { + switch (td_state) { + case SINGLE_TAP: + unregister_code16(KC_LPRN); + break; + case SINGLE_HOLD: + unregister_mods(MOD_BIT(KC_LALT)); // for a layer-tap key, use `layer_off(_MY_LAYER)` here + break; + case DOUBLE_SINGLE_TAP: + unregister_code16(KC_LPRN); + } +} + +// define `ACTION_TAP_DANCE_FN_ADVANCED()` for each tapdance keycode, passing in `finished` and `reset` functions +qk_tap_dance_action_t tap_dance_actions[] = { + [ALT_LP] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, altlp_finished, altlp_reset) +}; +``` + +Wrap each tapdance keycode in `TD()` when including it in your keymap, e.g. `TD(ALT_LP)`.