Enable KEYCHRON_RGB_ENABLE for the Q5 Max, wiring up PER_KEY_RGB and MIXED_RGB effects with proper defaults (default_per_key_led[], default_region[])
Fix a cascade of EEPROM bugs that caused the Launcher-configured RGB mode to revert to the default heatmap on every power cycle and wireless transport change
Pin VIA_EEPROM_MAGIC_ADDR to a fixed offset so future Keychron EEPROM growth can't silently corrupt the stored keymap
Changes by file
rules.mk
Add KEYCHRON_RGB_ENABLE = yes — master flag enabling all Keychron custom RGB code
eeconfig_kb.h
Add #undef EECONFIG_KB_DATA_SIZE before the Keychron redefinition to suppress redefinition of QMK's default-zero value
keychron_rgb.c — four EEPROM bug fixes
retail_demo_enable never written to EEPROM — eeconfig_reset_custom_rgb() used eeprom_read_block instead of eeprom_update_block, leaving 0xFF on freshly-flashed boards; retail_demo_task() treats any non-zero value as "demo active" and forces the mode to CUSTOM_MIXED_RGB every scan, preventing any other mode from sticking
Retail demo clamp on load — clamp retail_demo_enable > 1 to 0 to recover boards already affected by the above
Version stamp moved to reset path — eeprom_update_dword(EECONFIG_KEYBOARD, ...) moved from eeconfig_init_custom_rgb() (load) to eeconfig_reset_custom_rgb() (write), so the version is only stamped when valid defaults are actually committed to EEPROM
QMK RGB mode not persisted — kc_rgb_save() now calls eeconfig_update_rgb_matrix() so the current mode (e.g. CUSTOM_MIXED_RGB) is saved alongside Keychron data; without this, rgb_matrix_init() on transport change reloads the compile-time default RGB_MATRIX_TYPING_HEATMAP
mixed_rgb.c / rgb_matrix_kb.inc
Add #include "eeconfig_custom_rgb.h" so EECONFIG_SIZE_CUSTOM_RGB is in scope for the compile guards that gate the custom effects
ansi_encoder.c
Define default_per_key_led[] (red Esc/CapsLock, yellow modifiers, blue alpha keys) and default_region[] (all keys in region 0) — both are extern'd by keychron_rgb.c
q5_max.c
Call eeconfig_init_custom_rgb() in keyboard_post_init_kb() so Keychron RGB arrays are loaded from EEPROM on boot instead of being zero-initialised
Add wireless_enter_connected_kb() hook: re-applies the EEPROM-saved QMK RGB mode after BT/2.4G reconnect in case the reconnect sequence resets the in-RAM mode before the display settles
keymap.c
DIP switch Win-side override: replace rgb_matrix_mode() / rgb_matrix_sethsv() calls (which write to EEPROM and overwrite the Launcher-configured mode) with a dip_win_active flag; rgb_matrix_indicators_advanced_user() paints all LEDs white each frame when the flag is set, leaving the active effect and EEPROM untouched
Add QK_CLEAR_EEPROM to the KEEB_CTL layer as an escape hatch for EEPROM recovery
config.h
Define VIA_EEPROM_MAGIC_ADDR 544 to anchor VIA keymap storage at a fixed EEPROM offset; without this, growth in EECONFIG_KB_DATA_SIZE silently shifts the keymap block, corrupting stored layouts (observed as layer-0 keys reverting to KC_NONE on boot)
Test plan
Compile succeeds with no errors
Launcher-configured Mixed RGB mode survives power cycle
Launcher-configured Mixed RGB mode survives BT ↔ 2.4G ↔ USB transport change
DIP switch Win side shows solid white; returning to Mac side restores the active Launcher effect
Layer 0 keymap (including Esc) is preserved correctly across power cycles
QK_CLEAR_EEPROM on KEEB_CTL layer resets EEPROM as expected
## Summary
- Enable `KEYCHRON_RGB_ENABLE` for the Q5 Max, wiring up `PER_KEY_RGB` and `MIXED_RGB` effects with proper defaults (`default_per_key_led[]`, `default_region[]`)
- Fix a cascade of EEPROM bugs that caused the Launcher-configured RGB mode to revert to the default heatmap on every power cycle and wireless transport change
- Pin `VIA_EEPROM_MAGIC_ADDR` to a fixed offset so future Keychron EEPROM growth can't silently corrupt the stored keymap
## Changes by file
### `rules.mk`
- Add `KEYCHRON_RGB_ENABLE = yes` — master flag enabling all Keychron custom RGB code
### `eeconfig_kb.h`
- Add `#undef EECONFIG_KB_DATA_SIZE` before the Keychron redefinition to suppress redefinition of QMK's default-zero value
### `keychron_rgb.c` — four EEPROM bug fixes
1. **`retail_demo_enable` never written to EEPROM** — `eeconfig_reset_custom_rgb()` used `eeprom_read_block` instead of `eeprom_update_block`, leaving `0xFF` on freshly-flashed boards; `retail_demo_task()` treats any non-zero value as "demo active" and forces the mode to `CUSTOM_MIXED_RGB` every scan, preventing any other mode from sticking
2. **Retail demo clamp on load** — clamp `retail_demo_enable > 1` to `0` to recover boards already affected by the above
3. **Version stamp moved to reset path** — `eeprom_update_dword(EECONFIG_KEYBOARD, ...)` moved from `eeconfig_init_custom_rgb()` (load) to `eeconfig_reset_custom_rgb()` (write), so the version is only stamped when valid defaults are actually committed to EEPROM
4. **QMK RGB mode not persisted** — `kc_rgb_save()` now calls `eeconfig_update_rgb_matrix()` so the current mode (e.g. `CUSTOM_MIXED_RGB`) is saved alongside Keychron data; without this, `rgb_matrix_init()` on transport change reloads the compile-time default `RGB_MATRIX_TYPING_HEATMAP`
### `mixed_rgb.c` / `rgb_matrix_kb.inc`
- Add `#include "eeconfig_custom_rgb.h"` so `EECONFIG_SIZE_CUSTOM_RGB` is in scope for the compile guards that gate the custom effects
### `ansi_encoder.c`
- Define `default_per_key_led[]` (red Esc/CapsLock, yellow modifiers, blue alpha keys) and `default_region[]` (all keys in region 0) — both are `extern`'d by `keychron_rgb.c`
### `q5_max.c`
- Call `eeconfig_init_custom_rgb()` in `keyboard_post_init_kb()` so Keychron RGB arrays are loaded from EEPROM on boot instead of being zero-initialised
- Add `wireless_enter_connected_kb()` hook: re-applies the EEPROM-saved QMK RGB mode after BT/2.4G reconnect in case the reconnect sequence resets the in-RAM mode before the display settles
### `keymap.c`
- **DIP switch Win-side override**: replace `rgb_matrix_mode()` / `rgb_matrix_sethsv()` calls (which write to EEPROM and overwrite the Launcher-configured mode) with a `dip_win_active` flag; `rgb_matrix_indicators_advanced_user()` paints all LEDs white each frame when the flag is set, leaving the active effect and EEPROM untouched
- Add `QK_CLEAR_EEPROM` to the KEEB_CTL layer as an escape hatch for EEPROM recovery
### `config.h`
- Define `VIA_EEPROM_MAGIC_ADDR 544` to anchor VIA keymap storage at a fixed EEPROM offset; without this, growth in `EECONFIG_KB_DATA_SIZE` silently shifts the keymap block, corrupting stored layouts (observed as layer-0 keys reverting to `KC_NONE` on boot)
## Test plan
- [x] Compile succeeds with no errors
- [x] Launcher-configured Mixed RGB mode survives power cycle
- [x] Launcher-configured Mixed RGB mode survives BT ↔ 2.4G ↔ USB transport change
- [x] DIP switch Win side shows solid white; returning to Mac side restores the active Launcher effect
- [x] Layer 0 keymap (including Esc) is preserved correctly across power cycles
- [x] `QK_CLEAR_EEPROM` on KEEB_CTL layer resets EEPROM as expected
Enable KEYCHRON_RGB_ENABLE for the Q5 Max, wiring up PER_KEY_RGB and
MIXED_RGB effects, and fix a cascade of EEPROM bugs that caused the
Launcher-configured RGB mode to revert to the default heatmap on every
power cycle and wireless transport change.
Keychron RGB enablement:
- Add KEYCHRON_RGB_ENABLE = yes to rules.mk
- Define default_per_key_led[] and default_region[] for the ANSI Encoder
layout in ansi_encoder.c (extern'd by keychron_rgb.c)
- Fix missing #include "eeconfig_custom_rgb.h" in mixed_rgb.c and
rgb_matrix_kb.inc so EECONFIG_SIZE_CUSTOM_RGB is in scope for the
compile guards that gate the custom effects
- Add #undef EECONFIG_KB_DATA_SIZE before the Keychron redefinition in
eeconfig_kb.h to suppress redefinition of QMK's default-zero value
EEPROM persistence fixes (keychron_rgb.c):
- Fix retail_demo_enable never being written to EEPROM in
eeconfig_reset_custom_rgb(): original code used eeprom_read_block
instead of eeprom_update_block, leaving 0xFF on freshly-flashed
boards; retail_demo_task() treats any non-zero value as "demo active"
and forces the mode to CUSTOM_MIXED_RGB every scan
- Clamp retail_demo_enable > 1 to 0 on load to recover boards already
affected by the above bug
- Move EECONFIG_KEYBOARD version stamp from eeconfig_init_custom_rgb()
(load path) to eeconfig_reset_custom_rgb() (reset/write path) so the
version is only stamped when valid defaults are actually written
- Call eeconfig_update_rgb_matrix() in kc_rgb_save() so the current QMK
RGB mode is persisted alongside Keychron data; without this,
rgb_matrix_init() (called on every transport change) reloads the
compile-time default RGB_MATRIX_TYPING_HEATMAP from EEPROM
Transport-change persistence (q5_max.c):
- Call eeconfig_init_custom_rgb() in keyboard_post_init_kb() so Keychron
RGB arrays are loaded from EEPROM on every boot instead of being
zero-initialised
- Add wireless_enter_connected_kb() hook: re-applies the EEPROM-saved
QMK RGB mode after BT/2.4G reconnect in case the reconnect sequence
resets the in-RAM mode before the display settles
DIP switch Win-side override (keymap.c):
- Replace rgb_matrix_mode() / rgb_matrix_sethsv() calls (which write to
EEPROM and permanently overwrite the Launcher mode) with a
dip_win_active flag; rgb_matrix_indicators_advanced_user() paints all
LEDs white each frame when the flag is set, leaving the active effect
and EEPROM untouched
VIA keymap address pinning (config.h):
- Define VIA_EEPROM_MAGIC_ADDR 544 to anchor VIA keymap storage at a
fixed EEPROM offset; without this, growth in EECONFIG_KB_DATA_SIZE
silently shifts the keymap block, corrupting stored layouts (observed
as layer-0 keys reverting to KC_TRNS / KC_NONE on boot)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
KEYCHRON_RGB_ENABLEfor the Q5 Max, wiring upPER_KEY_RGBandMIXED_RGBeffects with proper defaults (default_per_key_led[],default_region[])VIA_EEPROM_MAGIC_ADDRto a fixed offset so future Keychron EEPROM growth can't silently corrupt the stored keymapChanges by file
rules.mkKEYCHRON_RGB_ENABLE = yes— master flag enabling all Keychron custom RGB codeeeconfig_kb.h#undef EECONFIG_KB_DATA_SIZEbefore the Keychron redefinition to suppress redefinition of QMK's default-zero valuekeychron_rgb.c— four EEPROM bug fixesretail_demo_enablenever written to EEPROM —eeconfig_reset_custom_rgb()usedeeprom_read_blockinstead ofeeprom_update_block, leaving0xFFon freshly-flashed boards;retail_demo_task()treats any non-zero value as "demo active" and forces the mode toCUSTOM_MIXED_RGBevery scan, preventing any other mode from stickingretail_demo_enable > 1to0to recover boards already affected by the aboveeeprom_update_dword(EECONFIG_KEYBOARD, ...)moved fromeeconfig_init_custom_rgb()(load) toeeconfig_reset_custom_rgb()(write), so the version is only stamped when valid defaults are actually committed to EEPROMkc_rgb_save()now callseeconfig_update_rgb_matrix()so the current mode (e.g.CUSTOM_MIXED_RGB) is saved alongside Keychron data; without this,rgb_matrix_init()on transport change reloads the compile-time defaultRGB_MATRIX_TYPING_HEATMAPmixed_rgb.c/rgb_matrix_kb.inc#include "eeconfig_custom_rgb.h"soEECONFIG_SIZE_CUSTOM_RGBis in scope for the compile guards that gate the custom effectsansi_encoder.cdefault_per_key_led[](red Esc/CapsLock, yellow modifiers, blue alpha keys) anddefault_region[](all keys in region 0) — both areextern'd bykeychron_rgb.cq5_max.ceeconfig_init_custom_rgb()inkeyboard_post_init_kb()so Keychron RGB arrays are loaded from EEPROM on boot instead of being zero-initialisedwireless_enter_connected_kb()hook: re-applies the EEPROM-saved QMK RGB mode after BT/2.4G reconnect in case the reconnect sequence resets the in-RAM mode before the display settleskeymap.crgb_matrix_mode()/rgb_matrix_sethsv()calls (which write to EEPROM and overwrite the Launcher-configured mode) with adip_win_activeflag;rgb_matrix_indicators_advanced_user()paints all LEDs white each frame when the flag is set, leaving the active effect and EEPROM untouchedQK_CLEAR_EEPROMto the KEEB_CTL layer as an escape hatch for EEPROM recoveryconfig.hVIA_EEPROM_MAGIC_ADDR 544to anchor VIA keymap storage at a fixed EEPROM offset; without this, growth inEECONFIG_KB_DATA_SIZEsilently shifts the keymap block, corrupting stored layouts (observed as layer-0 keys reverting toKC_NONEon boot)Test plan
QK_CLEAR_EEPROMon KEEB_CTL layer resets EEPROM as expected