~ruther/qmk_firmware

edef1f93960352bcc97ac75653867e23e3db45fc — Drashna Jaelre 6 years ago 2e8e465 + be1d5c6
Update personal userspace and keymaps + improve custom functionality (#5289)

* Change how desktop commands work

* Add DST_MOD_MASK as a config option

* DST_RMV → DST_REM

* Add melody96:konstantin keymap

* Update custom SEND_STRING

* Move feature flags from userspace into keyboard rules

* Use "Vo-", "Vo+" instead of "VoD", "VoU" in keymap comments

* Add RGB controls and numpad Unicode to Melody96 keymap

* Add RGB_SET keycode to Melody96 and RGB files to userspace

* Generate UNICODE and UNICODEMAP constants using macros

* Avoid collisions with X_* send string constants

* Use two spaces before inline comments

* Add _keymap versions of other custom Quantum functions

Not added: eeconfig_update_keymap, eeconfig_read_keymap

* Switch to UNICODEMAP in keyboard rules

* Make toggle_numpad a nested function in process_record_user

* Set Melody96 underglow color to Godspeed blue on EEPROM reset

* Remove most _keymap and _user definitions in userspace

Some keyboards misuse _user functions by defining them in the base files
instead of the corresponding _kb functions (especially led_set_user and
matrix_init_user). Until this is fixed (#5148), I've removed definitions
in my userspace that could cause linking collisions.

* Update GODSPEED_BLUE values and RGB mode keys

* Add GODSPEED_YELLOW color

* Set preferred intervals for rgblight effects

* Update tap dance function names

* Replace td_lshift_fn with generic td_mod_layer, add TD_RCTL_FN

Move TD_FN_RCTL after TD_RCTL_FN

* Replace td_fn_rctrl with generic td_layer_mod

* Add blank lines, prefer explicit initialization

* ACTION_TAP_DANCE_DOUBLE_MODS → ACTION_TAP_DANCE_DOUBLE_MOD

* Update Godspeed colors

* Add media controls to Melody96 keymap

* Add SysRq, Break combos and other keys to Melody96 keymap
M keyboards/kbdfans/kbd6x/keymaps/konstantin/keymap.c => keyboards/kbdfans/kbd6x/keymaps/konstantin/keymap.c +5 -5
@@ 56,9 56,9 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
   * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
   * │      │ ← │ ↓ │ → │PgD│   │   │   │MW↑│M← │M↓ │M→ │        │
   * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────┬───┤
   * │        │Mut│VoD│VoU│Ply│Prv│Nxt│MW←│MW→│M4 │M5 │      │   │
   * │        │Mut│Vo-│Vo+│Ply│Prv│Nxt│MW←│MW→│M4 │M5 │      │   │
   * └─────┬──┴┬──┴──┬┴───┴───┴───┴───┴───┴───┴──┬┴───┴┬───┬─┴───┘
   *       │   │     │            MW↓            │MAcl2│   │
   *       │DPR│DstNA│            MW↓            │MAcl2│   │
   *       └───┴─────┴───────────────────────────┴─────┴───┘
   */
  [L_FN] = LAYOUT(


@@ 66,7 66,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    _______, KC_HOME, KC_UP,   KC_END,  KC_PGUP, _______, _______, _______, _______, KC_BTN1, KC_MS_U, KC_BTN2, KC_BTN3, KC_DEL,
    _______, KC_LEFT, KC_DOWN, KC_RGHT, KC_PGDN, _______, _______, _______, KC_WH_U, KC_MS_L, KC_MS_D, KC_MS_R, _______,
    _______, KC_MUTE, KC_VOLD, KC_VOLU, KC_MPLY, KC_MPRV, KC_MNXT, KC_WH_L, KC_WH_R, KC_BTN4, KC_BTN5, _______, _______,
    XXXXXXX, _______, _______,                   KC_WH_D,                   KC_ACL2, _______, XXXXXXX
    XXXXXXX, DST_P_R, DST_N_A,                   KC_WH_D,                   KC_ACL2, _______, XXXXXXX
  ),

  /* RCtrl layer


@@ 79,7 79,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
   * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────┬───┤
   * │        │   │   │   │   │   │   │   │   │   │   │      │   │
   * └─────┬──┴┬──┴──┬┴───┴───┴───┴───┴───┴───┴──┬┴───┴┬───┬─┴───┘
   *       │Dst│Dstp←│                           │Dstp→│   │
   *       │DtR│DstA │                           │     │   │
   *       └───┴─────┴───────────────────────────┴─────┴───┘
   */
  [L_RCTRL] = LAYOUT(


@@ 87,6 87,6 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    _______, TOP,     MV_UP,   BOTTOM,  PRV_TAB, _______, _______, _______, _______, _______, _______, _______, _______, CLEAR,
    _______, MV_LEFT, MV_DOWN, MV_RGHT, NXT_TAB, _______, _______, _______, _______, _______, _______, _______, _______,
    _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
    XXXXXXX, DESKTOP, DSKTP_L,                   _______,                   DSKTP_R, _______, XXXXXXX
    XXXXXXX, DST_REM, DST_ADD,                   _______,                   _______, _______, XXXXXXX
  ),
};

M keyboards/kbdfans/kbd6x/keymaps/konstantin/rules.mk => keyboards/kbdfans/kbd6x/keymaps/konstantin/rules.mk +9 -0
@@ 1,2 1,11 @@
BOOTMAGIC_ENABLE  = no
COMMAND_ENABLE    = yes
CONSOLE_ENABLE    = yes
EXTRAKEY_ENABLE   = yes
MOUSEKEY_ENABLE   = yes
NKRO_ENABLE       = yes
TAP_DANCE_ENABLE  = yes
UNICODEMAP_ENABLE = yes

BACKLIGHT_ENABLE = no
RGBLIGHT_ENABLE  = no

A keyboards/melody96/keymaps/konstantin/config.h => keyboards/melody96/keymaps/konstantin/config.h +3 -0
@@ 0,0 1,3 @@
#pragma once

#define LAYER_FN

A keyboards/melody96/keymaps/konstantin/keymap.c => keyboards/melody96/keymaps/konstantin/keymap.c +78 -0
@@ 0,0 1,78 @@
#include QMK_KEYBOARD_H
#include "konstantin.h"

static const hsv_t *colors[] = { &GODSPEED_BLUE, &GODSPEED_YELLOW };
static size_t cnum = sizeof colors / sizeof *colors;
static size_t cidx = 0;

void eeconfig_init_keymap(void) {
  rgblight_sethsv(colors[cidx]->h, colors[cidx]->s, colors[cidx]->v);
}

enum keycodes_keymap {
  RGB_SET = RANGE_KEYMAP,
};

bool process_record_keymap(uint16_t keycode, keyrecord_t *record) {
  switch (keycode) {
  case RGB_SET:
    if (record->event.pressed) {
      cidx = (cidx + 1) % cnum;
      rgblight_sethsv(colors[cidx]->h, colors[cidx]->s, colors[cidx]->v);
    }
    return false;

  default:
    return true;
  }
}

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
  /* Base layer
   * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
   * │Esc│F1 │F2 │F3 │F4 │F5 │F6 │F7 │F8 │F9 │F10│F11│F12│PSc│Ins│Hom│End│PgU│PgD│
   * ├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
   * │ ` │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ = │ \ │Del│NLk│P/ │P* │P- │
   * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┼───┼───┼───┼───┤
   * │ Tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │ [ │ ] │Bspc │P7 │P8 │P9 │   │
   * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┼───┼───┼───┤P+ │
   * │FnCaps│ A │ S │ D │ F │ G │ H │ J │ K │ L │ ; │ ' │ Enter  │P4 │P5 │P6 │   │
   * ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────┬───┼───┼───┼───┼───┤
   * │LSft│RAG│ Z │ X │ C │ V │ B │ N │ M │ , │ . │ / │RShift│ ↑ │P1 │P2 │P3 │   │
   * ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┴┬──┴──┬───┼───┼───┼───┼───┤PEn│
   * │LCtl│LGui│LAlt│         Space          │RAlGu│RCtrl│ ← │ ↓ │ → │P0 │P. │   │
   * └────┴────┴────┴────────────────────────┴─────┴─────┴───┴───┴───┴───┴───┴───┘
   */
  [L_BASE] = LAYOUT( \
    KC_ESC,  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_PSCR, KC_INS,  KC_HOME, KC_END,  KC_PGUP, KC_PGDN,
    KC_GRV,  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_BSLS, KC_DEL,  KC_NLCK, KC_PSLS, KC_PAST, KC_PMNS,
    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_BSPC,          KC_P7,   KC_P8,   KC_P9,   XXXXXXX,
    FN_CAPS, 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_P4,   KC_P5,   KC_P6,   KC_PPLS,
    KC_LSFT, RAL_RGU, KC_Z,    KC_X,    KC_C,    KC_V,    KC_B,    KC_N,    KC_M,    KC_COMM, KC_DOT,  KC_SLSH, KC_RSFT,          KC_UP,   KC_P1,   KC_P2,   KC_P3,   XXXXXXX,
    KC_LCTL, KC_LGUI, KC_LALT,                            KC_SPC,                             RAL_RGU, XXXXXXX, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT, KC_P0,   KC_PDOT, KC_PENT
  ),

  /* Function layer
   * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
   * │   │   │   │   │   │   │   │   │   │   │   │   │   │Sys│SLk│Pau│Brk│Top│Btm│
   * ├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
   * │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │RTg│ ÷ │ × │ − │
   * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┼───┼───┼───┼───┤
   * │ M4  │M2 │M↑ │M1 │M3 │M5 │   │UCM│   │Stp│Ply│Prv│Nxt│Clear│RH+│RS+│RV+│   │
   * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┼───┼───┼───┤RSt│
   * │      │M← │M↓ │M→ │MW↑│   │   │   │   │   │   │   │        │RH-│RS-│RV-│   │
   * ├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────┬───┼───┼───┼───┼───┤
   * │    │   │MA0│MA2│MW←│MW→│   │   │   │Vo-│Vo+│Mut│      │PgU│RMR│RMS│RMB│   │
   * ├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┴┬──┴──┬───┼───┼───┼───┼───┤RMP│
   * │    │DtPR│DtNA│          MW↓           │     │ App │Hom│PgD│End│RM-│RM+│   │
   * └────┴────┴────┴────────────────────────┴─────┴─────┴───┴───┴───┴───┴───┴───┘
   */
  [L_FN] = LAYOUT( \
    _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_SYSR, KC_SLCK, KC_PAUS, KC_BRK,  TOP,     BOTTOM,
    _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, RGB_TOG, DIVIDE,  TIMES,   MINUS,
    KC_BTN4, KC_BTN2, KC_MS_U, KC_BTN1, KC_BTN3, KC_BTN5, _______, UC_MOD,  _______, KC_MSTP, KC_MPLY, KC_MPRV, KC_MNXT, CLEAR,            RGB_HUI, RGB_SAI, RGB_VAI, XXXXXXX,
    _______, KC_MS_L, KC_MS_D, KC_MS_R, KC_WH_U, _______, _______, _______, _______, _______, _______, _______, _______,                   RGB_HUD, RGB_SAD, RGB_VAD, RGB_SET,
    _______, _______, KC_ACL0, KC_ACL2, KC_WH_L, KC_WH_R, _______, _______, _______, KC_VOLD, KC_VOLU, KC_MUTE, _______,          KC_PGUP, RGB_M_R, RGB_M_SN,RGB_M_B, XXXXXXX,
    _______, DST_P_R, DST_N_A,                            KC_WH_D,                            _______, XXXXXXX, KC_APP,  KC_HOME, KC_PGDN, KC_END,  RGB_RMOD,RGB_MOD, RGB_M_P
  ),
};

A keyboards/melody96/keymaps/konstantin/rules.mk => keyboards/melody96/keymaps/konstantin/rules.mk +10 -0
@@ 0,0 1,10 @@
BOOTMAGIC_ENABLE  = no
COMMAND_ENABLE    = yes
CONSOLE_ENABLE    = no
EXTRAKEY_ENABLE   = yes
MOUSEKEY_ENABLE   = yes
NKRO_ENABLE       = yes
TAP_DANCE_ENABLE  = yes
UNICODEMAP_ENABLE = yes

BACKLIGHT_ENABLE = no

M keyboards/whitefox/keymaps/konstantin/keymap.c => keyboards/whitefox/keymaps/konstantin/keymap.c +4 -4
@@ 25,15 25,15 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {

  /* Function layer
   * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
   * │   │F1 │F2 │F3 │F4 │F5 │F6 │F7 │F8 │F9 │F10│F11│F12│Num│Scr│Pau│
   * │   │F1 │F2 │F3 │F4 │F5 │F6 │F7 │F8 │F9 │F10│F11│F12│Num│SLk│Pau│
   * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┼───┤
   * │ M4  │M2 │M↑ │M1 │M3 │M5 │   │UCM│   │Stp│Ply│Prv│Nxt│Clear│Ins│
   * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┼───┤
   * │      │M← │M↓ │M→ │MW↑│   │   │   │   │   │   │   │        │Top│
   * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────┬───┼───┤
   * │        │MA0│MA2│MW←│MW→│   │   │   │VoD│VoU│Mut│ App  │PgU│Btm│
   * │        │MA0│MA2│MW←│MW→│   │   │   │Vo-│Vo+│Mut│ App  │PgU│Btm│
   * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬─┬───┼───┼───┤
   * │    │Dstp│Dst←│          MW↓           │Dst→│    │ │Hom│PgD│End│
   * │    │DtPR│DtNA│          MW↓           │    │    │ │Hom│PgD│End│
   * └────┴────┴────┴────────────────────────┴────┴────┘ └───┴───┴───┘
   */
  [L_FN] = LAYOUT_truefox( \


@@ 41,7 41,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    KC_BTN4, KC_BTN2, KC_MS_U, KC_BTN1, KC_BTN3, KC_BTN5, _______, UC_MOD,  _______, KC_MSTP, KC_MPLY, KC_MPRV, KC_MNXT, CLEAR,            KC_INS,  \
    _______, KC_MS_L, KC_MS_D, KC_MS_R, KC_WH_U, _______, _______, _______, _______, _______, _______, _______,          _______,          TOP,     \
    _______,          KC_ACL0, KC_ACL2, KC_WH_L, KC_WH_R, _______, _______, _______, KC_VOLD, KC_VOLU, KC_MUTE, KC_APP,           KC_PGUP, BOTTOM,  \
    _______, DESKTOP, DSKTP_L,                            KC_WH_D,                   DSKTP_R, _______,                   KC_HOME, KC_PGDN, KC_END   \
    _______, DST_P_R, DST_N_A,                            KC_WH_D,                   _______, _______,                   KC_HOME, KC_PGDN, KC_END   \
  ),

  /* Numpad layer

M keyboards/whitefox/keymaps/konstantin/rules.mk => keyboards/whitefox/keymaps/konstantin/rules.mk +9 -0
@@ 1,2 1,11 @@
BOOTMAGIC_ENABLE  = no
COMMAND_ENABLE    = yes
CONSOLE_ENABLE    = yes
EXTRAKEY_ENABLE   = yes
MOUSEKEY_ENABLE   = yes
NKRO_ENABLE       = yes
TAP_DANCE_ENABLE  = yes
UNICODEMAP_ENABLE = yes

BACKLIGHT_ENABLE  = no
VISUALIZER_ENABLE = no

M users/konstantin/konstantin.c => users/konstantin/konstantin.c +43 -11
@@ 1,15 1,25 @@
#include "konstantin.h"

#ifdef LAYER_NUMPAD
static void toggle_numpad(void) {
  layer_invert(L_NUMPAD);
  bool numpad_on = IS_LAYER_ON(L_NUMPAD);
  bool num_lock_on = IS_HOST_LED_ON(USB_LED_NUM_LOCK);
  if (num_lock_on != numpad_on) {
    tap_code(KC_NLCK); // Toggle Num Lock to match layer state
  }
__attribute__((weak))
void keyboard_pre_init_keymap(void) {}

void keyboard_pre_init_user(void) {
  keyboard_pre_init_keymap();
}

__attribute__((weak))
void eeconfig_init_keymap(void) {}

void eeconfig_init_user(void) {
  eeconfig_init_keymap();
}

__attribute__((weak))
void keyboard_post_init_keymap(void) {}

void keyboard_post_init_user(void) {
  keyboard_post_init_keymap();
}
#endif

__attribute__((weak))
bool process_record_keymap(uint16_t keycode, keyrecord_t *record) {


@@ 21,6 31,16 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    return false;
  }

#ifdef LAYER_NUMPAD
  void toggle_numpad(void) {
    layer_invert(L_NUMPAD);
    bool numpad = IS_LAYER_ON(L_NUMPAD), num_lock = IS_HOST_LED_ON(USB_LED_NUM_LOCK);
    if (num_lock != numpad) {
      tap_code(KC_NLCK);  // Toggle Num Lock to match layer state
    }
  }
#endif

  switch (keycode) {
  case CLEAR:
    if (record->event.pressed) {


@@ 28,12 48,24 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    }
    return false;

  case DST_P_R:
    (record->event.pressed ? register_code16 : unregister_code16)(
      (get_mods() & DST_MOD_MASK) ? DST_REM : DST_PRV
    );
    return false;

  case DST_N_A:
    (record->event.pressed ? register_code16 : unregister_code16)(
      (get_mods() & DST_MOD_MASK) ? DST_ADD : DST_NXT
    );
    return false;

#ifdef LAYER_FN
  static bool fn_lock;
    static bool fn_lock;

  case FN_FNLK:
    if (record->event.pressed && record->tap.count == TAPPING_TOGGLE) {
      fn_lock = !IS_LAYER_ON(L_FN); // Fn layer will be toggled after this
      fn_lock = !IS_LAYER_ON(L_FN);  // Fn layer will be toggled after this
    }
    return true;
#endif

M users/konstantin/konstantin.h => users/konstantin/konstantin.h +27 -6
@@ 1,10 1,13 @@
#pragma once

#include "quantum.h"
#if defined(RGBLIGHT_ENABLE) || defined(RGBMATRIX_ENABLE)
  #include "rgb.h"
#endif
#ifdef TAP_DANCE_ENABLE
  #include "tap_dance.h"
#endif
#ifdef UNICODE_ENABLE
#if defined(UNICODE_ENABLE) || defined(UNICODEMAP_ENABLE)
  #include "unicode.h"
#endif



@@ 14,6 17,10 @@
  #define FN_FNLK TT(L_FN)
#endif

#define KC_SYSR LALT(KC_PSCR)
#undef  KC_BRK
#define KC_BRK  LCTL(KC_PAUS)

#define MV_UP   LCTL(KC_UP)
#define MV_DOWN LCTL(KC_DOWN)
#define MV_LEFT LCTL(KC_LEFT)


@@ 23,20 30,30 @@
#define PRV_TAB LCTL(KC_PGUP)
#define NXT_TAB LCTL(KC_PGDN)

#define DST_ADD LCTL(LGUI(KC_D))
#define DST_REM LCTL(LGUI(KC_F4))
#define DST_PRV LCTL(LGUI(KC_LEFT))
#define DST_NXT LCTL(LGUI(KC_RGHT))
#ifndef DST_MOD_MASK
  #define DST_MOD_MASK MOD_MASK_CTRL
#endif

#define LCT_CPS LCTL_T(KC_CAPS)

#ifdef SEND_STRING_CLEAN
  #undef  SEND_STRING
  #define SEND_STRING(...) {            \
      uint8_t ss_mods = get_mods();     \
      clear_mods();                     \
      send_string_P(PSTR(__VA_ARGS__)); \
      set_mods(ss_mods);                \
  #define SEND_STRING(string) {     \
      uint8_t ss_mods = get_mods(); \
      clear_mods();                 \
      send_string_P(PSTR(string));  \
      set_mods(ss_mods);            \
    }
#endif

enum keycodes_user {
  CLEAR = SAFE_RANGE,
  DST_P_R,
  DST_N_A,
#ifdef LAYER_NUMPAD
  NUMPAD,
#endif


@@ 56,5 73,9 @@ enum layers_user {
  L_RANGE_KEYMAP,
};

void keyboard_pre_init_keymap(void);
void eeconfig_init_keymap(void);
void keyboard_post_init_keymap(void);

bool process_record_keymap(uint16_t keycode, keyrecord_t *record);
uint32_t layer_state_set_keymap(uint32_t state);

A users/konstantin/rgb.c => users/konstantin/rgb.c +24 -0
@@ 0,0 1,24 @@
#include "rgb.h"

#ifdef RGBLIGHT_EFFECT_BREATHING
const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {20, 30, 5, 10};
#endif

#ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD
const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {20, 50, 100};
#endif

#ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL
const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {20, 50, 100};
#endif

#ifdef RGBLIGHT_EFFECT_SNAKE
const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {20, 50, 100};
#endif

#ifdef RGBLIGHT_EFFECT_KNIGHT
const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {20, 50, 100};
#endif

const hsv_t GODSPEED_BLUE   = { .h = 280, .s = 68,  .v = RGBLIGHT_LIMIT_VAL };
const hsv_t GODSPEED_YELLOW = { .h = 38,  .s = 153, .v = RGBLIGHT_LIMIT_VAL };

A users/konstantin/rgb.h => users/konstantin/rgb.h +18 -0
@@ 0,0 1,18 @@
#pragma once

#include "quantum.h"

typedef struct {
  uint16_t h;  // 0–360
  uint8_t  s;  // 0–255
  uint8_t  v;  // 0–255
} hsv_t;

typedef struct {
  uint8_t r;  // 0–255
  uint8_t g;  // 0–255
  uint8_t b;  // 0–255
} rgb_t;

extern const hsv_t GODSPEED_BLUE;
extern const hsv_t GODSPEED_YELLOW;

M users/konstantin/rules.mk => users/konstantin/rules.mk +6 -9
@@ 1,15 1,12 @@
BOOTMAGIC_ENABLE   = no
COMMAND_ENABLE     = yes
CONSOLE_ENABLE     = yes
EXTRAKEY_ENABLE    = yes
MOUSEKEY_ENABLE    = yes
NKRO_ENABLE        = yes
TAP_DANCE_ENABLE   = yes
UNICODE_ENABLE     = yes

SRC += konstantin.c
ifneq (,$(filter yes,$(RGBLIGHT_ENABLE) $(RGB_MATRIX_ENABLE)))  # if either is yes
  SRC += rgb.c
endif
ifeq ($(strip $(TAP_DANCE_ENABLE)), yes)
  SRC += tap_dance.c
endif
ifneq (,$(filter yes,$(UNICODE_ENABLE) $(UNICODEMAP_ENABLE)))  # if either is yes
  SRC += unicode.c
endif

EXTRAFLAGS += -flto

M users/konstantin/tap_dance.c => users/konstantin/tap_dance.c +75 -51
@@ 1,93 1,117 @@
#include "tap_dance.h"
#include "konstantin.h"

#define ACTION_TAP_DANCE_DOUBLE_MODS(mod1, mod2) { \
    .fn = { td_double_mods_each, NULL, td_double_mods_reset }, \
    .user_data = &(qk_tap_dance_pair_t){ mod1, mod2 }, \
#define ACTION_TAP_DANCE_DOUBLE_MOD(mod1, mod2) {                   \
    .fn        = { td_double_mod_each, NULL, td_double_mod_reset }, \
    .user_data = &(qk_tap_dance_pair_t){ mod1, mod2 },              \
  }

void td_double_mods_each(qk_tap_dance_state_t *state, void *user_data) {
  qk_tap_dance_pair_t *mods = (qk_tap_dance_pair_t *)user_data;
void td_double_mod_each(qk_tap_dance_state_t *state, void *user_data) {
  qk_tap_dance_pair_t *data = (qk_tap_dance_pair_t *)user_data;

  // Single tap → mod1, double tap → mod2, triple tap etc. → mod1+mod2
  if (state->count == 1 || state->count == 3) {
    register_code(mods->kc1);
    register_code(data->kc1);
  } else if (state->count == 2) {
    unregister_code(mods->kc1);
    register_code(mods->kc2);
    unregister_code(data->kc1);
    register_code(data->kc2);
  }
  // Prevent tap dance from sending kc1 and kc2 as weak mods
  state->weak_mods &= ~(MOD_BIT(mods->kc1) | MOD_BIT(mods->kc2));
  // Prevent tap dance from sending the mods as weak mods
  state->weak_mods &= ~(MOD_BIT(data->kc1) | MOD_BIT(data->kc2));
}

void td_double_mods_reset(qk_tap_dance_state_t *state, void *user_data) {
  qk_tap_dance_pair_t *mods = (qk_tap_dance_pair_t *)user_data;
void td_double_mod_reset(qk_tap_dance_state_t *state, void *user_data) {
  qk_tap_dance_pair_t *data = (qk_tap_dance_pair_t *)user_data;

  if (state->count == 1 || state->count >= 3) {
    unregister_code(mods->kc1);
    unregister_code(data->kc1);
  }
  if (state->count >= 2) {
    unregister_code(mods->kc2);
    unregister_code(data->kc2);
  }
}

struct {
  bool fn_on; // Layer state when tap dance started
  bool started;
} td_fn_rctrl_data;

void td_fn_rctrl_each(qk_tap_dance_state_t *state, void *user_data) {
  if (!td_fn_rctrl_data.started) {
    td_fn_rctrl_data.fn_on = IS_LAYER_ON(L_FN);
    td_fn_rctrl_data.started = true;
#define ACTION_TAP_DANCE_MOD_LAYER(mod, layer) {                  \
    .fn        = { td_mod_layer_each, NULL, td_mod_layer_reset }, \
    .user_data = &(qk_tap_dance_dual_role_t){ mod, layer },       \
  }
  // Single tap → Fn, double tap → RCtrl, triple tap etc. → Fn+RCtrl

void td_mod_layer_each(qk_tap_dance_state_t *state, void *user_data) {
  qk_tap_dance_dual_role_t *data = (qk_tap_dance_dual_role_t *)user_data;

  // Single tap → mod, double tap → layer, triple tap etc. → mod+layer
  if (state->count == 1 || state->count == 3) {
    layer_on(L_FN);
    register_code(data->kc);
  } else if (state->count == 2) {
    if (!td_fn_rctrl_data.fn_on) {
      layer_off(L_FN);
    }
    register_code(KC_RCTL);
    unregister_code(data->kc);
    // Prevent tap dance from sending the mod as a weak mod
    state->weak_mods &= ~MOD_BIT(data->kc);
    layer_on(data->layer);
  }
}

void td_fn_rctrl_reset(qk_tap_dance_state_t *state, void *user_data) {
  if ((state->count == 1 || state->count >= 3) && !td_fn_rctrl_data.fn_on) {
    layer_off(L_FN);
void td_mod_layer_reset(qk_tap_dance_state_t *state, void *user_data) {
  qk_tap_dance_dual_role_t *data = (qk_tap_dance_dual_role_t *)user_data;

  if (state->count == 1 || state->count >= 3) {
    unregister_code(data->kc);
  }
  if (state->count >= 2) {
    unregister_code(KC_RCTL);
    layer_off(data->layer);
  }
  td_fn_rctrl_data.started = false;
}

void td_lsft_fn_each(qk_tap_dance_state_t *state, void *user_data) {
  // Single tap → LShift, double tap → Fn, triple tap etc. → Fn+LShift
#define ACTION_TAP_DANCE_LAYER_MOD(layer, mod) {                  \
    .fn        = { td_layer_mod_each, NULL, td_layer_mod_reset }, \
    .user_data = &(qk_tap_dance_layer_mod_t){ layer, mod, 0, 0 }, \
  }

typedef struct {
  uint8_t  layer;
  uint16_t kc;
  bool     layer_on;  // Layer state when tap dance started
  bool     started;
} qk_tap_dance_layer_mod_t;

void td_layer_mod_each(qk_tap_dance_state_t *state, void *user_data) {
  qk_tap_dance_layer_mod_t *data = (qk_tap_dance_layer_mod_t *)user_data;
  if (!data->started) {
    data->layer_on = IS_LAYER_ON(data->layer);
    data->started = true;
  }

  // Single tap → layer, double tap → mod, triple tap etc. → layer+mod
  if (state->count == 1 || state->count == 3) {
    register_code(KC_LSFT);
    layer_on(data->layer);
  } else if (state->count == 2) {
    unregister_code(KC_LSFT);
    // Prevent tap dance from sending LShift as a weak mod
    state->weak_mods &= ~MOD_BIT(KC_LSFT);
    layer_on(L_FN);
    if (!data->layer_on) {
      layer_off(data->layer);
    }
    register_code(data->kc);
  }
}

void td_lsft_fn_reset(qk_tap_dance_state_t *state, void *user_data) {
  if (state->count == 1 || state->count >= 3) {
    unregister_code(KC_LSFT);
void td_layer_mod_reset(qk_tap_dance_state_t *state, void *user_data) {
  qk_tap_dance_layer_mod_t *data = (qk_tap_dance_layer_mod_t *)user_data;

  if ((state->count == 1 || state->count >= 3) && !data->layer_on) {
    layer_off(data->layer);
  }
  if (state->count >= 2) {
    layer_off(L_FN);
    unregister_code(data->kc);
  }

  data->started = false;
}

qk_tap_dance_action_t tap_dance_actions[] = {
  [TD_DESKTOP] = ACTION_TAP_DANCE_DOUBLE(LCTL(LGUI(KC_D)), LCTL(LGUI(KC_F4))), // Add/close virtual desktop
  [TD_DST_A_R] = ACTION_TAP_DANCE_DOUBLE(DST_ADD, DST_REM),

  [TD_RAL_LAL] = ACTION_TAP_DANCE_DOUBLE_MODS(KC_RALT, KC_LALT),
  [TD_RAL_RGU] = ACTION_TAP_DANCE_DOUBLE_MODS(KC_RALT, KC_RGUI),
  [TD_RCT_RSF] = ACTION_TAP_DANCE_DOUBLE_MODS(KC_RCTL, KC_RSFT),
  [TD_RAL_LAL] = ACTION_TAP_DANCE_DOUBLE_MOD(KC_RALT, KC_LALT),
  [TD_RAL_RGU] = ACTION_TAP_DANCE_DOUBLE_MOD(KC_RALT, KC_RGUI),
  [TD_RCT_RSF] = ACTION_TAP_DANCE_DOUBLE_MOD(KC_RCTL, KC_RSFT),

  [TD_FN_RCTL] = ACTION_TAP_DANCE_FN_ADVANCED(td_fn_rctrl_each, NULL, td_fn_rctrl_reset),
  [TD_LSFT_FN] = ACTION_TAP_DANCE_FN_ADVANCED(td_lsft_fn_each, NULL, td_lsft_fn_reset),
  [TD_LSFT_FN] = ACTION_TAP_DANCE_MOD_LAYER(KC_LSFT, L_FN),
  [TD_RCTL_FN] = ACTION_TAP_DANCE_MOD_LAYER(KC_RCTL, L_FN),
  [TD_FN_RCTL] = ACTION_TAP_DANCE_LAYER_MOD(L_FN, KC_RCTL),
};

M users/konstantin/tap_dance.h => users/konstantin/tap_dance.h +6 -6
@@ 2,24 2,24 @@

#include "quantum.h"

#define DESKTOP TD(TD_DESKTOP)
#define DSKTP_L LCTL(LGUI(KC_LEFT))
#define DSKTP_R LCTL(LGUI(KC_RGHT))
#define DST_A_R TD(TD_DST_A_R)

#define RAL_LAL TD(TD_RAL_LAL)
#define RAL_RGU TD(TD_RAL_RGU)
#define RCT_RSF TD(TD_RCT_RSF)

#define FN_RCTL TD(TD_FN_RCTL)
#define LSFT_FN TD(TD_LSFT_FN)
#define RCTL_FN TD(TD_RCTL_FN)
#define FN_RCTL TD(TD_FN_RCTL)

enum tap_dance {
  TD_DESKTOP,
  TD_DST_A_R,

  TD_RAL_LAL,
  TD_RAL_RGU,
  TD_RCT_RSF,

  TD_FN_RCTL,
  TD_LSFT_FN,
  TD_RCTL_FN,
  TD_FN_RCTL,
};

A users/konstantin/unicode.c => users/konstantin/unicode.c +7 -0
@@ 0,0 1,7 @@
#include "unicode.h"

#ifdef UNICODEMAP_ENABLE
const uint32_t PROGMEM unicode_map[] = {
  FOREACH_UNICODE(UCM_ENTRY)
};
#endif

M users/konstantin/unicode.h => users/konstantin/unicode.h +30 -7
@@ 2,10 2,33 @@

#include "quantum.h"

#define COMMA   UC(0x002C)
#define L_PAREN UC(0x0028)
#define R_PAREN UC(0x0029)
#define EQUALS  UC(0x003D)
#define TIMES   UC(0x00D7)
#define DIVIDE  UC(0x00F7)
#define MINUS   UC(0x2212)
#define FOREACH_UNICODE(M) \
  M(COMMA,   0x002C)       \
  M(L_PAREN, 0x0028)       \
  M(R_PAREN, 0x0029)       \
  M(EQUALS,  0x003D)       \
  M(TIMES,   0x00D7)       \
  M(DIVIDE,  0x00F7)       \
  M(MINUS,   0x2212)

#define UC_KEYCODE(name, code)  name = UC(code),

#define UCM_NAME(name, code)    UCM_ ## name,
#define UCM_ENTRY(name, code)   [UCM_ ## name] = code,
#define UCM_KEYCODE(name, code) name = X(UCM_ ## name),

#if defined(UNICODE_ENABLE)
enum unicode_keycodes {
  FOREACH_UNICODE(UC_KEYCODE)
};
#elif defined(UNICODEMAP_ENABLE)
enum unicode_names {
  FOREACH_UNICODE(UCM_NAME)
};

extern const uint32_t PROGMEM unicode_map[];

enum unicode_keycodes {
  FOREACH_UNICODE(UCM_KEYCODE)
};
#endif