~ruther/qmk_firmware

383e508bc56870aa971c4a881ed43dfe2f44f2ce — Daniel Gordon 7 years ago 3f3fa07
Quad Function Tap Dance added to TD Doc

    * Added section to example, detailing how to accomplish the
        'quad-function' tap dance.
    * Refactored TD documentation to clearly separate different complex
        examples

Change-Id: Ifc1495d1142849c771418fdabc458c04c48311e6
1 files changed, 90 insertions(+), 5 deletions(-)

M docs/tap_dance.md
M docs/tap_dance.md => docs/tap_dance.md +90 -5
@@ 63,20 63,23 @@ qk_tap_dance_action_t tap_dance_actions[] = {
TD(TD_ESC_CAPS)
```

## Complex Example
## Complex Examples

Here's a more complex example involving custom actions:
This section details several complex tap dance examples.
All the enums used in the examples are declared like this:

```c
// Enums defined for all examples:
enum {
 CT_SE = 0,
 CT_CLN,
 CT_EGG,
 CT_FLSH,
 X_TAP_DANCE
};

/* Have the above three on the keymap, TD(CT_SE), etc... */

```
### Example 1: Send `:` on single tap, `;` on double tap
```c
void dance_cln_finished (qk_tap_dance_state_t *state, void *user_data) {
  if (state->count == 1) {
    register_code (KC_RSFT);


@@ 95,6 98,13 @@ void dance_cln_reset (qk_tap_dance_state_t *state, void *user_data) {
  }
}

//All tap dance functions would go here. Only showing this one.
qk_tap_dance_action_t tap_dance_actions[] = {
 [CT_CLN] = ACTION_TAP_DANCE_FN_ADVANCED (NULL, dance_cln_finished, dance_cln_reset)
};
```
### Example 2: Send "Safety Dance!" after 100 taps
```c
void dance_egg (qk_tap_dance_state_t *state, void *user_data) {
  if (state->count >= 100) {
    SEND_STRING ("Safety dance!");


@@ 102,6 112,14 @@ void dance_egg (qk_tap_dance_state_t *state, void *user_data) {
  }
}

qk_tap_dance_action_t tap_dance_actions[] = {
 [CT_EGG] = ACTION_TAP_DANCE_FN (dance_egg)
};
```

### Example 3: Turn LED lights on then off, one at a time

```c
// on each tap, light up one led, from right to left
// on the forth tap, turn them off from right to left
void dance_flsh_each(qk_tap_dance_state_t *state, void *user_data) {


@@ 141,6 159,7 @@ void dance_flsh_reset(qk_tap_dance_state_t *state, void *user_data) {
  ergodox_right_led_3_off();
}

//All tap dances now put together. Example 3 is "CT_FLASH"
qk_tap_dance_action_t tap_dance_actions[] = {
  [CT_SE]  = ACTION_TAP_DANCE_DOUBLE (KC_SPC, KC_ENT)
 ,[CT_CLN] = ACTION_TAP_DANCE_FN_ADVANCED (NULL, dance_cln_finished, dance_cln_reset)


@@ 148,3 167,69 @@ qk_tap_dance_action_t tap_dance_actions[] = {
 ,[CT_FLSH] = ACTION_TAP_DANCE_FN_ADVANCED (dance_flsh_each, dance_flsh_finished, dance_flsh_reset)
};
```

### Example 4: 'Quad Function Tap-Dance'

By @DanielGGordon

Allow one key to have 4 (or more) functions, depending on number of presses, and if the key is held or tapped.
Below is a specific example:
*  Tap = Send `x`
*  Hold = Send `Control`
*  Double Tap = Send `Escape`
*  Double Tap and Hold = Send `Alt`

The following example can be easily expanded to more than 4 quite easily:
```c
//**************** Definitions needed for quad function to work *********************//
//Enums used to clearly convey the state of the tap dance
enum {
  SINGLE_TAP = 1,
  SINGLE_HOLD = 2,
  DOUBLE_TAP = 3,
  DOUBLE_HOLD = 4
  // Add more enums here if you want for triple, quadruple, etc. 
};

typedef struct {
  bool is_press_action;
  int state;
} tap;

int cur_dance (qk_tap_dance_state_t *state) {
  if ((state->count == 1) && (!state->pressed)) return SINGLE_TAP;
  else if ((state->count == 1) && (state->pressed)) return SINGLE_HOLD;
  else if ((state->count == 2) && (!state->pressed)) return DOUBLE_TAP;
  else if ((state->count == 2) && (state->pressed)) return DOUBLE_HOLD;
  else return 5; //magic number. At some point this method will expand to work for more presses
}
//**************** Definitions needed for quad function to work *********************//

//instanalize an instance of 'tap' for the 'x' tap dance.
static tap xtap_state = { 
  .is_press_action = true,
  .state = 0
};

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);
  }
}

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);
  }
  xtap_state.state = 0;
}
```
And then simply add this to your list of tap dance functions:
`[X_TAP_DANCE] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, x_finished, x_reset)`