diff options
| -rw-r--r-- | docs/feature_tap_dance.md | 162 | 
1 files changed, 84 insertions, 78 deletions
diff --git a/docs/feature_tap_dance.md b/docs/feature_tap_dance.md index d2da39ad2b..7396e791c3 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[] = {      [TD_ESC_CAPS] = ACTION_TAP_DANCE_DOUBLE(KC_ESC, KC_CAPS),  }; -// Add tap dance item in place of a key code +// Add tap dance item to your keymap in place of a keycode  const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {      // ...      TD(TD_ESC_CAPS) @@ -206,20 +206,22 @@ You will need a few things that can be used for 'Quad Function Tap-Dance'.  You'll need to add these to the top of your `keymap.c` file, before your keymap.   ```c +typedef enum { +    TD_NONE, +    TD_UNKNOWN, +    TD_SINGLE_TAP, +    TD_SINGLE_HOLD, +    TD_DOUBLE_TAP, +    TD_DOUBLE_HOLD, +    TD_DOUBLE_SINGLE_TAP, // Send two single taps +    TD_TRIPLE_TAP, +    TD_TRIPLE_HOLD +} td_state_t; +  typedef struct {      bool is_press_action; -    uint8_t state; -} tap; - -enum { -    SINGLE_TAP = 1, -    SINGLE_HOLD, -    DOUBLE_TAP, -    DOUBLE_HOLD, -    DOUBLE_SINGLE_TAP, // Send two single taps -    TRIPLE_TAP, -    TRIPLE_HOLD -}; +    td_state_t state; +} td_tap_t;  // Tap dance enums  enum { @@ -227,7 +229,7 @@ enum {      SOME_OTHER_DANCE  }; -uint8_t cur_dance(qk_tap_dance_state_t *state); +td_state_t 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); @@ -261,61 +263,61 @@ Now, at the bottom of your `keymap.c` file, you'll need to add the following:   *  Letters used in common words as a double. For example 'p' in 'pepper'. If a tap dance function existed on the   *    letter 'p', the word 'pepper' would be quite frustating to type.   * - * For the third point, there does exist the 'DOUBLE_SINGLE_TAP', however this is not fully tested + * For the third point, there does exist the 'TD_DOUBLE_SINGLE_TAP', however this is not fully tested   *   */ -uint8_t cur_dance(qk_tap_dance_state_t *state) { +td_state_t cur_dance(qk_tap_dance_state_t *state) {      if (state->count == 1) { -        if (state->interrupted || !state->pressed) return SINGLE_TAP; +        if (state->interrupted || !state->pressed) return TD_SINGLE_TAP;          // Key has not been interrupted, but the key is still held. Means you want to send a 'HOLD'. -        else return SINGLE_HOLD; +        else return TD_SINGLE_HOLD;      } else if (state->count == 2) { -        // DOUBLE_SINGLE_TAP is to distinguish between typing "pepper", and actually wanting a double tap +        // TD_DOUBLE_SINGLE_TAP is to distinguish between typing "pepper", and actually wanting a double tap          // action when hitting 'pp'. Suggested use case for this return value is when you want to send two          // keystrokes of the key, and not the 'double tap' action/macro. -        if (state->interrupted) return DOUBLE_SINGLE_TAP; -        else if (state->pressed) return DOUBLE_HOLD; -        else return DOUBLE_TAP; +        if (state->interrupted) return TD_DOUBLE_SINGLE_TAP; +        else if (state->pressed) return TD_DOUBLE_HOLD; +        else return TD_DOUBLE_TAP;      }      // Assumes no one is trying to type the same letter three times (at least not quickly).      // If your tap dance key is 'KC_W', and you want to type "www." quickly - then you will need to add -    // an exception here to return a 'TRIPLE_SINGLE_TAP', and define that enum just like 'DOUBLE_SINGLE_TAP' +    // an exception here to return a 'TD_TRIPLE_SINGLE_TAP', and define that enum just like 'TD_DOUBLE_SINGLE_TAP'      if (state->count == 3) { -        if (state->interrupted || !state->pressed) return TRIPLE_TAP; -        else return TRIPLE_HOLD; -    } else return 8; // Magic number. At some point this method will expand to work for more presses +        if (state->interrupted || !state->pressed) return TD_TRIPLE_TAP; +        else return TD_TRIPLE_HOLD; +    } else return TD_UNKNOWN;  } -// Create an instance of 'tap' for the 'x' tap dance. -static tap xtap_state = { +// Create an instance of 'td_tap_t' for the 'x' tap dance. +static td_tap_t xtap_state = {      .is_press_action = true, -    .state = 0 +    .state = TD_NONE  };  void x_finished(qk_tap_dance_state_t *state, void *user_data) {      xtap_state.state = cur_dance(state);      switch (xtap_state.state) { -        case SINGLE_TAP: register_code(KC_X); break; -        case SINGLE_HOLD: register_code(KC_LCTRL); break; -        case DOUBLE_TAP: register_code(KC_ESC); break; -        case DOUBLE_HOLD: register_code(KC_LALT); break; +        case TD_SINGLE_TAP: register_code(KC_X); break; +        case TD_SINGLE_HOLD: register_code(KC_LCTRL); break; +        case TD_DOUBLE_TAP: register_code(KC_ESC); break; +        case TD_DOUBLE_HOLD: register_code(KC_LALT); break;          // Last case is for fast typing. Assuming your key is `f`:          // For example, when typing the word `buffer`, and you want to make sure that you send `ff` and not `Esc`.          // 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. -        case DOUBLE_SINGLE_TAP: tap_code(KC_X); register_code(KC_X); +        case TD_DOUBLE_SINGLE_TAP: tap_code(KC_X); register_code(KC_X);      }  }  void x_reset(qk_tap_dance_state_t *state, void *user_data) {      switch (xtap_state.state) { -        case SINGLE_TAP: unregister_code(KC_X); break; -        case SINGLE_HOLD: unregister_code(KC_LCTRL); break; -        case DOUBLE_TAP: unregister_code(KC_ESC); break; -        case DOUBLE_HOLD: unregister_code(KC_LALT); -        case DOUBLE_SINGLE_TAP: unregister_code(KC_X); +        case TD_SINGLE_TAP: unregister_code(KC_X); break; +        case TD_SINGLE_HOLD: unregister_code(KC_LCTRL); break; +        case TD_DOUBLE_TAP: unregister_code(KC_ESC); break; +        case TD_DOUBLE_HOLD: unregister_code(KC_LALT); +        case TD_DOUBLE_SINGLE_TAP: unregister_code(KC_X);      } -    xtap_state.state = 0; +    xtap_state.state = TD_NONE;  }  qk_tap_dance_action_t tap_dance_actions[] = { @@ -343,9 +345,11 @@ enum td_keycodes {  // Define a type containing as many tapdance states as you need  typedef enum { -    SINGLE_TAP, -    SINGLE_HOLD, -    DOUBLE_SINGLE_TAP +    TD_NONE, +    TD_UNKNOWN, +    TD_SINGLE_TAP, +    TD_SINGLE_HOLD, +    TD_DOUBLE_SINGLE_TAP  } td_state_t;  // Create a global instance of the tapdance state type @@ -354,7 +358,7 @@ static td_state_t td_state;  // Declare your tapdance functions:  // Function to determine the current tapdance state -uint8_t cur_dance(qk_tap_dance_state_t *state); +td_state_t 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); @@ -365,14 +369,14 @@ Below your `LAYOUT`, define each of the tapdance functions:  ```c  // Determine the tapdance state to return -uint8_t cur_dance(qk_tap_dance_state_t *state) { +td_state_t 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->interrupted || !state->pressed) return TD_SINGLE_TAP; +        else return TD_SINGLE_HOLD;      } -    if (state->count == 2) return DOUBLE_SINGLE_TAP; -    else return 3; // Any number higher than the maximum state value you return above +    if (state->count == 2) return TD_DOUBLE_SINGLE_TAP; +    else return TD_UNKNOWN; // Any number higher than the maximum state value you return above  }  // Handle the possible states for each tapdance keycode you define: @@ -380,13 +384,13 @@ uint8_t cur_dance(qk_tap_dance_state_t *state) {  void altlp_finished(qk_tap_dance_state_t *state, void *user_data) {      td_state = cur_dance(state);      switch (td_state) { -        case SINGLE_TAP: +        case TD_SINGLE_TAP:              register_code16(KC_LPRN);              break; -        case SINGLE_HOLD: +        case TD_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 +        case TD_DOUBLE_SINGLE_TAP: // Allow nesting of 2 parens `((` within tapping term              tap_code16(KC_LPRN);              register_code16(KC_LPRN);      } @@ -394,13 +398,13 @@ void altlp_finished(qk_tap_dance_state_t *state, void *user_data) {  void altlp_reset(qk_tap_dance_state_t *state, void *user_data) {      switch (td_state) { -        case SINGLE_TAP: +        case TD_SINGLE_TAP:              unregister_code16(KC_LPRN);              break; -        case SINGLE_HOLD: +        case TD_SINGLE_HOLD:              unregister_mods(MOD_BIT(KC_LALT)); // For a layer-tap key, use `layer_off(_MY_LAYER)` here              break; -        case DOUBLE_SINGLE_TAP: +        case TD_DOUBLE_SINGLE_TAP:              unregister_code16(KC_LPRN);      }  } @@ -420,17 +424,19 @@ Tap Dance can be used to mimic MO(layer) and TG(layer) functionality. For this e  The first step is to include the following code towards the beginning of your `keymap.c`:  ```c +// Define a type for as many tap dance states as you need +typedef enum { +    TD_NONE, +    TD_UNKNOWN, +    TD_SINGLE_TAP, +    TD_SINGLE_HOLD, +    TD_DOUBLE_TAP +} td_state_t; +  typedef struct {      bool is_press_action; -    uint8_t state; -} tap; - -// Define a type for as many tap dance states as you need -enum { -    SINGLE_TAP = 1, -    SINGLE_HOLD, -    DOUBLE_TAP -}; +    td_state_t state; +} td_tap_t;  enum {      QUOT_LAYR, // Our custom tap dance key; add any other tap dance keys to this enum  @@ -439,7 +445,7 @@ enum {  // Declare the functions to be used with your tap dance key(s)  // Function associated with all tap dances -uint8_t cur_dance(qk_tap_dance_state_t *state); +td_state_t cur_dance(qk_tap_dance_state_t *state);  // Functions associated with individual tap dances  void 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:  ```c  // Determine the current tap dance state -uint8_t cur_dance(qk_tap_dance_state_t *state) { +td_state_t cur_dance(qk_tap_dance_state_t *state) {      if (state->count == 1) { -        if (!state->pressed) return SINGLE_TAP; -        else return SINGLE_HOLD; -    } else if (state->count == 2) return DOUBLE_TAP; -    else return 8; +        if (!state->pressed) return TD_SINGLE_TAP; +        else return TD_SINGLE_HOLD; +    } else if (state->count == 2) return TD_DOUBLE_TAP; +    else return TD_UNKNOWN;  }  // Initialize tap structure associated with example tap dance key -static tap ql_tap_state = { +static td_tap_t ql_tap_state = {      .is_press_action = true, -    .state = 0 +    .state = TD_NONE  };  // Functions that control what our tap dance key does  void ql_finished(qk_tap_dance_state_t *state, void *user_data) {      ql_tap_state.state = cur_dance(state);      switch (ql_tap_state.state) { -        case SINGLE_TAP: +        case TD_SINGLE_TAP:              tap_code(KC_QUOT);              break; -        case SINGLE_HOLD: +        case TD_SINGLE_HOLD:              layer_on(_MY_LAYER);              break; -        case DOUBLE_TAP: +        case TD_DOUBLE_TAP:              // Check to see if the layer is already set              if (layer_state_is(_MY_LAYER)) {                  // If already set, then switch it off @@ -489,10 +495,10 @@ void ql_finished(qk_tap_dance_state_t *state, void *user_data) {  void ql_reset(qk_tap_dance_state_t *state, void *user_data) {      // If the key was held down and now is released then switch off the layer -    if (ql_tap_state.state == SINGLE_HOLD) { +    if (ql_tap_state.state == TD_SINGLE_HOLD) {          layer_off(_MY_LAYER);      } -    ql_tap_state.state = 0; +    ql_tap_state.state = TD_NONE;  }  // 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  The use of `cur_dance()` and `ql_tap_state` mirrors the above examples. -The `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)`. +The `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)`.  `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.  | 
