Adding Default Keymaps to QMK Configurator
This page covers how to add a default keymap for a keyboard to QMK Configurator.
Technical Information
QMK Configurator uses JSON as its native file format for keymaps. As much as possible, these should be kept such that they behave the same as running make <keyboard>:default
from qmk_firmware
.
Keymaps in this directory require four key-value pairs:
keyboard
(string)- This is the name of the keyboard, the same as would be used when running a compile job through
make
(e.g.make 1upkeyboards/1up60rgb:default
).
- This is the name of the keyboard, the same as would be used when running a compile job through
keymap
(string)- Should be set to
default
.
- Should be set to
layout
(string)- This is the layout macro used by the default keymap.
layers
(array)- The keymap itself. This key should contain one array per layer, which themselves should contain the keycodes that make up that layer.
Additionally, most keymaps contain a commit
key. This key is not consumed by the API that back-stops QMK Configurator, but is used by Configurator's maintainers to tell which version of a keymap was used to create the JSON keymap in this repository. The value is the SHA of the last commit to modify a board's default keymap.c
in the qmk_firmware
repository. The SHA is found by checking out the master
branch of the qmk/qmk_firmware
repository and running git log -1 --pretty=oneline -- keyboards/<keyboard>/keymaps/default/keymap.c
(use keymap.json
if the keyboard in question has this file instead), which should return something similar to:
f14629ed1cd7c7ec9089604d64f29a99981558e8 Remove/migrate action_get_macro()s from default keymaps (#5625)
In this example, f14629ed1cd7c7ec9089604d64f29a99981558e8
is the value that should be used for commit
.
Example
If one wished to add a default keymap for the H87a by Hineybush, one would run the git log
command above against the H87a's default keymap in qmk_firmware
:
user ~/qmk_firmware (master)
$ git log -1 --pretty=oneline master -- keyboards/hineybush/h87a/keymaps/default/keymap.c
ef8878fba5d3786e3f9c66436da63a560cd36ac9 Hineybush h87a lock indicators (#8237)
Now that we have the commit hash, we need the keymap (edited for readability):
...
#include QMK_KEYBOARD_H
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = LAYOUT_all(
KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_PSCR, KC_SCRL, KC_PAUS,
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_BSPC, KC_INS, KC_HOME, KC_PGUP,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_DEL, KC_END, KC_PGDN,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_NUHS, KC_ENT,
KC_LSFT, KC_NUBS, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_TRNS, KC_UP,
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(1), KC_RGUI, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT),
[1] = LAYOUT_all(
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, UG_TOGG, UG_NEXT, UG_HUED, UG_HUEU, UG_SATD, UG_SATU, UG_VALD, UG_VALU, BL_TOGG, BL_DOWN, BL_UP,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_VOLU,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, QK_BOOT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_MPLY, KC_MNXT, KC_VOLD,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS),
};
The default keymap uses the LAYOUT_all
macro, so that will be the value of the layout
key. Compiled to a QMK Configurator JSON keymap, our resulting file should be:
{
"keyboard": "hineybush/h87a",
"keymap": "default",
"commit": "ef8878fba5d3786e3f9c66436da63a560cd36ac9",
"layout": "LAYOUT_all",
"layers": [
[
"KC_ESC", "KC_F1", "KC_F2", "KC_F3", "KC_F4", "KC_F5", "KC_F6", "KC_F7", "KC_F8", "KC_F9", "KC_F10", "KC_F11", "KC_F12", "KC_PSCR", "KC_SCRL", "KC_PAUS",
"KC_GRV", "KC_1", "KC_2", "KC_3", "KC_4", "KC_5", "KC_6", "KC_7", "KC_8", "KC_9", "KC_0", "KC_MINS", "KC_EQL", "KC_BSPC", "KC_BSPC", "KC_INS", "KC_HOME", "KC_PGUP",
"KC_TAB", "KC_Q", "KC_W", "KC_E", "KC_R", "KC_T", "KC_Y", "KC_U", "KC_I", "KC_O", "KC_P", "KC_LBRC", "KC_RBRC", "KC_BSLS", "KC_DEL", "KC_END", "KC_PGDN",
"KC_CAPS", "KC_A", "KC_S", "KC_D", "KC_F", "KC_G", "KC_H", "KC_J", "KC_K", "KC_L", "KC_SCLN", "KC_QUOT", "KC_NUHS", "KC_ENT",
"KC_LSFT", "KC_NUBS", "KC_Z", "KC_X", "KC_C", "KC_V", "KC_B", "KC_N", "KC_M", "KC_COMM", "KC_DOT", "KC_SLSH", "KC_RSFT", "KC_TRNS", "KC_UP",
"KC_LCTL", "KC_LGUI", "KC_LALT", "KC_SPC", "KC_RALT", "MO(1)", "KC_RGUI", "KC_RCTL", "KC_LEFT", "KC_DOWN", "KC_RGHT"
],
[
"KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "UG_TOGG", "UG_NEXT", "UG_HUED", "UG_HUEU", "UG_SATD", "UG_SATU", "UG_VALD", "UG_VALU", "BL_TOGG", "BL_DOWN", "BL_UP",
"KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_VOLU",
"KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "QK_BOOT", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_MPLY", "KC_MNXT", "KC_VOLD",
"KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS",
"KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS",
"KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS", "KC_TRNS"
]
]
}
The white space in the layers
arrays have no effect on the functionality of the keymap, but are used to make these files easier for humans to read.
Caveats
Layers can only be referenced by number
A common QMK convention is to name layers using a series of #define
s, or an enum
statement:
enum layer_names {
_BASE,
_MEDIA,
_FN
};
This works in C, but for Configurator, you must use the layer's numeric index – MO(_FN)
would need to be MO(2)
in the above example.
No support for custom code of any kind
Features that require adding functions to the keymap.c file, such as Tap Dance or Unicode, can not be compiled in Configurator at all. Even setting TAP_DANCE_ENABLE = yes
in the qmk_firmware
repository at the keyboard level will prevent Configurator from compiling any firmware for that keyboard. This is limited both by the API and the current spec of our JSON keymap format.
Limited Support for Custom keycodes
There is a way to support custom keycodes: if the logic for a custom keycode is implemented at the keyboard level instead of the keymap level in qmk_firmware, that keycode can be used in Configurator and it will compile and work. Instead of using the following in your keymap.c
:
enum custom_keycodes {
CUSTOM_1 = SAFE_RANGE,
CUSTOM_2,
CUSTOM_3
};
...
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch(keycode) {
case CUSTOM_1:
if (record->event.pressed) {
SEND_STRING("This is custom keycode #1.");
}
return false;
case CUSTOM_2:
if (record->event.pressed) {
SEND_STRING("This is custom keycode #2.");
}
return false;
case CUSTOM_3:
if (record->event.pressed) {
SEND_STRING("This is custom keycode #3.");
}
return false;
}
return true;
};
... add the keycode enum
block to your keyboard's header file (<keyboard>.h
) as follows (note that the enum
is named keyboard_keycodes
here):
enum keyboard_keycodes {
CUSTOM_1 = QK_KB_0,
CUSTOM_2,
CUSTOM_3,
};
... then the logic to your <keyboard>.c
through process_record_kb()
:
bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
switch(keycode) {
case CUSTOM_1:
if (record->event.pressed) {
SEND_STRING("This is custom keycode #1.");
}
return false;
case CUSTOM_2:
if (record->event.pressed) {
SEND_STRING("This is custom keycode #2.");
}
return false;
case CUSTOM_3:
if (record->event.pressed) {
SEND_STRING("This is custom keycode #3.");
}
return false;
}
return process_record_user(keycode, record);
};
Note the call to process_record_user()
at the end.
Additional Reading
For QMK Configurator to support your keyboard, your keyboard must be present in the master
branch of the qmk_firmware
repository. For instructions on this, please see Supporting Your Keyboard in QMK Configurator.