QMK Firmware

Setting up a layer

Step 1: Declare

Create each layer as an entry in an enum. Replace YOUR_LAYER_1, YOUR_LAYER_2, etc., below, with names of your layers.

// Layer Declarations
enum {
    YOUR_LAYER_1 = 0,
    YOUR_LAYER_2,
    // ..., the rest of your layers
};

Step 2: Define

Add the keycodes for each layer into the keymaps array, by calling KEYMAP() for each layer.

// Layer Definitions
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {

  [YOUR_LAYER_1] = KEYMAP(
    // ... list all your keycodes here, separating each with comma
  ),

  [YOUR_LAYER_2] = KEYMAP(
    // ... list all your keycodes here, separating each with comma
  ),

  // ..., the rest of your layers

};

Step 3: Use

Here are a variety of ways to change the layer.

Keycode Description
MO(YOUR_LAYER)
While held, MOmentarily switch to YOUR_LAYER.
LT(YOUR_LAYER, KC_XXXX)
Layer Tap. When held: go to YOUR_LAYER.
When tapped: send KC_XXXX
TG(YOUR_LAYER)
Layer Toggle. When tapped, toggles YOUR_LAYER on or off
TO(YOUR_LAYER)
When tapped, goes to YOUR_LAYER
TT(YOUR_LAYER)
When tapped, toggles YOUR_LAYER on or off.
When held, activates YOUR_LAYER.
OSL(YOUR_LAYER)
One-Shot Layer. Goes to YOUR_LAYER for the next keypress

Light LEDs according to layer

Create a function called matrix_scan_user, and add a case for each layer. Note, you will have to look up which function your keyboard calls to turn LEDs on/off, and insert them to the code, below.

// Runs constantly in the background, in a loop.
void matrix_scan_user(void) {

    uint8_t layer = biton32(layer_state);

    // INSERT CODE HERE: turn off all leds

    switch (layer) {
        case YOUR_LAYER_1:
            // INSERT CODE HERE: turn on leds that correspond to YOUR_LAYER_1
            break;
        case YOUR_LAYER_2:
            // INSERT CODE HERE: turn on leds that correspond to YOUR_LAYER_2
            break;
        // add case for each layer
    }
};

Modifier Keycode Functions

Keycode Description
LSFT(KC_XXXX)
applies left Shift to KC_XXXX (keycode) - S(KC_XXXX) is an alias
RSFT(KC_XXXX)
applies right Shift to KC_XXXX
LCTL(KC_XXXX)
applies left Control to KC_XXXX
RCTL(KC_XXXX)
applies right Control to KC_XXXX
LALT(KC_XXXX)
applies left Alt to KC_XXXX
RALT(KC_XXXX)
applies right Alt to KC_XXXX
LGUI(KC_XXXX)
applies left GUI (command/win) to KC_XXXX
RGUI(KC_XXXX)
applies right GUI (command/win) to KC_XXXX
HYPR(KC_XXXX)
applies Hyper (all modifiers) to KC_XXXX
MEH(KC_XXXX)
applies Meh (all modifiers except Win/Cmd) to KC_XXXX
LCAG(KC_XXXX)
applies CtrlAltGui to KC_XXXX

You can also chain these, like this: LALT(LCTL(KC_DEL)) -- this makes a key that sends Alt, Control, and Delete in a single keypress.

Modifier Special Functions

Keycode Description
MT(MOD_XXXX, KC_XXXX)
When held, activate modifier XXXX (see below)
When tapped, send KC_XXXX.
OSM(MOD_XXXX)
Activate modifier XXXX (see below) for the next key pressed.

Modifiers

You may use any of the following modifiers in the above special functions.

  • MOD_LCTL
  • MOD_LSFT
  • MOD_LALT
  • MOD_LGUI
  • MOD_RCTL
  • MOD_RSFT
  • MOD_RALT
  • MOD_RGUI
  • MOD_HYPR
  • MOD_MEH

Step 1: Declare

Create an entry for each macro in an enum. Replace YOUR_MACRO_1, YOUR_MACRO_2, etc., below, with the names of your macros.

// Macro Declarations
enum {
    YOUR_MACRO_1 = 0,
    YOUR_MACRO_2,
    // ..., the rest of your macros
};

Step 2: Define

// Macro Definitions
const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
{
  switch(id) {

    // for basic strings
    case YOUR_MACRO_1: {
        if (record->event.pressed) {
            SEND_STRING("YOUR_STRING_HERE"); // REPLACE with what you want your macro to be
            return false;
        }
    }

    // for more complex macros (want to add modifiers, etc.)
    case YOUR_MACRO_1: {
      if (recond->event.pressed) {
          // INSERT CODE HERE for your macro. See full documentation for details and functions
      }
    }


    //
  }
  return MACRO_NONE;
};

Step 3: Use

M(YOUR_MACRO_1)

Record and play back sequences of keystrokes. Note: macros are not kept in memory after the keyboard is unplugged.

Step 1: Setup

enum planck_keycodes {
    QWERTY = SAFE_RANGE,
    COLEMAK,
    DVORAK,
    PLOVER,
    LOWER,
    RAISE,
    BACKLIT,
    EXT_PLV,
    DYNAMIC_MACRO_RANGE,
};

// this is called when dynamic macro buffer is full
void backlight_toggle(void) {
    // INSERT CODE HERE: for example, call function to turn on indicator LED.
}

#include "dynamic_macro.h"`
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    if (!process_record_dynamic_macro(keycode, record)) {
        return false;
    }
    return true;
}

Step 2: Use

Keycode Description
DYN_REC_START1
Start recording Macro 1
DYN_REC_START2
Start recording Macro 2
DYN_REC_STOP
Stop recording current Macro
DYN_MACRO_PLAY1
Replay Macro 1
DYN_MACRO_PLAY2
Replay Macro 2

Send different key codes depending on how many times key is tapped. Tap key once does one thing, tap twice does another thing, etc.

Step 1: Setup

TAP_DANCE_ENABLE = yes
#define TAPPING_TERM 200

Step 2: Declare

Create an entry for each tap dance in an enum. Replace YOUR_TAPDANCE_1, YOUR_TAPDANCE_2, etc., with the names of your tap dances.

// Tap Dance Declarations
enum {
    YOUR_TAPDANCE_1 = 0,
    YOUR_TAPDANCE_2,
    // ..., the rest of your tap dances
};

Step 3: Define

// Tap Dance Definitions
qk_tap_dance_action_t tap_dance_actions[] = {
    // simple tap dance
    [YOUR_TAPDANCE_1] = ACTION_TAP_DANCE_DOUBLE(KC_XXXX, KC_YYYY), // replace with your keycodes. BASIC codes only, no custom codes.

    // complex tap dance function (to specify what happens when key is pressed 3+ times, for example). See full docs for how to define
    [YOUR_TAPDANCE_2] = ACTION_TAP_DANCE_FN(your_function_name),
};

Step 4: Use

TD(YOUR_TAPDANCE_1)

Control your mouse with the keyboard.

Step 1: Setup

MOUSEKEY_ENABLE = yes
#define MOUSEKEY_DELAY                              300
#define MOUSEKEY_INTERVAL                           50
#define MOUSEKEY_MAX_SPEED                          10
#define MOUSEKEY_TIME_TO_MAX                        20
#define MOUSEKEY_WHEEL_MAX_SPEED                    8
#define MOUSEKEY_WHEEL_MAX_TIME_TO_MAX              40

Step 2: Use

Keycode Description
KC_MS_UP
Mouse Cursor Up
KC_MS_DOWN
Mouse Cursor Down
KC_MS_LEFT
Mouse Cursor Left
KC_MS_RIGHT
Mouse Cursor Right
KC_MS_BTN1
Mouse Button 1
KC_MS_BTN2
Mouse Button 2
KC_MS_BTN3
Mouse Button 3
KC_MS_BTN4
Mouse Button 4
KC_MS_BTN5
Mouse Button 5
KC_MS_WH_UP
Mouse Wheel Up
KC_MS_WH_DOWN
Mouse Wheel Down
KC_MS_WH_LEFT
Mouse Wheel Left
KC_MS_WH_RIGHT
Mouse Wheel Right
KC_MS_ACCEL0
Set Mouse Acceleration Speed to 0
KC_MS_ACCEL1
Set Mouse Acceleration Speed to 1
KC_MS_ACCEL2
Set Mouse Acceleration Speed to 2

Set up your keyboard to input Unicode, working through additional, required software.

NOTE: The instructions here only apply for characters up to 0xFFFF. For higher characters, please consult the official docs.

Prerequisites: Configure OS and Software

Windows

Install WinCompose.

MacOS

In System Preferences -> Keyboard -> Input Sources ->, add a new layout. In the Others menu, select Unicode Hex Input. Note: Enable Unicode Hex Input each time you want to input Unicode. Check the box for "Show Input menu in menu bar" to switch to this quickly.

Linux

Add the Unicode input method for your distro. Note: Enable Unicode Hex Input each time you want to input Unicode. Should work almost anywhere on ibus enabled distros. Without ibus, this works under GTK apps, but rarely anywhere else.

Step 1: Setup

UNICODE_ENABLE = yes
void matrix_init_user(void) {
    set_unicode_input_mode(UC_XXXX); // REPLACE UC_XXXX with the Unicode Input Mode for your OS. See table below.
};
Unicode Input ModeDescription
UC_WINC
Windows using WinCompose.
UC_OSX
MacOS using Unicode Hex Input. Can also send `UC_OSX_RALT` to use the Right Alt key.
UC_LNX
Linux using Unicode input method.

Step 2: Define

#define STAR 0x2605 // ★
// ...,repeat for all characters

Step 3: Use

UC(STAR)

Press a sequence of keys to trigger functionality, in the style of Vim.

Step 1: Setup

LEADER_ENABLE = yes
LEADER_EXTERNS();

Step 2: Define

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

        // for single key sequences
        SEQ_ONE_KEY(KC_XXXX) {
            // INSERT CODE HERE: anything you can do in a macro
        }

        // for two-key sequences
        SEQ_TWO_KEYS(KC_XXXX, KC_YYYY) {
            // INSERT CODE HERE: anything you can do in a macro
        }

        // for three-key sequences
        SEQ_THREE_KEYS(KC_XXXX, KC_YYYY, KC_ZZZZ) {
            // INSERT CODE HERE: anything you can do in a macro
        }

        // ..., the rest of your Leader Key definitions.
    }
}

Step 3: Use

Tap the `KC_LEAD` followed by the sequence of keys, to access your functionality.

KC_LEAD

See also

Macros