From 0e20baeaaee8b2cb87f1c96e227f8a84c4cb0639 Mon Sep 17 00:00:00 2001 From: lokher Date: Fri, 31 Oct 2025 12:09:34 +0800 Subject: [PATCH] Add STATE_NOTIFY_ENABLE feature This feature enables the keyboard firmware to send a notification to the host via RAW HID whenever the keyboard state changes, such as default layer, layout profile, or mode switch. It allows Keychron Launcher to stay synchronized with the device state in real time. --- keyboards/keychron/c1_pro_8k/rules.mk | 2 - keyboards/keychron/c2_pro_8k/rules.mk | 2 - keyboards/keychron/c3_pro_8k/rules.mk | 2 - keyboards/keychron/common/factory_test.c | 16 ++---- keyboards/keychron/common/keychron_common.c | 13 ----- keyboards/keychron/common/keychron_common.h | 6 ++- keyboards/keychron/common/keychron_common.mk | 8 ++- keyboards/keychron/common/keychron_raw_hid.c | 6 +-- keyboards/keychron/common/keychron_raw_hid.h | 25 ++++----- keyboards/keychron/common/state_notify.c | 54 ++++++++++++++++++++ keyboards/keychron/common/state_notify.h | 24 +++++++++ keyboards/keychron/common/usb_report_rate.c | 14 ++--- 12 files changed, 111 insertions(+), 61 deletions(-) create mode 100644 keyboards/keychron/common/state_notify.c create mode 100644 keyboards/keychron/common/state_notify.h diff --git a/keyboards/keychron/c1_pro_8k/rules.mk b/keyboards/keychron/c1_pro_8k/rules.mk index 1107205d9f..ac8ba8405e 100644 --- a/keyboards/keychron/c1_pro_8k/rules.mk +++ b/keyboards/keychron/c1_pro_8k/rules.mk @@ -1,5 +1,3 @@ USB_REPORT_INTERVAL_ENABLE=yes -INFO_CHAGNED_NOTIFY_ENABLE=yes include keyboards/keychron/common/keychron_common.mk - diff --git a/keyboards/keychron/c2_pro_8k/rules.mk b/keyboards/keychron/c2_pro_8k/rules.mk index 1107205d9f..ac8ba8405e 100644 --- a/keyboards/keychron/c2_pro_8k/rules.mk +++ b/keyboards/keychron/c2_pro_8k/rules.mk @@ -1,5 +1,3 @@ USB_REPORT_INTERVAL_ENABLE=yes -INFO_CHAGNED_NOTIFY_ENABLE=yes include keyboards/keychron/common/keychron_common.mk - diff --git a/keyboards/keychron/c3_pro_8k/rules.mk b/keyboards/keychron/c3_pro_8k/rules.mk index 6d286d5637..ba81928702 100644 --- a/keyboards/keychron/c3_pro_8k/rules.mk +++ b/keyboards/keychron/c3_pro_8k/rules.mk @@ -1,6 +1,4 @@ USB_REPORT_INTERVAL_ENABLE=yes -INFO_CHAGNED_NOTIFY_ENABLE=yes KEYCOMBO_OS_TOGGLE_ENABLE=yes include keyboards/keychron/common/keychron_common.mk - diff --git a/keyboards/keychron/common/factory_test.c b/keyboards/keychron/common/factory_test.c index 1ad7d8ce20..40390d044c 100644 --- a/keyboards/keychron/common/factory_test.c +++ b/keyboards/keychron/common/factory_test.c @@ -39,6 +39,9 @@ #endif #include "config.h" #include "version.h" +#ifdef STATE_NOTIFY_ENABLE +# include "state_notify.h" +#endif #ifndef BL_CYCLE_KEY # define BL_CYCLE_KEY KC_RIGHT @@ -105,17 +108,6 @@ void factory_timer_start(void) { factory_reset_timer = timer_read32(); } -// #ifdef INFO_CHAGNED_NOTIFY_ENABLE -void factory_reset_nofity(void) { - uint8_t buf[RAW_EPSIZE] = {0}; - - buf[0] = KC_MISC_CMD_GROUP; - buf[1] = FACTORY_RESET; - - raw_hid_send(buf, RAW_EPSIZE); -} -// #endif - static inline void factory_timer_check(void) { if (timer_elapsed32(factory_reset_timer) > 3000) { factory_reset_timer = 0; @@ -172,7 +164,9 @@ static inline void factory_timer_check(void) { eeprom_update_transport(get_transport()); # endif #endif +#ifdef STATE_NOTIFY_ENABLE factory_reset_nofity(); +#endif #ifdef RGB_MATRIX_ENABLE RGB color = {.r = 255, .g = 0, .b = 0}; backlight_indicator_start(250, 250, 3, color); diff --git a/keyboards/keychron/common/keychron_common.c b/keyboards/keychron/common/keychron_common.c index ce043f3c2d..af06051e09 100644 --- a/keyboards/keychron/common/keychron_common.c +++ b/keyboards/keychron/common/keychron_common.c @@ -351,16 +351,3 @@ bool led_update_kb(led_t led_state) { return res; } #endif - -#ifdef INFO_CHAGNED_NOTIFY_ENABLE -layer_state_t default_layer_state_set_kb(layer_state_t state) { - uint8_t buf[RAW_EPSIZE] = {0}; - - buf[0] = KC_GET_DEFAULT_LAYER; - buf[1] = get_highest_layer(state); - - raw_hid_send(buf, RAW_EPSIZE); - - return default_layer_state_set_user(state); -} -#endif diff --git a/keyboards/keychron/common/keychron_common.h b/keyboards/keychron/common/keychron_common.h index 3ee303fbbe..65e30f4971 100644 --- a/keyboards/keychron/common/keychron_common.h +++ b/keyboards/keychron/common/keychron_common.h @@ -19,6 +19,9 @@ #include #include #include "keycodes.h" +#ifdef STATE_NOTIFY_ENABLE +# include "state_notify.h" +#endif #ifndef CUSTOM_KEYCODES_ENABLE // clang-format off @@ -120,7 +123,8 @@ enum { #include "keycodes_custom.h" #endif -static_assert(NEW_SAFE_RANGE <= 0x7E1F/* QK_KB_31 */, "Keycode overflow"); +// clang-format on +static_assert(NEW_SAFE_RANGE <= 0x7E1F /* QK_KB_31 */, "Keycode overflow"); typedef struct PACKED { uint8_t len; diff --git a/keyboards/keychron/common/keychron_common.mk b/keyboards/keychron/common/keychron_common.mk index 6da9bf21a0..aa8801f0cd 100644 --- a/keyboards/keychron/common/keychron_common.mk +++ b/keyboards/keychron/common/keychron_common.mk @@ -1,4 +1,5 @@ OPT_DEFS += -DFACTORY_TEST_ENABLE -DAPDAPTIVE_NKRO_ENABLE -DVIA_INSECURE +OPT_DEFS += -DSTATE_NOTIFY_ENABLE KEYCHRON_COMMON_DIR = $(TOP_DIR)/keyboards/keychron/common SRC += \ @@ -9,7 +10,8 @@ SRC += \ $(KEYCHRON_COMMON_DIR)/backlit_indicator.c \ $(KEYCHRON_COMMON_DIR)/eeconfig_kb.c \ $(KEYCHRON_COMMON_DIR)/dfu_info.c \ - $(KEYCHRON_COMMON_DIR)/nkro.c + $(KEYCHRON_COMMON_DIR)/nkro.c \ + $(KEYCHRON_COMMON_DIR)/state_notify.c VPATH += $(KEYCHRON_COMMON_DIR) @@ -23,10 +25,6 @@ endif include $(KEYCHRON_COMMON_DIR)/language/language.mk include $(KEYCHRON_COMMON_DIR)/snap_click/snap_click.mk -ifeq ($(strip $(INFO_CHAGNED_NOTIFY_ENABLE)), yes) -OPT_DEFS += -DINFO_CHAGNED_NOTIFY_ENABLE -endif - ifeq ($(strip $(KEYCHRON_RGB_ENABLE)), yes) ifeq ($(strip $(RGB_MATRIX_ENABLE)), yes) include $(KEYCHRON_COMMON_DIR)/rgb/rgb.mk diff --git a/keyboards/keychron/common/keychron_raw_hid.c b/keyboards/keychron/common/keychron_raw_hid.c index a505207dee..a4d8b6d4ab 100644 --- a/keyboards/keychron/common/keychron_raw_hid.c +++ b/keyboards/keychron/common/keychron_raw_hid.c @@ -57,8 +57,8 @@ void get_support_feature(uint8_t *data) { # ifdef ANANLOG_MATRIX | FEATURE_ANALOG_MATRIX # endif -# ifdef INFO_CHAGNED_NOTIFY_ENABLE - | FEATURE_INFO_CHAGNED_NOTIFY +# ifdef STATE_NOTIFY_ENABLE + | FEATURE_STATE_NOTIFY # endif # ifdef DYNAMIC_DEBOUNCE_ENABLE | FEATURE_DYNAMIC_DEBOUNCE @@ -71,7 +71,7 @@ void get_support_feature(uint8_t *data) { # endif ; - data[2] = (FEATURE_QUICK_START >> 8) | (FEATURE_NKRO >> 8); + data[2] = (FEATURE_QUICK_START | FEATURE_NKRO) >> 8; } void get_firmware_version(uint8_t *data) { diff --git a/keyboards/keychron/common/keychron_raw_hid.h b/keyboards/keychron/common/keychron_raw_hid.h index 580cfad8cd..4ef26754ef 100644 --- a/keyboards/keychron/common/keychron_raw_hid.h +++ b/keyboards/keychron/common/keychron_raw_hid.h @@ -33,28 +33,29 @@ enum { }; enum { + // Byte 0 FEATURE_DEFAULT_LAYER = 0x01U << 0, FEATURE_BLUETOOTH = 0x01U << 1, FEATURE_P24G = 0x01U << 2, FEATURE_ANALOG_MATRIX = 0x01U << 3, - FEATURE_INFO_CHAGNED_NOTIFY = 0x01U << 4, + FEATURE_STATE_NOTIFY = 0x01U << 4, FEATURE_DYNAMIC_DEBOUNCE = 0x01U << 5, FEATURE_SNAP_CLICK = 0x01U << 6, FEATURE_KEYCHRON_RGB = 0x01U << 7, - - FEATURE_QUICK_START = 0x01 << 8, - FEATURE_NKRO = 0x01 << 9, + // Byte 1 + FEATURE_QUICK_START = 0x01U << 8, + FEATURE_NKRO = 0x01U << 9, }; enum { - MISC_DFU_INFO = 0x01 << 0, - MISC_LANGUAGE = 0x01 << 1, - MISC_DEBOUNCE = 0x01 << 2, - MISC_SNAP_CLICK = 0x01 << 3, - MISC_WIRELESS_LPM = 0x01 << 4, - MISC_REPORT_REATE = 0x01 << 5, - MISC_QUICK_START = 0x01 << 6, - MISC_NKRO = 0x01 << 7, + MISC_DFU_INFO = 0x01U << 0, + MISC_LANGUAGE = 0x01U << 1, + MISC_DEBOUNCE = 0x01U << 2, + MISC_SNAP_CLICK = 0x01U << 3, + MISC_WIRELESS_LPM = 0x01U << 4, + MISC_REPORT_REATE = 0x01U << 5, + MISC_QUICK_START = 0x01U << 6, + MISC_NKRO = 0x01U << 7, }; enum { diff --git a/keyboards/keychron/common/state_notify.c b/keyboards/keychron/common/state_notify.c new file mode 100644 index 0000000000..bfd2c4cdb5 --- /dev/null +++ b/keyboards/keychron/common/state_notify.c @@ -0,0 +1,54 @@ +/* Copyright 2024 @ Keychron (https://www.keychron.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "quantum.h" +#include "keychron_raw_hid.h" +#include "raw_hid.h" +#include "usb_descriptor.h" + +layer_state_t default_layer_state_set_kb(layer_state_t state) { + uint8_t buf[RAW_EPSIZE] = {0}; + + buf[0] = KC_GET_DEFAULT_LAYER; + buf[1] = get_highest_layer(state); + + raw_hid_send(buf, RAW_EPSIZE); + + return default_layer_state_set_user(state); +} + +void factory_reset_nofity(void) { + uint8_t buf[RAW_EPSIZE] = {0}; + + buf[0] = KC_MISC_CMD_GROUP; + buf[1] = FACTORY_RESET; + + raw_hid_send(buf, RAW_EPSIZE); +} + +#ifdef USB_REPORT_INTERVAL_ENABLE +void usb_report_rate_notify(uint8_t report_rate_div) { + uint8_t buf[RAW_EPSIZE] = {0}; + + buf[0] = KC_MISC_CMD_GROUP; + buf[1] = REPORT_RATE_GET; + buf[2] = 0; + buf[3] = report_rate_div; + buf[4] = 0x7F; + + raw_hid_send(buf, RAW_EPSIZE); +} +#endif diff --git a/keyboards/keychron/common/state_notify.h b/keyboards/keychron/common/state_notify.h new file mode 100644 index 0000000000..5064fa7646 --- /dev/null +++ b/keyboards/keychron/common/state_notify.h @@ -0,0 +1,24 @@ +/* Copyright 2023 ~ 2025 @ Keychron (https://www.keychron.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +void factory_reset_nofity(void); +#ifdef USB_REPORT_INTERVAL_ENABLE +void usb_report_rate_notify(uint8_t report_rate_div); +#endif diff --git a/keyboards/keychron/common/usb_report_rate.c b/keyboards/keychron/common/usb_report_rate.c index dc70c981ce..de9792aab0 100644 --- a/keyboards/keychron/common/usb_report_rate.c +++ b/keyboards/keychron/common/usb_report_rate.c @@ -14,7 +14,7 @@ * along with this program. If not, see . */ -#if USB_REPORT_INTERVAL_ENABLE +#ifdef USB_REPORT_INTERVAL_ENABLE # include # include "eeconfig_kb.h" @@ -25,6 +25,7 @@ # include "usb_endpoints.h" # include "backlit_indicator.h" # include "eeprom.h" +# include "keychron_common.h" # ifndef KEY_RATE_SELECT # define KEY_RATE_SELECT KC_K @@ -93,16 +94,9 @@ static bool report_rate_set(uint8_t *data, bool notify) { eeprom_update_byte((uint8_t *)(EECONFIG_BASE_HSUSB_REPORT_RATE), report_rate_div); report_rate_update_interval(); -# ifdef INFO_CHAGNED_NOTIFY_ENABLE +# ifdef STATE_NOTIFY_ENABLE if (notify) { - uint8_t buf[RAW_EPSIZE] = {0}; - buf[0] = KC_MISC_CMD_GROUP; - buf[1] = REPORT_RATE_GET; - buf[2] = 0; - buf[3] = report_rate_div; - buf[4] = 0x7F; - - raw_hid_send(buf, RAW_EPSIZE); + usb_report_rate_notify(report_rate_div); } # endif (void)notify;