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.
This commit is contained in:
lokher
2025-10-31 12:09:34 +08:00
parent 3bf1ecd9b1
commit 0e20baeaae
12 changed files with 111 additions and 61 deletions

View File

@@ -1,5 +1,3 @@
USB_REPORT_INTERVAL_ENABLE=yes
INFO_CHAGNED_NOTIFY_ENABLE=yes
include keyboards/keychron/common/keychron_common.mk

View File

@@ -1,5 +1,3 @@
USB_REPORT_INTERVAL_ENABLE=yes
INFO_CHAGNED_NOTIFY_ENABLE=yes
include keyboards/keychron/common/keychron_common.mk

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -19,6 +19,9 @@
#include <stdint.h>
#include <assert.h>
#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;

View File

@@ -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

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#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

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
void factory_reset_nofity(void);
#ifdef USB_REPORT_INTERVAL_ENABLE
void usb_report_rate_notify(uint8_t report_rate_div);
#endif

View File

@@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if USB_REPORT_INTERVAL_ENABLE
#ifdef USB_REPORT_INTERVAL_ENABLE
# include <string.h>
# 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;