aboutsummaryrefslogtreecommitdiff
path: root/users/drashna/readme/tap_dance.md
diff options
context:
space:
mode:
Diffstat (limited to 'users/drashna/readme/tap_dance.md')
-rw-r--r--users/drashna/readme/tap_dance.md119
1 files changed, 119 insertions, 0 deletions
diff --git a/users/drashna/readme/tap_dance.md b/users/drashna/readme/tap_dance.md
new file mode 100644
index 000000000..a61dd1f2b
--- /dev/null
+++ b/users/drashna/readme/tap_dance.md
@@ -0,0 +1,119 @@
1# Diablo Tap Dances
2
3My [Tap Dance](https://github.com/qmk/qmk_firmware/blob/master/users/drashna/tap_dances.c) file includes the tap dance declarations, and everything needed for them.
4
5This is used for making Diablo 3 much easier to plan, especially at high rift levels.
6
7This works by using Tap Dances. The taps don't actually "do anything". Instead, it sets up the interval for how often to send specific keypresses. As you can tell, this makes automating things very easy.
8
9For critics that think this is cheating, just search "[diablo 3 num lock auto cast](http://lmgtfy.com/?q=diablo+3+numlock+autocast)". This is just a simpler method, that doesn't require a numpad.
10
11
12## Custom Tap Dance Type
13The real fun here is that the tap dances use a custom defined Tap Dance type:
14
15```c
16#define ACTION_TAP_DANCE_DIABLO(index, keycode) { \
17 .fn = { NULL, (void *)diablo_tapdance_master, NULL }, \
18 .user_data = (void *)&((diable_keys_t) { index, keycode }), \
19 }
20```
21This lets me set an index and keycode for the tap dance. This isn't the cool part yet, but this allows for the really cool stuff.
22
23The Index is needed because I don't know how to handle it otherwise.
24
25## The Actual Dances
26
27These are the custom defined dances that I'm using. It sets up everything for later, using the above custom dance type.
28
29```c
30//Tap Dance Definitions, sets the index and the keycode.
31qk_tap_dance_action_t tap_dance_actions[] = {
32 // tap once to disable, and more to enable timed micros
33 [TD_D3_1] = ACTION_TAP_DANCE_DIABLO(0, KC_1),
34 [TD_D3_2] = ACTION_TAP_DANCE_DIABLO(1, KC_2),
35 [TD_D3_3] = ACTION_TAP_DANCE_DIABLO(2, KC_3),
36 [TD_D3_4] = ACTION_TAP_DANCE_DIABLO(3, KC_4),
37};
38```
39
40## Custom Data Structures
41
42First, to get this all working, there are a couple of things that need to be set up. In a header file (or you could put it into the keymap), you need to create a couple of custom structures:
43
44```c
45typedef struct {
46 uint16_t timer;
47 uint8_t key_interval;
48 uint8_t keycode;
49} diablo_timer_t;
50
51typedef struct {
52 uint8_t index;
53 uint8_t keycode;
54} diable_keys_t;
55```
56
57The first structure is for tracking each key that is being used. The second is to pass data from the Tap Dance action array to the actual function that we will need.
58
59
60## Custom Arrays
61
62To facilitate things, you will need a couple of arrays in your `c` file.
63
64```c
65//define diablo macro timer variables
66diablo_timer_t diablo_timer[4];
67
68// Set the default intervals. Always start with 0 so that it will disable on first hit.
69// Otherwise, you will need to hit a bunch of times, or hit the "clear" command
70uint8_t diablo_times[] = { 0, 1, 3, 5, 10, 30 };
71```
72
73The first one (`diablo_timer`) is what keeps track of the timer used for the keys, the interval that it uses, and the actual keycode. This makes managing it a lot easier.
74
75The second array is a list of predefined intervals, in seconds. You can add more here, or remove entries. It doesn't matter how long the array is, as this is computed automatically.
76
77## The Magic - Part 1: Master function
78
79The first part of the magic here is the `diablo_tapdance_master` function. The Tap Dance feature calls this function, directly, and passes some data to the function. Namely, it passes the array of the index and the keycode (`diablo_keys_t` from above). This sets the keycode and the interval for the specific index of `diabolo_timer` based on the number of taps. If you hit it more than the number of items in the array, then it zeroes out the interval, disabling it.
80
81```c
82// Cycle through the times for the macro, starting at 0, for disabled.
83void diablo_tapdance_master(qk_tap_dance_state_t *state, void *user_data) {
84 diable_keys_t *diablo_keys = (diable_keys_t *)user_data;
85 // Sets the keycode based on the index
86 diablo_timer[diablo_keys->index].keycode = diablo_keys->keycode;
87
88 // if the tapdance is hit more than the number of elemints in the array, reset
89 if (state->count >= (sizeof(diablo_times) / sizeof(uint8_t) ) ) {
90 diablo_timer[diablo_keys->index].key_interval = 0;
91 reset_tap_dance(state);
92 } else { // else set the interval (tapdance count starts at 1, array starts at 0, so offset by one)
93 diablo_timer[diablo_keys->index].key_interval = diablo_times[state->count - 1];
94 }
95}
96```
97
98## The Magic - Part 2: The Coup de Grace
99
100The real core here is the `run_diablo_macro_check()` function. You need to call this from `matrix_scan_user`, as this handles the timer check.
101
102Specifically, it runs a check for each index of the timer. It checks to see if it's enabled, and if enough time has passed. If enough time has passed, it resets the timer, and will tap the keycode that you set for that index, but only if the Diablo layer is enabled.
103
104```c
105// Checks each of the 4 timers/keys to see if enough time has elapsed
106void run_diablo_macro_check(void) {
107 for (uint8_t index = 0; index < NUM_OF_DIABLO_KEYS; index++) {
108 // if key_interval is 0, it's disabled, so only run if it's set. If it's set, check the timer.
109 if ( diablo_timer[index].key_interval && timer_elapsed( diablo_timer[index].timer ) > ( diablo_timer[index].key_interval * 1000 ) ) {
110 // reset the timer, since enough time has passed
111 diablo_timer[index].timer = timer_read();
112 // send keycode ONLY if we're on the diablo layer.
113 if (IS_LAYER_ON(_DIABLO)) {
114 tap_code(diablo_timer[index].keycode);
115 }
116 }
117 }
118}
119```