Adds a new HID_CMD_BATTERY (0x44) command to the shared qmk-host protocol.
When the keyboard is in wireless transport mode (BT or 2.4G) the firmware
now pushes the current battery percentage to the host:
- Periodic push every 5 minutes via timer_read32()/timer_elapsed32(); fires
immediately on the first matrix_scan_user() call after boot so qmk-host
gets a reading as soon as the keyboard connects over USB in wireless mode.
- Redundant sends are suppressed: g_last_sent_bat tracks the last value
transmitted and the packet is skipped when the level has not changed.
- Query-response path: qmk-host can send CMD_BATTERY with HID_FLAG_QUERY at
any time; the keyboard replies with the current percentage or
HID_BATT_UNAVAILABLE (0xFF) when in USB transport mode.
- All battery and transport code is guarded by #ifdef LK_WIRELESS_ENABLE so
the keymap compiles cleanly on any wired-only build.
Firmware size delta: +160 bytes (well within flash budget).
Change the fallback combo's action from TO(BASE) to LCK_BASE.
Since LCK_BASE explicitly clears the locked_layers bitmask,
it ensures that the keyboard actually returns to the BASE
layer even if a layer was previously locked.
The previous TO(BASE) action only updated the temporary layer
state, which was immediately overwritten by the persistent
locked_layers bitmask in layer_state_set_user().
Port the Keychron RGB EEPROM persistence work from the Q5 Max (PR #18)
to the K17 Max ANSI Encoder RGB variant.
- Add KEYCHRON_RGB_ENABLE = yes to rules.mk
- Define default_per_key_led[] (red Esc/CapsLock, yellow modifiers and
numpad, blue alpha keys) and default_region[] for the 103-LED layout
in ansi_encoder/rgb/rgb.c; both are extern'd by keychron_rgb.c
- Add wireless_enter_connected_kb() hook and eeconfig_init_custom_rgb()
call in keyboard_post_init_kb() in k17_max.c, matching the Q5 Max
pattern for boot-time and transport-change RGB persistence
- Define VIA_EEPROM_MAGIC_ADDR 552 in ansi_encoder/rgb/config.h to pin
VIA keymap storage past the Keychron EEPROM data region end (540 for
K17 with 103 LEDs); prevents keymap corruption if the KB data block
grows in future
- Rename dev branch references from q5_dev to dev/q5; add dev/k17 for
K17 Max work
- Add K17 Max build/flash commands using the correct rgb subvariant path
(keychron/k17_max/ansi_encoder/rgb) to distinguish from the white LED
variant
- Add EEPROM Layout Notes section documenting the Q5 Max address map,
VIA_EEPROM_MAGIC_ADDR pinning rules, and EECONFIG_KB_DATA_SIZE #undef
requirement
- Add Keychron RGB section capturing lessons from the persistence work:
when to call eeconfig_init_custom_rgb(), version stamp placement,
kc_rgb_save() mode persistence, retail_demo_enable 0xFF bug, and
extern array requirements
- Add DIP Switch section explaining the frame overlay approach and why
direct rgb_matrix_mode() calls must be avoided
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)
Replace the Win/Mac default-layer switch with an RGB effect toggle:
- Win side → solid white backlight
- Mac side → typing heatmap
Add a weak dip_switch_update_keymap() hook in q5_max.c to work around
factory_test.c already owning dip_switch_update_user().
Define TAPPING_TERM (200ms default) and TAPPING_TERM_PER_KEY in config.h,
then implement get_tapping_term() to set a tight 50ms window for TD_HOME_END
so a single Home tap never accidentally resolves as End.
CK_CTRL_K_C and CK_CTRL_K_D were leftover from an earlier failed
attempt using ACTION_TAP_DANCE_DOUBLE with custom keycodes. Now that
TD_CHORDS uses ACTION_TAP_DANCE_FN with SEND_STRING, they are unused.
Two build errors:
1. RAW_EPSIZE undeclared — usb_descriptor.h is not in scope when
keymap.c is compiled through Keychron's build path. Replace all
uses with HID_PACKET_SIZE (= 32), now defined in hid_protocol.h.
2. via_command_kb duplicate symbol — keychron_raw_hid.c already defines
via_command_kb (non-weak) so we cannot redefine it in keymap.c.
Fix by adding a weak kc_raw_hid_rx_kb() extension hook to
keychron_raw_hid.c (following the same pattern as kc_rgb_matrix_rx).
kc_raw_hid_rx() now calls this hook from its default case instead of
returning false directly. The keymap overrides kc_raw_hid_rx_kb() to
handle our custom HID command range (0x40-0x7E).
Add hid_protocol.h defining a shared 32-byte packet structure for the
qmk-host bridge application (command IDs 0x40-0x7E, clear of VIA's
range). Implement via_command_kb() in keymap.c to intercept incoming
packets: LAYER_SYNC applies a new active layer, VOLUME and BRIGHTNESS
store host-reported values for future RGB indicators, and ACTIVE_APP
is stubbed for a later commit. Layer state changes are broadcast to the
host via raw_hid_send() from layer_state_set_user(), guarded by
g_hid_recv_active to prevent echo loops when the change itself
originated from HID.