keyboard stuff
at master 456 lines 17 kB view raw view rendered
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 &harr; Ctrl + Right Arrow. 54 55**Navigation** 56 57|Keycodes |Description | 58|-----------------------------------|-----------------------------------| 59|`KC_LEFT` &harr; `KC_RGHT` | Left &harr; Right Arrow | 60|`KC_UP` &harr; `KC_DOWN` | Up &harr; Down Arrow | 61|`KC_HOME` &harr; `KC_END` | Home &harr; End | 62|`KC_PGUP` &harr; `KC_PGDN` | Page Up &harr; Page Down | 63|`MS_LEFT` &harr; `MS_RGHT` | Mouse Cursor Left &harr; Right | 64|`MS_UP` &harr; `MS_DOWN` | Mouse Cursor Up &harr; Down | 65|`MS_WHLL` &harr; `MS_WHLR` | Mouse Wheel Left &harr; Right | 66|`MS_WHLU` &harr; `MS_WHLD` | Mouse Wheel Up &harr; Down | 67 68**Misc** 69 70|Keycodes |Description | 71|-----------------------------------|-----------------------------------| 72|`KC_BSPC` &harr; `KC_DEL` | Backspace &harr; Delete | 73|`KC_LBRC` &harr; `KC_RBRC` | `[` &harr; `]` | 74|`KC_LCBR` &harr; `KC_RCBR` | `{` &harr; `}` | 75 76**Media** 77 78|Keycodes |Description | 79|-----------------------------------|-----------------------------------| 80|`KC_WBAK` &harr; `KC_WFWD` | Browser Back &harr; Forward | 81|`KC_MNXT` &harr; `KC_MPRV` | Next &harr; Previous Media Track | 82|`KC_MFFD` &harr; `KC_MRWD` | Fast Forward &harr; Rewind Media | 83|`KC_VOLU` &harr; `KC_VOLD` | Volume Up &harr; Down | 84|`KC_BRIU` &harr; `KC_BRID` | Brightness Up &harr; Down | 85 86**Hotkeys in Vim, Emacs, and other programs** 87 88|Keycodes |Description | 89|-----------------------------------|-----------------------------------| 90|mod + `KC_F` &harr; mod + `KC_B` | Forward &harr; Backward | 91|mod + `KC_D` &harr; mod + `KC_U` | Down &harr; Up | 92|mod + `KC_N` &harr; mod + `KC_P` | Next &harr; Previous | 93|mod + `KC_A` &harr; mod + `KC_E` | Home &harr; End | 94|mod + `KC_O` &harr; mod + `KC_I` | Vim jump list Older &harr; Newer | 95|`KC_J` &harr; `KC_K` | Down &harr; Up | 96|`KC_H` &harr; `KC_L` | Left &harr; Right | 97|`KC_W` &harr; `KC_B` | Forward &harr; 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` &ndash; do nothing (any predefined alternate key is not used); 126* `KC_TRNS` &ndash; use the default alternate key if it exists; 127* anything else &ndash; 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