Keyboard Week Two

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:

backlit-fn-layer.jpg

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.

nerdism  oss