Diving into keyboard customisation with QMK.
My new keyboard arrived and I only had a few days to try it out before going on holiday for a week. That was long enough to discover the limitations of the VIA programming portal and get stuck in with customising the QMK firmware.
Now that I am back from holiday I want to experiment with some more complex customisation. First though, a recap of building and flashing the firmware.
Replacing the Firmware
The Keychron K15 Pro firmware is a fork of QMK and is available on Github. The most recent code
seems to be on the wireless_playground
branch and, yes, my keyboard is there in
keyboards/keychron/k15_pro
.
Rebuilding the Firmware
There is a detailed tutorial for getting started with QMK firmware and on macOS it is really straightforward. There is a homebrew package for the qmk cli which is used to set up a cross compilation tool chain and build the QMK firmware.
The first step is to install the qmk
cli and the qmk-toolbox
which can be used for flashing
the firmware:
brew install qmk/qmk/qmk
brew install qmk-toolbox
Next, run QMK setup to prepare the tool chain. It would normally clone the qmk_firmware
repo
but I already have the keychron repo ready so I ran the setup step from there:
cd qmk_firmware
qmk setup
I have a K15 Pro keyboard with ANSI encoder and RGB matrix lighting so the keyboard I want to
compile is keychron/k15_pro/ansi_encoder/rgb
and I used the default keymap for now:
qmk compile -kb keychron/k15_pro/ansi_encoder/rgb -km default
This builds a new firmware image that is ready to flash.
Flashing the Firmware
It is possible to flash the keyboard either using qmk-toolbox or by using the qmk
cli like I
did here. The keyboard first needs to be in firmware update mode by holding down the Esc
key
and switching the keyboard on (in USB wired mode).
qmk flash keychron_k15_pro_ansi_encoder_rgb_default.bin
After flashing completes, the keyboard will reboot with the new firmware.
Creating My Own Keymap
I configured the build environment for my keyboard and created a new keymap for myself:
qmk config user.keyboard=keychron/k15_pro/ansi_encoder/rgb
qmk config user.keymap=donaldh
qmk new-keymap
The qmk new-keymap
command copied the K15 Pro default keymap to a new keymap in my name, ready
for me to customise. I then edited keymap.c
for this keymap to incorporate the layout
modifications I had previously made using the VIA portal:
@@ -27,18 +28,18 @@ enum layers{
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[MAC_BASE] = LAYOUT_90_ansi(
KC_MUTE, KC_ESC, KC_BRID, KC_BRIU, KC_MCTL, KC_LPAD, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_INS, KC_DEL,
- MC_1, 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_PGUP,
- MC_2, 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_PGDN,
- MC_3, 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_ENT, KC_HOME,
+ A(KC_6), 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_HOME,
+ MC_2, 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_PGUP,
+ MC_3, 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_ENT, KC_PGDN,
MC_4, KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP,
MC_5, KC_LCTL, KC_LOPTN, KC_LCMMD, KC_SPC, MO(MAC_FN), KC_SPC, KC_RCMMD, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT),
[MAC_FN] = LAYOUT_90_ansi(
RGB_TOG, _______, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, _______, _______,
- _______, _______, BT_HST1, BT_HST2, BT_HST3, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
- _______, RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______, _______, _______, _______, _______,
- _______, _______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, _______, _______, _______, _______, _______, _______, _______, _______,
- _______, _______, _______, _______, _______, _______, BAT_LVL, BAT_LVL, NK_TOGG, _______, _______, _______, _______, _______, _______,
+ _______, _______, BT_HST1, BT_HST2, BT_HST3, _______, _______, _______, KC_P7, KC_P8, KC_P9, _______, _______, _______, _______, KC_END,
+ _______, RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, KC_P4, KC_P5, KC_P6, _______, _______, _______, _______, _______,
+ _______, _______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, _______, KC_P1, KC_P2, KC_P3, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, BAT_LVL, _______, _______, KC_P0, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______),
RGB Lighting
I started to experiment with toggling layers in the keymap and the first thing I noticed is that you lose track of which layer is active when there is no visual feedback. So I set about working out how to add some custom RGB lighting to indicate which layer is active.
It turns out that examples of this are provided in the RGB matrix docs. I chose to try out the code example that sets an indicator on "keys with configured keycodes", with a slight tweak to turn off the default RGB lighting for the remaining keys:
bool rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
if (get_highest_layer(layer_state) > 0) {
uint8_t layer = get_highest_layer(layer_state);
for (uint8_t row = 0; row < MATRIX_ROWS; ++row) {
for (uint8_t col = 0; col < MATRIX_COLS; ++col) {
uint8_t index = g_led_config.matrix_co[row][col];
if (index >= led_min && index < led_max && index != NO_LED) {
if (keymap_key_to_keycode(layer, (keypos_t){col,row}) > KC_TRNS) {
rgb_matrix_set_color(index, RGB_GREEN);
} else {
rgb_matrix_set_color(index, RGB_BLACK);
}
}
}
}
}
return false;
}
That was surprisingly easy and the result is just what I was hoping for:
Next Steps
The default fn
layer for this keyboard is busy with a lot of RGB keys on the left half. I
don't expect to use them very much so I plan to move them to a separate layer and free up some
space for more commonly used things.