Ramblings of an aging IT geek
← Ramblings of an aging IT geek
hardware

a mechanical keyboard build, down to the firmware

Building a 60% mechanical keyboard from a kit, soldering the switches, and flashing custom QMK firmware to get the layers and macros I actually wanted.

A keyboard PCB being soldered on a workbench

I have wanted a keyboard that fits my hands rather than the other way round for years. The compromise I had been living with was a full-size board where I never touched the numpad and my right hand had to make a small journey every time I wanted the arrow keys. So I built a 60% board from a kit, soldered it myself, and flashed firmware I could actually change. This is the writeup, soldering iron burns and all.

the kit

A 60% layout drops the function row, the numpad, the arrow cluster and the navigation block, and gives all of that back to you through a function layer. The kit was the usual suspects: a PCB, a plate, a case, a set of stabilisers, and the switches and keycaps bought separately because that is half the fun and all of the rabbit hole.

I went with tactile switches rather than the clicky ones, on the grounds that I work in the same room as other people and would like to keep working in the same room as other people. The board is hot-swap-less, meaning the switches solder directly to the PCB, which raised the stakes on the soldering and meant I wanted to get the firmware decisions roughly right before committing 61 switches permanently.

stabilisers first

The single best piece of advice I was given: sort the stabilisers before you solder anything. They sit under the larger keys, the spacebar, shift, enter, backspace, and a rattly stabiliser is the thing that will annoy you every day for the life of the board. So they got clipped, lubed, and band-aid-modded before the switches went anywhere near the plate. Tedious, fiddly, absolutely worth it.

A close-up of a keyboard circuit board

soldering 61 switches

Then the long bit. Switches clip into the plate, the plate sits on the PCB, every pin gets a touch of solder. Sixty-one switches, two pins each, so a hundred and twenty-two joints, and you really do not want to discover a cold joint after the case is screwed shut. My routine settled into: do a row, test continuity, move on.

A few things I learned the hard way:

  • Seat every switch fully into the plate before soldering any of them, or you get a board with one key sitting proud and no graceful way to fix it.
  • A cheap iron is a false economy. Temperature control is the difference between a clean joint and a grey lump.
  • Test as you go. Tweezers shorting a switch's pins should register a keypress once the board is flashed, and finding a dead column early is far better than finding it late.

By the end the soldering was almost meditative, which is not a sentence I expected to write at switch number twelve when I burnt my thumb.

Another close-up of the assembled board

the firmware is the actual point

Here is where it stops being a soldering project and becomes a computing one. The board runs QMK, the open firmware that lets you define exactly what every key does, including layers, macros, tap-versus-hold behaviour, and the lot. You describe your layout in C, compile it, and flash it over USB.

My layout is built around a function layer triggered by holding a key that is otherwise Caps Lock, because Caps Lock is wasted real estate and sits right where my little finger lives.

#include QMK_KEYBOARD_H

#define _BASE 0
#define _FN   1

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [_BASE] = LAYOUT_60_ansi(
        KC_GESC, 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_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,
        MO(_FN), 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_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT,
        KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(_FN), KC_RCTL
    ),
    [_FN] = LAYOUT_60_ansi(
        KC_GRV,  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_DEL,
        _______, _______, KC_UP, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
        _______, KC_LEFT, KC_DOWN, KC_RGHT, _______, _______, _______, _______, _______, _______, _______, _______, _______,
        _______, _______, _______, _______, _______, _______, _______, _______, KC_VOLD, KC_VOLU, KC_MUTE, _______,
        _______, _______, _______, _______, _______, _______, _______
    )
};

MO(_FN) means momentary layer: hold it and the second map applies, so the arrows live under WASD-ish positions on my right hand and the volume keys sit under the bottom row. KC_GESC is grave-escape, Escape on its own and backtick with shift, which on a board with no dedicated escape key is the small touch that makes it usable.

Compiling and flashing is the satisfying bit. make my_keyboard:default, hold the reset, and the new layout is live in seconds. The first time I changed the arrow layer, decided I hated it, and reflashed a better one inside a minute, I understood why people fall down this hole. The keyboard is no longer a fixed object. It is a small program I happen to type on.

was it worth it

Two evenings, one burnt thumb, and a board that does exactly what I want. The typing feel is better than anything I have bought, the layout fits my hands, and the firmware means I can change my mind whenever I like. The arrow keys are under my right hand where they belong and the numpad I never used is simply gone.

If you have ever caught yourself fighting a keyboard's layout instead of using it, build one. The soldering is learnable in an evening and the firmware is where it gets genuinely good.