QMK Basics

QMK Basics: Leader Key, using sequences for shortcuts

New to QMK, or in for a refresher? In this series of tutorials on QMK Basics, you’ll be brought up to speed on a number of features that help you customize your keyboard just the way you want it.

The Leader Key is a powerful feature in QMK. It allows you to define sequences with which you can trigger keypresses and functions, making complicated shortcuts easier.

To illustrate a simple use case for the Leader Key, let’s pick a shortcut that I use often with my web browser: CTRL + SHIFT + T. It allows me to reopen tabs I closed, one at a time. It’s a shortcut I use pretty often, but it can be cumbersome to use: I need to press three keys at the same time.

With the Leader Key, I can replace this with a sequence, for example LEAD > T. I can choose the sequences myself and I can make them up to five keypresses long after the leader key itself. Notice how this way, I only have to press LEAD first, followed by T: I don’t have to press any keys at the same time. Then, when using the key in my keymap, I can tell the leader key to send CTRL + SHIFT + T when I press LEAD > T.

You can define as many sequences as you want, and you can do anything with them you can also do in a macro, like sending strings of text with SEND_STRING("Hello world!");, or sending key sequences like my “reopen closed tab” shortcut with SEND_STRING(SS_LCTRL(SS_LSFT("t"))); which sends CTRL + SHIFT + T.

So in short, the Leader Key allows you to define shortcuts that you press key after key, instead of having to press all keys at once.

How the Leader Key works

In this post you’ll learn how you can implement the Leader Key in your own keymap. First, it’s useful to know how it works, so you understand why the key behaves the way it does.

Let’s start out with some definitions:

  • Leader Key: The Leader key is a key on your keyboard with which you can start so-called sequences. You’ll map this in one of your keymap’s layers with the keycode KC_LEAD.
  • Sequence: One or more keycodes together form a sequence, such as KC_S, KC_A. You can attach your own logic to a sequence: send text, other keycodes, control LEDs and much more, all within one of your sequences. You can have any number of sequences you like.
  • Timeout: When you press the leader key, you have a number of milliseconds to enter all other keys within the sequence. After this time, QMK will check whether the keys you entered match up with the sequences you defined.

Each sequence starts by pressing the leader key. You can then press up to five other keys one after the other to activate your sequence. After enough time has passed since you pressed the leader key, a timeout, QMK will check whether all the keys you entered match up with one of your sequences. If it does, QMK will run the logic you wrote in that sequence.

When you press the Leader Key, your logic will happen after LEADER_TIMEOUT milliseconds.

Given my “reopen closed tab” example from above: First I press the Leader key, followed by the key T. If I’ve defined a single sequence based on the letter T, QMK will run the logic in my sequence, sending CTRL + SHIFT + T to the computer.

What happens if I press a key that I haven’t defined a sequence for? Well, nothing happens, QMK will swallow the keypresses and output nothing. If you’d like to get some feedback when a leader key sequence doesn’t get matched, see the examples below.

Using the Leader Key

To use the Leader Key feature in your keymap, there are a few steps you’ll need to follow. The documentation on the Leader Key is short but effective: it contains everything you need to get it up and running. For a more verbose tutorial, keep reading along!

Enable the feature

First, enable the feature by adding LEADER_ENABLE = yes to your rules.mk file. If you don’t have a rules.mk file yet for your keymap, simply make a new text file and rename it to rules.mk. It doesn’t need to contain anything besides LEADER_ENABLE = yes.

Define the timeout

Add #define LEADER_TIMEOUT 300 in your config.h file. This means that from the start of pressing the leader key, you’ll have 300 milliseconds to finish the whole sequence. You can set the timeout to be longer so you can take more time to input the sequence. There are more ways to customize the Leader Key behaviour, explained below.

Use the KC_LEAD keycode

Next, you should use the KC_LEAD keycode in your keymap. This will be the Leader Key: the key you’ll press first for any leader key sequence.

If you plan on using your Leader Key shortcuts often, it’s a good idea to put this keycode on your base layer (often the first layer, the one that’s always active. Read more about layers here). This way, you can more easily tap the sequences you’ll define later on.

You can’t use the KC_LEAD keycode within other keycodes, like MT(modifier, key) for the Mod-tap feature, or on a key that uses Tap Dance. You can use the KC_LEAD key on another layer, which can be fine if you don’t use the key often.

Alter or add the matrix_scan_user function

The matrix_scan_user function is a way to hook into the QMK framework. This particular method will be called on each matrix scan. You don’t need to know how it works, but if you have some spare time it can be interesting to read through the page Understanding QMK’s Code in the documentation.

It’s likely you don’t yet have a matrix_scan_user function in your keymap.c file. You can add the following snippet to add it:

LEADER_EXTERNS();

void matrix_scan_user(void) {
  LEADER_DICTIONARY() {
    leading = false;
    leader_end();

    // Replace the sequences below with your own sequences.
    SEQ_ONE_KEY(KC_T) {
      // When I press KC_LEAD and then T, this sends CTRL + SHIFT + T
      SEND_STRING(SS_LCTRL(SS_LSFT("t")));
    }
    // Note: This is not an array, you don't need to put any commas
    // or semicolons between sequences.
    SEQ_TWO_KEYS(KC_N, KC_T) {
      // When I press KC_LEAD and then N followed by T, this sends CTRL + T
      SEND_STRING(SS_LCTRL("t"));
    }
  }
}

It’s important to include LEADER_EXTERNS() directly above the void matrix_scan_user(void) { line. It will expand into some lines of code that are necessary for the Leader Key to work. For advanced users: you can read more about what it does in the file quantum\process_keycode\process_leader.h.

I included the example from earlier that reopens the last closed tab. You can replace it with your own sequences.

Add your sequences

There are a five functions available to define your sequences with: SEQ_ONE_KEY, SEQ_TWO_KEYS, SEQ_THREE_KEYS, SEQ_FOUR_KEYS and lastly SEQ_FIVE_KEYS. These functions allow you to use up to five keys in a sequence.

You can do anything in a sequence that you can also do in a macro. This includes registering keycodes with register_code(keycode) and unregister_code(keycode). You can also use the very versatile SEND_STRING method. Read more about all it can do in QMK’s Macro documentation.

Some important things to know about Leader Key sequences:

  • You can reuse keycodes in your sequences. If you’d like to have a sequence in which you tap F three times, you can: SEQ_THREE_KEYS(KC_F, KC_F, KC_F).
  • The keycodes you use in a sequence can come from any layer. If you’d want to use SEQ_TWO_KEYS(KC_D, KC_F1) but your F1 key is used in another layer, that’s fine. Do keep in mind the time to complete your sequences is limited (though configurable).
  • Your sequences don’t need to be unique, but it’s a good idea to do so. If you have two sequences like SEQ_ONE_KEY(KC_A), they’ll both do their thing when you press LEAD > A, but you might as well put all your logic in a single sequence instead of duplicating it.

Configuring your leader key

There are a few ways with which you can configure and customize how your Leader Key behaves.

Increasing the timeout

The first and easiest customization is to alter the timeout. You should have this line somewhere in your config.h:

#define LEADER_TIMEOUT 300

Simply set 300 to another number in milliseconds to prolong or shorter the timeout. Keep in mind that any sequence, no matter the number of keys, will run your logic after LEADER_TIMEOUT milliseconds. If you have a high timeout but relatively short sequences, you’d still have to wait for the timeout before your logic happens.

Use per key timing

When you have sequences of varying length, for instance a sequence with only a single key and a sequence with five keys, it can be difficult to hit them all within the defined LEADER_TIMEOUT. Since your logic is only ran after the timeout expires, it can be annoying to have to wait for too long.

To solve this problem, you can make use of Per Key Timing. This will reset the timeout each time you press a button, giving you more time to input longer sequences while still timing out shorter sequences with an acceptable wait.

How much time you have to input your sequences differs depending on whether you use the default versus using Per Key Timing.

To use Per Key Timing, simply include #define LEADER_PER_KEY_TIMING in your config.h file.

When using Per Key Timing, the define LEADER_TIMEOUT will still be used. You will probably want to lower this value, since the timeout will now be reset after each keypress. The documentation recommends to use a value lower than 300, such as #define LEADER_TIMEOUT 250.

If you’re already using QMK, it’s a good idea to update your QMK branch with the latest changes. Per Key Timeout was recently updated through pull request 4026: Per Key Leader Timing Option, at the time of writing the last update was at 15 december 2018.

Doing something when starting or ending a sequence

The Leader Key feature gives you two functions to hook your own logic into: leader_start(void) and leader_end(void). When you one or both functions in your keymap, they’ll automatically be called at the appropriate times.

The leader_start and leader_end functions are yours to implement.

The leader_start() function will be called when you press the leader key down. The leader_end() function will be called right before your sequences are ran. Of note: The leader_start() function is called from within QMK, but the leader_end() is called from within your own keymap. You may choose to call it after handling your sequences, or you may call it multiple times.

To add these two functions to your keymap, include them somewhere within keymap.c:

void leader_start(void) {
  // Add your code to run when pressing the leader key here
}

void leader_end(void) {
  // Add your code to run when a leader key sequence ends here
}

Use Strict Key Processing

In a recent update (pull request 4662, merged 21 december 2018), the option #define LEADER_KEY_STRICT_KEY_PROCESSING was introduced. If you’d like to be able to define your sequence as SEQ_ONE_KEY(LT(3, KC_A)) instead of as SEQ_ONE_KEY(KC_A), you should now be able to do that.

If you’re starting out, you probably won’t need to worry about it: using normal keycodes is fine and works for most people. If you do need to define your sequences to be this nitty gritty, do read the Strict Key Processing part of the documentation.

Examples

We’ve already discussed a few shorts examples of what you can do with the Leader Key. Let’s see how it comes together and what more you can do with the Leader Key.

Mnemonic shortcuts

This isn’t a code example, but a guideline of how you can more easily remember your shortcuts.

A mnemonic is a system or pattern which helps in remembering something. In this case, it helps to think of what you intend to do. Do you want to close a tab? You can pick the first letter of each word, in this case Close Tab. Then you could use these two letters in your sequence, so you could press LEAD > C > T to Close a Tab.

If you’re used to the Windows operating system, you may have noticed some letters get highlighted when you press ALT. The way this is done is also a form of mnemonics. In the screenshot below, I pressed ALT > F to open the File menu. I can press more letters to invoke various menu items, such as O for Open File.

Selecting a menu item by pressing ALT and then highlighted letters in many Windows applications. In this example, I pressed ALT > F to open the File menu. You don’t need a Leader Key for this, but you can send keys with the Leader Key to use menu items with.

You can apply this system to your own sequences to more easily remember them. Feel free to choose a system that works for you, you can customize it to be just the way you want!

Reopening a tab in Chrome

If you’ve followed the steps above, you may have already pasted this example into your keymap. For completeness, I’ll include it in this samples section as well:

LEADER_EXTERNS();

void matrix_scan_user(void) {
  LEADER_DICTIONARY() {
    leading = false;
    leader_end();

    // Replace the sequence below with your own sequences.
    SEQ_ONE_KEY(KC_T) {
      // When I press KC_LEAD and then T, this sends CTRL + SHIFT + T
      SEND_STRING(SS_LCTRL(SS_LSFT("t")));
    }
  }
}

You can do anything here you can also do in a macro. Read more about Macros in the QMK documentation.

Doing something when no sequence was matched

Normally you don’t get feedback about whether a Leader Key sequence was succesful. If the keys you pressed match a sequence, QMK will execute whatever code you had in your sequence, but if your pressed keys did not match a sequence, there’s no way to know.

We can fix that by making some modifications to our Leader Key handling code in keymap.c by keeping track of whether it matched any sequence, and handling it afterwards:

LEADER_EXTERNS();

// Declare a boolean variable to keep track of whether any sequence
// will have been matched.
bool did_leader_succeed;

void matrix_scan_user(void) {
  LEADER_DICTIONARY() {
    // Initialize did_leader_succeed as well as leading to be false
    did_leader_succeed = leading = false;

    // Replace the sequences below with your own sequences.
    SEQ_ONE_KEY(KC_T) {
      SEND_STRING(SS_LCTRL(SS_LSFT("t")));
      // In each sequence, set our flag to true. This way, we'll
      // know when any sequence was matched.
      did_leader_succeed = true;
    }
    SEQ_TWO_KEYS(KC_N, KC_T) {
      SEND_STRING(SS_LCTRL("t"));
      did_leader_succeed = true;
    }

    // Call leader_end at the end of the function, instead of at
    // the start. This way, we're sure we have set did_leader_succeed.
    leader_end();
  }
}

void leader_end(void) {
  if (did_leader_succeed) {
    // If any sequence was matched, did_leader_succeed will have
    // been set to true up in the matrix_scan_user function.
    // Put your code for a matched leader key sequence here.
  } else {
    // If no sequence was matched, did_leader_succeed will not
    // have been set to true anywhere, so we'll end up here.
    // Put your code for an unmatched leader key sequence here.
  }
}

In the leader_end() function, you could choose to flash some LEDs with the RGB Lighting or RGB Matrix features, or by manually adding a LED to your keyboard. You could also sound a beep with the Audio feature.

Conclusion

You’ve learned how the Leader Key works, how to add it to your keymap and how to use and customize it.

You can do any things within Leader Key sequences that you can also do in macros. Unlike macros, the system to assign shortcuts using sequences makes the Leader Key very powerful and customizable, and can make the shortcuts easier to remember to boot.

Also unlike macros, you need to press at least two keys instead of the single key that a macro requires. If you have plenty of keys available or are fine with having them on a layer, macros are just as powerful. If you have a lot of macros or want to be able to remember them more easily, the Leader Key may be for you.

Further reading

New to QMK, or in for a refresher? In this series of tutorials on QMK Basics, you’ll be brought up to speed on a number of features that help you customize your keyboard just the way you want it.