The Fun Way to Configure and Compile your own Keymap in QMK

Disclaimer: This is not meant to supersede nor undermine any other guides out there. I am in no way an expert in this field. This is the way I configure my keymaps and compile my firmware. Use at your own risk.

Disclaimer #2: Frequent use of this method will contribute to wear and shine on your keycaps. Again, use at your own risk.

Official and comprehensive documentation on customizing, building and/or compiling your QMK Firmware can be found here: docs.qmk.fm. This guide is where I started: The Complete Newbs Guide To QMK.

Requirements

Windows Machine - We will need Windows 10 machine with Ubuntu installed. Please follow this guide if you do not have Ubuntu/Linux yet: [link]

QMK Firmware source code - Copy of an updated QMK Firmware source should be properly installed in your Ubuntu sub-system. It is also required that your copy is always up to date. Please follow this guide if you do not have one: [link]

Update20210120: A Windows one-click installer for the QMK CLIhttps://msys.qmk.fm/

Getting Started

Ubuntu screen once opened:


Type the commands below to move to qmk_firmware directory:




Making your own keymap

In this guide, I will be working with a P20 macropad. My keyboards are tucked under pabile folder. Structure of P20 keyboard is shown below if viewed under windows explorer:



keyboards /pabile /p20 /ver2 config.h readme.md rules.mk ver2.c ver2.h /keymaps /default keymap.c /4encoders config.h keymap.c rules.mk

To make a new keyboard layout for the p20, i would copy an existing keymap that is closest to what i wanted. In this example, i want new keymaps for a p20 with 4 encoders. Going back to Ubuntu App, the command will be:

sudo cp -r keyboards/pabile/p20/ver2/keymaps/4encoders keyboards/pabile/p20/ver2/keymaps/4encoders2 



The above command will result to this structure:

keyboards /pabile /p20 /ver2 config.h rules.mk readme.md ver2.c ver2.h /keymaps /default keymap.c /4encoders config.h keymap.c rules.mk /4encoders2 config.h keymap.c rules.mk


Or this (under windows explorer):

Unless there are configurations that needs to be edited, we will only work on keymap.c. To edit keymap.c, open it in nano text editor:

sudo nano keyboards/pabile/p20/ver2/keymaps/4encoders2/keymap.c


The default keymap.c of 4encoders contains the following:

#include QMK_KEYBOARD_H 

enum custom_keycodes { 
    DBLZERO = SAFE_RANGE, 
}; 

bool process_record_user(uint16_t keycode, keyrecord_t *record) { 
    switch (keycode) { 
    case DBLZERO: 
        if (record->event.pressed) { 
            tap_code(KC_P0);  
            tap_code(KC_P0);  
        } 
        break; 
    } 
    return true; 
}; 

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { 
    [0] = LAYOUT_ortho_5x4( 
         KC_NLCK, KC_PSLS, KC_PAST, KC_PMNS, 
         KC_P7,   KC_P8,   KC_P9,   KC_DEL, 
         KC_P4,   KC_P5,   KC_P6,   KC_PPLS, 
         KC_P1,   KC_P2,   KC_P3,   KC_TAB, 
         KC_P0,   DBLZERO, KC_PDOT, KC_PENT) 
}; 

void encoder_update_user(uint8_t index, bool clockwise) { 
    if (index == 0) { /* First encoder */  
        if (clockwise) { 
           tap_code(KC_RBRC); /* brush size big */ 
        } else { 
           tap_code(KC_LBRC); /* brush size small */ 
        } 
    } else if (index == 1) { /* Second encoder */ 
        if (clockwise) { 
           SEND_STRING(SS_LCTL("-")); /* zoom in */ 
        } else { 
           SEND_STRING(SS_LCTL("=")); /* zoom out */ 
        }  
    } else if (index == 2) { /* Third encoder */ 
        if (clockwise) { 
           tap_code(KC_WH_U); /* mouse wheel up */ 
        } else { 
           tap_code(KC_WH_D); /* mouse wheel down */ 
        } 
    } else if (index == 3) { /* Forth encoder */ 
        if (clockwise) { 
           tap_code(KC_VOLU); /* volume up */ 
        } else { 
           tap_code(KC_VOLD); /* volume down */ 
        } 
    } 
}

The first part contains a simple macro that I called DBLZERO and it outputs 00 (double zero) when pressed. Lets call this section, Macro Section. I am not sure if there's an official name for this section, so please let me know if there are any.

enum custom_keycodes { 
    DBLZERO = SAFE_RANGE, 
}; 

bool process_record_user(uint16_t keycode, keyrecord_t *record) { 
    switch (keycode) { 
    case DBLZERO:  
        if (record->event.pressed) { 
            tap_code(KC_P0); 
            tap_code(KC_P0); 
        } 
        break; 
    } 
    return true; 
};

It is safe to remove this portion if not needed. Otherwise, edit and/or replace with your own macro.

The second part of keymap.c, what I'll call Matrix Section, are the key codes and layers. In this example, there is only one layer, layer [0].

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { 
    [0] = LAYOUT_ortho_5x4( 
        KC_NLCK, KC_PSLS, KC_PAST, KC_PMNS, 
        KC_P7,   KC_P8,   KC_P9,   KC_DEL, 
        KC_P4,   KC_P5,   KC_P6,   KC_PPLS, 
        KC_P1,   KC_P2,   KC_P3,   KC_TAB, 
        KC_P0,   DBLZERO, KC_PDOT, KC_PENT)
}; 

*The top most row contains press/button function of the rotary encoders.

To add a layer [1], the following is what the above section will look like:

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { 
    [0] = LAYOUT_ortho_5x4( 
       KC_NLCK, KC_PSLS, KC_PAST, KC_PMNS, 
       KC_P7,   KC_P8,   KC_P9,   KC_DEL, 
       KC_P4,   KC_P5,   KC_P6,   KC_PPLS, 
       KC_P1,   KC_P2,   KC_P3,   KC_TAB,   
       KC_P0,   DBLZERO, KC_PDOT, TL(1,KC_PENT)), 
   [1] = LAYOUT_ortho_5x4( 
       KC_1,    KC_2,    KC_3,    KC_4, 
       KC_Q,    KC_W,    KC_E,    KC_R, 
       KC_A,    KC_S,    KC_D,    KC_F, 
       KC_Z,    KC_X,    KC_C,    KC_V, 
       KC_LCTL, KC_LGUI, KC_LALT, KC_TRNS) };

On layer [0], we added Layer Tap layer change command on KC_PENT. This will result on layer change, switch to layer [1], when this key is pressed and held, layer change will be released upon release of the key.

Now on the last part of the keymap.c. The following contains functions of the 4 rotary encoders on the p20. The encoders on p20 are arranged from left to right.

void encoder_update_user(uint8_t index, bool clockwise) { 
     if (index == 0) { /* First encoder */ 
        if (clockwise) {  
            tap_code(KC_RBRC); /* brush size small */ 
        } else { 
            tap_code(KC_LBRC); /* brush size big */ 
        } 
     } else if (index == 1) { /* Second encoder */ 
        if (clockwise) { 
            SEND_STRING(SS_LCTL("-")); /* zoom out */ 
        } else { 
            SEND_STRING(SS_LCTL("=")); /* zoom in */ 
        } 
     } else if (index == 2) { /* Third encoder */ 
        if (clockwise) { 
            tap_code(KC_WH_U); /* mouse wheel up */ 
        } else { 
            tap_code(KC_WH_D); /* mouse wheel down */ 
        }
     } else if (index == 3) { /* Forth encoder */ 
        if (clockwise) { 
            tap_code(KC_VOLU); /* volume up */ 
        } else { 
            tap_code(KC_VOLD); /* volume down */ 
        }
     }
}

Key combinations and/or macros can be used here. One example are those under Second encoder. Those are combination of left control and dash/equal keys.

Once satisfied with the custom layout, press Ctrl+X then Y to save and close nano.

On the qmk_formware root directory, the following will compile QMK Firmware with our custom layout:

sudo make pabile/p20/ver2:4encoders2

A bunch of codes will prompt with [OK]s on the side. If everything goes well, your hex file is ready and can be found on qmk_firmware root directory. This firmware will be named as pabile_p20_ver2_4encoders2.hex. Point QMK Toolbox to this file and you are ready to flash.

Most of the time there won't be [OK]s but series of failed texts. These are typically caused by a typographical errors and missing commas, brackets and other opening/closing characters. Examine these error codes and correct typos. If compilation still fails... 

Comments

  1. Thanks for this. Helped me figure out a couple of issues I was having trying to get a Shift+KC with my encoder. SEND_STRINGS should be SEND_STRING, though.

    ReplyDelete
    Replies
    1. OOPS. I read that wrong. The (SS...) tricked my brain into thinking it was STRINGS. Thanks again, though.

      Delete

Post a Comment