My keyboard layout inspired by manna-harbour/miryoku for my elephant42 split keyboard running the QMK firmware.
Optimizations are mostly taken from QMK documentation.
# Build Options
# change yes to no to disable
#
LTO_ENABLE = yes
BOOTMAGIC_ENABLE = no # Enable Bootmagic Lite
GRAVE_ESC_ENABLE = no # using grave key as esc
SPACE_CADET_ENABLE = no # using left and right shift for inserting parenthesis
MAGIC_ENABLE = no # change the layout with bootmagic after compilation with keys
TAP_DANCE_ENABLE = no # trigger different keys based on number of consecutive taps
NKRO_ENABLE = no # Enable N-Key Rollover
BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
RGB_MATRIX_ENABLE = no
AUDIO_ENABLE = no # Audio output
#pragma once
#undef LOCKING_SUPPORT_ENABLE
#undef LOCKING_RESYNC_ENABLE
#include QMK_KEYBOARD_H
uint16_t keycode_config(uint16_t keycode) {
return keycode;
}
uint8_t mod_config(uint8_t mod) {
return mod;
}
CONSOLE_ENABLE = no # Console for debug
COMMAND_ENABLE = no # Commands for debug and configuration
EXTRAKEY_ENABLE = yes # Audio control and System control
By default you can only have 16 layouts at max. This changes the limit to 32.
#undef LAYER_STATE_8BIT
#undef LAYER_STATE_16BIT
#define LAYER_STATE_32BIT
These custom remapped keys are simple C macros which alias keyboard keys that are not used (mainly F16 to F24). Since in some areas of qmk there is a limit on keycodes that can be used specially with the LT()
macro, instead of creating new custom keycodes I use one of the existing basic keycodes by overwriting its functionality in process_record_user function or with key overrides.
// custom remapped keys
#define MY_DLR KC_F16
#define MY_UNDS KC_F17
#define MY_BSLS KC_F18
These keys are custom keycodes which i use for doing different keys which are not bound to a real physical keyboard key.
// custom keys
enum my_keys {
MY_LOCK = SAFE_RANGE,
// language keys
MY_LANG_SWITCH,
// dynamic tap term keys
MY_TAP_TERM_DN,
MY_TAP_TERM_UP,
};
The order of layers in this enum is important. The commented line separates layers with layer numbers above 16, and this is important because some qmk features and macros specially the LT()
macro only works with layers below 16.
enum layer_names {
COLEMAK_DH,
QWERTY,
ON_LMODS,
ON_RMODS,
ON_SFT_COLEMAK,
ON_SFT_QWERTY,
ON_RSFT,
ON_LSFT,
SYM,
NUM,
FUN,
NAV,
MOS,
MED,
SYS,
ON_RCTL,
// ------------
ON_RALT,
ON_RGUI,
ON_LCTL,
ON_LALT,
ON_LGUI,
NUMBER_OF_LAYERS
};
These boilerplates could be used to quickly create new layers.
// //,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
// _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
// //|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
// _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
// //`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
// _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
// // `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
// _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______
// // `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
// //,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
// XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX ,
// //|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
// XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX ,
// //`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
// XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX ,
// // `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
// XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX
// // `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
This is the default layer. I use colemak-dh keyboard layout for english.
const uint16_t PROGMEM keymaps[NUMBER_OF_LAYERS][MATRIX_ROWS][MATRIX_COLS] = {
[COLEMAK_DH] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
MEH_T(MY_DLR) , KC_Q , KC_W , KC_F , KC_P , KC_B , KC_J , KC_L , KC_U , KC_Y , KC_DQT ,MEH_T(MY_UNDS),
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
HYPR_T(KC_SLSH), LGUI_T(KC_A) , LALT_T(KC_R) , LCTL_T(KC_S) , LSFT_T(KC_T) , KC_G , KC_M , RSFT_T(KC_N) , RCTL_T(KC_E) , RALT_T(KC_I) , RGUI_T(KC_O) ,HYPR_T(KC_EQUAL),
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
KC_Z , KC_X , KC_C , KC_D , KC_V , KC_K , KC_H , KC_COMM , KC_DOT , KC_SCLN ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
MO(SYS) ,LT(MED,KC_ESC),LT(NAV,KC_SPC),LT(MOS,KC_TAB), LT(NUM,KC_ENT),LT(SYM,KC_BSPC),LT(FUN,KC_DEL), KC_F15
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
This is an alternative base layer based on qwerty layout. I use this specially for typing farsi since i type farsi with a qwerty layout.
[QWERTY] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
MEH_T(MY_DLR) , KC_Q , KC_W , KC_E , KC_R , KC_T , KC_Y , KC_U , KC_I , KC_O , KC_P , MEH_T(KC_LBRC),
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
HYPR_T(KC_SLSH), LGUI_T(KC_A) , LALT_T(KC_S) , LCTL_T(KC_D) , LSFT_T(KC_F) , KC_G , KC_H , RSFT_T(KC_J) , RCTL_T(KC_K) , RALT_T(KC_L) ,RGUI_T(KC_SCLN),HYPR_T(KC_QUOT),
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
KC_Z , KC_X , KC_C , KC_V , KC_B , KC_N , KC_M , KC_COMM , KC_DOT , KC_SLSH ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
MO(SYS) ,LT(MED,KC_ESC),LT(NAV,KC_SPC),LT(MOS,KC_TAB), LT(NUM,KC_ENT),LT(SYM,KC_BSPC),LT(FUN,KC_F15), KC_F15
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
These base mod layers get activated when a modifier key is pressed down in combination to the specific modifier layer which are defined in here. This serves multiple purposes.
- When a modifier key from one side is being pressed the home row modifiers of the other side will be disabled and act only as normal letter keys.
- Also when a modifier key from one side is being pressed the other home row mods of that side, work only as modifiers and the normal letter keys are disabled (this is achived in mod layers).
- When a modifier key is pressed (unless it’s shift) a colemak-dh overlay is temporarily activated and the layout is switched to colemak-dh even if the active layout is qwerty. This is done to keep shortcuts and key combinations consistent across layouts and languages.
[ON_RMODS] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
KC_DLR , KC_Q , KC_W , KC_F , KC_P , KC_B , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , _______ ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
KC_SLSH , KC_A , KC_R , KC_S , KC_T , KC_G , _______ , _______ , _______ , _______ , _______ , _______ ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
KC_Z , KC_X , KC_C , KC_D , KC_V , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
_______ , KC_ESC , KC_SPC , KC_TAB , MO(NUM) , MO(SYM) , MO(FUN) , _______
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
[ON_LMODS] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
_______ , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , KC_J , KC_L , KC_U , KC_Y , KC_DQT , KC_UNDS ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
_______ , _______ , _______ , _______ , _______ , _______ , KC_M , KC_N , KC_E , KC_I , KC_O , KC_EQUAL ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , KC_K , KC_H , KC_COMM , KC_DOT , KC_SCLN ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
XXXXXXX , MO(MED) , MO(NAV) , MO(MOS) , KC_ENT , KC_BSPC , KC_DEL , _______
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
These layers compliment the ON_RSFT
and ON_LSFT
layers which are defined here. These layers are necessary for the caps word functionality to work correctly for both colemak-dh and qwerty layouts.
The reason why they are defined here is because they should be on a lower layer than other overlay layers like NUM
, SYM
, FUN
, etc.. to prevent overriding the keys on those layers when they are activated and a mod key is pressed down.
Also some custom shift values are defined here which are used in combination with key overrides to provide custom shifted values. For example when pressing shift the dollar key on the left acts as a tilde (~) symbol
[ON_SFT_COLEMAK] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
KC_TILD , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , KC_UNDS ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
MY_BSLS , _______ , _______ , _______ , LSFT_T(KC_T) , _______ , _______ , RSFT_T(KC_N) , _______ , _______ , _______ , _______ ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
[ON_SFT_QWERTY] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
KC_TILD , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , KC_LBRC ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
MY_BSLS , _______ , _______ , _______ , LSFT_T(KC_F) , _______ , _______ , RSFT_T(KC_J) , _______ , _______ , _______ , _______ ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
Overlay layers are temporarily layers that get activated when a specific key is held down and deactivated when the key is released.
Symbol layer contains punctuation and mathematical symbols.
[SYM] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
KC_DLR , KC_PERC , KC_AT , KC_LT , KC_GT , KC_PIPE , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , KC_MEH ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
KC_SLSH , KC_ASTR , KC_GRV , KC_LCBR , KC_RCBR , KC_AMPR , XXXXXXX , XXXXXXX , KC_RCTL , KC_RALT , KC_RGUI , KC_HYPR ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
KC_CIRC , XXXXXXX , KC_LBRC , KC_RBRC , KC_HASH , XXXXXXX , XXXXXXX , KC_COMM , KC_DOT , KC_SCLN ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
MY_LOCK , KC_EXLM , KC_SPC , KC_QUES , XXXXXXX , _______ , XXXXXXX , XXXXXXX
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
Numbers layer + additional mathematical symbols for easier access.
[NUM] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
KC_DLR , KC_PERC , KC_9 , KC_8 , KC_7 , KC_MINUS , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , KC_MEH ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
KC_SLSH , KC_ASTR , KC_6 , KC_5 , KC_4 , KC_PLUS , XXXXXXX , XXXXXXX , KC_RCTL , KC_RALT , KC_RGUI , KC_HYPR ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
KC_CIRC , KC_3 , KC_2 , KC_1 , KC_HASH , XXXXXXX , XXXXXXX , KC_COMM , KC_DOT , KC_SCLN ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
MY_LOCK , KC_COMM , KC_0 , KC_DOT , _______ , XXXXXXX , XXXXXXX , XXXXXXX
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
Function keys + F13
and F14
!
[FUN] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
KC_F14 , KC_F12 , KC_F9 , KC_F8 , KC_F7 , KC_PAUSE , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , KC_MEH ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
KC_F13 , KC_F11 , KC_F6 , KC_F5 , KC_F4 , KC_PSCR , XXXXXXX , KC_RSFT , KC_RCTL , KC_RALT , KC_RGUI , KC_HYPR ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
KC_F10 , KC_F3 , KC_F2 , KC_F1 , _______ , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
MY_LOCK , KC_ESC , KC_SPC , KC_TAB , XXXXXXX , XXXXXXX , _______ , XXXXXXX
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
Keys for navigation.
[NAV] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
KC_MEH , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , KC_NUM , KC_SCRL ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
KC_HYPR , KC_LGUI , KC_LALT , KC_LCTL , KC_LSFT , XXXXXXX , KC_LEFT , KC_DOWN , KC_UP , KC_RGHT , KC_INSERT , KC_CAPS ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , KC_HOME , KC_PGDN , KC_PGUP , XXXXXXX , KC_END ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
XXXXXXX , XXXXXXX , _______ , XXXXXXX , KC_ENT , KC_BSPC , KC_DEL , MY_LOCK
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
Mouse keys are here.
[MOS] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
KC_ACL0 , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , KC_MS_BTN5 ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
KC_ACL1 , KC_LGUI , KC_LALT , KC_LCTL , KC_LSFT , XXXXXXX , KC_MS_LEFT , KC_MS_DOWN , KC_MS_UP , KC_MS_RIGHT , XXXXXXX , KC_MS_BTN4 ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , KC_MS_WH_LEFT ,KC_MS_WH_DOWN , KC_MS_WH_UP ,KC_MS_WH_RIGHT, XXXXXXX ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
XXXXXXX , XXXXXXX , XXXXXXX , _______ , KC_MS_BTN2 , KC_MS_BTN1 , KC_MS_BTN3 , MY_LOCK
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
Media control keys.
[MED] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
KC_MEH , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , KC_MRWD , KC_BRID , KC_BRIU , KC_MFFD , XXXXXXX , XXXXXXX ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
KC_HYPR , KC_LGUI , KC_LALT , KC_LCTL , KC_LSFT , XXXXXXX , KC_MPRV , KC_VOLD , KC_VOLU , KC_MNXT , XXXXXXX , XXXXXXX ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
XXXXXXX , _______ , XXXXXXX , XXXXXXX , KC_MSTP , KC_MPLY , KC_MUTE , MY_LOCK
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
System layer contains keys related to settings and configurations for the keyboard itself
[SYS] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , KC_PWR ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , DM_REC1 , DM_PLY1 , DB_TOGG , XXXXXXX , XXXXXXX ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX ,MY_TAP_TERM_DN,MY_TAP_TERM_UP, DT_PRNT , EE_CLR ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
_______ , XXXXXXX , XXXXXXX , XXXXXXX , XXXXXXX ,MY_LANG_SWITCH, QK_REBOOT , QK_BOOTLOADER
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
[ON_RSFT] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , XXXXXXX ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
_______ , KC_A , KC_R , KC_S , _______ , _______ , _______ , _______ , KC_RCTL , KC_RALT , KC_RGUI , XXXXXXX ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
[ON_RCTL] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , XXXXXXX ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
_______ , _______ , _______ , _______ , _______ , _______ , _______ , KC_RSFT , _______ , KC_RALT , KC_RGUI , XXXXXXX ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
[ON_RALT] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , XXXXXXX ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
_______ , _______ , _______ , _______ , _______ , _______ , _______ , KC_RSFT , KC_RCTL , _______ , KC_RGUI , XXXXXXX ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
[ON_RGUI] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , XXXXXXX ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
_______ , _______ , _______ , _______ , _______ , _______ , _______ , KC_RSFT , KC_RCTL , KC_RALT , _______ , XXXXXXX ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
[ON_LSFT] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
XXXXXXX , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
XXXXXXX , KC_LGUI , KC_LALT , KC_LCTL , _______ , _______ , _______ , _______ , KC_E , KC_I , KC_O , _______ ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
[ON_LCTL] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
XXXXXXX , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
XXXXXXX , KC_LGUI , KC_LALT , _______ , KC_LSFT , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
[ON_LALT] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
XXXXXXX , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
XXXXXXX , KC_LGUI , _______ , KC_LCTL , KC_LSFT , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
[ON_LGUI] = LAYOUT(
//,--------------+--------------+--------------+--------------+--------------+--------------. ,--------------+--------------+--------------+--------------+--------------+--------------.
XXXXXXX , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
//|--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------|
XXXXXXX , _______ , KC_LALT , KC_LCTL , KC_LSFT , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
//`--------------+--------------+--------------+--------------+--------------+--------------| |--------------+--------------+--------------+--------------+--------------+--------------'
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
// `--------------+--------------+--------------+--------------+--------------+ `--------------+--------------+--------------+--------------+--------------`
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______
// `--------------+--------------+--------------+--------------' `--------------+--------------+--------------+--------------'
),
};
EEPROM is the persistence memory of the keyboard. Data that is written to the eeprom will persist after unplugging the keyboard. Currently I only use this to save the tapping term after it’s changed with dynamic tapping term keys.
typedef union {
uint32_t raw;
struct {
uint16_t global_tapping_term;
};
} user_config_t;
static user_config_t user_config;
// set default values for when eeprom is cleared
void eeconfig_init_user(){
user_config.global_tapping_term = 160;
eeconfig_update_user(user_config.raw);
}
Settings related to split keyboard, master/slave detection method and data synchronization between two sides.
SPLIT_KEYBOARD = yes
By defining EE_HANDS
and flashing each side with the proper -bl
argument you can make it so that the sides are detected correctly when USB is plugged to either thes left or the right split
// detect master and slave. out of all methods i've tested only this one seems to work
#define SPLIT_USB_DETECT
#define EE_HANDS
For OLED displays to function correctly some data needs to be synchronized across the two splits. That means some data should be sent from the master side to the slave side. QMK provides some convinient functionality to synchronize some things like the LED states (Caps Lock, Num Lock and Scroll Lock), layer state and other things. For more specific stuff you have to write your own synchronization logic using the provided RPC functions.
// sync for led states such as num lock and caps lock
#define SPLIT_LED_STATE_ENABLE
// sync for layer_state variable
#define SPLIT_LAYER_STATE_ENABLE
// sync for modifier keys
#define SPLIT_MODS_ENABLE
// sync for oled display state (on/off)
#define SPLIT_OLED_ENABLE
#define SPLIT_TRANSACTION_IDS_USER SPLIT_SYNC
Here I define all the data that needs to be synchronized across the splits and unite them in a single struct. Later on in I use a single RPC function to send this struct periodically from the master side to the slave side. The reason I use a single RPC transaction, is because I’ve found the experience of working with multiple RPC functions unreliable so I just use a single RPC function to send everything.
These properties are used for the bouncing dvd logo which is defined later in here.
typedef union {
uint8_t raw;
struct {
uint8_t x :7;
uint8_t y :7;
bool go_right :1;
bool go_down :1;
};
} dvd_info_t;
These properties are used for the word and backspace counters that are defined later in here.
typedef union {
uint32_t raw;
struct {
int16_t spc :15;
int16_t bspc :15;
bool prev_spc :1;
bool prev_bspc :1;
};
} counters_t;
Other properties which are displayed in the OLED displays so should be synchronized across displays.
typedef union {
uint8_t raw;
struct {
bool dvd_mode :1;
bool standby_mode :1;
uint8_t active_lang :4;
bool layer_lock :1;
bool caps_word :1;
};
} other_t;
The struct that includes all the above structs and unions and is synced across splits.
struct sync_data_t {
counters_t counters;
dvd_info_t dvd_info;
uint8_t tapping_term;
other_t other;
};
static struct sync_data_t sync_data;
#include "transactions.h"
// recieve data from master
void split_sync_slave_handler(uint8_t buf_len,const void* in_data,uint8_t out_buflen,void* out_data){
sync_data = *(struct sync_data_t*)in_data;
}
static uint16_t sync_interval = 0;
// send data to slave
void housekeeping_task_user(void){
if(is_keyboard_master() && timer_elapsed(sync_interval) > 200){
transaction_rpc_send(SPLIT_SYNC,sizeof(sync_data),&sync_data);
sync_interval = timer_read();
}
}
Control the mouse with the keyboard.
MOUSEKEY_ENABLE = yes
// mouse movement
#define MK_COMBINED
#define MOUSEKEY_INTERVAL 16
#define MOUSEKEY_MOVE_DELTA 6
#define MOUSEKEY_MAX_SPEED 9
#define MOUSEKEY_TIME_TO_MAX 60
// mouse wheel
#define MOUSEKEY_WHEEL_DELAY 10
#define MOUSEKEY_WHEEL_DELTA 1
#define MOUSEKEY_WHEEL_INTERVAL 80
#define MOUSEKEY_WHEEL_MAX_SPEED 8
#define MOUSEKEY_WHEEL_TIME_TO_MAX 60
The function change_language
is responsible for changing the keyboard layout and also setting the proper active_lang
value to be displayed in the OLED display. This function is used in here.
enum languages {
LANG_EN = COLEMAK_DH,
LANG_FA = QWERTY,
NUMBER_OF_LANGS
};
bool change_language(bool is_activated, void *suppressed_mods) {
if(is_activated){
sync_data.other.active_lang = LANG_EN + ((sync_data.other.active_lang + 1) % NUMBER_OF_LANGS); // cycles through languages
default_layer_set(1 << sync_data.other.active_lang);
}
return true;
}
KEY_OVERRIDE_ENABLE = yes
#undef TAP_CODE_DELAY
#define TAP_CODE_DELAY 5
const key_override_t shift_and_comma_is_left_parenthesis = ko_make_basic(MOD_MASK_SHIFT,KC_COMM,KC_LPRN);
const key_override_t shift_and_dot_is_right_parenthesis = ko_make_basic(MOD_MASK_SHIFT,KC_DOT,KC_RPRN);
const key_override_t shift_and_je_is_che_farsi = ko_make_basic(MOD_MASK_SHIFT,KC_LBRC,KC_RBRC);
// adds a small delay before activating the override. sometime this is required for the keyboard to function properly in VMs and remote desktops
bool add_delay(bool is_activated, void *suppressed_mods) {
if(is_activated){
wait_ms(TAP_CODE_DELAY);
}
return true;
}
const key_override_t shift_and_double_quote_is_single_quote = {
.trigger_mods = MOD_MASK_SHIFT,
.layers = ~0,
.suppressed_mods = MOD_MASK_SHIFT,
.options = ko_options_default,
.negative_mod_mask = 0,
.custom_action = add_delay,
.context = (void*)NULL,
.trigger = KC_DQT,
.replacement = KC_QUOT,
.enabled = NULL
};
const key_override_t shift_and_slash_is_back_slash = {
.trigger_mods = MOD_BIT(KC_RSFT),
.layers = ~0,
.suppressed_mods = MOD_MASK_SHIFT,
.options = ko_options_default,
.negative_mod_mask = 0,
.custom_action = add_delay,
.context = (void*)NULL,
.trigger = MY_BSLS,
.replacement = KC_BSLS,
.enabled = NULL
};
const key_override_t shift_and_underscore_is_minus = {
.trigger_mods = MOD_BIT(KC_LSFT),
.layers = ~0,
.suppressed_mods = MOD_BIT(KC_LSFT),
.options = ko_options_default,
.negative_mod_mask = 0,
.custom_action = add_delay,
.context = (void*)NULL,
.trigger = KC_UNDS,
.replacement = KC_MINUS,
.enabled = NULL
};
const key_override_t win_and_space_change_language = {
.trigger_mods = MOD_BIT(KC_RGUI),
.layers = ~0,
.suppressed_mods = 0,
.options = ko_options_default,
.negative_mod_mask = 0,
.custom_action = change_language,
.context = (void*)NULL,
.trigger = KC_SPC,
.replacement = KC_SPC,
.enabled = NULL
};
const key_override_t** key_overrides = (const key_override_t *[]){
&shift_and_underscore_is_minus,
&shift_and_slash_is_back_slash,
&shift_and_comma_is_left_parenthesis,
&shift_and_dot_is_right_parenthesis,
&shift_and_double_quote_is_single_quote,
&win_and_space_change_language,
&shift_and_je_is_che_farsi,
NULL
};
Simulate Caps Lock for only one word and stop after a non word character is typed.
CAPS_WORD_ENABLE = yes
This makes it so that pressing the two shifts together turns on the caps word mode.
#define BOTH_SHIFTS_TURNS_ON_CAPS_WORD
With this function you can define when caps word is enabled which keys are shifted and which ones are not. Also you can specify which keys disable caps word.
bool caps_word_press_user(uint16_t keycode) {
switch (keycode) {
// Keycodes that continue Caps Word, with shift applied.
case KC_A ... KC_Z:
add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to next key.
return true;
// Keycodes that continue Caps Word, without shifting.
case KC_1 ... KC_0:
case KC_BSPC:
case KC_DEL:
case KC_UNDS:
return true;
default:
return false; // Deactivate Caps Word.
}
}
void caps_word_set_user(bool active){
sync_data.other.caps_word = active;
}
Configurations related to whether a key press considered as a tap or a hold.
This allows the tapping term to be different values for different keys.
#define TAPPING_TERM_PER_KEY
uint16_t get_tapping_term(uint16_t keycode, keyrecord_t* record){
switch(keycode){
case RSFT_T(KC_N):
case RSFT_T(KC_J):
case LSFT_T(KC_T):
case LSFT_T(KC_F):
case RCTL_T(KC_E):
case RCTL_T(KC_J):
return g_tapping_term * 0.9;
case RGUI_T(KC_O):
case RALT_T(KC_I):
case RGUI_T(KC_SCLN):
case RALT_T(KC_L):
return g_tapping_term * 1.3;
case LGUI_T(KC_A):
case LALT_T(KC_R):
case LALT_T(KC_S):
return g_tapping_term * 1.4;
default:
return g_tapping_term;
}
}
Quick Tap makes it so that by tapping a key once (pressing and releasing it immediately), holding it right after, will hold the (tap) key instead of the (hold) key. And in the case the (tap) key is a letter key, the key is typed repeatedly by the host OS. This is a useful feature but annoying for some keys.
#define QUICK_TAP_TERM_PER_KEY
you can turn down the quick tap term so that you have to double press the key faster to get the quick tap functionality
uint16_t get_quick_tap_term(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case LSFT_T(KC_T):
case LSFT_T(KC_F):
case RSFT_T(KC_N):
case RSFT_T(KC_J):
return 0;
case LCTL_T(KC_S):
case LCTL_T(KC_D):
case RCTL_T(KC_E):
case RCTL_T(KC_K):
return g_tapping_term * 0.5;
default:
return g_tapping_term * 0.8;
}
}
WPM_ENABLE = yes
#define WPM_LAUNCH_CONTROL
Customizations I have added to the keyboard. Contains custom functions and the functionality that handles custom keycodes i’ve defined.
When a modifier key is held down one or more mod layers are activated. This function handles the activating and deactivating of those layers. This function is called in ~process_record_user~ function.
// if a modifier key is pressed all the other modifier keys on that side of the keyboard behave only as mod keys instead of
// double mod-tap keys.
static inline bool process_mod_layers(uint8_t side_layer,uint8_t mod_layer,bool pressed){
if(pressed){
if(mod_layer == ON_RSFT || mod_layer == ON_LSFT){
if(sync_data.other.active_lang == LANG_EN)
layer_on(ON_SFT_COLEMAK);
else if(sync_data.other.active_lang == LANG_FA)
layer_on(ON_SFT_QWERTY);
}
else{
layer_on(side_layer);
}
layer_on(mod_layer);
}
else{
layer_off(mod_layer);
if(mod_layer == ON_RSFT || mod_layer == ON_LSFT){
layer_off(ON_SFT_COLEMAK);
layer_off(ON_SFT_QWERTY);
}
else{
layer_off(side_layer);
}
}
return true;
}
void post_process_record_user(uint16_t keycode,keyrecord_t* record){
if(record->event.pressed){
switch(keycode){
case KC_SPC:
case LT(NAV,KC_SPC):
if(!sync_data.counters.prev_spc && record->tap.count) {
sync_data.counters.spc++;
sync_data.counters.prev_spc = true;
}
break;
case KC_BSPC:
case LT(SYM,KC_BSPC):
if(!sync_data.counters.prev_bspc && record->tap.count){
sync_data.counters.bspc++;
sync_data.counters.prev_bspc = true;
}
break;
default:
sync_data.counters.prev_spc = false;
sync_data.counters.prev_bspc = false;
}
}
}
This is one of the most important parts of the configuration file. The process_record_user
function is called every time that a key is pressed or released.
Customizing the default behaviour of some keys and defining the logic for custom keys are all done here.
static uint32_t locked_layer = 0;
static uint32_t inactivity_timer = 0; // indicates how long the keyboard has been inactive
bool process_record_user(uint16_t keycode, keyrecord_t* record){
inactivity_timer = timer_read32();
switch(keycode){
case RSFT_T(KC_N):
case RSFT_T(KC_J):
case KC_RSFT:
if(!record->tap.count){
return process_mod_layers(ON_RMODS,ON_RSFT,record->event.pressed);
}
break;
case RCTL_T(KC_E):
case RCTL_T(KC_K):
case KC_RCTL:
if(!record->tap.count){
return process_mod_layers(ON_RMODS,ON_RCTL,record->event.pressed);
}
break;
case RALT_T(KC_I):
case RALT_T(KC_L):
case KC_RALT:
if(!record->tap.count){
return process_mod_layers(ON_RMODS,ON_RALT,record->event.pressed);
}
break;
case RGUI_T(KC_O):
case RGUI_T(KC_SCLN):
case KC_RGUI:
if(!record->tap.count){
return process_mod_layers(ON_RMODS,ON_RGUI,record->event.pressed);
}
break;
case LSFT_T(KC_T):
case LSFT_T(KC_F):
case KC_LSFT:
if(!record->tap.count){
return process_mod_layers(ON_LMODS,ON_LSFT,record->event.pressed);
}
break;
case LCTL_T(KC_S):
case LCTL_T(KC_D):
case KC_LCTL:
if(!record->tap.count){
return process_mod_layers(ON_LMODS,ON_LCTL,record->event.pressed);
}
break;
case LALT_T(KC_R):
case LALT_T(KC_S):
case KC_LALT:
if(!record->tap.count){
return process_mod_layers(ON_LMODS,ON_LALT,record->event.pressed);
}
break;
case LGUI_T(KC_A):
case KC_LGUI:
if(!record->tap.count){
return process_mod_layers(ON_LMODS,ON_LGUI,record->event.pressed);
}
break;
case MEH_T(MY_DLR):
case MY_DLR:
if(record->event.pressed){
register_code16(KC_DLR);
}
else{
unregister_code16(KC_DLR);
}
return false;
case MEH_T(MY_UNDS):
case MY_UNDS:
if(record->event.pressed){
register_code16(KC_UNDS);
}
else{
unregister_code16(KC_UNDS);
}
return false;
case MY_LANG_SWITCH:
if(record->event.pressed)
change_language(true,NULL);
return false;
Locks a layer like NAV
and NUM
by pressing the MY_LOCK
key.
For each layer the MY_LOCK
key is placed in that layer which locks the layer until you press the key again
case MY_LOCK:
if(record->event.pressed){
if(locked_layer){
layer_clear();
locked_layer = 0;
sync_data.other.layer_lock = false;
}
else{
locked_layer = layer_state;
layer_state_set(layer_state);
sync_data.other.layer_lock = true;
}
}
return false;
case LT(SYM,KC_BSPC):
case MO(SYM):
case LT(NUM,KC_ENT):
case MO(NUM):
case LT(FUN,KC_DEL):
case MO(FUN):
case LT(NAV,KC_SPC):
case MO(NAV):
case LT(MOS,KC_TAB):
case MO(MOS):
case LT(MED,KC_ESC):
case MO(MED):
// when activating the layer lock mechanism this code prevents the locked layer to be automatically disabled when you release the LT() key for that layer
// prevents the LT() release functionality to activate to prevent the locked layer being turned off
if(locked_layer && !record->tap.count && !record->event.pressed) return false;
else return true;
Dynamic tapping term makes it so that you can change the tapping term on the fly without needing to re-flash the keyboard.
DYNAMIC_TAPPING_TERM_ENABLE = yes
case MY_TAP_TERM_UP:
if(record->event.pressed){
user_config.global_tapping_term += 5;
g_tapping_term = user_config.global_tapping_term;
eeconfig_update_user(user_config.raw);
sync_data.tapping_term = g_tapping_term;
}
return false;
case MY_TAP_TERM_DN:
if(record->event.pressed){
user_config.global_tapping_term -= 5;
g_tapping_term = user_config.global_tapping_term;
eeconfig_update_user(user_config.raw);
sync_data.tapping_term = g_tapping_term;
}
return false;
}
return true;
}
This function is executed after at the startup.
void keyboard_post_init_user(void){
user_config.raw = eeconfig_read_user();
g_tapping_term = user_config.global_tapping_term;
sync_data.tapping_term = g_tapping_term;
sync_data.counters.raw = 0;
sync_data.dvd_info.raw = 0;
sync_data.other.raw = 0;
transaction_register_rpc(SPLIT_SYNC,split_sync_slave_handler);
}
OLED_ENABLE = yes
#define OLED_BRIGHTNESS 255
#ifdef OLED_ENABLE
#define STEPS 32
oled_rotation_t oled_init_user(oled_rotation_t rotation){
return OLED_ROTATION_270;
}
Custom font for the OLED display created using QMK Logo Editor.
#undef OLED_FONT_H
#define OLED_FONT_H "./keyboards/elephant42/keymaps/daktylos/glcdfont.c"
#undef OLED_FONT_END
#define OLED_FONT_END 118
#include "progmem.h"
static const unsigned char PROGMEM font[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1C, 0x22, 0x41, 0x22, 0x1C, 0x00,
0x1C, 0x3E, 0x7F, 0x3E, 0x1C, 0x00,
0xC0, 0x80, 0xBE, 0x8A, 0x8A, 0x80,
0xBE, 0x8A, 0x8A, 0xBE, 0x80, 0xC0,
0xFF, 0x81, 0xBD, 0xA5, 0x81, 0xBD,
0x95, 0xBD, 0x81, 0xBD, 0x95, 0x9D,
0x81, 0xAD, 0xB5, 0x81, 0xFF, 0x00,
0xC0, 0x80, 0xBE, 0xAA, 0xAA, 0x80,
0xBE, 0x84, 0x88, 0xBE, 0x80, 0xC0,
0x42, 0x24, 0x18, 0x18, 0x24, 0x4A,
0x81, 0xBD, 0x95, 0xAD, 0x81, 0xFF,
0x81, 0xBD, 0xA1, 0xA1, 0x81, 0xFF,
0x42, 0x24, 0x18, 0x18, 0x24, 0x42,
0xFF, 0xFF, 0xC3, 0xDB, 0xFF, 0xC3,
0xEB, 0xC3, 0xFF, 0xC3, 0xEB, 0xE3,
0xFF, 0xD3, 0xCB, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFC,
0xF2, 0xF1, 0x91, 0xF1, 0xF2, 0xFC,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x66, 0x89, 0x95, 0x6A, 0x00,
0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
0x94, 0xA2, 0xFF, 0xA2, 0x94, 0x00,
0x08, 0x04, 0x7E, 0x04, 0x08, 0x00,
0x10, 0x20, 0x7E, 0x20, 0x10, 0x00,
0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00,
0x08, 0x1C, 0x2A, 0x08, 0x08, 0x00,
0x1E, 0x10, 0x10, 0x10, 0x10, 0x00,
0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 0x00,
0x30, 0x38, 0x3E, 0x38, 0x30, 0x00,
0x06, 0x0E, 0x3E, 0x0E, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x5F, 0x00, 0x00, 0x00,
0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00,
0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00,
0x23, 0x13, 0x08, 0x64, 0x62, 0x00,
0x36, 0x49, 0x56, 0x20, 0x50, 0x00,
0x00, 0x08, 0x07, 0x03, 0x00, 0x00,
0x00, 0x1C, 0x22, 0x41, 0x00, 0x00,
0x00, 0x41, 0x22, 0x1C, 0x00, 0x00,
0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00,
0x08, 0x08, 0x3E, 0x08, 0x08, 0x00,
0x00, 0x80, 0x70, 0x30, 0x00, 0x00,
0x08, 0x08, 0x08, 0x08, 0x08, 0x00,
0x00, 0x00, 0x60, 0x60, 0x00, 0x00,
0x20, 0x10, 0x08, 0x04, 0x02, 0x00,
0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00,
0x00, 0x42, 0x7F, 0x40, 0x00, 0x00,
0x72, 0x49, 0x49, 0x49, 0x46, 0x00,
0x21, 0x41, 0x49, 0x4D, 0x33, 0x00,
0x18, 0x14, 0x12, 0x7F, 0x10, 0x00,
0x27, 0x45, 0x45, 0x45, 0x39, 0x00,
0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00,
0x41, 0x21, 0x11, 0x09, 0x07, 0x00,
0x36, 0x49, 0x49, 0x49, 0x36, 0x00,
0x46, 0x49, 0x49, 0x29, 0x1E, 0x00,
0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x00, 0x40, 0x34, 0x00, 0x00, 0x00,
0x00, 0x08, 0x14, 0x22, 0x41, 0x00,
0x14, 0x14, 0x14, 0x14, 0x14, 0x00,
0x00, 0x41, 0x22, 0x14, 0x08, 0x00,
0x02, 0x01, 0x59, 0x09, 0x06, 0x00,
0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00,
0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00,
0x7F, 0x49, 0x49, 0x49, 0x36, 0x00,
0x3E, 0x41, 0x41, 0x41, 0x22, 0x00,
0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00,
0x7F, 0x49, 0x49, 0x49, 0x41, 0x00,
0x7F, 0x09, 0x09, 0x09, 0x01, 0x00,
0x3E, 0x41, 0x41, 0x51, 0x73, 0x00,
0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00,
0x00, 0x41, 0x7F, 0x41, 0x00, 0x00,
0x20, 0x40, 0x41, 0x3F, 0x01, 0x00,
0x7F, 0x08, 0x14, 0x22, 0x41, 0x00,
0x7F, 0x40, 0x40, 0x40, 0x40, 0x00,
0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00,
0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00,
0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00,
0x7F, 0x09, 0x09, 0x09, 0x06, 0x00,
0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00,
0x7F, 0x09, 0x19, 0x29, 0x46, 0x00,
0x26, 0x49, 0x49, 0x49, 0x32, 0x00,
0x03, 0x01, 0x7F, 0x01, 0x03, 0x00,
0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00,
0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00,
0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00,
0x63, 0x14, 0x08, 0x14, 0x63, 0x00,
0x03, 0x04, 0x78, 0x04, 0x03, 0x00,
0x61, 0x59, 0x49, 0x4D, 0x43, 0x00,
0x00, 0x7F, 0x41, 0x41, 0x41, 0x00,
0x02, 0x04, 0x08, 0x10, 0x20, 0x00,
0x00, 0x41, 0x41, 0x41, 0x7F, 0x00,
0x04, 0x02, 0x01, 0x02, 0x04, 0x00,
0x40, 0x40, 0x40, 0x40, 0x40, 0x00,
0x00, 0x03, 0x07, 0x08, 0x00, 0x00,
0x20, 0x54, 0x54, 0x78, 0x40, 0x00,
0x7F, 0x28, 0x44, 0x44, 0x38, 0x00,
0x38, 0x44, 0x44, 0x44, 0x28, 0x00,
0x38, 0x44, 0x44, 0x28, 0x7F, 0x00,
0x38, 0x54, 0x54, 0x54, 0x18, 0x00,
0x00, 0x08, 0x7E, 0x09, 0x02, 0x00,
0x18, 0x24, 0x24, 0x1C, 0x78, 0x00,
0x7F, 0x08, 0x04, 0x04, 0x78, 0x00,
0x00, 0x44, 0x7D, 0x40, 0x00, 0x00,
0x20, 0x40, 0x40, 0x3D, 0x00, 0x00,
0x7F, 0x10, 0x28, 0x44, 0x00, 0x00,
0x00, 0x41, 0x7F, 0x40, 0x00, 0x00,
0x7C, 0x04, 0x78, 0x04, 0x78, 0x00,
0x7C, 0x08, 0x04, 0x04, 0x78, 0x00,
0x38, 0x44, 0x44, 0x44, 0x38, 0x00,
0x7C, 0x18, 0x24, 0x24, 0x18, 0x00,
0x18, 0x24, 0x24, 0x18, 0x7C, 0x00,
0x7C, 0x08, 0x04, 0x04, 0x08, 0x00,
0x48, 0x54, 0x54, 0x54, 0x24, 0x00,
0x04, 0x04, 0x3F, 0x44, 0x24, 0x00,
0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00,
0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00,
0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00,
0x44, 0x28, 0x10, 0x28, 0x44, 0x00,
0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00,
0x44, 0x64, 0x54, 0x4C, 0x44, 0x00,
0x00, 0x08, 0x36, 0x41, 0x00, 0x00,
0x00, 0x00, 0x77, 0x00, 0x00, 0x00,
0x00, 0x41, 0x36, 0x08, 0x00, 0x00,
0x02, 0x01, 0x02, 0x04, 0x02, 0x00,
0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00,
};
A bouncing dvd logo starts moving across the OLED screens after some time of inactivity.
// theses should stay the same unless you change the bitmap
#define DVD_WIDTH 24
#define DVD_HEIGHT 11
// the speed of the dvd logo from 1 to 5
#define DVD_SPEED 4
// the gap assumed between two oled screens. if set to 0 the logo appears on the other screen immediately
#define DVD_GAP 32
// minimum time of inactivity to start the dvd mode (in milliseconds)
#define DVD_TIMEOUT 60000
// stop the dvd mode after this much time has passed even if inactive
#define STANDBY_TIMEOUT (DVD_TIMEOUT * 60)
// DON'T CHANGE
#define DVD_SHIFT (DVD_DISPLAY_WIDTH + DVD_GAP)
#define DVD_DISPLAY_HEIGHT OLED_DISPLAY_WIDTH
#define DVD_DISPLAY_WIDTH OLED_DISPLAY_HEIGHT
#define IS_RIGHT (!is_keyboard_left())
// dvd logo bitmap
static const PROGMEM uint8_t dvd_logo[] = {
0x3F,0xE1,0xFE,
0x33,0xE1,0xE3,
0x33,0xF3,0x63,
0x71,0xBE,0x63,
0x77,0x1E,0xE7,
0x7E,0x1C,0xFC,
0x00,0x18,0x00,
0x00,0x00,0x00,
0x3F,0xFF,0xFC,
0xFF,0x83,0xFE,
0x3F,0xFF,0xFC
};
static uint8_t i=0,j=0,b=0,a=0;
static inline void render_dvd(void){
// drawing the dvd
if((!IS_RIGHT && sync_data.dvd_info.x < DVD_DISPLAY_WIDTH) || (IS_RIGHT && sync_data.dvd_info.x > DVD_SHIFT - DVD_WIDTH)){
for(i=0;i<sizeof(dvd_logo);i++){
b = pgm_read_byte_near(dvd_logo + i);
for(j=0;j<8;j++){
oled_write_pixel((sync_data.dvd_info.x - (IS_RIGHT ? (DVD_SHIFT) : 0)) + (i%3) * 8 + j,(sync_data.dvd_info.y) + i/3,b & (1 << (7-j)));
}
}
}
// calculating next position for dvd
if(sync_data.dvd_info.x <= 1){
sync_data.dvd_info.go_right = true;
}
else if(sync_data.dvd_info.x >= DVD_DISPLAY_WIDTH + DVD_SHIFT - DVD_WIDTH){
sync_data.dvd_info.go_right = false;
}
if(sync_data.dvd_info.y <= 0){
sync_data.dvd_info.go_down = true;
}
else if(sync_data.dvd_info.y >= DVD_DISPLAY_HEIGHT-DVD_HEIGHT){
sync_data.dvd_info.go_down = false;
}
if(a % 5 < DVD_SPEED){
sync_data.dvd_info.x += sync_data.dvd_info.go_right ? +1 : -1;
sync_data.dvd_info.y += sync_data.dvd_info.go_down ? +1 : -1;
}
a = (a+1) % 5;
}
// activate the dvd mode if the keyboard has been inactive for some time
static inline void check_inactivity(void){
if(!is_keyboard_master()) return;
uint32_t elapsed = timer_elapsed32(inactivity_timer);
if (elapsed > STANDBY_TIMEOUT){
sync_data.other.standby_mode = true;
sync_data.other.dvd_mode = false;
}
else if(elapsed > DVD_TIMEOUT){
if(!sync_data.other.dvd_mode){
sync_data.dvd_info.raw = timer_read();
}
sync_data.other.standby_mode = false;
sync_data.other.dvd_mode = true;
}
else {
if(sync_data.other.dvd_mode){
sync_data.dvd_info.raw = 0;
}
sync_data.other.dvd_mode = false;
sync_data.other.standby_mode = false;
}
}
bool oled_task_user(void){
oled_clear();
check_inactivity();
if(sync_data.other.standby_mode){
oled_off();
}
else if(sync_data.other.dvd_mode){
render_dvd();
}
else if(is_keyboard_left()){
// print the word and backspace counters
oled_write(get_u16_str(sync_data.counters.spc,' '),false);
oled_write_ln_P(PSTR("WORDS"),true);
oled_write(get_u16_str(sync_data.counters.bspc,' '),false);
oled_write_ln_P(PSTR("\eBSPC"),true);
oled_write(get_u16_str(sync_data.tapping_term,' '),false);
oled_write_ln_P(PSTR(" TAP "),true);
oled_write(get_u16_str(get_current_wpm(),' '),false);
oled_write_ln_P(PSTR(" WPM "),true);
}
else {
led_t led_state = host_keyboard_led_state();
oled_write_P(led_state.num_lock ? PSTR("\x01\x20") : PSTR("\x01\x20"),false);
oled_write_P(led_state.caps_lock ? PSTR("\x01\x20") : PSTR("\x01\x20"),false);
oled_write_ln_P(led_state.scroll_lock ? PSTR("\x01\x20") : PSTR("\x01\x20"),false);
oled_write_P(sync_data.other.caps_word ? PSTR("\x0e\x0f\x10") : PSTR("\x05\x06\x07"),false);
oled_write_ln_P(sync_data.other.active_lang == LANG_EN ? PSTR("\x08\x09") : PSTR("\x03\x04"),false);
if(IS_LAYER_ON(NAV)) oled_write_P(PSTR("NAV"),false);
else if(IS_LAYER_ON(SYM)) oled_write_P(PSTR("SYM"),false);
else if(IS_LAYER_ON(NUM)) oled_write_P(PSTR("NUM"),false);
else if(IS_LAYER_ON(MOS)) oled_write_P(PSTR("MOS"),false);
else if(IS_LAYER_ON(FUN)) oled_write_P(PSTR("FUN"),false);
else if(IS_LAYER_ON(MED)) oled_write_P(PSTR("MED"),false);
else if(IS_LAYER_ON(SYS)) oled_write_P(PSTR("SYS"),false);
else oled_write_P(PSTR("___"),false);
oled_write_ln_P(sync_data.other.layer_lock ? PSTR("\x11\x12") : PSTR(" "),false);
uint8_t mods = get_mods();
oled_write_P(PSTR("\x0B"),false);
oled_write_P(PSTR("S"),mods & MOD_BIT(KC_LSFT));
oled_write_P(PSTR("C"),mods & MOD_BIT(KC_LCTL));
oled_write_P(PSTR("A"),mods & MOD_BIT(KC_LALT));
oled_write_P(PSTR("G"),mods & MOD_BIT(KC_LGUI));
oled_write_P(PSTR("\x0C"),false);
oled_write_P(PSTR("S"),mods & MOD_BIT(KC_RSFT));
oled_write_P(PSTR("C"),mods & MOD_BIT(KC_RCTL));
oled_write_P(PSTR("A"),mods & MOD_BIT(KC_RALT));
oled_write_P(PSTR("G"),mods & MOD_BIT(KC_RGUI));
}
return false;
}
#endif