495 lines
16 KiB
C
495 lines
16 KiB
C
/* 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 QMK_KEYBOARD_H
|
|
#include "raw_hid.h"
|
|
#include "keychron_common.h"
|
|
#include "keychron_rgb_type.h"
|
|
#include "eeconfig_kb.h"
|
|
#include "usb_main.h"
|
|
#include "color.h"
|
|
#ifdef LK_WIRELESS_ENABLE
|
|
#include "transport.h"
|
|
#endif
|
|
#include <lib/lib8tion/lib8tion.h>
|
|
|
|
#if defined(KEYCHRON_RGB_ENABLE) && defined(EECONFIG_SIZE_CUSTOM_RGB)
|
|
|
|
# define PER_KEY_RGB_VER 0x0001
|
|
|
|
# define OFFSET_OS_INDICATOR ((uint8_t *)(EECONFIG_BASE_CUSTOM_RGB))
|
|
# define OFFSET_RETAIL_DEMO (OFFSET_OS_INDICATOR + sizeof(os_indicator_config_t))
|
|
# define OFFSET_PER_KEY_RGB_TYPE (OFFSET_RETAIL_DEMO + sizeof(retail_demo_enable))
|
|
# define OFFSET_PER_KEY_RGBS (OFFSET_PER_KEY_RGB_TYPE + sizeof(per_key_rgb_type))
|
|
# define OFFSET_LAYER_FLAGS (OFFSET_PER_KEY_RGBS + sizeof(per_key_led))
|
|
# define OFFSET_EFFECT_LIST (OFFSET_LAYER_FLAGS + sizeof(regions))
|
|
|
|
enum {
|
|
RGB_GET_PROTOCOL_VER = 0x01,
|
|
RGB_SAVE,
|
|
GET_INDICATORS_CONFIG,
|
|
SET_INDICATORS_CONFIG,
|
|
RGB_GET_LED_COUNT,
|
|
RGB_GET_LED_IDX,
|
|
PER_KEY_RGB_GET_TYPE,
|
|
PER_KEY_RGB_SET_TYPE,
|
|
PER_KEY_RGB_GET_COLOR,
|
|
PER_KEY_RGB_SET_COLOR, //10
|
|
MIXED_EFFECT_RGB_GET_INFO,
|
|
MIXED_EFFECT_RGB_GET_REGIONS,
|
|
MIXED_EFFECT_RGB_SET_REGIONS,
|
|
MIXED_EFFECT_RGB_GET_EFFECT_LIST,
|
|
MIXED_EFFECT_RGB_SET_EFFECT_LIST,
|
|
};
|
|
|
|
extern uint8_t retail_demo_enable;
|
|
extern uint8_t per_key_rgb_type;
|
|
extern HSV per_key_led[RGB_MATRIX_LED_COUNT];
|
|
extern HSV default_per_key_led[RGB_MATRIX_LED_COUNT];
|
|
|
|
extern uint8_t regions[RGB_MATRIX_LED_COUNT];
|
|
extern uint8_t rgb_regions[RGB_MATRIX_LED_COUNT];
|
|
extern effect_config_t effect_list[EFFECT_LAYERS][EFFECTS_PER_LAYER];
|
|
extern uint8_t default_region[RGB_MATRIX_LED_COUNT];
|
|
|
|
os_indicator_config_t os_ind_cfg;
|
|
|
|
extern void update_mixed_rgb_effect_count(void);
|
|
|
|
void eeconfig_reset_custom_rgb(void) {
|
|
os_ind_cfg.disable.raw = 0;
|
|
os_ind_cfg.hsv.s = 0;
|
|
os_ind_cfg.hsv.h = os_ind_cfg.hsv.v = 0xFF;
|
|
|
|
eeprom_update_block(&os_ind_cfg, OFFSET_OS_INDICATOR, sizeof(os_ind_cfg));
|
|
retail_demo_enable = 0;
|
|
eeprom_read_block(&retail_demo_enable, (uint8_t *)(OFFSET_RETAIL_DEMO), sizeof(retail_demo_enable));
|
|
per_key_rgb_type = 0;
|
|
eeprom_update_block(&per_key_rgb_type, OFFSET_PER_KEY_RGB_TYPE, sizeof(per_key_rgb_type));
|
|
|
|
memcpy(per_key_led, default_per_key_led, sizeof(per_key_led));
|
|
eeprom_update_block(per_key_led, OFFSET_PER_KEY_RGBS, sizeof(per_key_led));
|
|
|
|
memcpy(regions, default_region, RGB_MATRIX_LED_COUNT);
|
|
eeprom_update_block(regions, OFFSET_LAYER_FLAGS, sizeof(regions));
|
|
|
|
memset(effect_list, 0, sizeof(effect_list));
|
|
|
|
effect_list[0][0].effect = 5;
|
|
effect_list[0][0].sat = 255;
|
|
effect_list[0][0].speed = 127;
|
|
effect_list[0][0].time = 5000;
|
|
|
|
effect_list[1][0].effect = 2;
|
|
effect_list[1][0].hue = 0;
|
|
effect_list[1][0].sat = 255;
|
|
effect_list[1][0].speed = 127;
|
|
effect_list[1][0].time = 5000;
|
|
|
|
eeprom_update_block(effect_list, OFFSET_EFFECT_LIST, sizeof(effect_list));
|
|
update_mixed_rgb_effect_count();
|
|
}
|
|
|
|
void eeconfig_init_custom_rgb(void) {
|
|
memcpy(per_key_led, default_per_key_led, sizeof(per_key_led));
|
|
eeprom_update_dword(EECONFIG_KEYBOARD, (EECONFIG_KB_DATA_VERSION));
|
|
|
|
eeprom_read_block(&os_ind_cfg, OFFSET_OS_INDICATOR, sizeof(os_ind_cfg));
|
|
eeprom_read_block(&retail_demo_enable, (uint8_t *)(OFFSET_RETAIL_DEMO), sizeof(retail_demo_enable));
|
|
|
|
if (os_ind_cfg.hsv.v < 128) os_ind_cfg.hsv.v = 128;
|
|
// Load per key rgb led
|
|
eeprom_read_block(&per_key_rgb_type, OFFSET_PER_KEY_RGB_TYPE, sizeof(per_key_rgb_type));
|
|
eeprom_read_block(per_key_led, OFFSET_PER_KEY_RGBS, sizeof(per_key_led));
|
|
// Load mixed rgb
|
|
eeprom_read_block(regions, OFFSET_LAYER_FLAGS, sizeof(regions));
|
|
eeprom_read_block(effect_list, OFFSET_EFFECT_LIST, sizeof(effect_list));
|
|
update_mixed_rgb_effect_count();
|
|
|
|
}
|
|
|
|
void rgb_save_retail_demo(void) {
|
|
eeprom_update_block(&retail_demo_enable, (uint8_t *)(OFFSET_RETAIL_DEMO), sizeof(retail_demo_enable));
|
|
}
|
|
|
|
static bool rgb_get_version(uint8_t *data) {
|
|
data[1] = PER_KEY_RGB_VER & 0xFF;
|
|
data[2] = (PER_KEY_RGB_VER >> 8) & 0xFF;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool rgb_get_led_count(uint8_t *data) {
|
|
data[1] = RGB_MATRIX_LED_COUNT;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool rgb_get_led_idx(uint8_t *data) {
|
|
uint8_t row = data[0];
|
|
if (row > MATRIX_ROWS) return false;
|
|
|
|
uint8_t led_idx[128];
|
|
uint32_t row_mask = 0;
|
|
memcpy(&row_mask, &data[1], 3);
|
|
|
|
for (uint8_t c = 0; c < MATRIX_COLS; c++) {
|
|
led_idx[0] = 0xFF;
|
|
if (row_mask & (0x01 << c)) {
|
|
rgb_matrix_map_row_column_to_led(row, c, led_idx);
|
|
}
|
|
data[1 + c] = led_idx[0];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool per_key_rgb_get_type(uint8_t *data) {
|
|
extern uint8_t per_key_rgb_type;
|
|
data[1] = per_key_rgb_type;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool per_key_rgb_set_type(uint8_t *data) {
|
|
uint8_t type = data[0];
|
|
|
|
if (type >= PER_KEY_RGB_MAX) return false;
|
|
|
|
per_key_rgb_type = data[0];
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool per_key_rgb_get_led_color(uint8_t *data) {
|
|
uint8_t start = data[0];
|
|
uint8_t count = data[1];
|
|
|
|
if (count > 9) return false;
|
|
|
|
for (uint8_t i = 0; i < count; i++) {
|
|
data[1 + i * 3] = per_key_led[start + i].h;
|
|
data[2 + i * 3] = per_key_led[start + i].s;
|
|
data[3 + i * 3] = per_key_led[start + i].v;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool per_key_rgb_set_led_color(uint8_t *data) {
|
|
uint8_t start = data[0];
|
|
uint8_t count = data[1];
|
|
|
|
if (count > 9) return false;
|
|
|
|
for (uint8_t i = 0; i < count; i++) {
|
|
per_key_led[start + i].h = data[2 + i * 3];
|
|
per_key_led[start + i].s = data[3 + i * 3];
|
|
per_key_led[start + i].v = data[4 + i * 3];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool mixed_rgb_get_effect_info(uint8_t *data) {
|
|
data[1] = EFFECT_LAYERS;
|
|
data[2] = EFFECTS_PER_LAYER;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool mixed_rgb_get_regions(uint8_t *data) {
|
|
uint8_t start = data[0];
|
|
uint8_t count = data[1];
|
|
|
|
if (count > 29 || start + count > RGB_MATRIX_LED_COUNT) return false;
|
|
memcpy(&data[1], ®ions[start], count);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool mixed_rgb_set_regions(uint8_t *data) {
|
|
uint8_t start = data[0];
|
|
uint8_t count = data[1];
|
|
|
|
if (count > 28 || start + count > RGB_MATRIX_LED_COUNT) return false;
|
|
for (uint8_t i = 0; i < count; i++)
|
|
if (data[2 + i] >= EFFECT_LAYERS) return false;
|
|
|
|
memcpy(®ions[start], &data[2], count);
|
|
memcpy(&rgb_regions[start], &data[2], count);
|
|
|
|
return true;
|
|
}
|
|
#define EFFECT_DATA_LEN 8
|
|
|
|
static bool mixed_rgb_get_effect_list(uint8_t *data) {
|
|
uint8_t region = data[0];
|
|
uint8_t start = data[1];
|
|
uint8_t count = data[2];
|
|
|
|
if (count > 3 || region > EFFECT_LAYERS || start + count > EFFECTS_PER_LAYER) return false;
|
|
|
|
for (uint8_t i = 0; i < count; i++) {
|
|
data[1 + i * EFFECT_DATA_LEN] = effect_list[region][start + i].effect;
|
|
data[2 + i * EFFECT_DATA_LEN] = effect_list[region][start + i].hue;
|
|
data[3 + i * EFFECT_DATA_LEN] = effect_list[region][start + i].sat;
|
|
data[4 + i * EFFECT_DATA_LEN] = effect_list[region][start + i].speed;
|
|
memcpy(&data[5 + i * EFFECT_DATA_LEN], &effect_list[region][start + i].time, 4);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool mixed_rgb_set_effect_list(uint8_t *data) {
|
|
uint8_t region = data[0];
|
|
uint8_t start = data[1];
|
|
uint8_t count = data[2];
|
|
|
|
if (count > 3 || region > EFFECT_LAYERS || start + count > EFFECTS_PER_LAYER) return false;
|
|
for (uint8_t i = 0; i < count; i++) {
|
|
if (data[3 + i * EFFECT_DATA_LEN] >= RGB_MATRIX_CUSTOM_MIXED_RGB) return false;
|
|
}
|
|
|
|
for (uint8_t i = 0; i < count; i++) {
|
|
effect_list[region][start + i].effect = data[3 + i * EFFECT_DATA_LEN];
|
|
effect_list[region][start + i].hue = data[4 + i * EFFECT_DATA_LEN];
|
|
effect_list[region][start + i].sat = data[5 + i * EFFECT_DATA_LEN];
|
|
effect_list[region][start + i].speed = data[6 + i * EFFECT_DATA_LEN];
|
|
memcpy(&effect_list[region][start + i].time, &data[7 + i * EFFECT_DATA_LEN], 4);
|
|
}
|
|
update_mixed_rgb_effect_count();
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool kc_rgb_save(void) {
|
|
eeprom_update_block(&os_ind_cfg, OFFSET_OS_INDICATOR, sizeof(os_ind_cfg));
|
|
eeprom_update_block(&per_key_rgb_type, OFFSET_PER_KEY_RGB_TYPE, sizeof(per_key_rgb_type));
|
|
eeprom_update_block(per_key_led, OFFSET_PER_KEY_RGBS, RGB_MATRIX_LED_COUNT * sizeof(rgb_led_t));
|
|
eeprom_update_block(regions, OFFSET_LAYER_FLAGS, RGB_MATRIX_LED_COUNT);
|
|
eeprom_update_block(effect_list, OFFSET_EFFECT_LIST, sizeof(effect_list));
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool get_indicators_config(uint8_t *data) {
|
|
data[1] = 0
|
|
#if defined(NUM_LOCK_INDEX) && !defined(DIM_NUM_LOCK)
|
|
| (1 << 0x00)
|
|
#endif
|
|
#if defined(CAPS_LOCK_INDEX) && !defined(DIM_CAPS_LOCK)
|
|
| (1 << 0x01)
|
|
#endif
|
|
#if defined(SCROLL_LOCK_INDEX)
|
|
| (1 << 0x02)
|
|
#endif
|
|
#if defined(COMPOSE_LOCK_INDEX)
|
|
| (1 << 0x03)
|
|
#endif
|
|
#if defined(KANA_LOCK_INDEX)
|
|
| (1 << 0x04)
|
|
#endif
|
|
;
|
|
data[2] = os_ind_cfg.disable.raw;
|
|
data[3] = os_ind_cfg.hsv.h;
|
|
data[4] = os_ind_cfg.hsv.s;
|
|
data[5] = os_ind_cfg.hsv.v;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool set_indicators_config(uint8_t *data) {
|
|
os_ind_cfg.disable.raw = data[0];
|
|
os_ind_cfg.hsv.h = data[1];
|
|
os_ind_cfg.hsv.s = data[2];
|
|
os_ind_cfg.hsv.v = data[3];
|
|
|
|
if (os_ind_cfg.hsv.v < 128) os_ind_cfg.hsv.v = 128;
|
|
led_update_kb(host_keyboard_led_state());
|
|
|
|
return true;
|
|
}
|
|
|
|
void kc_rgb_matrix_rx(uint8_t *data, uint8_t length) {
|
|
uint8_t cmd = data[1];
|
|
bool success = true;
|
|
|
|
switch (cmd) {
|
|
case RGB_GET_PROTOCOL_VER:
|
|
success = rgb_get_version(&data[2]);
|
|
break;
|
|
|
|
case RGB_SAVE:
|
|
success = kc_rgb_save();
|
|
break;
|
|
|
|
case GET_INDICATORS_CONFIG:
|
|
success = get_indicators_config(&data[2]);
|
|
break;
|
|
|
|
case SET_INDICATORS_CONFIG:
|
|
success = set_indicators_config(&data[2]);
|
|
break;
|
|
|
|
case RGB_GET_LED_COUNT:
|
|
success = rgb_get_led_count(&data[2]);
|
|
break;
|
|
|
|
case RGB_GET_LED_IDX:
|
|
success = rgb_get_led_idx(&data[2]);
|
|
break;
|
|
|
|
case PER_KEY_RGB_GET_TYPE:
|
|
success = per_key_rgb_get_type(&data[2]);
|
|
break;
|
|
|
|
case PER_KEY_RGB_SET_TYPE:
|
|
success = per_key_rgb_set_type(&data[2]);
|
|
break;
|
|
|
|
case PER_KEY_RGB_GET_COLOR:
|
|
success = per_key_rgb_get_led_color(&data[2]);
|
|
break;
|
|
|
|
case PER_KEY_RGB_SET_COLOR:
|
|
success = per_key_rgb_set_led_color(&data[2]);
|
|
break;
|
|
|
|
case MIXED_EFFECT_RGB_GET_INFO:
|
|
success = mixed_rgb_get_effect_info(&data[2]);
|
|
break;
|
|
|
|
case MIXED_EFFECT_RGB_GET_REGIONS:
|
|
success = mixed_rgb_get_regions(&data[2]);
|
|
break;
|
|
|
|
case MIXED_EFFECT_RGB_SET_REGIONS:
|
|
success = mixed_rgb_set_regions(&data[2]);
|
|
break;
|
|
|
|
case MIXED_EFFECT_RGB_GET_EFFECT_LIST:
|
|
success = mixed_rgb_get_effect_list(&data[2]);
|
|
break;
|
|
|
|
case MIXED_EFFECT_RGB_SET_EFFECT_LIST:
|
|
success = mixed_rgb_set_effect_list(&data[2]);
|
|
break;
|
|
|
|
default:
|
|
data[0] = 0xFF;
|
|
break;
|
|
}
|
|
|
|
data[2] = success ? 0 : 1;
|
|
}
|
|
|
|
void os_state_indicate(void) {
|
|
# if defined(RGB_DISABLE_WHEN_USB_SUSPENDED) || defined(LED_DISABLE_WHEN_USB_SUSPENDED)
|
|
if (get_transport() == TRANSPORT_USB && USB_DRIVER.state == USB_SUSPENDED) return;
|
|
# endif
|
|
|
|
RGB rgb = hsv_to_rgb(os_ind_cfg.hsv);
|
|
|
|
# if defined(NUM_LOCK_INDEX)
|
|
if (host_keyboard_led_state().num_lock && !os_ind_cfg.disable.num_lock) {
|
|
rgb_matrix_set_color(NUM_LOCK_INDEX, rgb.r, rgb.g, rgb.b);
|
|
}
|
|
# endif
|
|
# if defined(CAPS_LOCK_INDEX)
|
|
if (host_keyboard_led_state().caps_lock && !os_ind_cfg.disable.caps_lock) {
|
|
rgb_matrix_set_color(CAPS_LOCK_INDEX, rgb.r, rgb.g, rgb.b);
|
|
}
|
|
# endif
|
|
# if defined(SCROLL_LOCK_INDEX)
|
|
if (host_keyboard_led_state().compose && !os_ind_cfg.disable.scroll_lock) {
|
|
rgb_matrix_set_color(SCROLL_LOCK_INDEX, rgb.r, rgb.g, rgb.b);
|
|
}
|
|
# endif
|
|
# if defined(COMPOSE_LOCK_INDEX)
|
|
if (host_keyboard_led_state().compose && !os_ind_cfg.disable.compose) {
|
|
rgb_matrix_set_color(COMPOSE_LOCK_INDEX, rgb.r, rgb.g, rgb.b);
|
|
}
|
|
# endif
|
|
# if defined(KANA_LOCK_INDEX)
|
|
if (host_keyboard_led_state().kana && !os_ind_cfg.disable.kana) {
|
|
rgb_matrix_set_color(KANA_LOCK_INDEX, rgb.r, rgb.g, rgb.b);
|
|
}
|
|
# endif
|
|
(void)rgb;
|
|
}
|
|
|
|
bool process_record_keychron_rgb(uint16_t keycode, keyrecord_t *record) {
|
|
if (rgb_matrix_get_mode() == RGB_MATRIX_CUSTOM_MIXED_RGB || rgb_matrix_get_mode() == RGB_MATRIX_CUSTOM_PER_KEY_RGB) {
|
|
switch (keycode) {
|
|
case RGB_HUI ... RGB_SAD:
|
|
return false;
|
|
|
|
case RGB_SPI:
|
|
if (rgb_matrix_get_mode() == RGB_MATRIX_CUSTOM_MIXED_RGB) {
|
|
return false;
|
|
} else {
|
|
rgb_matrix_config.speed = qadd8(rgb_matrix_config.speed, RGB_MATRIX_SPD_STEP);
|
|
eeprom_write_byte((uint8_t *)EECONFIG_RGB_MATRIX + offsetof(rgb_config_t, speed), rgb_matrix_config.speed);
|
|
}
|
|
break;
|
|
case RGB_SPD:
|
|
if (rgb_matrix_get_mode() == RGB_MATRIX_CUSTOM_MIXED_RGB) {
|
|
return false;
|
|
} else {
|
|
rgb_matrix_config.speed = qsub8(rgb_matrix_config.speed, RGB_MATRIX_SPD_STEP);
|
|
eeprom_write_byte((uint8_t *)EECONFIG_RGB_MATRIX + offsetof(rgb_config_t, speed), rgb_matrix_config.speed);
|
|
}
|
|
break;
|
|
|
|
case RGB_VAI:
|
|
# ifdef RGB_MATRIX_BRIGHTNESS_TURN_OFF_VAL
|
|
if (!rgb_matrix_config.enable) {
|
|
rgb_matrix_toggle();
|
|
return false;
|
|
}
|
|
# endif
|
|
rgb_matrix_config.hsv.v = qadd8(rgb_matrix_config.hsv.v, RGB_MATRIX_VAL_STEP);
|
|
# ifdef RGB_MATRIX_BRIGHTNESS_TURN_OFF_VAL
|
|
while (rgb_matrix_config.hsv.v <= RGB_MATRIX_BRIGHTNESS_TURN_OFF_VAL)
|
|
rgb_matrix_config.hsv.v = qadd8(rgb_matrix_config.hsv.v, RGB_MATRIX_VAL_STEP);
|
|
# endif
|
|
eeprom_write_byte((uint8_t *)EECONFIG_RGB_MATRIX + offsetof(rgb_config_t, hsv.v), rgb_matrix_config.hsv.v);
|
|
return false;
|
|
|
|
case RGB_VAD:
|
|
# ifdef RGB_MATRIX_BRIGHTNESS_TURN_OFF_VAL
|
|
if (rgb_matrix_config.enable && rgb_matrix_config.hsv.v > RGB_MATRIX_BRIGHTNESS_TURN_OFF_VAL)
|
|
# endif
|
|
{
|
|
rgb_matrix_config.hsv.v = qsub8(rgb_matrix_config.hsv.v, RGB_MATRIX_VAL_STEP);
|
|
eeprom_write_byte((uint8_t *)EECONFIG_RGB_MATRIX + offsetof(rgb_config_t, hsv.v), rgb_matrix_config.hsv.v);
|
|
}
|
|
# ifdef RGB_MATRIX_BRIGHTNESS_TURN_OFF_VAL
|
|
if (rgb_matrix_config.enable && rgb_matrix_config.hsv.v <= RGB_MATRIX_BRIGHTNESS_TURN_OFF_VAL) {
|
|
rgb_matrix_toggle();
|
|
}
|
|
# endif
|
|
return false;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
#endif
|