Skip to content

RazMelon/qmk_userspace

 
 

Repository files navigation

Summary

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.

Setup

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.

Supported Keyboards

corneplanck

To build, run qmk compile on the JSON files in keymaps folder. Example:

qmk compile keymaps/corne.json

Code Features

  • Shared layout wrapper macros
  • Combos simplified with preprocessors
  • Tap-hold clipboard shortcuts
  • OLED indicators and animation
    • Bongocat with compressed RLE frames
    • Luna (and Felix) the dog
    • Soundmonster indicator icons
    • Katakana コルネ font file
  • RGB matrix lighting and effects
  • Word processing functions
    • Caps Word to toggle caps lock following a word
    • Autocorrection for typos

Split Keyboard Handedness

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

Modular Corne (CRKBD) Build

Corne keyboard is configured with a few modular build options using rules.mk:

Tiny build

Minimal firmware with no OLED and RGB support is the default:

qmk compile corne.json

Compiling for OLED display

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:

Bongocat

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

Felix and Luna

Build for Luna or Felix the dog:

qmk compile -e OLED=LUNA corne.json
qmk compile -e OLED=FELIX corne.json

Compiling for RGB matrix

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.

Logo file

Images in glcdfont.c can be viewed and edited with:

Code Snippets

Light configured layers keys

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.

Tap hold macros

#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.

Combo helper macros

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.

Pro Micro RX/TX LEDs

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;
}

macOS / Windows Shortcuts

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);

Layout wrapper macros

Basic layout

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.

Wrapping home row modifiers

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" ]
],

Adapting layouts

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
}

ISP Flashing Notes

Hardware

USBasp wiring

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)

Atmel DFU

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

NanoBoot

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.

Useful Links

Hardware Parts

About

Personal user space for QMK firmware

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C 89.2%
  • C++ 5.6%
  • Python 4.6%
  • Makefile 0.6%