Merge remote-tracking branch 'origin/master' into develop
This commit is contained in:
		
						commit
						d6b18ebfe7
					
				
					 1 changed files with 84 additions and 78 deletions
				
			
		|  | @ -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. | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 QMK Bot
						QMK Bot