QMK: The Subtle Art of Key Overrides

Posted on Jan 15, 2024 (updated on Jan 31, 2024)

The power of QMK

Introduction #

As a newcomer to QMK, I initially relied heavily on the Oryx configurator. I wasn’t too keen on complicating things without a good reason, and it would give me the opportunity to slowly discover the wonderful world of QMK. Plus, the immediate feedback from configuring and flashing my keyboard layout directly via Chrome was quite satisfying. It’s said that a picture is worth a thousand words, but in this case, a graphical user interface was worth a thousand key presses.

My keyboard layout has now reached a point of stability, marking the end of a phase of constant changes. The transition from my R-Go Split, with its luxurious array of 80 keys, to the ZSA Voyager’s modest 52 keys, felt like moving from a mansion to a cozy studio apartment. And at the same time, in a burst of reckless enthusiasm, I embraced Colemak-DH. Who knew that rearranging 52 pieces of plastic could feel like solving a Rubik’s Cube in the dark?

Going Full QMK #

Oryx has been a user-friendly gateway into the world of QMK for beginners like me. Its intuitive design allowed me to experiment with various configurations without the fear of bricking my keyboard. However, as comforting as Oryx was, it’s akin to swimming with floaties in the shallow end of the pool. The real excitement lies in the deep end - diving into the source code of QMK and discovering its true power.

In the realm of user interface design, one is inevitably bound to the constraints of representing features visually. If you cannot visualise it, you cannot build it. Take, for example, the feature Leader Keys. It is currently not supported in Oryx, and it’s uncertain whether it’ll ever make a visual debut. When delving into source code, the focus shifts primarily to behavior. The central question becomes: does the code perform as intended?

The initial task on my agenda is transforming my backspace key into a delete key when combined with the shift modifier. You can configure this in Oryx, although it requires a bit of extra legwork:

  • Create a new layer
  • Replace the backspace with a delete key
  • Replace the shift keys on the base layer with Momentary Layer Toggles to activate our freshly created layer and enable the shift modifier

It’s manageable, but given my eagerness to experiment with Leader Keys, venturing into the depths of QMK was an unavoidable path.

Key Overrides #

Riding the bike of QMK customization can be a breeze, but beware of the occasional pothole. My particular pothole was the intriguing Key Overrides feature. Follow the guide for a basic keymap, and you’ll find yourself humming a tune of triumph in no time:

C
// Shift + esc = ~
const key_override_t tilde_esc_override = ko_make_basic(MOD_MASK_SHIFT, KC_ESCAPE, S(KC_GRV));

// This globally defines all key overrides to be used
const key_override_t **key_overrides = (const key_override_t *[]){
    &tilde_esc_override,
    NULL // Elegantly ending the array of overrides
};

But as my key matrix grew more complex, like a plot in a mystery novel, it became clear that the key override needed to match the keymap precisely. I used the escape key as a hyper key (ALL_T(kc)), and the key override needed to be a mirror image:

C
// Shift + esc = ~
const key_override_t tilde_esc_override = ko_make_basic(MOD_MASK_SHIFT, ALL_T(KC_ESCAPE), S(KC_GRV));

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [0] = LAYOUT_voyager(ALL_T(KC_ESCAPE), // A mirror image of the override above
          ...
}

Conclusion #

In summary, it’s crucial to have a precise match between the key override and the key’s definition in the keymap. Otherwise, you may find yourself puzzled as to why your key overrides aren’t functioning as expected.