summaryrefslogtreecommitdiff
path: root/docs/feature_leader_key.md
blob: 72a6818dd1dd6d599ff6e981162ce79bea0953dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
# The Leader Key: A New Kind of Modifier :id=the-leader-key

If you're a Vim user, you probably know what a Leader key is. In contrast to [Combos](feature_combo.md), the Leader key allows you to hit a *sequence* of up to five keys instead, which triggers some custom functionality once complete.

## Usage :id=usage

Add the following to your `rules.mk`:

```make
LEADER_ENABLE = yes
```

Then add the `QK_LEAD` keycode to your keymap.

## Callbacks :id=callbacks

These callbacks are invoked when the leader sequence begins and ends. In the latter you can implement your custom functionality based on the contents of the sequence buffer.

```c
void leader_start_user(void) {
    // Do something when the leader key is pressed
}

void leader_end_user(void) {
    if (leader_sequence_one_key(KC_F)) {
        // Leader, f => Types the below string
        SEND_STRING("QMK is awesome.");
    } else if (leader_sequence_two_keys(KC_D, KC_D)) {
        // Leader, d, d => Ctrl+A, Ctrl+C
        SEND_STRING(SS_LCTL("a") SS_LCTL("c"));
    } else if (leader_sequence_three_keys(KC_D, KC_D, KC_S)) {
        // Leader, d, d, s => Types the below string
        SEND_STRING("https://start.duckduckgo.com\n");
    } else if (leader_sequence_two_keys(KC_A, KC_S)) {
        // Leader, a, s => GUI+S
        tap_code16(LGUI(KC_S));
    }
}
```

## Basic Configuration :id=basic-configuration

### Timeout :id=timeout

This is the amount of time you have to complete a sequence once the leader key has been pressed. The default value is 300 milliseconds, but you can change this by adding the following to your `config.h`:

```c
#define LEADER_TIMEOUT 350
```

### Per-Key Timeout :id=per-key-timeout

Rather than relying on an incredibly high timeout for long leader key strings or those of us without 200 wpm typing skills, you can enable per-key timing to ensure that each key pressed provides you with more time to finish the sequence. This is incredibly helpful with leader key emulation of tap dance (such as multiple taps of the same key like C, C, C).

To enable this, add the following to your `config.h`:

```c
#define LEADER_PER_KEY_TIMING
```

After this, it's recommended that you lower your timeout below 300 ms:

```c
#define LEADER_TIMEOUT 250
```

Now, something like this won't seem impossible to do without a 1000 millisecond timeout:

```c
if (leader_sequence_three_keys(KC_C, KC_C, KC_C)) {
    SEND_STRING("Per key timing is great!!!");
}
```

### Disabling Initial Timeout :id=disabling-initial-timeout

Sometimes your leader key may be too far away from the rest of the keys in the sequence. Imagine that your leader key is one of your outer top right keys - you may need to reposition your hand just to reach your leader key. This can make typing the entire sequence on time hard difficult if you are able to type most of the sequence fast. For example, if your sequence is `Leader + asd`, typing `asd` fast is very easy once you have your hands in your home row, but starting the sequence in time after moving your hand out of the home row to reach the leader key and back is not.

To remove the stress this situation produces to your hands, you can disable the timeout just for the leader key. Add the following to your `config.h`:

```c
#define LEADER_NO_TIMEOUT
```

Now, after you hit the leader key, you will have an infinite amount of time to start the rest of the sequence, allowing you to properly position your hands to type the rest of the sequence comfortably. This way you can configure a very short `LEADER_TIMEOUT`, but still have plenty of time to position your hands.

### Strict Key Processing :id=strict-key-processing

By default, only the "tap keycode" portions of [Mod-Taps](mod_tap.md) and [Layer Taps](feature_layers.md#switching-and-toggling-layers) are added to the sequence buffer. This means if you press eg. `LT(3, KC_A)` as part of a sequence, `KC_A` will be added to the buffer, rather than the entire `LT(3, KC_A)` keycode.

This gives a more expected behaviour for most users, however you may want to change this.

To enable this, add the following to your `config.h`:

```c
#define LEADER_KEY_STRICT_KEY_PROCESSING
```

## Example :id=example

This example will play the Mario "One Up" sound when you hit `QK_LEAD` to start the leader sequence. When the sequence ends, it will play "All Star" if it completes successfully or "Rick Roll" you if it fails (in other words, no sequence matched).

```c
#ifdef AUDIO_ENABLE
float leader_start_song[][2] = SONG(ONE_UP_SOUND);
float leader_succeed_song[][2] = SONG(ALL_STAR);
float leader_fail_song[][2] = SONG(RICK_ROLL);
#endif

void leader_start_user(void) {
#ifdef AUDIO_ENABLE
    PLAY_SONG(leader_start_song);
#endif
}

void leader_end_user(void) {
    bool did_leader_succeed = false;

    if (leader_sequence_one_key(KC_E)) {
        SEND_STRING(SS_LCTL(SS_LSFT("t")));
        did_leader_succeed = true;
    } else if (leader_sequence_two_keys(KC_E, KC_D)) {
        SEND_STRING(SS_LGUI("r") "cmd\n" SS_LCTL("c"));
        did_leader_succeed = true;
    }

#ifdef AUDIO_ENABLE
    if (did_leader_succeed) {
        PLAY_SONG(leader_succeed_song);
    } else {
        PLAY_SONG(leader_fail_song);
    }
#endif
}
```

## Keycodes :id=keycodes

|Key                    |Aliases  |Description              |
|-----------------------|---------|-------------------------|
|`QK_LEADER`            |`QK_LEAD`|Begin the leader sequence|

## API :id=api

### `void leader_start_user(void)` :id=api-leader-start-user

User callback, invoked when the leader sequence begins.

---

### `void leader_end_user(void)` :id=api-leader-end-user

User callback, invoked when the leader sequence ends.

---

### `void leader_start(void)` :id=api-leader-start

Begin the leader sequence, resetting the buffer and timer.

---

### `void leader_end(void)` :id=api-leader-end

End the leader sequence.

---

### `bool leader_sequence_active(void)` :id=api-leader-sequence-active

Whether the leader sequence is active.

---

### `bool leader_sequence_add(uint16_t keycode)` :id=api-leader-sequence-add

Add the given keycode to the sequence buffer.

If `LEADER_NO_TIMEOUT` is defined, the timer is reset if the buffer is empty.

#### Arguments :id=api-leader-sequence-add-arguments

 - `uint16_t keycode`  
   The keycode to add.

#### Return Value :id=api-leader-sequence-add-return

`true` if the keycode was added, `false` if the buffer is full.

---

### `bool leader_sequence_timed_out(void)` :id=api-leader-sequence-timed-out

Whether the leader sequence has reached the timeout.

If `LEADER_NO_TIMEOUT` is defined, the buffer must also contain at least one key.

---

### `bool leader_reset_timer(void)` :id=api-leader-reset-timer

Reset the leader sequence timer.

---

### `bool leader_sequence_one_key(uint16_t kc)` :id=api-leader-sequence-one-key

Check the sequence buffer for the given keycode.

#### Arguments :id=api-leader-sequence-one-key-arguments

 - `uint16_t kc`  
   The keycode to check.

#### Return Value :id=api-leader-sequence-one-key-return

`true` if the sequence buffer matches.

---

### `bool leader_sequence_two_keys(uint16_t kc1, uint16_t kc2)` :id=api-leader-sequence-two-keys

Check the sequence buffer for the given keycodes.

#### Arguments :id=api-leader-sequence-two-keys-arguments

 - `uint16_t kc1`  
   The first keycode to check.
 - `uint16_t kc2`  
   The second keycode to check.

#### Return Value :id=api-leader-sequence-two-keys-return

`true` if the sequence buffer matches.

---

### `bool leader_sequence_three_keys(uint16_t kc1, uint16_t kc2, uint16_t kc3)` :id=api-leader-sequence-three-keys

Check the sequence buffer for the given keycodes.

#### Arguments :id=api-leader-sequence-three-keys-arguments

 - `uint16_t kc1`  
   The first keycode to check.
 - `uint16_t kc2`  
   The second keycode to check.
 - `uint16_t kc3`  
   The third keycode to check.

#### Return Value :id=api-leader-sequence-three-keys-return

`true` if the sequence buffer matches.

---

### `bool leader_sequence_four_keys(uint16_t kc1, uint16_t kc2, uint16_t kc3, uint16_t kc4)` :id=api-leader-sequence-four-keys

Check the sequence buffer for the given keycodes.

#### Arguments :id=api-leader-sequence-four-keys-arguments

 - `uint16_t kc1`  
   The first keycode to check.
 - `uint16_t kc2`  
   The second keycode to check.
 - `uint16_t kc3`  
   The third keycode to check.
 - `uint16_t kc4`  
   The fourth keycode to check.

#### Return Value :id=api-leader-sequence-four-keys-return

`true` if the sequence buffer matches.

---

### `bool leader_sequence_five_keys(uint16_t kc1, uint16_t kc2, uint16_t kc3, uint16_t kc4, uint16_t kc5)` :id=api-leader-sequence-five-keys

Check the sequence buffer for the given keycodes.

#### Arguments :id=api-leader-sequence-five-keys-arguments

 - `uint16_t kc1`  
   The first keycode to check.
 - `uint16_t kc2`  
   The second keycode to check.
 - `uint16_t kc3`  
   The third keycode to check.
 - `uint16_t kc4`  
   The fourth keycode to check.
 - `uint16_t kc5`  
   The fifth keycode to check.

#### Return Value :id=api-leader-sequence-five-keys-return

`true` if the sequence buffer matches.