~ruther/qmk_firmware

07a1574732677dd91acde20020b9372cc9c82685 — Joshua Diamond 4 years ago f5a38b9
[Keymap] Revamp spidey3 userspace and keymaps (#11768)

* Don't block keys during startup animation

* More refinements related to startup and debug state

* restore key logging

* some cleanup on scan rate reporting

* trim some fat

* better lighting to indicate jumped to bootloader

* use eeprom for state restoration

* a little reorganization

* report version immediately when turn on debug

* hold-to-adjust for hue, sat, val

* cformat

* reorg rules.mk settings, fix compile with CONSOLE_ENABLE=no

* simplify spidey3 userspace

* NULL in layer list caused buggy behavior

* more bugfix

* update numpad layout to match matt30 MT3 /dev/tty keycaps

* swap emdash and endash

* map shift+backspace to delete

* removing NO_ACTION_ONSHOT makes the firmware SMALLER ?!

* cformat

* improve spi_glow

* disable shift-backspace = delete by default
M layouts/community/75_ansi/spidey3/config.h => layouts/community/75_ansi/spidey3/config.h +0 -1
@@ 1,6 1,5 @@
#pragma once

#define NO_ACTION_ONESHOT
#define NO_ACTION_MACRO
#define NO_ACTION_FUNCTION
#undef LOCKING_SUPPORT_ENABLE

M layouts/community/75_ansi/spidey3/keymap.c => layouts/community/75_ansi/spidey3/keymap.c +11 -20
@@ 3,7 3,7 @@
#define FN_MENU LT(_FN,KC_APP)

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    // Linux / Win layout
    // Base
    [_BASE] = LAYOUT_75_ansi(
        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_DEL,
        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_BSPC,    KC_HOME,


@@ 12,31 12,22 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
        KC_LSFT,    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_END,
        KC_LCTL,    KC_LGUI,    KC_LALT,                                    KC_SPC,                                             KC_RALT,    FN_MENU,    KC_RCTL,    KC_LEFT,    KC_DOWN,    KC_RGHT
    ),
    // OSX layout
    [_OSX] = LAYOUT_75_ansi(
        _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,
        _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,                _______,    _______,
        _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,                _______,    _______,
        _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,                            _______,    _______,
        _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,                            _______,    _______,    _______,
        _______,    KC_LALT,    KC_LGUI,                                    _______,                                            _______,    _______,    _______,    _______,    _______,    _______
    ),
    // Numpad
    [_NUMPAD] = LAYOUT_75_ansi(
        XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    KC_NUMLOCK, KC_PEQL,    KC_PSLS,    KC_PAST,    XXXXXXX,    XXXXXXX,    _______,    _______,    _______,
        XXXXXXX,    XXXXXXX,    XXXXXXX,    KC_NUMLOCK, XXXXXXX,    XXXXXXX,    XXXXXXX,    KC_KP_7,    KC_KP_8,    KC_KP_9,    KC_PSLS,    KC_PMNS,    KC_PEQL,                _______,    _______,
        _______,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    KC_KP_4,    KC_KP_5,    KC_KP_6,    KC_PAST,    _______,    _______,                _______,    _______,
        _______,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    KC_KP_1,    KC_KP_2,    KC_KP_3,    KC_PMNS,    KC_SCLN,                            KC_PENT,    _______,
        _______,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    KC_KP_0,    KC_PDOT,    KC_PCMM,    KC_PPLS,                            _______,    _______,    _______,
        _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,    _______,
        XXXXXXX,    XXXXXXX,    XXXXXXX,    KC_NUMLOCK, XXXXXXX,    XXXXXXX,    XXXXXXX,    KC_KP_7,    KC_KP_8,    KC_KP_9,    KC_KP_0,    KC_PMNS,    KC_PEQL,                _______,    _______,
        _______,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    KC_KP_4,    KC_KP_5,    KC_KP_6,    KC_PCMM,    _______,    _______,                _______,    _______,
        KC_NUMLOCK, XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    KC_KP_1,    KC_KP_2,    KC_KP_3,    KC_PPLS,    KC_PAST,                            KC_PENT,    _______,
        _______,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    XXXXXXX,    KC_KP_0,    SPI_KP_00,  KC_PDOT,    KC_PSLS,                            _______,    _______,    _______,
        _______,    _______,    _______,                                    _______,                                            _______,    _______,    _______,    _______,    _______,    _______
    ),
    // FN
    [_FN] = LAYOUT_75_ansi(
        RESET,      SPI_NORMAL, SPI_WIDE,   SPI_SCRIPT, SPI_BLOCKS, SPI_CIRCLE, SPI_SQUARE, SPI_PARENS, SPI_FRAKTR, _______,    _______,    _______,    SPI_GFLOCK, KC_SLEP,    KC_WAKE,    KC_PWR,
        EEP_RST,    X(SAD),     X(MEH),     X(HAPPY),   X(ANGRY),   X(THUMBDN), X(THUMBUP), X(SPIDER),  X_BUL,      X(LOL),     X(SURPRISE),X_DASH,     _______,                KC_PAUS,    KC_SLCK,
        _______,    RGB_TOG,    RGB_MOD,    RGB_HUD,    RGB_HUI,    RGB_SAD,    RGB_SAI,    RGB_VAD,    RGB_VAI,    RGB_SPD,    RGB_SPI,    VLK_TOG,    _______,                _______,    KC_BRIU,
        _______,    RGB_M_P,    RGB_M_B,    RGB_M_R,    RGB_M_SW,   RGB_M_SN,   RGB_M_K,    RGB_M_G,    RGB_M_T,    SPI_LNX,    _______,    _______,                            _______,    KC_BRID,
        _______,    SPI_GLO,    CH_SUSP,    SPI_WIN,    _______,    NK_TOGG,    TG(_NUMPAD),SPI_OSX,    X(LARR),    X(RARR),    DEBUG,      _______,                            KC_VOLU,    KC_MUTE,
        RESET,      SPI_NORMAL, SPI_WIDE,   SPI_SCRIPT, SPI_BLOCKS, SPI_CIRCLE, SPI_SQUARE, SPI_PARENS, SPI_FRAKTR, XXXXXXX,    XXXXXXX,    XXXXXXX,    SPI_GFLOCK, KC_SLEP,    CH_SUSP,    KC_PWR,
        EEP_RST,    X(SAD),     X(MEH),     X(HAPPY),   X(ANGRY),   X(THUMBDN), X(THUMBUP), X(SPIDER),  X_BUL,      X(LOL),     X(SURPRISE),X_DASH,     XXXXXXX,                KC_PAUS,    KC_SLCK,
        XXXXXXX,    RGB_TOG,    RGB_MOD,    RGB_HUD,    RGB_HUI,    RGB_SAD,    RGB_SAI,    RGB_VAD,    RGB_VAI,    RGB_SPD,    RGB_SPI,    VLK_TOG,    XXXXXXX,                XXXXXXX,    KC_BRIU,
        XXXXXXX,    RGB_M_P,    RGB_M_B,    RGB_M_R,    RGB_M_SW,   RGB_M_SN,   RGB_M_K,    RGB_M_G,    RGB_M_T,    SPI_LNX,    XXXXXXX,    XXXXXXX,                            XXXXXXX,    KC_BRID,
        _______,    SPI_GLO,    XXXXXXX,    SPI_WIN,    UC_MOD,     NK_TOGG,    TG(_NUMPAD),SPI_OSX,    X(LARR),    X(RARR),    DEBUG,      _______,                            KC_VOLU,    KC_MUTE,
        _______,    _______,    _______,                                    KC_MPLY,                                            CH_ASST,    _______,    CH_CPNL,    KC_MPRV,    KC_VOLD,    KC_MNXT
    )
};

M layouts/community/75_ansi/spidey3/rules.mk => layouts/community/75_ansi/spidey3/rules.mk +0 -2
@@ 2,8 2,6 @@
#   comment out to disable the options.
#
MOUSEKEY_ENABLE = no	# Mouse keys
CONSOLE_ENABLE = yes	# Console for debug
BACKLIGHT_ENABLE = no	# Enable keyboard backlight functionality
UNICODEMAP_ENABLE = yes
VELOCIKEY_ENABLE = yes
GRAVE_ESC_ENABLE = no

M users/spidey3/config.h => users/spidey3/config.h +4 -1
@@ 3,9 3,10 @@
#define LED_DISABLE_WHEN_USB_SUSPENDED true
#define RGB_DISABLE_WHEN_USB_SUSPENDED true
#define RGBLIGHT_LAYERS
#define RGBLIGHT_MAX_LAYERS 16
#define RGBLIGHT_MAX_LAYERS 17
#define RGBLIGHT_LAYER_BLINK
#define RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF
#define RGBLIGHT_STARTUP_ANIMATION

#undef RGBLIGHT_ANIMATIONS
#define RGBLIGHT_EFFECT_BREATHING


@@ 17,6 18,8 @@
#define RGBLIGHT_EFFECT_ALTERNATING
#define RGBLIGHT_EFFECT_TWINKLE

#define UNICODE_SELECTED_MODES UC_MAC, UC_LNX, UC_WINC

#define SPI_DEBUG_SCAN_RATE

#undef MANUFACTURER

M users/spidey3/init.c => users/spidey3/init.c +1 -6
@@ 18,11 18,6 @@ void eeconfig_init_user(void) {
#endif
}

void shutdown_user() {
#ifdef RGBLIGHT_ENABLE
    clear_rgb_layers();
    rgblight_enable();
    rgblight_mode_noeeprom(RGBLIGHT_MODE_STATIC_LIGHT);
    rgblight_sethsv_noeeprom(HSV_RED);
void shutdown_user(void) { shutdown_user_rgb(); }
#endif
}

M users/spidey3/layer_rgb.c => users/spidey3/layer_rgb.c +302 -95
@@ 2,6 2,7 @@

#include "spidey3.h"
#include "velocikey.h"
#include <lib/lib8tion/lib8tion.h>

uint32_t rgb_mode;
uint16_t rgb_hue;


@@ 9,10 10,17 @@ uint8_t  rgb_sat;
uint8_t  rgb_val;
bool     rgb_saved = 0;

extern bool     spi_gflock;
extern uint16_t spi_replace_mode;

void spidey_glow(void) {
    rgblight_enable();
    rgblight_mode(RGBLIGHT_MODE_TWINKLE + 4);
    rgblight_sethsv(213, 255, 128);
    if ((RGBLIGHT_MODE_TWINKLE <= rgblight_get_mode()) && (rgblight_get_mode() < RGBLIGHT_MODE_TWINKLE_end)) {
        rgblight_step();
    } else {
        rgblight_mode(RGBLIGHT_MODE_TWINKLE);
    }
#ifdef VELOCIKEY_ENABLE
    if (velocikey_enabled()) velocikey_toggle();
#endif


@@ 23,6 31,7 @@ void eeconfig_init_user_rgb(void) { spidey_glow(); }
// clang-format off

// Convenience macros
#define NONE { RGBLIGHT_END_SEGMENTS }
#define CORNER_BL(color) { 0, 1, color }
#define CORNER_BR(color) { RGBLED_NUM / 2 - 1, 1, color }
#define CORNER_FR(color) { RGBLED_NUM / 2, 1, color }


@@ 31,10 40,12 @@ void eeconfig_init_user_rgb(void) { spidey_glow(); }
#define FRONT(inset, color) { RGBLED_NUM / 2 + inset, RGBLED_NUM / 2 - 2 * inset, color }
#define BACK(inset, color) { inset, RGBLED_NUM / 2 - 2 * inset, color }

const rgblight_segment_t PROGMEM _none[] = NONE;

#define LAYER_OFFSET 0
const rgblight_segment_t PROGMEM _layer1_layer[] = RGBLIGHT_LAYER_SEGMENTS(CORNER_BR(HSV_PURPLE));
const rgblight_segment_t PROGMEM _layer2_layer[] = RGBLIGHT_LAYER_SEGMENTS(CORNERS(HSV_MAGENTA));
const rgblight_segment_t PROGMEM _layer3_layer[] = RGBLIGHT_LAYER_SEGMENTS(CORNERS(HSV_GREEN));
// No indicator for base layer
const rgblight_segment_t PROGMEM _layer1_layer[] = RGBLIGHT_LAYER_SEGMENTS(CORNERS(HSV_MAGENTA));  // _NUMPAD
const rgblight_segment_t PROGMEM _layer2_layer[] = RGBLIGHT_LAYER_SEGMENTS(CORNERS(HSV_GREEN));    // _FN

#define LOCK_OFFSET 3
const rgblight_segment_t PROGMEM _numlock_layer[]    = RGBLIGHT_LAYER_SEGMENTS(FRONT(3, HSV_YELLOW));


@@ 49,12 60,20 @@ const rgblight_segment_t PROGMEM _glyphreplace_layer[] = RGBLIGHT_LAYER_SEGMENTS
const rgblight_segment_t PROGMEM _no_layer[]     = RGBLIGHT_LAYER_SEGMENTS(FRONT(1, HSV_RED));
const rgblight_segment_t PROGMEM _yes_layer[]    = RGBLIGHT_LAYER_SEGMENTS(FRONT(1, HSV_GREEN));
const rgblight_segment_t PROGMEM _meh_layer[]    = RGBLIGHT_LAYER_SEGMENTS(FRONT(1, HSV_YELLOW));
const rgblight_segment_t PROGMEM _huh_layer[]    = RGBLIGHT_LAYER_SEGMENTS(CORNERS(HSV_YELLOW), FRONT(1, HSV_BLUE), BACK(1, HSV_BLUE));

#define UNICODE_OFFSET 12
const rgblight_segment_t PROGMEM _uc_mac_layer[]  = RGBLIGHT_LAYER_SEGMENTS(CORNER_BR(HSV_PURPLE));
// No indicator for UC_LNX
// UC_WIN disabled in config.h
// UC_BSD not implemented
const rgblight_segment_t PROGMEM _uc_winc_layer[] = RGBLIGHT_LAYER_SEGMENTS(CORNER_BR(HSV_CYAN));

// Now define the array of layers. Higher numbered layers take precedence.
const rgblight_segment_t *const PROGMEM _rgb_layers[] = {
    [LAYER_OFFSET + 0] = _layer1_layer,
    [LAYER_OFFSET + 1] = _layer2_layer,
    [LAYER_OFFSET + 2] = _layer3_layer,
    [LAYER_OFFSET + _BASE]   = _none,
    [LAYER_OFFSET + _NUMPAD] = _layer1_layer,
    [LAYER_OFFSET + _FN]     = _layer2_layer,

    [LOCK_OFFSET + USB_LED_NUM_LOCK]    = _numlock_layer,
    [LOCK_OFFSET + USB_LED_CAPS_LOCK]   = _capslock_layer,


@@ 66,11 85,18 @@ const rgblight_segment_t *const PROGMEM _rgb_layers[] = {
    [ACK_OFFSET + ACK_NO]     = _no_layer,
    [ACK_OFFSET + ACK_YES]    = _yes_layer,
    [ACK_OFFSET + ACK_MEH]    = _meh_layer,
    [ACK_OFFSET + ACK_HUH]    = _huh_layer,

    [UNICODE_OFFSET + UC_MAC]  = _uc_mac_layer,
    [UNICODE_OFFSET + UC_LNX]  = _none,
    [UNICODE_OFFSET + UC_WIN]  = _none,
    [UNICODE_OFFSET + UC_BSD]  = _none,
    [UNICODE_OFFSET + UC_WINC] = _uc_winc_layer,

    [ACK_OFFSET + ACK_MEH + 1] = NULL
    [UNICODE_OFFSET + UC__COUNT] = NULL
};

// clang-format on 
// clang-format on

const uint8_t PROGMEM _n_rgb_layers = sizeof(_rgb_layers) / sizeof(_rgb_layers[0]) - 1;



@@ 84,118 110,259 @@ void clear_rgb_layers() {
void do_rgb_layers(layer_state_t state, uint8_t start, uint8_t end) {
    for (uint8_t i = start; i < end; i++) {
        bool is_on = layer_state_cmp(state, i);
        dprintf("layer[%u]=%u\n", i, is_on);
        rgblight_set_layer_state(LAYER_OFFSET + i - 1, is_on);
        dprintf("layer[%u]=rl[%u]=%u\n", i, LAYER_OFFSET + i, is_on);
        rgblight_set_layer_state(LAYER_OFFSET + i, is_on);
    }
}

void do_rgb_unicode(void) {
    uint8_t uc_mode = get_unicode_input_mode();
    for (uint8_t i = 0; i < UC__COUNT; i++) {
        bool is_on = i == uc_mode;
        dprintf("unicode[%u]=rl[%u]=%u\n", i, UNICODE_OFFSET + i, is_on);
        rgblight_set_layer_state(UNICODE_OFFSET + i, is_on);
    }
}

void do_rgb_all(void) {
    do_rgb_layers(default_layer_state, LAYER_BASE_DEFAULT, LAYER_BASE_REGULAR);
    do_rgb_layers(layer_state, LAYER_BASE_REGULAR, LAYER_BASE_END);
    do_rgb_unicode();
    rgblight_set_layer_state(MISC_OFFSET + 0, spi_gflock);
    rgblight_set_layer_state(MISC_OFFSET + 1, spi_replace_mode != SPI_NORMAL);
}

// flags. 0 = no change, 1 = increment, -1 = decrement.
int8_t change_hue = 0;
int8_t change_sat = 0;
int8_t change_val = 0;

// timer to control color change speed
uint16_t change_timer = 0;
const uint16_t change_tick  = 15;

extern rgblight_config_t rgblight_config;
extern rgblight_status_t rgblight_status;
static bool              startup_animation_done = false;

#if defined(RGBLIGHT_STARTUP_ANIMATION)

#define STARTUP_ANIMATION_SATURATION 200
#define STARTUP_ANIMATION_VALUE 255
#define STARTUP_ANIMATION_FADE_STEP 5
#define STARTUP_ANIMATION_CYCLE_STEP 2
#define STARTUP_ANIMATION_RAMP_TO_STEPS 70
#define STARTUP_ANIMATION_STEP_TIME 10
#define STARTUP_ANIMATION_INITIAL_DELAY 0 // milliseconds, must be < 255 * STEP_TIME

typedef enum {
    DISABLED,
    WAITING,
    RESTART,
    START,
    FADE_OLD,
    FADE_IN,
    CYCLE,
    RAMP_DOWN,
    RAMP_TO,
    CLEAN_UP,
    DONE
} startup_animation_state_t;

static rgblight_config_t old_config;
static uint8_t old_base_mode;
static startup_animation_state_t startup_animation_state = DISABLED;
static uint16_t rgblight_startup_loop_timer;

void startup_animation_init(void) {
    old_config.raw = rgblight_config.raw;
    old_base_mode  = rgblight_status.base_mode;

    if (!old_config.enable)
        rgblight_enable_noeeprom();
}
#endif

void keyboard_post_init_user_rgb(void) {
    // Enable the LED layers
    rgblight_layers = _rgb_layers;
    do_rgb_layers(default_layer_state, LAYER_BASE_DEFAULT + 1, LAYER_BASE_REGULAR);
    do_rgb_layers(layer_state, LAYER_BASE_REGULAR, LAYER_BASE_END);
    do_rgb_all();

    // Startup animation
    {
        bool    is_enabled = rgblight_config.enable;
        uint8_t old_hue    = rgblight_config.hue;
        uint8_t old_sat    = rgblight_config.sat;
        uint8_t old_val    = rgblight_config.val;
        uint8_t old_mode   = rgblight_config.mode;
#if defined(RGBLIGHT_STARTUP_ANIMATION)
    startup_animation_init();
    startup_animation_state = STARTUP_ANIMATION_INITIAL_DELAY ? WAITING : START;
#endif
}

        bool ramp_down =
void matrix_scan_user_rgb(void) {
#if defined(RGBLIGHT_STARTUP_ANIMATION)
    if (startup_animation_state != DONE && is_keyboard_master()) {
        if (startup_animation_state == START || timer_elapsed(rgblight_startup_loop_timer) > STARTUP_ANIMATION_STEP_TIME) {
            static uint8_t counter;
            rgblight_startup_loop_timer = timer_read();

            switch (startup_animation_state) {
                case WAITING:
#ifdef STARTUP_ANIMATION_DEBUG
                    dprintf("sua WAITING counter=%u\n", counter);
#endif
                    if (counter < STARTUP_ANIMATION_INITIAL_DELAY / STARTUP_ANIMATION_STEP_TIME) {
                        counter++;
                    } else {
                        startup_animation_state = START;
                    }
                    break;

                case RESTART:
                    dprintln("sua RESTART");
                    startup_animation_init();
                case START:
                    dprintln("sua START");
                    startup_animation_state = FADE_OLD;
                    counter = old_config.val;
                    // No break! Just roll into FADE_OLD in the same iteration...

                case FADE_OLD:
#ifdef STARTUP_ANIMATION_DEBUG
                    dprintf("sua FADE_OLD counter=%u\n", counter);
#endif
                    if (counter >= STARTUP_ANIMATION_FADE_STEP) {
                        rgblight_sethsv_noeeprom(old_config.hue, old_config.sat, counter);
                        counter -= STARTUP_ANIMATION_FADE_STEP;
                    } else {
                        counter = 0;
                        startup_animation_state = FADE_IN;
                        rgblight_mode_noeeprom(RGBLIGHT_MODE_STATIC_LIGHT);
                    }
                    break;

                case FADE_IN:
#ifdef STARTUP_ANIMATION_DEBUG
                    dprintf("sua FADE_IN counter=%u\n", counter);
#endif
                    if (counter < STARTUP_ANIMATION_VALUE) {
                        rgblight_sethsv_noeeprom(old_config.hue, STARTUP_ANIMATION_SATURATION, counter);
                        counter += STARTUP_ANIMATION_FADE_STEP;
                    } else {
                        counter = 255;
                        startup_animation_state = CYCLE;
                    }
                    break;

                case CYCLE:
#ifdef STARTUP_ANIMATION_DEBUG
                    dprintf("sua CYCLE counter=%u\n", counter);
#endif
                    if (counter >= STARTUP_ANIMATION_CYCLE_STEP) {
                        rgblight_sethsv_noeeprom((counter + old_config.hue) % 255, STARTUP_ANIMATION_SATURATION, STARTUP_ANIMATION_VALUE);
                        counter -= STARTUP_ANIMATION_CYCLE_STEP;
                    } else {
                        if (
#ifdef RGBLIGHT_EFFECT_BREATHING
            (rgblight_status.base_mode == RGBLIGHT_MODE_BREATHING) ||
                            (old_base_mode == RGBLIGHT_MODE_BREATHING) ||
#endif
#ifdef RGBLIGHT_EFFECT_SNAKE
            (rgblight_status.base_mode == RGBLIGHT_MODE_SNAKE) ||
                            (old_base_mode == RGBLIGHT_MODE_SNAKE) ||
#endif
#ifdef RGBLIGHT_EFFECT_KNIGHT
            (rgblight_status.base_mode == RGBLIGHT_MODE_KNIGHT) ||
                            (old_base_mode == RGBLIGHT_MODE_KNIGHT) ||
#endif
#ifdef RGBLIGHT_EFFECT_TWINKLE
            (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) ||
                            (old_base_mode == RGBLIGHT_MODE_TWINKLE) ||
#endif
            !is_enabled;

        bool ramp_to =
                            !old_config.enable) {
                            counter = STARTUP_ANIMATION_VALUE;
                            startup_animation_state = RAMP_DOWN;
                        } else if (
#ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT
            (rgblight_status.base_mode == RGBLIGHT_MODE_STATIC_GRADIENT) ||
                            (old_base_mode == RGBLIGHT_MODE_STATIC_GRADIENT) ||
#endif
#ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD
            (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_MOOD) ||
                            (old_base_mode == RGBLIGHT_MODE_RAINBOW_MOOD) ||
#endif
#ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL
            (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_SWIRL) ||
                            (old_base_mode == RGBLIGHT_MODE_RAINBOW_SWIRL) ||
#endif
#ifdef RGBLIGHT_EFFECT_RAINBOW_CHRISTMAS
            (rgblight_status.base_mode == RGBLIGHT_MODE_CHRISTMAS) ||
                            (old_base_mode == RGBLIGHT_MODE_CHRISTMAS) ||
#endif
#ifdef RGBLIGHT_EFFECT_RAINBOW_RGB_TEST_
            (rgblight_status.base_mode == RGBLIGHT_MODE_RGB_TEST) ||
                            (old_base_mode == RGBLIGHT_MODE_RGB_TEST) ||
#endif
            (rgblight_status.base_mode == RGBLIGHT_MODE_STATIC_LIGHT);

#define STARTUP_ANIMATION_SATURATION 200
#define STARTUP_ANIMATION_VALUE 255
#define STARTUP_ANIMATION_STEP 5

        rgblight_enable_noeeprom();
        if (rgblight_config.enable) {
            rgblight_mode_noeeprom(RGBLIGHT_MODE_STATIC_LIGHT);
            for (uint8_t i = 0; i < STARTUP_ANIMATION_VALUE; i += STARTUP_ANIMATION_STEP) {
                rgblight_sethsv_noeeprom(old_hue, STARTUP_ANIMATION_SATURATION, i);
                matrix_scan();
                wait_ms(10);
            }
            for (uint8_t i = 255; i > 0; i -= STARTUP_ANIMATION_STEP) {
                rgblight_sethsv_noeeprom((i + old_hue) % 255, STARTUP_ANIMATION_SATURATION, STARTUP_ANIMATION_VALUE);
                matrix_scan();
                wait_ms(10);
            }

            if (ramp_down) {
                dprintln("ramp_down");
                for (uint8_t i = STARTUP_ANIMATION_VALUE; i > 0; i -= STARTUP_ANIMATION_STEP) {
                    rgblight_sethsv_noeeprom(old_hue, STARTUP_ANIMATION_SATURATION, i);
                    matrix_scan();
                    wait_ms(10);
                }
            } else if (ramp_to) {
                dprintf("ramp_to s=%u, v=%u\n", old_sat, old_val);
                uint8_t steps = 50;
                for (uint8_t i = 0; i < steps; i++) {
                    uint8_t s = STARTUP_ANIMATION_SATURATION + i * (((float)old_sat - STARTUP_ANIMATION_SATURATION) / (float)steps);
                    uint8_t v = STARTUP_ANIMATION_VALUE + i * (((float)old_val - STARTUP_ANIMATION_VALUE) / (float)steps);
                    rgblight_sethsv_noeeprom(old_hue, s, v);
                    matrix_scan();
                    wait_ms(10);
                }
                            (old_base_mode == RGBLIGHT_MODE_STATIC_LIGHT)) {
                            counter = 0;
                            startup_animation_state = RAMP_TO;
                        } else {
                            startup_animation_state = CLEAN_UP;
                        }
                    }
                    break;

                case RAMP_DOWN:
#ifdef STARTUP_ANIMATION_DEBUG
                    dprintf("sua RAMP_DOWN counter=%u\n", counter);
#endif
                    if (counter >= STARTUP_ANIMATION_FADE_STEP) {
                        rgblight_sethsv_noeeprom(old_config.hue, STARTUP_ANIMATION_SATURATION, counter);
                        counter -= STARTUP_ANIMATION_FADE_STEP;
                    } else {
                        startup_animation_state = CLEAN_UP;
                    }
                    break;

                case RAMP_TO:
                    {
#ifdef STARTUP_ANIMATION_DEBUG
                        dprintf("sua RAMP_TO s=%u, v=%u, counter=%u\n", old_config.sat, old_config.val, counter);
#endif
                        uint8_t steps = STARTUP_ANIMATION_RAMP_TO_STEPS;
                        if (counter < steps) {
                            uint8_t s = STARTUP_ANIMATION_SATURATION + counter * (((float)old_config.sat - STARTUP_ANIMATION_SATURATION) / (float)steps);
                            uint8_t v = STARTUP_ANIMATION_VALUE + counter * (((float)old_config.val - STARTUP_ANIMATION_VALUE) / (float)steps);
                            rgblight_sethsv_noeeprom(old_config.hue, s, v);
                            counter++;
                        } else {
                            startup_animation_state = CLEAN_UP;
                        }
                    }
                    break;

                case CLEAN_UP:
                    dprintln("sua CLEAN_UP");
                    rgblight_reload_from_eeprom();
                    startup_animation_state = DONE;
                    dprintln("sua DONE");
                    break;

                default:
                    break;
            }
            rgblight_mode_noeeprom(old_mode);
        }
        if (is_enabled) {
            rgblight_sethsv_noeeprom(old_hue, old_sat, old_val);
        } else {
            rgblight_disable_noeeprom();
            // Hack!
            // rgblight_sethsv_noeeprom() doesn't update these if rgblight is disabled,
            // but if do it before disabling we get an ugly flash.
            rgblight_config.hue = old_hue;
            rgblight_config.sat = old_sat;
            rgblight_config.val = old_val;
    }
#endif

    if (change_hue != 0 || change_val != 0 || change_sat != 0) {
        if (timer_elapsed(change_timer) > change_tick) {
            HSV hsv = rgblight_get_hsv();
            hsv.h += change_hue;
            hsv.s = change_sat > 0 ? qadd8(hsv.s, (uint8_t) change_sat) : qsub8(hsv.s, (uint8_t) -change_sat);
            hsv.v = change_val > 0 ? qadd8(hsv.v, (uint8_t) change_val) : qsub8(hsv.v, (uint8_t) -change_val);
            rgblight_sethsv_noeeprom(hsv.h, hsv.s, hsv.v);
            change_timer = timer_read();
        }
        dprint("done\n");
        startup_animation_done = true;
    }
}

void shutdown_user_rgb(void) {
    clear_rgb_layers();
    rgblight_enable_noeeprom();
    rgblight_mode_noeeprom(RGBLIGHT_MODE_STATIC_LIGHT);
    for (int i = 0; i < RGBLED_NUM; i++) {
        rgblight_setrgb_at(0xFF, 0x80 * (i % 2), 0, i);
    }
}

layer_state_t default_layer_state_set_user_rgb(layer_state_t state) {
    do_rgb_layers(state, 1u, LAYER_BASE_REGULAR);
    do_rgb_layers(state, LAYER_BASE_DEFAULT, LAYER_BASE_REGULAR);
    return state;
}



@@ 225,15 392,45 @@ void rgb_layer_ack(layer_ack_t n) {
extern keymap_config_t   keymap_config;
extern rgblight_config_t rgblight_config;

extern bool     spi_gflock;
extern uint16_t spi_replace_mode;

bool process_record_user_rgb(uint16_t keycode, keyrecord_t *record) {
    if (record->event.pressed) {
        switch (keycode) {
            case SPI_GLO:
                spidey_glow();
                return false;

                // clang-format off
            case RGB_HUI: change_timer = timer_read(); change_hue =  1; return false;
            case RGB_HUD: change_timer = timer_read(); change_hue = -1; return false;
            case RGB_SAI: change_timer = timer_read(); change_sat =  1; return false;
            case RGB_SAD: change_timer = timer_read(); change_sat = -1; return false;
            case RGB_VAI: change_timer = timer_read(); change_val =  1; return false;
            case RGB_VAD: change_timer = timer_read(); change_val = -1; return false;
                // clang-format on
        }
    } else {
        bool rgb_done = false;
        switch (keycode) {
            case RGB_HUI:
            case RGB_HUD:
                change_hue = 0;
                rgb_done   = true;
                break;
            case RGB_SAI:
            case RGB_SAD:
                change_sat = 0;
                rgb_done   = true;
                break;
            case RGB_VAI:
            case RGB_VAD:
                change_val = 0;
                rgb_done   = true;
                break;
        }

        if (rgb_done) {
            HSV final = rgblight_get_hsv();
            rgblight_sethsv(final.h, final.s, final.v);
        }
    }



@@ 244,13 441,12 @@ void post_process_record_user_rgb(uint16_t keycode, keyrecord_t *record) {
    switch (keycode) {
        // Acks follow...
        case DEBUG:
            rgb_layer_ack_yn(debug_enable);
            break;

        case SPI_LNX:
        case SPI_OSX:
        case SPI_WIN:
            rgb_layer_ack(ACK_MEH);
            if (debug_matrix || debug_keyboard)
                rgb_layer_ack(ACK_HUH);
            else if (debug_enable)
                rgb_layer_ack(ACK_YES);
            else
                rgb_layer_ack(ACK_NO);
            break;

        case SPI_GFLOCK:


@@ 280,5 476,16 @@ void post_process_record_user_rgb(uint16_t keycode, keyrecord_t *record) {
            rgb_layer_ack_yn(keymap_config.nkro);
            break;
#endif

#if defined(UNICODE_ENABLE) || defined(UNICODEMAP_ENABLE) || defined(UCIS_ENABLE)
        case SPI_LNX:
        case SPI_OSX:
        case SPI_WIN:
        case UC_MOD:
        case UC_RMOD:
            rgb_layer_ack(ACK_MEH);
            do_rgb_unicode();
            break;
#endif
    }
}

M users/spidey3/rules.mk => users/spidey3/rules.mk +2 -0
@@ 1,4 1,6 @@
BOOTMAGIC_ENABLE = lite
CONSOLE_ENABLE = yes   # Console for debug
BACKLIGHT_ENABLE = no  # Enable keyboard backlight functionality
LTO_ENABLE = yes

SRC += init.c

M users/spidey3/spidey3.c => users/spidey3/spidey3.c +99 -69
@@ 14,49 14,44 @@ static uint32_t matrix_scan_count = 0;
static bool     reported_version  = false;

#    if defined(SPI_DEBUG_SCAN_RATE)
static uint32_t matrix_timer           = 0;
static uint32_t last_matrix_scan_count = 0;
static uint32_t matrix_timer = 0;
#    endif

void report_version(void) {
    uprintln(QMK_KEYBOARD "/" QMK_KEYMAP " @ " QMK_VERSION ", Built on: " QMK_BUILDDATE);
    reported_version = true;
}
#endif

void matrix_scan_user(void) {
#if defined(CONSOLE_ENABLE) && !defined(NO_DEBUG)
#    if defined(SPI_DEBUG_SCAN_RATE)
    matrix_scan_count++;
    if (debug_enable) {
        uint32_t timer_now = timer_read32();
        if (matrix_timer == 0) {
            matrix_timer           = timer_now;
            last_matrix_scan_count = matrix_scan_count;
            matrix_scan_count      = 0;
            matrix_timer      = timer_now;
            matrix_scan_count = 0;
        } else if (TIMER_DIFF_32(timer_now, matrix_timer) > SPI_SCAN_RATE_INTERVAL * 1000) {
            matrix_timer           = timer_now;
            last_matrix_scan_count = matrix_scan_count;
            matrix_scan_count      = 0;
            if (!reported_version) {
                uprintln(QMK_KEYBOARD "/" QMK_KEYMAP " @ " QMK_VERSION ", Built on: " QMK_BUILDDATE);
                reported_version = true;
            }
            uprintf("scan rate: %lu/s\n", last_matrix_scan_count / SPI_SCAN_RATE_INTERVAL);
            matrix_timer = timer_now;
            uprintf("scan rate: %lu/s\n", matrix_scan_count / SPI_SCAN_RATE_INTERVAL);
            matrix_scan_count = 0;
            if (!reported_version) report_version();
        }
    }
#    else
    if (!reported_version) {
        matrix_scan_count++;
        if (matrix_scan_count > 300) {
            uprintln(QMK_KEYBOARD "/" QMK_KEYMAP " @ " QMK_VERSION ", Built on: " QMK_BUILDDATE);
            reported_version = true;
        }
        if (matrix_scan_count > 300) report_version();
    }
#    endif
}
#endif

bool process_record_glyph_replacement(uint16_t keycode, keyrecord_t *record, uint32_t baseAlphaLower, uint32_t baseAlphaUpper, uint32_t zeroGlyph, uint32_t baseNumberOne, uint32_t spaceGlyph) {
    uint8_t temp_mod = get_mods();
#ifndef NO_ACTION_ONESHOT
    uint8_t temp_osm = get_oneshot_mods();
#else
    uint8_t temp_osm = 0;
#ifdef RGBLIGHT_ENABLE
    matrix_scan_user_rgb();
#endif
}

bool process_record_glyph_replacement(uint16_t keycode, keyrecord_t *record, uint32_t baseAlphaLower, uint32_t baseAlphaUpper, uint32_t zeroGlyph, uint32_t baseNumberOne, uint32_t spaceGlyph, uint8_t temp_mod, uint8_t temp_osm) {
    if ((((temp_mod | temp_osm) & (MOD_MASK_CTRL | MOD_MASK_ALT | MOD_MASK_GUI))) == 0) {
        switch (keycode) {
            case KC_A ... KC_Z:


@@ 121,21 116,43 @@ bool process_gflock(uint16_t keycode, keyrecord_t *record) {
}

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    dprintf("key event: kc: %02X, col: %02u, row: %02u, pressed: %u mods: %08b "
#if !defined(NO_ACTION_ONESHOT)
            "os: %08b "
#endif
            "weak: %08b\n",
            keycode, record->event.key.col, record->event.key.row, record->event.pressed, bitrev(get_mods()),
#if !defined(NO_ACTION_ONESHOT)
            bitrev(get_oneshot_mods()),
#endif
            bitrev(get_weak_mods()));

    if (!rand_seeded) {
        srand(record->event.time % keycode);
        rand_seeded = true;
    }

    uint8_t mods = get_mods();
#ifndef NO_ACTION_ONESHOT
    uint8_t osm = get_oneshot_mods();
#else
    uint8_t osm = 0;
#endif

    if (record->event.pressed) {
        switch (keycode) {
#ifndef NO_DEBUG
            // Re-implement this here, but fix the persistence!
            case DEBUG:
                if (!debug_enable) {
                if (get_mods() & MOD_MASK_SHIFT) {
                    debug_enable   = 0;
                    debug_keyboard = 0;
                    debug_matrix   = 0;
                } else if (!debug_enable) {
                    debug_enable = 1;
#    if defined(SPI_DEBUG_SCAN_RATE)
                    matrix_timer     = 0;
                    reported_version = false;
                    matrix_timer = 0;
                    report_version();
#    endif
                } else if (!debug_keyboard) {
                    debug_keyboard = 1;


@@ 157,31 174,12 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
            case CH_ASST: host_consumer_send(AL_ASSISTANT); return false;
            case CH_SUSP: tap_code16(LGUI(LSFT(KC_L))); return true;

                // clang-format on

            case SPI_LNX:
                dprint("SPI_LNX\n");
                set_single_persistent_default_layer(_BASE);
                layer_off(_OSX);
#if defined(UNICODE_ENABLE) || defined(UNICODEMAP_ENABLE)
                set_unicode_input_mode(UC_LNX);
#if defined(UNICODE_ENABLE) || defined(UNICODEMAP_ENABLE) || defined(UCIS_ENABLE)
            case SPI_LNX: set_unicode_input_mode(UC_LNX); break;
            case SPI_OSX: set_unicode_input_mode(UC_OSX); break;
            case SPI_WIN: set_unicode_input_mode(UC_WINC); break;
#endif
                break;
            case SPI_OSX:
                dprint("SPI_OSX\n");
                set_single_persistent_default_layer(_OSX);
#if defined(UNICODE_ENABLE) || defined(UNICODEMAP_ENABLE)
                set_unicode_input_mode(UC_OSX);
#endif
                break;
            case SPI_WIN:
                dprint("SPI_WIN\n");
                set_single_persistent_default_layer(_BASE);
                layer_off(_OSX);
#if defined(UNICODE_ENABLE) || defined(UNICODEMAP_ENABLE)
                set_unicode_input_mode(UC_WINC);
#endif
                break;
                // clang-format on

            case SPI_NORMAL ... SPI_FRAKTR:
                spi_replace_mode = (spi_replace_mode == keycode) ? SPI_NORMAL : keycode;


@@ 193,14 191,18 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
                dprintf("spi_gflock = %u\n", spi_gflock);
                break;

            case KC_PSCR: {
                uint8_t mods = get_mods();
#ifndef NO_ACTION_ONESHOT
                uint8_t osm = get_oneshot_mods();
#else
                uint8_t osm = 0;
            case SPI_KP_00:
                tap_code(KC_KP_0);
#if TAP_CODE_DELAY > 0
                wait_ms(TAP_CODE_DELAY);
#endif
                register_code(KC_KP_0);
                return false;

            case KC_PSCR: {
                // It's kind of a hack, but we use unicode input mode
                // to determine what Print Screen key should do. The
                // idea here is to make it consistent across hosts.
                switch (get_unicode_input_mode()) {
                    case UC_MAC:
                        if ((mods | osm) & MOD_MASK_ALT) {


@@ 265,6 267,10 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
            case CH_ASST:
                host_consumer_send(0);
                return false;

            case SPI_KP_00:
                unregister_code(KC_KP_0);
                return false;
        }
    }



@@ 273,32 279,56 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
        case KC_SPACE:
            switch (spi_replace_mode) {
                case SPI_WIDE:
                    return process_record_glyph_replacement(keycode, record, 0xFF41, 0xFF21, 0xFF10, 0xFF11, 0x2003);
                    return process_record_glyph_replacement(keycode, record, 0xFF41, 0xFF21, 0xFF10, 0xFF11, 0x2003, mods, osm);
                case SPI_SCRIPT:
                    return process_record_glyph_replacement(keycode, record, 0x1D4EA, 0x1D4D0, 0x1D7CE, 0x1D7CF, 0x2002);
                    return process_record_glyph_replacement(keycode, record, 0x1D4EA, 0x1D4D0, 0x1D7CE, 0x1D7CF, 0x2002, mods, osm);
                case SPI_BLOCKS:
                    return process_record_glyph_replacement(keycode, record, 0x1F170, 0x1F170, '0', '1', 0x2002);
                    return process_record_glyph_replacement(keycode, record, 0x1F170, 0x1F170, '0', '1', 0x2002, mods, osm);
                case SPI_CIRCLE:
                    return process_record_glyph_replacement(keycode, record, 0x1F150, 0x1F150, '0', '1', 0x2002);
                    return process_record_glyph_replacement(keycode, record, 0x1F150, 0x1F150, '0', '1', 0x2002, mods, osm);
                case SPI_SQUARE:
                    return process_record_glyph_replacement(keycode, record, 0x1F130, 0x1F130, '0', '1', 0x2002);
                    return process_record_glyph_replacement(keycode, record, 0x1F130, 0x1F130, '0', '1', 0x2002, mods, osm);
                case SPI_PARENS:
                    return process_record_glyph_replacement(keycode, record, 0x1F110, 0x1F110, '0', '1', 0x2002);
                    return process_record_glyph_replacement(keycode, record, 0x1F110, 0x1F110, '0', '1', 0x2002, mods, osm);
                case SPI_FRAKTR:
                    return process_record_glyph_replacement(keycode, record, 0x1D586, 0x1D56C, '0', '1', 0x2002);
                    return process_record_glyph_replacement(keycode, record, 0x1D586, 0x1D56C, '0', '1', 0x2002, mods, osm);
            }
            break;

        case KC_F1 ... KC_F12:
            return process_gflock(keycode, record);
    }

#ifdef RGBLIGHT_ENABLE
    bool res = process_record_user_rgb(keycode, record);
    if (!res) return false;
#ifdef SHIFT_BACKSPACE_DELETE
        case KC_BSPC: {
            static bool delkey_registered;
            if (record->event.pressed) {
                if ((mods | osm) & MOD_MASK_SHIFT) {
                    del_mods(MOD_MASK_SHIFT);
#ifndef NO_ACTION_ONESHOT
                    clear_oneshot_mods();
#endif
                    register_code(KC_DEL);
                    delkey_registered = true;
                    set_mods(mods);
                    return false;
                }
            } else {  // on release of KC_BSPC
                // In case KC_DEL is still being sent even after the release of KC_BSPC
                if (delkey_registered) {
                    unregister_code(KC_DEL);
                    delkey_registered = false;
                    return false;
                }
            }
        }
#endif
    }

#ifdef RGBLIGHT_ENABLE
    return process_record_user_rgb(keycode, record);
#else
    return true;
#endif
}

void post_process_record_user(uint16_t keycode, keyrecord_t *record) {

M users/spidey3/spidey3.h => users/spidey3/spidey3.h +4 -1
@@ 8,7 8,6 @@

enum userspace_layers {
    _BASE = 0,
    _OSX,
    _NUMPAD,
    _FN,
};


@@ 31,6 30,7 @@ enum custom_keycodes {
    SPI_PARENS,
    SPI_FRAKTR,
    SPI_GFLOCK,
    SPI_KP_00,
};

#ifdef RGBLIGHT_ENABLE


@@ 45,12 45,14 @@ typedef enum layer_ack {
    ACK_NO = 0,
    ACK_YES,
    ACK_MEH,
    ACK_HUH,
} layer_ack_t;

#    define RGB_LAYER_ACK_DURATION 500

void          eeconfig_init_user_rgb(void);
void          matrix_init_user_rgb(void);
void          matrix_scan_user_rgb(void);
void          keyboard_post_init_user_rgb(void);
bool          process_record_user_rgb(uint16_t keycode, keyrecord_t *record);
void          post_process_record_user_rgb(uint16_t keycode, keyrecord_t *record);


@@ 60,6 62,7 @@ bool          led_update_user_rgb(led_t led_state);
void          rgb_layer_ack(layer_ack_t n);
void          rgb_layer_ack_yn(bool yn);
void          clear_rgb_layers(void);
void          shutdown_user_rgb(void);
#endif

#ifdef UNICODEMAP_ENABLE

M users/spidey3/unicode.h => users/spidey3/unicode.h +1 -1
@@ 23,6 23,6 @@ enum unicode_names {
};

#    define X_BUL (XP(BUL1, BUL2))
#    define X_DASH (XP(ENDASH, EMDASH))
#    define X_DASH (XP(EMDASH, ENDASH))

#endif