Compare commits

...
10 Commits
Author SHA1 Message Date
rootiest e99318637c feat(q5_max): overhaul via keymap with custom layers and encoder features
Automatic Approve / automatic_approve (push) Has been skipped
Replace stock MAC/WIN dual-boot layers with a single-OS 6-layer layout
(BASE, FN1, FN2, FN3, FN4, KEEB_CTL). Add tap-dance Home/End, a mouse
control layer (FN2), and timer-based Alt+Tab cycling on the FN2 encoder.

- Restructure layers: drop MAC_BASE/MAC_FN/WIN_BASE/WIN_FN; add FN1-FN4
  and KEEB_CTL with Bluetooth/RGB controls
- Add ALT_TAB_FWD/ALT_TAB_BWD custom keycodes driven by matrix_scan_user
  timer to hold Alt across encoder ticks (750ms timeout)
- Assign FN2 encoder to Alt+Tab / Alt+Shift+Tab cycling
- Add TD_HOME_END tap-dance (tap=Home, double=End) on numpad Home key
- Enable MOUSEKEY_ENABLE and TAP_DANCE_ENABLE in rules.mk
- Set DYNAMIC_KEYMAP_LAYER_COUNT=6 and TAPPING_TOGGLE=3 in config.h
2026-04-05 20:07:55 -04:00
rootiest 2dba2a548b feat(k17_max): add td_home_end to zooey's board
Add the tap-dance sequence:
  - Single Tap - Home
  - Double Tap - End
2026-04-05 20:07:55 -04:00
lokher 666862cb81 Add Q2 Max JIS 2026-03-16 19:07:27 +08:00
lokher 6f5058f7d0 Add Lemokey L1 ISO 2026-01-19 11:17:48 +08:00
lokher f3cea8e97a Add Q3 Max JIS 2025-12-08 10:14:28 +08:00
lokher 0a529031e6 Added Q6 Max JIS 2025-09-09 12:31:34 +08:00
lokher 8b525cb770 Added snap click and per-key/mixed RGB to V3 MAX 2025-05-30 23:56:29 +08:00
lokher c9049679ac Added snap click, per-key/mixed rgb, custom debounce, wireless config feature 2025-05-30 23:55:10 +08:00
lokher b507ea2216 Added K11 Max JIS 2025-03-25 16:16:19 +08:00
lokher 3a445969c4 Fixed Q6 Max compile error when rgb_matrix is disabled 2025-03-25 16:15:30 +08:00
169 changed files with 9052 additions and 1007 deletions
+2
View File
@@ -2,3 +2,5 @@ COMMON_DIR = common
SRC += $(COMMON_DIR)/matrix.c
VPATH += $(TOP_DIR)/keyboards/keychron/$(COMMON_DIR)
include $(TOP_DIR)/keyboards/keychron/$(COMMON_DIR)/debounce/debounce.mk
@@ -0,0 +1,170 @@
/*
* Copyright 2017 Alex Ong <the.onga@gmail.com>
* Copyright 2020 Andrei Purdea <andrei@purdea.ro>
* Copyright 2021 Simon Arlott
* 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/>.
*/
/*
Basic symmetric per-key algorithm. Uses an 8-bit counter per key.
When no state changes have occured for DEBOUNCE milliseconds, we push the state.
*/
#include "debounce.h"
#include "timer.h"
#include <stdlib.h>
#ifdef PROTOCOL_CHIBIOS
# if CH_CFG_USE_MEMCORE == FALSE
# error ChibiOS is configured without a memory allocator. Your keyboard may have set `#define CH_CFG_USE_MEMCORE FALSE`, which is incompatible with this debounce algorithm.
# endif
#endif
#define ROW_SHIFTER ((matrix_row_t)1)
typedef struct {
bool pressed : 1;
uint8_t time : 7;
} debounce_counter_t;
extern uint8_t debounce_time;
static debounce_counter_t *debounce_counters = NULL;
static fast_timer_t last_time;
static bool counters_need_update;
static bool matrix_need_update;
static bool cooked_changed;
# define DEBOUNCE_ELAPSED 0
static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time);
static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
// we use num_rows rather than MATRIX_ROWS to support split keyboards
void asym_eager_defer_pk_debounce_init(uint8_t num_rows) {
debounce_counters = malloc(num_rows * MATRIX_COLS * sizeof(debounce_counter_t));
int i = 0;
for (uint8_t r = 0; r < num_rows; r++) {
for (uint8_t c = 0; c < MATRIX_COLS; c++) {
debounce_counters[i++].time = DEBOUNCE_ELAPSED;
}
}
}
void asym_eager_defer_pk_debounce_free(void) {
if (debounce_counters != NULL) {
free(debounce_counters);
debounce_counters = NULL;
}
}
bool asym_eager_defer_pk_debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
bool updated_last = false;
cooked_changed = false;
if (counters_need_update) {
fast_timer_t now = timer_read_fast();
fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
last_time = now;
updated_last = true;
if (elapsed_time > UINT8_MAX) {
elapsed_time = UINT8_MAX;
}
if (elapsed_time > 0) {
update_debounce_counters_and_transfer_if_expired(raw, cooked, num_rows, elapsed_time);
}
}
if (changed || matrix_need_update) {
if (!updated_last) {
last_time = timer_read_fast();
}
transfer_matrix_values(raw, cooked, num_rows);
}
return cooked_changed;
}
static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time) {
debounce_counter_t *debounce_pointer = debounce_counters;
counters_need_update = false;
matrix_need_update = false;
for (uint8_t row = 0; row < num_rows; row++) {
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
matrix_row_t col_mask = (ROW_SHIFTER << col);
if (debounce_pointer->time != DEBOUNCE_ELAPSED) {
if (debounce_pointer->time <= elapsed_time) {
debounce_pointer->time = DEBOUNCE_ELAPSED;
if (debounce_pointer->pressed) {
// key-down: eager
matrix_need_update = true;
} else {
// key-up: defer
matrix_row_t cooked_next = (cooked[row] & ~col_mask) | (raw[row] & col_mask);
cooked_changed |= cooked_next ^ cooked[row];
cooked[row] = cooked_next;
}
} else {
debounce_pointer->time -= elapsed_time;
counters_need_update = true;
}
}
debounce_pointer++;
}
}
}
static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) {
debounce_counter_t *debounce_pointer = debounce_counters;
matrix_need_update = false;
for (uint8_t row = 0; row < num_rows; row++) {
matrix_row_t delta = raw[row] ^ cooked[row];
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
matrix_row_t col_mask = (ROW_SHIFTER << col);
if (delta & col_mask) {
if (debounce_pointer->time == DEBOUNCE_ELAPSED) {
debounce_pointer->pressed = (raw[row] & col_mask);
debounce_pointer->time = debounce_time;;
counters_need_update = true;
if (debounce_pointer->pressed) {
// key-down: eager
cooked[row] ^= col_mask;
cooked_changed = true;
}
}
} else if (debounce_pointer->time != DEBOUNCE_ELAPSED) {
if (!debounce_pointer->pressed) {
// key-up: defer
debounce_pointer->time = DEBOUNCE_ELAPSED;
}
}
debounce_pointer++;
}
}
}
@@ -0,0 +1,14 @@
DEBOUNCE_DIR = common/debounce
SRC += \
$(DEBOUNCE_DIR)/sym_defer_g.c \
$(DEBOUNCE_DIR)/sym_defer_pr.c \
$(DEBOUNCE_DIR)/sym_defer_pk.c \
$(DEBOUNCE_DIR)/sym_eager_pr.c \
$(DEBOUNCE_DIR)/sym_eager_pk.c \
$(DEBOUNCE_DIR)/asym_eager_defer_pk.c \
$(DEBOUNCE_DIR)/none.c \
$(DEBOUNCE_DIR)/keychron_debounce.c
VPATH += $(TOP_DIR)/keyboards/keychron/$(DEBOUNCE_DIR)
OPT_DEFS += -DDYNAMIC_DEBOUNCE_ENABLE
@@ -0,0 +1,20 @@
/* 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/>.
*/
#pragma once
#define EECONFIG_SIZE_DEBOUNCE 2
@@ -0,0 +1,214 @@
/* 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 "keychron_debounce.h"
#include "raw_hid.h"
#include "quantum.h"
#include "eeconfig.h"
#include "eeconfig_kb.h"
#include "keychron_raw_hid.h"
#ifdef SPLIT_KEYBOARD
# pragma(error "Split keyboard is not supported")
#endif
#ifndef DEBOUNCE
# define DEBOUNCE 5
#endif
// Maximum debounce: 255ms
#if DEBOUNCE > UINT8_MAX
# undef DEBOUNCE
# define DEBOUNCE UINT8_MAX
#endif
#ifndef DEFAULT_DEBOUNCE_TYPE
#define DEFAULT_DEBOUNCE_TYPE DEBOUNCE_SYM_EAGER_PER_KEY
#endif
#define DEBOUNCE_SET_QMK 0
#define OFFSET_DEBOUNCE ((uint8_t *)(EECONFIG_BASE_DYNAMIC_DEBOUNCE))
static uint8_t debounce_type = 0;
uint8_t debounce_time = 0;
static debounce_t debounce_func = {NULL, NULL, NULL};
extern void sym_defer_g_debounce_init(uint8_t num_rows);
extern bool sym_defer_g_debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed);
extern void sym_defer_g_debounce_free(void);
extern void sym_defer_pr_debounce_init(uint8_t num_rows);
extern bool sym_defer_pr_debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed);
extern void sym_defer_pr_debounce_free(void);
extern void sym_defer_pk_debounce_init(uint8_t num_rows);
extern bool sym_defer_pk_debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed);
extern void sym_defer_pk_debounce_free(void);
extern void sym_eager_pr_debounce_init(uint8_t num_rows);
extern bool sym_eager_pr_debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed);
extern void sym_eager_pr_debounce_free(void);
extern void sym_eager_pk_debounce_init(uint8_t num_rows);
extern bool sym_eager_pk_debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed);
extern void sym_eager_pk_debounce_free(void);
extern void asym_eager_defer_pk_debounce_init(uint8_t num_rows);
extern bool asym_eager_defer_pk_debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed);
extern void asym_eager_defer_pk_debounce_free(void);
extern void none_debounce_init(uint8_t num_rows);
extern bool none_debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed);
extern void none_debounce_free(void);
void debounce_set(uint8_t new_debounce_type, uint8_t time, bool force);
/**
* @brief Debounce raw matrix events according to the choosen debounce algorithm.
*
* @param raw The current key state
* @param cooked The debounced key state
* @param num_rows Number of rows to debounce
* @param changed True if raw has changed since the last call
* @return true Cooked has new keychanges after debouncing
* @return false Cooked is the same as before
*/
bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
if (debounce_func.debounce) debounce_func.debounce(raw, cooked, num_rows, changed);
return false;
}
void debounce_init(uint8_t num_rows) {
debounce_type = 0;
// debounce_set(DEBOUNCE_SYM_EAGER_PER_KEY, DEBOUNCE);
if (!eeconfig_is_enabled()) {
eeconfig_init();
}
uint8_t type = eeprom_read_byte(OFFSET_DEBOUNCE);
uint8_t time = eeprom_read_byte(OFFSET_DEBOUNCE + 1);
if (type >= DEBOUNCE_MAX) type = DEFAULT_DEBOUNCE_TYPE;
debounce_set(type, time, debounce_type == type);
}
void debounce_free(void) {
if (debounce_func.debounce_free) debounce_func.debounce_free();
}
static bool debounce_save(void) {
eeprom_update_byte(OFFSET_DEBOUNCE, debounce_type);
eeprom_update_byte(OFFSET_DEBOUNCE + 1, debounce_time);
return true;
}
void debounce_config_reset(void) {
debounce_set(DEFAULT_DEBOUNCE_TYPE, DEBOUNCE, true);
debounce_save();
}
void debounce_set(uint8_t new_debounce_type, uint8_t time, bool force) {
if (new_debounce_type == debounce_type && time == debounce_time && !force) return;
debounce_free();
debounce_type = new_debounce_type;
debounce_time = time;
if (debounce_time == 0) new_debounce_type = DEBOUNCE_NONE;
switch (new_debounce_type) {
case DEBOUNCE_SYM_DEFER_GLOBAL:
debounce_func.debounce_init = sym_defer_g_debounce_init;
debounce_func.debounce = sym_defer_g_debounce;
debounce_func.debounce_free = sym_defer_g_debounce_free;
break;
case DEBOUNCE_SYM_DEFER_PER_ROW:
debounce_func.debounce_init = sym_defer_pr_debounce_init;
debounce_func.debounce = sym_defer_pr_debounce;
debounce_func.debounce_free = sym_defer_pr_debounce_free;
break;
case DEBOUNCE_SYM_DEFER_PER_KEY:
debounce_func.debounce_init = sym_defer_pk_debounce_init;
debounce_func.debounce = sym_defer_pk_debounce;
debounce_func.debounce_free = sym_defer_pk_debounce_free;
break;
case DEBOUNCE_SYM_EAGER_PER_ROW:
debounce_func.debounce_init = sym_eager_pr_debounce_init;
debounce_func.debounce = sym_eager_pr_debounce;
debounce_func.debounce_free = sym_eager_pr_debounce_free;
break;
case DEBOUNCE_SYM_EAGER_PER_KEY:
debounce_func.debounce_init = sym_eager_pk_debounce_init;
debounce_func.debounce = sym_eager_pk_debounce;
debounce_func.debounce_free = sym_eager_pk_debounce_free;
break;
case DEBOUNCE_ASYM_EAGER_DEFER_PER_KEY:
debounce_func.debounce_init = asym_eager_defer_pk_debounce_init;
debounce_func.debounce = asym_eager_defer_pk_debounce;
debounce_func.debounce_free = asym_eager_defer_pk_debounce_free;
if (debounce_time > 127) debounce_time = 127;
break;
case DEBOUNCE_NONE:
debounce_func.debounce_init = none_debounce_init;
debounce_func.debounce = none_debounce;
debounce_func.debounce_free = none_debounce_free;
break;
}
if (debounce_func.debounce_init) debounce_func.debounce_init(MATRIX_ROWS);
}
void debounce_time_set(uint8_t time) {
debounce_time = time;
}
void debounce_rx(uint8_t *data, uint8_t length) {
uint8_t cmd = data[1];
switch (cmd) {
case DEBOUNCE_GET:
data[2] = 0;
data[3] = DEBOUNCE_SET_QMK;
data[4] = debounce_type;
data[5] = debounce_time;
break;
case DEBOUNCE_SET: {
uint8_t type = data[2];
uint8_t time = data[3];
if (type < DEBOUNCE_MAX) {
data[2] = 0;
debounce_set(type, time, false);
debounce_save();
} else
data[2] = 1;
} break;
default:
data[0] = 0xFF;
break;
}
}
@@ -0,0 +1,56 @@
/* 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/>.
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "matrix.h"
enum {
DEBOUNCE_SYM_DEFER_GLOBAL,
DEBOUNCE_SYM_DEFER_PER_ROW,
DEBOUNCE_SYM_DEFER_PER_KEY,
DEBOUNCE_SYM_EAGER_PER_ROW,
DEBOUNCE_SYM_EAGER_PER_KEY,
DEBOUNCE_ASYM_EAGER_DEFER_PER_KEY,
DEBOUNCE_NONE,
DEBOUNCE_MAX,
};
typedef struct {
void (*debounce_init)(uint8_t);
bool (*debounce)(matrix_row_t [], matrix_row_t [], uint8_t, bool);
void (*debounce_free)(void);
} debounce_t;
/**
* @brief Debounce raw matrix events according to the choosen debounce algorithm.
*
* @param raw The current key state
* @param cooked The debounced key state
* @param num_rows Number of rows to debounce
* @param changed True if raw has changed since the last call
* @return true Cooked has new keychanges after debouncing
* @return false Cooked is the same as before
*/
bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed);
void debounce_init(uint8_t num_rows);
void debounce_config_reset(void);
void debounce_free(void);
void debounce_rx(uint8_t *data, uint8_t length);
+36
View File
@@ -0,0 +1,36 @@
/* Copyright 2021 Simon Arlott
*
* 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 "debounce.h"
#include <string.h>
void none_debounce_init(uint8_t num_rows) {}
bool none_debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
bool cooked_changed = false;
if (changed) {
size_t matrix_size = num_rows * sizeof(matrix_row_t);
if (memcmp(cooked, raw, matrix_size) != 0) {
memcpy(cooked, raw, matrix_size);
cooked_changed = true;
}
}
return cooked_changed;
}
void none_debounce_free(void) {}
+36
View File
@@ -0,0 +1,36 @@
/* Copyright 2021 Simon Arlott
*
* 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 "debounce.h"
#include <string.h>
void none_debounce_init(uint8_t num_rows) {}
bool none_debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
bool cooked_changed = false;
if (changed) {
size_t matrix_size = num_rows * sizeof(matrix_row_t);
if (memcmp(cooked, raw, matrix_size) != 0) {
memcpy(cooked, raw, matrix_size);
cooked_changed = true;
}
}
return cooked_changed;
}
void none_debounce_free(void) {}
@@ -0,0 +1,51 @@
/*
Copyright 2017 Alex Ong<the.onga@gmail.com>
Copyright 2021 Simon Arlott
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/>.
*/
/*
Basic global debounce algorithm. Used in 99% of keyboards at time of implementation
When no state changes have occured for DEBOUNCE milliseconds, we push the state.
*/
#include "debounce.h"
#include "timer.h"
#include <string.h>
extern uint8_t debounce_time;
static bool debouncing = false;
static fast_timer_t debouncing_time;
void sym_defer_g_debounce_init(uint8_t num_rows) {}
bool sym_defer_g_debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
bool cooked_changed = false;
if (changed) {
debouncing = true;
debouncing_time = timer_read_fast();
} else if (debouncing && timer_elapsed_fast(debouncing_time) >= debounce_time) {
size_t matrix_size = num_rows * sizeof(matrix_row_t);
if (memcmp(cooked, raw, matrix_size) != 0) {
memcpy(cooked, raw, matrix_size);
cooked_changed = true;
}
debouncing = false;
}
return cooked_changed;
}
void sym_defer_g_debounce_free(void) {}
@@ -0,0 +1,137 @@
/*
Copyright 2017 Alex Ong<the.onga@gmail.com>
Copyright 2020 Andrei Purdea<andrei@purdea.ro>
Copyright 2021 Simon Arlott
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/>.
*/
/*
Basic symmetric per-key algorithm. Uses an 8-bit counter per key.
When no state changes have occured for DEBOUNCE milliseconds, we push the state.
*/
#include "debounce.h"
#include "timer.h"
#include <stdlib.h>
#ifdef PROTOCOL_CHIBIOS
# if CH_CFG_USE_MEMCORE == FALSE
# error ChibiOS is configured without a memory allocator. Your keyboard may have set `#define CH_CFG_USE_MEMCORE FALSE`, which is incompatible with this debounce algorithm.
# endif
#endif
#define ROW_SHIFTER ((matrix_row_t)1)
typedef uint8_t debounce_counter_t;
extern uint8_t debounce_time;
static debounce_counter_t *debounce_counters = NULL;
static fast_timer_t last_time;
static bool counters_need_update;
static bool cooked_changed;
# define DEBOUNCE_ELAPSED 0
static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time);
static void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
// we use num_rows rather than MATRIX_ROWS to support split keyboards
void sym_defer_pk_debounce_init(uint8_t num_rows) {
debounce_counters = (debounce_counter_t *)malloc(num_rows * MATRIX_COLS * sizeof(debounce_counter_t));
int i = 0;
for (uint8_t r = 0; r < num_rows; r++) {
for (uint8_t c = 0; c < MATRIX_COLS; c++) {
debounce_counters[i++] = DEBOUNCE_ELAPSED;
}
}
}
void sym_defer_pk_debounce_free(void) {
if (debounce_counters != NULL) {
free(debounce_counters);
debounce_counters = NULL;
}
}
bool sym_defer_pk_debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
bool updated_last = false;
cooked_changed = false;
if (counters_need_update) {
fast_timer_t now = timer_read_fast();
fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
last_time = now;
updated_last = true;
if (elapsed_time > UINT8_MAX) {
elapsed_time = UINT8_MAX;
}
if (elapsed_time > 0) {
update_debounce_counters_and_transfer_if_expired(raw, cooked, num_rows, elapsed_time);
}
}
if (changed) {
if (!updated_last) {
last_time = timer_read_fast();
}
start_debounce_counters(raw, cooked, num_rows);
}
return cooked_changed;
}
static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time) {
counters_need_update = false;
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
if (*debounce_pointer != DEBOUNCE_ELAPSED) {
if (*debounce_pointer <= elapsed_time) {
*debounce_pointer = DEBOUNCE_ELAPSED;
matrix_row_t cooked_next = (cooked[row] & ~(ROW_SHIFTER << col)) | (raw[row] & (ROW_SHIFTER << col));
cooked_changed |= cooked[row] ^ cooked_next;
cooked[row] = cooked_next;
} else {
*debounce_pointer -= elapsed_time;
counters_need_update = true;
}
}
debounce_pointer++;
}
}
}
static void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) {
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
matrix_row_t delta = raw[row] ^ cooked[row];
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
if (delta & (ROW_SHIFTER << col)) {
if (*debounce_pointer == DEBOUNCE_ELAPSED) {
*debounce_pointer = debounce_time;;
counters_need_update = true;
}
} else {
*debounce_pointer = DEBOUNCE_ELAPSED;
}
debounce_pointer++;
}
}
}
@@ -0,0 +1,80 @@
/*
Copyright 2021 Chad Austin <chad@chadaustin.me>
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/>.
*/
/*
Symmetric per-row debounce algorithm. Changes only apply when
DEBOUNCE milliseconds have elapsed since the last change.
*/
#include "debounce.h"
#include "timer.h"
#include <stdlib.h>
extern uint8_t debounce_time;
static uint16_t last_time;
// [row] milliseconds until key's state is considered debounced.
static uint8_t* countdowns = NULL;
// [row]
static matrix_row_t* last_raw = NULL;
void sym_defer_pr_debounce_init(uint8_t num_rows) {
countdowns = (uint8_t*)calloc(num_rows, sizeof(uint8_t));
last_raw = (matrix_row_t*)calloc(num_rows, sizeof(matrix_row_t));
last_time = timer_read();
}
void sym_defer_pr_debounce_free(void) {
if (countdowns != NULL) {
free(countdowns);
countdowns = NULL;
}
if (last_raw != NULL) {
free(last_raw);
last_raw = NULL;
}
}
bool sym_defer_pr_debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
uint16_t now = timer_read();
uint16_t elapsed16 = TIMER_DIFF_16(now, last_time);
last_time = now;
uint8_t elapsed = (elapsed16 > 255) ? 255 : elapsed16;
bool cooked_changed = false;
uint8_t* countdown = countdowns;
for (uint8_t row = 0; row < num_rows; ++row, ++countdown) {
matrix_row_t raw_row = raw[row];
if (raw_row != last_raw[row]) {
*countdown = debounce_time;
last_raw[row] = raw_row;
} else if (*countdown > elapsed) {
*countdown -= elapsed;
} else if (*countdown) {
cooked_changed |= cooked[row] ^ raw_row;
cooked[row] = raw_row;
*countdown = 0;
}
}
return cooked_changed;
}
bool debounce_active(void) {
return true;
}
@@ -0,0 +1,142 @@
/*
Copyright 2017 Alex Ong<the.onga@gmail.com>
Copyright 2021 Simon Arlott
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/>.
*/
/*
Basic per-key algorithm. Uses an 8-bit counter per key.
After pressing a key, it immediately changes state, and sets a counter.
No further inputs are accepted until DEBOUNCE milliseconds have occurred.
*/
#include "debounce.h"
#include "timer.h"
#include <stdlib.h>
#ifdef PROTOCOL_CHIBIOS
# if CH_CFG_USE_MEMCORE == FALSE
# error ChibiOS is configured without a memory allocator. Your keyboard may have set `#define CH_CFG_USE_MEMCORE FALSE`, which is incompatible with this debounce algorithm.
# endif
#endif
extern uint8_t debounce_time;
#define ROW_SHIFTER ((matrix_row_t)1)
typedef uint8_t debounce_counter_t;
static debounce_counter_t *debounce_counters = NULL;
static fast_timer_t last_time;
static bool counters_need_update;
static bool matrix_need_update;
static bool cooked_changed;
# define DEBOUNCE_ELAPSED 0
static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time);
static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
// we use num_rows rather than MATRIX_ROWS to support split keyboards
void sym_eager_pk_debounce_init(uint8_t num_rows) {
debounce_counters = (debounce_counter_t *)malloc(num_rows * MATRIX_COLS * sizeof(debounce_counter_t));
int i = 0;
for (uint8_t r = 0; r < num_rows; r++) {
for (uint8_t c = 0; c < MATRIX_COLS; c++) {
debounce_counters[i++] = DEBOUNCE_ELAPSED;
}
}
}
void sym_eager_pk_debounce_free(void) {
if (debounce_counters != NULL) {
free(debounce_counters);
debounce_counters = NULL;
}
}
bool sym_eager_pk_debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
bool updated_last = false;
cooked_changed = false;
if (counters_need_update) {
fast_timer_t now = timer_read_fast();
fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
last_time = now;
updated_last = true;
if (elapsed_time > UINT8_MAX) {
elapsed_time = UINT8_MAX;
}
if (elapsed_time > 0) {
update_debounce_counters(num_rows, elapsed_time);
}
}
if (changed || matrix_need_update) {
if (!updated_last) {
last_time = timer_read_fast();
}
transfer_matrix_values(raw, cooked, num_rows);
}
return cooked_changed;
}
// If the current time is > debounce counter, set the counter to enable input.
static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time) {
counters_need_update = false;
matrix_need_update = false;
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
if (*debounce_pointer != DEBOUNCE_ELAPSED) {
if (*debounce_pointer <= elapsed_time) {
*debounce_pointer = DEBOUNCE_ELAPSED;
matrix_need_update = true;
} else {
*debounce_pointer -= elapsed_time;
counters_need_update = true;
}
}
debounce_pointer++;
}
}
}
// upload from raw_matrix to final matrix;
static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) {
matrix_need_update = false;
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
matrix_row_t delta = raw[row] ^ cooked[row];
matrix_row_t existing_row = cooked[row];
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
matrix_row_t col_mask = (ROW_SHIFTER << col);
if (delta & col_mask) {
if (*debounce_pointer == DEBOUNCE_ELAPSED) {
*debounce_pointer = debounce_time;
counters_need_update = true;
existing_row ^= col_mask; // flip the bit.
cooked_changed = true;
}
}
debounce_pointer++;
}
cooked[row] = existing_row;
}
}
@@ -0,0 +1,134 @@
/*
Copyright 2019 Alex Ong<the.onga@gmail.com>
Copyright 2021 Simon Arlott
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/>.
*/
/*
Basic per-row algorithm. Uses an 8-bit counter per row.
After pressing a key, it immediately changes state, and sets a counter.
No further inputs are accepted until DEBOUNCE milliseconds have occurred.
*/
#include "debounce.h"
#include "timer.h"
#include <stdlib.h>
#ifdef PROTOCOL_CHIBIOS
# if CH_CFG_USE_MEMCORE == FALSE
# error ChibiOS is configured without a memory allocator. Your keyboard may have set `#define CH_CFG_USE_MEMCORE FALSE`, which is incompatible with this debounce algorithm.
# endif
#endif
typedef uint8_t debounce_counter_t;
extern uint8_t debounce_time;
static bool matrix_need_update;
static debounce_counter_t *debounce_counters = NULL;
static fast_timer_t last_time;
static bool counters_need_update;
static bool cooked_changed;
# define DEBOUNCE_ELAPSED 0
static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time);
static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
// we use num_rows rather than MATRIX_ROWS to support split keyboards
void sym_eager_pr_debounce_init(uint8_t num_rows) {
debounce_counters = (debounce_counter_t *)malloc(num_rows * sizeof(debounce_counter_t));
for (uint8_t r = 0; r < num_rows; r++) {
debounce_counters[r] = DEBOUNCE_ELAPSED;
}
}
void sym_eager_pr_debounce_free(void) {
if (debounce_counters != NULL) {
free(debounce_counters);
debounce_counters = NULL;
}
}
bool sym_eager_pr_debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
bool updated_last = false;
cooked_changed = false;
if (counters_need_update) {
fast_timer_t now = timer_read_fast();
fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
last_time = now;
updated_last = true;
if (elapsed_time > UINT8_MAX) {
elapsed_time = UINT8_MAX;
}
if (elapsed_time > 0) {
update_debounce_counters(num_rows, elapsed_time);
}
}
if (changed || matrix_need_update) {
if (!updated_last) {
last_time = timer_read_fast();
}
transfer_matrix_values(raw, cooked, num_rows);
}
return cooked_changed;
}
// If the current time is > debounce counter, set the counter to enable input.
static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time) {
counters_need_update = false;
matrix_need_update = false;
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
if (*debounce_pointer != DEBOUNCE_ELAPSED) {
if (*debounce_pointer <= elapsed_time) {
*debounce_pointer = DEBOUNCE_ELAPSED;
matrix_need_update = true;
} else {
*debounce_pointer -= elapsed_time;
counters_need_update = true;
}
}
debounce_pointer++;
}
}
// upload from raw_matrix to final matrix;
static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) {
matrix_need_update = false;
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
matrix_row_t existing_row = cooked[row];
matrix_row_t raw_row = raw[row];
// determine new value basd on debounce pointer + raw value
if (existing_row != raw_row) {
if (*debounce_pointer == DEBOUNCE_ELAPSED) {
*debounce_pointer = debounce_time;
cooked_changed |= cooked[row] ^ raw_row;
cooked[row] = raw_row;
counters_need_update = true;
}
}
debounce_pointer++;
}
}
+49
View File
@@ -0,0 +1,49 @@
/* 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 <string.h>
#include "quantum.h"
enum {
DFU_INFO_CHIP = 1,
DFU_INFO_TYPE,
};
enum {
BL_TYPE_STM32 = 1,
BL_TYPE_WB32,
};
void dfu_info_rx(uint8_t *data, uint8_t length) {
uint8_t i = 2;
data[i++] = 0; // success
data[i++] = DFU_INFO_CHIP,
data[i++] = strlen(STR(QMK_MCU));
memcpy(&data[i], STR(QMK_MCU), strlen(STR(QMK_MCU)));
i += strlen(STR(QMK_MCU));
data[i++] = DFU_INFO_TYPE;
data[i++] = 1;
data[i++] =
#if defined(BOOTLOADER_STM32_DFU)
BL_TYPE_STM32
#elif defined(BOOTLOADER_WB32_DFU)
BL_TYPE_WB32
#else
0
#endif
;
}
+35
View File
@@ -0,0 +1,35 @@
/* 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 "eeconfig_kb.h"
#ifdef DYNAMIC_DEBOUNCE_ENABLE
# include "keychron_debounce.h"
#endif
void eeconfig_init_kb_datablock(void) {
#ifdef DYNAMIC_DEBOUNCE_ENABLE
extern void debounce_config_reset(void);
debounce_config_reset();
#endif
#if defined(SNAP_CLICK_ENABLE)
extern void snap_click_config_reset(void);
snap_click_config_reset();
#endif
#if defined(KEYCHRON_RGB_ENABLE) && defined(RGB_MATRIX_ENABLE)
extern void eeconfig_reset_custom_rgb(void);
eeconfig_reset_custom_rgb();
#endif
}
+61
View File
@@ -0,0 +1,61 @@
/* 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/>.
*/
#pragma once
#include "eeconfig_language.h"
#define EECONFIG_BASE_LANGUAGE 37
#define EECONFIG_END_LANGUAGE (EECONFIG_BASE_LANGUAGE + EECONFIG_SIZE_LANGUAGE)
#ifdef DYNAMIC_DEBOUNCE_ENABLE
# include "eeconfig_debounce.h"
# define __EECONFIG_SIZE_DEBOUNCE EECONFIG_SIZE_DEBOUNCE
#else
# define __EECONFIG_SIZE_DEBOUNCE 0
#endif
#define EECONFIG_BASE_DYNAMIC_DEBOUNCE EECONFIG_END_LANGUAGE
#define EECONFIG_END_DYNAMIC_DEBOUNCE (EECONFIG_BASE_DYNAMIC_DEBOUNCE + __EECONFIG_SIZE_DEBOUNCE)
#ifdef SNAP_CLICK_ENABLE
# include "eeconfig_snap_click.h"
# define __EECONFIG_SIZE_SNAP_CLICK EECONFIG_SIZE_SNAP_CLICK
#else
# define __EECONFIG_SIZE_SNAP_CLICK 0
#endif
#define EECONFIG_BASE_SNAP_CLICK (EECONFIG_END_DYNAMIC_DEBOUNCE)
#define EECONFIG_END_SNAP_CLICK (EECONFIG_BASE_SNAP_CLICK + __EECONFIG_SIZE_SNAP_CLICK)
#if defined(KEYCHRON_RGB_ENABLE) && defined(RGB_MATRIX_ENABLE)
# include "eeconfig_custom_rgb.h"
# define __EECONFIG_SIZE_CUSTOM_RGB EECONFIG_SIZE_CUSTOM_RGB
#else
# define __EECONFIG_SIZE_CUSTOM_RGB 0
#endif
#define EECONFIG_BASE_CUSTOM_RGB EECONFIG_END_SNAP_CLICK
#define EECONFIG_END_CUSTOM_RGB (EECONFIG_BASE_CUSTOM_RGB + __EECONFIG_SIZE_CUSTOM_RGB)
#if defined(WIRELESS_CONFIG_ENABLE)
# include "eeconfig_wireless.h"
# define __EECONFIG_SIZE_WIRELESS_CONFIG EECONFIG_SIZE_WIRELESS_CONFIG
#else
# define __EECONFIG_SIZE_WIRELESS_CONFIG 0
#endif
#define EECONFIG_BASE_WIRELESS_CONFIG EECONFIG_END_CUSTOM_RGB
#define EECONFIG_END_WIRELESS_CONFIG (EECONFIG_BASE_WIRELESS_CONFIG + __EECONFIG_SIZE_WIRELESS_CONFIG)
#define EECONFIG_KB_DATA_SIZE (EECONFIG_END_WIRELESS_CONFIG - EECONFIG_BASE_LANGUAGE)
+35 -9
View File
@@ -1,4 +1,4 @@
/* Copyright 2021 @ Keychron (https://www.keychron.com)
/* Copyright 2021~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
@@ -26,6 +26,12 @@
# include "lkbt51.h"
# include "indicator.h"
#endif
#ifdef DYNAMIC_DEBOUNCE_ENABLE
# include "keychron_debounce.h"
#endif
#ifdef SNAP_CLICK_ENABLE
# include "snap_click.h"
#endif
#include "config.h"
#include "version.h"
@@ -92,7 +98,9 @@ static uint8_t backlight_test_mode = BACKLIGHT_TEST_OFF;
static uint32_t factory_reset_ind_timer = 0;
static uint8_t factory_reset_ind_state = 0;
static bool report_os_sw_state = false;
static bool keys_released = true;
static uint8_t keys_released = 0;
extern void eeconfig_reset_custom_rgb(void);
void factory_timer_start(void) {
factory_reset_timer = timer_read32();
@@ -112,6 +120,12 @@ static inline void factory_timer_check(void) {
eeconfig_init();
keymap_config.raw = eeconfig_read_keymap();
default_layer_set(default_layer_tmp);
#ifdef DYNAMIC_DEBOUNCE_ENABLE
debounce_config_reset();
#endif
#ifdef SNAP_CLICK_ENABLE
snap_click_config_reset();
#endif
#ifdef LED_MATRIX_ENABLE
if (!led_matrix_is_enabled()) led_matrix_enable();
led_matrix_init();
@@ -119,8 +133,15 @@ static inline void factory_timer_check(void) {
#ifdef RGB_MATRIX_ENABLE
if (!rgb_matrix_is_enabled()) rgb_matrix_enable();
rgb_matrix_init();
#if defined(KEYCHRON_RGB_ENABLE) && defined(EECONFIG_SIZE_CUSTOM_RGB)
eeconfig_reset_custom_rgb();
#endif
#endif
#ifdef LK_WIRELESS_ENABLE
#ifdef EECONFIG_SIZE_WIRELESS_CONFIG
wireless_config_reset();
#endif
wait_ms(50);
lkbt51_factory_reset(P2P4G_CELAR_MASK);
#endif
} else if (factory_reset_state == KEY_PRESS_BACKLIGTH_TEST) {
@@ -168,13 +189,21 @@ bool process_record_factory_test(uint16_t keycode, keyrecord_t *record) {
break;
#endif
case KC_J:
#if defined(FN_J_KEY)
case FN_J_KEY:
#endif
if (record->event.pressed) {
factory_reset_state |= KEY_PRESS_J;
if (factory_reset_state == 0x07) factory_timer_start();
if (factory_reset_state & KEY_PRESS_FN) return false;
if ((factory_reset_state & KEY_PRESS_FN) && keycode == KC_J) return false;
} else {
factory_reset_state &= ~KEY_PRESS_J;
factory_reset_timer = 0;
/* Avoid changing backlight effect on key released if FN_Z_KEY is mode*/
if (keys_released & KEY_PRESS_J) {
keys_released &= ~KEY_PRESS_J;
if (keycode >= QK_BACKLIGHT_ON && keycode <= RGB_MODE_TWINKLE) return false;
}
}
break;
case KC_Z:
@@ -189,10 +218,9 @@ bool process_record_factory_test(uint16_t keycode, keyrecord_t *record) {
factory_reset_state &= ~KEY_PRESS_Z;
factory_reset_timer = 0;
/* Avoid changing backlight effect on key released if FN_Z_KEY is mode*/
if (!keys_released && keycode >= QK_BACKLIGHT_ON && keycode <= RGB_MODE_TWINKLE) {
keys_released = true;
return false;
if (keys_released & KEY_PRESS_Z) {
keys_released &= ~KEY_PRESS_Z;
if (keycode >= QK_BACKLIGHT_ON && keycode <= RGB_MODE_TWINKLE) return false;
}
}
break;
@@ -327,10 +355,8 @@ void factory_test_rx(uint8_t *data, uint8_t length) {
/* Verify checksum */
if ((checksum & 0xFF) != data[RAW_EPSIZE - 2] || checksum >> 8 != data[RAW_EPSIZE - 1]) return;
#ifdef LK_WIRELESS_ENABLE
uint8_t payload[32];
uint8_t len = 0;
#endif
switch (data[1]) {
case FACTORY_TEST_CMD_BACKLIGHT:
+48 -102
View File
@@ -16,16 +16,18 @@
#include QMK_KEYBOARD_H
#include "keychron_common.h"
#include "raw_hid.h"
#include "version.h"
#ifdef FACTORY_TEST_ENABLE
# include "factory_test.h"
# include "keychron_common.h"
#endif
#ifdef RETAIL_DEMO_ENABLE
# include "retail_demo.h"
#endif
#ifdef LK_WIRELESS_ENABLE
# include "lkbt51.h"
# include "wireless.h"
#endif
#ifdef LED_MATRIX_ENABLE
# include "led_matrix.h"
#endif
bool is_siri_active = false;
@@ -53,6 +55,35 @@ static key_combination_t key_comb_list[] = {
};
// clang-format on
void keychron_common_init(void) {
#ifdef SNAP_CLICK_ENABLE
extern void snap_click_init(void);
snap_click_init();
#endif
#if defined(RGB_MATRIX_ENABLE) && defined(KEYCHRON_RGB_ENABLE)
extern void eeconfig_init_custom_rgb(void);
eeconfig_init_custom_rgb();
#endif
#ifdef LK_WIRELESS_ENABLE
# ifdef P2P4_MODE_SELECT_PIN
palSetLineMode(P2P4_MODE_SELECT_PIN, PAL_MODE_INPUT);
# endif
# ifdef BT_MODE_SELECT_PIN
palSetLineMode(BT_MODE_SELECT_PIN, PAL_MODE_INPUT);
# endif
# ifdef BAT_LOW_LED_PIN
writePin(BAT_LOW_LED_PIN, BAT_LOW_LED_PIN_ON_STATE);
# endif
lkbt51_init(false);
wireless_init();
#endif
#ifdef ENCODER_ENABLE
encoder_cb_init();
#endif
}
bool process_record_keychron_common(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case KC_MCTRL:
@@ -111,9 +142,18 @@ bool process_record_keychron_common(uint16_t keycode, keyrecord_t *record) {
}
}
return false; // Skip all further processing of this key
#ifdef LED_MATRIX_ENABLE
case BL_SPI:
led_matrix_increase_speed();
break;
case BL_SPD:
led_matrix_decrease_speed();
break;
#endif
default:
return true; // Process all other keycodes normally
}
return true;
}
void keychron_common_task(void) {
@@ -134,105 +174,11 @@ static void encoder_pad_cb(void *param) {
void encoder_cb_init(void) {
pin_t encoders_pad_a[] = ENCODERS_PAD_A;
pin_t encoders_pad_b[] = ENCODERS_PAD_B;
for (uint32_t i=0; i<NUM_ENCODERS; i++)
{
for (uint32_t i = 0; i < NUM_ENCODERS; i++) {
palEnableLineEvent(encoders_pad_a[i], PAL_EVENT_MODE_BOTH_EDGES);
palEnableLineEvent(encoders_pad_b[i], PAL_EVENT_MODE_BOTH_EDGES);
palSetLineCallback(encoders_pad_a[i], encoder_pad_cb, (void*)i);
palSetLineCallback(encoders_pad_b[i], encoder_pad_cb, (void*)i);
palSetLineCallback(encoders_pad_a[i], encoder_pad_cb, (void *)i);
palSetLineCallback(encoders_pad_b[i], encoder_pad_cb, (void *)i);
}
}
#endif
//__attribute__((weak)) bool raw_hid_receive_keychron(uint8_t *data, uint8_t length) { return true; }
#define PROTOCOL_VERSION 0x02
enum { kc_get_protocol_version = 0xA0, kc_get_firmware_version = 0xA1, kc_get_support_feature = 0xA2, kc_get_default_layer = 0xA3 };
enum {
FEATURE_DEFAULT_LAYER = 0x01 << 0,
FEATURE_BLUETOOTH = 0x01 << 1,
FEATURE_P2P4G = 0x01 << 2,
FEATURE_ANALOG_MATRIX = 0x01 << 3,
};
void get_support_feature(uint8_t *data) {
data[1] = FEATURE_DEFAULT_LAYER
#ifdef KC_BLUETOOTH_ENABLE
| FEATURE_BLUETOOTH
#endif
#ifdef LK_WIRELESS_ENABLE
| FEATURE_BLUETOOTH | FEATURE_P2P4G
#endif
#ifdef ANANLOG_MATRIX
| FEATURE_ANALOG_MATRIX
#endif
;
}
bool kc_raw_hid_rx(uint8_t *data, uint8_t length) {
// if (!raw_hid_receive_keychron(data, length))
// return false;
switch (data[0]) {
case kc_get_protocol_version:
data[1] = PROTOCOL_VERSION;
raw_hid_send(data, length);
break;
case kc_get_firmware_version: {
uint8_t i = 1;
data[i++] = 'v';
if ((DEVICE_VER & 0xF000) != 0) itoa((DEVICE_VER >> 12), (char *)&data[i++], 16);
itoa((DEVICE_VER >> 8) & 0xF, (char *)&data[i++], 16);
data[i++] = '.';
itoa((DEVICE_VER >> 4) & 0xF, (char *)&data[i++], 16);
data[i++] = '.';
itoa(DEVICE_VER & 0xF, (char *)&data[i++], 16);
data[i++] = ' ';
memcpy(&data[i], QMK_BUILDDATE, sizeof(QMK_BUILDDATE));
i += sizeof(QMK_BUILDDATE);
raw_hid_send(data, length);
} break;
case kc_get_support_feature:
get_support_feature(&data[1]);
raw_hid_send(data, length);
break;
case kc_get_default_layer:
data[1] = get_highest_layer(default_layer_state);
raw_hid_send(data, length);
break;
#ifdef ANANLOG_MATRIX
case 0xA9:
analog_matrix_rx(data, length);
break;
#endif
#ifdef LK_WIRELESS_ENABLE
case 0xAA:
lkbt51_dfu_rx(data, length);
break;
#endif
#ifdef FACTORY_TEST_ENABLE
case 0xAB:
factory_test_rx(data, length);
break;
#endif
default:
return false;
}
return true;
}
#if defined(VIA_ENABLE)
bool via_command_kb(uint8_t *data, uint8_t length) {
return kc_raw_hid_rx(data, length);
}
#else
void raw_hid_receive(uint8_t *data, uint8_t length) {
kc_raw_hid_rx(data, length);
}
#endif
+5 -1
View File
@@ -54,6 +54,10 @@ enum {
PROF1,
PROF2,
PROF3,
#endif
#ifdef LED_MATRIX_ENABLE
BL_SPI,
BL_SPD,
#endif
NEW_SAFE_RANGE,
};
@@ -83,10 +87,10 @@ typedef struct PACKED {
uint8_t keycode[3];
} key_combination_t;
void keychron_common_init(void);
bool process_record_keychron_common(uint16_t keycode, keyrecord_t *record);
void keychron_common_task(void);
#ifdef ENCODER_ENABLE
void encoder_cb_init(void);
#endif
+24 -3
View File
@@ -1,10 +1,31 @@
OPT_DEFS += -DFACTORY_TEST_ENABLE
OPT_DEFS += -DFACTORY_TEST_ENABLE -DAPDAPTIVE_NKRO_ENABLE
KEYCHRON_COMMON_DIR = common
SRC += \
$(KEYCHRON_COMMON_DIR)/keychron_task.c \
$(KEYCHRON_COMMON_DIR)/keychron_task.c \
$(KEYCHRON_COMMON_DIR)/keychron_common.c \
$(KEYCHRON_COMMON_DIR)/factory_test.c
$(KEYCHRON_COMMON_DIR)/keychron_raw_hid.c \
$(KEYCHRON_COMMON_DIR)/factory_test.c \
$(KEYCHRON_COMMON_DIR)/eeconfig_kb.c \
$(KEYCHRON_COMMON_DIR)/dfu_info.c
VPATH += $(TOP_DIR)/keyboards/keychron/$(KEYCHRON_COMMON_DIR)
INFO_RULES_MK = $(shell $(QMK_BIN) generate-rules-mk --quiet --escape --keyboard $(KEYBOARD) --output $(INTERMEDIATE_OUTPUT)/src/info_rules.mk)
include $(INFO_RULES_MK)
include $(TOP_DIR)/keyboards/keychron/$(KEYCHRON_COMMON_DIR)/language/language.mk
ifeq ($(strip $(DEBOUNCE_TYPE)), custom)
include $(TOP_DIR)/keyboards/keychron/$(KEYCHRON_COMMON_DIR)/debounce/debounce.mk
endif
ifeq ($(strip $(SNAP_CLICK_ENABLE)), yes)
include $(TOP_DIR)/keyboards/keychron/$(KEYCHRON_COMMON_DIR)/snap_click/snap_click.mk
endif
ifeq ($(strip $(KEYCHRON_RGB_ENABLE)), yes)
ifeq ($(strip $(RGB_MATRIX_ENABLE)), yes)
include $(TOP_DIR)/keyboards/keychron/$(KEYCHRON_COMMON_DIR)/rgb/rgb.mk
endif
endif
@@ -0,0 +1,203 @@
/* 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 "keychron_common.h"
#include "keychron_raw_hid.h"
#include "raw_hid.h"
#include "version.h"
#include "language.h"
#ifdef FACTORY_TEST_ENABLE
# include "factory_test.h"
#endif
#ifdef LK_WIRELESS_ENABLE
# include "lkbt51.h"
#endif
#ifdef ANANLOG_MATRIX
# include "analog_matrix.h"
#endif
#ifdef DYNAMIC_DEBOUNCE_ENABLE
# include "keychron_debounce.h"
#endif
#ifdef SNAP_CLICK_ENABLE
# include "snap_click.h"
#endif
#ifdef LK_WIRELESS_ENABLE
# include "wireless.h"
#endif
extern void dfu_info_rx(uint8_t *data, uint8_t length);
void get_support_feature(uint8_t *data) {
data[0] = 0;
data[1] = FEATURE_DEFAULT_LAYER
#ifdef KC_BLUETOOTH_ENABLE
| FEATURE_BLUETOOTH
#endif
#ifdef LK_WIRELESS_ENABLE
| FEATURE_BLUETOOTH | FEATURE_P24G
#endif
#ifdef ANANLOG_MATRIX
| FEATURE_ANALOG_MATRIX
#endif
#ifdef INFO_CHAGNED_NOTIFY_ENABLE
| FEATURE_INFO_CHAGNED_NOTIFY
#endif
#ifdef DYNAMIC_DEBOUNCE_ENABLE
| FEATURE_DYNAMIC_DEBOUNCE
#endif
#ifdef SNAP_CLICK_ENABLE
| FEATURE_SNAP_CLICK
#endif
#ifdef KEYCHRON_RGB_ENABLE
| FEATURE_KEYCHRON_RGB
#endif
;
}
void get_firmware_version(uint8_t *data) {
uint8_t i = 0;
data[i++] = 'v';
if ((DEVICE_VER & 0xF000) != 0) itoa((DEVICE_VER >> 12), (char *)&data[i++], 16);
itoa((DEVICE_VER >> 8) & 0xF, (char *)&data[i++], 16);
data[i++] = '.';
itoa((DEVICE_VER >> 4) & 0xF, (char *)&data[i++], 16);
data[i++] = '.';
itoa(DEVICE_VER & 0xF, (char *)&data[i++], 16);
data[i++] = ' ';
memcpy(&data[i], QMK_BUILDDATE, sizeof(QMK_BUILDDATE));
i += sizeof(QMK_BUILDDATE);
}
__attribute__((weak)) void kc_rgb_matrix_rx(uint8_t *data, uint8_t length) {}
bool kc_raw_hid_rx(uint8_t *data, uint8_t length) {
switch (data[0]) {
case KC_GET_PROTOCOL_VERSION:
data[1] = PROTOCOL_VERSION;
data[2] = 0;
data[3] = QMK_COMMAND_SET;
break;
case KC_GET_FIRMWARE_VERSION:
get_firmware_version(&data[1]);
break;
case KC_GET_SUPPORT_FEATURE:
get_support_feature(&data[1]);
break;
case KC_GET_DEFAULT_LAYER:
data[1] = get_highest_layer(default_layer_state);
break;
case 0xA7:
switch (data[1]) {
case MISC_GET_PROTOCOL_VER:
data[2] = 0;
data[3] = MISC_PROTOCOL_VERSION & 0xFF;
data[4] = (MISC_PROTOCOL_VERSION >> 8) & 0xFF;
data[5] = MISC_DFU_INFO | MISC_LANGUAGE
#ifdef DYNAMIC_DEBOUNCE_ENABLE
| MISC_DEBOUNCE
#endif
#ifdef SNAP_CLICK_ENABLE
| MISC_SNAP_CLICK
#endif
#ifdef LK_WIRELESS_ENABLE
| MISC_WIRELESS_LPM
#endif
#ifdef HSUSB_8K_ENABLE
| MISC_REPORT_REATE
#endif
;
break;
case DFU_INFO_GET:
dfu_info_rx(data, length);
break;
case LANGUAGE_GET ... LANGUAGE_SET:
language_rx(data, length);
break;
#if defined(DYNAMIC_DEBOUNCE_ENABLE)
case DEBOUNCE_GET ... DEBOUNCE_SET:
debounce_rx(data, length);
break;
#endif
#if defined(SNAP_CLICK_ENABLE)
case SNAP_CLICK_GET_INFO ... SNAP_CLICK_SAVE:
snap_click_rx(data, length);
break;
#endif
#if defined(LK_WIRELESS_ENABLE) && defined(EECONFIG_BASE_WIRELESS_CONFIG)
case WIRELESS_LPM_GET ... WIRELESS_LPM_SET:
wireless_raw_hid_rx(data, length);
break;
#endif
#if defined(HSUSB_8K_ENABLE)
case REPORT_RATE_GET ... REPORT_RATE_SET:
report_rate_hid_rx(data, length);
break;
#endif
default:
data[0] = 0xFF;
data[1] = 0;
break;
}
break;
#if defined(KEYCHRON_RGB_ENABLE)
case 0xA8:
kc_rgb_matrix_rx(data, length);
break;
#endif
#ifdef ANANLOG_MATRIX
case 0xA9:
analog_matrix_rx(data, length);
return true;
#endif
#ifdef LK_WIRELESS_ENABLE
case 0xAA:
lkbt51_dfu_rx(data, length);
return true;
#endif
#ifdef FACTORY_TEST_ENABLE
case 0xAB:
factory_test_rx(data, length);
return true;
#endif
default:
return false;
}
raw_hid_send(data, length);
return true;
}
#if defined(VIA_ENABLE)
bool via_command_kb(uint8_t *data, uint8_t length) {
return kc_raw_hid_rx(data, length);
}
#else
void raw_hid_receive(uint8_t *data, uint8_t length) {
kc_raw_hid_rx(data, length);
}
#endif
@@ -0,0 +1,65 @@
/* 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/>.
*/
#pragma once
#define PROTOCOL_VERSION 0x02
#define MISC_PROTOCOL_VERSION 0x0002
#define QMK_COMMAND_SET 2
enum {
KC_GET_PROTOCOL_VERSION = 0xA0,
KC_GET_FIRMWARE_VERSION = 0xA1,
KC_GET_SUPPORT_FEATURE = 0xA2,
KC_GET_DEFAULT_LAYER = 0xA3,
};
enum {
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_DYNAMIC_DEBOUNCE = 0x01U << 5,
FEATURE_SNAP_CLICK = 0x01U << 6,
FEATURE_KEYCHRON_RGB = 0x01U << 7,
};
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,
};
enum {
MISC_GET_PROTOCOL_VER = 0x01,
DFU_INFO_GET,
LANGUAGE_GET,
LANGUAGE_SET,
DEBOUNCE_GET, // 5
DEBOUNCE_SET,
SNAP_CLICK_GET_INFO,
SNAP_CLICK_GET,
SNAP_CLICK_SET,
SNAP_CLICK_SAVE, // A
WIRELESS_LPM_GET,
WIRELESS_LPM_SET,
REPORT_RATE_GET,
REPORT_RATE_SET,
};
+26 -2
View File
@@ -1,4 +1,4 @@
/* Copyright 2023 @ Keychron (https://www.keychron.com)
/* 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
@@ -21,6 +21,9 @@
#ifdef FACTORY_TEST_ENABLE
# include "factory_test.h"
#endif
#ifdef RETAIL_DEMO_ENABLE
# include "retail_demo.h"
#endif
__attribute__((weak)) bool process_record_keychron_kb(uint16_t keycode, keyrecord_t *record) {
return true;
@@ -34,10 +37,27 @@ bool process_record_keychron(uint16_t keycode, keyrecord_t *record) {
#ifdef FACTORY_TEST_ENABLE
if (!process_record_factory_test(keycode, record)) return false;
#endif
// extern bool process_record_keychron_kb(uint16_t keycode, keyrecord_t *record);
#ifdef SNAP_CLICK_ENABLE
extern bool process_record_snap_click(uint16_t keycode, keyrecord_t * record);
if (!process_record_snap_click(keycode, record)) return false;
#endif
if (!process_record_keychron_kb(keycode, record)) return false;
#if defined(KEYCHRON_RGB_ENABLE) && defined(EECONFIG_SIZE_CUSTOM_RGB)
# if defined(RETAIL_DEMO_ENABLE)
if (!process_record_retail_demo(keycode, record)) {
return false;
}
# endif
extern bool process_record_keychron_rgb(uint16_t keycode, keyrecord_t *record);
if (!process_record_keychron_rgb(keycode, record)) {
return false;
}
#endif
return true;
}
@@ -79,6 +99,10 @@ void keychron_task(void) {
#ifdef FACTORY_TEST_ENABLE
factory_test_task();
#endif
#if defined(RETAIL_DEMO_ENABLE) && defined(KEYCHRON_RGB_ENABLE) && defined(EECONFIG_SIZE_CUSTOM_RGB)
retail_demo_task();
#endif
keychron_common_task();
keychron_task_kb();
@@ -0,0 +1,20 @@
/* 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/>.
*/
#pragma once
#define EECONFIG_SIZE_LANGUAGE 1
@@ -0,0 +1,60 @@
/* 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 <string.h>
#include "eeconfig_kb.h"
#include "raw_hid.h"
#include "eeconfig.h"
#include "matrix.h"
#include "quantum.h"
#include "keychron_raw_hid.h"
static uint8_t lang;
static bool language_get(uint8_t *data) {
eeprom_read_block(&lang, (uint8_t *)(EECONFIG_BASE_LANGUAGE), sizeof(lang));
data[1] = lang;
return true;
}
static bool language_set(uint8_t *data) {
lang = data[0];
eeprom_update_block(&lang, (uint8_t *)(EECONFIG_BASE_LANGUAGE), sizeof(lang));
return true;
}
void language_rx(uint8_t *data, uint8_t length) {
uint8_t cmd = data[1];
bool success = true;
switch (cmd) {
case LANGUAGE_GET:
success = language_get(&data[2]);
break;
case LANGUAGE_SET:
success = language_set(&data[2]);
break;
default:
data[0] = 0xFF;
break;
}
data[2] = success ? 0 : 1;
}
@@ -0,0 +1,21 @@
/* 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/>.
*/
#pragma once
void language_config_reset(void);
void language_rx(uint8_t *data, uint8_t length);
@@ -0,0 +1,7 @@
LANGUAGE_DIR = common/language
SRC += \
$(LANGUAGE_DIR)/language.c \
VPATH += $(TOP_DIR)/keyboards/keychron/$(LANGUAGE_DIR)
OPT_DEFS += -DLANGUAGE_ENABLE
@@ -0,0 +1,39 @@
/* 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/>.
*/
#pragma once
#include "rgb_matrix_kb_config.h"
#define OS_INDICATOR_CONFIG_SIZE 4 // sizeof(os_indicator_config_t)
//#define OS_INDICATOR_CONFIG_OFFSET (PER_KEY_RGB_LED_COLOR_LIST_SIZE + RGB_MATRIX_LED_COUNT)
#define RETAIL_DEMO_SIZE 1 // sizeof(retail_demo_enable)
#define PER_KEY_RGB_TYPE_SIZE 1
#define PER_KEY_RGB_LED_COLOR_LIST_SIZE (RGB_MATRIX_LED_COUNT * 3)
#define MIX_RGB_LAYER_FLAG_SIZE RGB_MATRIX_LED_COUNT
#define EFFECT_CONFIG_SIZE 8 // sizeof(effect_config_t)
#define EFFECT_LIST_SIZE (EFFECT_LAYERS * EFFECTS_PER_LAYER * EFFECT_CONFIG_SIZE)
#define EECONFIG_SIZE_CUSTOM_RGB ( \
OS_INDICATOR_CONFIG_SIZE \
+ RETAIL_DEMO_SIZE \
+ PER_KEY_RGB_TYPE_SIZE \
+ PER_KEY_RGB_LED_COLOR_LIST_SIZE \
+ MIX_RGB_LAYER_FLAG_SIZE \
+ EFFECT_LIST_SIZE)
@@ -0,0 +1,494 @@
/* 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], &regions[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(&regions[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
@@ -0,0 +1,59 @@
/* 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/>.
*/
#pragma once
#include "color.h"
enum {
PER_KEY_RGB_SOLID,
PER_KEY_RGB_BREATHING,
PER_KEY_RGB_REATIVE_SIMPLE,
PER_KEY_RGB_REATIVE_MULTI_WIDE,
PER_KEY_RGB_REATIVE_SPLASH,
PER_KEY_RGB_MAX,
};
typedef struct PACKED {
uint8_t effect;
uint8_t hue;
uint8_t sat;
uint8_t speed;
uint32_t time;
} effect_config_t;
typedef union {
uint8_t raw;
struct {
bool num_lock : 1;
bool caps_lock : 1;
bool scroll_lock : 1;
bool compose : 1;
bool kana : 1;
uint8_t reserved : 3;
};
} os_led_t;
// TODO:
// typedef struct PACKED HSV2 {
// uint8_t h;
// uint8_t s;
// uint8_t v;
// } HSV2;
typedef struct PACKED {
os_led_t disable;
HSV hsv;
} os_indicator_config_t;
+191
View File
@@ -0,0 +1,191 @@
/* 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/>.
*/
#if defined(KEYCHRON_RGB_ENABLE) && defined(EECONFIG_SIZE_CUSTOM_RGB)
#include "quantum.h"
#include "rgb_matrix.h"
#include "keychron_rgb_type.h"
#define RGB_MATRIX_EFFECT(name, ...) \
extern bool name(effect_params_t *params);
#include "rgb_matrix_effects.inc"
#include "rgb_matrix_kb.inc"
#undef RGB_MATRIX_EFFECT
// PER_KEY_RGB data
extern uint8_t per_key_rgb_type;
// MIXED_RGB data
extern uint8_t rgb_regions[RGB_MATRIX_LED_COUNT];
uint8_t regions[RGB_MATRIX_LED_COUNT] = {0}; //
effect_config_t effect_list[EFFECT_LAYERS][EFFECTS_PER_LAYER];
uint8_t layer_effect_count[EFFECT_LAYERS] = {0};
uint8_t layer_effect_index[EFFECT_LAYERS] = {0};
uint32_t layer_effect_timer[EFFECT_LAYERS] = {0};
// Typing heatmap
uint8_t typingHeatmap = 0;
static bool multiple_rgb_effect_runner(effect_params_t *params);
void mixed_rgb_reset(void) {
typingHeatmap = 0;
for (uint8_t i=0; i<EFFECT_LAYERS; i++) {
layer_effect_index[i] = 0;
layer_effect_timer[i] = timer_read32();
if (effect_list[i][0].effect == RGB_MATRIX_TYPING_HEATMAP) typingHeatmap |= 0x01 << i;
}
}
void update_mixed_rgb_effect_count(void) {
for (int8_t layer=0; layer<EFFECT_LAYERS; layer++) {
layer_effect_count[layer] = 0;
for (uint8_t i=0; i<EFFECTS_PER_LAYER; i++) {
if (effect_list[layer][i].effect != 0) ++layer_effect_count[layer];
}
}
mixed_rgb_reset();
}
bool mixed_rgb(effect_params_t *params) {
bool ret;
extern uint8_t rgb_regions[RGB_MATRIX_LED_COUNT];
if (params->init) {
memcpy(rgb_regions, regions, RGB_MATRIX_LED_COUNT);
memset(layer_effect_index, 0, sizeof(layer_effect_index));
mixed_rgb_reset();
}
for (int8_t i=EFFECT_LAYERS-1; i>=0; i--) {
params->region = i;
ret = multiple_rgb_effect_runner(params);
}
return ret;
}
#define TRANSITION_TIME 1000
bool multiple_rgb_effect_runner(effect_params_t *params) {
HSV hsv= rgb_matrix_get_hsv();
uint8_t backup_value = hsv.v;
bool transation = false;
bool rendering = false;
uint8_t layer = params->region;
uint8_t effect_index = layer_effect_index[layer];
if (effect_list[layer][effect_index].effect == RGB_MATRIX_TYPING_HEATMAP)
typingHeatmap |= 0x01 << layer;
else
typingHeatmap &= ~(0x01 << layer);
uint8_t last_effect = effect_list[layer][layer_effect_index[layer]].effect;
if (layer_effect_count[layer] > 1) {
if (timer_elapsed32(layer_effect_timer[layer]) > effect_list[layer][effect_index].time) {
layer_effect_timer[layer] = timer_read32();
if (++layer_effect_index[layer] >= EFFECTS_PER_LAYER) layer_effect_index[layer] = 0;
effect_index = layer_effect_index[layer];
if (effect_list[layer][effect_index].time == 0) return true; //
}
else if (timer_elapsed32(layer_effect_timer[layer]) > effect_list[layer][effect_index].time - TRANSITION_TIME)
{
hsv.v = backup_value*(effect_list[layer][effect_index].time - timer_elapsed32(layer_effect_timer[layer]))/TRANSITION_TIME;
transation = true;
}
if (timer_elapsed32(layer_effect_timer[layer]) < TRANSITION_TIME)
{
hsv.v = backup_value*timer_elapsed32(layer_effect_timer[layer])/TRANSITION_TIME;
transation = true;
}
} else if (layer_effect_count[layer] == 1 && effect_list[layer][effect_index].effect == 0) {
for (uint8_t i=0; i<EFFECTS_PER_LAYER; i++) {
if (effect_list[layer][i].effect != 0) {
effect_index = layer_effect_index[params->region] = i;
break;
}
}
}
uint8_t effect = effect_list[layer][effect_index].effect;
if (effect == 0) ++layer_effect_index[layer]; // Skip effect 0
if (layer_effect_index[layer] >= EFFECTS_PER_LAYER) layer_effect_index[layer] = 0;
effect = effect_list[layer][effect_index].effect;
hsv.h = effect_list[layer][effect_index].hue;
hsv.s = effect_list[layer][effect_index].sat;
rgb_matrix_sethsv_noeeprom(hsv.h, hsv.s, hsv.v);
rgb_matrix_set_speed_noeeprom(effect_list[layer][effect_index].speed);
params->init = last_effect != effect;
// each effect can opt to do calculations
// and/or request PWM buffer updates.
switch (effect) {
// ---------------------------------------------
// -----Begin rgb effect switch case macros-----
#define RGB_MATRIX_EFFECT(name, ...) \
case RGB_MATRIX_##name: \
rendering = name(params); \
break;
#include "rgb_matrix_effects.inc"
#undef RGB_MATRIX_EFFECT
#if defined(RGB_MATRIX_CUSTOM_KB) || defined(RGB_MATRIX_CUSTOM_USER)
# define RGB_MATRIX_EFFECT(name, ...) \
case RGB_MATRIX_CUSTOM_##name: \
rendering = name(params); \
break;
# ifdef RGB_MATRIX_CUSTOM_KB
# include "rgb_matrix_kb.inc"
# endif
# undef RGB_MATRIX_EFFECT
#endif
// -----End rgb effect switch case macros-------
// ---------------------------------------------
}
if (transation) {
rgb_matrix_sethsv_noeeprom(hsv.h, hsv.s, backup_value);
}
return rendering;
}
void process_rgb_matrix_kb(uint8_t row, uint8_t col, bool pressed) {
if (pressed)
{
if (rgb_matrix_config.mode == RGB_MATRIX_CUSTOM_MIXED_RGB) {
extern void process_rgb_matrix_typing_heatmap(uint8_t row, uint8_t col);
if (typingHeatmap) process_rgb_matrix_typing_heatmap(row, col);
}
}
}
#endif
+160
View File
@@ -0,0 +1,160 @@
/* 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 "rgb_matrix.h"
#include "keychron_rgb_type.h"
#include <math.h>
#include <lib/lib8tion/lib8tion.h>
#if defined(KEYCHRON_RGB_ENABLE)
// PER_KEY_RGB data
uint8_t per_key_rgb_type;
HSV per_key_led[RGB_MATRIX_LED_COUNT] = {0};
bool per_key_rgb_solid(effect_params_t *params) {
RGB_MATRIX_USE_LIMITS(led_min, led_max);
HSV hsv;
for (uint8_t i = led_min; i < led_max; i++) {
hsv = per_key_led[i];
hsv.v = rgb_matrix_config.hsv.v;
RGB rgb = hsv_to_rgb(hsv);
rgb_matrix_region_set_color(params->region, i, rgb.r, rgb.g, rgb.b);
}
return rgb_matrix_check_finished_leds(led_max);
}
bool per_key_rgb_breahting(effect_params_t *params) {
RGB_MATRIX_USE_LIMITS(led_min, led_max);
HSV hsv;
uint16_t time = scale16by8(g_rgb_timer, rgb_matrix_config.speed / 8);
for (uint8_t i = led_min; i < led_max; i++) {
hsv = per_key_led[i];
hsv.v = scale8(abs8(sin8(time) - 128) * 2, rgb_matrix_config.hsv.v);
RGB rgb = hsv_to_rgb(hsv);
RGB_MATRIX_TEST_LED_FLAGS();
rgb_matrix_region_set_color(params->region, i, rgb.r, rgb.g, rgb.b);
}
return rgb_matrix_check_finished_leds(led_max);
}
bool per_key_rgb_reactive_simple(effect_params_t *params) {
RGB_MATRIX_USE_LIMITS(led_min, led_max);
uint16_t max_tick = 65535 / qadd8(rgb_matrix_config.speed, 1);
for (uint8_t i = led_min; i < led_max; i++) {
RGB_MATRIX_TEST_LED_FLAGS();
uint16_t tick = max_tick;
// Reverse search to find most recent key hit
for (int8_t j = g_last_hit_tracker.count - 1; j >= 0; j--) {
if (g_last_hit_tracker.index[j] == i && g_last_hit_tracker.tick[j] < tick) {
tick = g_last_hit_tracker.tick[j];
break;
}
}
uint16_t offset = scale16by8(tick, qadd8(rgb_matrix_config.speed, 1));
HSV hsv = per_key_led[i];
hsv.v = scale8(255 - offset, rgb_matrix_config.hsv.v);
if (per_key_led[i].v < hsv.v)
hsv.v = per_key_led[i].v;
RGB rgb = hsv_to_rgb(hsv);
rgb_matrix_region_set_color(params->region, i, rgb.r, rgb.g, rgb.b);
}
return rgb_matrix_check_finished_leds(led_max);
}
typedef HSV (*reactive_splash_f)(HSV hsv, int16_t dx, int16_t dy, uint8_t dist, uint16_t tick);
bool per_key_rgb_effect_runner_reactive_splash(uint8_t start, effect_params_t* params, reactive_splash_f effect_func) {
RGB_MATRIX_USE_LIMITS(led_min, led_max);
uint8_t count = g_last_hit_tracker.count;
for (uint8_t i = led_min; i < led_max; i++) {
RGB_MATRIX_TEST_LED_FLAGS();
HSV hsv = rgb_matrix_config.hsv;
hsv.v = 0;
for (uint8_t j = start; j < count; j++) {
int16_t dx = g_led_config.point[i].x - g_last_hit_tracker.x[j];
int16_t dy = g_led_config.point[i].y - g_last_hit_tracker.y[j];
uint8_t dist = sqrt16(dx * dx + dy * dy);
uint16_t tick = scale16by8(g_last_hit_tracker.tick[j], qadd8(rgb_matrix_config.speed, 1));
hsv = effect_func(hsv, dx, dy, dist, tick);
}
hsv.h = per_key_led[i].h;
hsv.s = per_key_led[i].s;
hsv.v = scale8(hsv.v, rgb_matrix_config.hsv.v);
if (per_key_led[i].v < hsv.v)
hsv.v = per_key_led[i].v;
RGB rgb = hsv_to_rgb(hsv);
rgb_matrix_region_set_color(params->region, i, rgb.r, rgb.g, rgb.b);
}
return rgb_matrix_check_finished_leds(led_max);
}
static HSV solid_reactive_wide_math(HSV hsv, int16_t dx, int16_t dy, uint8_t dist, uint16_t tick) {
uint16_t effect = tick + dist * 5;
if (effect > 255) effect = 255;
# ifdef RGB_MATRIX_SOLID_REACTIVE_GRADIENT_MODE
hsv.h = scale16by8(g_rgb_timer, qadd8(rgb_matrix_config.speed, 8) >> 4);
# endif
hsv.v = qadd8(hsv.v, 255 - effect);
return hsv;
}
bool per_key_rgb_reactive_multi_wide(effect_params_t *params) {
return per_key_rgb_effect_runner_reactive_splash(0, params, &solid_reactive_wide_math);
}
static HSV SPLASH_math(HSV hsv, int16_t dx, int16_t dy, uint8_t dist, uint16_t tick) {
uint16_t effect = tick - dist;
if (effect > 255) effect = 255;
hsv.h += effect;
hsv.v = qadd8(hsv.v, 255 - effect);
return hsv;
}
bool per_key_rgb_reactive_splash(effect_params_t *params) {
return per_key_rgb_effect_runner_reactive_splash(qsub8(g_last_hit_tracker.count, 1), params, &SPLASH_math);
}
bool per_key_rgb(effect_params_t *params) {
switch (per_key_rgb_type) {
case PER_KEY_RGB_BREATHING:
return per_key_rgb_breahting(params);
case PER_KEY_RGB_REATIVE_SIMPLE:
return per_key_rgb_reactive_simple(params);
case PER_KEY_RGB_REATIVE_MULTI_WIDE:
return per_key_rgb_reactive_multi_wide(params);
case PER_KEY_RGB_REATIVE_SPLASH:
return per_key_rgb_reactive_splash(params);
default:
return per_key_rgb_solid(params);
}
}
#endif
+185
View File
@@ -0,0 +1,185 @@
/* 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 <string.h>
#include "eeconfig_kb.h"
#include "retail_demo.h"
#include "eeconfig.h"
#include "matrix.h"
#include "quantum.h"
#ifdef LK_WIRELESS_ENABLE
# include "transport.h"
#endif
#if defined(RETAIL_DEMO_ENABLE) && defined(KEYCHRON_RGB_ENABLE) && defined(EECONFIG_SIZE_CUSTOM_RGB)
# ifndef RETAIL_DEMO_KEY_1
# ifdef RGB_MATRIX_ENABLE
# define RETAIL_DEMO_KEY_1 RGB_HUI
# else
# define RETAIL_DEMO_KEY_1 KC_D
# endif
# endif
# ifndef RETAIL_DEMO_KEY_2
# ifdef RGB_MATRIX_ENABLE
# define RETAIL_DEMO_KEY_2 RGB_HUD
# else
# define RETAIL_DEMO_KEY_2 KC_E
# endif
# endif
# ifndef EFFECT_DURATION
# define EFFECT_DURATION 10000
# endif
enum {
KEY_PRESS_FN = 0x01 << 0,
KEY_PRESS_D = 0x01 << 1,
KEY_PRESS_E = 0x01 << 2,
KEY_PRESS_RETAIL_DEMO = KEY_PRESS_FN | KEY_PRESS_D | KEY_PRESS_E,
};
uint8_t retail_demo_enable = 0;
static uint8_t retail_demo_combo = 0;
static uint32_t retail_demo_timer = 0;
extern void rgb_save_retail_demo(void);
bool process_record_retail_demo(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case MO(0)... MO(15):
if (record->event.pressed)
retail_demo_combo |= KEY_PRESS_FN;
else
retail_demo_combo &= ~KEY_PRESS_FN;
break;
case RETAIL_DEMO_KEY_1:
if (record->event.pressed) {
retail_demo_combo |= KEY_PRESS_D;
if (retail_demo_combo == KEY_PRESS_RETAIL_DEMO) retail_demo_timer = timer_read32();
} else {
retail_demo_combo &= ~KEY_PRESS_D;
retail_demo_timer = 0;
}
break;
case RETAIL_DEMO_KEY_2:
if (record->event.pressed) {
retail_demo_combo |= KEY_PRESS_E;
if (retail_demo_combo == KEY_PRESS_RETAIL_DEMO) retail_demo_timer = timer_read32();
} else {
retail_demo_combo &= ~KEY_PRESS_E;
retail_demo_timer = 0;
}
break;
}
if (retail_demo_enable && keycode >= RGB_TOG && keycode <= RGB_SPD) return false;
return true;
}
void retail_demo_start(void) {
extern bool mixed_rgb_set_regions(uint8_t * data);
extern bool mixed_rgb_set_effect_list(uint8_t * data);
uint8_t index = 0;
uint8_t this_count = 28;
uint8_t data[31] = {0};
// Set all LED to region 0
while (index < RGB_MATRIX_LED_COUNT - 1) {
memset(data, 0, 31);
if ((index + this_count) >= RGB_MATRIX_LED_COUNT)
this_count = RGB_MATRIX_LED_COUNT - 1 - index;
else
this_count = 28;
data[0] = index;
data[1] = this_count;
mixed_rgb_set_regions(data);
index += this_count;
}
uint8_t effect_list[5] = {4, 7, 8, 11, 14};
// Set effect list
for (uint8_t i = 0; i < 5; i++) {
data[0] = 0; // regsion
data[1] = i; // start
data[2] = 1; // count
data[3] = effect_list[i]; // effect
data[4] = 0; // hue
data[5] = 255; // sat
data[6] = 127; // speed;
data[7] = EFFECT_DURATION & 0xFF;
data[8] = (EFFECT_DURATION >> 8) & 0xFF;
data[9] = (EFFECT_DURATION >> 16) & 0xFF;
data[10] = (EFFECT_DURATION >> 24) & 0xFF;
mixed_rgb_set_effect_list(data);
}
HSV hsv = rgb_matrix_get_hsv();
hsv.v = hsv.s = UINT8_MAX;
rgb_matrix_sethsv_noeeprom(hsv.h, hsv.s, hsv.v);
rgb_matrix_set_speed_noeeprom(RGB_MATRIX_DEFAULT_SPD);
rgb_matrix_mode_noeeprom(RGB_MATRIX_CUSTOM_MIXED_RGB);
}
void retail_demo_stop(void) {
retail_demo_enable = false;
rgb_save_retail_demo();
eeprom_read_block(&rgb_matrix_config, EECONFIG_RGB_MATRIX, sizeof(rgb_matrix_config));
}
static inline void retail_demo_timer_check(void) {
if (timer_elapsed32(retail_demo_timer) > 5000) {
retail_demo_timer = 0;
if (retail_demo_combo == KEY_PRESS_RETAIL_DEMO) {
retail_demo_combo = 0;
retail_demo_enable = !retail_demo_enable;
if (retail_demo_enable) {
# ifdef LK_WIRELESS_ENABLE
// Retail demo is allowed only in wireless mode
if (get_transport() != TRANSPORT_USB) {
retail_demo_enable = false;
return;
}
# endif
} else {
eeprom_read_block(&rgb_matrix_config, EECONFIG_RGB_MATRIX, sizeof(rgb_matrix_config));
}
rgb_save_retail_demo();
if (!retail_demo_enable) {
extern void eeconfig_init_custom_rgb(void);
eeconfig_init_custom_rgb();
}
}
}
}
void retail_demo_task(void) {
if (retail_demo_timer) retail_demo_timer_check();
if (retail_demo_enable && rgb_matrix_get_mode() != RGB_MATRIX_CUSTOM_MIXED_RGB) retail_demo_start();
}
#endif
@@ -0,0 +1,25 @@
/* 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/>.
*/
#pragma once
#include "stdint.h"
#include "action.h"
void retail_demo_start(void);
void retail_demo_stop(void);
bool process_record_retail_demo(uint16_t keycode, keyrecord_t * record);
void retail_demo_task(void);
+14
View File
@@ -0,0 +1,14 @@
OPT_DEFS += -DKEYCHRON_RGB_ENABLE -DRETAIL_DEMO_ENABLE
RGB_MATRIX_CUSTOM_KB = yes
RGB_MATRIX_DIR = common/rgb
SRC += \
$(RGB_MATRIX_DIR)/keychron_rgb.c \
$(RGB_MATRIX_DIR)/per_key_rgb.c \
$(RGB_MATRIX_DIR)/mixed_rgb.c \
$(RGB_MATRIX_DIR)/retail_demo.c
VPATH += $(TOP_DIR)/keyboards/keychron/$(RGB_MATRIX_DIR)
@@ -0,0 +1,39 @@
/* 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 "rgb_matrix_kb_config.h"
#if defined(KEYCHRON_RGB_ENABLE) && defined(EECONFIG_SIZE_CUSTOM_RGB)
//extern bool MIXED_RGB(effect_params_t *params);
RGB_MATRIX_EFFECT(PER_KEY_RGB)
RGB_MATRIX_EFFECT(MIXED_RGB)
# ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS
bool PER_KEY_RGB(effect_params_t *params) {
extern bool per_key_rgb(effect_params_t *params);
return per_key_rgb(params);
}
bool MIXED_RGB(effect_params_t *params) {
extern bool mixed_rgb(effect_params_t *params);
return mixed_rgb(params);
}
#endif
#endif
@@ -0,0 +1,26 @@
/* 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/>.
*/
#pragma once
#include "config.h"
#ifndef EFFECT_LAYERS
#define EFFECT_LAYERS 2
#endif
#ifndef EFFECTS_PER_LAYER
#define EFFECTS_PER_LAYER 5
#endif
@@ -0,0 +1,26 @@
/* 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/>.
*/
#pragma once
#ifndef SNAP_CLICK_COUNT
# define SNAP_CLICK_COUNT 20
#endif
#define SIZE_OF_SNAP_CLICK_CONFIG_T 3
#define EECONFIG_SIZE_SNAP_CLICK (SNAP_CLICK_COUNT * SIZE_OF_SNAP_CLICK_CONFIG_T)
@@ -0,0 +1,201 @@
/* 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 <string.h>
#include "eeconfig_kb.h"
#include "snap_click.h"
#include "raw_hid.h"
#include "eeconfig.h"
#include "matrix.h"
#include "quantum.h"
#include "keychron_raw_hid.h"
#if defined(SNAP_CLICK_ENABLE) &&defined(EECONFIG_SIZE_SNAP_CLICK)
enum {
SNAP_CLICK_TYPE_NONE = 0,
SNAP_CLICK_TYPE_REGULAR,
SNAP_CLICK_TYPE_LAST_INPUT,
SNAP_CLICK_TYPE_FIRST_KEY,
SNAP_CLICK_TYPE_SECOND_KEY,
SNAP_CLICK_TYPE_NEUTRAL,
SNAP_CLICK_TYPE_MAX,
};
#define SC_MASK_BOTH_KEYS_PRESSED 3
snap_click_config_t snap_click_pair[SNAP_CLICK_COUNT];
snap_click_state_t snap_click_state[SNAP_CLICK_COUNT];
void snap_click_config_reset(void) {
memset(snap_click_pair, 0, sizeof(snap_click_pair));
eeprom_update_block(snap_click_pair, (uint8_t *)(EECONFIG_BASE_SNAP_CLICK), sizeof(snap_click_pair));
}
void snap_click_init(void) {
eeprom_read_block(snap_click_pair, (uint8_t *)(EECONFIG_BASE_SNAP_CLICK), sizeof(snap_click_pair));
memset(snap_click_state, 0, sizeof(snap_click_state));
}
bool process_record_snap_click(uint16_t keycode, keyrecord_t * record)
{
for (uint8_t i=0; i<SNAP_CLICK_COUNT; i++)
{
snap_click_config_t *p = &snap_click_pair[i];
if (p->type && (keycode == p->key[0] || keycode == p->key[1]))
{
snap_click_state_t *pState = &snap_click_state[i];
uint8_t index = keycode == p->key[1]; // 0 or 1 of key pair
if (record->event.pressed) {
uint8_t state = 0x01 << index;
if (pState->state == 0) {
// Single key down
pState->state_keys = pState->last_single_key = state;
} else if ((state & pState->state_keys) == 0) { // TODO: do we need checking?
// Both keys are pressed
pState->state_keys = SC_MASK_BOTH_KEYS_PRESSED;
switch (p->type) {
case SNAP_CLICK_TYPE_REGULAR:
case SNAP_CLICK_TYPE_LAST_INPUT:
unregister_code(p->key[1-index]);
register_code(p->key[index]);
break;
case SNAP_CLICK_TYPE_FIRST_KEY:
unregister_code(p->key[1]);
register_code(p->key[0]);
break;
case SNAP_CLICK_TYPE_SECOND_KEY:
unregister_code(p->key[0]);
register_code(p->key[1]);
break;
case SNAP_CLICK_TYPE_NEUTRAL:
unregister_code(p->key[1-index]);
break;
}
return false;
}
} else {
if (pState->state_keys == SC_MASK_BOTH_KEYS_PRESSED) {
// Snap click active
uint8_t state = 0x01 << (1-index);
pState->state_keys = pState->last_single_key = state;
switch (p->type) {
case SNAP_CLICK_TYPE_REGULAR:
unregister_code(p->key[index]);
break;
case SNAP_CLICK_TYPE_LAST_INPUT:
case SNAP_CLICK_TYPE_FIRST_KEY:
case SNAP_CLICK_TYPE_SECOND_KEY:
if (is_key_pressed(p->key[index])) {
unregister_code(p->key[index]);
}
if (!is_key_pressed(p->key[1-index])) {
register_code(p->key[1-index]);
}
break;
case SNAP_CLICK_TYPE_NEUTRAL:
register_code(p->key[1-index]);
break;
}
return false;
} else {
pState->state = 0;
}
}
}
}
return true;
}
static bool snap_click_get_info(uint8_t *data) {
data[1] = SNAP_CLICK_COUNT;
return true;
}
static bool snap_click_get(uint8_t *data) {
uint8_t start = data[0];
uint8_t count = data[1];
if (count > 9 || start + count > SNAP_CLICK_COUNT) return false;
memcpy(&data[1], &snap_click_pair[start], count * sizeof(snap_click_config_t));
return true;
}
static bool snap_click_set(uint8_t *data) {
uint8_t start = data[0];
uint8_t count = data[1];
if (count > 9 || start + count > SNAP_CLICK_COUNT) return false;
for (uint8_t i=0; i<count; i++) {
uint8_t offset = 2+sizeof(snap_click_config_t)*i;
uint8_t type = data[offset];
uint8_t keycode1 = data[offset+1];
uint8_t keycode2 = data[offset+2];
if (type >= SNAP_CLICK_TYPE_MAX)
return false;
if (type != 0 && (keycode1 == 0 || keycode2 == 0))
return false;
}
memcpy(&snap_click_pair[start], &data[2], count * sizeof(snap_click_config_t));
return true;
}
static bool snap_click_save(uint8_t *data) {
eeprom_update_block(snap_click_pair, (uint8_t *)(EECONFIG_BASE_SNAP_CLICK), sizeof(snap_click_pair));
return true;
}
void snap_click_rx(uint8_t *data, uint8_t length) {
uint8_t cmd = data[1];
bool success = true;
switch (cmd) {
case SNAP_CLICK_GET_INFO:
success = snap_click_get_info(&data[2]);
break;
case SNAP_CLICK_GET:
success = snap_click_get(&data[2]);
break;
case SNAP_CLICK_SET:
success = snap_click_set(&data[2]);
break;
case SNAP_CLICK_SAVE:
success = snap_click_save(&data[2]);
break;
default:
data[0] = 0xFF;
break;
}
data[2] = success ? 0 : 1;
}
#endif
@@ -0,0 +1,43 @@
/* 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/>.
*/
#pragma once
typedef struct __attribute__((__packed__)) {
uint8_t type;
uint8_t key[2];
} snap_click_config_t;
// size = 3 bytes
typedef union {
uint8_t state;
struct {
uint8_t state_key_1:1;
uint8_t state_key_2:1;
uint8_t last_single_key_1:1;
uint8_t last_single_key_2:1;
uint8_t reserved:4;
};
struct {
uint8_t state_keys:2;
uint8_t last_single_key:2;
uint8_t reserved2:4;
};
} snap_click_state_t;
void snap_click_config_reset(void);
void snap_click_rx(uint8_t *data, uint8_t length);
@@ -0,0 +1,7 @@
SNAP_CLICK_DIR = common/snap_click
SRC += \
$(SNAP_CLICK_DIR)/snap_click.c \
VPATH += $(TOP_DIR)/keyboards/keychron/$(SNAP_CLICK_DIR)
OPT_DEFS += -DSNAP_CLICK_ENABLE
@@ -1,4 +1,20 @@
/* 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/>.
*/
#include "quantum.h"
#include "wireless.h"
#include "indicator.h"
@@ -1,4 +1,4 @@
/* Copyright 2022 @ lokher (https://www.keychron.com)
/* Copyright 2023~2025 @ lokher (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
@@ -0,0 +1,20 @@
/* 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/>.
*/
#pragma once
#define EECONFIG_SIZE_WIRELESS_CONFIG 4 //sizeof(backlit_disable_time) + sizeof (connected_idle_time)
+14 -7
View File
@@ -1,4 +1,4 @@
/* Copyright 2023 @ lokher (https://www.keychron.com)
/* Copyright 2023~2025 @ lokher (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
@@ -60,6 +60,8 @@ enum {
BACKLIGHT_ON_UNCONNECTED = 0x02,
};
extern uint16_t backlit_disable_time;
static indicator_config_t pairing_config = INDICATOR_CONFIG_PARING;
static indicator_config_t connected_config = INDICATOR_CONFIG_CONNECTD;
static indicator_config_t reconnecting_config = INDICATOR_CONFIG_RECONNECTING;
@@ -201,12 +203,13 @@ inline void indicator_disable(void) {
LED_DRIVER_DISABLE_NOEEPROM();
}
void indicator_set_backlit_timeout(uint32_t time) {
LED_DRIVER_DISABLE_TIMEOUT_SET(time);
void indicator_reset_backlit_time(void) {
LED_DRIVER_DISABLE_TIME_RESET();
}
static inline void indicator_reset_backlit_time(void) {
LED_DRIVER_DISABLE_TIME_RESET();
void indicator_set_backlit_timeout(uint32_t time) {
LED_DRIVER_DISABLE_TIMEOUT_SET(time);
indicator_reset_backlit_time();
}
bool indicator_is_enabled(void) {
@@ -443,7 +446,7 @@ void indicator_set(wt_state_t state, uint8_t host_index) {
indicator_timer_cb((void *)&indicator_config.type);
}
#if defined(LED_MATRIX_ENABLE) || defined(RGB_MATRIX_ENABLE)
indicator_set_backlit_timeout(DECIDE_TIME(CONNECTED_BACKLIGHT_DISABLE_TIMEOUT * 1000, indicator_config.duration));
indicator_set_backlit_timeout(DECIDE_TIME(backlit_disable_time * 1000, indicator_config.duration));
#endif
break;
@@ -541,6 +544,9 @@ void indicator_battery_low_enable(bool enable) {
} else {
rtc_time = 0;
bat_low_ind_state = 0;
# if defined(BAT_LOW_LED_PIN)
writePin(BAT_LOW_LED_PIN, !BAT_LOW_LED_PIN_ON_STATE);
# endif
# if defined(SPACE_KEY_LOW_BAT_IND)
indicator_eeconfig_reload();
if (!LED_DRIVER_IS_ENABLED()) indicator_disable();
@@ -552,7 +558,8 @@ void indicator_battery_low_enable(bool enable) {
void indicator_battery_low(void) {
#if defined(BAT_LOW_LED_PIN) || defined(SPACE_KEY_LOW_BAT_IND)
if (bat_low_ind_state) {
if ((bat_low_ind_state & 0x0F) <= (LOW_BAT_LED_BLINK_TIMES) && timer_elapsed32(bat_low_backlit_indicator) > (LOW_BAT_LED_BLINK_PERIOD)) {
if ((bat_low_ind_state & 0x0F) <= (LOW_BAT_LED_BLINK_TIMES) &&
timer_elapsed32(bat_low_backlit_indicator) > (LOW_BAT_LED_BLINK_PERIOD)) {
if (bat_low_ind_state & 0x80) {
bat_low_ind_state &= 0x7F;
bat_low_ind_state++;
@@ -1,4 +1,4 @@
/* Copyright 2023 @ lokher (https://www.keychron.com)
/* Copyright 2023~2025 @ lokher (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
@@ -101,7 +101,7 @@ typedef struct {
void indicator_init(void);
void indicator_set(wt_state_t state, uint8_t host_index);
void indicator_set_backlit_timeout(uint32_t time);
void indicator_backlight_timer_reset(bool enable);
void indicator_reset_backlit_time(void);
bool indicator_hook_key(uint16_t keycode);
void indicator_enable(void);
void indicator_disable(void);
@@ -1,4 +1,4 @@
/* Copyright 2022 @ Keychron (https://www.keychron.com)
/* Copyright 2022~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
@@ -32,6 +32,7 @@ bool firstDisconnect = true;
static uint32_t pairing_key_timer;
static uint8_t host_idx = 0;
extern uint32_t connected_idle_time;
bool process_record_keychron_wireless(uint16_t keycode, keyrecord_t *record) {
static uint8_t host_idx;
@@ -84,7 +85,7 @@ void lkbt51_param_init(void) {
// clang-format off
/* Set bluetooth parameters */
module_param_t param = {.event_mode = 0x02,
.connected_idle_timeout = 7200,
.connected_idle_timeout = connected_idle_time,
.pairing_timeout = 180,
.pairing_mode = 0,
.reconnect_timeout = 5,
+24 -4
View File
@@ -194,6 +194,11 @@ static inline void lpm_wakeup(void) {
halInit();
#if defined(DIP_SWITCH_PINS)
/* Init dip switch as early as possible, and read it later. */
dip_switch_init();
#endif
#ifdef ENCODER_ENABLE
encoder_cb_init();
#endif
@@ -227,15 +232,30 @@ static inline void lpm_wakeup(void) {
#endif
#if defined(DIP_SWITCH_PINS)
dip_switch_init();
dip_switch_read(true);
#endif
/* Call debounce_free() to avoiding memory leak of debounce_counters as debounce_init()
invoked in matrix_init() alloc new memory to debounce_counters */
debounce_free();
matrix_init();
#ifdef ENABLE_RGB_MATRIX_PIXEL_RAIN
extern void PIXEL_RAIN_init(void);
PIXEL_RAIN_init();
#endif
#ifdef ENABLE_RGB_MATRIX_PIXEL_FLOW
extern void PIXEL_FLOW_init(void);
PIXEL_FLOW_init();
#endif
#ifdef ENABLE_RGB_MATRIX_PIXEL_FRACTAL
extern void PIXEL_FRACTAL_init(void);
PIXEL_FRACTAL_init();
#endif
#if defined(DIP_SWITCH_PINS)
dip_switch_read(true);
#endif
}
void lpm_task(void) {
+118 -2
View File
@@ -24,6 +24,8 @@
#include "rtc_timer.h"
#include "keychron_wireless_common.h"
#include "keychron_task.h"
#include "wireless_config.h"
#include "keychron_raw_hid.h"
extern uint8_t pairing_indication;
extern host_driver_t chibios_driver;
@@ -39,6 +41,9 @@ static wt_state_t wireless_state = WT_RESET;
static bool pincodeEntry = false;
uint8_t wireless_report_protocol = true;
uint16_t backlit_disable_time = CONNECTED_BACKLIGHT_DISABLE_TIMEOUT;
uint16_t connected_idle_time = CONNECTED_IDLE_TIME;
/* declarations */
uint8_t wreless_keyboard_leds(void);
void wireless_send_keyboard(report_keyboard_t *report);
@@ -55,6 +60,8 @@ wireless_event_t wireless_event_queue[WT_EVENT_QUEUE_SIZE];
uint8_t wireless_event_queue_head;
uint8_t wireless_event_queue_tail;
bool wireless_lpm_set(uint8_t *data);
void wireless_event_queue_init(void) {
// Initialise the event queue
memset(&wireless_event_queue, 0, sizeof(wireless_event_queue));
@@ -82,6 +89,41 @@ static inline bool wireless_event_dequeue(wireless_event_t *event) {
return true;
}
#if defined(EECONFIG_BASE_WIRELESS_CONFIG)
void wireless_config_reset(void) {
uint8_t data[4] = { 0 };
uint16_t backlit_disable_time = CONNECTED_BACKLIGHT_DISABLE_TIMEOUT;
uint16_t connected_idle_time = CONNECTED_IDLE_TIME;
memcpy(&data[0], &backlit_disable_time, sizeof(backlit_disable_time));
memcpy(&data[2], &connected_idle_time, sizeof(connected_idle_time));
wireless_lpm_set(data);
}
void wireless_config_load(void) {
uint8_t offset = 0;
eeprom_read_block(&backlit_disable_time, (uint8_t *)(EECONFIG_BASE_WIRELESS_CONFIG+offset), sizeof(backlit_disable_time));
offset += sizeof(backlit_disable_time);
eeprom_read_block(&connected_idle_time, (uint8_t *)(EECONFIG_BASE_WIRELESS_CONFIG+offset), sizeof(connected_idle_time));
if (backlit_disable_time == 0)
backlit_disable_time = CONNECTED_BACKLIGHT_DISABLE_TIMEOUT;
else if (backlit_disable_time < 5 ) backlit_disable_time = 5;
if (connected_idle_time == 0)
connected_idle_time = CONNECTED_IDLE_TIME;
else if (connected_idle_time < 30 ) connected_idle_time = 30;
}
void wireless_config_save(void) {
uint8_t offset = 0;
eeprom_update_block(&backlit_disable_time, (uint8_t *)(EECONFIG_BASE_WIRELESS_CONFIG+offset), sizeof(backlit_disable_time));
offset += sizeof(backlit_disable_time);
eeprom_update_block(&connected_idle_time, (uint8_t *)(EECONFIG_BASE_WIRELESS_CONFIG+offset), sizeof(connected_idle_time));
}
#endif
/*
* Bluetooth init.
*/
@@ -102,6 +144,10 @@ void wireless_init(void) {
#if HAL_USE_RTC
rtc_timer_init();
#endif
#if defined(EECONFIG_BASE_WIRELESS_CONFIG)
wireless_config_load();
#endif
}
/*
@@ -253,9 +299,10 @@ static void wireless_enter_disconnected(uint8_t host_idx, uint8_t reason) {
indicator_set(WT_SUSPEND, host_idx);
} else {
indicator_set(wireless_state, host_idx);
#if defined(RGB_MATRIX) || defined(LED_MATRIX)
if (reason && (get_transport() & TRANSPORT_WIRELESS))
#if defined(RGB_MATRIX_ENABLE) || defined(LED_MATRIX_ENABLE)
if (reason && (get_transport() & TRANSPORT_WIRELESS)) {
indicator_set_backlit_timeout(DISCONNECTED_BACKLIGHT_DISABLE_TIMEOUT*1000);
}
#endif
}
@@ -539,3 +586,72 @@ bool process_record_wireless(uint16_t keycode, keyrecord_t *record) {
return true;
}
#if defined(EECONFIG_BASE_WIRELESS_CONFIG)
bool wireless_lpm_get(uint8_t *data) {
uint8_t index = 1;
memcpy(&data[index], &backlit_disable_time, sizeof(backlit_disable_time));
index += sizeof(backlit_disable_time);
memcpy(&data[index], &connected_idle_time, sizeof(connected_idle_time));
return true;
}
bool wireless_lpm_set(uint8_t *data) {
uint8_t index = 0;
memcpy(&backlit_disable_time, &data[index], sizeof(backlit_disable_time));
index += sizeof(backlit_disable_time);
memcpy(&connected_idle_time, &data[index], sizeof(connected_idle_time));
if (backlit_disable_time < 5 || connected_idle_time < 60) {
wireless_config_load();
return false;
}
wireless_config_save();
// Reset backlight timeout
if ((get_transport() & TRANSPORT_WIRELESS) && wireless_state == WT_CONNECTED)
{
indicator_set_backlit_timeout(backlit_disable_time*1000);
indicator_reset_backlit_time();
// Wiggle mouse to reset bluetooth module timer
mousekey_on(KC_MS_LEFT);
mousekey_send();
wait_ms(10);
mousekey_on(KC_MS_RIGHT);
mousekey_send();
wait_ms(10);
mousekey_off((KC_MS_RIGHT));
mousekey_send();
wait_ms(10);
}
// Update bluetooth module param
lkbt51_param_init();
return true;
}
void wireless_raw_hid_rx(uint8_t *data, uint8_t length) {
uint8_t cmd = data[1];
bool success = true;
switch (cmd) {
case WIRELESS_LPM_GET:
success = wireless_lpm_get(&data[2]);
break;
case WIRELESS_LPM_SET:
success = wireless_lpm_set(&data[2]);
break;
default:
data[0] = 0xFF;
break;
}
data[2] = success ? 0 : 1;
}
#endif
@@ -1,4 +1,4 @@
/* Copyright 2023 @ lokher (https://www.keychron.com)
/* Copyright 2023~2025 @ lokher (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
@@ -67,6 +67,8 @@ typedef struct {
extern void register_wt_tasks(void);
void wireless_init(void);
void wireless_config_reset(void);
void wireless_set_transport(wt_func_t *transport);
void wireless(void);
@@ -99,3 +101,6 @@ wt_state_t wireless_get_state(void);
void wireless_low_battery_shutdown(void);
bool process_record_wireless(uint16_t keycode, keyrecord_t *record);
void wireless_raw_hid_rx(uint8_t *data, uint8_t length);
@@ -1,4 +1,4 @@
OPT_DEFS += -DLK_WIRELESS_ENABLE
OPT_DEFS += -DLK_WIRELESS_ENABLE -DWIRELESS_CONFIG_ENABLE
OPT_DEFS += -DNO_USB_STARTUP_CHECK
OPT_DEFS += -DCORTEX_ENABLE_WFI_IDLE=TRUE
@@ -1,4 +1,4 @@
/* Copyright 2023 @ lokher (https://www.keychron.com)
/* Copyright 2023~2025 @ lokher (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
@@ -25,12 +25,7 @@
#define P2P4G_HOST_DEVICES_COUNT 1
// Uint: Second
#ifndef DISCONNECTED_BACKLIGHT_OFF_DELAY_TIME
# define DISCONNECTED_BACKLIGHT_OFF_DELAY_TIME 40
#endif
// Uint: Second, the timer restarts on key activities.
#ifndef CONNECTED_BACKLIGHT_OFF_DELAY_TIME
# define CONNECTED_BACKLIGHT_OFF_DELAY_TIME 600
#ifndef CONNECTED_IDLE_TIME
# define CONNECTED_IDLE_TIME 7200
#endif
@@ -1,4 +1,4 @@
/* Copyright 2023 @ lokher (https://www.keychron.com)
/* Copyright 2023~2025 @ lokher (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
@@ -4,16 +4,7 @@
"device_version": "1.0.0"
},
"features": {
"rgb_matrix": true,
"encoder": true
},
"encoder": {
"rotary": [
{
"pin_a": "A8",
"pin_b": "C9"
}
]
"rgb_matrix": true
},
"rgb_matrix": {
"driver": "snled27351_spi",
@@ -19,7 +19,7 @@
// clang-format off
#ifdef RGB_MATRIX_ENABLE
const snled27351_led_t PROGMEM g_snled27351_leds[RGB_MATRIX_LED_COUNT] = {
/* Refer to snled27351manual for these locations
/* Refer to SNLED27351 manual for these locations
* driver
* | R location
* | | G location
@@ -4,16 +4,7 @@
"device_version": "1.0.0"
},
"features": {
"led_matrix": true,
"encoder": true
},
"encoder": {
"rotary": [
{
"pin_a": "A8",
"pin_b": "C9"
}
]
"led_matrix": true
},
"led_matrix": {
"driver": "snled27351_spi",
+14 -13
View File
@@ -1,4 +1,4 @@
/* Copyright 2024 @ Keychron (https://www.keychron.com)
/* Copyright 2024 ~ 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
@@ -19,6 +19,19 @@
#define ENCODER_DEFAULT_POS 0x3
#define ENCODER_MAP_KEY_DELAY 2
#if defined(RGB_MATRIX_ENABLE) || defined(LED_MATRIX_ENABLE) || defined(LK_WIRELESS_ENABLE)
/* SPI configuration */
# define SPI_DRIVER SPID1
# define SPI_SCK_PIN A5
# define SPI_MISO_PIN A6
# define SPI_MOSI_PIN A7
#endif
#if defined(RGB_MATRIX_ENABLE) || defined(LED_MATRIX_ENABLE)
# define LED_DRIVER_SHUTDOWN_PIN B7
# define SNLED23751_SPI_DIVISOR 16
#endif
#ifdef LK_WIRELESS_ENABLE
/* Hardware configuration */
# define P2P4_MODE_SELECT_PIN A10
@@ -43,26 +56,19 @@
# if defined(RGB_MATRIX_ENABLE) || defined(LED_MATRIX_ENABLE)
# define LED_DRIVER_SHUTDOWN_PIN B7
# define BT_HOST_LED_MATRIX_LIST \
{ 15, 16, 17 }
# define P2P4G_HOST_LED_MATRIX_LIST \
{ 18 }
# define BAT_LEVEL_LED_LIST \
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
/* Backlit disable timeout when keyboard is disconnected(unit: second) */
# define DISCONNECTED_BACKLIGHT_DISABLE_TIMEOUT 40
/* Backlit disable timeout when keyboard is connected(unit: second) */
# define CONNECTED_BACKLIGHT_DISABLE_TIMEOUT 600
/* Reinit LED driver on tranport changed */
# define REINIT_LED_DRIVER 1
# endif
/* Keep USB connection in blueooth mode */
@@ -71,11 +77,6 @@
/* Enable bluetooth NKRO */
# define WIRELESS_NKRO_ENABLE
/* Raw hid command for factory test and bluetooth DFU */
# define RAW_HID_CMD 0xAA ... 0xAB
#else
/* Raw hid command for factory test */
# define RAW_HID_CMD 0xAB
#endif
/* Factory test keys */
+89 -1
View File
@@ -27,6 +27,14 @@
"dip_switch": {
"pins": ["B14"]
},
"encoder": {
"rotary": [
{
"pin_a": "A8",
"pin_b": "C9"
}
]
},
"indicators": {
"caps_lock": "A13",
"on_state": 1
@@ -196,7 +204,87 @@
{"matrix":[4,14], "x":17.25, "y":4.5},
{"matrix":[4,15], "x":18.25, "y":4.5}
]
}
},
"LAYOUT_73_jis": {
"layout": [
{"matrix":[0, 0], "x":0.75, "y":0.25},
{"matrix":[0, 1], "x":1.75, "y":0.25},
{"matrix":[0, 2], "x":2.75, "y":0},
{"matrix":[0, 3], "x":3.75, "y":0.25},
{"matrix":[0, 4], "x":4.75, "y":0.25},
{"matrix":[0, 5], "x":5.75, "y":0.25},
{"matrix":[0, 6], "x":6.75, "y":0.25},
{"matrix":[0, 7], "x":9.5, "y":0.25},
{"matrix":[0, 8], "x":10.5, "y":0.25},
{"matrix":[0, 9], "x":11.5, "y":0.25},
{"matrix":[0,10], "x":12.5, "y":0.25},
{"matrix":[0,11], "x":13.5, "y":0},
{"matrix":[0,12], "x":14.5, "y":0.25},
{"matrix":[0,13], "x":15.5, "y":0.25},
{"matrix":[0,14], "x":15.5, "y":0.25},
{"matrix":[0,15], "x":18, "y":0},
{"matrix":[1, 0], "x":0.5, "y":1.25, "w":1.5},
{"matrix":[1, 1], "x":2, "y":1.25},
{"matrix":[1, 2], "x":3.25, "y":1.25},
{"matrix":[1, 3], "x":4.25, "y":1.25},
{"matrix":[1, 4], "x":5.25, "y":1.25},
{"matrix":[1, 5], "x":6.25, "y":1.25},
{"matrix":[1, 6], "x":9, "y":1.25},
{"matrix":[1, 7], "x":10, "y":1.25},
{"matrix":[1, 8], "x":11, "y":1.25},
{"matrix":[1, 9], "x":12, "y":1.25},
{"matrix":[1,10], "x":13.25, "y":1.25},
{"matrix":[1,11], "x":14.25, "y":1.25},
{"matrix":[1,12], "x":15.25, "y":1.25},
{"matrix":[1,15], "x":18.25, "y":1.5},
{"matrix":[2, 0], "x":0.25, "y":2.25, "w":1.75},
{"matrix":[2, 1], "x":2, "y":2.25},
{"matrix":[2, 2], "x":3.5, "y":2.25},
{"matrix":[2, 3], "x":4.5, "y":2.25},
{"matrix":[2, 4], "x":5.5, "y":2.25},
{"matrix":[2, 5], "x":6.5, "y":2.25},
{"matrix":[2, 6], "x":9.5, "y":2.25},
{"matrix":[2, 7], "x":10.25, "y":2.25},
{"matrix":[2, 8], "x":11.25, "y":2.25},
{"matrix":[2, 9], "x":12.25, "y":2.25},
{"matrix":[2,10], "x":13.25, "y":2.25},
{"matrix":[2,11], "x":14.75, "y":2.25},
{"matrix":[2,13], "x":15.75, "y":2.25, "w":2.25},
{"matrix":[1,13], "x":16.75, "y":1.25, "w":1.25, "h":2},
{"matrix":[2,15], "x":18.5, "y":2.5},
{"matrix":[3, 0], "x":0, "y":3.25, "w":2.25},
{"matrix":[3, 2], "x":2.25, "y":3.25},
{"matrix":[3, 3], "x":3.75, "y":3.25},
{"matrix":[3, 4], "x":4.75, "y":3.25},
{"matrix":[3, 5], "x":5.75, "y":3.25},
{"matrix":[3, 6], "x":6.75, "y":3.25},
{"matrix":[3, 7], "x":8.5, "y":3.25},
{"matrix":[3, 8], "x":9.5, "y":3.25},
{"matrix":[3, 9], "x":10.5, "y":3.25},
{"matrix":[3,10], "x":11.5, "y":3.25},
{"matrix":[3,11], "x":12.5, "y":3.25},
{"matrix":[3,12], "x":13.5, "y":3.25},
{"matrix":[3,13], "x":14.25, "y":3.25},
{"matrix":[3,14], "x":15.25, "y":3.25},
{"matrix":[3,15], "x":17.25, "y":3.5},
{"matrix":[4, 0], "x":0, "y":4.25, "w":1.25},
{"matrix":[4, 1], "x":1.25, "y":4.25},
{"matrix":[4, 2], "x":2.25, "y":4.25},
{"matrix":[4, 3], "x":3.75, "y":4.25, "w":1.25},
{"matrix":[4, 4], "x":5, "y":4.25, "w":2.25},
{"matrix":[4, 6], "x":7.25, "y":4.25},
{"matrix":[4, 7], "x":8.75, "y":4.25},
{"matrix":[4, 9], "x":9.75, "y":4.25},
{"matrix":[4,11], "x":10.75, "y":4.25},
{"matrix":[4,12], "x":12.5, "y":4.25},
{"matrix":[4,13], "x":16.25, "y":4.5},
{"matrix":[4,14], "x":17.25, "y":4.5},
{"matrix":[4,15], "x":18.25, "y":4.5}
]
}
}
}
@@ -4,16 +4,7 @@
"device_version": "1.0.0"
},
"features": {
"rgb_matrix": true,
"encoder": true
},
"encoder": {
"rotary": [
{
"pin_a": "A8",
"pin_b": "C9"
}
]
"rgb_matrix": true
},
"rgb_matrix": {
"driver": "snled27351_spi",
@@ -19,7 +19,7 @@
// clang-format off
#ifdef RGB_MATRIX_ENABLE
const snled27351_led_t PROGMEM g_snled27351_leds[RGB_MATRIX_LED_COUNT] = {
/* Refer to snled27351manual for these locations
/* Refer to SNLED27351 manual for these locations
* driver
* | R location
* | | G location
@@ -4,16 +4,7 @@
"device_version": "1.0.0"
},
"features": {
"led_matrix": true,
"encoder": true
},
"encoder": {
"rotary": [
{
"pin_a": "A8",
"pin_b": "C9"
}
]
"led_matrix": true
},
"led_matrix": {
"driver": "snled27351_spi",
@@ -0,0 +1,46 @@
/* Copyright 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
#ifdef RGB_MATRIX_ENABLE
/* RGB Matrix driver configuration */
# define DRIVER_COUNT 2
# define RGB_MATRIX_LED_COUNT 72
# define DRIVER_CS_PINS \
{ B8, B9 }
/* Set LED driver current */
# define SNLED27351_CURRENT_TUNE \
{ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }
/* Set to infinit, which is use in USB mode by default */
# define RGB_MATRIX_TIMEOUT RGB_MATRIX_TIMEOUT_INFINITE
/* Allow shutdown of led driver to save power */
# define RGB_MATRIX_DRIVER_SHUTDOWN_ENABLE
/* Turn off backlight on low brightness to save power */
# define RGB_MATRIX_BRIGHTNESS_TURN_OFF_VAL 48
/* Indications */
# define LOW_BAT_IND_INDEX \
{ 63, 66 }
# define DIM_CAPS_LOCK
# define CAPS_LOCK_INDEX 30
# define RGB_MATRIX_KEYPRESSES
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
#endif
@@ -0,0 +1,35 @@
{
"usb": {
"pid": "0x0AB5",
"device_version": "1.0.0"
},
"features": {
"rgb_matrix": true
},
"rgb_matrix": {
"driver": "snled27351_spi",
"animations": {
"band_spiral_val": true,
"breathing": true,
"cycle_all": true,
"cycle_left_right": true,
"cycle_out_in": true,
"cycle_out_in_dual": true,
"cycle_pinwheel": true,
"cycle_spiral": true,
"cycle_up_down": true,
"digital_rain": true,
"dual_beacon": true,
"jellybean_raindrops": true,
"pixel_rain": true,
"rainbow_beacon": true,
"rainbow_moving_chevron": true,
"solid_reactive_multinexus": true,
"solid_reactive_multiwide": true,
"solid_reactive_simple": true,
"solid_splash": true,
"splash": true,
"typing_heatmap": true
}
}
}
@@ -0,0 +1,81 @@
/* Copyright 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/>.
*/
#include QMK_KEYBOARD_H
#include "keychron_common.h"
enum layers {
MAC_BASE,
WIN_BASE,
MAC_FN1,
WIN_FN1,
FN2,
};
// clang-format off
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[MAC_BASE] = LAYOUT_73_jis(
KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_INT3, KC_BSPC, KC_MUTE,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_DEL,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_BSLS, KC_ENT, KC_HOME,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_INT1, KC_RSFT, KC_UP,
KC_LCTL, KC_LOPTN, KC_LCMMD, KC_LNG2, KC_SPC, MO(MAC_FN1), MO(FN2), KC_SPC, KC_LNG1, KC_RCMMD, KC_LEFT, KC_DOWN, KC_RGHT),
[WIN_BASE] = LAYOUT_73_jis(
KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_INT3, KC_BSPC, KC_MUTE,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_DEL,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_BSLS, KC_ENT, KC_HOME,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_INT1, KC_RSFT, KC_UP,
KC_LCTL, KC_LWIN, KC_LALT, KC_INT5, KC_SPC, MO(WIN_FN1), MO(FN2), KC_SPC, KC_INT4, KC_RALT, KC_LEFT, KC_DOWN, KC_RGHT),
[MAC_FN1] = LAYOUT_73_jis(
KC_GRV, KC_BRID, KC_BRIU, KC_MCTRL, KC_LNPAD, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______, RGB_TOG,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, KC_INS,
RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______, _______, _______, _______, KC_END,
_______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, _______, NK_TOGG, _______, _______, _______, _______, _______, _______, KC_PGUP,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_PGDN, _______),
[WIN_FN1] = LAYOUT_73_jis(
KC_GRV, KC_BRID, KC_BRIU, KC_TASK, KC_FILE, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______, RGB_TOG,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, KC_INS,
RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______, _______, _______, _______, KC_END,
_______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, _______, NK_TOGG, _______, _______, _______, _______, _______, _______, KC_PGUP,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_PGDN, _______),
[FN2] = LAYOUT_73_jis(
KC_TILD, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, BAT_LVL, BAT_LVL, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______)
};
#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
[MAC_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
[WIN_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
[MAC_FN1] = { ENCODER_CCW_CW(RGB_VAD, RGB_VAI)},
[WIN_FN1] = { ENCODER_CCW_CW(RGB_VAD, RGB_VAI)},
[FN2] = { ENCODER_CCW_CW(_______, _______)},
};
#endif // ENCODER_MAP_ENABLE
// clang-format on
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
if (!process_record_keychron_common(keycode, record)) {
return false;
}
return true;
}
@@ -0,0 +1,81 @@
/* Copyright 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/>.
*/
#include QMK_KEYBOARD_H
#include "keychron_common.h"
enum layers {
MAC_BASE,
WIN_BASE,
MAC_FN1,
WIN_FN1,
FN2,
};
// clang-format off
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[MAC_BASE] = LAYOUT_73_jis(
KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_INT3, KC_BSPC, KC_MUTE,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_DEL,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_BSLS, KC_ENT, KC_HOME,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_INT1, KC_RSFT, KC_UP,
KC_LCTL, KC_LOPTN, KC_LCMMD, KC_LNG2, KC_SPC, MO(MAC_FN1), MO(FN2), KC_SPC, KC_LNG1, KC_RCMMD, KC_LEFT, KC_DOWN, KC_RGHT),
[WIN_BASE] = LAYOUT_73_jis(
KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_INT3, KC_BSPC, KC_MUTE,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_DEL,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_BSLS, KC_ENT, KC_HOME,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_INT1, KC_RSFT, KC_UP,
KC_LCTL, KC_LWIN, KC_LALT, KC_INT5, KC_SPC, MO(WIN_FN1), MO(FN2), KC_SPC, KC_INT4, KC_RALT, KC_LEFT, KC_DOWN, KC_RGHT),
[MAC_FN1] = LAYOUT_73_jis(
KC_GRV, KC_BRID, KC_BRIU, KC_MCTRL, KC_LNPAD, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______, RGB_TOG,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, KC_INS,
RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______, _______, _______, _______, KC_END,
_______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, _______, NK_TOGG, _______, _______, _______, _______, _______, _______, KC_PGUP,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_PGDN, _______),
[WIN_FN1] = LAYOUT_73_jis(
KC_GRV, KC_BRID, KC_BRIU, KC_TASK, KC_FILE, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______, RGB_TOG,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, KC_INS,
RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______, _______, _______, _______, KC_END,
_______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, _______, NK_TOGG, _______, _______, _______, _______, _______, _______, KC_PGUP,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_PGDN, _______),
[FN2] = LAYOUT_73_jis(
KC_TILD, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, BAT_LVL, BAT_LVL, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______)
};
#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
[MAC_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
[WIN_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
[MAC_FN1] = { ENCODER_CCW_CW(RGB_VAD, RGB_VAI)},
[WIN_FN1] = { ENCODER_CCW_CW(RGB_VAD, RGB_VAI)},
[FN2] = { ENCODER_CCW_CW(_______, _______)},
};
#endif // ENCODER_MAP_ENABLE
// clang-format on
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
if (!process_record_keychron_common(keycode, record)) {
return false;
}
return true;
}
@@ -0,0 +1 @@
VIA_ENABLE = yes
@@ -0,0 +1,135 @@
/* Copyright 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/>.
*/
#include "quantum.h"
// clang-format off
#ifdef RGB_MATRIX_ENABLE
const snled27351_led_t PROGMEM g_snled27351_leds[RGB_MATRIX_LED_COUNT] = {
/* Refer to SNLED27351 manual for these locations
* driver
* | R location
* | | G location
* | | | B location
* | | | | */
{0, A_1, C_1, B_1},
{0, A_2, C_2, B_2},
{0, A_3, C_3, B_3},
{0, A_4, C_4, B_4},
{0, A_5, C_5, B_5},
{0, A_6, C_6, B_6},
{0, A_7, C_7, B_7},
{0, A_8, C_8, B_8},
{0, A_9, C_9, B_9},
{0, A_10, C_10, B_10},
{0, A_11, C_11, B_11},
{0, A_12, C_12, B_12},
{0, A_13, C_13, B_13},
{0, A_14, C_14, B_14},
{0, A_15, C_15, B_15},
{0, F_1, D_1, E_1},
{0, F_2, D_2, E_2},
{0, F_3, D_3, E_3},
{0, F_4, D_4, E_4},
{0, F_5, D_5, E_5},
{0, F_6, D_6, E_6},
{0, F_7, D_7, E_7},
{0, F_8, D_8, E_8},
{0, F_9, D_9, E_9},
{0, F_10, D_10, E_10},
{0, F_11, D_11, E_11},
{0, F_12, D_12, E_12},
{0, F_13, D_13, E_13},
{0, F_14, D_14, E_14},
{0, F_16, D_16, E_16},
{1, I_1, G_1, H_1},
{1, I_2, G_2, H_2},
{1, I_3, G_3, H_3},
{1, I_4, G_4, H_4},
{1, I_5, G_5, H_5},
{1, I_6, G_6, H_6},
{1, I_7, G_7, H_7},
{1, I_8, G_8, H_8},
{1, I_9, G_9, H_9},
{1, I_10, G_10, H_10},
{1, I_11, G_11, H_11},
{1, I_12, G_12, H_12},
{1, I_14, G_14, H_14},
{1, I_16, G_16, H_16},
{1, C_1, A_1, B_1},
{1, C_3, A_3, B_3},
{1, C_4, A_4, B_4},
{1, C_5, A_5, B_5},
{1, C_6, A_6, B_6},
{1, C_7, A_7, B_7},
{1, C_8, A_8, B_8},
{1, C_9, A_9, B_9},
{1, C_10, A_10, B_10},
{1, C_11, A_11, B_11},
{1, C_12, A_12, B_12},
{1, C_13, A_13, B_13},
{1, C_14, A_14, B_14},
{1, C_15, A_15, B_15},
{1, C_16, A_16, B_16},
{1, F_1, D_1, E_1},
{1, F_2, D_2, E_2},
{1, F_3, D_3, E_3},
{1, F_4, D_4, E_4},
{1, F_5, D_5, E_5},
{1, F_7, D_7, E_7},
{1, F_8, D_8, E_8},
{1, F_10, D_10, E_10},
{1, F_12, D_12, E_12},
{1, F_13, D_13, E_13},
{1, F_14, D_14, E_14},
{1, F_15, D_15, E_15},
{1, F_16, D_16, E_16}
};
#define __ NO_LED
led_config_t g_led_config = {
{
// Key Matrix to LED Index
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, __ },
{ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, __, 29 },
{ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, __, 42, __, 43 },
{ 44, __, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58 },
{ 59, 60, 61, 62, 63, __, 64, 65, __, 66, __, 67, 68, 69, 70, 71 },
},
{
// LED Index to Physical Position
{8, 1}, {20, 1}, {33, 0}, {48, 3}, {61, 6}, {74, 8}, {86,11}, {106,11}, {119, 8}, {132, 6}, {145, 3}, {160, 0}, {173, 1}, {186, 1}, {199, 1},
{8,14}, {24,14}, {39,14}, {52,17}, {65,20}, {78,22}, {103,25},{116,22}, {129,20}, {142,17}, {155,14}, {171,14}, {184,14}, {204,20}, {222,14},
{8,27}, {24,27}, {39,28}, {52,30}, {65,33}, {78,36}, {109,37},{122,34}, {135,32}, {148,29}, {162,27}, {176,27}, {190,27}, {224,27},
{8,40}, {28,40}, {43,42}, {56,44}, {69,47}, {82,50}, {102,52},{115,49}, {128,46}, {141,44}, {154,44}, {169,40}, {182,40}, {196,40}, {209,43},
{0,53}, {15,53}, {28,53}, {42,55}, {65,60}, {86,64}, {107,64}, {131,59}, {156,54}, {169,53}, {196,56}, {209,56}, {222,56},
},
{
// LED Index to Flag
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
}
};
#endif
@@ -0,0 +1 @@
# This file intentionally left blank
@@ -0,0 +1,51 @@
/* Copyright 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
#ifdef LED_MATRIX_ENABLE
/* LED matrix driver configuration */
# define DRIVER_COUNT 1
# define LED_MATRIX_LED_COUNT 72
# define LED_MATRIX_VAL_STEP 16
# define DRIVER_CS_PINS \
{ B9 }
/* Set LED driver scan phase */
# define SNLED27351_PHASE_CHANNEL MSKPHASE_6CHANNEL
/* Set LED driver current */
# define SNLED27351_CURRENT_TUNE \
{ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50 }
/* Set to infinit, which is use in USB mode by default */
# define LED_MATRIX_TIMEOUT LED_MATRIX_TIMEOUT_INFINITE
/* Allow shutdown of led driver to save power */
# define LED_MATRIX_DRIVER_SHUTDOWN_ENABLE
/* Turn off backlight on low brightness to save power */
# define LED_MATRIX_BRIGHTNESS_TURN_OFF_VAL 48
/* Indications */
# define DIM_CAPS_LOCK
# define CAPS_LOCK_INDEX 30
/* Low battery indicating led */
# define LOW_BAT_IND_INDEX \
{ 63, 66 }
# define LED_MATRIX_KEYPRESSES
# define VOLTAGE_TRIM_LED_MATRIX 200
#endif
@@ -0,0 +1,29 @@
{
"usb": {
"pid": "0x0ABB",
"device_version": "1.0.0"
},
"features": {
"led_matrix": true
},
"led_matrix": {
"driver": "snled27351_spi",
"animations": {
"none": true,
"solid": true,
"breathing": true,
"band_pinwheel": true,
"band_spiral": true,
"cycle_left_right": true,
"cycle_up_down": true,
"cycle_out_in": true,
"dual_beacon": true,
"solid_reactive_simple": true,
"solid_reactive_multiwide": true,
"solid_reactive_multinexus": true,
"solid_splash": true,
"wave_left_right": true,
"wave_up_down": true
}
}
}
@@ -0,0 +1,82 @@
/* Copyright 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/>.
*/
#include QMK_KEYBOARD_H
#include "keychron_common.h"
enum layers{
MAC_BASE,
WIN_BASE,
MAC_FN1,
WIN_FN1,
FN2,
};
// clang-format off
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[MAC_BASE] = LAYOUT_73_jis(
KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_INT3, KC_BSPC, KC_MUTE,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_DEL,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_BSLS, KC_ENT, KC_HOME,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_INT1, KC_RSFT, KC_UP,
KC_LCTL, KC_LOPTN, KC_LCMMD, KC_LNG2, KC_SPC, MO(MAC_FN1), MO(FN2), KC_SPC, KC_LNG1, KC_RCMMD, KC_LEFT, KC_DOWN, KC_RGHT),
[WIN_BASE] = LAYOUT_73_jis(
KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_INT3, KC_BSPC, KC_MUTE,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_DEL,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_BSLS, KC_ENT, KC_HOME,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_INT1, KC_RSFT, KC_UP,
KC_LCTL, KC_LWIN, KC_LALT, KC_INT5, KC_SPC, MO(WIN_FN1), MO(FN2), KC_SPC, KC_INT4, KC_RALT, KC_LEFT, KC_DOWN, KC_RGHT),
[MAC_FN1] = LAYOUT_73_jis(
KC_GRV, KC_BRID, KC_BRIU, KC_MCTRL, KC_LNPAD, BL_DOWN, BL_UP, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______, BL_TOGG,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, KC_INS,
BL_TOGG, BL_STEP, BL_UP, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_END,
_______, _______, BL_DOWN, _______, _______, _______, _______, NK_TOGG, _______, _______, _______, _______, _______, _______, KC_PGUP,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_PGDN, _______),
[WIN_FN1] = LAYOUT_73_jis(
KC_GRV, KC_BRID, KC_BRIU, KC_TASK, KC_FILE, BL_DOWN, BL_UP, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______, BL_TOGG,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, KC_INS,
BL_TOGG, BL_STEP, BL_UP, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_END,
_______, _______, BL_DOWN, _______, _______, _______, _______, NK_TOGG, _______, _______, _______, _______, _______, _______, KC_PGUP,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_PGDN, _______),
[FN2] = LAYOUT_73_jis(
KC_TILD, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, BAT_LVL, BAT_LVL, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______)
};
#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
[MAC_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
[WIN_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
[MAC_FN1] = { ENCODER_CCW_CW(BL_DOWN, BL_UP)},
[WIN_FN1] = { ENCODER_CCW_CW(BL_DOWN, BL_UP)},
[FN2] = { ENCODER_CCW_CW(_______, _______)},
};
#endif // ENCODER_MAP_ENABLE
// clang-format on
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
if (!process_record_keychron_common(keycode, record)) {
return false;
}
return true;
}
@@ -0,0 +1,82 @@
/* Copyright 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/>.
*/
#include QMK_KEYBOARD_H
#include "keychron_common.h"
enum layers{
MAC_BASE,
WIN_BASE,
MAC_FN1,
WIN_FN1,
FN2,
};
// clang-format off
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[MAC_BASE] = LAYOUT_73_jis(
KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_INT3, KC_BSPC, KC_MUTE,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_DEL,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_BSLS, KC_ENT, KC_HOME,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_INT1, KC_RSFT, KC_UP,
KC_LCTL, KC_LOPTN, KC_LCMMD, KC_LNG2, KC_SPC, MO(MAC_FN1), MO(FN2), KC_SPC, KC_LNG1, KC_RCMMD, KC_LEFT, KC_DOWN, KC_RGHT),
[WIN_BASE] = LAYOUT_73_jis(
KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_INT3, KC_BSPC, KC_MUTE,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_DEL,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_BSLS, KC_ENT, KC_HOME,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_INT1, KC_RSFT, KC_UP,
KC_LCTL, KC_LWIN, KC_LALT, KC_INT5, KC_SPC, MO(WIN_FN1), MO(FN2), KC_SPC, KC_INT4, KC_RALT, KC_LEFT, KC_DOWN, KC_RGHT),
[MAC_FN1] = LAYOUT_73_jis(
KC_GRV, KC_BRID, KC_BRIU, KC_MCTRL, KC_LNPAD, BL_DOWN, BL_UP, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______, BL_TOGG,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, KC_INS,
BL_TOGG, BL_STEP, BL_UP, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_END,
_______, _______, BL_DOWN, _______, _______, _______, _______, NK_TOGG, _______, _______, _______, _______, _______, _______, KC_PGUP,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_PGDN, _______),
[WIN_FN1] = LAYOUT_73_jis(
KC_GRV, KC_BRID, KC_BRIU, KC_TASK, KC_FILE, BL_DOWN, BL_UP, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______, BL_TOGG,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, KC_INS,
BL_TOGG, BL_STEP, BL_UP, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_END,
_______, _______, BL_DOWN, _______, _______, _______, _______, NK_TOGG, _______, _______, _______, _______, _______, _______, KC_PGUP,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_PGDN, _______),
[FN2] = LAYOUT_73_jis(
KC_TILD, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, BAT_LVL, BAT_LVL, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______)
};
#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
[MAC_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
[WIN_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
[MAC_FN1] = { ENCODER_CCW_CW(BL_DOWN, BL_UP)},
[WIN_FN1] = { ENCODER_CCW_CW(BL_DOWN, BL_UP)},
[FN2] = { ENCODER_CCW_CW(_______, _______)},
};
#endif // ENCODER_MAP_ENABLE
// clang-format on
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
if (!process_record_keychron_common(keycode, record)) {
return false;
}
return true;
}
@@ -0,0 +1 @@
VIA_ENABLE = yes
@@ -0,0 +1 @@
# This file intentionally left blank
@@ -0,0 +1,133 @@
/* Copyright 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/>.
*/
#include "quantum.h"
// clang-format off
#ifdef LED_MATRIX_ENABLE
const snled27351_led_t g_snled27351_leds[LED_MATRIX_LED_COUNT] = {
/* Refer to SNLED27351 manual for these locations
* driver
* | LED address
* | | */
{0, E_1},
{0, E_2},
{0, E_3},
{0, E_4},
{0, E_5},
{0, E_6},
{0, E_7},
{0, E_8},
{0, E_9},
{0, E_10},
{0, E_11},
{0, E_12},
{0, E_13},
{0, E_14},
{0, E_15},
{0, D_1},
{0, D_2},
{0, D_3},
{0, D_4},
{0, D_5},
{0, D_6},
{0, D_7},
{0, D_8},
{0, D_9},
{0, D_10},
{0, D_11},
{0, D_12},
{0, D_13},
{0, D_14},
{0, D_16},
{0, C_1},
{0, C_2},
{0, C_3},
{0, C_4},
{0, C_5},
{0, C_6},
{0, C_7},
{0, C_8},
{0, C_9},
{0, C_10},
{0, C_11},
{0, C_12},
{0, C_14},
{0, C_16},
{0, B_1},
{0, B_3},
{0, B_4},
{0, B_5},
{0, B_6},
{0, B_7},
{0, B_8},
{0, B_9},
{0, B_10},
{0, B_11},
{0, B_12},
{0, B_13},
{0, B_14},
{0, B_15},
{0, B_16},
{0, A_1},
{0, A_2},
{0, A_3},
{0, A_4},
{0, A_5},
{0, A_7},
{0, A_8},
{0, A_10},
{0, A_12},
{0, A_13},
{0, A_14},
{0, A_15},
{0, A_16},
};
#define __ NO_LED
led_config_t g_led_config = {
{
// Key Matrix to LED Index
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, __ },
{ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, __, 29 },
{ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, __, 42, __, 43 },
{ 44, __, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58 },
{ 59, 60, 61, 62, 63, __, 64, 65, __, 66, __, 67, 68, 69, 70, 71 },
},
{
// LED Index to Physical Position
{8, 1}, {20, 1}, {33, 0}, {48, 3}, {61, 6}, {74, 8}, {86,11}, {106,11}, {119, 8}, {132, 6}, {145, 3}, {160, 0}, {173, 1}, {186, 1}, {199, 1},
{8,14}, {24,14}, {39,14}, {52,17}, {65,20}, {78,22}, {103,25},{116,22}, {129,20}, {142,17}, {155,14}, {171,14}, {184,14}, {204,20}, {222,14},
{8,27}, {24,27}, {39,28}, {52,30}, {65,33}, {78,36}, {109,37},{122,34}, {135,32}, {148,29}, {162,27}, {176,27}, {190,27}, {224,27},
{8,40}, {28,40}, {43,42}, {56,44}, {69,47}, {82,50}, {102,52},{115,49}, {128,46}, {141,44}, {154,44}, {169,40}, {182,40}, {196,40}, {209,43},
{0,53}, {15,53}, {28,53}, {42,55}, {65,60}, {86,64}, {107,64}, {131,59}, {156,54}, {169,53}, {196,56}, {209,56}, {222,56},
},
{
// LED Index to Flag
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
}
};
#endif
@@ -0,0 +1,358 @@
{
"name": "Keychron K11 Max JIS RGB Knob",
"vendorId": "0x3434",
"productId": "0x0AB5",
"keycodes": ["qmk_lighting"],
"menus": [
{
"label": "Lighting",
"content": [
{
"label": "Backlight",
"content": [
{
"label": "Brightness",
"type": "range",
"options": [0, 255],
"content": ["id_qmk_rgb_matrix_brightness", 3, 1]
},
{
"label": "Effect",
"type": "dropdown",
"content": ["id_qmk_rgb_matrix_effect", 3, 2],
"options": [
["None", 0],
["Solid Color", 1],
["Breathing", 2],
["Band Spiral Val", 3],
["Cycle All", 4],
["Cycle Left Right", 5],
["Cycle Up Down", 6],
["Rainbow Moving Chevron", 7],
["Cycle Out In", 8],
["Cycle Out In Dual", 9],
["Cycle Pinwheel", 10],
["Cycle Spiral", 11],
["Dual Beacon", 12],
["Rainbow Beacon", 13],
["Jellybean Raindrops", 14],
["Pixel Rain", 15],
["Typing Heatmap", 16],
["Digital Rain", 17],
["Reactive Simple", 18],
["Reactive Multiwide", 19],
["Reactive Multinexus", 20],
["Splash", 21],
["Solid Splash", 22]
]
},
{
"showIf": "{id_qmk_rgb_matrix_effect} > 1",
"label": "Effect Speed",
"type": "range",
"options": [0, 255],
"content": ["id_qmk_rgb_matrix_effect_speed", 3, 3]
},
{
"showIf": "{id_qmk_rgb_matrix_effect} != 0 && ( {id_qmk_rgb_matrix_effect} < 4 || {id_qmk_rgb_matrix_effect} == 18 || ({id_qmk_rgb_matrix_effect} > 17 && {id_qmk_rgb_matrix_effect} != 21) ) ",
"label": "Color",
"type": "color",
"content": ["id_qmk_rgb_matrix_color", 3, 4]
}
]
}
]
}
],
"customKeycodes": [
{"name": "Left Option", "title": "Left Option", "shortName": "LOpt"},
{"name": "Right Option", "title": "Right Option", "shortName": "ROpt"},
{"name": "Left Cmd", "title": "Left Command", "shortName": "LCmd"},
{"name": "Right Cmd", "title": "Right Command", "shortName": "RCmd"},
{"name": "Misson Control", "title": "Misson Control in Mac", "shortName": "MCtl"},
{"name": "Lanuch Pad", "title": "Lanuch Pad in Windows", "shortName": "LPad"},
{"name": "Task View", "title": "Task View in Windows", "shortName": "Task"},
{"name": "File Explorer", "title": "File Explorer in Windows", "shortName": "File"},
{"name": "Screen shot", "title": "Screenshot in macOS", "shortName": "SShot"},
{"name": "Cortana", "title": "Cortana in Windows", "shortName": "Cortana"},
{"name": "Siri", "title": "Siri in macOS", "shortName": "Siri"},
{"name": "Bluetooth Host 1", "title": "Bluetooth Host 1", "shortName": "BTH1"},
{"name": "Bluetooth Host 2", "title": "Bluetooth Host 2", "shortName": "BTH2"},
{"name": "Bluetooth Host 3", "title": "Bluetooth Host 3", "shortName": "BTH3"},
{"name": "2.4G", "title": "2.4G", "shortName": "2.4G"},
{"name": "Battery Level", "title": "Show battery level", "shortName": "Batt"}
],
"matrix": {"rows": 5, "cols": 16},
"layouts": {
"keymap": [
[
{
"x": 2.75
},
"0,2",
{
"x": 8.85
},
"0,11"
],
[
{
"y": -0.95,
"x": 0.75,
"c": "#777777"
},
"0,0\nESC",
{
"c": "#cccccc"
},
"0,1"
],
[
{
"y": -0.85,
"x": 14.6,
"c": "#aaaaaa"
},
"0,13",
"0,14",
{
"x": 0.5
},
"0,15\n\n\n\n\n\n\n\n\ne0"
],
[
{
"y": -1,
"x": 13.6,
"c": "#cccccc"
},
"0,12"
],
[
{
"y": -0.15,
"x": 0.5,
"c": "#aaaaaa",
"w": 1.5
},
"1,0",
{
"c": "#cccccc"
},
"1,1"
],
[
{
"y": -0.85,
"x": 13.6
},
"1,11",
"1,12",
{
"x": 0.25,
"c": "#aaaaaa",
"w": 1.25,
"h": 2,
"w2": 1.5,
"h2": 1,
"x2": -0.25
},
"1,13",
{
"x": 0.25
},
"1,15"
],
[
{
"y": -0.15,
"x": 0.25,
"w": 1.75
},
"2,0",
{
"c": "#cccccc"
},
"2,1"
],
[
{
"y": -0.85,
"x": 12.85
},
"2,10",
"2,11",
{
"c": "#aaaaaa"
},
"2,13",
{
"x": 1.75
},
"2,15"
],
[
{
"y": -0.15,
"w": 2.25
},
"3,0",
{
"c": "#cccccc"
},
"3,2"
],
[
{
"y": -0.85,
"x": 13.3
},
"3,12",
{
"c": "#aaaaaa"
},
"3,13",
"3,14"
],
[
{
"y": -0.75,
"x": 16.3,
"c": "#cccccc"
},
"3,15"
],
[
{
"y": -0.4,
"c": "#aaaaaa",
"w": 1.25
},
"4,0",
"4,1",
"4,2"
],
[
{
"y": -0.85,
"x":13.3
},
"4,12"
],
[
{
"y": -0.76,
"x": 15.3,
"c": "#cccccc"
},
"4,13",
"4,14",
"4,15"
],
[
{
"r": 6,
"y": -5.7,
"x": 3.85,
"c": "#cccccc"
},
"0,3",
"0,4",
"0,5",
"0,6"
],
[
{
"x": 3.3
},
"1,2",
"1,3",
"1,4",
"1,5"
],
[
{
"x": 3.55
},
"2,2",
"2,3",
"2,4",
"2,5"
],
[
{
"x": 3.9
},
"3,3",
"3,4",
"3,5",
"3,6"
],
[
{
"x": 4.2,
"c": "#aaaaaa"
},
"4,3",
{
"w": 2.25
},
"4,4",
"4,6"
],
[
{
"r": -6,
"y": -3.3,
"x": 8.45,
"c": "#cccccc"
},
"0,7",
"0,8",
"0,9",
"0,10"
],
[
{
"x": 8.0
},
"1,6",
"1,7",
"1,8",
"1,9",
"1,10"
],
[
{
"x": 8.35
},
"2,6",
"2,7",
"2,8",
"2,9"
],
[
{
"x": 7.65
},
"3,7",
"3,8",
"3,9",
"3,10",
"3,11"
],
[
{
"x": 7.65,
"c": "#aaaaaa"
},
"4,7",
{
"w": 2.75
},
"4,9",
"4,11"
]
]
}
}
@@ -0,0 +1,297 @@
{
"name": "Keychron K11 Max JIS White Knob",
"vendorId": "0x3434",
"productId": "0x0ABB",
"keycodes": ["qmk_lighting"],
"customKeycodes": [
{"name": "Left Option", "title": "Left Option", "shortName": "LOpt"},
{"name": "Right Option", "title": "Right Option", "shortName": "ROpt"},
{"name": "Left Cmd", "title": "Left Command", "shortName": "LCmd"},
{"name": "Right Cmd", "title": "Right Command", "shortName": "RCmd"},
{"name": "Misson Control", "title": "Misson Control in Mac", "shortName": "MCtl"},
{"name": "Lanuch Pad", "title": "Lanuch Pad in Windows", "shortName": "LPad"},
{"name": "Task View", "title": "Task View in Windows", "shortName": "Task"},
{"name": "File Explorer", "title": "File Explorer in Windows", "shortName": "File"},
{"name": "Screen shot", "title": "Screenshot in macOS", "shortName": "SShot"},
{"name": "Cortana", "title": "Cortana in Windows", "shortName": "Cortana"},
{"name": "Siri", "title": "Siri in macOS", "shortName": "Siri"},
{"name": "Bluetooth Host 1", "title": "Bluetooth Host 1", "shortName": "BTH1"},
{"name": "Bluetooth Host 2", "title": "Bluetooth Host 2", "shortName": "BTH2"},
{"name": "Bluetooth Host 3", "title": "Bluetooth Host 3", "shortName": "BTH3"},
{"name": "2.4G", "title": "2.4G", "shortName": "2.4G"},
{"name": "Battery Level", "title": "Show battery level", "shortName": "Batt"}
],
"matrix": {"rows": 5, "cols": 16},
"layouts": {
"keymap": [
[
{
"x": 2.75
},
"0,2",
{
"x": 8.85
},
"0,11"
],
[
{
"y": -0.95,
"x": 0.75,
"c": "#777777"
},
"0,0\nESC",
{
"c": "#cccccc"
},
"0,1"
],
[
{
"y": -0.85,
"x": 14.6,
"c": "#aaaaaa"
},
"0,13",
"0,14",
{
"x": 0.5
},
"0,15\n\n\n\n\n\n\n\n\ne0"
],
[
{
"y": -1,
"x": 13.6,
"c": "#cccccc"
},
"0,12"
],
[
{
"y": -0.15,
"x": 0.5,
"c": "#aaaaaa",
"w": 1.5
},
"1,0",
{
"c": "#cccccc"
},
"1,1"
],
[
{
"y": -0.85,
"x": 13.6
},
"1,11",
"1,12",
{
"x": 0.25,
"c": "#aaaaaa",
"w": 1.25,
"h": 2,
"w2": 1.5,
"h2": 1,
"x2": -0.25
},
"1,13",
{
"x": 0.25
},
"1,15"
],
[
{
"y": -0.15,
"x": 0.25,
"w": 1.75
},
"2,0",
{
"c": "#cccccc"
},
"2,1"
],
[
{
"y": -0.85,
"x": 12.85
},
"2,10",
"2,11",
{
"c": "#aaaaaa"
},
"2,13",
{
"x": 1.75
},
"2,15"
],
[
{
"y": -0.15,
"w": 2.25
},
"3,0",
{
"c": "#cccccc"
},
"3,2"
],
[
{
"y": -0.85,
"x": 13.3
},
"3,12",
{
"c": "#aaaaaa"
},
"3,13",
"3,14"
],
[
{
"y": -0.75,
"x": 16.3,
"c": "#cccccc"
},
"3,15"
],
[
{
"y": -0.4,
"c": "#aaaaaa",
"w": 1.25
},
"4,0",
"4,1",
"4,2"
],
[
{
"y": -0.85,
"x":13.3
},
"4,12"
],
[
{
"y": -0.76,
"x": 15.3,
"c": "#cccccc"
},
"4,13",
"4,14",
"4,15"
],
[
{
"r": 6,
"y": -5.7,
"x": 3.85,
"c": "#cccccc"
},
"0,3",
"0,4",
"0,5",
"0,6"
],
[
{
"x": 3.3
},
"1,2",
"1,3",
"1,4",
"1,5"
],
[
{
"x": 3.55
},
"2,2",
"2,3",
"2,4",
"2,5"
],
[
{
"x": 3.9
},
"3,3",
"3,4",
"3,5",
"3,6"
],
[
{
"x": 4.2,
"c": "#aaaaaa"
},
"4,3",
{
"w": 2.25
},
"4,4",
"4,6"
],
[
{
"r": -6,
"y": -3.3,
"x": 8.45,
"c": "#cccccc"
},
"0,7",
"0,8",
"0,9",
"0,10"
],
[
{
"x": 8.0
},
"1,6",
"1,7",
"1,8",
"1,9",
"1,10"
],
[
{
"x": 8.35
},
"2,6",
"2,7",
"2,8",
"2,9"
],
[
{
"x": 7.65
},
"3,7",
"3,8",
"3,9",
"3,10",
"3,11"
],
[
{
"x": 7.65,
"c": "#aaaaaa"
},
"4,7",
{
"w": 2.75
},
"4,9",
"4,11"
]
]
}
}
@@ -17,11 +17,17 @@
#include QMK_KEYBOARD_H
#include "keychron_common.h"
enum layers{
MAC_BASE,
MAC_FN,
WIN_BASE,
WIN_FN,
// Tap Dance declarations
enum {
TD_HOME_END,
};
enum layers {
MAC_BASE,
MAC_FN,
WIN_BASE,
WIN_FN,
};
// clang-format off
@@ -30,7 +36,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
KC_ESC, KC_BRID, KC_BRIU, KC_MCTRL, KC_LNPAD, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_SNAP, RGB_MOD, KC_DEL, KC_F13, KC_F14, KC_F15, KC_MUTE,
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_PGUP, KC_NUM, KC_PSLS, KC_PAST, KC_PMNS,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, KC_P7, KC_P8, KC_P9, KC_PPLS,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_HOME, KC_P4, KC_P5, KC_P6,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, TD(TD_HOME_END), KC_P4, KC_P5, KC_P6,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_P1, KC_P2, KC_P3, KC_PENT,
KC_LCTL, KC_LOPTN, KC_LCMMD, KC_SPC, KC_RCMMD, MO(MAC_FN), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT, KC_P0, KC_PDOT ),
@@ -75,3 +81,9 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
}
return true;
}
// Tap Dance definitions
tap_dance_action_t tap_dance_actions[] = {
// Tap once for Home, twice for End
[TD_HOME_END] = ACTION_TAP_DANCE_DOUBLE(KC_HOME, KC_END),
};
@@ -1 +1,2 @@
VIA_ENABLE = yes
TAP_DANCE_ENABLE = yes
@@ -0,0 +1,54 @@
/* Copyright 2023 @ 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
#ifdef RGB_MATRIX_ENABLE
/* RGB Matrix driver configuration */
# define DRIVER_COUNT 2
# define RGB_MATRIX_LED_COUNT 70
# define SPI_SCK_PIN A5
# define SPI_MISO_PIN A6
# define SPI_MOSI_PIN A7
# define DRIVER_CS_PINS \
{ B8, B9 }
# define SNLED23751_SPI_DIVISOR 16
# define SPI_DRIVER SPID1
/* Scan phase of led driver set as MSKPHASE_9CHANNEL(defined as 0x03 in snled27351.h) */
# define PHASE_CHANNEL MSKPHASE_9CHAN
/* Set LED driver current */
# define SNLED27351_CURRENT_TUNE \
{ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 }
/* Set to infinit, which is use in USB mode by default */
# define RGB_MATRIX_TIMEOUT RGB_MATRIX_TIMEOUT_INFINITE
/* Allow shutdown of led driver to save power */
# define RGB_MATRIX_DRIVER_SHUTDOWN_ENABLE
/* Turn off backlight on low brightness to save power */
# define RGB_MATRIX_BRIGHTNESS_TURN_OFF_VAL 32
/* Indications */
# define CAPS_LOCK_INDEX 29
# define LOW_BAT_IND_INDEX \
{ 63 }
# define RGB_MATRIX_KEYPRESSES
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
#endif
@@ -0,0 +1,87 @@
{
"usb": {
"pid": "0x0822",
"device_version": "1.0.0"
},
"layouts": {
"LAYOUT_jis_71": {
"layout": [
{"matrix": [0, 0], "x": 0, "y": 0},
{"matrix": [0, 1], "x": 1, "y": 0},
{"matrix": [0, 2], "x": 2, "y": 0},
{"matrix": [0, 3], "x": 3, "y": 0},
{"matrix": [0, 4], "x": 4, "y": 0},
{"matrix": [0, 5], "x": 5, "y": 0},
{"matrix": [0, 6], "x": 6, "y": 0},
{"matrix": [0, 7], "x": 7, "y": 0},
{"matrix": [0, 8], "x": 8, "y": 0},
{"matrix": [0, 9], "x": 9, "y": 0},
{"matrix": [0, 10], "x": 10, "y": 0},
{"matrix": [0, 11], "x": 11, "y": 0},
{"matrix": [0, 12], "x": 12, "y": 0},
{"matrix": [0, 13], "x": 13, "y": 0 },
{"matrix": [0, 14], "x": 14, "y": 0},
{"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5 },
{"matrix": [1, 1], "x": 1.5, "y": 1},
{"matrix": [1, 2], "x": 2.5, "y": 1},
{"matrix": [1, 3], "x": 3.5, "y": 1},
{"matrix": [1, 4], "x": 4.5, "y": 1},
{"matrix": [1, 5], "x": 5.5, "y": 1},
{"matrix": [1, 6], "x": 6.5, "y": 1},
{"matrix": [1, 7], "x": 7.5, "y": 1},
{"matrix": [1, 8], "x": 8.5, "y": 1},
{"matrix": [1, 9], "x": 9.5, "y": 1},
{"matrix": [1, 10], "x": 10.5, "y": 1},
{"matrix": [1, 11], "x": 11.5, "y": 1},
{"matrix": [1, 12], "x": 12.5, "y": 1},
{"matrix": [1, 13], "x": 13.5, "y": 1, "w": 1.5,"h": 2},
{"matrix": [1, 14], "x": 15.25, "y": 1},
{"matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
{"matrix": [2, 1], "x": 1.75, "y": 2},
{"matrix": [2, 2], "x": 2.75, "y": 2},
{"matrix": [2, 3], "x": 3.75, "y": 2},
{"matrix": [2, 4], "x": 4.75, "y": 2},
{"matrix": [2, 5], "x": 5.75, "y": 2},
{"matrix": [2, 6], "x": 6.75, "y": 2},
{"matrix": [2, 7], "x": 7.75, "y": 2},
{"matrix": [2, 8], "x": 8.75, "y": 2},
{"matrix": [2, 9], "x": 9.75, "y": 2},
{"matrix": [2, 10], "x": 10.75, "y": 2},
{"matrix": [2, 11], "x": 11.75, "y": 2},
{"matrix": [2, 12], "x": 12.75, "y": 2},
{"matrix": [2, 13], "x": 15.25, "y": 2},
{"matrix": [2, 14], "x": 15.25, "y": 0},
{"matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
{"matrix": [3, 2], "x": 2.25, "y": 3},
{"matrix": [3, 3], "x": 3.25, "y": 3},
{"matrix": [3, 4], "x": 4.25, "y": 3},
{"matrix": [3, 5], "x": 5.25, "y": 3},
{"matrix": [3, 6], "x": 6.25, "y": 3},
{"matrix": [3, 7], "x": 7.25, "y": 3},
{"matrix": [3, 8], "x": 8.25, "y": 3},
{"matrix": [3, 9], "x": 9.25, "y": 3},
{"matrix": [3, 10], "x": 10.25, "y": 3},
{"matrix": [3, 11], "x": 11.25, "y": 3},
{"matrix": [3, 12], "x": 12.25, "y": 3},
{"matrix": [3, 13], "x": 13.25, "y": 3},
{"matrix": [3, 14], "x": 14.25, "y": 3},
{"matrix": [4, 0], "x": 0, "y": 4, "w": 1.25},
{"matrix": [4, 1], "x": 1.25, "y": 4 },
{"matrix": [4, 2], "x": 2.25, "y": 4, "w": 1.25},
{"matrix": [4, 3], "x": 3.5, "y": 4 },
{"matrix": [4, 6], "x": 4.5, "y": 4, "w": 4.5},
{"matrix": [4, 8], "x": 9, "y": 4 },
{"matrix": [4, 9], "x": 10, "y": 4, "w": 1.25},
{"matrix": [4, 10], "x": 11.25, "y": 4},
{"matrix": [4, 11], "x": 12.25, "y": 4},
{"matrix": [4, 12], "x": 13.25, "y": 4},
{"matrix": [4, 13], "x": 14.25, "y": 4},
{"matrix": [4, 14], "x": 15.25, "y": 4}
]
}
}
}
@@ -0,0 +1,133 @@
/* Copyright 2023 @ 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"
// clang-format off
#ifdef RGB_MATRIX_ENABLE
const snled27351_led_t g_snled27351_leds[RGB_MATRIX_LED_COUNT] = {
/* Refer to SNLED27351 manual for these locations
* driver
* | R location
* | | G location
* | | | B location
* | | | | */
{0, A_15, C_15, B_15},
{0, A_14, C_14, B_14},
{0, A_13, C_13, B_13},
{0, A_12, C_12, B_12},
{0, A_11, C_11, B_11},
{0, A_10, C_10, B_10},
{0, A_9, C_9, B_9},
{0, A_8, C_8, B_8},
{0, A_7, C_7, B_7},
{0, A_6, C_6, B_6},
{0, A_5, C_5, B_5},
{0, A_4, C_4, B_4},
{0, A_3, C_3, B_3},
{0, A_2, C_2, B_2},
{0, A_1, C_1, B_1},
{0, D_15, F_15, E_15},
{0, D_14, F_14, E_14},
{0, D_13, F_13, E_13},
{0, D_12, F_12, E_12},
{0, D_11, F_11, E_11},
{0, D_10, F_10, E_10},
{0, D_9, F_9, E_9},
{0, D_8, F_8, E_8},
{0, D_7, F_7, E_7},
{0, D_6, F_6, E_6},
{0, D_5, F_5, E_5},
{0, D_4, F_4, E_4},
{0, D_3, F_3, E_3},
{0, D_2, F_2, E_2},
{0, D_1, F_1, E_1},
{1, A_15, C_15, B_15},
{1, A_14, C_14, B_14},
{1, A_13, C_13, B_13},
{1, A_12, C_12, B_12},
{1, A_11, C_11, B_11},
{1, A_10, C_10, B_10},
{1, A_9, C_9, B_9},
{1, A_8, C_8, B_8},
{1, A_7, C_7, B_7},
{1, A_6, C_6, B_6},
{1, A_5, C_5, B_5},
{1, A_4, C_4, B_4},
{1, A_3, C_3, B_3},
{1, A_2, C_2, B_2},
{1, G_15, I_15, H_15},
{1, G_13, I_13, H_13},
{1, G_12, I_12, H_12},
{1, G_11, I_11, H_11},
{1, G_10, I_10, H_10},
{1, G_9, I_9, H_9},
{1, G_8, I_8, H_8},
{1, G_7, I_7, H_7},
{1, G_6, I_6, H_6},
{1, G_5, I_5, H_5},
{1, G_4, I_4, H_4},
{1, G_3, I_3, H_3},
{1, G_2, I_2, H_2},
{1, G_1, I_1, H_1},
{1, D_15, F_15, E_15},
{1, D_14, F_14, E_14},
{1, D_13, F_13, E_13},
{1, D_12, F_12, E_12},
{1, D_9, F_9, E_9},
{1, D_7, F_7, E_7},
{1, D_6, F_6, E_6},
{1, D_5, F_5, E_5},
{1, D_4, F_4, E_4},
{1, D_3, F_3, E_3},
{1, D_2, F_2, E_2},
{1, D_1, F_1, E_1},
};
#define __ NO_LED
led_config_t g_led_config = {
{
// Key Matrix to LED Index
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 },
{ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 },
{ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, __ },
{ 44, __, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57 },
{ 58, 59, 60, 61, __, __, 62, __, 63, 64, 65, 66, 67, 68, 69 },
},
{
// LED Index to Physical Position
{0, 0}, {15, 0}, {29, 0}, {44, 0}, {59, 0}, {73, 0}, {88, 0}, {103, 0}, {117, 0}, {132, 0}, {146, 0}, {161, 0}, {176, 0}, {190, 0}, {205, 0},
{4,15}, {21,15}, {36,15}, {51,15}, {66,15}, {81,15}, {96,15}, {111,15}, {125,15}, {140,15}, {154,15}, {169,15}, {184,15}, {201,15}, {224,15},
{6,26}, {25,26}, {40,26}, {55,26}, {69,26}, {84,26}, {99,26}, {114,26}, {129,26}, {144,26}, {158,26}, {173,26}, {188,26}, {224,26},
{8,38}, {32,38}, {48,38}, {62,38}, {77,38}, {92,38}, {106,38}, {121,38}, {136,38}, {150,38}, {165,38}, {179,38}, {194,38}, {209,38},
{2,49}, {20,49}, {36,49}, {51,49}, {92,49}, {132,49}, {148,49}, {161,49}, {176,49}, {195,49}, {209,49}, {224,49}
},
{
// RGB LED Index to Flag
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
}
};
#endif
@@ -0,0 +1,83 @@
/* Copyright 2023 @ 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 "keychron_common.h"
enum layers {
MAC_BASE,
WIN_BASE,
MAC_FN1,
WIN_FN1,
FN2,
};
// clang-format off
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[MAC_BASE] = LAYOUT_jis_71(
KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_INT3, KC_BSPC,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_ENT, KC_DEL,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_BSLS, KC_HOME, KC_MUTE,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_INT1, KC_RSFT, KC_UP,
KC_LCTL, KC_LOPTN, KC_LCMMD,KC_LNG2, KC_SPC, KC_LNG1, KC_RCMMD,MO(MAC_FN1),MO(FN2), KC_LEFT, KC_DOWN, KC_RGHT),
[WIN_BASE] = LAYOUT_jis_71(
KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_INT3, KC_BSPC,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_ENT, KC_DEL,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_BSLS, KC_HOME, KC_MUTE,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_INT1, KC_RSFT, KC_UP,
KC_LCTL, KC_LGUI, KC_LALT,KC_INT5, KC_SPC, KC_INT4, KC_RALT, MO(WIN_FN1),MO(FN2), KC_LEFT, KC_DOWN, KC_RGHT),
[MAC_FN1] = LAYOUT_jis_71(
KC_GRV, KC_BRID, KC_BRIU, KC_MCTRL, KC_LNPAD, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______, _______, _______, KC_END, RGB_TOG,
_______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, NK_TOGG, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______),
[WIN_FN1] = LAYOUT_jis_71(
KC_GRV, KC_BRID, KC_BRIU, KC_TASK, KC_FILE, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______, _______, _______, KC_END, RGB_TOG,
_______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, NK_TOGG, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______),
[FN2] = LAYOUT_jis_71(
KC_TILD, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, BAT_LVL, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______)
};
// clang-format on
#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
[MAC_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU) },
[WIN_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU) },
[MAC_FN1] = { ENCODER_CCW_CW(RGB_VAD, RGB_VAI) },
[WIN_FN1] = { ENCODER_CCW_CW(RGB_VAD, RGB_VAI) },
[FN2] = { ENCODER_CCW_CW(_______, _______) },
};
#endif // ENCODER_MAP_ENABLE
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
if (!process_record_keychron_common(keycode, record)) {
return false;
}
return true;
}
@@ -0,0 +1,83 @@
/* Copyright 2023 @ 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 "keychron_common.h"
enum layers {
MAC_BASE,
WIN_BASE,
MAC_FN1,
WIN_FN1,
FN2,
};
// clang-format off
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[MAC_BASE] = LAYOUT_jis_71(
KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_INT3, KC_BSPC,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_ENT, KC_DEL,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_BSLS, KC_HOME, KC_MUTE,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_INT1, KC_RSFT, KC_UP,
KC_LCTL, KC_LOPTN, KC_LCMMD,KC_LNG2, KC_SPC, KC_LNG1, KC_RCMMD,MO(MAC_FN1),MO(FN2), KC_LEFT, KC_DOWN, KC_RGHT),
[WIN_BASE] = LAYOUT_jis_71(
KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_INT3, KC_BSPC,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_ENT, KC_DEL,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_BSLS, KC_HOME, KC_MUTE,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_INT1, KC_RSFT, KC_UP,
KC_LCTL, KC_LGUI, KC_LALT,KC_INT5, KC_SPC, KC_INT4, KC_RALT, MO(WIN_FN1),MO(FN2), KC_LEFT, KC_DOWN, KC_RGHT),
[MAC_FN1] = LAYOUT_jis_71(
KC_GRV, KC_BRID, KC_BRIU, KC_MCTRL, KC_LNPAD, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______, _______, _______, KC_END, RGB_TOG,
_______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, NK_TOGG, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______ ),
[WIN_FN1] = LAYOUT_jis_71(
KC_GRV, KC_BRID, KC_BRIU, KC_TASK, KC_FILE, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______, _______, _______, KC_END, RGB_TOG,
_______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, NK_TOGG, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______ ),
[FN2] = LAYOUT_jis_71(
KC_TILD, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, BAT_LVL, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______ )
};
// clang-format on
#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
[MAC_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU) },
[WIN_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU) },
[MAC_FN1] = { ENCODER_CCW_CW(RGB_VAD, RGB_VAI) },
[WIN_FN1] = { ENCODER_CCW_CW(RGB_VAD, RGB_VAI) },
[FN2] = { ENCODER_CCW_CW(_______, _______) },
};
#endif // ENCODER_MAP_ENABLE
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
if (!process_record_keychron_common(keycode, record)) {
return false;
}
return true;
}
@@ -0,0 +1 @@
VIA_ENABLE = yes
@@ -0,0 +1 @@
# This file intentionally left blank
@@ -55,7 +55,6 @@
{"matrix": [2, 10], "x": 10.5, "y": 2.25},
{"matrix": [2, 11], "x": 11.5, "y": 2.25},
{"matrix": [2, 12], "x": 12.5, "y": 2.25},
{"matrix": [2, 13], "x": 13.5, "y": 2.25,"w":1.5,"h":2},
{"matrix": [2, 14], "x": 15.25, "y": 2.25},
{"matrix": [2, 15], "x": 16.25, "y": 2.25},
{"matrix": [2, 16], "x": 17.25, "y": 2.25},
@@ -73,7 +72,7 @@
{"matrix": [3, 10], "x": 10.75, "y": 3.25},
{"matrix": [3, 11], "x": 11.75, "y": 3.25},
{"matrix": [3, 12], "x": 12.75, "y": 3.25},
{"matrix": [2, 13], "x": 13.75, "y": 2.25,"w":1.25,"h":2},
{"matrix": [4, 0], "x": 0, "y": 4.25, "w": 1.25},
{"matrix": [4, 1], "x": 1.25, "y": 4.25},
@@ -87,7 +86,7 @@
{"matrix": [4, 9], "x": 9.25, "y": 4.25},
{"matrix": [4, 10], "x": 10.25, "y": 4.25},
{"matrix": [4, 11], "x": 11.25, "y": 4.25},
{"matrix": [4, 13], "x": 12.25, "y": 4.25, "w": 2.25},
{"matrix": [4, 13], "x": 12.25, "y": 4.25, "w": 2.75},
{"matrix": [4, 15], "x": 16.25, "y": 4.25},
{"matrix": [5, 0], "x": 0, "y": 5.25, "w": 1.25},
@@ -0,0 +1,54 @@
/* Copyright 2023 @ 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
#ifdef RGB_MATRIX_ENABLE
/* RGB Matrix driver configuration */
# define DRIVER_COUNT 2
# define RGB_MATRIX_LED_COUNT 92
# define SPI_SCK_PIN A5
# define SPI_MISO_PIN A6
# define SPI_MOSI_PIN A7
# define DRIVER_CS_PINS \
{ B8, B9 }
# define SNLED23751_SPI_DIVISOR 16
# define SPI_DRIVER SPID1
/* Scan phase of led driver set as MSKPHASE_9CHANNEL(defined as 0x03 in snled27351.h) */
# define PHASE_CHANNEL MSKPHASE_9CHANNEL
/* Set LED driver current */
# define SNLED27351_CURRENT_TUNE \
{ 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34 }
/* Set to infinit, which is use in USB mode by default */
# define RGB_MATRIX_TIMEOUT RGB_MATRIX_TIMEOUT_INFINITE
/* Allow shutdown of led driver to save power */
# define RGB_MATRIX_DRIVER_SHUTDOWN_ENABLE
/* Turn off backlight on low brightness to save power */
# define RGB_MATRIX_BRIGHTNESS_TURN_OFF_VAL 32
/* Caps lock indicating led */
# define CAPS_LOCK_INDEX 51
# define RGB_MATRIX_KEYPRESSES
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
#endif
@@ -0,0 +1,109 @@
{
"usb": {
"pid": "0x0832",
"device_version": "1.0.0"
},
"layouts": {
"LAYOUT_jis_92": {
"layout": [
{"matrix": [0, 0], "x": 0, "y": 0},
{"matrix": [0, 1], "x": 1.25, "y": 0},
{"matrix": [0, 2], "x": 2.25, "y": 0},
{"matrix": [0, 3], "x": 3.25, "y": 0},
{"matrix": [0, 4], "x": 4.25, "y": 0},
{"matrix": [0, 5], "x": 5.5, "y": 0},
{"matrix": [0, 6], "x": 6.5, "y": 0},
{"matrix": [0, 7], "x": 7.5, "y": 0},
{"matrix": [0, 8], "x": 8.5, "y": 0},
{"matrix": [0, 9], "x": 9.75, "y": 0},
{"matrix": [0, 10], "x": 10.75, "y": 0},
{"matrix": [0, 11], "x": 11.75, "y": 0},
{"matrix": [0, 12], "x": 12.75, "y": 0},
{"matrix": [0, 13], "x": 14, "y": 0},
{"matrix": [0, 14], "x": 15.25, "y": 0},
{"matrix": [0, 15], "x": 16.25, "y": 0},
{"matrix": [0, 16], "x": 17.25, "y": 0},
{"matrix": [1, 0], "x": 0, "y": 1.25},
{"matrix": [1, 1], "x": 1, "y": 1.25},
{"matrix": [1, 2], "x": 2, "y": 1.25},
{"matrix": [1, 3], "x": 3, "y": 1.25},
{"matrix": [1, 4], "x": 4, "y": 1.25},
{"matrix": [1, 5], "x": 5, "y": 1.25},
{"matrix": [1, 6], "x": 6, "y": 1.25},
{"matrix": [1, 7], "x": 7, "y": 1.25},
{"matrix": [1, 8], "x": 8, "y": 1.25},
{"matrix": [1, 9], "x": 9, "y": 1.25},
{"matrix": [1, 10], "x": 10, "y": 1.25},
{"matrix": [1, 11], "x": 11, "y": 1.25},
{"matrix": [1, 12], "x": 12, "y": 1.25},
{"matrix": [1, 13], "x": 13, "y": 1.25},
{"matrix": [3, 13], "x": 14, "y": 1.25},
{"matrix": [1, 14], "x": 15.25, "y": 1.25},
{"matrix": [1, 15], "x": 16.25, "y": 1.25},
{"matrix": [1, 16], "x": 17.25, "y": 1.25},
{"matrix": [2, 0], "x": 0, "y": 2.25, "w": 1.5},
{"matrix": [2, 1], "x": 1.5, "y": 2.25},
{"matrix": [2, 2], "x": 2.5, "y": 2.25},
{"matrix": [2, 3], "x": 3.5, "y": 2.25},
{"matrix": [2, 4], "x": 4.5, "y": 2.25},
{"matrix": [2, 5], "x": 5.5, "y": 2.25},
{"matrix": [2, 6], "x": 6.5, "y": 2.25},
{"matrix": [2, 7], "x": 7.5, "y": 2.25},
{"matrix": [2, 8], "x": 8.5, "y": 2.25},
{"matrix": [2, 9], "x": 9.5, "y": 2.25},
{"matrix": [2, 10], "x": 10.5, "y": 2.25},
{"matrix": [2, 11], "x": 11.5, "y": 2.25},
{"matrix": [2, 12], "x": 12.5, "y": 2.25},
{"matrix": [2, 14], "x": 15.25, "y": 2.25},
{"matrix": [2, 15], "x": 16.25, "y": 2.25},
{"matrix": [2, 16], "x": 17.25, "y": 2.25},
{"matrix": [3, 0], "x": 0, "y": 3.25, "w": 1.75},
{"matrix": [3, 1], "x": 1.75, "y": 3.25},
{"matrix": [3, 2], "x": 2.75, "y": 3.25},
{"matrix": [3, 3], "x": 3.75, "y": 3.25},
{"matrix": [3, 4], "x": 4.75, "y": 3.25},
{"matrix": [3, 5], "x": 5.75, "y": 3.25},
{"matrix": [3, 6], "x": 6.75, "y": 3.25},
{"matrix": [3, 7], "x": 7.75, "y": 3.25},
{"matrix": [3, 8], "x": 8.75, "y": 3.25},
{"matrix": [3, 9], "x": 9.75, "y": 3.25},
{"matrix": [3, 10], "x": 10.75, "y": 3.25},
{"matrix": [3, 11], "x": 11.75, "y": 3.25},
{"matrix": [3, 12], "x": 12.75, "y": 3.25},
{"matrix": [2, 13], "x": 13.75, "y": 2.25,"w":1.25,"h":2},
{"matrix": [4, 0], "x": 0, "y": 4.25, "w": 2.25},
{"matrix": [4, 2], "x": 2.25, "y": 4.25},
{"matrix": [4, 3], "x": 3.25, "y": 4.25},
{"matrix": [4, 4], "x": 4.25, "y": 4.25},
{"matrix": [4, 5], "x": 5.25, "y": 4.25},
{"matrix": [4, 6], "x": 6.25, "y": 4.25},
{"matrix": [4, 7], "x": 7.25, "y": 4.25},
{"matrix": [4, 8], "x": 8.25, "y": 4.25},
{"matrix": [4, 9], "x": 9.25, "y": 4.25},
{"matrix": [4, 10], "x": 10.25, "y": 4.25},
{"matrix": [4, 11], "x": 11.25, "y": 4.25},
{"matrix": [4, 12], "x": 12.25, "y": 4.25},
{"matrix": [4, 13], "x": 13.25, "y": 4.25,"w": 1.75},
{"matrix": [4, 15], "x": 16.25, "y": 4.25},
{"matrix": [5, 0], "x": 0, "y": 5.25, "w": 1.25},
{"matrix": [5, 1], "x": 1.25, "y": 5.25},
{"matrix": [5, 2], "x": 2.25, "y": 5.25, "w": 1.25},
{"matrix": [5, 3], "x": 3.5, "y": 5.25},
{"matrix": [5, 6], "x": 4.5, "y": 5.25, "w": 4.5},
{"matrix": [5, 9], "x": 9, "y": 5.25},
{"matrix": [5, 10], "x": 10, "y": 5.25,"w": 1.25},
{"matrix": [5, 11], "x": 11.25, "y": 5.25, "w": 1.25},
{"matrix": [5, 12], "x": 12.5, "y": 5.25, "w": 1.25},
{"matrix": [5, 13], "x": 13.75, "y": 5.25, "w": 1.25},
{"matrix": [5, 14], "x": 15.25, "y": 5.25},
{"matrix": [5, 15], "x": 16.25, "y": 5.25},
{"matrix": [5, 16], "x": 17.25, "y": 5.25}
]
}
}
}
@@ -0,0 +1,159 @@
/* Copyright 2023 @ 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"
// clang-format off
#ifdef RGB_MATRIX_ENABLE
const snled27351_led_t g_snled27351_leds[RGB_MATRIX_LED_COUNT] = {
/* Refer to SNLED27351 manual for these locations
* driver
* | R location
* | | G location
* | | | B location
* | | | | */
{0, G_15, I_15, H_15},
{0, G_14, I_14, H_14},
{0, G_13, I_13, H_13},
{0, G_12, I_12, H_12},
{0, G_11, I_11, H_11},
{0, G_10, I_10, H_10},
{0, G_9, I_9, H_9},
{0, G_8, I_8, H_8},
{0, G_7, I_7, H_7},
{0, G_6, I_6, H_6},
{0, G_5, I_5, H_5},
{0, G_4, I_4, H_4},
{0, G_3, I_3, H_3},
{0, G_2, I_2, H_2},
{0, G_1, I_1, H_1},
{0, D_6, F_6, E_6},
{0, D_5, F_5, E_5},
{0, A_15, C_15, B_15},
{0, A_14, C_14, B_14},
{0, A_13, C_13, B_13},
{0, A_12, C_12, B_12},
{0, A_11, C_11, B_11},
{0, A_10, C_10, B_10},
{0, A_9, C_9, B_9},
{0, A_8, C_8, B_8},
{0, A_7, C_7, B_7},
{0, A_6, C_6, B_6},
{0, A_5, C_5, B_5},
{0, A_4, C_4, B_4},
{0, A_3, C_3, B_3},
{0, A_2, C_2, B_2},
{0, A_1, C_1, B_1},
{0, D_4, F_4, E_4},
{0, D_3, F_3, E_3},
{0, J_15, L_15, K_15},
{0, J_14, L_14, K_14},
{0, J_13, L_13, K_13},
{0, J_12, L_12, K_12},
{0, J_11, L_11, K_11},
{0, J_10, L_10, K_10},
{0, J_9, L_9, K_9},
{0, J_8, L_8, K_8},
{0, J_7, L_7, K_7},
{0, J_6, L_6, K_6},
{0, J_5, L_5, K_5},
{0, J_4, L_4, K_4},
{0, J_3, L_3, K_3},
{0, J_2, L_2, K_2},
{0, J_1, L_1, K_1},
{0, D_2, F_2, E_2},
{0, D_1, F_1, E_1},
{1, A_15, C_15, B_15},
{1, A_14, C_14, B_14},
{1, A_13, C_13, B_13},
{1, A_12, C_12, B_12},
{1, A_11, C_11, B_11},
{1, A_10, C_10, B_10},
{1, A_9, C_9, B_9},
{1, A_8, C_8, B_8},
{1, A_7, C_7, B_7},
{1, A_6, C_6, B_6},
{1, A_5, C_5, B_5},
{1, A_4, C_4, B_4},
{1, A_3, C_3, B_3},
{1, A_2, C_2, B_2},
{1, G_15, I_15, H_15},
{1, G_13, I_13, H_13},
{1, G_12, I_12, H_12},
{1, G_11, I_11, H_11},
{1, G_10, I_10, H_10},
{1, G_9, I_9, H_9},
{1, G_8, I_8, H_8},
{1, G_7, I_7, H_7},
{1, G_6, I_6, H_6},
{1, G_5, I_5, H_5},
{1, G_4, I_4, H_4},
{1, G_3, I_3, H_3},
{1, G_2, I_2, H_2},
{1, G_1, I_1, H_1},
{1, D_15, F_15, E_15},
{1, D_14, F_14, E_14},
{1, D_13, F_13, E_13},
{1, D_12, F_12, E_12},
{1, D_9, F_9, E_9},
{1, D_8, F_8, E_8},
{1, D_7, F_7, E_7},
{1, D_6, F_6, E_6},
{1, D_5, F_5, E_5},
{1, D_4, F_4, E_4},
{1, D_3, F_3, E_3},
{1, D_2, F_2, E_2},
{1, D_1, F_1, E_1},
};
#define __ NO_LED
led_config_t g_led_config = {
{
// Key Matrix to LED Index
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 },
{ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33 },
{ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50 },
{ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, __, __, __ },
{ 65, __, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, __, 78, __ },
{ 79, 80, 81, 82, __, __, 83, __, __, 84, 85, 86, 87, 88, 89, 90, 91 },
},
{
// LED Index to Physical Position
{0, 0}, {16, 0}, {29, 0}, {42, 0}, {54, 0}, {70, 0}, {84, 0}, {97, 0}, {110, 0}, {126, 0}, {139, 0}, {152, 0}, {165,0}, {182, 0}, {198, 0}, {211,0}, {224,0},
{0,15}, {13,15}, {26,15}, {39,15}, {52,15}, {65,15}, {78,15}, {91,15}, {104,15}, {117,15}, {130,15}, {143,15}, {156,15}, {169,15}, {198,15}, {211,15}, {224,15},
{3,28}, {20,28}, {33,28}, {46,28}, {59,28}, {72,28}, {85,28}, {98,28}, {111,28}, {124,28}, {137,28}, {150,28}, {163,28}, {178,34}, {198,28}, {211,28}, {224,28},
{5,40}, {23,40}, {36,40}, {49,40}, {62,40}, {75,40}, {88,40}, {101,40}, {114,40}, {127,40}, {140,40}, {150,40}, {182,15}, {166,40},
{8,52}, {29,52}, {42,52}, {55,52}, {68,52}, {81,52}, {94,52}, {107,52}, {120,52}, {133,52}, {146,52}, {159,52}, {176,52}, {211,52},
{2,64}, {16,64}, {31,64}, {46,64}, {83,64}, {118,64}, {131,64}, {148,64}, {164,64}, {178,64}, {198,64}, {211,64}, {224,64}
},
{
// RGB LED Index to Flag
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1,
1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1,
8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 1,
1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 1,
1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1
}
};
#endif
@@ -0,0 +1,82 @@
/* Copyright 2023 @ 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 "keychron_common.h"
enum layers {
MAC_BASE,
MAC_FN,
WIN_BASE,
WIN_FN,
};
#define FN_MAC MO(MAC_FN)
#define FN_WIN MO(WIN_FN)
// clang-format off
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[MAC_BASE] = LAYOUT_jis_92(
KC_ESC, KC_BRID, KC_BRIU, KC_MCTRL, KC_LNPAD, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_MUTE, KC_SNAP, KC_SIRI, RGB_MOD,
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_INT3, KC_BSPC, KC_INS, KC_HOME, KC_PGUP,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_DEL, KC_END, KC_PGDN,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_BSLS, KC_ENT,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_INT1, KC_RSFT, KC_UP,
KC_LCTL, KC_LOPTN, KC_LCMMD, KC_LNG2, KC_SPC, KC_LNG1, KC_RCMMD, KC_ROPTN, FN_MAC, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT),
[MAC_FN] = LAYOUT_jis_92(
_______, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, RGB_TOG, _______, _______, RGB_TOG,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, BAT_LVL, NK_TOGG, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______)
,
[WIN_BASE] = LAYOUT_jis_92(
KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_MUTE, KC_PSCR, KC_CTANA, RGB_MOD,
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_INT3, KC_BSPC, KC_INS, KC_HOME, KC_PGUP,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_DEL, KC_END, KC_PGDN,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_BSLS, KC_ENT,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_INT1, KC_RSFT, KC_UP,
KC_LCTL, KC_LWIN, KC_LALT, KC_INT5, KC_SPC, KC_INT4, KC_RALT, KC_RWIN, WIN_FN, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT),
[WIN_FN] = LAYOUT_jis_92(
_______, KC_BRID, KC_BRIU, KC_TASK, KC_FILE, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, RGB_TOG, _______, _______, RGB_TOG,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, BAT_LVL, NK_TOGG, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______)
};
// clang-format on
#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
[MAC_BASE] = {ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
[MAC_FN] = {ENCODER_CCW_CW(RGB_VAD, RGB_VAI)},
[WIN_BASE] = {ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
[WIN_FN] = {ENCODER_CCW_CW(RGB_VAD, RGB_VAI)},
};
#endif // ENCODER_MAP_ENABLE
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
if (!process_record_keychron_common(keycode, record)) {
return false;
}
return true;
}
@@ -0,0 +1,82 @@
/* Copyright 2023 @ 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 "keychron_common.h"
enum layers {
MAC_BASE,
MAC_FN,
WIN_BASE,
WIN_FN,
};
#define FN_MAC MO(MAC_FN)
#define FN_WIN MO(WIN_FN)
// clang-format off
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[MAC_BASE] = LAYOUT_jis_92(
KC_ESC, KC_BRID, KC_BRIU, KC_MCTRL, KC_LNPAD, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_MUTE, KC_SNAP, KC_SIRI, RGB_MOD,
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_INT3, KC_BSPC, KC_INS, KC_HOME, KC_PGUP,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_DEL, KC_END, KC_PGDN,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_BSLS, KC_ENT,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_INT1, KC_RSFT, KC_UP,
KC_LCTL, KC_LOPTN, KC_LCMMD, KC_LNG2, KC_SPC, KC_LNG1, KC_RCMMD, KC_ROPTN, FN_MAC, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT),
[MAC_FN] = LAYOUT_jis_92(
_______, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, RGB_TOG, _______, _______, RGB_TOG,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, BAT_LVL, NK_TOGG, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______)
,
[WIN_BASE] = LAYOUT_jis_92(
KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_MUTE, KC_PSCR, KC_CTANA, RGB_MOD,
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_INT3, KC_BSPC, KC_INS, KC_HOME, KC_PGUP,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_DEL, KC_END, KC_PGDN,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_BSLS, KC_ENT,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_INT1, KC_RSFT, KC_UP,
KC_LCTL, KC_LWIN, KC_LALT, KC_INT5, KC_SPC, KC_INT4, KC_RALT, KC_RWIN, WIN_FN, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT),
[WIN_FN] = LAYOUT_jis_92(
_______, KC_BRID, KC_BRIU, KC_TASK, KC_FILE, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, RGB_TOG, _______, _______, RGB_TOG,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, BAT_LVL, NK_TOGG, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______)
};
// clang-format on
#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
[MAC_BASE] = {ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
[MAC_FN] = {ENCODER_CCW_CW(RGB_VAD, RGB_VAI)},
[WIN_BASE] = {ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
[WIN_FN] = {ENCODER_CCW_CW(RGB_VAD, RGB_VAI)},
};
#endif // ENCODER_MAP_ENABLE
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
if (!process_record_keychron_common(keycode, record)) {
return false;
}
return true;
}
@@ -0,0 +1 @@
VIA_ENABLE = yes
@@ -0,0 +1 @@
# This file intentionally left blank
@@ -20,12 +20,10 @@
/* RGB Matrix driver configuration */
# define RGB_MATRIX_LED_COUNT 101
# define DRIVER_COUNT 2
# define DRIVER_CS_PINS \
{ B8, B9 }
# define DRIVER_CS_PINS {B8, B9}
/* Set LED driver current */
# define SNLED27351_CURRENT_TUNE \
{ 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C }
# define SNLED27351_CURRENT_TUNE {0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C}
/* Set to infinit, which is use in USB mode by default */
# define RGB_MATRIX_TIMEOUT RGB_MATRIX_TIMEOUT_INFINITE
@@ -37,10 +35,15 @@
/* Indications */
# define NUM_LOCK_INDEX 32
# define CAPS_LOCK_INDEX 55
# define LOW_BAT_IND_INDEX \
{ 92 }
# define LOW_BAT_IND_INDEX {92}
# define RGB_MATRIX_KEYPRESSES
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
#endif
/* Number of layers */
#define DYNAMIC_KEYMAP_LAYER_COUNT 6
/* Number of taps to toggle layer with TT */
#define TAPPING_TOGGLE 3
@@ -17,40 +17,74 @@
#include QMK_KEYBOARD_H
#include "keychron_common.h"
// Tap Dance declarations
enum {
TD_HOME_END,
};
// Custom keycodes
enum custom_keycodes {
ALT_TAB_FWD = SAFE_RANGE, // Alt+Tab (forward)
ALT_TAB_BWD, // Alt+Shift+Tab (backward)
};
// Alt-Tab cycling state
static bool alt_tab_active = false;
static uint16_t alt_tab_timer = 0;
#define ALT_TAB_TIMEOUT 750 // ms to hold Alt after last encoder tick
enum layers {
MAC_BASE,
MAC_FN,
WIN_BASE,
WIN_FN,
BASE,
FN1,
FN2,
FN3,
FN4,
KEEB_CTL,
};
// clang-format off
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[MAC_BASE] = LAYOUT_ansi_101(
KC_ESC, KC_BRID, KC_BRIU, KC_MCTRL, KC_LNPAD, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_DEL, KC_F13, KC_F14 , KC_F15, KC_MUTE,
[BASE] = LAYOUT_ansi_101(
KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL, KC_PSCR, KC_CALC, KC_FIND, KC_MPLY,
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_PGUP, KC_NUM, KC_PSLS, KC_PAST, KC_PMNS,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, KC_P7, KC_P8, KC_P9,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_HOME, KC_P4, KC_P5, KC_P6, KC_PPLS,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, TD(TD_HOME_END), KC_P4, KC_P5, KC_P6, KC_PPLS,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_P1, KC_P2, KC_P3,
KC_LCTL, KC_LOPTN, KC_LCMMD, KC_SPC, KC_RCMMD, MO(MAC_FN), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT, KC_P0, KC_PDOT, KC_PENT),
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, TT(FN2), TT(FN1), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT, KC_P0, KC_PDOT, KC_PENT),
[MAC_FN] = LAYOUT_ansi_101(
_______, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, _______, _______, _______, _______, RGB_TOG,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, _______, _______, _______, _______, _______, _______, _______, KC_END, _______, _______, _______, _______,
_______, _______, _______, _______, _______, BAT_LVL, NK_TOGG, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______),
[WIN_BASE] = LAYOUT_ansi_101(
KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL, _______, _______, _______, KC_MUTE,
[FN1] = LAYOUT_ansi_101(
KC_ESC, KC_BRID, KC_BRIU, KC_MCTRL, KC_LNPAD, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_DEL, KC_PSCR, KC_CALC, KC_FIND, KC_MUTE,
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_PGUP, KC_NUM, KC_PSLS, KC_PAST, KC_PMNS,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, KC_P7, KC_P8, KC_P9,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_HOME, KC_P4, KC_P5, KC_P6, KC_PPLS,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, TD(TD_HOME_END), KC_P4, KC_P5, KC_P6, KC_PPLS,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_P1, KC_P2, KC_P3,
KC_LCTL, KC_LWIN, KC_LALT, KC_SPC, KC_RALT, MO(WIN_FN), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT, KC_P0, KC_PDOT, KC_PENT),
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, TT(FN3), TG(FN1), OSL(KEEB_CTL), KC_LEFT, KC_DOWN, KC_RGHT, KC_P0, KC_PDOT, KC_PENT),
[WIN_FN] = LAYOUT_ansi_101(
[FN2] = LAYOUT_ansi_101(
KC_ESC, KC_F13, KC_F14, KC_F15, KC_F16, KC_F17, KC_F18, KC_F19, KC_F20, KC_F21, KC_F22, KC_F23, KC_F24, KC_DEL, KC_PSCR, KC_CALC, KC_FIND, KC_MPLY,
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_MS_WH_UP, KC_NUM, KC_PSLS, KC_PAST, KC_PMNS,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_MS_WH_DOWN, KC_P7, KC_P8, KC_P9,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_MS_BTN3, KC_P4, KC_P5, KC_P6, KC_PPLS,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_MS_UP, KC_P1, KC_P2, KC_P3,
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, TG(FN2), TT(FN4), KC_RCTL, KC_MS_LEFT, KC_MS_DOWN, KC_MS_RIGHT, KC_MS_BTN1, KC_MS_BTN2, KC_PENT),
[FN3] = LAYOUT_ansi_101(
KC_ESC, KC_BRID, KC_BRIU, KC_MCTRL, KC_LNPAD, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_DEL, KC_PSCR, KC_CALC, KC_FIND, KC_MPLY,
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_PGUP, KC_NUM, KC_PSLS, KC_PAST, KC_PMNS,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, KC_P7, KC_P8, KC_P9,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, TD(TD_HOME_END), KC_P4, KC_P5, KC_P6, KC_PPLS,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_P1, KC_P2, KC_P3,
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, TG(FN3), TT(FN4), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT, KC_P0, KC_PDOT, KC_PENT),
[FN4] = LAYOUT_ansi_101(
KC_ESC, KC_BRID, KC_BRIU, KC_MCTRL, KC_LNPAD, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_DEL, KC_PSCR, KC_CALC, KC_FIND, KC_MPLY,
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_PGUP, KC_NUM, KC_PSLS, KC_PAST, KC_PMNS,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, KC_P7, KC_P8, KC_P9,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, TD(TD_HOME_END), KC_P4, KC_P5, KC_P6, KC_PPLS,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_P1, KC_P2, KC_P3,
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, TO(BASE), TG(FN4), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT, KC_P0, KC_PDOT, KC_PENT),
[KEEB_CTL] = LAYOUT_ansi_101(
_______, KC_BRID, KC_BRIU, KC_TASK, KC_FILE, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______, _______, _______, RGB_TOG,
_______, BT_HST1, BT_HST2, BT_HST3, P2P4G, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
@@ -59,19 +93,58 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______),
};
// clang-format on
#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
[MAC_BASE] = {ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
[MAC_FN] = {ENCODER_CCW_CW(RGB_VAD, RGB_VAI)},
[WIN_BASE] = {ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
[WIN_FN] = {ENCODER_CCW_CW(RGB_VAD, RGB_VAI)},
[BASE] = {ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
[FN1] = {ENCODER_CCW_CW(KC_MRWD, KC_MFFD)},
[FN2] = {ENCODER_CCW_CW(ALT_TAB_BWD, ALT_TAB_FWD)},
[FN3] = {ENCODER_CCW_CW(KC_MRWD, KC_MFFD)},
[FN4] = {ENCODER_CCW_CW(KC_MRWD, KC_MFFD)},
[KEEB_CTL] = {ENCODER_CCW_CW(RGB_VAD, RGB_VAI)},
};
#endif // ENCODER_MAP_ENABLE
// clang-format on
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
if (!process_record_keychron_common(keycode, record)) {
return false;
}
switch (keycode) {
case ALT_TAB_FWD:
if (record->event.pressed) {
if (!alt_tab_active) {
alt_tab_active = true;
register_code(KC_LALT);
}
alt_tab_timer = timer_read();
tap_code(KC_TAB);
}
return false;
case ALT_TAB_BWD:
if (record->event.pressed) {
if (!alt_tab_active) {
alt_tab_active = true;
register_code(KC_LALT);
}
alt_tab_timer = timer_read();
register_code(KC_LSFT);
tap_code(KC_TAB);
unregister_code(KC_LSFT);
}
return false;
}
return true;
}
void matrix_scan_user(void) {
if (alt_tab_active && timer_elapsed(alt_tab_timer) > ALT_TAB_TIMEOUT) {
unregister_code(KC_LALT);
alt_tab_active = false;
}
}
// Tap Dance definitions
tap_dance_action_t tap_dance_actions[] = {
// Tap once for Home, twice for End
[TD_HOME_END] = ACTION_TAP_DANCE_DOUBLE(KC_HOME, KC_END),
};
@@ -1 +1,2 @@
VIA_ENABLE = yes
TAP_DANCE_ENABLE = yes
@@ -1 +1,3 @@
# This file intentionally left blank
VIA_ENABLE = yes
TAP_DANCE_ENABLE = yes
MOUSEKEY_ENABLE = yes
@@ -20,15 +20,8 @@
/* RGB Matrix driver configuration */
# define DRIVER_COUNT 2
# define RGB_MATRIX_LED_COUNT 108
# define SPI_SCK_PIN A5
# define SPI_MISO_PIN A6
# define SPI_MOSI_PIN A7
# define DRIVER_CS_PINS \
{ B8, B9 }
# define SNLED23751_SPI_DIVISOR 16
# define SPI_DRIVER SPID1
/* Set LED driver current */
# define SNLED27351_CURRENT_TUNE \
@@ -36,7 +29,6 @@
/* Set to infinit, which is use in USB mode by default */
# define RGB_MATRIX_TIMEOUT RGB_MATRIX_TIMEOUT_INFINITE
/* Allow shutdown of led driver to save power */
# define RGB_MATRIX_DRIVER_SHUTDOWN_ENABLE
/* Turn off backlight on low brightness to save power */
+13 -6
View File
@@ -20,6 +20,19 @@
#define ENCODER_DEFAULT_POS 0x3
#define ENCODER_MAP_KEY_DELAY 2
#if defined(RGB_MATRIX_ENABLE) || defined(LK_WIRELESS_ENABLE)
/* SPI configuration */
# define SPI_DRIVER SPID1
# define SPI_SCK_PIN A5
# define SPI_MISO_PIN A6
# define SPI_MOSI_PIN A7
#endif
#if defined(RGB_MATRIX_ENABLE)
# define LED_DRIVER_SHUTDOWN_PIN B7
# define SNLED23751_SPI_DIVISOR 16
#endif
#ifdef LK_WIRELESS_ENABLE
/* Hardware configuration */
# define P2P4_MODE_SELECT_PIN A10
@@ -42,23 +55,17 @@
# if defined(RGB_MATRIX_ENABLE) || defined(LED_MATRIX_ENABLE)
# define LED_DRIVER_SHUTDOWN_PIN B7
# define BT_HOST_LED_MATRIX_LIST \
{ 20, 21, 22 }
# define P2P4G_HOST_LED_MATRIX_LIST \
{ 23 }
# define BAT_LEVEL_LED_LIST \
{ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 }
/* Backlit disable timeout when keyboard is disconnected(unit: second) */
# define DISCONNECTED_BACKLIGHT_DISABLE_TIMEOUT 40
/* Backlit disable timeout when keyboard is connected(unit: second) */
# define CONNECTED_BACKLIGHT_DISABLE_TIMEOUT 600
/* Reinit LED driver on tranport changed */
# define REINIT_LED_DRIVER 1

Some files were not shown because too many files have changed in this diff Show More