qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

repeat_key.md (17429B)


      1 # Repeat Key
      2 
      3 The Repeat Key performs the action of the last pressed key. Tapping the Repeat
      4 Key after tapping the <kbd>Z</kbd> key types another "`z`." This is useful for
      5 typing doubled letters, like the `z` in "`dazzle`": a double tap on <kbd>Z</kbd>
      6 can instead be a roll from <kbd>Z</kbd> to <kbd>Repeat</kbd>, which is
      7 potentially faster and more comfortable. The Repeat Key is also useful for
      8 hotkeys, like repeating Ctrl + Shift + Right Arrow to select by word.
      9 
     10 Repeat Key remembers mods that were active with the last key press. These mods
     11 are combined with any additional mods while pressing the Repeat Key. If the last
     12 press 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 
     17 In your `rules.mk`, add:
     18 
     19 ```make
     20 REPEAT_KEY_ENABLE = yes
     21 ```
     22 
     23 Then pick a key in your keymap and assign it the keycode `QK_REPEAT_KEY` (short
     24 alias `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 
     36 The Alternate Repeat Key performs the "alternate" action of the last pressed key
     37 if it is defined. By default, Alternate Repeat is defined for navigation keys to
     38 act in the reverse direction. When the last key is the common "select by word"
     39 hotkey Ctrl + Shift + Right Arrow, the Alternate Repeat Key performs Ctrl +
     40 Shift + Left Arrow, which together with the Repeat Key enables convenient
     41 selection by words in either direction.
     42 
     43 Alternate Repeat is enabled with the Repeat Key by default. Optionally, to
     44 reduce firmware size, Alternate Repeat may be disabled by adding in config.h:
     45 
     46 ```c
     47 #define NO_ALT_REPEAT_KEY
     48 ```
     49 
     50 The following alternate keys are defined by default. See
     51 `get_alt_repeat_key_keycode_user()` below for how to change or add to these
     52 definitions. Where it makes sense, these definitions also include combinations
     53 with 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 
    104 Use the `get_alt_repeat_key_keycode_user()` callback to define the "alternate"
    105 for additional keys or override the default definitions. For example, to define
    106 Ctrl + Y as the alternate of Ctrl + Z, and vice versa, add the following in
    107 keymap.c:
    108 
    109 ```c
    110 uint16_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 
    122 The `keycode` and `mods` args are the keycode and mods that were active with the
    123 last 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 
    130 Another example, defining Shift + Tab as the alternate of Tab, and vice versa:
    131 
    132 ```c
    133 uint16_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 
    150 Alternate Repeat can be configured more generally to perform an action that
    151 "complements" the last key. Alternate Repeat is not limited to reverse
    152 repeating, and it need not be symmetric. You can use it to eliminate cases of
    153 same-finger bigrams in your layout, that is, pairs of letters typed by the same
    154 finger. The following addresses the top 5 same-finger bigrams in English on
    155 QWERTY, so that for instance "`ed`" may be typed as <kbd>E</kbd>, <kbd>Alt
    156 Repeat</kbd>.
    157 
    158 ```c
    159 uint16_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 
    174 A useful possibility is having Alternate Repeat press [a
    175 macro](../feature_macros). This way macros can be used without having to
    176 dedicate 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
    185 enum custom_keycodes {
    186     M_KEYBOARD = SAFE_RANGE,
    187     M_UPDIR,
    188     // Other custom keys...
    189 };
    190 
    191 uint16_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 
    200 bool 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 
    211 In tracking what is "the last key" to be repeated or alternate repeated,
    212 modifier and layer switch keys are always ignored. This makes it possible to set
    213 some mods and change layers between pressing a key and repeating it. By default,
    214 all other (non-modifier, non-layer switch) keys are remembered so that they are
    215 eligible 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 
    220 The following ignores the Backspace key:
    221 
    222 ```c
    223 bool 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 
    234 Then for instance, the Repeat key in <kbd>Left Arrow</kbd>,
    235 <kbd>Backspace</kbd>, <kbd>Repeat</kbd> sends Left Arrow again instead of
    236 repeating Backspace.
    237 
    238 The `remember_last_key_user()` callback is called on every key press excluding
    239 modifiers and layer switches. Returning true indicates the key is remembered,
    240 while false means it is ignored.
    241 
    242 #### Filtering remembered mods
    243 
    244 The `remembered_mods` arg represents the mods that will be remembered with
    245 this key. It can be modified to forget certain mods. This may be
    246 useful to forget capitalization when repeating shifted letters, so that "Aaron"
    247 does not becom "AAron":
    248 
    249 ```c
    250 bool 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 
    267 Besides checking the keycode, this callback could also make conditions based on
    268 the current layer state (with `IS_LAYER_ON(layer)`) or mods (`get_mods()`). For
    269 example, the following ignores keys on layer 2 as well as key combinations
    270 involving GUI:
    271 
    272 ```c
    273 bool 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
    284 See [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 
    289 By default, pressing the Repeat Key will simply behave as if the last key
    290 were pressed again. This also works with macro keys with custom handlers,
    291 invoking the macro again. In case fine-tuning is needed for sensible repetition,
    292 you can handle how a key is repeated with `get_repeat_key_count()` within
    293 `process_record_user()`.
    294 
    295 The `get_repeat_key_count()` function returns a signed count of times the key
    296 has 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
    298 repeat, 2, and so on. Negative counts are used similarly for alternate
    299 repeating. For instance supposing `MY_MACRO` is a custom keycode used in the
    300 layout:
    301 
    302 ```c
    303 bool 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 
    327 Pressing the Alternate Repeat Key behaves as if the "alternate" of the last
    328 pressed key were pressed, if an alternate is defined. To define how a particular
    329 key is alternate repeated, use the `get_alt_repeat_key_keycode_user()` callback
    330 as 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
    332 when alternate repeating.
    333 
    334 The following example defines `MY_MACRO` as its own alternate, and specially
    335 handles repeating and alternate repeating:
    336 
    337 ```c
    338 uint16_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 
    345 bool 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 
    384 By leveraging `get_last_keycode()` in macros, it is possible to define
    385 additional, distinct "Alternate Repeat"-like keys. The following defines two
    386 keys `ALTREP2` and `ALTREP3` and implements ten shortcuts with them for common
    387 English 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
    400 enum custom_keycodes {
    401     ALTREP2 = SAFE_RANGE,
    402     ALTREP3,
    403 };
    404 
    405 // Use ALTREP2 and ALTREP3 in your layout...
    406 
    407 bool 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 
    418 static 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 
    428 static 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 
    438 bool 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