This is my personal userspace for QMK Firmware. It is setup as a self-contained folder that avoids placing keymap.c
files inside keyboard sub-directories. All firmware customisations are configured within this space in the following manner:
- Save QMK Configurator layout or wrapper macro keymaps in JSON format.
- Use shared
rules.mk
,config.h
and source files in this space. - See my standalone userspace guide for more details.
Forking QMK repository can be avoided in this manner: clone the QMK firmware, followed by this repository into users/filterpaper
:
git clone https://github.com/qmk/qmk_firmware qmk_firmware
git clone https://github.com/filterpaper/qmk_userspace qmk_firmware/users/filterpaper
Git updates to users/filterpaper
will be independent from QMK source when setup in this manner.
To build, run qmk compile
on the JSON files in keymaps folder. Example:
qmk compile keymaps/corne.json
- Shared layout wrapper macros
- Combos simplified with preprocessors
- Tap-hold clipboard shortcuts
- OLED indicators and animation
- RGB matrix lighting and effects
- Custom "candy" matrix effect
- Layer indicators of active keys
- Word processing functions
- Caps Word to toggle caps lock following a word
- Autocorrection for typos
Split keyboards use Handedness by EEPROM, and each half is flashed once with the following command:
qmk flash -kb cradio -km default -bl dfu-split-left
qmk flash -kb cradio -km default -bl dfu-split-right
Corne keyboard is configured with a few modular build options using rules.mk:
Minimal firmware with no OLED and RGB support is the default:
qmk compile corne.json
The -OLED=
option will build support for pet animation on primary OLED with status icons on the secondary. Animation are key stroke driven by tap_timer
. To use WPM (at the expense of size), add -e WPM_ENABLE=yes
to the compile commands:
Build and flash each side with the corresponding options for left and right aligned Bongocat:
qmk compile -e OLED=LEFTCAT corne.json
qmk compile -e OLED=RIGHTCAT corne.json
Build for Luna or Felix the dog:
qmk compile -e OLED=LUNA corne.json
qmk compile -e OLED=FELIX corne.json
The -KB=
option will add support for RGB matrix lighting. IMK
value will use under glow LEDs as indicators:
qmk compile -e KB=LP corne.json
qmk compile -e KB=IMK corne.json
Combine -e OLED=
and -e KB=
options to support both features.
Images in glcdfont.c
can be viewed and edited with:
if (get_highest_layer(layer_state); > COLEMAK) {
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) {
if (g_led_config.matrix_co[row][col] != NO_LED &&
keymap_key_to_keycode(layer, (keypos_t){col, row}) != KC_TRNS) {
rgb_matrix_set_color(g_led_config.matrix_co[row][col], RGB_LAYER);
}
}
}
}
Code loops through every row and column on a per-key RGB board, scanning for configured keys (not KC_TRANS
) and lighting that index location. It is configured to activate on non-default layers. This can be further customised using layer switch
condition inside the last if
statement.
#define W_TH LT(0, KC_W)
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case W_TH:
// Unmatched return on tap
if (record->tap.count) { return true; }
// Send macro string on hold
else if (record->event.pressed) { SEND_STRING(":wq"); }
return false;
}
return true; // continue with unmatched keycodes
}
Tap hold shortcuts using layer tap (LT()
) uses less firmware space than tap dance (~35 bytes per shortcut). Macro W_TH
replaces KC_W
on the key map (keymap[]
), and the code will intercept hold function of LT()
to send the macro string. There are more examples in QMK's Intercepting Mod Taps.
The QMK combo code file combos.c
is modified from Germ's helper macros to simplify combo management. New shortcuts are added to combos.inc
as one-liners and preprocessor macros will generate required QMK combo source codes at compile time.
Data LEDs on Pro Micro can be used as indicators with code. They are pins B0
(RX) and D5
(TX) on Atmega32u4. To use them with QMK's LED Indicators, flag the pin in config.h
:
#define LED_CAPS_LOCK_PIN B0
#define LED_PIN_ON_STATE 0
For advance usage, setup the following macros to use both pins with GPIO controls:
// Pro Micro data LED pins
#define RXLED B0
#define TXLED D5
// GPIO control macros
#define RXLED_INIT setPinOutput(RXLED)
#define TXLED_INIT setPinOutput(TXLED)
#define RXLED_ON writePinLow(RXLED)
#define TXLED_ON writePinLow(TXLED)
#define RXLED_OFF writePinHigh(RXLED)
#define TXLED_OFF writePinHigh(TXLED)
Initiate the LEDs and turn them off with:
void matrix_init_user(void) {
RXLED_INIT;
TXLED_INIT;
RXLED_OFF;
TXLED_OFF;
}
LED macros can then be used as indicators like Caps Lock:
void matrix_scan_user(void) {
if (host_keyboard_led_state().caps_lock) {
RXLED_ON; TXLED_ON;
} else {
RXLED_OFF; TXLED_OFF;
}
}
Or as layer indicator:
layer_state_t layer_state_set_user(layer_state_t const state) {
switch(get_highest_layer(state|default_layer_state)) {
case FNC: RXLED_ON; TXLED_ON; break;
case SYM: RXLED_OFF; TXLED_ON; break;
case NUM: RXLED_ON; TXLED_OFF; break;
default: RXLED_OFF; TXLED_OFF;
}
return state;
}
Magic Keycodes swap key MAGIC_TOGGLE_CTL_GUI
can be used as OS toggle, allowing QMK to read its status from the following variable to swap clipboard shortcuts:
paste_keycode = keymap_config.swap_lctl_lgui ? C(KC_V) : G(KC_V);
Text-based key map layout (in keymap.c
format) using JSON file is supported with the use of preprocessor macros. Create each layer as a C macro definition in a layout.h
file. This is an example of a "number" layer for Corne:
#define _NUMB \
_______, _______, KC_1, KC_2, KC_3, _______, KC_HOME, KC_PGDN, KC_PGUP, KC_END, KC_DQUO, _______, \
_______, _______, KC_4, KC_5, KC_6, _______, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT, KC_QUOT, _______, \
_______, _______, KC_7, KC_8, KC_9, KC_0, KC_INS, _______, _______, _______, _______, _______, \
_______, MO(FNC), _______, _______, _______, _______
Next, create a wrapper name in layout.h
that points to the actual layout used by the keyboard, example:
#define CORNE_wrapper(...) LAYOUT_split_3x6_3(__VA_ARGS__)
Finally create the keyboard's JSON file using the macro names for each layer, and the layout wrapper name in the following format:
{
"author": "",
"documentation": "Wrapper based keymap",
"keyboard": "crkbd/rev1",
"keymap": "filterpaper",
"layers": [
[ "_BASE" ],
[ "_NUMB" ],
[ "_SYMB" ],
[ "_FUNC" ]
],
"layout": "CORNE_wrapper",
"notes": "",
"version": 1
}
Add #include layout.h
into config.h
. The build process will construct a transient keymap.c
from JSON file that includes config.h
, and C preprocessor will use macros defined in layout.h
to expand them into the real layout structure in the compile process.
Home row mods can be placed over the layout macros. An example below uses the keyboard matrix layout of crkbd/rev1
with home row keys wrapped by mod-taps:
#define HRM(a) HRM_SACG(a)
#define HRM_SACG( \
k01, k02, k03, k04, k05, k06, k07, k08, k09, k10, k11, k12, \
k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, \
k25, k26, k27, k28, k29, k30, k31, k32, k33, k34, k35, k36 \
k37, k38, k39, k40, k41, k42 \
) \
k01, k02, k03, k04, k05, k06, k07, k08, k09, k10, k11, k12, \
k13, SFT_T(k14), ALT_T(k15), CTL_T(k16), GUI_T(k17), k18, \
k19, GUI_T(k20), CTL_T(k21), ALT_T(k22), SFT_T(k23), k24, \
k25, k26, k27, k28, k29, k30, k31, k32, k33, k34, k35, k36, \
k37, k38, k39, k40, k41, k42
Next, wrap layers that requires home-row mods with HRM()
in the JSON file, making it convenient manage home row mods on multiple layouts:
"layers": [
[ "HRM(_BASE)" ],
[ "HRM(_COLE)" ],
[ "_NUMB" ],
[ "_SYMB" ],
[ "_FUNC" ]
],
Depending compatibility, layouts can be adapted with macros. Corne's split 3x6_3 (6-column, 3-thumb) can be reduced to a split 34-key 3x5_2 (5-column, 2-thumb) with a simple wrapper macro to exclude the outer column and thumb keys:
#define _34key_wrapper(...) LAYOUT(__VA_ARGS__)
// Corne to 34-key layout conversion
#define C_34(k) SPLIT_3x6_3_TO_3x5_2(k)
#define SPLIT_3x6_3_TO_3x5_2( \
k01, k02, k03, k04, k05, k06, k07, k08, k09, k10, k11, k12, \
k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, \
k25, k26, k27, k28, k29, k30, k31, k32, k33, k34, k35, k36, \
k37, k38, k39, k40, k41, k42 \
) \
k02, k03, k04, k05, k06, k07, k08, k09, k10, k11, \
k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, \
k26, k27, k28, k29, k30, k31, k32, k33, k34, k35, \
k38, k39, k40, k41
The JSON layout for 34-key Cradio keyboard uses the macro above to adapt 3x6_3 for 3x5_2:
{
"author": "",
"documentation": "Wrapper based keymap",
"keyboard": "Cradio",
"keymap": "filterpaper",
"layers": [
[ "C_34(HRM(_BASE))" ],
[ "C_34(HRM(_COLE))" ],
[ "C_34(_NUMB)" ],
[ "C_34(_SYMB)" ],
[ "C_34(_FUNC)" ]
],
"layout": "_34key_wrapper",
"notes": "",
"version": 1
}
Connect the USBasp programmer to the target controller in this manner:
USBasp GND <-> Pro Micro GND
USBasp RST <-> Pro Micro RST
USBasp VCC <-> Pro Micro VCC
USBasp SCLK <-> Pro Micro 15/B1 (SCLK)
USBasp MISO <-> Pro Micro 14/B3 (MISO)
USBasp MOSI <-> Pro Micro 16/B2 (MOSI)
See the QMK ISP Flashing Guide. Replace the Pro Micro's default Caterina boot loader with Atmel-DFU using the following command for USBasp and fuses parameter:
avrdude -c usbasp -P usb -p atmega32u4 \
-U flash:w:bootloader_atmega32u4_1.0.0.hex:i \
-U lfuse:w:0x5E:m -U hfuse:w:0xD9:m -U efuse:w:0xC3:m
Clone @sigprof's nanoBoot fork, and run git checkout string-descriptors
followed by make
to build the updated boot loader. Replace the current boot loader with nanoBoot using the following command and fuses:
avrdude -c usbasp -P usb -p atmega32u4 \
-U flash:w:nanoBoot.hex:i \
-U lfuse:w:0xFF:m -U hfuse:w:0xD6:m -U efuse:w:0xC7:m
Use the following rules.mk
options for nanoBoot:
BOOTLOADER = qmk-hid
BOOTLOADER_SIZE = 512
Limitation: Bootmagic lite will not work.
- Seniply 34 key layout
- Callum-style mods
- Architeuthis dux PCB
- Hypergolic PCB
- Split Keyboard database
- Sockets
- Git Purr
- Data in Program Space
- Autocorrections with QMK
- Elite-C
- Pro Micro C
- Mill-Max 315-43-112-41-003000 low sockets for Elite-C
- Mill-Max 315-43-164-41-001000 sockets for Pro Micro C
- Mill-Max connector pins
- PJ320A jack
- TRRS cable
- Silicone bumper feet
- Kailh gchoc v1 switches