keyboard stuff
1# Repeat Key
2
3The Repeat Key performs the action of the last pressed key. Tapping the Repeat
4Key after tapping the <kbd>Z</kbd> key types another "`z`." This is useful for
5typing doubled letters, like the `z` in "`dazzle`": a double tap on <kbd>Z</kbd>
6can instead be a roll from <kbd>Z</kbd> to <kbd>Repeat</kbd>, which is
7potentially faster and more comfortable. The Repeat Key is also useful for
8hotkeys, like repeating Ctrl + Shift + Right Arrow to select by word.
9
10Repeat Key remembers mods that were active with the last key press. These mods
11are combined with any additional mods while pressing the Repeat Key. If the last
12press key was <kbd>Ctrl</kbd> + <kbd>Z</kbd>, then <kbd>Shift</kbd> +
13<kbd>Repeat</kbd> performs Ctrl + Shift + `Z`.
14
15## How do I enable Repeat Key
16
17In your `rules.mk`, add:
18
19```make
20REPEAT_KEY_ENABLE = yes
21```
22
23Then pick a key in your keymap and assign it the keycode `QK_REPEAT_KEY` (short
24alias `QK_REP`). Optionally, use the keycode `QK_ALT_REPEAT_KEY` (short alias
25`QK_AREP`) on another key.
26
27## Keycodes
28
29|Keycode |Aliases |Description |
30|-----------------------|---------|-------------------------------------|
31|`QK_REPEAT_KEY` |`QK_REP` |Repeat the last pressed key |
32|`QK_ALT_REPEAT_KEY` |`QK_AREP`|Perform alternate of the last key |
33
34## Alternate Repeating
35
36The Alternate Repeat Key performs the "alternate" action of the last pressed key
37if it is defined. By default, Alternate Repeat is defined for navigation keys to
38act in the reverse direction. When the last key is the common "select by word"
39hotkey Ctrl + Shift + Right Arrow, the Alternate Repeat Key performs Ctrl +
40Shift + Left Arrow, which together with the Repeat Key enables convenient
41selection by words in either direction.
42
43Alternate Repeat is enabled with the Repeat Key by default. Optionally, to
44reduce firmware size, Alternate Repeat may be disabled by adding in config.h:
45
46```c
47#define NO_ALT_REPEAT_KEY
48```
49
50The following alternate keys are defined by default. See
51`get_alt_repeat_key_keycode_user()` below for how to change or add to these
52definitions. Where it makes sense, these definitions also include combinations
53with mods, like Ctrl + Left ↔ Ctrl + Right Arrow.
54
55**Navigation**
56
57|Keycodes |Description |
58|-----------------------------------|-----------------------------------|
59|`KC_LEFT` ↔ `KC_RGHT` | Left ↔ Right Arrow |
60|`KC_UP` ↔ `KC_DOWN` | Up ↔ Down Arrow |
61|`KC_HOME` ↔ `KC_END` | Home ↔ End |
62|`KC_PGUP` ↔ `KC_PGDN` | Page Up ↔ Page Down |
63|`MS_LEFT` ↔ `MS_RGHT` | Mouse Cursor Left ↔ Right |
64|`MS_UP` ↔ `MS_DOWN` | Mouse Cursor Up ↔ Down |
65|`MS_WHLL` ↔ `MS_WHLR` | Mouse Wheel Left ↔ Right |
66|`MS_WHLU` ↔ `MS_WHLD` | Mouse Wheel Up ↔ Down |
67
68**Misc**
69
70|Keycodes |Description |
71|-----------------------------------|-----------------------------------|
72|`KC_BSPC` ↔ `KC_DEL` | Backspace ↔ Delete |
73|`KC_LBRC` ↔ `KC_RBRC` | `[` ↔ `]` |
74|`KC_LCBR` ↔ `KC_RCBR` | `{` ↔ `}` |
75
76**Media**
77
78|Keycodes |Description |
79|-----------------------------------|-----------------------------------|
80|`KC_WBAK` ↔ `KC_WFWD` | Browser Back ↔ Forward |
81|`KC_MNXT` ↔ `KC_MPRV` | Next ↔ Previous Media Track |
82|`KC_MFFD` ↔ `KC_MRWD` | Fast Forward ↔ Rewind Media |
83|`KC_VOLU` ↔ `KC_VOLD` | Volume Up ↔ Down |
84|`KC_BRIU` ↔ `KC_BRID` | Brightness Up ↔ Down |
85
86**Hotkeys in Vim, Emacs, and other programs**
87
88|Keycodes |Description |
89|-----------------------------------|-----------------------------------|
90|mod + `KC_F` ↔ mod + `KC_B` | Forward ↔ Backward |
91|mod + `KC_D` ↔ mod + `KC_U` | Down ↔ Up |
92|mod + `KC_N` ↔ mod + `KC_P` | Next ↔ Previous |
93|mod + `KC_A` ↔ mod + `KC_E` | Home ↔ End |
94|mod + `KC_O` ↔ mod + `KC_I` | Vim jump list Older ↔ Newer |
95|`KC_J` ↔ `KC_K` | Down ↔ Up |
96|`KC_H` ↔ `KC_L` | Left ↔ Right |
97|`KC_W` ↔ `KC_B` | Forward ↔ Backward by Word |
98
99(where above, "mod" is Ctrl, Alt, or GUI)
100
101
102## Defining alternate keys
103
104Use the `get_alt_repeat_key_keycode_user()` callback to define the "alternate"
105for additional keys or override the default definitions. For example, to define
106Ctrl + Y as the alternate of Ctrl + Z, and vice versa, add the following in
107keymap.c:
108
109```c
110uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
111 if ((mods & MOD_MASK_CTRL)) { // Was Ctrl held?
112 switch (keycode) {
113 case KC_Y: return C(KC_Z); // Ctrl + Y reverses to Ctrl + Z.
114 case KC_Z: return C(KC_Y); // Ctrl + Z reverses to Ctrl + Y.
115 }
116 }
117
118 return KC_TRNS; // Defer to default definitions.
119}
120```
121
122The `keycode` and `mods` args are the keycode and mods that were active with the
123last pressed key. The meaning of the return value from this function is:
124
125* `KC_NO` – do nothing (any predefined alternate key is not used);
126* `KC_TRNS` – use the default alternate key if it exists;
127* anything else – use the specified keycode. Any keycode may be returned
128 as an alternate key, including custom keycodes.
129
130Another example, defining Shift + Tab as the alternate of Tab, and vice versa:
131
132```c
133uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
134 bool shifted = (mods & MOD_MASK_SHIFT); // Was Shift held?
135 switch (keycode) {
136 case KC_TAB:
137 if (shifted) { // If the last key was Shift + Tab,
138 return KC_TAB; // ... the reverse is Tab.
139 } else { // Otherwise, the last key was Tab,
140 return S(KC_TAB); // ... and the reverse is Shift + Tab.
141 }
142 }
143
144 return KC_TRNS;
145}
146```
147
148#### Eliminating SFBs
149
150Alternate Repeat can be configured more generally to perform an action that
151"complements" the last key. Alternate Repeat is not limited to reverse
152repeating, and it need not be symmetric. You can use it to eliminate cases of
153same-finger bigrams in your layout, that is, pairs of letters typed by the same
154finger. The following addresses the top 5 same-finger bigrams in English on
155QWERTY, so that for instance "`ed`" may be typed as <kbd>E</kbd>, <kbd>Alt
156Repeat</kbd>.
157
158```c
159uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
160 switch (keycode) {
161 case KC_E: return KC_D; // For "ED" bigram.
162 case KC_D: return KC_E; // For "DE" bigram.
163 case KC_C: return KC_E; // For "CE" bigram.
164 case KC_L: return KC_O; // For "LO" bigram.
165 case KC_U: return KC_N; // For "UN" bigram.
166 }
167
168 return KC_TRNS;
169}
170```
171
172#### Typing shortcuts
173
174A useful possibility is having Alternate Repeat press [a
175macro](../feature_macros). This way macros can be used without having to
176dedicate keys to them. The following defines a couple shortcuts.
177
178* Typing <kbd>K</kbd>, <kbd>Alt Repeat</kbd> produces "`keyboard`," with the
179 initial "`k`" typed as usual and the "`eybord`" produced by the macro.
180* Typing <kbd>.</kbd>, <kbd>Alt Repeat</kbd> produces "`../`," handy for "up
181 directory" on the shell. Similarly, <kbd>.</kbd> types the initial "`.`" and
182 "`./`" is produced by the macro.
183
184```c
185enum custom_keycodes {
186 M_KEYBOARD = SAFE_RANGE,
187 M_UPDIR,
188 // Other custom keys...
189};
190
191uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
192 switch (keycode) {
193 case KC_K: return M_KEYBOARD;
194 case KC_DOT: return M_UPDIR;
195 }
196
197 return KC_TRNS;
198}
199
200bool process_record_user(uint16_t keycode, keyrecord_t* record) {
201 switch (keycode) {
202 case M_KEYBOARD: SEND_STRING(/*k*/"eyboard"); break;
203 case M_UPDIR: SEND_STRING(/*.*/"./"); break;
204 }
205 return true;
206}
207```
208
209## Ignoring certain keys and mods
210
211In tracking what is "the last key" to be repeated or alternate repeated,
212modifier and layer switch keys are always ignored. This makes it possible to set
213some mods and change layers between pressing a key and repeating it. By default,
214all other (non-modifier, non-layer switch) keys are remembered so that they are
215eligible for repeating. To configure additional keys to be ignored, define
216`remember_last_key_user()` in your keymap.c.
217
218#### Ignoring a key
219
220The following ignores the Backspace key:
221
222```c
223bool remember_last_key_user(uint16_t keycode, keyrecord_t* record,
224 uint8_t* remembered_mods) {
225 switch (keycode) {
226 case KC_BSPC:
227 return false; // Ignore backspace.
228 }
229
230 return true; // Other keys can be repeated.
231}
232```
233
234Then for instance, the Repeat key in <kbd>Left Arrow</kbd>,
235<kbd>Backspace</kbd>, <kbd>Repeat</kbd> sends Left Arrow again instead of
236repeating Backspace.
237
238The `remember_last_key_user()` callback is called on every key press excluding
239modifiers and layer switches. Returning true indicates the key is remembered,
240while false means it is ignored.
241
242#### Filtering remembered mods
243
244The `remembered_mods` arg represents the mods that will be remembered with
245this key. It can be modified to forget certain mods. This may be
246useful to forget capitalization when repeating shifted letters, so that "Aaron"
247does not becom "AAron":
248
249```c
250bool remember_last_key_user(uint16_t keycode, keyrecord_t* record,
251 uint8_t* remembered_mods) {
252 // Forget Shift on letter keys when Shift or AltGr are the only mods.
253 switch (keycode) {
254 case KC_A ... KC_Z:
255 if ((*remembered_mods & ~(MOD_MASK_SHIFT | MOD_BIT(KC_RALT))) == 0) {
256 *remembered_mods &= ~MOD_MASK_SHIFT;
257 }
258 break;
259 }
260
261 return true;
262}
263```
264
265#### Further conditions
266
267Besides checking the keycode, this callback could also make conditions based on
268the current layer state (with `IS_LAYER_ON(layer)`) or mods (`get_mods()`). For
269example, the following ignores keys on layer 2 as well as key combinations
270involving GUI:
271
272```c
273bool remember_last_key_user(uint16_t keycode, keyrecord_t* record,
274 uint8_t* remembered_mods) {
275 if (IS_LAYER_ON(2) || (get_mods() & MOD_MASK_GUI)) {
276 return false; // Ignore layer 2 keys and GUI chords.
277 }
278
279 return true; // Other keys can be repeated.
280}
281```
282
283::: tip
284See [Layer Functions](../feature_layers#functions) and [Checking Modifier State](../feature_advanced_keycodes#checking-modifier-state) for further details.
285:::
286
287## Handle how a key is repeated
288
289By default, pressing the Repeat Key will simply behave as if the last key
290were pressed again. This also works with macro keys with custom handlers,
291invoking the macro again. In case fine-tuning is needed for sensible repetition,
292you can handle how a key is repeated with `get_repeat_key_count()` within
293`process_record_user()`.
294
295The `get_repeat_key_count()` function returns a signed count of times the key
296has been repeated or alternate repeated. When a key is pressed as usual,
297`get_repeat_key_count()` is 0. On the first repeat, it is 1, then the second
298repeat, 2, and so on. Negative counts are used similarly for alternate
299repeating. For instance supposing `MY_MACRO` is a custom keycode used in the
300layout:
301
302```c
303bool process_record_user(uint16_t keycode, keyrecord_t* record) {
304 switch (keycode) {
305 case MY_MACRO:
306 if (get_repeat_key_count() > 0) {
307 // MY_MACRO is being repeated!
308 if (record->event.pressed) {
309 SEND_STRING("repeat!");
310 }
311 } else {
312 // MY_MACRO is being used normally.
313 if (record->event.pressed) {
314 SEND_STRING("macro");
315 }
316 }
317 return false;
318
319 // Other macros...
320 }
321 return true;
322}
323```
324
325## Handle how a key is alternate repeated
326
327Pressing the Alternate Repeat Key behaves as if the "alternate" of the last
328pressed key were pressed, if an alternate is defined. To define how a particular
329key is alternate repeated, use the `get_alt_repeat_key_keycode_user()` callback
330as described above to define which keycode to use as its alternate. Beyond this,
331`get_repeat_key_count()` may be used in custom handlers to fine-tune behavior
332when alternate repeating.
333
334The following example defines `MY_MACRO` as its own alternate, and specially
335handles repeating and alternate repeating:
336
337```c
338uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
339 switch (keycode) {
340 case MY_MACRO: return MY_MACRO; // MY_MACRO is its own alternate.
341 }
342 return KC_TRNS;
343}
344
345bool process_record_user(uint16_t keycode, keyrecord_t* record) {
346 switch (keycode) {
347 case MY_MACRO:
348 if (get_repeat_key_count() > 0) { // Repeating.
349 if (record->event.pressed) {
350 SEND_STRING("repeat!");
351 }
352 } else if (get_repeat_key_count() < 0) { // Alternate repeating.
353 if (record->event.pressed) {
354 SEND_STRING("alt repeat!");
355 }
356 } else { // Used normally.
357 if (record->event.pressed) {
358 SEND_STRING("macro");
359 }
360 }
361 return false;
362
363 // Other macros...
364 }
365 return true;
366}
367```
368
369
370## Functions
371
372| Function | Description |
373|--------------------------------|------------------------------------------------------------------------|
374| `get_last_keycode()` | The last key's keycode, the key to be repeated. |
375| `get_last_mods()` | Mods to apply when repeating. |
376| `set_last_keycode(kc)` | Set the keycode to be repeated. |
377| `set_last_mods(mods)` | Set the mods to apply when repeating. |
378| `get_repeat_key_count()` | Signed count of times the key has been repeated or alternate repeated. |
379| `get_alt_repeat_key_keycode()` | Keycode to be used for alternate repeating. |
380
381
382## Additional "Alternate" keys
383
384By leveraging `get_last_keycode()` in macros, it is possible to define
385additional, distinct "Alternate Repeat"-like keys. The following defines two
386keys `ALTREP2` and `ALTREP3` and implements ten shortcuts with them for common
387English 5-gram letter patterns, taking inspiration from
388[Stenotype](stenography):
389
390
391| Typing | Produces | Typing | Produces |
392|----------------------------------|----------|----------------------------------|----------|
393| <kbd>A</kbd>, <kbd>ALTREP2</kbd> | `ation` | <kbd>A</kbd>, <kbd>ALTREP3</kbd> | `about` |
394| <kbd>I</kbd>, <kbd>ALTREP2</kbd> | `ition` | <kbd>I</kbd>, <kbd>ALTREP3</kbd> | `inter` |
395| <kbd>S</kbd>, <kbd>ALTREP2</kbd> | `ssion` | <kbd>S</kbd>, <kbd>ALTREP3</kbd> | `state` |
396| <kbd>T</kbd>, <kbd>ALTREP2</kbd> | `their` | <kbd>T</kbd>, <kbd>ALTREP3</kbd> | `there` |
397| <kbd>W</kbd>, <kbd>ALTREP2</kbd> | `which` | <kbd>W</kbd>, <kbd>ALTREP3</kbd> | `would` |
398
399```c
400enum custom_keycodes {
401 ALTREP2 = SAFE_RANGE,
402 ALTREP3,
403};
404
405// Use ALTREP2 and ALTREP3 in your layout...
406
407bool remember_last_key_user(uint16_t keycode, keyrecord_t* record,
408 uint8_t* remembered_mods) {
409 switch (keycode) {
410 case ALTREP2:
411 case ALTREP3:
412 return false; // Ignore ALTREP keys.
413 }
414
415 return true; // Other keys can be repeated.
416}
417
418static void process_altrep2(uint16_t keycode, uint8_t mods) {
419 switch (keycode) {
420 case KC_A: SEND_STRING(/*a*/"tion"); break;
421 case KC_I: SEND_STRING(/*i*/"tion"); break;
422 case KC_S: SEND_STRING(/*s*/"sion"); break;
423 case KC_T: SEND_STRING(/*t*/"heir"); break;
424 case KC_W: SEND_STRING(/*w*/"hich"); break;
425 }
426}
427
428static void process_altrep3(uint16_t keycode, uint8_t mods) {
429 switch (keycode) {
430 case KC_A: SEND_STRING(/*a*/"bout"); break;
431 case KC_I: SEND_STRING(/*i*/"nter"); break;
432 case KC_S: SEND_STRING(/*s*/"tate"); break;
433 case KC_T: SEND_STRING(/*t*/"here"); break;
434 case KC_W: SEND_STRING(/*w*/"ould"); break;
435 }
436}
437
438bool process_record_user(uint16_t keycode, keyrecord_t* record) {
439 switch (keycode) {
440 case ALTREP2:
441 if (record->event.pressed) {
442 process_altrep2(get_last_keycode(), get_last_mods());
443 }
444 return false;
445
446 case ALTREP3:
447 if (record->event.pressed) {
448 process_altrep3(get_last_keycode(), get_last_mods());
449 }
450 return false;
451 }
452
453 return true;
454}
455```
456