From 0b3575c6dc3e52590899055f4d0886a9146ab6d2 Mon Sep 17 00:00:00 2001 From: william <43848894@qq.com> Date: Mon, 13 Jan 2025 14:44:15 +0800 Subject: [PATCH 1/7] keychron changes for B pro series! --- app/CMakeLists.txt | 12 + app/Kconfig | 60 +- .../behaviors/zmk,behavior-tap-dance.yaml | 2 +- app/include/dt-bindings/zmk/bt.h | 2 + app/include/dt-bindings/zmk/keys.h | 2 + app/include/dt-bindings/zmk/outputs.h | 10 +- app/include/zmk/activity.h | 3 +- app/include/zmk/ble.h | 3 + app/include/zmk/ble/profile.h | 5 + app/include/zmk/endpoints.h | 6 + app/include/zmk/endpoints_types.h | 2 + app/include/zmk/hid.h | 56 + app/module/drivers/CMakeLists.txt | 1 + app/module/drivers/Kconfig | 1 + app/module/drivers/kscan/kscan_gpio_direct.c | 50 +- app/module/drivers/kscan/kscan_gpio_matrix.c | 183 ++- app/src/activity.c | 21 +- app/src/battery.c | 151 ++- app/src/behavior_queue.c | 19 +- app/src/behaviors/behavior_bt.c | 2 + app/src/behaviors/behavior_macro.c | 42 +- app/src/behaviors/behavior_outputs.c | 205 +++- app/src/behaviors/behavior_tap_dance.c | 17 + app/src/ble.c | 1041 +++++++++++++++-- app/src/endpoints.c | 225 +++- app/src/hid.c | 18 +- app/src/hog.c | 127 +- app/src/keymap.c | 138 ++- app/src/kscan.c | 8 +- app/src/main.c | 61 + app/src/usb.c | 65 +- app/src/usb_hid.c | 75 +- 32 files changed, 2430 insertions(+), 183 deletions(-) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 793f386dbe3..bf6d1ccd511 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -90,6 +90,18 @@ target_sources_ifdef(CONFIG_ZMK_BACKLIGHT app PRIVATE src/backlight.c) target_sources(app PRIVATE src/workqueue.c) target_sources(app PRIVATE src/main.c) +target_sources(app PRIVATE src/leds.c) +zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/bluetooth/host) + add_subdirectory(src/display/) + +add_subdirectory_ifdef(CONFIG_ZMK_NRF_24G_ECB src/24G) +zephyr_library_include_directories(src/24G) + + +add_subdirectory_ifdef(CONFIG_ZMK_LAUNCHER src/launcher) +add_subdirectory(src/dfu/) + + zephyr_cc_option(-Wfatal-errors) diff --git a/app/Kconfig b/app/Kconfig index 0dd9316a2a7..bf92dc86476 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -124,10 +124,10 @@ if ZMK_BLE config BT_TINYCRYPT_ECC default y if BT_HCI && !BT_CTLR -choice BT_LL_SW_LLCP_IMPL - default BT_LL_SW_LLCP_LEGACY +#choice BT_LL_SW_LLCP_IMPL +# default BT_LL_SW_LLCP_LEGACY -endchoice +#endchoice config SYSTEM_WORKQUEUE_STACK_SIZE default 4096 if SOC_RP2040 @@ -143,7 +143,7 @@ config ZMK_BLE_THREAD_PRIORITY config ZMK_BLE_KEYBOARD_REPORT_QUEUE_SIZE int "Max number of keyboard HID reports to queue for sending over BLE" - default 20 + default 64 config ZMK_BLE_CONSUMER_REPORT_QUEUE_SIZE int "Max number of consumer HID reports to queue for sending over BLE" @@ -364,7 +364,7 @@ menu "Behavior Options" config ZMK_BEHAVIORS_QUEUE_SIZE int "Maximum number of behaviors to allow queueing from a macro or other complex behavior" - default 64 + default 512 rsource "Kconfig.behaviors" @@ -425,7 +425,7 @@ config ZMK_LOGGING_MINIMAL if !ZMK_LOGGING_MINIMAL config ZMK_LOG_LEVEL - default 4 + default 1 #4 endif @@ -472,6 +472,16 @@ config ZMK_RTT_LOGGING select CONSOLE select RTT_CONSOLE +config ZMK_UART_LOGGING + bool "Enable UART logging to help debug" + select LOG + select DEBUG + select ASSERT + select SERIAL + select SERIAL_HAS_DRIVER + select CONSOLE + select UART_CONSOLE + if ZMK_RTT_LOGGING config SEGGER_RTT_BUFFER_SIZE_UP @@ -480,7 +490,7 @@ config SEGGER_RTT_BUFFER_SIZE_UP #ZMK_RTT_LOGGING endif -if ZMK_USB_LOGGING || ZMK_RTT_LOGGING +if ZMK_USB_LOGGING || ZMK_RTT_LOGGING || ZMK_UART_LOGGING config LOG_BUFFER_SIZE default 8192 @@ -506,7 +516,7 @@ endif config ZMK_BATTERY_REPORT_INTERVAL depends on ZMK_BATTERY_REPORTING int "Battery level report interval in seconds" - default 60 + default 30 config ZMK_LOW_PRIORITY_THREAD_STACK_SIZE int "Low priority thread stack size" @@ -562,6 +572,40 @@ choice CBPRINTF_IMPLEMENTATION endchoice +config ZMK_LED_INIT_PRIORITY + int "LED Init Priority" + default 40 + +config ZMK_NRF_24G_ECB + bool "enabel nordic 24g ecb" + select NRFX_TIMER2 + default n + +if ZMK_NRF_24G_ECB +config ESB_PTX_APP_LOG_LEVEL + int + default 4 +config ESB_DYNAMIC_INTERRUPTS + bool "enable dynamic interrupt" + default y +config ESB_MAX_PAYLOAD_LENGTH + int "max payload length" + default 40 +endif + + + +if ZMK_NRF_24G_ECB + config ZMK_NRF_24G + bool + default y +endif + +config ZMK_LAUNCHER + bool "enable via dynamic setting" + default y + + module = ZMK module-str = zmk source "subsys/logging/Kconfig.template.log_config" diff --git a/app/dts/bindings/behaviors/zmk,behavior-tap-dance.yaml b/app/dts/bindings/behaviors/zmk,behavior-tap-dance.yaml index 82e1517dac9..455b21d55e4 100644 --- a/app/dts/bindings/behaviors/zmk,behavior-tap-dance.yaml +++ b/app/dts/bindings/behaviors/zmk,behavior-tap-dance.yaml @@ -5,7 +5,7 @@ description: Tap Dance Behavior compatible: "zmk,behavior-tap-dance" -include: zero_param.yaml +include: one_param.yaml properties: bindings: diff --git a/app/include/dt-bindings/zmk/bt.h b/app/include/dt-bindings/zmk/bt.h index 8ca10606942..979284ea3a2 100644 --- a/app/include/dt-bindings/zmk/bt.h +++ b/app/include/dt-bindings/zmk/bt.h @@ -8,6 +8,7 @@ #define BT_NXT_CMD 1 #define BT_PRV_CMD 2 #define BT_SEL_CMD 3 +#define BT_PAIR_CMD 4 // #define BT_FULL_RESET_CMD 4 /* @@ -19,3 +20,4 @@ defines these aliases up front. #define BT_NXT BT_NXT_CMD 0 #define BT_PRV BT_PRV_CMD 0 #define BT_SEL BT_SEL_CMD +#define BT_PAIR BT_PAIR_CMD diff --git a/app/include/dt-bindings/zmk/keys.h b/app/include/dt-bindings/zmk/keys.h index 364ffa8647a..f4bf5d1cd9b 100644 --- a/app/include/dt-bindings/zmk/keys.h +++ b/app/include/dt-bindings/zmk/keys.h @@ -1443,3 +1443,5 @@ /* Apple Globe key */ #define C_AC_NEXT_KEYBOARD_LAYOUT_SELECT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, 0x029D)) #define GLOBE (C_AC_NEXT_KEYBOARD_LAYOUT_SELECT) +/* add */ +#define C_AC_MAC_LAUNCH (ZMK_HID_USAGE(HID_USAGE_CONSUMER, 0x02A0)) diff --git a/app/include/dt-bindings/zmk/outputs.h b/app/include/dt-bindings/zmk/outputs.h index f24380f7e1f..911e0cc1c74 100644 --- a/app/include/dt-bindings/zmk/outputs.h +++ b/app/include/dt-bindings/zmk/outputs.h @@ -6,4 +6,12 @@ #define OUT_TOG 0 #define OUT_USB 1 -#define OUT_BLE 2 \ No newline at end of file +#define OUT_BLE 2 +#define OUT_24G 3 +#define OUT_CHG 4 +#define OUT_CHGD 5 +#define OUT_BAT 6 +#define OUT_FN 7 +#define OUT_RECOVER 8 +#define OUT_FN_WIN 9 + diff --git a/app/include/zmk/activity.h b/app/include/zmk/activity.h index 9c858b15d42..4aaf87886e0 100644 --- a/app/include/zmk/activity.h +++ b/app/include/zmk/activity.h @@ -8,4 +8,5 @@ enum zmk_activity_state { ZMK_ACTIVITY_ACTIVE, ZMK_ACTIVITY_IDLE, ZMK_ACTIVITY_SLEEP }; -enum zmk_activity_state zmk_activity_get_state(); \ No newline at end of file +enum zmk_activity_state zmk_activity_get_state(); +int set_state(enum zmk_activity_state state); \ No newline at end of file diff --git a/app/include/zmk/ble.h b/app/include/zmk/ble.h index 435fde49654..9fb5ee092b8 100644 --- a/app/include/zmk/ble.h +++ b/app/include/zmk/ble.h @@ -24,6 +24,7 @@ int zmk_ble_clear_bonds(); int zmk_ble_prof_next(); int zmk_ble_prof_prev(); int zmk_ble_prof_select(uint8_t index); +int zmk_ble_prof_pair_start(uint8_t index); int zmk_ble_active_profile_index(); bt_addr_le_t *zmk_ble_active_profile_addr(); @@ -32,6 +33,8 @@ bool zmk_ble_active_profile_is_connected(); char *zmk_ble_active_profile_name(); int zmk_ble_unpair_all(); +uint8_t zmk_ble_get_active_profile_bt_id(void); +uint8_t zmk_ble_is_connected(void); #if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) int zmk_ble_put_peripheral_addr(const bt_addr_le_t *addr); diff --git a/app/include/zmk/ble/profile.h b/app/include/zmk/ble/profile.h index 0a57f16fa4b..166cb9defb3 100644 --- a/app/include/zmk/ble/profile.h +++ b/app/include/zmk/ble/profile.h @@ -12,5 +12,10 @@ struct zmk_ble_profile { char name[ZMK_BLE_PROFILE_NAME_MAX]; + uint8_t bt_id : 4; + uint8_t is_rpa : 2; + uint8_t connected:1; + uint8_t bonded:1; + uint8_t fn_exchange; bt_addr_le_t peer; }; diff --git a/app/include/zmk/endpoints.h b/app/include/zmk/endpoints.h index c5964ff8535..af197c92b33 100644 --- a/app/include/zmk/endpoints.h +++ b/app/include/zmk/endpoints.h @@ -26,6 +26,10 @@ #define ZMK_ENDPOINT_BLE_COUNT 0 #endif +enum { + REBOOT_ENDPOINT_BLE=0xc0, + REBOOT_ENDPOINT_24G +}; /** * The total number of different (struct zmk_endpoint_instance) values that can * be selected. @@ -69,3 +73,5 @@ int zmk_endpoints_toggle_transport(void); struct zmk_endpoint_instance zmk_endpoints_selected(void); int zmk_endpoints_send_report(uint16_t usage_page); + +uint8_t get_current_transport(void); diff --git a/app/include/zmk/endpoints_types.h b/app/include/zmk/endpoints_types.h index ea51c8aa93d..2e7ff713153 100644 --- a/app/include/zmk/endpoints_types.h +++ b/app/include/zmk/endpoints_types.h @@ -12,6 +12,8 @@ enum zmk_transport { ZMK_TRANSPORT_USB, ZMK_TRANSPORT_BLE, + ZMK_TRANSPORT_24G, + ZMK_TRANSPORT_NONE }; /** diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index da6bfa65a68..2aa8958ed50 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -46,6 +46,11 @@ #define ZMK_HID_REPORT_ID_KEYBOARD 0x01 #define ZMK_HID_REPORT_ID_CONSUMER 0x02 +#define ZMK_HID_REPORT_ID_SYSTEM 0x03 +#define ZMK_HID_REPORT_ID_MOUSE 0x04 + +#define HID_USAGE_2(a,b) \ + HID_ITEM(HID_ITEM_TAG_USAGE, HID_ITEM_TYPE_LOCAL, 2), a,b static const uint8_t zmk_hid_report_desc[] = { HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP), @@ -67,6 +72,21 @@ static const uint8_t zmk_hid_report_desc[] = { HID_REPORT_COUNT(0x01), HID_INPUT(ZMK_HID_MAIN_VAL_CONST | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS), + //add led output + HID_REPORT_SIZE(1), + HID_REPORT_COUNT(5), + HID_USAGE_PAGE(HID_USAGE_GEN_LEDS), + /* HID_USAGE_MINIMUM(Num Lock) */ + HID_USAGE_MIN8(1), + /* HID_USAGE_MAXIMUM(Kana) */ + HID_USAGE_MAX8(5), + /* HID_OUTPUT(Data,Var,Abs) */ + HID_OUTPUT(0x02), + HID_REPORT_SIZE(3), + HID_REPORT_COUNT(1), + /* HID_OUTPUT(Cnst,Var,Abs) */ + HID_OUTPUT(0x03), + HID_USAGE_PAGE(HID_USAGE_KEY), #if IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_NKRO) @@ -114,6 +134,42 @@ static const uint8_t zmk_hid_report_desc[] = { HID_REPORT_COUNT(CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE), HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_ARRAY | ZMK_HID_MAIN_VAL_ABS), HID_END_COLLECTION, + + HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP), + HID_USAGE(HID_USAGE_GD_MOUSE), + HID_COLLECTION(HID_COLLECTION_APPLICATION), + HID_REPORT_ID(ZMK_HID_REPORT_ID_MOUSE), + HID_USAGE(HID_USAGE_GEN_DESKTOP_POINTER), + HID_COLLECTION(HID_COLLECTION_PHYSICAL), + HID_USAGE_PAGE(HID_USAGE_GEN_BUTTON), + HID_USAGE_MIN8(0x01), + HID_USAGE_MAX8(0x08), + HID_LOGICAL_MIN8(0x00), + HID_LOGICAL_MAX8(0x01), + HID_REPORT_SIZE(1), + HID_REPORT_COUNT(8), + HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS), + + HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP), + HID_USAGE(HID_USAGE_GEN_DESKTOP_X), + HID_USAGE(HID_USAGE_GEN_DESKTOP_Y), + HID_USAGE(HID_USAGE_GEN_DESKTOP_WHEEL), + HID_LOGICAL_MIN8(-127), + HID_LOGICAL_MAX8(127), + HID_REPORT_SIZE(8), + HID_REPORT_COUNT(3), + HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_REL), + + HID_USAGE_PAGE(HID_USAGE_CONSUMER), + HID_USAGE_2(0x38,0x02), //AC Pan + HID_LOGICAL_MIN8(-127), + HID_LOGICAL_MAX8(127), + HID_REPORT_SIZE(8), + HID_REPORT_COUNT(1), + HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_REL), + HID_END_COLLECTION, + HID_END_COLLECTION, + }; // struct zmk_hid_boot_report diff --git a/app/module/drivers/CMakeLists.txt b/app/module/drivers/CMakeLists.txt index 5281c3dcb21..51814c312a8 100644 --- a/app/module/drivers/CMakeLists.txt +++ b/app/module/drivers/CMakeLists.txt @@ -5,3 +5,4 @@ add_subdirectory_ifdef(CONFIG_GPIO gpio) add_subdirectory_ifdef(CONFIG_KSCAN kscan) add_subdirectory_ifdef(CONFIG_SENSOR sensor) add_subdirectory_ifdef(CONFIG_DISPLAY display) +add_subdirectory_ifdef(CONFIG_ZMK_RGB_UNDERGLOW led_strip) diff --git a/app/module/drivers/Kconfig b/app/module/drivers/Kconfig index c57ed3347c9..5c0d6437e3e 100644 --- a/app/module/drivers/Kconfig +++ b/app/module/drivers/Kconfig @@ -5,3 +5,4 @@ rsource "gpio/Kconfig" rsource "kscan/Kconfig" rsource "sensor/Kconfig" rsource "display/Kconfig" +rsource "led_strip/Kconfig" diff --git a/app/module/drivers/kscan/kscan_gpio_direct.c b/app/module/drivers/kscan/kscan_gpio_direct.c index 5b227784dad..826b0ebbd08 100644 --- a/app/module/drivers/kscan/kscan_gpio_direct.c +++ b/app/module/drivers/kscan/kscan_gpio_direct.c @@ -13,7 +13,7 @@ #include #include #include - +#include #include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); @@ -71,6 +71,9 @@ struct kscan_direct_config { int32_t poll_period_ms; bool toggle_mode; }; +static uint8_t long_poll; +bool is_usb_power_present(void); +void switch_to_usb(void); #if USE_INTERRUPTS static int kscan_direct_interrupt_configure(const struct device *dev, const gpio_flags_t flags) { @@ -147,7 +150,7 @@ static void kscan_direct_read_continue(const struct device *dev) { const struct kscan_direct_config *config = dev->config; struct kscan_direct_data *data = dev->data; - data->scan_time += config->debounce_scan_period_ms; + data->scan_time += long_poll?400: config->debounce_scan_period_ms; k_work_reschedule(&data->work, K_TIMEOUT_ABS_MS(data->scan_time)); } @@ -182,14 +185,16 @@ static int kscan_direct_read(const struct device *dev) { LOG_ERR("Failed to read port %s: %i", gpio->spec.port->name, active); return active; } - + zmk_debounce_update(&data->pin_state[gpio->index], active, config->debounce_scan_period_ms, &config->debounce_config); + // if(!long_poll) + // LOG_DBG("pin:%d,v:%d,counter:%d",gpio->spec.pin,active,data->pin_state[gpio->index].counter); } // Process the new state. bool continue_scan = false; - + bool changed=false; for (int i = 0; i < data->inputs.len; i++) { const struct kscan_gpio *gpio = &data->inputs.gpios[i]; struct zmk_debounce_state *state = &data->pin_state[gpio->index]; @@ -205,8 +210,9 @@ static int kscan_direct_read(const struct device *dev) { } continue_scan = continue_scan || zmk_debounce_is_active(state); + if(state->counter) changed =true; } - + long_poll = !changed; if (continue_scan) { // At least one key is pressed or the debouncer has not yet decided if // it is pressed. Poll quickly until everything is released. @@ -359,3 +365,37 @@ static const struct kscan_driver_api kscan_direct_api = { &kscan_direct_api); DT_INST_FOREACH_STATUS_OKAY(KSCAN_DIRECT_INIT); + + +void kscan_gpio_direct_enter_sleep(void) +{ + const struct kscan_direct_data *data = &kscan_direct_data_0; + //set p1.8/p1.9 to wakeup from system_off + //note: can't set pullup in dts!!! + for (int i = 0; i < 2; i++) { + const struct gpio_dt_spec *gpio = &data->inputs.gpios[i].spec; + //NOTE:can't set interrupts more than 8 ; + // gpio_pin_interrupt_configure_dt(gpio, GPIO_INT_LEVEL_ACTIVE); + uint32_t pin_num =NRF_GPIO_PIN_MAP(1,gpio->pin); + // LOG_ERR("pin value:%d",gpio_pin_get_raw(gpio->port,gpio->pin)); + { + // LOG_ERR("set sense ,pin:%d",pin_num); + nrf_gpio_cfg_input(pin_num, NRF_GPIO_PIN_NOPULL); + nrf_gpio_pin_sense_t sense_config =GPIO_PIN_CNF_SENSE_Low; + nrf_gpio_cfg_sense_set(pin_num, sense_config); + } + } +} +uint8_t get_mode_status(void) +{ + uint8_t status =0; + const struct kscan_direct_data *data = &kscan_direct_data_0; + + for (int i = 0; i < 2; i++) { + const struct gpio_dt_spec *gpio = &data->inputs.gpios[i].spec; + status |= gpio_pin_get_raw(gpio->port,gpio->pin)<<(i); + + } + LOG_ERR("mode status:%x",status); + return status; +} \ No newline at end of file diff --git a/app/module/drivers/kscan/kscan_gpio_matrix.c b/app/module/drivers/kscan/kscan_gpio_matrix.c index 0d8a3190659..8f5b1768748 100644 --- a/app/module/drivers/kscan/kscan_gpio_matrix.c +++ b/app/module/drivers/kscan/kscan_gpio_matrix.c @@ -16,8 +16,10 @@ #include #include +#include +#include -LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); +LOG_MODULE_DECLARE(zmk, 4);//CONFIG_ZMK_LOG_LEVEL); #define DT_DRV_COMPAT zmk_kscan_gpio_matrix @@ -82,6 +84,7 @@ struct kscan_matrix_data { * (config->rows * config->cols) */ struct zmk_debounce_state *matrix_state; + uint32_t *rows; }; struct kscan_matrix_config { @@ -93,7 +96,42 @@ struct kscan_matrix_config { int32_t poll_period_ms; enum kscan_diode_direction diode_direction; }; +//add ---- +static uint8_t slow_poll; +struct user_debounce_config { + struct zmk_debounce_config debounce_config; + uint32_t debounce_scan_period_ms; +}; + +static struct user_debounce_config user_debounce; +static struct user_debounce_config defualt_debouce; +void user_set_debounce(uint32_t scan_period_ms,uint32_t debounce_press_ms,uint32_t debounce_release_ms) +{ + if(scan_period_ms ==0 || debounce_press_ms==0 || debounce_release_ms==0) + { + user_debounce.debounce_scan_period_ms =defualt_debouce.debounce_scan_period_ms; + user_debounce.debounce_config.debounce_press_ms = defualt_debouce.debounce_config.debounce_press_ms; + user_debounce.debounce_config.debounce_release_ms =defualt_debouce.debounce_config.debounce_release_ms; + } + else + { + user_debounce.debounce_scan_period_ms =scan_period_ms; + user_debounce.debounce_config.debounce_press_ms = debounce_press_ms; + user_debounce.debounce_config.debounce_release_ms = debounce_release_ms; + LOG_DBG("set debounce,scan:%d,press:%d,release:%d",scan_period_ms,debounce_press_ms,debounce_release_ms); + } +} + +//esc key =row3,col1 +struct gpio_dt_spec esc_gpio = { //row3,input + .pin = 4, + .port = DEVICE_DT_GET(DT_NODELABEL(gpio1)), + .dt_flags = GPIO_ACTIVE_HIGH| GPIO_PULL_DOWN, +}; + +//--- +static int kscan_matrix_init_outputs(const struct device *dev); /** * Get the index into a matrix state array from a row and column. */ @@ -119,7 +157,7 @@ static int kscan_matrix_set_all_outputs(const struct device *dev, const int valu for (int i = 0; i < config->outputs.len; i++) { const struct gpio_dt_spec *gpio = &config->outputs.gpios[i].spec; - + gpio_pin_configure_dt(gpio, GPIO_OUTPUT); int err = gpio_pin_set_dt(gpio, value); if (err) { LOG_ERR("Failed to set output %i to %i: %i", i, value, err); @@ -129,7 +167,21 @@ static int kscan_matrix_set_all_outputs(const struct device *dev, const int valu return 0; } +static int kscan_matrix_set_esc_check_outputs(const struct device *dev) { + const struct kscan_matrix_config *config = dev->config; + + for (int i = 0; i < config->outputs.len; i++) { + const struct gpio_dt_spec *gpio = &config->outputs.gpios[i].spec; + gpio_pin_configure_dt(gpio, GPIO_OUTPUT); + int err = gpio_pin_set_dt(gpio, (gpio->pin == 1) ? 1 : 0); //col1,ouput=1 + if (err) { + LOG_ERR("Failed to set output %i to %i: %i", i, gpio->pin, err); + return err; + } + } + return 0; +} #if USE_INTERRUPTS static int kscan_matrix_interrupt_configure(const struct device *dev, const gpio_flags_t flags) { const struct kscan_matrix_data *data = dev->data; @@ -154,7 +206,7 @@ static int kscan_matrix_interrupt_enable(const struct device *dev) { if (err) { return err; } - + // kscan_matrix_init_outputs(dev); // While interrupts are enabled, set all outputs active so a pressed key // will trigger an interrupt. return kscan_matrix_set_all_outputs(dev, 1); @@ -167,7 +219,7 @@ static int kscan_matrix_interrupt_disable(const struct device *dev) { if (err) { return err; } - + // LOG_DBG("x"); // While interrupts are disabled, set all outputs inactive so // kscan_matrix_read() can scan them one by one. return kscan_matrix_set_all_outputs(dev, 0); @@ -191,15 +243,43 @@ static void kscan_matrix_irq_callback_handler(const struct device *port, struct #endif static void kscan_matrix_read_continue(const struct device *dev) { - const struct kscan_matrix_config *config = dev->config; + // const struct kscan_matrix_config *config = dev->config; struct kscan_matrix_data *data = dev->data; + if(slow_poll) + { + if(user_debounce.debounce_scan_period_ms<5) + data->scan_time += 10; + else + data->scan_time += user_debounce.debounce_scan_period_ms*2; + } + else + data->scan_time += user_debounce.debounce_scan_period_ms; //config->debounce_scan_period_ms; - data->scan_time += config->debounce_scan_period_ms; k_work_reschedule(&data->work, K_TIMEOUT_ABS_MS(data->scan_time)); } - +static inline bool check_more_than_one(uint32_t rowdata) { + rowdata &= rowdata - 1; + return rowdata; +} +static inline bool has_ghost_in_row(const struct device *dev,uint8_t row, uint32_t rowdata) { + struct kscan_matrix_data *data = dev->data; + const struct kscan_matrix_config *config = dev->config; + if ((check_more_than_one(rowdata)) == 0) { + return false; + } + for (uint8_t i = 0; i < config->cols; i++) { + if(data->rows[i]) + LOG_DBG("col:%d,data:%04x",i,data->rows[i]); + if (i != row && check_more_than_one(data->rows[i] & rowdata)) { + LOG_DBG("ghost ,col:%d,row:%d,data:%04x",i,row,rowdata); + return true; + } + } + return false; +} static void kscan_matrix_read_end(const struct device *dev) { + #if USE_INTERRUPTS // Return to waiting for an interrupt. kscan_matrix_interrupt_enable(dev); @@ -221,8 +301,8 @@ static int kscan_matrix_read(const struct device *dev) { // Scan the matrix. for (int i = 0; i < config->outputs.len; i++) { const struct kscan_gpio *out_gpio = &config->outputs.gpios[i]; - - int err = gpio_pin_set_dt(&out_gpio->spec, 1); + gpio_pin_configure_dt(&out_gpio->spec, GPIO_OUTPUT); + int err = gpio_pin_set_dt(&out_gpio->spec,1); if (err) { LOG_ERR("Failed to set output %i active: %i", out_gpio->index, err); return err; @@ -232,22 +312,29 @@ static int kscan_matrix_read(const struct device *dev) { k_busy_wait(CONFIG_ZMK_KSCAN_MATRIX_WAIT_BEFORE_INPUTS); #endif struct kscan_gpio_port_state state = {0}; - + uint32_t row =0; for (int j = 0; j < data->inputs.len; j++) { const struct kscan_gpio *in_gpio = &data->inputs.gpios[j]; - + const int index = state_index_io(config, in_gpio->index, out_gpio->index); + + const int active = kscan_gpio_pin_get(in_gpio, &state); if (active < 0) { LOG_ERR("Failed to read port %s: %i", in_gpio->spec.port->name, active); return active; } - - zmk_debounce_update(&data->matrix_state[index], active, config->debounce_scan_period_ms, - &config->debounce_config); + row |= (active<matrix_state[index], active, user_debounce.debounce_scan_period_ms, + &user_debounce.debounce_config); } - + data->rows[i] = row; + // if(row) + // { + // LOG_DBG("col:%d,row :%04x",i,row); + // } err = gpio_pin_set_dt(&out_gpio->spec, 0); + gpio_pin_configure_dt(&out_gpio->spec, GPIO_INPUT); if (err) { LOG_ERR("Failed to set output %i inactive: %i", out_gpio->index, err); return err; @@ -260,23 +347,27 @@ static int kscan_matrix_read(const struct device *dev) { // Process the new state. bool continue_scan = false; - + bool changed=false; for (int r = 0; r < config->rows; r++) { for (int c = 0; c < config->cols; c++) { const int index = state_index_rc(config, r, c); struct zmk_debounce_state *state = &data->matrix_state[index]; if (zmk_debounce_get_changed(state)) { + const bool pressed = zmk_debounce_is_pressed(state); + if(has_ghost_in_row(dev,c,data->rows[c]) && pressed) + continue; LOG_DBG("Sending event at %i,%i state %s", r, c, pressed ? "on" : "off"); data->callback(dev, r, c, pressed); } continue_scan = continue_scan || zmk_debounce_is_active(state); + if(state->counter) changed =true; } } - + slow_poll = !changed; if (continue_scan) { // At least one key is pressed or the debouncer has not yet decided if // it is pressed. Poll quickly until everything is released. @@ -340,7 +431,7 @@ static int kscan_matrix_init_input_inst(const struct device *dev, const struct k return err; } - LOG_DBG("Configured pin %u on %s for input", gpio->spec.pin, gpio->spec.port->name); + // LOG_DBG("Configured pin %u on %s for input", gpio->spec.pin, gpio->spec.port->name); #if USE_INTERRUPTS struct kscan_matrix_data *data = dev->data; @@ -363,6 +454,7 @@ static int kscan_matrix_init_inputs(const struct device *dev) { for (int i = 0; i < data->inputs.len; i++) { const struct kscan_gpio *gpio = &data->inputs.gpios[i]; + // LOG_DBG("input,gpio:%d, index:%d,pin:%d",i,gpio->index,gpio->spec.pin); int err = kscan_matrix_init_input_inst(dev, gpio); if (err) { return err; @@ -385,7 +477,7 @@ static int kscan_matrix_init_output_inst(const struct device *dev, return err; } - LOG_DBG("Configured pin %u on %s for output", gpio->pin, gpio->port->name); + // LOG_DBG("Configured pin %u on %s for output", gpio->pin, gpio->port->name); return 0; } @@ -395,6 +487,7 @@ static int kscan_matrix_init_outputs(const struct device *dev) { for (int i = 0; i < config->outputs.len; i++) { const struct gpio_dt_spec *gpio = &config->outputs.gpios[i].spec; + // LOG_DBG("output,gpio:%d index:%d,pin:%d",i,config->outputs.gpios[i].index,gpio->pin); int err = kscan_matrix_init_output_inst(dev, gpio); if (err) { return err; @@ -406,6 +499,15 @@ static int kscan_matrix_init_outputs(const struct device *dev) { static int kscan_matrix_init(const struct device *dev) { struct kscan_matrix_data *data = dev->data; + const struct kscan_matrix_config *config = dev->config; + + defualt_debouce.debounce_scan_period_ms =config->debounce_scan_period_ms; + defualt_debouce.debounce_config.debounce_press_ms =config->debounce_config.debounce_press_ms; + defualt_debouce.debounce_config.debounce_release_ms =config->debounce_config.debounce_release_ms; + + user_debounce.debounce_scan_period_ms =config->debounce_scan_period_ms; + user_debounce.debounce_config.debounce_press_ms =config->debounce_config.debounce_press_ms; + user_debounce.debounce_config.debounce_release_ms =config->debounce_config.debounce_release_ms; data->dev = dev; @@ -414,6 +516,20 @@ static int kscan_matrix_init(const struct device *dev) { kscan_matrix_init_inputs(dev); kscan_matrix_init_outputs(dev); + // add esc key check + kscan_matrix_set_esc_check_outputs(dev); + k_msleep(2); + + if (gpio_pin_get_dt(&esc_gpio) == 1) { + LOG_ERR("esc_press_when_poweron"); + uint8_t type = nrf_power_gpregret_get(NRF_POWER); + LOG_ERR("reboot type:%02x", type); + if(type == 0) + { + sys_reboot(0x4e);//only serial! + } + } + kscan_matrix_set_all_outputs(dev, 0); k_work_init_delayable(&data->work, kscan_matrix_work_handler); @@ -440,11 +556,13 @@ static const struct kscan_driver_api kscan_matrix_api = { LISTIFY(INST_COLS_LEN(n), KSCAN_GPIO_COL_CFG_INIT, (, ), n)}; \ \ static struct zmk_debounce_state kscan_matrix_state_##n[INST_MATRIX_LEN(n)]; \ + static uint32_t matrix_rows[INST_COLS_LEN(n)]; \ \ COND_INTERRUPTS( \ (static struct kscan_matrix_irq_callback kscan_matrix_irqs_##n[INST_INPUTS_LEN(n)];)) \ \ static struct kscan_matrix_data kscan_matrix_data_##n = { \ + .rows = matrix_rows, \ .inputs = \ KSCAN_GPIO_LIST(COND_DIODE_DIR(n, (kscan_matrix_cols_##n), (kscan_matrix_rows_##n))), \ .matrix_state = kscan_matrix_state_##n, \ @@ -470,3 +588,30 @@ static const struct kscan_driver_api kscan_matrix_api = { &kscan_matrix_api); DT_INST_FOREACH_STATUS_OKAY(KSCAN_MATRIX_INIT); +#define MATRIX_ROWS DT_PROP_LEN(DT_NODELABEL(kscan0), row_gpios) +uint32_t matrix_get_row(uint8_t row) +{ + uint32_t col_values=0; + uint32_t cols = sizeof(matrix_rows)/4; + uint8_t read_row = (row -1 +MATRIX_ROWS) % MATRIX_ROWS; + for(int i=0;i #endif - +bool all_keys_up(void); bool is_usb_power_present() { #if IS_ENABLED(CONFIG_USB_DEVICE_STACK) return zmk_usb_is_powered(); @@ -59,7 +59,17 @@ enum zmk_activity_state zmk_activity_get_state() { return activity_state; } int activity_event_listener(const zmk_event_t *eh) { activity_last_uptime = k_uptime_get(); - + struct zmk_position_state_changed *pos_state; + + pos_state = as_zmk_position_state_changed(eh); + if(pos_state) + { + if(pos_state->state) + { + void bat_low_check(void); + bat_low_check(); + } + } return set_state(ZMK_ACTIVITY_ACTIVE); } @@ -67,8 +77,13 @@ void activity_work_handler(struct k_work *work) { int32_t current = k_uptime_get(); int32_t inactive_time = current - activity_last_uptime; #if IS_ENABLED(CONFIG_ZMK_SLEEP) - if (inactive_time > MAX_SLEEP_MS && !is_usb_power_present()) { + if ((inactive_time > MAX_SLEEP_MS || activity_state == ZMK_ACTIVITY_SLEEP) && !is_usb_power_present() && all_keys_up()) { // Put devices in suspend power mode before sleeping + void leds_turnoff(void); + leds_turnoff(); + void kscan_gpio_direct_enter_sleep(void); + kscan_gpio_direct_enter_sleep(); + LOG_DBG("ZMK_ACTIVITY_SLEEP"); set_state(ZMK_ACTIVITY_SLEEP); pm_state_force(0U, &(struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0}); } else diff --git a/app/src/battery.c b/app/src/battery.c index 87a25e08a2d..87962531115 100644 --- a/app/src/battery.c +++ b/app/src/battery.c @@ -19,8 +19,20 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include - -static uint8_t last_state_of_charge = 0; +#include +#include +#include +#include +#include +#define BAT_VOLTAGE_LOW 3320 +#define BAT_VOLTAGE_SHUTDOWN (3045) +void zmk_battery_check(void); +void check_voltage_when_boot(void); +bool is_usb_power_present(void); +static uint8_t last_state_of_charge = 100; +static bool bat_shutdown; +static const struct device *adc = DEVICE_DT_GET(DT_NODELABEL(adc)); +static uint16_t voltage; uint8_t zmk_battery_state_of_charge() { return last_state_of_charge; } @@ -32,9 +44,15 @@ static const struct device *const battery = DEVICE_DT_GET(DT_CHOSEN(zmk_battery) static const struct device *battery; #endif +extern struct bt_conn *destination_connection(); +extern int bt_bas_set_battery_level_fix(struct bt_conn *conn,uint8_t level); +extern void bt_conn_unref(struct bt_conn *conn); + static int zmk_battery_update(const struct device *battery) { struct sensor_value state_of_charge; + struct sensor_value sensor_voltage; + pm_device_action_run(adc,PM_DEVICE_ACTION_RESUME); int rc = sensor_sample_fetch_chan(battery, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE); if (rc != 0) { @@ -48,13 +66,29 @@ static int zmk_battery_update(const struct device *battery) { LOG_DBG("Failed to get battery state of charge: %d", rc); return rc; } + rc = sensor_channel_get(battery, SENSOR_CHAN_GAUGE_VOLTAGE, &sensor_voltage); + if (rc != 0) { + LOG_DBG("Failed to fetch battery values: %d", rc); + return rc; + } + voltage = sensor_voltage.val1*1000+ sensor_voltage.val2/1000; + if(voltage >BAT_VOLTAGE_LOW) + { + bat_shutdown=false; + } + zmk_battery_check(); + + LOG_DBG("bat,last per:%d,cur:%d",last_state_of_charge,state_of_charge.val1); - if (last_state_of_charge != state_of_charge.val1) { + if (last_state_of_charge != state_of_charge.val1 && ((state_of_charge.val1 < last_state_of_charge) ||is_usb_power_present())) { last_state_of_charge = state_of_charge.val1; LOG_DBG("Setting BAS GATT battery level to %d.", last_state_of_charge); - rc = bt_bas_set_battery_level(last_state_of_charge); + // rc = bt_bas_set_battery_level(last_state_of_charge); + struct bt_conn *conn=destination_connection(); + rc = bt_bas_set_battery_level_fix(conn,last_state_of_charge); + bt_conn_unref(conn); if (rc != 0) { LOG_WRN("Failed to set BAS GATT battery level (err %d)", rc); @@ -64,7 +98,7 @@ static int zmk_battery_update(const struct device *battery) { rc = ZMK_EVENT_RAISE(new_zmk_battery_state_changed( (struct zmk_battery_state_changed){.state_of_charge = last_state_of_charge})); } - + pm_device_action_run(adc,PM_DEVICE_ACTION_SUSPEND); return rc; } @@ -100,9 +134,114 @@ static int zmk_battery_init(const struct device *_arg) { return -ENODEV; } - k_timer_start(&battery_timer, K_NO_WAIT, K_SECONDS(CONFIG_ZMK_BATTERY_REPORT_INTERVAL)); + k_timer_start(&battery_timer, K_SECONDS(1), K_SECONDS(CONFIG_ZMK_BATTERY_REPORT_INTERVAL)); + check_voltage_when_boot(); + pm_device_action_run(adc,PM_DEVICE_ACTION_SUSPEND); return 0; } SYS_INIT(zmk_battery_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); + + +void zmk_battery_check(void) +{ + static uint8_t check_count=0; + LOG_DBG("voltage:%d,count:%d,state:%d",voltage,check_count,get_charge_led_state()); + if(zmk_usb_is_powered()) return; + if(voltage 2) + { + set_state(ZMK_ACTIVITY_SLEEP); + } + } + else + { + check_count=0; + } + } + else + { + if(get_charge_led_state()==LED_BAT_LOW) + led_charge_set_state(LED_BAT_NONE); + } + +} + +void check_voltage_when_boot(void) +{ + struct sensor_value sensor_voltage; + uint16_t voltage=0; + uint16_t max=0; + uint16_t min=0xffff; + uint32_t sum=0; + int i; + bat_shutdown =false; + for(i=0;i<10;i++) + { + int rc = sensor_sample_fetch_chan(battery, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE); + if (rc != 0) { + LOG_DBG("Failed to fetch battery values: %d", rc); + return ; + } + rc = sensor_channel_get(battery, SENSOR_CHAN_GAUGE_VOLTAGE, &sensor_voltage); + if (rc != 0) { + LOG_DBG("Failed to fetch battery values: %d", rc); + return ; + } + voltage = sensor_voltage.val1*1000+ sensor_voltage.val2/1000; + sum +=voltage; + if(voltage>=max) + { + max = voltage ; + } + if(voltage2000) + { + + LOG_ERR("bat low to shutdown"); + bat_shutdown =true; + } + +} +bool bat_is_shutdown(void) +{ + return bat_shutdown; +} + +void clear_bat_shutdown(void) +{ + bat_shutdown =false; +} + +void bat_low_check(void) +{ + static int64_t last_time=0; + int64_t uptime= k_uptime_get(); + int64_t delta_time= uptime -last_time; + if((delta_time>30*1000) ||(last_time==0)) + { + if((voltage BAT_VOLTAGE_SHUTDOWN) && !zmk_usb_is_powered()) + { + led_charge_set_state(LED_BAT_LOW); + last_time = uptime; + } + } + +} \ No newline at end of file diff --git a/app/src/behavior_queue.c b/app/src/behavior_queue.c index 1511e755d4f..97f5199887f 100644 --- a/app/src/behavior_queue.c +++ b/app/src/behavior_queue.c @@ -23,13 +23,13 @@ K_MSGQ_DEFINE(zmk_behavior_queue_msgq, sizeof(struct q_item), CONFIG_ZMK_BEHAVIO static void behavior_queue_process_next(struct k_work *work); static K_WORK_DELAYABLE_DEFINE(queue_work, behavior_queue_process_next); - +uint8_t macro_running; static void behavior_queue_process_next(struct k_work *work) { struct q_item item = {.wait = 0}; while (k_msgq_get(&zmk_behavior_queue_msgq, &item, K_NO_WAIT) == 0) { - LOG_DBG("Invoking %s: 0x%02x 0x%02x", item.binding.behavior_dev, item.binding.param1, - item.binding.param2); + LOG_DBG("Invoking %s: 0x%02x 0x%02x,%d", item.binding.behavior_dev, item.binding.param1, + item.binding.param2,item.press); struct zmk_behavior_binding_event event = {.position = item.position, .timestamp = k_uptime_get()}; @@ -47,6 +47,14 @@ static void behavior_queue_process_next(struct k_work *work) { break; } } + if(k_msgq_num_used_get(&zmk_behavior_queue_msgq)>0) + { + macro_running =1; + } + else + { + macro_running =0; + } } int zmk_behavior_queue_add(uint32_t position, const struct zmk_behavior_binding binding, bool press, @@ -55,6 +63,7 @@ int zmk_behavior_queue_add(uint32_t position, const struct zmk_behavior_binding const int ret = k_msgq_put(&zmk_behavior_queue_msgq, &item, K_NO_WAIT); if (ret < 0) { + LOG_ERR("behavior_queue full"); return ret; } @@ -64,3 +73,7 @@ int zmk_behavior_queue_add(uint32_t position, const struct zmk_behavior_binding return 0; } +uint8_t behavior_queue_is_full(void) +{ + return (k_msgq_num_used_get(&zmk_behavior_queue_msgq)>(CONFIG_ZMK_BEHAVIORS_QUEUE_SIZE-32))?1:0; +} \ No newline at end of file diff --git a/app/src/behaviors/behavior_bt.c b/app/src/behaviors/behavior_bt.c index 6d44b5f5e9f..600ffc24092 100644 --- a/app/src/behaviors/behavior_bt.c +++ b/app/src/behaviors/behavior_bt.c @@ -31,6 +31,8 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, return zmk_ble_prof_prev(); case BT_SEL_CMD: return zmk_ble_prof_select(binding->param2); + case BT_PAIR_CMD: + return zmk_ble_prof_pair_start(binding->param2); default: LOG_ERR("Unknown BT command: %d", binding->param1); } diff --git a/app/src/behaviors/behavior_macro.c b/app/src/behaviors/behavior_macro.c index c47284531a7..988c5cc3ff1 100644 --- a/app/src/behaviors/behavior_macro.c +++ b/app/src/behaviors/behavior_macro.c @@ -13,6 +13,21 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include "../launcher/keycodes.h" +#include "../launcher/send_string.h" + +char keychron_web_win[]= +{ + "\1\2\xe3r\1\3\xe3\1\004100|msedge.exe https://keychron.com\n" + // SS_LWIN(R)SS_DELAY(100)"msedge.exe https://keychron.com\r" +}; +char keychron_web_mac[]= +{ + "\1\2\xe3 \1\3\xe3\1\004100|safari\n\1\004100|\1\2\xe3t\1\3\xe3\1\004100|https://keychron.com\n" + //SS_LCMD( )SS_DELAY(100)"safari\r"SS_DELAY(100)SS_LCMD(T)SS_DELAY(100)"https://keychron.com\r" +}; + enum behavior_macro_mode { MACRO_MODE_TAP, MACRO_MODE_PRESS, @@ -158,11 +173,13 @@ static void queue_macro(uint32_t position, const struct zmk_behavior_binding bin struct behavior_macro_trigger_state state, const struct zmk_behavior_binding *macro_binding) { LOG_DBG("Iterating macro bindings - starting: %d, count: %d", state.start_index, state.count); + LOG_DBG("state.mode:%d,macro binding:%s",state.mode,macro_binding->behavior_dev); for (int i = state.start_index; i < state.start_index + state.count; i++) { + LOG_DBG("bindings:%d,dev:%s,p1:%d,p2:%d",i,bindings[i].behavior_dev,bindings[i].param1,bindings[i].param2); if (!handle_control_binding(&state, &bindings[i])) { struct zmk_behavior_binding binding = bindings[i]; replace_params(&state, &binding, macro_binding); - + LOG_DBG("state.mode:%d",state.mode); switch (state.mode) { case MACRO_MODE_TAP: zmk_behavior_queue_add(position, binding, true, state.tap_ms); @@ -181,7 +198,7 @@ static void queue_macro(uint32_t position, const struct zmk_behavior_binding bin } } } - +void dynamic_keymap_macro_send(uint8_t id); static int on_macro_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { const struct device *dev = device_get_binding(binding->behavior_dev); @@ -192,8 +209,25 @@ static int on_macro_binding_pressed(struct zmk_behavior_binding *binding, .wait_ms = cfg->default_wait_ms, .start_index = 0, .count = state->press_bindings_count}; - - queue_macro(event.position, cfg->bindings, trigger_state, binding); + if(memcmp(binding->behavior_dev,"ZM_MA",5)==0) + { + LOG_DBG("via macro,p1:%x,p2:%d",binding->param1,binding->param2); + if(binding->param1 !=0x770100) + dynamic_keymap_macro_send(binding->param1 &0xff); + else + { + char * p = zmk_keymap_highest_layer_active()>=2? keychron_web_win:keychron_web_mac; + // uint8_t len = strlen(p); + // LOG_HEXDUMP_ERR(p,len,"macro"); + send_string_with_delay(p,0); + send_string_end(); + } + } + + else + { + queue_macro(event.position, cfg->bindings, trigger_state, binding); + } return ZMK_BEHAVIOR_OPAQUE; } diff --git a/app/src/behaviors/behavior_outputs.c b/app/src/behaviors/behavior_outputs.c index 6ae81a0fdd7..0090e18cbcd 100644 --- a/app/src/behaviors/behavior_outputs.c +++ b/app/src/behaviors/behavior_outputs.c @@ -14,12 +14,37 @@ #include #include - +#include +#include +#include +#include #include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) +static uint8_t bat_charge_state; +static uint8_t bat_charge_done; +static uint8_t hardware_select_transport; +static uint8_t fn_win_lock; +extern void do_f1_f13_fn_exchange(void); +void bt_24g_switch_pulldown(uint8_t current); +void bt_24g_switch_reset(void); +uint8_t skip_switch_change(void); +bool keyboard_os_is_mac(void); +void clear_bat_shutdown(void); +void reset_led_power_on(void); +uint8_t get_mode_status(void); + +uint8_t get_hardware_select_transport(void) +{ + return hardware_select_transport; +} +bool get_fn_win_lock(void) +{ + return !keyboard_os_is_mac() &&fn_win_lock ; +} + static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { switch (binding->param1) { @@ -28,18 +53,194 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, case OUT_USB: return zmk_endpoints_select_transport(ZMK_TRANSPORT_USB); case OUT_BLE: - return zmk_endpoints_select_transport(ZMK_TRANSPORT_BLE); + { + LOG_ERR("out ble"); + reset_led_power_on(); + hardware_select_transport = ZMK_TRANSPORT_BLE; + // nrf_power_gpregret_set(NRF_POWER,REBOOT_ENDPOINT_BLE); + // if(zmk_usb_is_powered()) return 0; + uint8_t type = nrf_power_gpregret_get(NRF_POWER); + LOG_DBG("reboot type:%02x", type); + if (type == REBOOT_ENDPOINT_BLE) + { + // bt_24g_switch_pulldown(0); + zmk_endpoints_select_transport(ZMK_TRANSPORT_BLE); + + } + else + { + nrf_power_gpregret_set(NRF_POWER,REBOOT_ENDPOINT_BLE); + LOG_ERR("set:%x",REBOOT_ENDPOINT_BLE); + LOG_DBG("REBOOT"); + + k_msleep(200); + sys_reboot(REBOOT_ENDPOINT_BLE); + } + return 0; + } + case OUT_24G: + { + LOG_ERR("out 24g"); + reset_led_power_on(); + hardware_select_transport = ZMK_TRANSPORT_24G; + // nrf_power_gpregret_set(NRF_POWER,REBOOT_ENDPOINT_24G); + // if(zmk_usb_is_powered()) return 0; + uint8_t type = nrf_power_gpregret_get(NRF_POWER); + + LOG_DBG("reboot type:%02x", type); + if (type == REBOOT_ENDPOINT_24G) + { + // bt_24g_switch_pulldown(1); + zmk_endpoints_select_transport(ZMK_TRANSPORT_24G); + + } + else + { + nrf_power_gpregret_set(NRF_POWER,REBOOT_ENDPOINT_24G); + LOG_ERR("set:%x",REBOOT_ENDPOINT_24G); + LOG_DBG("REBOOT"); + k_msleep(200); + sys_reboot(REBOOT_ENDPOINT_24G); + } + return 0; + } + case OUT_CHG: + LOG_ERR("charging"); + led_charge_set_state(LED_BAT_CHARGING); + bat_charge_state =1; + // bt_24g_switch_reset(); + clear_bat_shutdown(); + return 0;; + case OUT_CHGD: + LOG_ERR("charge done"); + led_charge_set_state(LED_BAT_CHARGE_DONE); + bat_charge_done=1; + // bt_24g_switch_reset(); + return 0; + case OUT_BAT: + led_bat_display(); + return 0; + case OUT_FN: + do_f1_f13_fn_exchange(); + return 0; + case OUT_RECOVER: + void zmk_factory_recover(void); + zmk_factory_recover(); + return 0; + case OUT_FN_WIN: + { + fn_win_lock = ~fn_win_lock; + LOG_ERR("fn win lock:%d",fn_win_lock); + } + return 0; default: LOG_ERR("Unknown output command: %d", binding->param1); } return -ENOTSUP; } +void zmk_24g_endpoint_disconnect(void); +void zmk_ble_endpoint_disconnect(void); + + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + switch (binding->param1) { + case OUT_TOG: + case OUT_USB: + break; + case OUT_BLE: + LOG_ERR("switch off:%d",binding->param1); + zmk_ble_endpoint_disconnect(); + if(zmk_usb_is_powered()&&get_mode_status()==0x03) + { + hardware_select_transport=ZMK_TRANSPORT_USB; + reset_led_power_on(); + zmk_endpoints_select_transport(ZMK_TRANSPORT_USB); + } + else + { + LOG_ERR("select transport none"); + zmk_endpoints_select_transport(ZMK_TRANSPORT_NONE); + } + return 0; + case OUT_24G: + LOG_ERR("switch off:%d",binding->param1); + // if(skip_switch_change()) + // { + // LOG_ERR("skip"); + // return 0; + // } + zmk_24g_endpoint_disconnect(); + if(zmk_usb_is_powered()&&get_mode_status()==0x03) + { + hardware_select_transport=ZMK_TRANSPORT_USB; + reset_led_power_on(); + zmk_endpoints_select_transport(ZMK_TRANSPORT_USB); + } + else + { + LOG_ERR("select transport none"); + zmk_endpoints_select_transport(ZMK_TRANSPORT_NONE); + } + return 0; + // hardware_select_transport=ZMK_TRANSPORT_USB; + // return zmk_endpoints_select_transport(ZMK_TRANSPORT_USB); + case OUT_CHG: + LOG_ERR("not charging"); + led_charge_set_state(LED_BAT_NONE); + bat_charge_state =0; + // if(bat_charge_done==0) + // { + // LOG_ERR("reset pulldown"); + // if(get_current_transport()==ZMK_TRANSPORT_BLE) + // { + // bt_24g_switch_pulldown(0); + // } + // else if(get_current_transport()==ZMK_TRANSPORT_24G) + // { + // bt_24g_switch_pulldown(1); + // } + // } + return 0; + case OUT_CHGD: + LOG_ERR("not charge done"); + if(bat_charge_state) + led_charge_set_state(LED_BAT_CHARGING); + else + led_charge_set_state(LED_BAT_NONE); + bat_charge_done=0; + // if(bat_charge_state==0) + // { + // LOG_ERR("reset pulldown"); + // if(get_current_transport()==ZMK_TRANSPORT_BLE) + // { + // bt_24g_switch_pulldown(0); + // } + // else if(get_current_transport()==ZMK_TRANSPORT_24G) + // { + // bt_24g_switch_pulldown(1); + // } + // } + return 0; + case OUT_BAT: + led_bat_display_off(); + return 0; + case OUT_FN_WIN: + return 0; + + default: + LOG_ERR("Unknown output command: %d", binding->param1); + } + + return -ENOTSUP; +} static int behavior_out_init(const struct device *dev) { return 0; } static const struct behavior_driver_api behavior_outputs_driver_api = { .binding_pressed = on_keymap_binding_pressed, + .binding_released = on_keymap_binding_released, }; DEVICE_DT_INST_DEFINE(0, behavior_out_init, NULL, NULL, NULL, APPLICATION, diff --git a/app/src/behaviors/behavior_tap_dance.c b/app/src/behaviors/behavior_tap_dance.c index fc685124860..9d4e5dec1ee 100644 --- a/app/src/behaviors/behavior_tap_dance.c +++ b/app/src/behaviors/behavior_tap_dance.c @@ -109,6 +109,13 @@ static inline int press_tap_dance_behavior(struct active_tap_dance *tap_dance, i .position = tap_dance->position, .timestamp = timestamp, }; + LOG_DBG("binding:%s,p1:%d",binding.behavior_dev,binding.param1); + if((tap_dance->param1 &0x520000) ==0x520000) + { + uint8_t layer=tap_dance->param1 &0x1f; + LOG_DBG("to layer:%d",layer); + binding.param1= layer; + } return behavior_keymap_binding_pressed(&binding, event); } @@ -119,6 +126,12 @@ static inline int release_tap_dance_behavior(struct active_tap_dance *tap_dance, .position = tap_dance->position, .timestamp = timestamp, }; + if((tap_dance->param1 &0x520000) ==0x520000) + { + uint8_t layer=tap_dance->param1 &0x1f; + LOG_DBG("to layer:%d",layer); + binding.param1= layer; + } clear_tap_dance(tap_dance); return behavior_keymap_binding_released(&binding, event); } @@ -137,6 +150,10 @@ static int on_tap_dance_binding_pressed(struct zmk_behavior_binding *binding, LOG_DBG("%d created new tap dance", event.position); } tap_dance->is_pressed = true; + LOG_DBG("binding:%s,p1:%d,counter:%d",binding->behavior_dev,binding->param1, tap_dance->counter); + if(memcmp(binding->behavior_dev,"TAPD_LAYER",10)==0 ) + tap_dance->param1 = binding->param1|0x520000; + LOG_DBG("%d tap dance pressed", event.position); stop_timer(tap_dance); // Increment the counter on keypress. If the counter has reached its maximum diff --git a/app/src/ble.c b/app/src/ble.c index 483bc9d79c1..acebe3e6a05 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -19,7 +19,11 @@ #include #include #include -#include +#include +// #include +#include "conn_internal.h" +#include +#include #if IS_ENABLED(CONFIG_SETTINGS) @@ -30,16 +34,17 @@ #include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); - +#include #include #include #include #include #include - -#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) +#include +#include #include - +#include +#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) #define PASSKEY_DIGITS 6 static struct bt_conn *auth_passkey_entry_conn; @@ -47,12 +52,77 @@ RING_BUF_DECLARE(passkey_entries, PASSKEY_DIGITS); #endif /* IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) */ +#define ADV_RECONN_TIME_OUT (3000)//(3*60*1000) +#define ADV_PAIR_TIME_OUT (3*60*1000) +#if EN_UPATE_PARAM_DYNAMIC //disable for sometime send data fail! +void ble_param_update_work_callback(struct k_work *work); +void ble_active_work_callback(struct k_work *work); +K_WORK_DELAYABLE_DEFINE(ble_active_work, ble_active_work_callback); +K_WORK_DELAYABLE_DEFINE(ble_param_update_work, ble_param_update_work_callback); +static uint8_t ble_active; +static uint8_t ble_param_update_try_count =0; +#endif + +void update_conn_param_worker(struct k_work *work); +K_WORK_DELAYABLE_DEFINE(update_conn_param_work, update_conn_param_worker); + +bt_addr_le_t * inc_bt_addr(uint8_t index); +void print_device_addr(uint8_t id); +void zmk_24g_pair(void); +void zmk_24g_reconn(void); +void set_dis_value(void); +int load_immediate_value(const char *name, void *dest, size_t len); +bool bat_is_shutdown(void); +void zmk_ble_disconn_active_profile(void); +void zmk_24g_endpoint_disconnect(void); +void ble_active_handler(void); +void set_delay_clear_bonds(uint8_t set); +uint8_t delay_clear_bonds(void); + enum advertising_type { ZMK_ADV_NONE, ZMK_ADV_DIR, ZMK_ADV_CONN, + ZMK_ADV_RECONN, + ZMK_ADV_PAIR, } advertising_status; +static uint8_t adv_state; +void sleep_worker(struct k_work *work); +K_WORK_DELAYABLE_DEFINE(sleep_work, sleep_worker); + + +static void load_identities(void) { + + bt_addr_le_t addrs[CONFIG_BT_ID_MAX]; + size_t count = ARRAY_SIZE(addrs); + + bt_id_get(addrs, &count); + + LOG_INF("Device has %zu identities\n", count); + + /* Default identity should always exist */ + for (int i = 0; i < count; i++) { + char addr_str[64] = {0}; + + bt_addr_le_to_str(&addrs[i], addr_str, sizeof(addr_str)); + LOG_INF("Device i:%d,addr:%s\n", i, addr_str); + } + + for (; count < CONFIG_BT_ID_MAX; count++) { + int err = bt_id_create(NULL, NULL); + + if (err < 0) { + printk("Cannot create identity (err:%d)\n", err); + + break; + } else { + + printk("Identity %zu created\n", count); + } + } +} + #define CURR_ADV(adv) (adv << 4) #define ZMK_ADV_CONN_NAME \ @@ -61,6 +131,8 @@ enum advertising_type { static struct zmk_ble_profile profiles[ZMK_BLE_PROFILE_COUNT]; static uint8_t active_profile; +enum advertising_type desired_adv = ZMK_ADV_NONE; // change +static uint8_t adv_bt_id; #define DEVICE_NAME CONFIG_BT_DEVICE_NAME #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) @@ -75,6 +147,140 @@ static const struct bt_data zmk_ble_ad[] = { 0x0f, 0x18 /* Battery Service */ ), }; +//add swift pair +static const struct bt_data zmk_ble_ad_win[] = { + BT_DATA_BYTES(BT_DATA_GAP_APPEARANCE, 0xC1, 0x03), + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA_BYTES(BT_DATA_UUID16_SOME, 0x12, 0x18, /* HID Service */ + 0x0f, 0x18 /* Battery Service */ + ), + //swift pair + BT_DATA_BYTES(BT_DATA_MANUFACTURER_DATA,0x06,0x00, 0x03,0x00,0x80, 'K','e','y','c','h','r','o','n',' ','K','B') + +}; +static const struct bt_data zmk_ble_ad_sr[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), +}; + +static const struct bt_data zmk_ble_reconn_ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), +}; + +void adv_timeout_work_callback(struct k_work *work) { + int err = bt_le_adv_stop(); + advertising_status = ZMK_ADV_NONE; + blue_led_set_state( LED_PEER_STATE_DISCONNECTED); + + LOG_INF("adv timeout ,stop"); + if (err) { + LOG_ERR("Failed to stop advertising (err %d)", err); + } + k_work_reschedule(&sleep_work, (adv_state ==ZMK_ADV_RECONN)?K_MSEC(40*1000-ADV_RECONN_TIME_OUT):K_NO_WAIT); + adv_state = ZMK_ADV_NONE; +} +void sleep_worker(struct k_work *work) +{ + LOG_INF("sleep"); + set_state(ZMK_ACTIVITY_SLEEP); +} +K_WORK_DELAYABLE_DEFINE(adv_timeout_work, adv_timeout_work_callback); +void print_bt_addr(const bt_addr_le_t *addr); +int update_advertising(void); +// static struct k_work_delayable update_advertising_work; +static void update_advertising_callback(struct k_work *work) { + LOG_INF("update_advertising_callback"); + update_advertising(); +} +// K_WORK_DELAYABLE_DEFINE(update_advertising_work, update_advertising_callback); +K_WORK_DEFINE(update_advertising_work, update_advertising_callback); + +bool zmk_ble_active_profile_is_connected(void); +bool zmk_ble_active_profile_is_open(void); +int zmk_ble_prof_pair_start(uint8_t index); +int zmk_ble_prof_select(uint8_t index); +void hid_disconnected(struct bt_conn *conn, uint8_t reason); +void insert_conn_object(struct bt_conn *conn); +void load_identities(void); +struct switch_to_adv { + uint8_t adv_type : 4; + uint8_t index : 4; +}; +struct switch_to_adv switch_state; +// static uint8_t switch_to_pair; +/* Bonded address queue. */ +// K_MSGQ_DEFINE(bonds_queue, +// sizeof(bt_addr_le_t), +// CONFIG_BT_MAX_PAIRED, +// 4); + +static void bond_cnt_cb(const struct bt_bond_info *info, void *user_data) { + size_t *cnt = user_data; + if (bt_addr_le_cmp(&info->addr, zmk_ble_active_profile_addr())) { + // not same + return; + } + (*cnt)++; +} + +static size_t bond_check(uint8_t local_id) { + size_t cnt = 0; + + bt_foreach_bond(local_id, bond_cnt_cb, &cnt); + + // if(cnt==0) + // { + // profiles[local_id].bt_id =0xff; + // } + + return cnt; +} + +// extern struct k_msgq bonds_queue; + +// static void bond_find(const struct bt_bond_info *info, void *user_data) { +// int err; + +// if (bt_addr_le_cmp(&info->addr, zmk_ble_active_profile_addr()) || +// zmk_ble_active_profile_is_connected()) { +// // not same +// return; +// } +// printk("id:%d,bond peer ", active_profile); +// print_bt_addr(&info->addr); +// err = k_msgq_put(&bonds_queue, (void *)&info->addr, K_NO_WAIT); +// if (err) { +// printk("No space in the queue for the bond.\n"); +// } +// } + +static int setup_accept_list(void) { + int err = bt_le_filter_accept_list_clear(); + if (err) { + LOG_ERR("Cannot clear filter accept list (err: %d)", err); + return err; + } + + err = bt_le_filter_accept_list_add(zmk_ble_active_profile_addr()); + if (err) { + LOG_ERR("Cannot add peer to filter accept list (err: %d)", err); + return err; + } + + return 0; +} +static void advertising_start(void) { + // if (zmk_ble_active_profile_is_open()) { + // desired_adv = ZMK_ADV_CONN; + // } else if (!zmk_ble_active_profile_is_connected()) { + // desired_adv = ZMK_ADV_RECONN; + // } + + // LOG_INF("advertising_start,desired_adv:%d\n",desired_adv); + // k_work_submit(&update_advertising_work); + if(adv_state!=ZMK_ADV_PAIR) + zmk_ble_prof_select(active_profile); +} #if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) @@ -83,8 +289,21 @@ static bt_addr_le_t peripheral_addrs[ZMK_SPLIT_BLE_PERIPHERAL_COUNT]; #endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */ static void raise_profile_changed_event() { - ZMK_EVENT_RAISE(new_zmk_ble_active_profile_changed((struct zmk_ble_active_profile_changed){ - .index = active_profile, .profile = &profiles[active_profile]})); + // ZMK_EVENT_RAISE(new_zmk_ble_active_profile_changed((struct zmk_ble_active_profile_changed){ + // .index = active_profile, .profile = &profiles[active_profile]})); + LOG_INF("raise_profile_changed_event"); + if (!zmk_ble_active_profile_is_connected() && switch_state.adv_type) { + switch (switch_state.adv_type) { + case ZMK_ADV_PAIR: + switch_state.adv_type = 0; + zmk_ble_prof_pair_start(switch_state.index); + break; + case ZMK_ADV_RECONN: + switch_state.adv_type = 0; + zmk_ble_prof_select(switch_state.index); + break; + } + } } static void raise_profile_changed_event_callback(struct k_work *work) { @@ -96,9 +315,23 @@ K_WORK_DEFINE(raise_profile_changed_event_work, raise_profile_changed_event_call bool zmk_ble_active_profile_is_open() { return !bt_addr_le_cmp(&profiles[active_profile].peer, BT_ADDR_LE_ANY); } - +void copy_profile_to_same_peer(const bt_addr_le_t *peer) { + for (int i = 0; i < ZMK_BLE_PROFILE_COUNT; i++) { + if (!bt_addr_le_cmp(&profiles[i].peer, peer) && + (profiles[i].bt_id != profiles[active_profile].bt_id)) { + bt_id_reset(profiles[i].bt_id,inc_bt_addr(profiles[i].bt_id), NULL); + profiles[i].bt_id = profiles[active_profile].bt_id; + // profiles[i].is_rpa = profiles[active_profile].is_rpa; + profiles[i].bonded = profiles[active_profile].bonded; + char setting_name[20]; + sprintf(setting_name, "ble/profiles/%d", i); + settings_save_one(setting_name, &profiles[i], sizeof(struct zmk_ble_profile)); + LOG_INF("copy profle %d to %d", active_profile, i); + } + } +} void set_profile_address(uint8_t index, const bt_addr_le_t *addr) { - char setting_name[15]; + char setting_name[20]; char addr_str[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); @@ -109,14 +342,24 @@ void set_profile_address(uint8_t index, const bt_addr_le_t *addr) { settings_save_one(setting_name, &profiles[index], sizeof(struct zmk_ble_profile)); k_work_submit(&raise_profile_changed_event_work); } +void save_profile(uint8_t index) { + char setting_name[20]; + sprintf(setting_name, "ble/profiles/%d", index); + settings_save_one(setting_name, &profiles[index], sizeof(struct zmk_ble_profile)); +} bool zmk_ble_active_profile_is_connected() { struct bt_conn *conn; struct bt_conn_info info; bt_addr_le_t *addr = zmk_ble_active_profile_addr(); + char addr_str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + // LOG_INF("active profie:%d,peer:%s",active_profile,addr_str); if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) { return false; - } else if ((conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr)) == NULL) { + } else if ((conn = bt_conn_lookup_addr_le(profiles[active_profile].bt_id, addr)) == NULL) { + LOG_INF("pro:%d,conn found none", active_profile); return false; } @@ -135,7 +378,7 @@ bool zmk_ble_active_profile_is_connected() { return err; \ } -#define CHECKED_DIR_ADV() \ +#define _CHECKED_DIR_ADV() \ addr = zmk_ble_active_profile_addr(); \ conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr); \ if (conn != NULL) { /* TODO: Check status of connection */ \ @@ -150,82 +393,243 @@ bool zmk_ble_active_profile_is_connected() { return err; \ } \ advertising_status = ZMK_ADV_DIR; +// adv_param.options |= BT_LE_ADV_OPT_DIR_ADDR_RPA; +#define CHECKED_DIR_ADV() \ + { \ + char addr_buf[BT_ADDR_LE_STR_LEN]; \ + addr = zmk_ble_active_profile_addr(); \ + struct bt_le_adv_param adv_param; \ + adv_param = *BT_LE_ADV_CONN_DIR(addr); \ + adv_param.id = adv_bt_id; \ + if (IS_ENABLED(CONFIG_BT_PRIVACY)) { \ + adv_param.options |= BT_LE_ADV_OPT_DIR_ADDR_RPA; \ + } \ + adv_param.options |= BT_LE_ADV_OPT_USE_IDENTITY; \ + int err = bt_le_adv_start(&adv_param, NULL, 0, NULL, 0); \ + if (err) { \ + LOG_ERR("Directed advertising failed to start\n"); \ + return err; \ + } \ + bt_addr_le_to_str(addr, addr_buf, BT_ADDR_LE_STR_LEN); \ + LOG_INF("Direct advertising to %s started,prof:%d,id:%d\n", addr_buf, active_profile, \ + profiles[active_profile].bt_id); \ + advertising_status = ZMK_ADV_DIR; \ + } #define CHECKED_OPEN_ADV() \ - err = bt_le_adv_start(ZMK_ADV_CONN_NAME, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); \ - if (err) { \ - LOG_ERR("Advertising failed to start (err %d)", err); \ - return err; \ - } \ + { \ + struct bt_le_adv_param adv_param; \ + adv_param = *ZMK_ADV_CONN_NAME; \ + adv_param.id = adv_bt_id; \ + if (IS_ENABLED(CONFIG_BT_PRIVACY)) { \ + adv_param.options |= BT_LE_ADV_OPT_DIR_ADDR_RPA; \ + } \ + adv_param.options |= BT_LE_ADV_OPT_USE_IDENTITY; \ + if (enable_filter == 0) { \ + adv_param.options |= BT_LE_ADV_OPT_FILTER_SCAN_REQ; \ + adv_param.options |= BT_LE_ADV_OPT_FILTER_CONN; \ + } \ + err = bt_le_adv_start(&adv_param, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); \ + if (err) { \ + LOG_ERR("Advertising failed to start (err %d)", err); \ + return err; \ + } \ + advertising_status = ZMK_ADV_CONN; \ + } + +static int enable_filter = -1; +void checked_adv_stop(void) { + int err = bt_le_adv_stop(); + advertising_status = ZMK_ADV_NONE; + if (err) { + LOG_ERR("Failed to stop advertising (err %d)", err); + } + return; +} + +void checked_dir_adv(void) { + char addr_buf[BT_ADDR_LE_STR_LEN]; + bt_addr_le_t *addr = zmk_ble_active_profile_addr(); + struct bt_le_adv_param adv_param; + adv_param = *BT_LE_ADV_CONN_DIR(addr); + adv_param.id = adv_bt_id; + if (profiles[active_profile].is_rpa) { + adv_param.options |= BT_LE_ADV_OPT_DIR_ADDR_RPA; + LOG_INF("dir add adv opt: RPA"); + } + if (!IS_ENABLED(CONFIG_BT_PRIVACY)) { + adv_param.options |= BT_LE_ADV_OPT_USE_IDENTITY; + LOG_INF("dir add adv opt: IDENTITY,id:%d", adv_bt_id); + } + int err = bt_le_adv_start(&adv_param, NULL, 0, NULL, 0); + if (err) { + LOG_ERR("Directed advertising failed to start:%d\n", err); + return; + } + bt_addr_le_to_str(addr, addr_buf, BT_ADDR_LE_STR_LEN); + LOG_INF("Direct advertising to %s started,prof:%d,id:%d\n", addr_buf, active_profile, + profiles[active_profile].bt_id); + advertising_status = ZMK_ADV_DIR; +} + +void checked_open_adv(void) { + struct bt_le_adv_param adv_param; + adv_param = *ZMK_ADV_CONN_NAME; + adv_param.id = adv_bt_id; + + adv_param.options |= BT_LE_ADV_OPT_USE_IDENTITY; + LOG_INF("adv opt: IDENTITY,id:%d", adv_bt_id); + if (enable_filter == 0) { + adv_param.options |= BT_LE_ADV_OPT_FILTER_SCAN_REQ; + adv_param.options |= BT_LE_ADV_OPT_FILTER_CONN; + LOG_INF("adv opt: FILTER"); + } + int err; + if(adv_state == ZMK_ADV_RECONN) + { + err = bt_le_adv_start(&adv_param, zmk_ble_reconn_ad, ARRAY_SIZE(zmk_ble_reconn_ad), NULL, 0); + } + else + { + if(zmk_keymap_highest_layer_active()>=2) + { + err=bt_le_adv_start(&adv_param, zmk_ble_ad_win, ARRAY_SIZE(zmk_ble_ad_win), zmk_ble_ad_sr, ARRAY_SIZE(zmk_ble_ad_sr)); + } + else + err = bt_le_adv_start(&adv_param, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); + } + if (err) { + LOG_ERR("Advertising failed to start (err %d)", err); + return; + } advertising_status = ZMK_ADV_CONN; +} int update_advertising() { - int err = 0; - bt_addr_le_t *addr; - struct bt_conn *conn; - enum advertising_type desired_adv = ZMK_ADV_NONE; - - if (zmk_ble_active_profile_is_open()) { - desired_adv = ZMK_ADV_CONN; - } else if (!zmk_ble_active_profile_is_connected()) { + // int err = 0; + // bt_addr_le_t *addr; + enable_filter = -1; + keyboad_led_set_onoff(0); + if (desired_adv == ZMK_ADV_RECONN) { + if (bond_check(profiles[active_profile].bt_id)) { + desired_adv = ZMK_ADV_DIR; + enable_filter = setup_accept_list(); + blue_led_set_state( LED_PEER_STATE_RECONN); + } else { + desired_adv = ZMK_ADV_CONN; + blue_led_set_state( LED_PEER_STATE_RECONN); + } + } else if (desired_adv == ZMK_ADV_PAIR) { desired_adv = ZMK_ADV_CONN; - // Need to fix directed advertising for privacy centrals. See - // https://github.com/zephyrproject-rtos/zephyr/pull/14984 char - // addr_str[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(zmk_ble_active_profile_addr(), addr_str, - // sizeof(addr_str)); - - // LOG_DBG("Directed advertising to %s", addr_str); - // desired_adv = ZMK_ADV_DIR; + blue_led_set_state( LED_PEER_STATE_PAIR); + k_work_cancel_delayable(&sleep_work); } - LOG_DBG("advertising from %d to %d", advertising_status, desired_adv); + + LOG_DBG("advertising from %d to %d,adv id:%d", advertising_status, desired_adv, adv_bt_id); switch (desired_adv + CURR_ADV(advertising_status)) { case ZMK_ADV_NONE + CURR_ADV(ZMK_ADV_DIR): case ZMK_ADV_NONE + CURR_ADV(ZMK_ADV_CONN): - CHECKED_ADV_STOP(); + checked_adv_stop(); break; case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_DIR): case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_CONN): - CHECKED_ADV_STOP(); - CHECKED_DIR_ADV(); + checked_adv_stop(); + checked_dir_adv(); break; case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_NONE): - CHECKED_DIR_ADV(); + checked_dir_adv(); break; + case ZMK_ADV_CONN + CURR_ADV(ZMK_ADV_CONN): case ZMK_ADV_CONN + CURR_ADV(ZMK_ADV_DIR): - CHECKED_ADV_STOP(); - CHECKED_OPEN_ADV(); + { + checked_adv_stop(); + checked_open_adv(); + k_timeout_t timeout = (adv_state== ZMK_ADV_PAIR) ? K_MSEC(ADV_PAIR_TIME_OUT):K_MSEC(ADV_RECONN_TIME_OUT); + k_work_reschedule(&adv_timeout_work, timeout); + } break; case ZMK_ADV_CONN + CURR_ADV(ZMK_ADV_NONE): - CHECKED_OPEN_ADV(); + { + checked_open_adv(); + k_timeout_t timeout = (adv_state== ZMK_ADV_PAIR) ? K_MSEC(ADV_PAIR_TIME_OUT):K_MSEC(ADV_RECONN_TIME_OUT); + k_work_reschedule(&adv_timeout_work, timeout); + } break; } return 0; }; -static void update_advertising_callback(struct k_work *work) { update_advertising(); } - -K_WORK_DEFINE(update_advertising_work, update_advertising_callback); - -int zmk_ble_clear_bonds() { +static struct k_work_delayable factory_recover_work; +static void factory_recover_work_cb(struct k_work *work) +{ + static uint8_t state =0; + if(state==0) + { + led_recover(); + k_work_reschedule(&factory_recover_work, K_MSEC(2800)); + state++; + } + else + { + k_msleep(200); + sys_reboot(0); + } +} +void zmk_factory_recover(void) +{ + if(get_current_transport()==ZMK_TRANSPORT_BLE) + { + zmk_ble_disconn_active_profile(); + k_msleep(100); + bt_le_adv_stop(); + zmk_ble_clear_bonds(); + } + else + { + zmk_24g_endpoint_disconnect(); + set_delay_clear_bonds(1); + } +#if CONFIG_ZMK_LAUNCHER + void via_ee_delete(void); + via_ee_delete(); +#endif + settings_delete("fn_exchange"); + + + k_work_init_delayable(&factory_recover_work, factory_recover_work_cb); + k_work_reschedule(&factory_recover_work, K_MSEC(200)); +} +int zmk_ble_clear_bonds(void) +{ + char setting_name[20]; LOG_DBG(""); + + int i; + for(i=1;ible_save_profile"); settings_save_one("ble/active_profile", &active_profile, sizeof(active_profile)); } @@ -234,28 +638,148 @@ static struct k_work_delayable ble_save_work; static int ble_save_profile() { #if IS_ENABLED(CONFIG_SETTINGS) - return k_work_reschedule(&ble_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE)); + return k_work_reschedule(&ble_save_work, K_MSEC(2500)); #else return 0; #endif } +int get_empty_bt_id(void) { + uint8_t ret = -1; + uint8_t id; + for (id = 1; id < CONFIG_BT_ID_MAX; id++) { //not use id=0; + uint8_t used = 0; + for (int i = 0; i < ZMK_BLE_PROFILE_COUNT; i++) { + if ((id == profiles[i].bt_id) && (profiles[i].bt_id != 0x0f)) { + used = 1; + break; + } + } + if (!used) { + ret = id; + break; + } + } + LOG_INF("get empty id:%d", ret); + return ret; +} +int zmk_ble_prof_pair_start(uint8_t index) { + if (index >= ZMK_BLE_PROFILE_COUNT) { + return -ERANGE; + } + if(get_current_transport()==ZMK_TRANSPORT_24G) + { + if(index ==3) + zmk_24g_pair(); + return 0; + } + if(get_current_transport()!=ZMK_TRANSPORT_BLE || (index>=3)) + { + return -ENOTSUP; + } + if (zmk_ble_active_profile_is_connected()) // wait for disconnect! + { + struct bt_conn *conn = NULL; + bt_addr_le_t *addr = zmk_ble_active_profile_addr(); + LOG_INF("wait for disconnect %d", active_profile); + conn = bt_conn_lookup_addr_le(profiles[active_profile].bt_id, addr); + if (conn != NULL) { + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + bt_conn_unref(conn); + } + switch_state.adv_type = ZMK_ADV_PAIR; + switch_state.index = index; + return -ERANGE; + } + + LOG_DBG("profile %d,pairing", index); + if (active_profile != index) { + active_profile = index; + ble_save_profile(); + raise_profile_changed_event(); + } + + if ((profiles[active_profile].bt_id == 0x0f) || + (bond_check(profiles[active_profile].bt_id) > 0)) { + int id = get_empty_bt_id(); + if (id >= 0) { + adv_bt_id = id; + } else { + LOG_ERR("bt id get failed"); + } + } else + adv_bt_id = profiles[active_profile].bt_id; + + profiles[active_profile].is_rpa = 0; + LOG_INF("in pair,prof:%d,adv bt id:%d", active_profile, adv_bt_id); + print_device_addr(adv_bt_id); + + desired_adv = ZMK_ADV_PAIR; + adv_state =ZMK_ADV_PAIR; + k_work_submit(&update_advertising_work); + return 0; +} int zmk_ble_prof_select(uint8_t index) { if (index >= ZMK_BLE_PROFILE_COUNT) { return -ERANGE; } - - LOG_DBG("profile %d", index); - if (active_profile == index) { + if(get_current_transport() == ZMK_TRANSPORT_24G) + { + if(index ==3) + { + zmk_24g_reconn(); + } + return 0; + } + if(get_current_transport()!=ZMK_TRANSPORT_BLE || (index>=3)) + { + return -ENOTSUP; + } + LOG_DBG("active profile %d need to :%d", active_profile, index); + if (active_profile == index && zmk_ble_active_profile_is_connected()) { return 0; } - active_profile = index; - ble_save_profile(); + if (zmk_ble_active_profile_is_connected()) // wait for disconnect! + { + struct bt_conn *conn = NULL; + bt_addr_le_t *addr = zmk_ble_active_profile_addr(); + LOG_INF("wait for disconnect %d", active_profile); + conn = bt_conn_lookup_addr_le(profiles[active_profile].bt_id, addr); + if (conn != NULL) { + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + bt_conn_unref(conn); + } - update_advertising(); + switch_state.adv_type = ZMK_ADV_RECONN; + switch_state.index = index; + return -ERANGE; + } + if(active_profile !=index) + { + active_profile = index; + ble_save_profile(); + } - raise_profile_changed_event(); + if ((profiles[active_profile].bt_id == 0x0f)) { + int id = get_empty_bt_id(); + if (id >= 0) { + adv_bt_id = id; + profiles[active_profile].is_rpa = 0; + LOG_INF("prof:%d,bt id:%d", active_profile, adv_bt_id); + } else { + LOG_ERR("bt id get failed"); + } + } else + adv_bt_id = profiles[active_profile].bt_id; + + print_device_addr(adv_bt_id); + + desired_adv = ZMK_ADV_RECONN; + adv_state = ZMK_ADV_RECONN; + k_work_submit(&update_advertising_work); + + // raise_profile_changed_event(); return 0; }; @@ -395,8 +919,21 @@ static bool is_conn_active_profile(const struct bt_conn *conn) { static void connected(struct bt_conn *conn, uint8_t err) { char addr[BT_ADDR_LE_STR_LEN]; struct bt_conn_info info; - LOG_DBG("Connected thread: %p", k_current_get()); + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + LOG_DBG("Connected thread: %p,conn id:%d", k_current_get(), conn->id); + if (err) { + if (err == BT_HCI_ERR_ADV_TIMEOUT) { + printk("Direct advertising to %s timed out\n", addr); + advertising_status = ZMK_ADV_NONE; + desired_adv = ZMK_ADV_CONN; + k_work_submit(&update_advertising_work); + + } else { + printk("Failed to connect to %s (%u)\n", addr, err); + } + return; + } bt_conn_get_info(conn, &info); if (info.role != BT_CONN_ROLE_PERIPHERAL) { @@ -404,33 +941,34 @@ static void connected(struct bt_conn *conn, uint8_t err) { return; } - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); advertising_status = ZMK_ADV_NONE; + adv_state = advertising_status; + k_work_cancel_delayable(&adv_timeout_work); + blue_led_set_state( LED_PEER_STATE_CONNECTED); - if (err) { - LOG_WRN("Failed to connect to %s (%u)", addr, err); - update_advertising(); - return; - } + profiles[active_profile].connected=1; LOG_DBG("Connected %s", addr); - - if (bt_conn_set_security(conn, BT_SECURITY_L2)) { - LOG_ERR("Failed to set security"); + int ret = bt_conn_set_security(conn, BT_SECURITY_L2); + if (ret) { + LOG_ERR("Failed to set security,err:%d", ret); //,id:%d", ret,conn->id); } - update_advertising(); - if (is_conn_active_profile(conn)) { LOG_DBG("Active profile connected"); k_work_submit(&raise_profile_changed_event_work); } +#if EN_UPATE_PARAM_DYNAMIC + k_work_reschedule(&ble_active_work,K_MSEC(15000)); +#endif + k_work_reschedule(&update_conn_param_work,K_MSEC(5000)); } static void disconnected(struct bt_conn *conn, uint8_t reason) { char addr[BT_ADDR_LE_STR_LEN]; struct bt_conn_info info; - + if(!zmk_usb_is_powered()) + keyboad_led_set_onoff(0); bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); LOG_DBG("Disconnected from %s (reason 0x%02x)", addr, reason); @@ -441,15 +979,25 @@ static void disconnected(struct bt_conn *conn, uint8_t reason) { LOG_DBG("SKIPPING FOR ROLE %d", info.role); return; } - + profiles[active_profile].connected=0; // We need to do this in a work callback, otherwise the advertising update will still see the // connection for a profile as active, and not start advertising yet. - k_work_submit(&update_advertising_work); + // k_work_submit(&update_advertising_work); + if ((reason != BT_HCI_ERR_REMOTE_USER_TERM_CONN) && + (reason != BT_HCI_ERR_LOCALHOST_TERM_CONN) && (reason != BT_HCI_ERR_REMOTE_POWER_OFF)) { + advertising_start(); + } + else + { + if(switch_state.adv_type==0) + set_state(ZMK_ACTIVITY_SLEEP); + } if (is_conn_active_profile(conn)) { LOG_DBG("Active profile disconnected"); k_work_submit(&raise_profile_changed_event_work); } + k_work_cancel_delayable(&update_conn_param_work); } static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) { @@ -459,8 +1007,31 @@ static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_ if (!err) { LOG_DBG("Security changed: %s level %u", addr, level); + if (level >= BT_SECURITY_L2) { + + if (bt_addr_le_is_rpa(bt_conn_get_dst(conn))) { + profiles[active_profile].is_rpa = 1; + LOG_INF("host:%s is rpa", addr); + } + if(!profiles[active_profile].bonded) + { + profiles[active_profile].bonded =1; + set_profile_address(active_profile, bt_conn_get_dst(conn)); + LOG_DBG("NOT BOND,SAVE AGAIN"); + } + } } else { LOG_ERR("Security failed: %s level %u err %d", addr, level, err); + if(err ==BT_SECURITY_ERR_PIN_OR_KEY_MISSING) + { + // bt_unpair(conn->id, bt_conn_get_dst(conn)); + bt_id_reset(conn->id,inc_bt_addr(conn->id),NULL); + profiles[active_profile].is_rpa = 0; + profiles[active_profile].bonded = 0; + set_profile_address(active_profile, BT_ADDR_LE_ANY); + LOG_INF("clear pair info"); + blue_led_set_state( LED_PEER_STATE_FAILE); + } } } @@ -471,6 +1042,10 @@ static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t l bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); LOG_DBG("%s: interval %d latency %d timeout %d", addr, interval, latency, timeout); +#if EN_UPATE_PARAM_DYNAMIC + k_work_cancel_delayable(&ble_param_update_work); + ble_param_update_try_count=0; +#endif } static struct bt_conn_cb conn_callbacks = { @@ -480,7 +1055,7 @@ static struct bt_conn_cb conn_callbacks = { .le_param_updated = le_param_updated, }; -/* + static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) { char addr[BT_ADDR_LE_STR_LEN]; @@ -488,7 +1063,7 @@ static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) { LOG_DBG("Passkey for %s: %06u", addr, passkey); } -*/ + #if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) @@ -548,19 +1123,38 @@ static void auth_pairing_complete(struct bt_conn *conn, bool bonded) { return; } - if (!zmk_ble_active_profile_is_open()) { - LOG_ERR("Pairing completed but current profile is not open: %s", addr); - bt_unpair(BT_ID_DEFAULT, dst); - return; + // if (!zmk_ble_active_profile_is_open()) { + // LOG_ERR("Pairing completed but current profile is not open: %s", addr); + // bt_unpair(BT_ID_DEFAULT, dst); + // return; + // } + if (profiles[active_profile].bt_id != conn->id) + { + // if (profiles[active_profile].bt_id != 0x0f) + // { + // if(conn->id==0) + // { + // LOG_DBG("-->unpair bt 0\n"); + // bt_unpair(conn->id, bt_conn_get_dst(conn)); + // } + // else + // { + // bt_id_reset(profiles[active_profile].bt_id, inc_bt_addr(profiles[active_profile].bt_id), NULL); + // } + // LOG_INF("reset bt id:%d,new:%d", profiles[active_profile].bt_id, conn->id); + // } + profiles[active_profile].bt_id = conn->id; } + profiles[active_profile].bonded=1; set_profile_address(active_profile, dst); - update_advertising(); + // due to CONFIG_BT_ID_UNPAIR_MATCHING_BONDS + copy_profile_to_same_peer(dst); }; static struct bt_conn_auth_cb zmk_ble_auth_cb_display = { .pairing_accept = auth_pairing_accept, -// .passkey_display = auth_passkey_display, + .passkey_display = auth_passkey_display, #if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) .passkey_entry = auth_passkey_entry, @@ -568,6 +1162,7 @@ static struct bt_conn_auth_cb zmk_ble_auth_cb_display = { .cancel = auth_cancel, }; + static struct bt_conn_auth_info_cb zmk_ble_auth_info_cb_display = { .pairing_complete = auth_pairing_complete, }; @@ -579,19 +1174,50 @@ static void zmk_ble_ready(int err) { return; } - update_advertising(); + // update_advertising(); + // advertising_start(); + profiles[active_profile].connected=0; + // settings_subsys_init(); + + // err = settings_register(&profiles_handler); + // if (err) { + // LOG_ERR("Failed to setup the profile settings handler (err %d)", err); + // return ; + // } + + // settings_load_subtree("ble"); + advertising_start(); } -static int zmk_ble_init(const struct device *_arg) { +// static int zmk_ble_init(const struct device *_arg) +int zmk_ble_init(const struct device *_arg) { + + // uint8_t addr[]={0x31,0x10,0x23,0x26,0x2c,0xdc}; + // int ret=bt_ctlr_set_public_addr(addr); + // LOG_INF("bt_ctlr_set_public_addr,ret:%d\n",ret); + static bool inited =false; + if(bat_is_shutdown()) return 0; + if(inited) + { + advertising_start(); + return 0; + } + inited =true; + + for (int i = 0; i < ZMK_BLE_PROFILE_COUNT; i++) + profiles[i].bt_id = 0x0f; int err = bt_enable(NULL); if (err) { LOG_ERR("BLUETOOTH FAILED (%d)", err); return err; } + // leds_init(NULL); #if IS_ENABLED(CONFIG_SETTINGS) + LOG_INF("settings init"); settings_subsys_init(); + err = settings_register(&profiles_handler); if (err) { @@ -603,6 +1229,16 @@ static int zmk_ble_init(const struct device *_arg) { settings_load_subtree("ble"); settings_load_subtree("bt"); + load_identities(); + + set_dis_value(); + // advertising_start(); + + if(delay_clear_bonds()) + { + zmk_ble_clear_bonds(); + set_delay_clear_bonds(0); + } #endif @@ -636,11 +1272,13 @@ static int zmk_ble_init(const struct device *_arg) { #endif // IS_ENABLED(CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START) bt_conn_cb_register(&conn_callbacks); - bt_conn_auth_cb_register(&zmk_ble_auth_cb_display); + // bt_conn_auth_cb_register(&zmk_ble_auth_cb_display); bt_conn_auth_info_cb_register(&zmk_ble_auth_info_cb_display); zmk_ble_ready(0); + // enable_llpm_mode(); + return 0; } @@ -711,14 +1349,34 @@ static int zmk_ble_handle_key_user(struct zmk_keycode_state_changed *event) { return ZMK_EV_EVENT_HANDLED; } +#endif /* IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) */ static int zmk_ble_listener(const zmk_event_t *eh) { struct zmk_keycode_state_changed *kc_state; - + kc_state = as_zmk_keycode_state_changed(eh); - if (kc_state != NULL) { - return zmk_ble_handle_key_user(kc_state); + if ((kc_state != NULL) && !bat_is_shutdown()) { + if(kc_state->state) { + LOG_DBG("."); + if(get_current_transport()==ZMK_TRANSPORT_BLE){ + LOG_DBG("profiles:%d,bonded:%d,connected:%d",active_profile,profiles[active_profile].bonded,profiles[active_profile].connected); + if(!profiles[active_profile].connected ) + { + advertising_start(); + } +#if EN_UPATE_PARAM_DYNAMIC + else + { + ble_active_handler(); + } +#endif + } + else if(get_current_transport()==ZMK_TRANSPORT_24G) + { + zmk_24g_reconn(); + } + } } return 0; @@ -726,6 +1384,213 @@ static int zmk_ble_listener(const zmk_event_t *eh) { ZMK_LISTENER(zmk_ble, zmk_ble_listener); ZMK_SUBSCRIPTION(zmk_ble, zmk_keycode_state_changed); -#endif /* IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) */ -SYS_INIT(zmk_ble_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY); + +// SYS_INIT(zmk_ble_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY); + +uint8_t zmk_ble_get_active_profile(void) { return active_profile; } + +uint8_t zmk_ble_get_active_profile_bt_id(void) { return profiles[active_profile].bt_id; } + +uint8_t zmk_ble_is_connected(void) {return profiles[active_profile].connected;} + +void zmk_ble_disconn_active_profile(void) { + if (zmk_ble_active_profile_is_connected()) // wait for disconnect! + { + struct bt_conn *conn; + bt_addr_le_t *addr = zmk_ble_active_profile_addr(); + LOG_INF("try for disconnect %d", active_profile); + conn = bt_conn_lookup_addr_le(profiles[active_profile].bt_id, addr); + if (conn != NULL) { + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + bt_conn_unref(conn); + } + } +} +void zmk_ble_endpoint_disconnect(void) +{ + if(get_current_transport()==ZMK_TRANSPORT_BLE) + { + struct bt_conn *conn = NULL; + bt_addr_le_t *addr = zmk_ble_active_profile_addr(); + + conn = bt_conn_lookup_addr_le(profiles[active_profile].bt_id, addr); + if (conn != NULL) { + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + bt_conn_unref(conn); + } + k_work_reschedule(&adv_timeout_work,K_MSEC(20)); + } +} + + +static bt_addr_le_t inced_bt_addr; +bt_addr_le_t * inc_bt_addr(uint8_t index) +{ + bt_addr_le_t addrs[CONFIG_BT_ID_MAX]; + size_t count = ARRAY_SIZE(addrs); + bt_id_get(addrs, &count); + LOG_DBG("index:%d,count:%d",index,count); + if(index DEVICEID[0]>>(i*8)); + } + sprintf(&sn[10],"%02x%02x%02x%02x",deviceid[0],deviceid[1],deviceid[2],deviceid[3]); + settings_save_one("bt/dis/serial",sn,strlen(sn)); + LOG_DBG("set sn:%s",sn); + } + else + { + LOG_DBG("sn is:%s",sn); + } +} +#if EN_UPATE_PARAM_DYNAMIC +int update_ble_conn_param(void) +{ + int rc=0; + struct bt_le_conn_param *slow_param =BT_LE_CONN_PARAM(40, 40,30,400); + struct bt_le_conn_param *active_param =BT_LE_CONN_PARAM(6, 12,30,400); + struct bt_conn *conn; + bt_addr_le_t *addr = zmk_ble_active_profile_addr(); + + conn = bt_conn_lookup_addr_le(profiles[active_profile].bt_id, addr); + LOG_DBG("conn:%p,active:%d",conn,ble_active); + if (conn != NULL) { + rc= bt_conn_le_param_update(conn,ble_active?active_param:slow_param); + LOG_DBG("rc:%d",rc); + bt_conn_unref(conn); + } + return rc; +} + +void ble_active_work_callback(struct k_work *work) +{ + ble_active=0; + LOG_DBG("."); + k_work_reschedule(&ble_param_update_work,K_NO_WAIT); +} +void ble_param_update_work_callback(struct k_work *work) +{ + LOG_DBG("try_count:%d",ble_param_update_try_count); + int rc =update_ble_conn_param(); + if(rc!=0 && rc !=-EALREADY) + { + if(++ble_param_update_try_count <=3) + { + k_work_reschedule(&ble_param_update_work,K_MSEC(1000)); + } + } + else + ble_param_update_try_count =0; +} +void ble_active_handler(void) +{ + ble_active =1; + struct bt_conn *conn; + bt_addr_le_t *addr = zmk_ble_active_profile_addr(); + + conn = bt_conn_lookup_addr_le(profiles[active_profile].bt_id, addr); + if(conn !=NULL) + { + struct bt_conn_info info ; + bt_conn_get_info(conn,&info); + LOG_DBG("conn interval:%d,latency:%d,timeout:%d,count:%d",info.le.interval,info.le.latency,info.le.timeout,ble_param_update_try_count); + if(info.le.interval>24) + { + if(ble_param_update_try_count==0) + { + //int rc=update_ble_conn_param(); + ble_param_update_try_count=1; + //if(rc !=0 && rc != -EALREADY) + { + // k_work_cancel_delayable(&ble_param_update_work); + k_work_reschedule(&ble_param_update_work,K_MSEC(500)); + } + } + } + bt_conn_unref(conn); + k_work_reschedule(&ble_active_work,K_MSEC(15000)); + } +} +#endif + +void update_conn_param_worker(struct k_work *work) +{ + int rc=0; + struct bt_le_conn_param *active_param =BT_LE_CONN_PARAM(6, 12,30,400); + struct bt_conn *conn; + bt_addr_le_t *addr = zmk_ble_active_profile_addr(); + + conn = bt_conn_lookup_addr_le(profiles[active_profile].bt_id, addr); + LOG_DBG("conn:%p",conn); + if (conn != NULL) { + LOG_ERR("ch inteval:%d",active_param->interval_max); + rc= bt_conn_le_param_update(conn,active_param); + LOG_ERR("rc:%d",rc); + bt_conn_unref(conn); + } +} + +uint8_t delay_clear_bonds(void) +{ + uint8_t delay_clear_bond=0; + int rc =load_immediate_value("delay_clear_bond", &delay_clear_bond, sizeof(delay_clear_bond)); + if (rc == -ENOENT) { + delay_clear_bond = 0; + LOG_DBG("delay_clear_bond:%d,default",delay_clear_bond); + } + else if(rc ==0) + { + LOG_DBG("delay_clear_bond:%d",delay_clear_bond); + } + return delay_clear_bond; +} +void set_delay_clear_bonds(uint8_t set) +{ + uint8_t delay_clear_bond=set; + LOG_ERR("set_delay_clear_bonds:%d",set); + settings_save_one("delay_clear_bond", &delay_clear_bond, sizeof(delay_clear_bond)); +} \ No newline at end of file diff --git a/app/src/endpoints.c b/app/src/endpoints.c index 138e790fe72..138de1e121d 100644 --- a/app/src/endpoints.c +++ b/app/src/endpoints.c @@ -20,11 +20,29 @@ #include #include +#include +#include + #include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); -#define DEFAULT_TRANSPORT \ - COND_CODE_1(IS_ENABLED(CONFIG_ZMK_BLE), (ZMK_TRANSPORT_BLE), (ZMK_TRANSPORT_USB)) +#include "./launcher/mousekey.h" + +extern uint8_t get_hardware_select_transport(void); +extern int zmk_ble_init(const struct device *_arg); +#if CONFIG_ZMK_NRF_24G +extern void zmk_24g_init(void); +extern int zmk_24g_send_report(uint8_t *data,uint8_t len) ; +#endif +int zmk_hog_send_mouse_report(report_mouse_t *report); +void keyboad_led_set_onoff(uint8_t led_state); +void bt_24g_switch_reset(void); +uint8_t get_mode_status(void); + +// #define DEFAULT_TRANSPORT +// COND_CODE_1(IS_ENABLED(CONFIG_ZMK_BLE), (ZMK_TRANSPORT_BLE), (ZMK_TRANSPORT_USB)) + +#define DEFAULT_TRANSPORT ZMK_TRANSPORT_USB static struct zmk_endpoint_instance current_instance = {}; static enum zmk_transport preferred_transport = @@ -32,6 +50,11 @@ static enum zmk_transport preferred_transport = static void update_current_endpoint(void); +void switch_to_usb(void) +{ + zmk_endpoints_select_transport(ZMK_TRANSPORT_USB); +} +#if 0 #if IS_ENABLED(CONFIG_SETTINGS) static void endpoints_save_preferred_work(struct k_work *work) { settings_save_one("endpoints/preferred", &preferred_transport, sizeof(preferred_transport)); @@ -47,6 +70,7 @@ static int endpoints_save_preferred(void) { return 0; #endif } +#endif bool zmk_endpoint_instance_eq(struct zmk_endpoint_instance a, struct zmk_endpoint_instance b) { if (a.transport != b.transport) { @@ -59,6 +83,11 @@ bool zmk_endpoint_instance_eq(struct zmk_endpoint_instance a, struct zmk_endpoin case ZMK_TRANSPORT_BLE: return a.ble.profile_index == b.ble.profile_index; + case ZMK_TRANSPORT_24G: + return true; + break; + default : + return false; } LOG_ERR("Invalid transport %d", a.transport); @@ -72,6 +101,8 @@ int zmk_endpoint_instance_to_str(struct zmk_endpoint_instance endpoint, char *st case ZMK_TRANSPORT_BLE: return snprintf(str, len, "BLE:%d", endpoint.ble.profile_index); + case ZMK_TRANSPORT_24G: + return snprintf(str, len, "24G"); default: return snprintf(str, len, "Invalid"); @@ -88,6 +119,10 @@ int zmk_endpoint_instance_to_index(struct zmk_endpoint_instance endpoint) { case ZMK_TRANSPORT_BLE: return INSTANCE_INDEX_OFFSET_BLE + endpoint.ble.profile_index; + case ZMK_TRANSPORT_24G: + break; + default : + break; } LOG_ERR("Invalid transport %d", endpoint.transport); @@ -97,14 +132,23 @@ int zmk_endpoint_instance_to_index(struct zmk_endpoint_instance endpoint) { int zmk_endpoints_select_transport(enum zmk_transport transport) { LOG_DBG("Selected endpoint transport %d", transport); - if (preferred_transport == transport) { + // if (preferred_transport == transport) { + // return 0; + // } + + // preferred_transport = transport; + + // endpoints_save_preferred(); + if(current_instance.transport == transport) + { + return 0; + } + if(transport == ZMK_TRANSPORT_NONE) + { + current_instance.transport = transport; return 0; } - preferred_transport = transport; - - endpoints_save_preferred(); - update_current_endpoint(); return 0; @@ -143,6 +187,20 @@ static int send_keyboard_report(void) { return err; } #endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ +#if CONFIG_ZMK_NRF_24G + case ZMK_TRANSPORT_24G: + { + + int err=zmk_24g_send_report((uint8_t *)keyboard_report, sizeof(*keyboard_report)); + if (err) { + LOG_ERR("FAILED TO SEND OVER HOG: %d", err); + } + return err; + } + break; +#endif + default: + break; } LOG_ERR("Unsupported endpoint transport %d", current_instance.transport); @@ -172,6 +230,19 @@ static int send_consumer_report(void) { return err; } #endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ +#if CONFIG_ZMK_NRF_24G + case ZMK_TRANSPORT_24G: + { + int err=zmk_24g_send_report((uint8_t *)consumer_report, sizeof(*consumer_report)); + if (err) { + LOG_ERR("FAILED TO SEND OVER HOG: %d", err); + } + return err; + } + break; +#endif + default: + break; } LOG_ERR("Unsupported endpoint transport %d", current_instance.transport); @@ -187,6 +258,9 @@ int zmk_endpoints_send_report(uint16_t usage_page) { case HID_USAGE_CONSUMER: return send_consumer_report(); + case HID_USAGE_GEN_BUTTON: + mousekey_send(); + return 0; } LOG_ERR("Unsupported usage page %d", usage_page); @@ -219,7 +293,7 @@ static int endpoints_handle_set(const char *name, size_t len, settings_read_cb r struct settings_handler endpoints_handler = {.name = "endpoints", .h_set = endpoints_handle_set}; #endif /* IS_ENABLED(CONFIG_SETTINGS) */ - +#if 0 static bool is_usb_ready(void) { #if IS_ENABLED(CONFIG_ZMK_USB) return zmk_usb_is_hid_ready(); @@ -230,7 +304,7 @@ static bool is_usb_ready(void) { static bool is_ble_ready(void) { #if IS_ENABLED(CONFIG_ZMK_BLE) - return zmk_ble_active_profile_is_connected(); + return zmk_ble_is_connected();//zmk_ble_active_profile_is_connected(); #else return false; #endif @@ -253,9 +327,14 @@ static enum zmk_transport get_selected_transport(void) { } LOG_DBG("No endpoint transports are ready."); - return DEFAULT_TRANSPORT; + return current_instance.transport;// DEFAULT_TRANSPORT; } - +#endif +uint8_t get_current_transport(void) +{ + return current_instance.transport; +} +#if 0 static struct zmk_endpoint_instance get_selected_instance(void) { struct zmk_endpoint_instance instance = {.transport = get_selected_transport()}; @@ -273,9 +352,10 @@ static struct zmk_endpoint_instance get_selected_instance(void) { return instance; } +#endif static int zmk_endpoints_init(const struct device *_arg) { -#if IS_ENABLED(CONFIG_SETTINGS) +#if 0// IS_ENABLED(CONFIG_SETTINGS) settings_subsys_init(); int err = settings_register(&endpoints_handler); @@ -286,10 +366,16 @@ static int zmk_endpoints_init(const struct device *_arg) { k_work_init_delayable(&endpoints_save_work, endpoints_save_preferred_work); - settings_load_subtree("endpoints"); + // settings_load_subtree("endpoints"); #endif - current_instance = get_selected_instance(); + uint32_t reason_reset_pin = nrf_power_resetreas_get(NRF_POWER) & POWER_RESETREAS_RESETPIN_Msk; + if (reason_reset_pin) { + LOG_DBG("reason_reset_pin"); + nrf_power_resetreas_clear(NRF_POWER, POWER_RESETREAS_RESETPIN_Msk); + } + + current_instance.transport =ZMK_TRANSPORT_NONE;//ZMK_TRANSPORT_USB; return 0; } @@ -300,16 +386,44 @@ static void disconnect_current_endpoint() { zmk_endpoints_send_report(HID_USAGE_KEY); zmk_endpoints_send_report(HID_USAGE_CONSUMER); -} + keyboad_led_set_onoff(0); + void zmk_24g_endpoint_disconnect(void); + void zmk_ble_endpoint_disconnect(void); + zmk_24g_endpoint_disconnect(); + zmk_ble_endpoint_disconnect(); +} +void led_power_on(void); static void update_current_endpoint(void) { - struct zmk_endpoint_instance new_instance = get_selected_instance(); + LOG_DBG("curr:%d,new:%d",current_instance.transport,preferred_transport); + struct zmk_endpoint_instance new_instance ={.transport = preferred_transport};// get_selected_instance(); if (!zmk_endpoint_instance_eq(new_instance, current_instance)) { // Cancel all current keypresses so keys don't stay held on the old endpoint. - disconnect_current_endpoint(); - + if(current_instance.transport !=ZMK_TRANSPORT_NONE) + disconnect_current_endpoint(); current_instance = new_instance; + led_power_on(); + + switch(current_instance.transport) + { + case ZMK_TRANSPORT_BLE: + LOG_DBG("change to ble"); + zmk_ble_init(NULL); + break; +#if CONFIG_ZMK_NRF_24G + case ZMK_TRANSPORT_24G: + LOG_DBG("change to 24g"); + zmk_24g_init(); + break; +#endif + case ZMK_TRANSPORT_USB: + LOG_ERR("usb_dc_reset"); + usb_dc_reset(); + break; + default: + break; + } char endpoint_str[ZMK_ENDPOINT_STR_LEN]; zmk_endpoint_instance_to_str(current_instance, endpoint_str, sizeof(endpoint_str)); @@ -321,10 +435,83 @@ static void update_current_endpoint(void) { } static int endpoint_listener(const zmk_event_t *eh) { - update_current_endpoint(); + + const struct zmk_usb_conn_state_changed *ev = as_zmk_usb_conn_state_changed(eh); + if(ev) + { + LOG_DBG("usb state:%d",ev->conn_state); + if(ev->conn_state == ZMK_USB_CONN_HID) + { + if(current_instance.transport ==ZMK_TRANSPORT_USB) + { + LOG_DBG("usb status:%d",zmk_usb_get_status()); + + if(zmk_usb_get_status()==USB_DC_SUSPEND) + { + + keyboad_led_set_onoff(0); + } + } + if(get_hardware_select_transport()==0 && get_mode_status()==3) + { + preferred_transport = ZMK_TRANSPORT_USB; + update_current_endpoint(); + } + } + else if(ev->conn_state == ZMK_USB_CONN_NONE) + { + preferred_transport =get_hardware_select_transport(); + update_current_endpoint(); + } + + } + return 0; } + +int host_mouse_send(report_mouse_t *rp) { + + switch (current_instance.transport) { +#if IS_ENABLED(CONFIG_ZMK_USB) + case ZMK_TRANSPORT_USB: { + int err = zmk_usb_hid_send_report((uint8_t *)rp,sizeof(report_mouse_t)); + if (err) { + LOG_ERR("FAILED TO SEND OVER USB: %d", err); + } + return err; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB) */ + +#if IS_ENABLED(CONFIG_ZMK_BLE) + case ZMK_TRANSPORT_BLE: { + int err = zmk_hog_send_mouse_report(rp); + if (err) { + LOG_ERR("FAILED TO SEND OVER HOG: %d", err); + } + return err; + } +#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */ +#if CONFIG_ZMK_NRF_24G + case ZMK_TRANSPORT_24G: + { + + int err=zmk_24g_send_report((uint8_t*)rp,sizeof(report_mouse_t)); + if (err) { + LOG_ERR("FAILED TO SEND OVER HOG: %d", err); + } + return err; + } + break; +#endif + default: + break; + } + + LOG_ERR("Unsupported endpoint transport %d", current_instance.transport); + return -ENOTSUP; +} + ZMK_LISTENER(endpoint_listener, endpoint_listener); #if IS_ENABLED(CONFIG_ZMK_USB) ZMK_SUBSCRIPTION(endpoint_listener, zmk_usb_conn_state_changed); diff --git a/app/src/hid.c b/app/src/hid.c index 58e5824d2e4..3ec8e5493f9 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -24,6 +24,9 @@ static zmk_mod_flags_t explicit_modifiers = 0; static zmk_mod_flags_t implicit_modifiers = 0; static zmk_mod_flags_t masked_modifiers = 0; +extern uint8_t macro_running; +bool get_fn_win_lock(void); + #define SET_MODIFIERS(mods) \ { \ keyboard_report.body.modifiers = (mods & ~masked_modifiers) | implicit_modifiers; \ @@ -35,6 +38,13 @@ static zmk_mod_flags_t masked_modifiers = 0; zmk_mod_flags_t zmk_hid_get_explicit_mods() { return explicit_modifiers; } int zmk_hid_register_mod(zmk_mod_t modifier) { + if(get_fn_win_lock() && (modifier == 7 || modifier ==3)) + { + explicit_modifier_counts[modifier]=0; + LOG_ERR("not send modifier:%d",modifier); + return 0; + } + explicit_modifier_counts[modifier]++; LOG_DBG("Modifier %d count %d", modifier, explicit_modifier_counts[modifier]); WRITE_BIT(explicit_modifiers, modifier, true); @@ -49,6 +59,12 @@ int zmk_hid_unregister_mod(zmk_mod_t modifier) { return -EINVAL; } explicit_modifier_counts[modifier]--; + + if(macro_running) + { + explicit_modifier_counts[modifier]=0; + } + LOG_DBG("Modifier %d count: %d", modifier, explicit_modifier_counts[modifier]); if (explicit_modifier_counts[modifier] == 0) { LOG_DBG("Modifier %d released", modifier); @@ -116,7 +132,7 @@ static inline bool check_keyboard_usage(zmk_key_t usage) { #define TOGGLE_KEYBOARD(match, val) \ for (int idx = 0; idx < CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE; idx++) { \ - if (keyboard_report.body.keys[idx] != match) { \ + if (keyboard_report.body.keys[idx] != match && keyboard_report.body.keys[idx] != val ) { \ continue; \ } \ keyboard_report.body.keys[idx] = val; \ diff --git a/app/src/hog.c b/app/src/hog.c index 9ccfd9d2c0e..fc5f7210468 100644 --- a/app/src/hog.c +++ b/app/src/hog.c @@ -17,6 +17,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include +#include "./launcher/mousekey.h" enum { HIDS_REMOTE_WAKE = BIT(0), @@ -56,8 +57,17 @@ static struct hids_report consumer_input = { .type = HIDS_INPUT, }; +static struct hids_report output = { + .id = ZMK_HID_REPORT_ID_KEYBOARD, + .type = HIDS_OUTPUT, +}; +static struct hids_report mouse_input = { + .id = ZMK_HID_REPORT_ID_MOUSE, + .type = HIDS_INPUT, +}; static bool host_requests_notification = false; static uint8_t ctrl_point; +static uint8_t hids_outp_rep[20]; // static uint8_t proto_mode; static ssize_t read_hids_info(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, @@ -68,6 +78,8 @@ static ssize_t read_hids_info(struct bt_conn *conn, const struct bt_gatt_attr *a static ssize_t read_hids_report_ref(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { + uint8_t *p_data = attr->user_data; + LOG_DBG("report ref,id:%d,type:%d",p_data[0],p_data[1]); return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data, sizeof(struct hids_report)); } @@ -92,7 +104,13 @@ static ssize_t read_hids_consumer_input_report(struct bt_conn *conn, return bt_gatt_attr_read(conn, attr, buf, len, offset, report_body, sizeof(struct zmk_hid_consumer_report_body)); } - +static ssize_t read_hids_mouse_input_report(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) { + report_mouse_t report =mousekey_get_report(); + return bt_gatt_attr_read(conn, attr, buf, len, offset, &report.buttons, + sizeof(report_mouse_t)-1); +} // static ssize_t write_proto_mode(struct bt_conn *conn, // const struct bt_gatt_attr *attr, // const void *buf, uint16_t len, uint16_t offset, @@ -106,6 +124,27 @@ static void input_ccc_changed(const struct bt_gatt_attr *attr, uint16_t value) { host_requests_notification = (value == BT_GATT_CCC_NOTIFY) ? 1 : 0; } +void keyboad_led_set_onoff(uint8_t led_state); + +static ssize_t hids_outp_rep_write(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, uint8_t flags) { + uint8_t *value = attr->user_data; + LOG_DBG("hids_outp_rep_write"); + if (offset + len > sizeof(hids_outp_rep)) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy(value + offset, buf, len); + LOG_HEXDUMP_INF(buf, len, "ble report"); + const uint8_t *report =buf; + // if(report[0]==ZMK_HID_REPORT_ID_KEYBOARD) + { + keyboad_led_set_onoff(report[0]); + } + + return len; + +} static ssize_t write_ctrl_point(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, uint16_t len, uint16_t offset, uint8_t flags) { uint8_t *value = attr->user_data; @@ -115,7 +154,7 @@ static ssize_t write_ctrl_point(struct bt_conn *conn, const struct bt_gatt_attr } memcpy(value + offset, buf, len); - + LOG_HEXDUMP_INF(buf, len, "write_ctrl_point"); return len; } @@ -139,17 +178,34 @@ BT_GATT_SERVICE_DEFINE( BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref, NULL, &consumer_input), + //mouse reprot + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, read_hids_mouse_input_report, NULL, NULL), + BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref, + NULL, &mouse_input), + //led out + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT,BT_GATT_CHRC_READ|BT_GATT_CHRC_WRITE |BT_GATT_CHRC_WRITE_WITHOUT_RESP, + BT_GATT_PERM_WRITE, NULL, hids_outp_rep_write,hids_outp_rep), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref, + NULL, &output), + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_CTRL_POINT, BT_GATT_CHRC_WRITE_WITHOUT_RESP, - BT_GATT_PERM_WRITE, NULL, write_ctrl_point, &ctrl_point)); + BT_GATT_PERM_WRITE, NULL, write_ctrl_point, &ctrl_point), + + + + + ); struct bt_conn *destination_connection() { struct bt_conn *conn; bt_addr_le_t *addr = zmk_ble_active_profile_addr(); - LOG_DBG("Address pointer %p", addr); + // LOG_DBG("Address pointer %p", addr); if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) { LOG_WRN("Not sending, no active address for current profile"); return NULL; - } else if ((conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr)) == NULL) { + } else if ((conn = bt_conn_lookup_addr_le(zmk_ble_get_active_profile_bt_id(), addr)) == NULL) { LOG_WRN("Not sending, not connected to active profile"); return NULL; } @@ -178,13 +234,17 @@ void send_keyboard_report_callback(struct k_work *work) { .data = &report, .len = sizeof(report), }; - + // LOG_HEXDUMP_INF(notify_params.data, notify_params.len, "report:"); int err = bt_gatt_notify_cb(conn, ¬ify_params); if (err) { LOG_ERR("Error notifying %d", err); } bt_conn_unref(conn); + // if (k_msgq_num_used_get(&zmk_hog_keyboard_msgq) == 0) { + // LOG_DBG("---->msgq empty,break:%d", 0); + // return; + // } } } @@ -206,8 +266,9 @@ int zmk_hog_send_keyboard_report(struct zmk_hid_keyboard_report_body *report) { } } - k_work_submit_to_queue(&hog_work_q, &hog_keyboard_work); + err = k_work_submit_to_queue(&hog_work_q, &hog_keyboard_work); + LOG_DBG("k_work_submit_to_queue:%d", err); return 0; }; @@ -224,7 +285,7 @@ void send_consumer_report_callback(struct k_work *work) { } struct bt_gatt_notify_params notify_params = { - .attr = &hog_svc.attrs[10], + .attr = &hog_svc.attrs[9], .data = &report, .len = sizeof(report), }; @@ -261,6 +322,56 @@ int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *report) { return 0; }; +K_MSGQ_DEFINE(zmk_hog_mouse_msgq, sizeof(report_mouse_t),10, 4); + +void send_mouse_report_callback(struct k_work *work) { + report_mouse_t report; + + while (k_msgq_get(&zmk_hog_mouse_msgq, &report, K_NO_WAIT) == 0) { + struct bt_conn *conn = destination_connection(); + if (conn == NULL) { + return; + } + + struct bt_gatt_notify_params notify_params = { + .attr = &hog_svc.attrs[13], + .data = &report.buttons, + .len = sizeof(report)-1, + }; + + int err = bt_gatt_notify_cb(conn, ¬ify_params); + if (err) { + LOG_DBG("Error notifying %d", err); + } + + bt_conn_unref(conn); + } +}; + +K_WORK_DEFINE(hog_mouse_work, send_mouse_report_callback); + +int zmk_hog_send_mouse_report(report_mouse_t *report) { + int err = k_msgq_put(&zmk_hog_mouse_msgq, report, K_MSEC(100)); + if (err) { + switch (err) { + case -EAGAIN: { + LOG_WRN("Consumer message queue full, popping first message and queueing again"); + report_mouse_t discarded_report; + k_msgq_get(&zmk_hog_mouse_msgq, &discarded_report, K_NO_WAIT); + return zmk_hog_send_mouse_report(report); + } + default: + LOG_WRN("Failed to queue mouse report to send (%d)", err); + return err; + } + } + + k_work_submit_to_queue(&hog_work_q, &hog_mouse_work); + + return 0; +}; + + int zmk_hog_init(const struct device *_arg) { static const struct k_work_queue_config queue_config = {.name = "HID Over GATT Send Work"}; k_work_queue_start(&hog_work_q, hog_q_stack, K_THREAD_STACK_SIZEOF(hog_q_stack), diff --git a/app/src/keymap.c b/app/src/keymap.c index bda694276c8..a89b4bb03f3 100644 --- a/app/src/keymap.c +++ b/app/src/keymap.c @@ -25,6 +25,8 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include +#include +#include static zmk_keymap_layers_state_t _zmk_keymap_layer_state = 0; static uint8_t _zmk_keymap_layer_default = 0; @@ -177,7 +179,7 @@ int zmk_keymap_apply_position_state(uint8_t source, int layer, uint32_t position .timestamp = timestamp, }; - LOG_DBG("layer: %d position: %d, binding name: %s", layer, position, binding.behavior_dev); + LOG_DBG("layer: %d position: %d, binding name: %s,p1:%x,p2:%x", layer, position, binding.behavior_dev,binding.param1,binding.param2); behavior = device_get_binding(binding.behavior_dev); @@ -328,3 +330,137 @@ ZMK_SUBSCRIPTION(keymap, zmk_position_state_changed); #if ZMK_KEYMAP_HAS_SENSORS ZMK_SUBSCRIPTION(keymap, zmk_sensor_event); #endif /* ZMK_KEYMAP_HAS_SENSORS */ + + +void led_recover(void); + +static uint8_t fn_exchange_flag_mac; +static uint8_t fn_exchange_flag_win; +static uint8_t fn_exchange; + +#define WIN_LAYER 2 +#define MAC_LAYER 0 + +static inline uint8_t get_fn_exchange_state(void) +{ + return fn_exchange; +} +static void save_fn_exchange_state(uint8_t state) +{ + fn_exchange =state; + + settings_save_one("fn_exchange", &fn_exchange, sizeof(fn_exchange)); +} +int load_immediate_value(const char *name, void *dest, size_t len); +void fn_exchange_setting_init(void) +{ + + LOG_INF("settings init"); + settings_subsys_init(); + + // int err = settings_register(&profiles_handler); + // if (err) { + // LOG_ERR("Failed to setup the profile settings handler (err %d)", err); + // return ; + // } + // settings_load_subtree("ble/profiles"); + int rc; + rc = load_immediate_value("fn_exchange", &fn_exchange, sizeof(fn_exchange)); + if (rc == -ENOENT) { + fn_exchange = 0; + LOG_DBG("fn_exchange:%d,default",fn_exchange); + } + else if(rc ==0) + { + LOG_DBG("fn_exchange:%d",fn_exchange); + } + +} +bool keyboard_os_is_mac(void) +{ + return ((_zmk_keymap_layer_state & BIT(MAC_LAYER)) || (_zmk_keymap_layer_state &BIT(MAC_LAYER+1)) || _zmk_keymap_layer_state==MAC_LAYER); +} +void f1_f13_fn_exchange_mac(void) +{ +#if CONFIG_SHIELD_KEYCHRON_B1 + struct zmk_behavior_binding backup_bindings[12]; +#else + struct zmk_behavior_binding backup_bindings[13]; +#endif + LOG_DBG("cur lay_state:%x",_zmk_keymap_layer_state); + + { + LOG_DBG("layer:mac"); + memcpy(backup_bindings,&zmk_keymap[MAC_LAYER][1],sizeof(backup_bindings)); + memcpy(&zmk_keymap[MAC_LAYER][1],&zmk_keymap[MAC_LAYER+1][1],sizeof(backup_bindings)); + memcpy(&zmk_keymap[MAC_LAYER+1][1],backup_bindings,sizeof(backup_bindings)); + } + +} +void f1_f13_fn_exchange_win(void) +{ +#if CONFIG_SHIELD_KEYCHRON_B1 + struct zmk_behavior_binding backup_bindings[12]; +#else + struct zmk_behavior_binding backup_bindings[13]; +#endif + LOG_DBG("cur lay_state:%x",_zmk_keymap_layer_state); + + { + LOG_DBG("layer:win"); + memcpy(backup_bindings,&zmk_keymap[WIN_LAYER][1],sizeof(backup_bindings)); + memcpy(&zmk_keymap[WIN_LAYER][1],&zmk_keymap[WIN_LAYER+1][1],sizeof(backup_bindings)); + memcpy(&zmk_keymap[WIN_LAYER+1][1],backup_bindings,sizeof(backup_bindings)); + } +} +void f1_f13_fn_exchange_start_check(void) +{ + fn_exchange_setting_init(); + uint8_t fn_exchange_flag=get_fn_exchange_state(); + + fn_exchange_flag_mac=(fn_exchange_flag &0x02) ?0xff:0; + fn_exchange_flag_win=(fn_exchange_flag &0x01) ?0xff:0; + + LOG_DBG("mac:%d,win:%d",fn_exchange_flag_mac,fn_exchange_flag_win); + if(fn_exchange_flag_mac ) f1_f13_fn_exchange_mac(); + if(fn_exchange_flag_win ) f1_f13_fn_exchange_win(); +} + +uint8_t keyboard_get_led_state(void); +void keyboad_led_set_onoff(uint8_t led_state); +static struct k_work_delayable reset_led_work; +static void reset_led_work_cb(struct k_work *work) +{ + keyboad_led_set_onoff(keyboard_get_led_state()); +} + +void do_f1_f13_fn_exchange(void) +{ + + if(keyboard_os_is_mac()) + { + f1_f13_fn_exchange_mac(); + fn_exchange_flag_mac = ~fn_exchange_flag_mac; + } + else + { + f1_f13_fn_exchange_win(); + fn_exchange_flag_win = ~fn_exchange_flag_win; + } + led_recover(); + LOG_DBG("mac:%d,win:%d",fn_exchange_flag_mac,fn_exchange_flag_win); + save_fn_exchange_state((fn_exchange_flag_win?0x01:0) | (fn_exchange_flag_mac?0x02:0)); + k_work_init_delayable(&reset_led_work, reset_led_work_cb); + k_work_reschedule(&reset_led_work, K_MSEC(2800)); +} + +void update_zmk_keymap(uint8_t layer,uint8_t pos,struct zmk_behavior_binding* binding) +{ + zmk_keymap[layer][pos].behavior_dev =binding->behavior_dev; + zmk_keymap[layer][pos].param1 =binding->param1; + zmk_keymap[layer][pos].param2 =binding->param2; +} +struct zmk_behavior_binding * get_zmk_keymap(uint8_t layer ,uint8_t pos) +{ + return &zmk_keymap[layer][pos]; +} \ No newline at end of file diff --git a/app/src/kscan.c b/app/src/kscan.c index 62d0cf0756e..7a11e4b9d3e 100644 --- a/app/src/kscan.c +++ b/app/src/kscan.c @@ -18,7 +18,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #define ZMK_KSCAN_EVENT_STATE_PRESSED 0 #define ZMK_KSCAN_EVENT_STATE_RELEASED 1 - +bool dip_switch_update_user(uint8_t index, bool active); struct zmk_kscan_event { uint32_t row; uint32_t column; @@ -37,7 +37,11 @@ static void zmk_kscan_callback(const struct device *dev, uint32_t row, uint32_t .row = row, .column = column, .state = (pressed ? ZMK_KSCAN_EVENT_STATE_PRESSED : ZMK_KSCAN_EVENT_STATE_RELEASED)}; - + //report mac/win dip status. + if(row==8&&column==0) + { + dip_switch_update_user(0,pressed?1:0); + } k_msgq_put(&zmk_kscan_msgq, &ev, K_NO_WAIT); k_work_submit(&msg_processor.work); } diff --git a/app/src/main.c b/app/src/main.c index 3fd6b116608..ddc3b5d480c 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -16,15 +16,76 @@ LOG_MODULE_REGISTER(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include +#include +#include +#include +#include + +void f1_f13_fn_exchange_start_check(void); +bool bat_is_shutdown(void); +void clear_bat_shutdown(void); +int zmk_ble_init(const struct device *_arg); +void zmk_24g_init(void); void main(void) { LOG_INF("Welcome to ZMK!\n"); + if (zmk_kscan_init(DEVICE_DT_GET(ZMK_MATRIX_NODE_ID)) != 0) { return; } + uint8_t exit_shutdown=0; + uint8_t bat_shutdown=0; + + while(1) + { + if(bat_is_shutdown()) + { + bat_shutdown =1; + if(zmk_usb_is_powered()) + { + exit_shutdown =1; + } + } + else + { + exit_shutdown =1; + } + if(exit_shutdown) + { + exit_shutdown =0; + LOG_ERR("Exit shutdown!"); + if(bat_shutdown) + { + LOG_ERR("bat low ,Exit shutdown!"); + bat_shutdown=0; + clear_bat_shutdown(); + if(get_current_transport()==ZMK_TRANSPORT_BLE) + { + zmk_ble_init(NULL); + } + else if(get_current_transport()==ZMK_TRANSPORT_24G) + { + zmk_24g_init(); + } + } + set_state(ZMK_ACTIVITY_ACTIVE); + break; + } + + LOG_ERR("shutdown now"); + k_msleep(100); + set_state(ZMK_ACTIVITY_SLEEP); + } + #ifdef CONFIG_ZMK_DISPLAY zmk_display_init(); #endif /* CONFIG_ZMK_DISPLAY */ + + + k_msleep(20); + f1_f13_fn_exchange_start_check(); + + } diff --git a/app/src/usb.c b/app/src/usb.c index cf04ef46c8f..56f18c2809d 100644 --- a/app/src/usb.c +++ b/app/src/usb.c @@ -14,9 +14,17 @@ #include #include #include +#include "version.h" +#include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); - +void bt_24g_switch_reset(void); +void bt_24g_switch_pulldown(uint8_t current); +void zmk_usb_set_protocol_report(void); +void keyboad_led_set_onoff(uint8_t led_state); +uint8_t keyboard_get_led_state(void); +uint32_t usb_sof_count=0; static enum usb_dc_status_code usb_status = USB_DC_UNKNOWN; static void raise_usb_status_changed_event(struct k_work *_work) { @@ -29,12 +37,13 @@ K_WORK_DEFINE(usb_status_notifier_work, raise_usb_status_changed_event); enum usb_dc_status_code zmk_usb_get_status() { return usb_status; } enum zmk_usb_conn_state zmk_usb_get_conn_state() { - LOG_DBG("state: %d", usb_status); + // LOG_DBG("state: %d", usb_status); switch (usb_status) { - case USB_DC_SUSPEND: + // case USB_DC_SUSPEND: + // LOG_DBG("USB_DC_SUSPEND"); case USB_DC_CONFIGURED: case USB_DC_RESUME: - case USB_DC_CLEAR_HALT: + case USB_DC_CLEAR_HALT: return ZMK_USB_CONN_HID; case USB_DC_DISCONNECTED: @@ -47,11 +56,52 @@ enum zmk_usb_conn_state zmk_usb_get_conn_state() { } void usb_status_cb(enum usb_dc_status_code status, const uint8_t *params) { + static uint8_t led_bak_state=0; usb_status = status; + + switch(status) + { + case USB_DC_RESET: + + zmk_usb_set_protocol_report(); + led_bak_state =0; + usb_sof_count=0; + break; + case USB_DC_RESUME: + + if(get_current_transport()==ZMK_TRANSPORT_USB) + { + keyboad_led_set_onoff(led_bak_state); + } + usb_sof_count =0; + break; + case USB_DC_SUSPEND: + led_bak_state= keyboard_get_led_state(); + if(get_current_transport()==ZMK_TRANSPORT_USB) + { + keyboad_led_set_onoff(0); + } + break; + case USB_DC_DISCONNECTED: + + break; + default: + break; + } + LOG_ERR("status:%d,sof:%d",status,usb_sof_count); k_work_submit(&usb_status_notifier_work); }; - +extern struct usb_desc_header __usb_descriptor_start[]; static int zmk_usb_init(const struct device *_arg) { + + struct usb_device_descriptor *device_descriptor=(struct usb_device_descriptor *)__usb_descriptor_start; + if(device_descriptor) + { + LOG_ERR("usb bcd ver:%x",device_descriptor->bcdDevice); + device_descriptor->bcdDevice = sys_cpu_to_le16(USB_BCD_VER); + LOG_ERR("new usb bcd ver:%x,ver:%s",device_descriptor->bcdDevice,APP_VERSION_STRING); + } + int usb_enable_ret; usb_enable_ret = usb_enable(usb_status_cb); @@ -65,3 +115,8 @@ static int zmk_usb_init(const struct device *_arg) { } SYS_INIT(zmk_usb_init, APPLICATION, CONFIG_ZMK_USB_INIT_PRIORITY); + +uint32_t get_usb_sof_count(void) +{ + return usb_sof_count; +} \ No newline at end of file diff --git a/app/src/usb_hid.c b/app/src/usb_hid.c index f46c70a0a92..3dbe1bf6fe2 100644 --- a/app/src/usb_hid.c +++ b/app/src/usb_hid.c @@ -14,33 +14,96 @@ #include #include #include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); +void keyboad_led_set_onoff(uint8_t led_state); +uint32_t get_usb_sof_count(void); + static const struct device *hid_dev; static K_SEM_DEFINE(hid_sem, 1, 1); +static uint8_t zmk_usb_protocol=HID_PROTOCOL_REPORT; +void zmk_usb_set_protocol_report(void) +{ + zmk_usb_protocol=HID_PROTOCOL_REPORT; +} +void zmk_usb_protocol_change(const struct device *dev, uint8_t protocol) +{ + zmk_usb_protocol =protocol; + LOG_DBG("usb protocol:%d",protocol); +} +static void out_ready_cb(const struct device *dev) +{ + uint8_t rev_buf[32]={0}; + uint32_t rev_bytes =0; + hid_int_ep_read(dev,rev_buf,sizeof(rev_buf),&rev_bytes); + LOG_HEXDUMP_DBG(rev_buf,rev_bytes,"rx"); + if(rev_buf[0]==ZMK_HID_REPORT_ID_KEYBOARD) + { + if(get_current_transport()==ZMK_TRANSPORT_USB) + keyboad_led_set_onoff(rev_buf[1]); + } +} static void in_ready_cb(const struct device *dev) { k_sem_give(&hid_sem); } - +static int zmk_usb_hid_set_report(const struct device *dev, struct usb_setup_packet *setup, + int32_t *len, uint8_t **data) { + LOG_HEXDUMP_DBG(*data, *len, "set report"); + uint8_t *report=*data; + if(report[0]==ZMK_HID_REPORT_ID_KEYBOARD) + { + keyboad_led_set_onoff(report[1]); + } + return 0; +} static const struct hid_ops ops = { .int_in_ready = in_ready_cb, + .int_out_ready = out_ready_cb, + .set_report = zmk_usb_hid_set_report, + .protocol_change =zmk_usb_protocol_change }; int zmk_usb_hid_send_report(const uint8_t *report, size_t len) { switch (zmk_usb_get_status()) { - case USB_DC_SUSPEND: - return usb_wakeup_request(); + case USB_DC_ERROR: case USB_DC_RESET: case USB_DC_DISCONNECTED: case USB_DC_UNKNOWN: return -ENODEV; + case USB_DC_SUSPEND: + usb_wakeup_request(); + + for(int i=0;i<50;i++) + { + k_msleep(100); + if(!usb_get_remote_wakeup_status()|| get_usb_sof_count()>100) + { + LOG_ERR("i:%d,sof:%d",i,get_usb_sof_count()); + break; + } + } default: - k_sem_take(&hid_sem, K_MSEC(30)); - int err = hid_int_ep_write(hid_dev, report, len, NULL); + int sem_err=k_sem_take(&hid_sem, K_MSEC(100)); + if(sem_err) + { + LOG_ERR("sem err:%d",sem_err); + } + LOG_HEXDUMP_DBG(report,len,"usb"); + int err; + if(zmk_usb_protocol == HID_PROTOCOL_REPORT) + { + err = hid_int_ep_write(hid_dev, report, len, NULL); + } + else + { + err = hid_int_ep_write(hid_dev, &report[1], len-1, NULL); + } if (err) { + LOG_ERR("err:%d",err); k_sem_give(&hid_sem); } @@ -57,7 +120,7 @@ static int zmk_usb_hid_init(const struct device *_arg) { usb_hid_register_device(hid_dev, zmk_hid_report_desc, sizeof(zmk_hid_report_desc), &ops); usb_hid_init(hid_dev); - + usb_hid_set_proto_code(hid_dev,1);//set boot keyboard! return 0; } From f61b7a5a57a207a158cbdad78bc33797bfb39bbc Mon Sep 17 00:00:00 2001 From: william <43848894@qq.com> Date: Mon, 13 Jan 2025 14:52:29 +0800 Subject: [PATCH 2/7] add keychron files. --- app/VERSION | 5 + app/boards/arm/keychron/Kconfig | 8 + app/boards/arm/keychron/Kconfig.board | 6 + app/boards/arm/keychron/Kconfig.defconfig | 36 + app/boards/arm/keychron/README.md | 32 + app/boards/arm/keychron/board.cmake | 7 + app/boards/arm/keychron/keychron.dts | 441 +++++ app/boards/arm/keychron/keychron.yaml | 14 + app/boards/arm/keychron/keychron.zmk.yml | 12 + app/boards/arm/keychron/keychron_defconfig | 123 ++ .../arm/keychron/keychron_z1-287f3d87.keymap | 268 +++ app/boards/shields/keychron/Kconfig.shield | 51 + app/boards/shields/keychron/keychron.zmk.yml | 12 + .../shields/keychron/keychron_b1_jis.conf | 11 + .../shields/keychron/keychron_b1_jis.keymap | 255 +++ .../shields/keychron/keychron_b1_jis.overlay | 35 + .../shields/keychron/keychron_b1_uk.conf | 11 + .../shields/keychron/keychron_b1_uk.keymap | 255 +++ .../shields/keychron/keychron_b1_uk.overlay | 35 + .../shields/keychron/keychron_b1_us.conf | 11 + .../shields/keychron/keychron_b1_us.keymap | 255 +++ .../shields/keychron/keychron_b1_us.overlay | 36 + .../shields/keychron/keychron_b1_us_dbg.conf | 25 + .../keychron/keychron_b1_us_dbg.keymap | 255 +++ .../keychron/keychron_b1_us_dbg.overlay | 56 + .../shields/keychron/keychron_b2_jis.conf | 11 + .../shields/keychron/keychron_b2_jis.keymap | 255 +++ .../shields/keychron/keychron_b2_jis.overlay | 35 + .../shields/keychron/keychron_b2_kr.conf | 14 + .../shields/keychron/keychron_b2_kr.keymap | 255 +++ .../shields/keychron/keychron_b2_kr.overlay | 39 + .../shields/keychron/keychron_b2_uk.conf | 11 + .../shields/keychron/keychron_b2_uk.keymap | 255 +++ .../shields/keychron/keychron_b2_uk.overlay | 35 + .../shields/keychron/keychron_b2_us.conf | 14 + .../shields/keychron/keychron_b2_us.keymap | 255 +++ .../shields/keychron/keychron_b2_us.overlay | 39 + .../shields/keychron/keychron_b6_jis.conf | 7 + .../shields/keychron/keychron_b6_jis.keymap | 268 +++ .../shields/keychron/keychron_b6_jis.overlay | 36 + .../shields/keychron/keychron_b6_uk.conf | 7 + .../shields/keychron/keychron_b6_uk.keymap | 267 +++ .../shields/keychron/keychron_b6_uk.overlay | 37 + .../shields/keychron/keychron_b6_us.conf | 7 + .../shields/keychron/keychron_b6_us.keymap | 266 +++ .../shields/keychron/keychron_b6_us.overlay | 35 + app/boards/shields/keychron/keychron_rgb.conf | 20 + .../shields/keychron/keychron_rgb.keymap | 59 + .../shields/keychron/keychron_rgb.overlay | 195 +++ app/include/zmk/leds.h | 34 + app/src/24G/CMakeLists.txt | 8 + app/src/24G/lib_nrf_esb_24G.a | Bin 0 -> 369352 bytes app/src/dfu/CMakeLists.txt | 3 + app/src/dfu/tdfu.c | 739 ++++++++ app/src/dfu/tdfu.h | 110 ++ app/src/dfu/tdfu_prv.c | 42 + app/src/dfu/tdfu_prv.h | 22 + app/src/launcher/CMakeLists.txt | 6 + app/src/launcher/dynamic_keymap.c | 509 ++++++ app/src/launcher/dynamic_keymap.h | 73 + app/src/launcher/dynamic_macro.h | 264 +++ app/src/launcher/keycodes.h | 1519 ++++++++++++++++ app/src/launcher/keymap_japanese.h | 106 ++ app/src/launcher/launcher.c | 1527 +++++++++++++++++ app/src/launcher/launcher.h | 466 +++++ app/src/launcher/map_keycode.c | 703 ++++++++ app/src/launcher/mousekey.c | 785 +++++++++ app/src/launcher/mousekey.h | 220 +++ app/src/launcher/send_string.c | 341 ++++ app/src/launcher/send_string.h | 156 ++ app/src/launcher/send_string_keycodes.h | 445 +++++ app/src/launcher/sendstring_japanese.h | 81 + app/src/led_effect.h | 383 +++++ app/src/leds.c | 566 ++++++ app/src/version.h | 37 + 75 files changed, 13822 insertions(+) create mode 100644 app/VERSION create mode 100644 app/boards/arm/keychron/Kconfig create mode 100644 app/boards/arm/keychron/Kconfig.board create mode 100644 app/boards/arm/keychron/Kconfig.defconfig create mode 100644 app/boards/arm/keychron/README.md create mode 100644 app/boards/arm/keychron/board.cmake create mode 100644 app/boards/arm/keychron/keychron.dts create mode 100644 app/boards/arm/keychron/keychron.yaml create mode 100644 app/boards/arm/keychron/keychron.zmk.yml create mode 100644 app/boards/arm/keychron/keychron_defconfig create mode 100644 app/boards/arm/keychron/keychron_z1-287f3d87.keymap create mode 100644 app/boards/shields/keychron/Kconfig.shield create mode 100644 app/boards/shields/keychron/keychron.zmk.yml create mode 100644 app/boards/shields/keychron/keychron_b1_jis.conf create mode 100644 app/boards/shields/keychron/keychron_b1_jis.keymap create mode 100644 app/boards/shields/keychron/keychron_b1_jis.overlay create mode 100644 app/boards/shields/keychron/keychron_b1_uk.conf create mode 100644 app/boards/shields/keychron/keychron_b1_uk.keymap create mode 100644 app/boards/shields/keychron/keychron_b1_uk.overlay create mode 100644 app/boards/shields/keychron/keychron_b1_us.conf create mode 100644 app/boards/shields/keychron/keychron_b1_us.keymap create mode 100644 app/boards/shields/keychron/keychron_b1_us.overlay create mode 100644 app/boards/shields/keychron/keychron_b1_us_dbg.conf create mode 100644 app/boards/shields/keychron/keychron_b1_us_dbg.keymap create mode 100644 app/boards/shields/keychron/keychron_b1_us_dbg.overlay create mode 100644 app/boards/shields/keychron/keychron_b2_jis.conf create mode 100644 app/boards/shields/keychron/keychron_b2_jis.keymap create mode 100644 app/boards/shields/keychron/keychron_b2_jis.overlay create mode 100644 app/boards/shields/keychron/keychron_b2_kr.conf create mode 100644 app/boards/shields/keychron/keychron_b2_kr.keymap create mode 100644 app/boards/shields/keychron/keychron_b2_kr.overlay create mode 100644 app/boards/shields/keychron/keychron_b2_uk.conf create mode 100644 app/boards/shields/keychron/keychron_b2_uk.keymap create mode 100644 app/boards/shields/keychron/keychron_b2_uk.overlay create mode 100644 app/boards/shields/keychron/keychron_b2_us.conf create mode 100644 app/boards/shields/keychron/keychron_b2_us.keymap create mode 100644 app/boards/shields/keychron/keychron_b2_us.overlay create mode 100644 app/boards/shields/keychron/keychron_b6_jis.conf create mode 100644 app/boards/shields/keychron/keychron_b6_jis.keymap create mode 100644 app/boards/shields/keychron/keychron_b6_jis.overlay create mode 100644 app/boards/shields/keychron/keychron_b6_uk.conf create mode 100644 app/boards/shields/keychron/keychron_b6_uk.keymap create mode 100644 app/boards/shields/keychron/keychron_b6_uk.overlay create mode 100644 app/boards/shields/keychron/keychron_b6_us.conf create mode 100644 app/boards/shields/keychron/keychron_b6_us.keymap create mode 100644 app/boards/shields/keychron/keychron_b6_us.overlay create mode 100644 app/boards/shields/keychron/keychron_rgb.conf create mode 100644 app/boards/shields/keychron/keychron_rgb.keymap create mode 100644 app/boards/shields/keychron/keychron_rgb.overlay create mode 100644 app/include/zmk/leds.h create mode 100644 app/src/24G/CMakeLists.txt create mode 100644 app/src/24G/lib_nrf_esb_24G.a create mode 100644 app/src/dfu/CMakeLists.txt create mode 100644 app/src/dfu/tdfu.c create mode 100644 app/src/dfu/tdfu.h create mode 100644 app/src/dfu/tdfu_prv.c create mode 100644 app/src/dfu/tdfu_prv.h create mode 100644 app/src/launcher/CMakeLists.txt create mode 100644 app/src/launcher/dynamic_keymap.c create mode 100644 app/src/launcher/dynamic_keymap.h create mode 100644 app/src/launcher/dynamic_macro.h create mode 100644 app/src/launcher/keycodes.h create mode 100644 app/src/launcher/keymap_japanese.h create mode 100644 app/src/launcher/launcher.c create mode 100644 app/src/launcher/launcher.h create mode 100644 app/src/launcher/map_keycode.c create mode 100644 app/src/launcher/mousekey.c create mode 100644 app/src/launcher/mousekey.h create mode 100644 app/src/launcher/send_string.c create mode 100644 app/src/launcher/send_string.h create mode 100644 app/src/launcher/send_string_keycodes.h create mode 100644 app/src/launcher/sendstring_japanese.h create mode 100644 app/src/led_effect.h create mode 100644 app/src/leds.c create mode 100644 app/src/version.h diff --git a/app/VERSION b/app/VERSION new file mode 100644 index 00000000000..137a54b92f1 --- /dev/null +++ b/app/VERSION @@ -0,0 +1,5 @@ +VERSION_MAJOR = 1 +VERSION_MINOR = 2 +PATCHLEVEL = 3 +VERSION_TWEAK = 0 +EXTRAVERSION = ZMK diff --git a/app/boards/arm/keychron/Kconfig b/app/boards/arm/keychron/Kconfig new file mode 100644 index 00000000000..573e6740cd1 --- /dev/null +++ b/app/boards/arm/keychron/Kconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_ENABLE_DCDC + bool "Enable DCDC mode" + select SOC_DCDC_NRF52X + default y + depends on BOARD_KEYCHRON diff --git a/app/boards/arm/keychron/Kconfig.board b/app/boards/arm/keychron/Kconfig.board new file mode 100644 index 00000000000..a6627cca672 --- /dev/null +++ b/app/boards/arm/keychron/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_KEYCHRON + bool "keychron" + depends on SOC_NRF52840_QIAA diff --git a/app/boards/arm/keychron/Kconfig.defconfig b/app/boards/arm/keychron/Kconfig.defconfig new file mode 100644 index 00000000000..27e70bb2e1e --- /dev/null +++ b/app/boards/arm/keychron/Kconfig.defconfig @@ -0,0 +1,36 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BOARD_KEYCHRON + +config ZMK_KEYBOARD_NAME + default "Keychron B6 Pro" + +if USB_DEVICE_STACK + +config USB_NRFX + default y + +endif # USB_DEVICE_STACK + +config BT_CTLR + default BT + +config ZMK_BLE + default y + +config ZMK_USB + default y + +config ZMK_LEDS_GPIO + bool "enable gpio leds" + default y + select LED + +config ZMK_LEDS_PWM + bool "enable pwm leds" + default n + select PWM + select LED_PWM + +endif # BOARD_KEYCHRON diff --git a/app/boards/arm/keychron/README.md b/app/boards/arm/keychron/README.md new file mode 100644 index 00000000000..e82686cc9ab --- /dev/null +++ b/app/boards/arm/keychron/README.md @@ -0,0 +1,32 @@ +# Keychron `NRF52840` Experimental Support + + + +### Specifications: + + - `NRF52840` + - 15 column x 5 row key matrix with a ROW -> COL (`row2col`) layout + - DIP switch embedded in matrix at `(4,4)` + - LED Matrix + - 2x I2C `CKLED2001` LED Drivers + - EC11 Encoder + +### Current Progress: + +### Flashing: + + + +### Development: + +1. Follow the [ZMK Documentation](https://zmk.dev/docs/development/setup) to set up your local build environment +2. To build the firmware, run: +```sh +west build -p -b keychron +``` +3. To build and flash the the firmware, hold down the RESET button while connecting the keyboard over USB. The run: +```sh +west build -p -b keychron && west flash +``` + + diff --git a/app/boards/arm/keychron/board.cmake b/app/boards/arm/keychron/board.cmake new file mode 100644 index 00000000000..8bc0fdc8bfd --- /dev/null +++ b/app/boards/arm/keychron/board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +set(OPENOCD_NRF5_SUBFAMILY nrf52) +board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd-nrf5.board.cmake) diff --git a/app/boards/arm/keychron/keychron.dts b/app/boards/arm/keychron/keychron.dts new file mode 100644 index 00000000000..1c17fb5691a --- /dev/null +++ b/app/boards/arm/keychron/keychron.dts @@ -0,0 +1,441 @@ +/* + * Copyright (c) 2021 Nick Winans + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include + +#include +#include +#include + +/ { + model = "keychron"; + compatible = "keychron"; + + chosen { + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &uart0; //&cdc_acm_uart; + zmk,battery = &vbatt; + zmk,kscan = &kscan_comp;//&kscan0; + zmk,matrix_transform = &default_transform; + zmk,underglow = &led_strip; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <18>; + rows = <8>; + map = < + //esc //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //print //scr //pause + RC(3,1) RC(6,2) RC(6,3) RC(1,3) RC(3,3) RC(7,0) RC(3,6) RC(1,7) RC(6,7) RC(6,10) RC(7,10) RC(3,10) RC(5,10) RC(5,17) RC(7,9) RC(0,9) RC(0,0) RC(7,16) RC(4,16) RC(2,16) RC(5,16) + //grave //1 //2 //3 //4 //5 //6 //7 //8 //9 //0 //- //+= //back //ins //home //pg up //num // / //* // - + RC(6,1) RC(7,1) RC(7,2) RC(7,3) RC(7,4) RC(6,4) RC(6,5) RC(7,5) RC(7,6) RC(7,7) RC(7,8) RC(6,8) RC(6,6) RC(1,10) RC(6,12) RC(6,14) RC(6,13) RC(4,11) RC(4,12) RC(4,13) RC(5,13) + //tab //q //w //e //r // t //y //u //i //o //p //[ //] //\ //del //end //pg dn //kp 7 //kp8 //kp 9 //kp + + RC(1,1) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(1,4) RC(1,5) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(1,8) RC(1,6) RC(2,10) RC(6,11) RC(7,14) RC(7,13) RC(0,11) RC(0,12) RC(0,13) RC(0,14) + //cap //a //s //d //f //g //h //j //k //l // ; //' " //enter //4 //5 //6 + RC(1,2) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(3,8) RC(4,10) RC(1,11) RC(1,12) RC(1,13) + //lshit //z //x //c //v //b //n //m //,< //.> //?/ //rshit //up //1 //2 //3 + RC(1,15) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(5,4) RC(5,5) RC(4,5) RC(4,6) RC(4,7) RC(5,8) RC(2,15) RC(3,14) RC(2,11) RC(2,12) RC(2,13) + //lctrl //win l //alt l //space //alt r //win r //fn //ctrl r //left //down //right //0 //dot //kp enter + RC(6,0) RC(1,16) RC(3,9) RC(3,11) RC(5,9) RC(2,9) RC(5,7) RC(4,0) RC(5,14) RC(5,11) RC(5,12) RC(3,12) RC(3,13) RC(2,14) + //m/w //bt //24g //ch //ch done + RC(8,0) RC(8,1) RC(8,2) RC(8,3) RC(8,4) + >; + }; + + + kscan0: kscan_matrix { + compatible = "zmk,kscan-gpio-matrix"; + //label = "KSCAN"; + diode-direction = "col2row"; + debounce-scan-period-ms =<4>; + debounce-press-ms =<8>; + debounce-release-ms=<8>; + + row-gpios + = <&gpio1 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r0 + , <&gpio1 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r1 + , <&gpio1 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r2 + , <&gpio1 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r3 + , <&gpio1 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r4 + , <&gpio1 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r5 + , <&gpio1 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r6 + , <&gpio1 12 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r7 + ; + col-gpios + = <&gpio0 0 (GPIO_ACTIVE_HIGH )> //c0 + , <&gpio0 1 (GPIO_ACTIVE_HIGH)> //c1 + , <&gpio0 26 (GPIO_ACTIVE_HIGH)> //c2 + , <&gpio0 27 (GPIO_ACTIVE_HIGH)> //c3 + , <&gpio0 4 (GPIO_ACTIVE_HIGH)> //c4 + , <&gpio0 5 (GPIO_ACTIVE_HIGH)> //c5 + , <&gpio0 6 (GPIO_ACTIVE_HIGH)> //c6 + , <&gpio0 7 (GPIO_ACTIVE_HIGH)> //c7 + , <&gpio0 8 (GPIO_ACTIVE_HIGH)> //c8 + , <&gpio0 11 (GPIO_ACTIVE_HIGH)> //c9 + , <&gpio0 12 (GPIO_ACTIVE_HIGH)> //c10 + , <&gpio0 13 (GPIO_ACTIVE_HIGH)> //c11 + , <&gpio0 14 (GPIO_ACTIVE_HIGH)> //c12 + , <&gpio0 15 (GPIO_ACTIVE_HIGH)> //c13 + , <&gpio0 16 (GPIO_ACTIVE_HIGH)> //c14 + , <&gpio0 17 (GPIO_ACTIVE_HIGH)> //c15 + , <&gpio0 18 (GPIO_ACTIVE_HIGH)> //c16 + , <&gpio0 20 (GPIO_ACTIVE_HIGH)> //c17 + ; + + }; + + kscan1:kscan_direct { + compatible = "zmk,kscan-gpio-direct"; + //label = "CONTROL"; + input-gpios + = <&gpio0 24 GPIO_ACTIVE_LOW> //mac/win + , <&gpio1 8 (GPIO_ACTIVE_LOW)> //bt + , <&gpio1 9 (GPIO_ACTIVE_LOW)> //24g + , <&gpio0 21 GPIO_ACTIVE_LOW> //charging + , <&gpio0 22 GPIO_ACTIVE_LOW> //charge done + ; + }; + + kscan_comp: kscan { + compatible = "zmk,kscan-composite"; + label = "KSCAN_ALL"; + rows = <9>; + columns = <18>; + + // Include the matrix driver + matrix { + kscan = <&kscan0>; + }; + + // Include the direct GPIO driver... + direct { + kscan = <&kscan1>; + row-offset = <8>; // ...and shift it to not overlap + }; + }; + + led_strip: led-strip-composite { + compatible = "zmk,led-strip-composite"; + label = "LED_STRIP"; + chain-length = <67>; + strip-0 { + led-strip = <&led_strip_0>; + }; + strip-1 { + led-strip = <&led_strip_1>; + }; + }; + + + ext-power { + compatible = "zmk,ext-power-generic"; + status ="disabled"; + label = "EXT_POWER"; + control-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; + }; + + vbatt: vbatt { + compatible = "zmk,battery-voltage-divider"; + //label = "BATTERY"; + io-channels = <&adc 7>; + output-ohms = <510000>; + full-ohms = <(510000 + 510000)>; + }; + + led_blue { + compatible = "gpio-leds"; + label = "LED_BLUE"; + blue_led: led_01 { + gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; + + }; + }; + led_numlock { + compatible = "gpio-leds"; + label = "LED_NumLock"; + status = "okay"; + numlock_led: led_02 { + gpios = <&gpio0 9 GPIO_ACTIVE_LOW>; + + }; + }; + led_CAPS { + compatible = "gpio-leds"; + label = "LED_CAPS"; + status = "okay"; + caps_led: led_03 { + gpios = <&gpio0 10 GPIO_ACTIVE_LOW>; + + }; + }; + led_24G { + compatible = "gpio-leds"; + label = "LED_24G"; + status = "okay"; + led_24g: led_04 { + gpios = <&gpio0 3 GPIO_ACTIVE_LOW>; + + }; + }; + led_rgb { + compatible = "gpio-leds"; + label = "LED_RGB"; + status = "okay"; + + myled_r: led_r { + gpios = <&gpio0 28 GPIO_ACTIVE_LOW>; + label = "led_r"; + }; + myled_g: led_g { + gpios = <&gpio0 30 GPIO_ACTIVE_LOW>; + label = "led_g"; + }; + myled_b: led_b { + gpios = <&gpio0 29 GPIO_ACTIVE_LOW>; + label = "led_b"; + }; + }; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&pinctrl { + i2c0_default:i2c0_default{ + group1 { + psels = , + ; + }; + }; + i2c0_sleep:i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + uart0_default:uart0_default { + group1 { + psels = ; + low-power-enable; + }; + + group2 { + psels = ; + low-power-enable; + }; + }; + uart0_sleep:uart0_sleep { + group1 { + psels = ; + low-power-enable; + }; + + group2 { + psels = ; + low-power-enable; + }; + }; + +}; + + + +ckled:&i2c0 { + // compatible = "nordic,nrf-twi"; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; + status = "disabled"; + + // pinctrl-0 = <&i2c0_default>; + // pinctrl-1 = <&i2c0_sleep>; + // pinctrl-names = "default", "sleep"; + + // clock-frequency = ; + + led_strip_0: ckled2001@77 { + compatible = "zmk,ckled2001"; + //label = "LED_STRIP_0"; + /* ADDR/CS pin connected to VDDIO */ + /* Located closer to the USB daughterboard connection */ + reg = <0x77>; + chain-length = <34>; + map = < + /* ROW 0 */ + /* R G B */ + CK(2, 0) CK(0, 0) CK(1, 0) + CK(2, 1) CK(0, 1) CK(1, 1) + CK(2, 2) CK(0, 2) CK(1, 2) + CK(2, 3) CK(0, 3) CK(1, 3) + CK(2, 4) CK(0, 4) CK(1, 4) + CK(2, 5) CK(0, 5) CK(1, 5) + CK(2, 6) CK(0, 6) CK(1, 6) + CK(2, 7) CK(0, 7) CK(1, 7) + CK(2, 8) CK(0, 8) CK(1, 8) + CK(2, 9) CK(0, 9) CK(1, 9) + CK(2,10) CK(0,10) CK(1,10) + CK(2,11) CK(0,11) CK(1,11) + CK(2,12) CK(0,12) CK(1,12) + CK(2,13) CK(0,13) CK(1,13) + CK(2,15) CK(0,15) CK(1,15) + /* ROW 1 */ + /* R G B */ + CK(8, 0) CK(6, 0) CK(7, 0) + CK(8, 1) CK(6, 1) CK(7, 1) + CK(8, 2) CK(6, 2) CK(7, 2) + CK(8, 3) CK(6, 3) CK(7, 3) + /* ROW 2 */ + /* R G B */ + CK(5, 0) CK(3, 0) CK(4, 0) + CK(5, 1) CK(3, 1) CK(4, 1) + CK(5, 2) CK(3, 2) CK(4, 2) + CK(5, 3) CK(3, 3) CK(4, 3) + CK(5, 4) CK(3, 4) CK(4, 4) + CK(5, 5) CK(3, 5) CK(4, 5) + CK(5, 6) CK(3, 6) CK(4, 6) + CK(5, 7) CK(3, 7) CK(4, 7) + CK(5, 8) CK(3, 8) CK(4, 8) + CK(5, 9) CK(3, 9) CK(4, 9) + CK(5,10) CK(3,10) CK(4,10) + CK(5,11) CK(3,11) CK(4,11) + CK(5,12) CK(3,12) CK(4,12) + CK(5,13) CK(3,13) CK(4,13) + CK(5,15) CK(3,15) CK(4,15) + >; + }; + + led_strip_1: ckled2001@74 { + compatible = "zmk,ckled2001"; + //label = "LED_STRIP_1"; + /* ADDR/CS pin connected to GND */ + /* Located closer to the space bar */ + reg = <0x74>; + chain-length = <33>; + map = < + /* ROW 3 */ + /* R G B */ + CK(8, 4) CK(6, 4) CK(7, 4) + CK(8, 5) CK(6, 5) CK(7, 5) + CK(8, 6) CK(6, 6) CK(7, 6) + CK(8, 7) CK(6, 7) CK(7, 7) + CK(8, 8) CK(6, 8) CK(7, 8) + CK(8, 9) CK(6, 9) CK(7, 9) + CK(8,10) CK(6,10) CK(7,10) + CK(8,11) CK(6,11) CK(7,11) + CK(8,13) CK(6,13) CK(7,13) + CK(8,15) CK(6,15) CK(7,15) + /* ROW 4 */ + /* R G B */ + CK(5, 0) CK(3, 0) CK(4, 0) + CK(5, 1) CK(3, 1) CK(4, 1) + CK(5, 2) CK(3, 2) CK(4, 2) + CK(5, 6) CK(3, 6) CK(4, 6) + CK(5,10) CK(3,10) CK(4,10) + CK(5,11) CK(3,11) CK(4,11) + CK(5,12) CK(3,12) CK(4,12) + CK(5,13) CK(3,13) CK(4,13) + CK(5,14) CK(3,14) CK(4,14) + CK(5,15) CK(3,15) CK(4,15) + /* ROW 5 */ + /* R G B */ + CK(2, 0) CK(0, 0) CK(1, 0) + CK(2, 2) CK(0, 2) CK(1, 2) + CK(2, 3) CK(0, 3) CK(1, 3) + CK(2, 4) CK(0, 4) CK(1, 4) + CK(2, 5) CK(0, 5) CK(1, 5) + CK(2, 6) CK(0, 6) CK(1, 6) + CK(2, 7) CK(0, 7) CK(1, 7) + CK(2, 8) CK(0, 8) CK(1, 8) + CK(2, 9) CK(0, 9) CK(1, 9) + CK(2,10) CK(0,10) CK(1,10) + CK(2,11) CK(0,11) CK(1,11) + CK(2,13) CK(0,13) CK(1,13) + CK(2,14) CK(0,14) CK(1,14) + >; + }; +}; + + +&usbd { + status = "okay"; + //cdc_acm_uart: cdc_acm_uart { + // compatible = "zephyr,cdc-acm-uart"; + // label = "CDC_ACM_0"; + //}; +}; + + +&uart0 { + compatible = "nordic,nrf-uarte"; + status = "disabled";//"okay";// + current-speed = <1000000>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + label = "mbr"; + reg = <0x00000000 0x00001000>; + }; + + code_partition: partition@1000 { + label = "code_partition"; + reg = <0x00001000 0x000d3000>; + }; + + /* + * The flash starting at 0x000d4000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@d4000 { + label = "storage"; + reg = <0x000d4000 0x00020000>; + }; + + boot_partition: partition@f4000 { + label = "adafruit_boot"; + reg = <0x000f4000 0x0000c000>; + }; + }; +}; +#include +&mt { + tapping-term-ms = <400>; +}; diff --git a/app/boards/arm/keychron/keychron.yaml b/app/boards/arm/keychron/keychron.yaml new file mode 100644 index 00000000000..e20286072d3 --- /dev/null +++ b/app/boards/arm/keychron/keychron.yaml @@ -0,0 +1,14 @@ +identifier: keychron +name: keychron +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/keychron/keychron.zmk.yml b/app/boards/arm/keychron/keychron.zmk.yml new file mode 100644 index 00000000000..6f648122afa --- /dev/null +++ b/app/boards/arm/keychron/keychron.zmk.yml @@ -0,0 +1,12 @@ +file_format: "1" +id: keychron +name: keychron +type: board +arch: arm +features: + - keys + - underglow +outputs: + - usb + - ble +url: https://www.keychron.com/ diff --git a/app/boards/arm/keychron/keychron_defconfig b/app/boards/arm/keychron/keychron_defconfig new file mode 100644 index 00000000000..dde9a028a1a --- /dev/null +++ b/app/boards/arm/keychron/keychron_defconfig @@ -0,0 +1,123 @@ +# Copyright (c) 2021 Nick Winans +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_KEYCHRON=y + +# Enable MPU +CONFIG_ARM_MPU=y + +CONFIG_PINCTRL=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable i2c +CONFIG_I2C=n + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +# CONFIG_ZMK_RTT_LOGGING=y +# CONFIG_ZMK_USB_LOGGING=y +#CONFIG_ZMK_UART_LOGGING=y + +# RGB +# Uncomment these to enable RGB underglow +# CONFIG_CKLED2001=n +#CONFIG_ZMK_RGB_UNDERGLOW=n +#CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=n +#CONFIG_ZMK_RGB_UNDERGLOW_EFF_START=3 +#CONFIG_ZMK_RGB_UNDERGLOW_BRT_START=10 +#CONFIG_ZMK_RGB_UNDERGLOW_HUE_START=100 +#CONFIG_ZMK_RGB_UNDERGLOW_ON_START=n + +CONFIG_BT_ID_MAX=5 +CONFIG_BT_SMP_ALLOW_UNAUTH_OVERWRITE=y +# CONFIG_BT_ID_UNPAIR_MATCHING_BONDS=y +CONFIG_BT_FILTER_ACCEPT_LIST=y +CONFIG_BT_PRIVACY=n +CONFIG_BT_CTLR_PRIVACY=y + +# CONFIG_ZMK_HID_REPORT_TYPE_NKRO=y +CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_FULL=y + +#CONFIG_USB_HID_LOG_LEVEL_DBG=y +#CONFIG_USB_DEVICE_LOG_LEVEL_DBG=y + + +#CONFIG_ZERO_LATENCY_IRQS=y +CONFIG_DYNAMIC_INTERRUPTS=y +CONFIG_DYNAMIC_DIRECT_INTERRUPTS=y + + + +CONFIG_GPIO_AS_PINRESET=n +# Clock Source +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=n +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC_CALIBRATION=y + +CONFIG_ZMK_EXT_POWER=n + +#CONFIG_ZMK_KSCAN_MATRIX_POLLING=y + +#CONFIG_ZMK_KSCAN_MATRIX_WAIT_BETWEEN_OUTPUTS=10 +#CONFIG_ZMK_KSCAN_MATRIX_WAIT_BEFORE_INPUTS=10 + +CONFIG_ZMK_BLE_THREAD_PRIORITY=-1 + + +CONFIG_ZMK_NRF_24G_ECB=y + + + +CONFIG_ZMK_KSCAN_EVENT_QUEUE_SIZE=32 +CONFIG_ZMK_BLE_KEYBOARD_REPORT_QUEUE_SIZE=64 + +CONFIG_USB_DEVICE_PRODUCT="Keychron B6 Pro" +CONFIG_USB_DEVICE_MANUFACTURER="Keychron" +CONFIG_USB_DEVICE_VID=0x3434 +CONFIG_USB_DEVICE_PID=0x0761 + +CONFIG_BT_DIS_PNP_VID=0x3434 +CONFIG_BT_DIS_PNP_PID=0x0761 +CONFIG_BT_DIS_MODEL="Keychron B6 Pro" +CONFIG_BT_DIS_MANUF="Keychron" +CONFIG_BT_DIS_SETTINGS=y +CONFIG_BT_DIS_FW_REV=y +CONFIG_BT_DIS_HW_REV=y +CONFIG_BT_DIS_SERIAL_NUMBER=y +CONFIG_BT_DIS_FW_REV_STR="v1.2.9" +CONFIG_BT_DIS_HW_REV_STR="v1.0.0" +CONFIG_BT_DIS_SERIAL_NUMBER_STR="SN2024013114230078" + +CONFIG_ZMK_SLEEP=y +CONFIG_ZMK_IDLE_SLEEP_TIMEOUT=7200000 + + +#CONFIG_USB_DRIVER_LOG_LEVEL_DBG=y +#CONFIG_USB_DEVICE_LOG_LEVEL_DBG=y + +CONFIG_USB_HID_BOOT_PROTOCOL=y +CONFIG_USB_HID_DEVICE_COUNT=2 +CONFIG_ENABLE_HID_INT_OUT_EP=y +CONFIG_HID_INTERRUPT_EP_MPS=32 +CONFIG_USB_DEVICE_SOF=y + + +CONFIG_RING_BUFFER=y +#disable ble 2M +CONFIG_BT_CTLR_PHY_2M=n +CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n +CONFIG_BT_KEYS_OVERWRITE_OLDEST=y + +CONFIG_BT_CONN_TX_MAX=8 \ No newline at end of file diff --git a/app/boards/arm/keychron/keychron_z1-287f3d87.keymap b/app/boards/arm/keychron/keychron_z1-287f3d87.keymap new file mode 100644 index 00000000000..bc061a0b81e --- /dev/null +++ b/app/boards/arm/keychron/keychron_z1-287f3d87.keymap @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +// &main_encoder { +// status = "okay"; +// }; + +/ { + ZMK_MACRO(recover, bindings = <&out OUT_RECOVER>;) + ZMK_MACRO(change, bindings = <&out OUT_FN>;) + ZMK_MACRO(fn_win, bindings = <&out OUT_FN_WIN>;) + + ZMK_MACRO(en_bootloader, bindings = <&bootloader>;) + ZMK_MACRO1(MA,bindings=<&kp 0x770000>;) + + long_press_recover:l1 { + compatible = "zmk,behavior-hold-tap"; + label = "l1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&recover>, <&none>; + }; + + long_press_change:l2{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_change"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&change>, <&none>; + }; + long_press_bootloader:l3{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_bootloader"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&en_bootloader>, <&none>; + }; + long_press_fn_win:l4{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_fn_win"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; + bindings = <&fn_win>, <&none>; + }; + + //fn = 95+7 -1 + //j = 63+8 -1 + //z = 79+2 -1 + //x = 79+3 -1 + //l = 63+10 -1 + combos1 { + compatible = "zmk,combos"; + combo_jz { + timeout-ms = <1000>; + layers = <1 3>; + key-positions = <69 81>; //fn+j+z + bindings = <&long_press_recover 0 0>; + }; + combo_xl { + timeout-ms = <1000>; + layers =< 1 3>; + key-positions = <82 71>; //fn+x+l + bindings = <&long_press_change 0 0>; + }; + combo_b { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <85>; //fn+b + bindings = <&out OUT_BAT>; + }; + + combo_win_l { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <97>; //fn+win + bindings = <&long_press_fn_win 0 0>; + }; + combo_win_r { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <101>; //fn+win + bindings = <&long_press_fn_win 0 0>; + }; + combo_t0 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 90>; + bindings = <&to 3 >; + }; + combo_t1 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 91>; + bindings = <&tog 3 >; + }; + combo_t2 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 92>; + bindings = <&sl 3 >; + }; + combo_t3 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <70 93>; + bindings = << 3 SPACE>; + }; + combo_t4 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 94>; + bindings = <&sk LSHIFT>; + }; + combo_t5 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&mt LSHIFT SPACE>; + }; + combo_t6 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&gresc>; + }; + }; + + td0 { + compatible = "zmk,behavior-tap-dance"; + label = "TAPD_LAYER"; + #binding-cells = <1>; + tapping-term-ms = <350>; + bindings =<&mo 0>,<&mo 0>,<&mo 0>,<&mo 0>,<&to 0>; + }; + ZMK_MACRO(bt_pair0, bindings = <&bt BT_PAIR 0>;) + ZMK_MACRO(bt_pair1, bindings = <&bt BT_PAIR 1>;) + ZMK_MACRO(bt_pair2, bindings = <&bt BT_PAIR 2>;) + ZMK_MACRO(bt_pair3, bindings = <&bt BT_PAIR 3>;) + ZMK_MACRO(bt_recon_0, bindings = <&bt BT_SEL 0>;) + ZMK_MACRO(bt_recon_1, bindings = <&bt BT_SEL 1>;) + ZMK_MACRO(bt_recon_2, bindings = <&bt BT_SEL 2>;) + ZMK_MACRO(bt_recon_3, bindings = <&bt BT_SEL 3>;) + + + // hold-tap that doesn't do anything on tap and BT_CLR on hold + bt_pair_0: bt_pair_0 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair0"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair0>, <&bt_recon_0>; + }; + bt_pair_1: bt_pair_1 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair1>, <&bt_recon_1>; + }; + bt_pair_2: bt_pair_2 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair2"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair2>, <&bt_recon_2>; + }; + bt_pair_3: bt_pair_3 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair3"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair3>, <&bt_recon_3>; + }; + uc:user_custom { + compatible = "zmk,behavior-key-press"; + label ="user_custom"; + #binding-cells =<1>; + }; + keymap { + compatible = "zmk,keymap"; + //mac + default_layer { + bindings = < + //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //f14 //f15 //f16 //f17 + &kp ESC &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &kp C_AC_MAC_LAUNCH &kp C_AC_SEARCH &kp C_AL_LOCK &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &uc LG(COMMA) &uc LG(LS(N4)) &none &none &kp C_AC_SEARCH &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &uc LC(LEFT) &uc LC(RIGHT) + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp INS &kp HOME &kp PG_UP &kp KP_NLCK &kp KP_SLASH &kp KP_ASTERISK &kp KP_MINUS + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp DEL &kp END &kp PG_DN &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NUHS &kp RET &kp KP_N4 &kp KP_N5 &kp KP_N6 + &kp LSHFT &kp NUBS &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp KP_N1 &kp KP_N2 &kp KP_N3 + &kp LCTRL &uc LALT &uc LCMD &kp SPACE &uc RCMD &uc RALT &mo 1 &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT &kp KP_N0 &kp KP_DOT &kp KP_ENTER + // + &mo 2 &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //mac + layer_one { + bindings = < + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp F13 &trans &trans &trans &trans &trans &trans &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AC_SEARCH &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LC(LG(SPACE)) &kp PG_UP &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp HOME &kp PG_DN &kp END &trans &trans &trans + // + &none &none &none &none &none + >; + }; + //win + layer_two { + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp F13 &kp PSCRN &kp SLCK &kp PAUS &kp C_AL_CALC &uc LG(TAB) &uc LG(LC(LEFT)) &uc LG(LC(RIGHT)) //21 + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp INS &kp HOME &kp PG_UP &kp KP_NLCK &kp KP_SLASH &kp KP_ASTERISK &kp KP_MINUS //42 + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp DEL &kp END &kp PG_DN &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS //63 + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NUHS &kp RET &kp KP_N4 &kp KP_N5 &kp KP_N6 //63+21-5 + &kp LSHFT &kp NUBS &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp KP_N1 &kp KP_N2 &kp KP_N3 //79+21-5 + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &kp RGUI &mo 3 &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT &kp KP_N0 &kp KP_DOT &kp KP_ENTER + // + &none &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //win + layer_three { + bindings = < + //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //f14 //f15 //f16 //f17 + &trans &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &uc LG(TAB) &uc LG(E) &kp C_AC_SEARCH &uc LG(L) &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &uc LG(I) &trans &trans &trans &trans &trans &trans &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AL_CALC &trans &trans &trans &trans &trans &trans &trans &long_press_bootloader 0 0 + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LG(DOT) &kp PG_UP &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp HOME &kp PG_DN &kp END &trans &trans &trans + // + &none &none &none &none &none + >; + }; + + + + + }; +}; + + diff --git a/app/boards/shields/keychron/Kconfig.shield b/app/boards/shields/keychron/Kconfig.shield new file mode 100644 index 00000000000..7418aa2e9e9 --- /dev/null +++ b/app/boards/shields/keychron/Kconfig.shield @@ -0,0 +1,51 @@ +# Copyright (c) 2020 Pete Johanson +# SPDX-License-Identifier: MIT + +config SHIELD_KEYCHRON_B6_UK + def_bool $(shields_list_contains,keychron_b6_uk) + +config SHIELD_KEYCHRON_B6_US + def_bool $(shields_list_contains,keychron_b6_us) + +config SHIELD_KEYCHRON_B6_JIS + def_bool $(shields_list_contains,keychron_b6_jis) + +config SHIELD_KEYCHRON_B1 + bool + +config SHIELD_KEYCHRON_B1_UK + def_bool $(shields_list_contains,keychron_b1_uk) + select SHIELD_KEYCHRON_B1 + +config SHIELD_KEYCHRON_B1_US + def_bool $(shields_list_contains,keychron_b1_us) + select SHIELD_KEYCHRON_B1 + +config SHIELD_KEYCHRON_B1_JIS + def_bool $(shields_list_contains,keychron_b1_jis) + select SHIELD_KEYCHRON_B1 + +config SHIELD_KEYCHRON_B1_US_DEBUG + def_bool $(shields_list_contains,keychron_b1_us_dbg) + select SHIELD_KEYCHRON_B1 + +config SHIELD_KEYCHRON_B2 + bool +config SHIELD_KEYCHRON_B2_UK + def_bool $(shields_list_contains,keychron_b2_uk) + select SHIELD_KEYCHRON_B2 + +config SHIELD_KEYCHRON_B2_US + def_bool $(shields_list_contains,keychron_b2_us) + select SHIELD_KEYCHRON_B2 + +config SHIELD_KEYCHRON_B2_JIS + def_bool $(shields_list_contains,keychron_b2_jis) + select SHIELD_KEYCHRON_B2 + +config SHIELD_KEYCHRON_B2_KR + def_bool $(shields_list_contains,keychron_b2_kr) + select SHIELD_KEYCHRON_B2 + +config SHIELD_KEYCHRON_RGB + def_bool $(shields_list_contains,keychron_RGB) \ No newline at end of file diff --git a/app/boards/shields/keychron/keychron.zmk.yml b/app/boards/shields/keychron/keychron.zmk.yml new file mode 100644 index 00000000000..6f648122afa --- /dev/null +++ b/app/boards/shields/keychron/keychron.zmk.yml @@ -0,0 +1,12 @@ +file_format: "1" +id: keychron +name: keychron +type: board +arch: arm +features: + - keys + - underglow +outputs: + - usb + - ble +url: https://www.keychron.com/ diff --git a/app/boards/shields/keychron/keychron_b1_jis.conf b/app/boards/shields/keychron/keychron_b1_jis.conf new file mode 100644 index 00000000000..bf1c4518f5e --- /dev/null +++ b/app/boards/shields/keychron/keychron_b1_jis.conf @@ -0,0 +1,11 @@ +CONFIG_USB_DEVICE_PRODUCT="Keychron B1 Pro" +CONFIG_BT_DIS_MODEL="Keychron B1 pro" +CONFIG_ZMK_KEYBOARD_NAME="Keychron B1 Pro" + +CONFIG_USB_DEVICE_VID=0x3434 +CONFIG_USB_DEVICE_PID=0x0713 +CONFIG_BT_DIS_PNP_VID=0x3434 +CONFIG_BT_DIS_PNP_PID=0x0713 +CONFIG_BT_DIS_FW_REV_STR="v1.0.4" +CONFIG_BT_DIS_HW_REV_STR="v1.0.0" +CONFIG_BT_DIS_SERIAL_NUMBER_STR="SN2024040814230078" \ No newline at end of file diff --git a/app/boards/shields/keychron/keychron_b1_jis.keymap b/app/boards/shields/keychron/keychron_b1_jis.keymap new file mode 100644 index 00000000000..145cca9f282 --- /dev/null +++ b/app/boards/shields/keychron/keychron_b1_jis.keymap @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +/ { + ZMK_MACRO(recover, bindings = <&out OUT_RECOVER>;) + ZMK_MACRO(change, bindings = <&out OUT_FN>;) + ZMK_MACRO(fn_win, bindings = <&out OUT_FN_WIN>;) + + ZMK_MACRO(en_bootloader, bindings = <&bootloader>;) + ZMK_MACRO1(MA,bindings=<&kp 0x770000>;) + + long_press_recover:l1 { + compatible = "zmk,behavior-hold-tap"; + label = "l1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&recover>, <&none>; + }; + + long_press_change:l2{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_change"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&change>, <&none>; + }; + long_press_bootloader:l3{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_bootloader"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&en_bootloader>, <&none>; + }; + long_press_fn_win:l4{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_fn_win"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; + bindings = <&fn_win>, <&none>; + }; + + + combos1 { + compatible = "zmk,combos"; + combo_jz { + timeout-ms = <1000>; + layers = <1 3>; + key-positions = <49 57>; //fn+j+z + bindings = <&long_press_recover 0 0>; + }; + combo_xl { + timeout-ms = <1000>; + layers =< 1 3>; + key-positions = <58 51>; //fn+x+l + bindings = <&long_press_change 0 0>; + }; + combo_b { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <61>; //fn+b + bindings = <&out OUT_BAT>; + }; + + combo_win_l { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <70>; //fn+win + bindings = <&long_press_fn_win 0 0>; + }; + + combo_t0 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 90>; + bindings = <&to 3 >; + }; + combo_t1 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 91>; + bindings = <&tog 3 >; + }; + combo_t2 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 92>; + bindings = <&sl 3 >; + }; + combo_t3 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <70 93>; + bindings = << 3 SPACE>; + }; + combo_t4 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 94>; + bindings = <&sk LSHIFT>; + }; + combo_t5 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&mt LSHIFT SPACE>; + }; + combo_t6 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&gresc>; + }; + }; + + td0 { + compatible = "zmk,behavior-tap-dance"; + label = "TAPD_LAYER"; + #binding-cells = <1>; + tapping-term-ms = <350>; + bindings =<&mo 0>,<&mo 0>,<&mo 0>,<&mo 0>,<&to 0>; + }; + ZMK_MACRO(bt_pair0, bindings = <&bt BT_PAIR 0>;) + ZMK_MACRO(bt_pair1, bindings = <&bt BT_PAIR 1>;) + ZMK_MACRO(bt_pair2, bindings = <&bt BT_PAIR 2>;) + ZMK_MACRO(bt_pair3, bindings = <&bt BT_PAIR 3>;) + ZMK_MACRO(bt_recon_0, bindings = <&bt BT_SEL 0>;) + ZMK_MACRO(bt_recon_1, bindings = <&bt BT_SEL 1>;) + ZMK_MACRO(bt_recon_2, bindings = <&bt BT_SEL 2>;) + ZMK_MACRO(bt_recon_3, bindings = <&bt BT_SEL 3>;) + + + + bt_pair_0: bt_pair_0 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair0"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair0>, <&bt_recon_0>; + }; + bt_pair_1: bt_pair_1 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair1>, <&bt_recon_1>; + }; + bt_pair_2: bt_pair_2 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair2"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair2>, <&bt_recon_2>; + }; + bt_pair_3: bt_pair_3 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair3"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair3>, <&bt_recon_3>; + }; + uc:user_custom { + compatible = "zmk,behavior-key-press"; + label ="user_custom"; + #binding-cells =<1>; + }; + + keymap { + compatible = "zmk,keymap"; + //mac + default_layer { + bindings = < + //ESC //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //DEL + &kp ESC &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &kp C_AC_MAC_LAUNCH &kp C_AC_SEARCH &kp C_AL_LOCK &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &kp DEL + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp INT3 &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NUHS &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp INT1 &kp RSHFT + &kp LCTRL &uc LALT &uc LCMD &kp LANG2 &kp SPACE &kp LANG1 &uc RCMD &mo 1 &kp LEFT &kp UP &kp DOWN &kp RIGHT + &mo 2 &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //mac + layer_one { + bindings = < + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AC_SEARCH &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LC(LG(SPACE)) + &trans &trans &trans &trans &trans &trans &kp RCTRL &trans &kp HOME &kp PG_UP &kp PG_DN &kp END + // + &none &none &none &none &none + >; + }; + //win + layer_two { + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp DEL + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp INT3 &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NUHS &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp INT1 &kp RSHFT + &kp LCTRL &kp LGUI &kp LALT &kp INT5 &kp SPACE &kp INT4 &kp RALT &mo 3 &kp LEFT &kp UP &kp DOWN &kp RIGHT + // + &none &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //win + layer_three { + bindings = < + //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 + &trans &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &uc LG(TAB) &uc LG(E) &kp C_AC_SEARCH &uc LG(L) &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AL_CALC &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LG(DOT) + &trans &trans &trans &trans &trans &trans &kp RCTRL &trans &kp HOME &kp PG_UP &kp PG_DN &kp END + // + &none &none &none &none &none + >; + }; + + + + + }; +}; + + diff --git a/app/boards/shields/keychron/keychron_b1_jis.overlay b/app/boards/shields/keychron/keychron_b1_jis.overlay new file mode 100644 index 00000000000..d05970233bb --- /dev/null +++ b/app/boards/shields/keychron/keychron_b1_jis.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 Nick Winans + * + * SPDX-License-Identifier: MIT + */ + +#include + + +/ { + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <18>; + rows = <8>; + map = < + //esc //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //del + RC(3,1) RC(6,2) RC(6,3) RC(1,3) RC(3,3) RC(7,0) RC(3,6) RC(1,7) RC(6,7) RC(6,10) RC(7,10) RC(3,10) RC(5,10) RC(6,11) + //grave //1 //2 //3 //4 //5 //6 //7 //8 //9 //0 //- //+= //int3 //back + RC(6,1) RC(7,1) RC(7,2) RC(7,3) RC(7,4) RC(6,4) RC(6,5) RC(7,5) RC(7,6) RC(7,7) RC(7,8) RC(6,8) RC(6,6) RC(0,10) RC(1,10) + //tab //q //w //e //r // t //y //u //i //o //p //[ //] + RC(1,1) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(1,4) RC(1,5) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(1,8) RC(1,6) + //cap //a //s //d //f //g //h //j //k //l // ; //' " //NUHS //enter + RC(1,2) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(3,8) RC(4, 8) RC(4,10) + //lshit //z //x //c //v //b //n //m //,< //.> //?/ //int1 //rshit + RC(1,15) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(5,4) RC(5,5) RC(4,5) RC(4,6) RC(4,7) RC(5,8) RC(5,6) RC(2,15) + //lctrl //win l //alt l //int5/lan2 //space //int4/lan1 //alt gr //fn //left //up //down //right + RC(6,0) RC(1,16) RC(3,9) RC(5,1) RC(3,11) RC(5,2) RC(5,9) RC(2,9) RC(5,14) RC(3,14) RC(5,11) RC(5,12) + //m/w //bt //24g //ch //ch done + RC(8,0) RC(8,1) RC(8,2) RC(8,3) RC(8,4) + >; + }; + +}; + diff --git a/app/boards/shields/keychron/keychron_b1_uk.conf b/app/boards/shields/keychron/keychron_b1_uk.conf new file mode 100644 index 00000000000..c580deb5568 --- /dev/null +++ b/app/boards/shields/keychron/keychron_b1_uk.conf @@ -0,0 +1,11 @@ +CONFIG_USB_DEVICE_PRODUCT="Keychron B1 Pro" +CONFIG_BT_DIS_MODEL="Keychron B1 pro" +CONFIG_ZMK_KEYBOARD_NAME="Keychron B1 Pro" + +CONFIG_USB_DEVICE_VID=0x3434 +CONFIG_USB_DEVICE_PID=0x0712 +CONFIG_BT_DIS_PNP_VID=0x3434 +CONFIG_BT_DIS_PNP_PID=0x0712 +CONFIG_BT_DIS_FW_REV_STR="v1.0.4" +CONFIG_BT_DIS_HW_REV_STR="v1.0.0" +CONFIG_BT_DIS_SERIAL_NUMBER_STR="SN2024040814230078" \ No newline at end of file diff --git a/app/boards/shields/keychron/keychron_b1_uk.keymap b/app/boards/shields/keychron/keychron_b1_uk.keymap new file mode 100644 index 00000000000..4e90e435d2b --- /dev/null +++ b/app/boards/shields/keychron/keychron_b1_uk.keymap @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +/ { + ZMK_MACRO(recover, bindings = <&out OUT_RECOVER>;) + ZMK_MACRO(change, bindings = <&out OUT_FN>;) + ZMK_MACRO(fn_win, bindings = <&out OUT_FN_WIN>;) + + ZMK_MACRO(en_bootloader, bindings = <&bootloader>;) + ZMK_MACRO1(MA,bindings=<&kp 0x770000>;) + + long_press_recover:l1 { + compatible = "zmk,behavior-hold-tap"; + label = "l1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&recover>, <&none>; + }; + + long_press_change:l2{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_change"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&change>, <&none>; + }; + long_press_bootloader:l3{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_bootloader"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&en_bootloader>, <&none>; + }; + long_press_fn_win:l4{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_fn_win"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; + bindings = <&fn_win>, <&none>; + }; + + + combos1 { + compatible = "zmk,combos"; + combo_jz { + timeout-ms = <1000>; + layers = <1 3>; + key-positions = <48 57>; //fn+j+z + bindings = <&long_press_recover 0 0>; + }; + combo_xl { + timeout-ms = <1000>; + layers =< 1 3>; + key-positions = <58 50>; //fn+x+l + bindings = <&long_press_change 0 0>; + }; + combo_b { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <61>; //fn+b + bindings = <&out OUT_BAT>; + }; + + combo_win_l { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <69>; //fn+win + bindings = <&long_press_fn_win 0 0>; + }; + + combo_t0 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 90>; + bindings = <&to 3 >; + }; + combo_t1 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 91>; + bindings = <&tog 3 >; + }; + combo_t2 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 92>; + bindings = <&sl 3 >; + }; + combo_t3 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <70 93>; + bindings = << 3 SPACE>; + }; + combo_t4 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 94>; + bindings = <&sk LSHIFT>; + }; + combo_t5 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&mt LSHIFT SPACE>; + }; + combo_t6 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&gresc>; + }; + }; + + td0 { + compatible = "zmk,behavior-tap-dance"; + label = "TAPD_LAYER"; + #binding-cells = <1>; + tapping-term-ms = <350>; + bindings =<&mo 0>,<&mo 0>,<&mo 0>,<&mo 0>,<&to 0>; + }; + ZMK_MACRO(bt_pair0, bindings = <&bt BT_PAIR 0>;) + ZMK_MACRO(bt_pair1, bindings = <&bt BT_PAIR 1>;) + ZMK_MACRO(bt_pair2, bindings = <&bt BT_PAIR 2>;) + ZMK_MACRO(bt_pair3, bindings = <&bt BT_PAIR 3>;) + ZMK_MACRO(bt_recon_0, bindings = <&bt BT_SEL 0>;) + ZMK_MACRO(bt_recon_1, bindings = <&bt BT_SEL 1>;) + ZMK_MACRO(bt_recon_2, bindings = <&bt BT_SEL 2>;) + ZMK_MACRO(bt_recon_3, bindings = <&bt BT_SEL 3>;) + + + + bt_pair_0: bt_pair_0 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair0"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair0>, <&bt_recon_0>; + }; + bt_pair_1: bt_pair_1 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair1>, <&bt_recon_1>; + }; + bt_pair_2: bt_pair_2 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair2"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair2>, <&bt_recon_2>; + }; + bt_pair_3: bt_pair_3 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair3"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair3>, <&bt_recon_3>; + }; + uc:user_custom { + compatible = "zmk,behavior-key-press"; + label ="user_custom"; + #binding-cells =<1>; + }; + + keymap { + compatible = "zmk,keymap"; + //mac + default_layer { + bindings = < + //ESC //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //DEL + &kp ESC &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &kp C_AC_MAC_LAUNCH &kp C_AC_SEARCH &kp C_AL_LOCK &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &kp DEL + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NUHS &kp RET + &kp LSHFT &kp NUBS &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LCTRL &uc LALT &uc LCMD &kp SPACE &uc RCMD &mo 1 &kp LEFT &kp UP &kp DOWN &kp RIGHT + &mo 2 &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //mac + layer_one { + bindings = < + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AC_SEARCH &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LC(LG(SPACE)) + &trans &trans &trans &trans &kp RCTRL &trans &kp HOME &kp PG_UP &kp PG_DN &kp END + // + &none &none &none &none &none + >; + }; + //win + layer_two { + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp DEL + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NUHS &kp RET + &kp LSHFT &kp NUBS &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 3 &kp LEFT &kp UP &kp DOWN &kp RIGHT + // + &none &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //win + layer_three { + bindings = < + //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 + &trans &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &uc LG(TAB) &uc LG(E) &kp C_AC_SEARCH &uc LG(L) &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AL_CALC &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LG(DOT) + &trans &trans &trans &trans &kp RCTRL &trans &kp HOME &kp PG_UP &kp PG_DN &kp END + // + &none &none &none &none &none + >; + }; + + + + + }; +}; + + diff --git a/app/boards/shields/keychron/keychron_b1_uk.overlay b/app/boards/shields/keychron/keychron_b1_uk.overlay new file mode 100644 index 00000000000..b0e55ed57f6 --- /dev/null +++ b/app/boards/shields/keychron/keychron_b1_uk.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 Nick Winans + * + * SPDX-License-Identifier: MIT + */ + +#include + + +/ { + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <18>; + rows = <8>; + map = < + //esc //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //del + RC(3,1) RC(6,2) RC(6,3) RC(1,3) RC(3,3) RC(7,0) RC(3,6) RC(1,7) RC(6,7) RC(6,10) RC(7,10) RC(3,10) RC(5,10) RC(6,11) + //grave //1 //2 //3 //4 //5 //6 //7 //8 //9 //0 //- //+= //back + RC(6,1) RC(7,1) RC(7,2) RC(7,3) RC(7,4) RC(6,4) RC(6,5) RC(7,5) RC(7,6) RC(7,7) RC(7,8) RC(6,8) RC(6,6) RC(1,10) + //tab //q //w //e //r // t //y //u //i //o //p //[ //] + RC(1,1) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(1,4) RC(1,5) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(1,8) RC(1,6) + //cap //a //s //d //f //g //h //j //k //l // ; //' " //NUHS //enter + RC(1,2) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(3,8) RC(2,10) RC(4,10) + //lshit //NUBS //z //x //c //v //b //n //m //,< //.> //?/ //rshit + RC(1,15) RC(3,2) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(5,4) RC(5,5) RC(4,5) RC(4,6) RC(4,7) RC(5,8) RC(2,15) + //lctrl //win l //alt l //space //alt gr //fn //left //up //down //right + RC(6,0) RC(1,16) RC(3,9) RC(3,11) RC(5,9) RC(2,9) RC(5,14) RC(3,14) RC(5,11) RC(5,12) + //m/w //bt //24g //ch //ch done + RC(8,0) RC(8,1) RC(8,2) RC(8,3) RC(8,4) + >; + }; + +}; + diff --git a/app/boards/shields/keychron/keychron_b1_us.conf b/app/boards/shields/keychron/keychron_b1_us.conf new file mode 100644 index 00000000000..8a15f87e52c --- /dev/null +++ b/app/boards/shields/keychron/keychron_b1_us.conf @@ -0,0 +1,11 @@ +CONFIG_USB_DEVICE_PRODUCT="Keychron B1 Pro" +CONFIG_BT_DIS_MODEL="Keychron B1 pro" +CONFIG_ZMK_KEYBOARD_NAME="Keychron B1 Pro" + +CONFIG_USB_DEVICE_VID=0x3434 +CONFIG_USB_DEVICE_PID=0x0711 +CONFIG_BT_DIS_PNP_VID=0x3434 +CONFIG_BT_DIS_PNP_PID=0x0711 +CONFIG_BT_DIS_FW_REV_STR="v1.0.4" +CONFIG_BT_DIS_HW_REV_STR="v1.0.0" +CONFIG_BT_DIS_SERIAL_NUMBER_STR="SN2024040814230078" \ No newline at end of file diff --git a/app/boards/shields/keychron/keychron_b1_us.keymap b/app/boards/shields/keychron/keychron_b1_us.keymap new file mode 100644 index 00000000000..9714174cde3 --- /dev/null +++ b/app/boards/shields/keychron/keychron_b1_us.keymap @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +/ { + ZMK_MACRO(recover, bindings = <&out OUT_RECOVER>;) + ZMK_MACRO(change, bindings = <&out OUT_FN>;) + ZMK_MACRO(fn_win, bindings = <&out OUT_FN_WIN>;) + + ZMK_MACRO(en_bootloader, bindings = <&bootloader>;) + ZMK_MACRO1(MA,bindings=<&kp 0x770000>;) + + long_press_recover:l1 { + compatible = "zmk,behavior-hold-tap"; + label = "l1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&recover>, <&none>; + }; + + long_press_change:l2{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_change"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&change>, <&none>; + }; + long_press_bootloader:l3{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_bootloader"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&en_bootloader>, <&none>; + }; + long_press_fn_win:l4{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_fn_win"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; + bindings = <&fn_win>, <&none>; + }; + + + combos1 { + compatible = "zmk,combos"; + combo_jz { + timeout-ms = <1000>; + layers = <1 3>; + key-positions = <49 56>; //fn+j+z + bindings = <&long_press_recover 0 0>; + }; + combo_xl { + timeout-ms = <1000>; + layers =< 1 3>; + key-positions = <57 51>; //fn+x+l + bindings = <&long_press_change 0 0>; + }; + combo_b { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <60>; //fn+b + bindings = <&out OUT_BAT>; + }; + + combo_win_l { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <68>; //fn+win + bindings = <&long_press_fn_win 0 0>; + }; + + combo_t0 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 90>; + bindings = <&to 3 >; + }; + combo_t1 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 91>; + bindings = <&tog 3 >; + }; + combo_t2 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 92>; + bindings = <&sl 3 >; + }; + combo_t3 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <70 93>; + bindings = << 3 SPACE>; + }; + combo_t4 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 94>; + bindings = <&sk LSHIFT>; + }; + combo_t5 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&mt LSHIFT SPACE>; + }; + combo_t6 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&gresc>; + }; + }; + + td0 { + compatible = "zmk,behavior-tap-dance"; + label = "TAPD_LAYER"; + #binding-cells = <1>; + tapping-term-ms = <350>; + bindings =<&mo 0>,<&mo 0>,<&mo 0>,<&mo 0>,<&to 0>; + }; + ZMK_MACRO(bt_pair0, bindings = <&bt BT_PAIR 0>;) + ZMK_MACRO(bt_pair1, bindings = <&bt BT_PAIR 1>;) + ZMK_MACRO(bt_pair2, bindings = <&bt BT_PAIR 2>;) + ZMK_MACRO(bt_pair3, bindings = <&bt BT_PAIR 3>;) + ZMK_MACRO(bt_recon_0, bindings = <&bt BT_SEL 0>;) + ZMK_MACRO(bt_recon_1, bindings = <&bt BT_SEL 1>;) + ZMK_MACRO(bt_recon_2, bindings = <&bt BT_SEL 2>;) + ZMK_MACRO(bt_recon_3, bindings = <&bt BT_SEL 3>;) + + + + bt_pair_0: bt_pair_0 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair0"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair0>, <&bt_recon_0>; + }; + bt_pair_1: bt_pair_1 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair1>, <&bt_recon_1>; + }; + bt_pair_2: bt_pair_2 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair2"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair2>, <&bt_recon_2>; + }; + bt_pair_3: bt_pair_3 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair3"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair3>, <&bt_recon_3>; + }; + uc:user_custom { + compatible = "zmk,behavior-key-press"; + label ="user_custom"; + #binding-cells =<1>; + }; + + keymap { + compatible = "zmk,keymap"; + //mac + default_layer { + bindings = < + //ESC //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //DEL + &kp ESC &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &kp C_AC_MAC_LAUNCH &kp C_AC_SEARCH &kp C_AL_LOCK &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &kp DEL + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LCTRL &uc LALT &uc LCMD &kp SPACE &uc RCMD &mo 1 &kp LEFT &kp UP &kp DOWN &kp RIGHT + &mo 2 &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //mac + layer_one { + bindings = < + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AC_SEARCH &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &uc LG(LS(N4)) + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LC(LG(SPACE)) + &trans &trans &trans &trans &kp RCTRL &trans &kp HOME &kp PG_UP &kp PG_DN &kp END + // + &none &none &none &none &none + >; + }; + //win + layer_two { + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp DEL + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 3 &kp LEFT &kp UP &kp DOWN &kp RIGHT + // + &none &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //win + layer_three { + bindings = < + //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 + &trans &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &uc LG(TAB) &uc LG(E) &kp C_AC_SEARCH &uc LG(L) &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AL_CALC &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &uc LG(LS(S)) + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LG(DOT) + &trans &trans &trans &trans &kp RCTRL &trans &kp HOME &kp PG_UP &kp PG_DN &kp END + // + &none &none &none &none &none + >; + }; + + + + + }; +}; + + diff --git a/app/boards/shields/keychron/keychron_b1_us.overlay b/app/boards/shields/keychron/keychron_b1_us.overlay new file mode 100644 index 00000000000..56bd7621c8d --- /dev/null +++ b/app/boards/shields/keychron/keychron_b1_us.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 Nick Winans + * + * SPDX-License-Identifier: MIT + */ + + +#include + + +/ { + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <18>; + rows = <8>; + map = < + //esc //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //del + RC(3,1) RC(6,2) RC(6,3) RC(1,3) RC(3,3) RC(7,0) RC(3,6) RC(1,7) RC(6,7) RC(6,10) RC(7,10) RC(3,10) RC(5,10) RC(6,11) + //grave //1 //2 //3 //4 //5 //6 //7 //8 //9 //0 //- //+= //back + RC(6,1) RC(7,1) RC(7,2) RC(7,3) RC(7,4) RC(6,4) RC(6,5) RC(7,5) RC(7,6) RC(7,7) RC(7,8) RC(6,8) RC(6,6) RC(1,10) + //tab //q //w //e //r // t //y //u //i //o //p //[ //] //'\' + RC(1,1) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(1,4) RC(1,5) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(1,8) RC(1,6) RC(2,10) + //cap //a //s //d //f //g //h //j //k //l // ; //' " //enter + RC(1,2) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(3,8) RC(4,10) + //lshit //z //x //c //v //b //n //m //,< //.> //?/ //rshit + RC(1,15) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(5,4) RC(5,5) RC(4,5) RC(4,6) RC(4,7) RC(5,8) RC(2,15) + //lctrl //win l //alt l //space //alt r //fn //left //up //down //right + RC(6,0) RC(1,16) RC(3,9) RC(3,11) RC(5,9) RC(2,9) RC(5,14) RC(3,14) RC(5,11) RC(5,12) + //m/w //bt //24g //ch //ch done + RC(8,0) RC(8,1) RC(8,2) RC(8,3) RC(8,4) + >; + }; + +}; + diff --git a/app/boards/shields/keychron/keychron_b1_us_dbg.conf b/app/boards/shields/keychron/keychron_b1_us_dbg.conf new file mode 100644 index 00000000000..1c25538f3e9 --- /dev/null +++ b/app/boards/shields/keychron/keychron_b1_us_dbg.conf @@ -0,0 +1,25 @@ +CONFIG_USB_DEVICE_PRODUCT="Keychron B1 Pro" +CONFIG_BT_DIS_MODEL="Keychron B1 pro" +CONFIG_ZMK_KEYBOARD_NAME="Keychron B1 Pro" + +CONFIG_USB_DEVICE_VID=0x3434 +CONFIG_USB_DEVICE_PID=0x0711 +CONFIG_BT_DIS_PNP_VID=0x3434 +CONFIG_BT_DIS_PNP_PID=0x0711 +CONFIG_BT_DIS_FW_REV_STR="v1.0.1" +CONFIG_BT_DIS_HW_REV_STR="v1.0.0" +CONFIG_BT_DIS_SERIAL_NUMBER_STR="SN2024040814230078" + +#debug +CONFIG_ZMK_UART_LOGGING=y +CONFIG_ZMK_BLE_THREAD_PRIORITY=5 + +#CONFIG_BT_DEBUG_LOG=y +#CONFIG_BT_DEBUG_GATT=y +CONFIG_BT_CONN_TX_MAX=8 + + +#usb debug +CONFIG_ZMK_UART_LOGGING=n +CONFIG_ZMK_USB_LOGGING=y +CONFIG_USB_CDC_ACM_RINGBUF_SIZE=8192 \ No newline at end of file diff --git a/app/boards/shields/keychron/keychron_b1_us_dbg.keymap b/app/boards/shields/keychron/keychron_b1_us_dbg.keymap new file mode 100644 index 00000000000..b692ba6dc7d --- /dev/null +++ b/app/boards/shields/keychron/keychron_b1_us_dbg.keymap @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +/ { + ZMK_MACRO(recover, bindings = <&out OUT_RECOVER>;) + ZMK_MACRO(change, bindings = <&out OUT_FN>;) + ZMK_MACRO(fn_win, bindings = <&out OUT_FN_WIN>;) + + ZMK_MACRO(en_bootloader, bindings = <&bootloader>;) + ZMK_MACRO1(MA,bindings=<&kp 0x770000>;) + + long_press_recover:l1 { + compatible = "zmk,behavior-hold-tap"; + label = "l1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&recover>, <&none>; + }; + + long_press_change:l2{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_change"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&change>, <&none>; + }; + long_press_bootloader:l3{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_bootloader"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&en_bootloader>, <&none>; + }; + long_press_fn_win:l4{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_fn_win"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; + bindings = <&fn_win>, <&none>; + }; + + + combos1 { + compatible = "zmk,combos"; + combo_jz { + timeout-ms = <1000>; + layers = <1 3>; + key-positions = <49 56>; //fn+j+z + bindings = <&long_press_recover 0 0>; + }; + combo_xl { + timeout-ms = <1000>; + layers =< 1 3>; + key-positions = <57 51>; //fn+x+l + bindings = <&long_press_change 0 0>; + }; + combo_b { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <60>; //fn+b + bindings = <&out OUT_BAT>; + }; + + combo_win_l { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <68>; //fn+win + bindings = <&long_press_fn_win 0 0>; + }; + + combo_t0 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 90>; + bindings = <&to 3 >; + }; + combo_t1 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 91>; + bindings = <&tog 3 >; + }; + combo_t2 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 92>; + bindings = <&sl 3 >; + }; + combo_t3 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <70 93>; + bindings = << 3 SPACE>; + }; + combo_t4 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 94>; + bindings = <&sk LSHIFT>; + }; + combo_t5 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&mt LSHIFT SPACE>; + }; + combo_t6 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&gresc>; + }; + }; + + td0 { + compatible = "zmk,behavior-tap-dance"; + label = "TAPD_LAYER"; + #binding-cells = <1>; + tapping-term-ms = <350>; + bindings =<&mo 0>,<&mo 0>,<&mo 0>,<&mo 0>,<&to 0>; + }; + ZMK_MACRO(bt_pair0, bindings = <&bt BT_PAIR 0>;) + ZMK_MACRO(bt_pair1, bindings = <&bt BT_PAIR 1>;) + ZMK_MACRO(bt_pair2, bindings = <&bt BT_PAIR 2>;) + ZMK_MACRO(bt_pair3, bindings = <&bt BT_PAIR 3>;) + ZMK_MACRO(bt_recon_0, bindings = <&bt BT_SEL 0>;) + ZMK_MACRO(bt_recon_1, bindings = <&bt BT_SEL 1>;) + ZMK_MACRO(bt_recon_2, bindings = <&bt BT_SEL 2>;) + ZMK_MACRO(bt_recon_3, bindings = <&bt BT_SEL 3>;) + + + + bt_pair_0: bt_pair_0 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair0"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair0>, <&bt_recon_0>; + }; + bt_pair_1: bt_pair_1 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair1>, <&bt_recon_1>; + }; + bt_pair_2: bt_pair_2 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair2"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair2>, <&bt_recon_2>; + }; + bt_pair_3: bt_pair_3 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair3"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair3>, <&bt_recon_3>; + }; + uc:user_custom { + compatible = "zmk,behavior-key-press"; + label ="user_custom"; + #binding-cells =<1>; + }; + + keymap { + compatible = "zmk,keymap"; + //mac + default_layer { + bindings = < + //ESC //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //DEL + &kp ESC &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &kp C_AC_MAC_LAUNCH &kp C_AC_SEARCH &kp C_AL_LOCK &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &kp DEL + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LCTRL &uc LALT &uc LCMD &kp SPACE &uc RCMD &mo 1 &kp LEFT &kp UP &kp DOWN &kp RIGHT + &mo 2 &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //mac + layer_one { + bindings = < + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AC_SEARCH &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &uc LG(LS(N4)) + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LC(LG(SPACE)) + &trans &trans &trans &trans &kp RCTRL &trans &kp HOME &kp PG_UP &kp PG_DN &kp END + // + &none &none &none &none &none + >; + }; + //win + layer_two { + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp DEL + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 3 &kp LEFT &kp UP &kp DOWN &kp RIGHT + // + &none &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //win + layer_three { + bindings = < + //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 + &trans &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &uc LG(TAB) &uc LG(E) &kp C_AC_SEARCH &uc LG(L) &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &long_press_bootloader 0 0 &kp C_AL_CALC &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &uc LG(LS(S)) + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LG(DOT) + &trans &trans &trans &trans &kp RCTRL &trans &kp HOME &kp PG_UP &kp PG_DN &kp END + // + &none &none &none &none &none + >; + }; + + + + + }; +}; + + diff --git a/app/boards/shields/keychron/keychron_b1_us_dbg.overlay b/app/boards/shields/keychron/keychron_b1_us_dbg.overlay new file mode 100644 index 00000000000..0241cc2be2f --- /dev/null +++ b/app/boards/shields/keychron/keychron_b1_us_dbg.overlay @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 Nick Winans + * + * SPDX-License-Identifier: MIT + */ + + +#include + + +/ { + // add for usb debug + chosen { + zephyr,console = &cdc_acm_uart; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <18>; + rows = <8>; + map = < + //esc //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //del + RC(3,1) RC(6,2) RC(6,3) RC(1,3) RC(3,3) RC(7,0) RC(3,6) RC(1,7) RC(6,7) RC(6,10) RC(7,10) RC(3,10) RC(5,10) RC(6,11) + //grave //1 //2 //3 //4 //5 //6 //7 //8 //9 //0 //- //+= //back + RC(6,1) RC(7,1) RC(7,2) RC(7,3) RC(7,4) RC(6,4) RC(6,5) RC(7,5) RC(7,6) RC(7,7) RC(7,8) RC(6,8) RC(6,6) RC(1,10) + //tab //q //w //e //r // t //y //u //i //o //p //[ //] //'\' + RC(1,1) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(1,4) RC(1,5) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(1,8) RC(1,6) RC(2,10) + //cap //a //s //d //f //g //h //j //k //l // ; //' " //enter + RC(1,2) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(3,8) RC(4,10) + //lshit //z //x //c //v //b //n //m //,< //.> //?/ //rshit + RC(1,15) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(5,4) RC(5,5) RC(4,5) RC(4,6) RC(4,7) RC(5,8) RC(2,15) + //lctrl //win l //alt l //space //alt r //fn //left //up //down //right + RC(6,0) RC(1,16) RC(3,9) RC(3,11) RC(5,9) RC(2,9) RC(5,14) RC(3,14) RC(5,11) RC(5,12) + //m/w //bt //24g //ch //ch done + RC(8,0) RC(8,1) RC(8,2) RC(8,3) RC(8,4) + >; + }; + +}; +&uart0{ + status="okay"; +}; + +&kscan0{ + + debounce-scan-period-ms =<4>; + debounce-press-ms =<8>; + debounce-release-ms=<8>; +}; +// add for usb debug +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; diff --git a/app/boards/shields/keychron/keychron_b2_jis.conf b/app/boards/shields/keychron/keychron_b2_jis.conf new file mode 100644 index 00000000000..0b6f5509ec3 --- /dev/null +++ b/app/boards/shields/keychron/keychron_b2_jis.conf @@ -0,0 +1,11 @@ +CONFIG_USB_DEVICE_PRODUCT="Keychron B2 Pro" +CONFIG_BT_DIS_MODEL="Keychron B2 Pro" +CONFIG_ZMK_KEYBOARD_NAME="Keychron B2 Pro" + +CONFIG_USB_DEVICE_VID=0x3434 +CONFIG_USB_DEVICE_PID=0x0722 +CONFIG_BT_DIS_PNP_VID=0x3434 +CONFIG_BT_DIS_PNP_PID=0x0722 +CONFIG_BT_DIS_FW_REV_STR="v1.0.2" +CONFIG_BT_DIS_HW_REV_STR="v1.0.0" +CONFIG_BT_DIS_SERIAL_NUMBER_STR="SN2024051614230078" \ No newline at end of file diff --git a/app/boards/shields/keychron/keychron_b2_jis.keymap b/app/boards/shields/keychron/keychron_b2_jis.keymap new file mode 100644 index 00000000000..8b3a4a85fff --- /dev/null +++ b/app/boards/shields/keychron/keychron_b2_jis.keymap @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +/ { + ZMK_MACRO(recover, bindings = <&out OUT_RECOVER>;) + ZMK_MACRO(change, bindings = <&out OUT_FN>;) + ZMK_MACRO(fn_win, bindings = <&out OUT_FN_WIN>;) + + ZMK_MACRO(en_bootloader, bindings = <&bootloader>;) + ZMK_MACRO1(MA,bindings=<&kp 0x770000>;) + + long_press_recover:l1 { + compatible = "zmk,behavior-hold-tap"; + label = "l1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&recover>, <&none>; + }; + + long_press_change:l2{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_change"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&change>, <&none>; + }; + long_press_bootloader:l3{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_bootloader"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&en_bootloader>, <&none>; + }; + long_press_fn_win:l4{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_fn_win"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; + bindings = <&fn_win>, <&none>; + }; + + + combos1 { + compatible = "zmk,combos"; + combo_jz { + timeout-ms = <1000>; + layers = <1 3>; + key-positions = <61 72>; //fn+j+z + bindings = <&long_press_recover 0 0>; + }; + combo_xl { + timeout-ms = <1000>; + layers =< 1 3>; + key-positions = <73 63>; //fn+x+l + bindings = <&long_press_change 0 0>; + }; + combo_b { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <76>; //fn+b + bindings = <&out OUT_BAT>; + }; + + combo_win_l { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <88>; //fn+win + bindings = <&long_press_fn_win 0 0>; + }; + + combo_t0 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 90>; + bindings = <&to 3 >; + }; + combo_t1 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 91>; + bindings = <&tog 3 >; + }; + combo_t2 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 92>; + bindings = <&sl 3 >; + }; + combo_t3 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <70 93>; + bindings = << 3 SPACE>; + }; + combo_t4 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 94>; + bindings = <&sk LSHIFT>; + }; + combo_t5 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&mt LSHIFT SPACE>; + }; + combo_t6 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&gresc>; + }; + }; + + td0 { + compatible = "zmk,behavior-tap-dance"; + label = "TAPD_LAYER"; + #binding-cells = <1>; + tapping-term-ms = <350>; + bindings =<&mo 0>,<&mo 0>,<&mo 0>,<&mo 0>,<&to 0>; + }; + ZMK_MACRO(bt_pair0, bindings = <&bt BT_PAIR 0>;) + ZMK_MACRO(bt_pair1, bindings = <&bt BT_PAIR 1>;) + ZMK_MACRO(bt_pair2, bindings = <&bt BT_PAIR 2>;) + ZMK_MACRO(bt_pair3, bindings = <&bt BT_PAIR 3>;) + ZMK_MACRO(bt_recon_0, bindings = <&bt BT_SEL 0>;) + ZMK_MACRO(bt_recon_1, bindings = <&bt BT_SEL 1>;) + ZMK_MACRO(bt_recon_2, bindings = <&bt BT_SEL 2>;) + ZMK_MACRO(bt_recon_3, bindings = <&bt BT_SEL 3>;) + + + + bt_pair_0: bt_pair_0 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair0"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair0>, <&bt_recon_0>; + }; + bt_pair_1: bt_pair_1 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair1>, <&bt_recon_1>; + }; + bt_pair_2: bt_pair_2 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair2"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair2>, <&bt_recon_2>; + }; + bt_pair_3: bt_pair_3 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair3"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair3>, <&bt_recon_3>; + }; + uc:user_custom { + compatible = "zmk,behavior-key-press"; + label ="user_custom"; + #binding-cells =<1>; + }; + + keymap { + compatible = "zmk,keymap"; + //mac + default_layer { + bindings = < + //ESC //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //del //home //pgup //pgdn + &kp ESC &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &kp C_AC_MAC_LAUNCH &kp C_AC_SEARCH &kp C_AL_LOCK &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &uc LG(COMMA) &kp DEL &kp HOME &kp PG_UP &kp PG_DN + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp INT3 &kp BSPC &kp KP_NLCK &kp KP_SLASH &kp KP_ASTERISK &kp KP_MINUS + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NUHS &kp RET &kp KP_N4 &kp KP_N5 &kp KP_N6 + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp INT1 &kp RSHFT &kp KP_N1 &kp KP_N2 &kp KP_N3 + &kp LCTRL &uc LALT &uc LCMD &kp LANG2 &kp SPACE &kp LANG1 &uc RCMD &mo 1 &kp LEFT &kp UP &kp DOWN &kp RIGHT &kp KP_N0 &kp KP_DOT &kp KP_ENTER + &mo 2 &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //mac + layer_one { + bindings = < + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp F13 &trans &trans &trans &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AC_SEARCH &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LC(LG(SPACE)) &trans &trans &trans + &trans &trans &trans &trans &trans &trans &kp RCTRL &trans &kp HOME &kp PG_UP &kp PG_DN &kp END &trans &trans &trans + // + &none &none &none &none &none + >; + }; + //win + layer_two { + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp F13 &kp DEL &kp HOME &kp PG_UP &kp PG_DN + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp INT3 &kp BSPC &kp KP_NLCK &kp KP_SLASH &kp KP_ASTERISK &kp KP_MINUS + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NUHS &kp RET &kp KP_N4 &kp KP_N5 &kp KP_N6 + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp INT1 &kp RSHFT &kp KP_N1 &kp KP_N2 &kp KP_N3 + &kp LCTRL &kp LGUI &kp LALT &kp INT5 &kp SPACE &kp INT4 &kp RALT &mo 3 &kp LEFT &kp UP &kp DOWN &kp RIGHT &kp KP_N0 &kp KP_DOT &kp KP_ENTER + // + &none &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //win + layer_three { + bindings = < + //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 + &trans &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &uc LG(TAB) &uc LG(E) &kp C_AC_SEARCH &uc LG(L) &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &uc LG(I) &trans &trans &trans &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AL_CALC &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LG(DOT) &trans &trans &trans + &trans &trans &trans &trans &trans &trans &kp RCTRL &trans &kp HOME &kp PG_UP &kp PG_DN &kp END &trans &trans &trans + // + &none &none &none &none &none + >; + }; + + + + + }; +}; + + diff --git a/app/boards/shields/keychron/keychron_b2_jis.overlay b/app/boards/shields/keychron/keychron_b2_jis.overlay new file mode 100644 index 00000000000..64aa6c80055 --- /dev/null +++ b/app/boards/shields/keychron/keychron_b2_jis.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 Nick Winans + * + * SPDX-License-Identifier: MIT + */ + +#include + + +/ { + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <18>; + rows = <8>; + map = < + //esc //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //del //home //pgup //pgdn + RC(3,1) RC(6,2) RC(6,3) RC(1,3) RC(3,3) RC(7,0) RC(3,6) RC(1,7) RC(6,7) RC(6,10) RC(7,10) RC(3,10) RC(5,10) RC(3, 0) RC(6,11) RC(6,14) RC(6,13) RC(7,13) + //grave //1 //2 //3 //4 //5 //6 //7 //8 //9 //0 //- //+= //int3 //back //num // / //* // - + RC(6,1) RC(7,1) RC(7,2) RC(7,3) RC(7,4) RC(6,4) RC(6,5) RC(7,5) RC(7,6) RC(7,7) RC(7,8) RC(6,8) RC(6,6) RC(0,10) RC(1,10) RC(4,11) RC(4,12) RC(4,13) RC(5,13) + //tab //q //w //e //r // t //y //u //i //o //p //[ //] //kp 7 //kp8 //kp 9 //kp + + RC(1,1) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(1,4) RC(1,5) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(1,8) RC(1,6) RC(0,11) RC(0,12) RC(0,13) RC(0,14) + //cap //a //s //d //f //g //h //j //k //l // ; //' " //NUHS //enter //4 //5 //6 + RC(1,2) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(3,8) RC(4, 8) RC(4,10) RC(1,11) RC(1,12) RC(1,13) + //lshit //z //x //c //v //b //n //m //,< //.> //?/ //int1 //rshit //1 //2 //3 + RC(1,15) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(5,4) RC(5,5) RC(4,5) RC(4,6) RC(4,7) RC(5,8) RC(5,6) RC(2,15) RC(2,11) RC(2,12) RC(2,13) + //lctrl //win l //alt l //int5 //space //int4 //int2 //fn //left //up //down //right //0 //dot //kp enter + RC(6,0) RC(1,16) RC(3,9) RC(5,1) RC(3,11) RC(5,2) RC(5,9) RC(2,9) RC(5,14) RC(3,14) RC(5,11) RC(5,12) RC(3,12) RC(3,13) RC(2,14) + //m/w //bt //24g //ch //ch done + RC(8,0) RC(8,1) RC(8,2) RC(8,3) RC(8,4) + >; + }; + +}; + diff --git a/app/boards/shields/keychron/keychron_b2_kr.conf b/app/boards/shields/keychron/keychron_b2_kr.conf new file mode 100644 index 00000000000..88438b9b3b1 --- /dev/null +++ b/app/boards/shields/keychron/keychron_b2_kr.conf @@ -0,0 +1,14 @@ +CONFIG_USB_DEVICE_PRODUCT="Keychron B2 Pro" +CONFIG_BT_DIS_MODEL="Keychron B2 Pro" +CONFIG_ZMK_KEYBOARD_NAME="Keychron B2 Pro" + +CONFIG_USB_DEVICE_VID=0x3434 +CONFIG_USB_DEVICE_PID=0x0723 +CONFIG_BT_DIS_PNP_VID=0x3434 +CONFIG_BT_DIS_PNP_PID=0x0723 +CONFIG_BT_DIS_FW_REV_STR="v1.0.2" +CONFIG_BT_DIS_HW_REV_STR="v1.0.0" +CONFIG_BT_DIS_SERIAL_NUMBER_STR="SN2024071214230078" + +#uart debug +#CONFIG_ZMK_UART_LOGGING=y \ No newline at end of file diff --git a/app/boards/shields/keychron/keychron_b2_kr.keymap b/app/boards/shields/keychron/keychron_b2_kr.keymap new file mode 100644 index 00000000000..d3dbab76caf --- /dev/null +++ b/app/boards/shields/keychron/keychron_b2_kr.keymap @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +/ { + ZMK_MACRO(recover, bindings = <&out OUT_RECOVER>;) + ZMK_MACRO(change, bindings = <&out OUT_FN>;) + ZMK_MACRO(fn_win, bindings = <&out OUT_FN_WIN>;) + + ZMK_MACRO(en_bootloader, bindings = <&bootloader>;) + ZMK_MACRO1(MA,bindings=<&kp 0x770000>;) + + long_press_recover:l1 { + compatible = "zmk,behavior-hold-tap"; + label = "l1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&recover>, <&none>; + }; + + long_press_change:l2{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_change"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&change>, <&none>; + }; + long_press_bootloader:l3{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_bootloader"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&en_bootloader>, <&none>; + }; + long_press_fn_win:l4{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_fn_win"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; + bindings = <&fn_win>, <&none>; + }; + + + combos1 { + compatible = "zmk,combos"; + combo_jz { + timeout-ms = <1000>; + layers = <1 3>; + key-positions = <61 71>; //fn+j+z + bindings = <&long_press_recover 0 0>; + }; + combo_xl { + timeout-ms = <1000>; + layers =< 1 3>; + key-positions = <72 63>; //fn+x+l + bindings = <&long_press_change 0 0>; + }; + combo_b { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <75>; //fn+b + bindings = <&out OUT_BAT>; + }; + + combo_win_l { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <86>; //fn+win + bindings = <&long_press_fn_win 0 0>; + }; + + combo_t0 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 90>; + bindings = <&to 3 >; + }; + combo_t1 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 91>; + bindings = <&tog 3 >; + }; + combo_t2 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 92>; + bindings = <&sl 3 >; + }; + combo_t3 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <70 93>; + bindings = << 3 SPACE>; + }; + combo_t4 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 94>; + bindings = <&sk LSHIFT>; + }; + combo_t5 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&mt LSHIFT SPACE>; + }; + combo_t6 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&gresc>; + }; + }; + + td0 { + compatible = "zmk,behavior-tap-dance"; + label = "TAPD_LAYER"; + #binding-cells = <1>; + tapping-term-ms = <350>; + bindings =<&mo 0>,<&mo 0>,<&mo 0>,<&mo 0>,<&to 0>; + }; + ZMK_MACRO(bt_pair0, bindings = <&bt BT_PAIR 0>;) + ZMK_MACRO(bt_pair1, bindings = <&bt BT_PAIR 1>;) + ZMK_MACRO(bt_pair2, bindings = <&bt BT_PAIR 2>;) + ZMK_MACRO(bt_pair3, bindings = <&bt BT_PAIR 3>;) + ZMK_MACRO(bt_recon_0, bindings = <&bt BT_SEL 0>;) + ZMK_MACRO(bt_recon_1, bindings = <&bt BT_SEL 1>;) + ZMK_MACRO(bt_recon_2, bindings = <&bt BT_SEL 2>;) + ZMK_MACRO(bt_recon_3, bindings = <&bt BT_SEL 3>;) + + + + bt_pair_0: bt_pair_0 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair0"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair0>, <&bt_recon_0>; + }; + bt_pair_1: bt_pair_1 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair1>, <&bt_recon_1>; + }; + bt_pair_2: bt_pair_2 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair2"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair2>, <&bt_recon_2>; + }; + bt_pair_3: bt_pair_3 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair3"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair3>, <&bt_recon_3>; + }; + uc:user_custom { + compatible = "zmk,behavior-key-press"; + label ="user_custom"; + #binding-cells =<1>; + }; + + keymap { + compatible = "zmk,keymap"; + //mac + default_layer { + bindings = < + //ESC //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //del //home //pgup //pgdn + &kp ESC &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &kp C_AC_MAC_LAUNCH &kp C_AC_SEARCH &kp C_AL_LOCK &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &uc LG(COMMA) &kp C_AC_SEARCH &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &uc LC(LEFT) &uc LC(RIGHT) + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp KP_NLCK &kp KP_SLASH &kp KP_ASTERISK &kp KP_MINUS + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp KP_N4 &kp KP_N5 &kp KP_N6 + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp KP_N1 &kp KP_N2 &kp KP_N3 + &kp LCTRL &uc LALT &uc LCMD &kp SPACE &uc RCMD &mo 1 &kp LEFT &kp UP &kp DOWN &kp RIGHT &kp KP_N0 &kp KP_DOT &kp KP_ENTER + &mo 2 &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //mac + layer_one { + bindings = < + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans &trans &trans &trans &trans + &MA 0x770100 &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AC_SEARCH &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &uc LG(LS(N4)) &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LC(LG(SPACE)) &trans &trans &trans + &trans &trans &trans &trans &kp LANG2 &trans &kp HOME &kp PG_UP &kp PG_DN &kp END &trans &trans &trans + // + &none &none &none &none &none + >; + }; + //win + layer_two { + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp F13 &kp C_AL_CALC &uc LG(TAB) &uc LG(LC(LEFT)) &uc LG(LC(RIGHT)) + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp KP_NLCK &kp KP_SLASH &kp KP_ASTERISK &kp KP_MINUS + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp KP_N4 &kp KP_N5 &kp KP_N6 + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp KP_N1 &kp KP_N2 &kp KP_N3 + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp LANG1 &mo 3 &kp LEFT &kp UP &kp DOWN &kp RIGHT &kp KP_N0 &kp KP_DOT &kp KP_ENTER + // + &none &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //win + layer_three { + bindings = < + //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 + &trans &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &uc LG(TAB) &uc LG(E) &kp C_AC_SEARCH &uc LG(L) &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &uc LG(I) &trans &trans &trans &trans + &MA 0x770100 &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AL_CALC &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &uc LG(LS(S)) &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LG(DOT) &trans &trans &trans + &trans &trans &trans &trans &kp LANG2 &trans &kp HOME &kp PG_UP &kp PG_DN &kp END &trans &trans &trans + // + &none &none &none &none &none + >; + }; + + + + + }; +}; + + diff --git a/app/boards/shields/keychron/keychron_b2_kr.overlay b/app/boards/shields/keychron/keychron_b2_kr.overlay new file mode 100644 index 00000000000..031c649489f --- /dev/null +++ b/app/boards/shields/keychron/keychron_b2_kr.overlay @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 Nick Winans + * + * SPDX-License-Identifier: MIT + */ + + +#include + + +/ { + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <18>; + rows = <8>; + map = < + //esc //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //del //home //pgup //pgdn + RC(3,1) RC(6,2) RC(6,3) RC(1,3) RC(3,3) RC(7,0) RC(3,6) RC(1,7) RC(6,7) RC(6,10) RC(7,10) RC(3,10) RC(5,10) RC(3, 0) RC(6,11) RC(6,14) RC(6,13) RC(7,13) + //grave //1 //2 //3 //4 //5 //6 //7 //8 //9 //0 //- //+= //back //num // / //* // - + RC(6,1) RC(7,1) RC(7,2) RC(7,3) RC(7,4) RC(6,4) RC(6,5) RC(7,5) RC(7,6) RC(7,7) RC(7,8) RC(6,8) RC(6,6) RC(1,10) RC(4,11) RC(4,12) RC(4,13) RC(5,13) + //tab //q //w //e //r // t //y //u //i //o //p //[ //] //'\' //kp 7 //kp8 //kp 9 //kp + + RC(1,1) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(1,4) RC(1,5) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(1,8) RC(1,6) RC(2,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) + //cap //a //s //d //f //g //h //j //k //l // ; //' " //enter //4 //5 //6 + RC(1,2) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(3,8) RC(4,10) RC(1,11) RC(1,12) RC(1,13) + //lshit //z //x //c //v //b //n //m //,< //.> //?/ //rshit //1 //2 //3 + RC(1,15) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(5,4) RC(5,5) RC(4,5) RC(4,6) RC(4,7) RC(5,8) RC(2,15) RC(2,11) RC(2,12) RC(2,13) + //lctrl //win l //alt l //space //alt r //fn //left //up //down //right //0 //dot //kp enter + RC(6,0) RC(1,16) RC(3,9) RC(3,11) RC(5,9) RC(2,9) RC(5,14) RC(3,14) RC(5,11) RC(5,12) RC(3,12) RC(3,13) RC(2,14) + //m/w //bt //24g //ch //ch done + RC(8,0) RC(8,1) RC(8,2) RC(8,3) RC(8,4) + >; + }; + +}; + +//&uart0{ +// status="okay"; +//}; \ No newline at end of file diff --git a/app/boards/shields/keychron/keychron_b2_uk.conf b/app/boards/shields/keychron/keychron_b2_uk.conf new file mode 100644 index 00000000000..d298b262a71 --- /dev/null +++ b/app/boards/shields/keychron/keychron_b2_uk.conf @@ -0,0 +1,11 @@ +CONFIG_USB_DEVICE_PRODUCT="Keychron B2 Pro" +CONFIG_BT_DIS_MODEL="Keychron B2 Pro" +CONFIG_ZMK_KEYBOARD_NAME="Keychron B2 Pro" + +CONFIG_USB_DEVICE_VID=0x3434 +CONFIG_USB_DEVICE_PID=0x0721 +CONFIG_BT_DIS_PNP_VID=0x3434 +CONFIG_BT_DIS_PNP_PID=0x0721 +CONFIG_BT_DIS_FW_REV_STR="v1.0.2" +CONFIG_BT_DIS_HW_REV_STR="v1.0.0" +CONFIG_BT_DIS_SERIAL_NUMBER_STR="SN2024051614230078" \ No newline at end of file diff --git a/app/boards/shields/keychron/keychron_b2_uk.keymap b/app/boards/shields/keychron/keychron_b2_uk.keymap new file mode 100644 index 00000000000..2b234dbcbd6 --- /dev/null +++ b/app/boards/shields/keychron/keychron_b2_uk.keymap @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +/ { + ZMK_MACRO(recover, bindings = <&out OUT_RECOVER>;) + ZMK_MACRO(change, bindings = <&out OUT_FN>;) + ZMK_MACRO(fn_win, bindings = <&out OUT_FN_WIN>;) + + ZMK_MACRO(en_bootloader, bindings = <&bootloader>;) + ZMK_MACRO1(MA,bindings=<&kp 0x770000>;) + + long_press_recover:l1 { + compatible = "zmk,behavior-hold-tap"; + label = "l1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&recover>, <&none>; + }; + + long_press_change:l2{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_change"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&change>, <&none>; + }; + long_press_bootloader:l3{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_bootloader"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&en_bootloader>, <&none>; + }; + long_press_fn_win:l4{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_fn_win"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; + bindings = <&fn_win>, <&none>; + }; + + + combos1 { + compatible = "zmk,combos"; + combo_jz { + timeout-ms = <1000>; + layers = <1 3>; + key-positions = <60 72>; //fn+j+z + bindings = <&long_press_recover 0 0>; + }; + combo_xl { + timeout-ms = <1000>; + layers =< 1 3>; + key-positions = <73 62>; //fn+x+l + bindings = <&long_press_change 0 0>; + }; + combo_b { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <76>; //fn+b + bindings = <&out OUT_BAT>; + }; + + combo_win_l { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <87>; //fn+win + bindings = <&long_press_fn_win 0 0>; + }; + + combo_t0 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 90>; + bindings = <&to 3 >; + }; + combo_t1 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 91>; + bindings = <&tog 3 >; + }; + combo_t2 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 92>; + bindings = <&sl 3 >; + }; + combo_t3 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <70 93>; + bindings = << 3 SPACE>; + }; + combo_t4 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 94>; + bindings = <&sk LSHIFT>; + }; + combo_t5 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&mt LSHIFT SPACE>; + }; + combo_t6 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&gresc>; + }; + }; + + td0 { + compatible = "zmk,behavior-tap-dance"; + label = "TAPD_LAYER"; + #binding-cells = <1>; + tapping-term-ms = <350>; + bindings =<&mo 0>,<&mo 0>,<&mo 0>,<&mo 0>,<&to 0>; + }; + ZMK_MACRO(bt_pair0, bindings = <&bt BT_PAIR 0>;) + ZMK_MACRO(bt_pair1, bindings = <&bt BT_PAIR 1>;) + ZMK_MACRO(bt_pair2, bindings = <&bt BT_PAIR 2>;) + ZMK_MACRO(bt_pair3, bindings = <&bt BT_PAIR 3>;) + ZMK_MACRO(bt_recon_0, bindings = <&bt BT_SEL 0>;) + ZMK_MACRO(bt_recon_1, bindings = <&bt BT_SEL 1>;) + ZMK_MACRO(bt_recon_2, bindings = <&bt BT_SEL 2>;) + ZMK_MACRO(bt_recon_3, bindings = <&bt BT_SEL 3>;) + + + + bt_pair_0: bt_pair_0 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair0"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair0>, <&bt_recon_0>; + }; + bt_pair_1: bt_pair_1 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair1>, <&bt_recon_1>; + }; + bt_pair_2: bt_pair_2 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair2"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair2>, <&bt_recon_2>; + }; + bt_pair_3: bt_pair_3 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair3"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair3>, <&bt_recon_3>; + }; + uc:user_custom { + compatible = "zmk,behavior-key-press"; + label ="user_custom"; + #binding-cells =<1>; + }; + + keymap { + compatible = "zmk,keymap"; + //mac + default_layer { + bindings = < + //ESC //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //del //home //pgup //pgdn + &kp ESC &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &kp C_AC_MAC_LAUNCH &kp C_AC_SEARCH &kp C_AL_LOCK &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &uc LG(COMMA) &kp DEL &kp HOME &kp PG_UP &kp PG_DN + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp KP_NLCK &kp KP_SLASH &kp KP_ASTERISK &kp KP_MINUS + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NUHS &kp RET &kp KP_N4 &kp KP_N5 &kp KP_N6 + &kp LSHFT &kp NUBS &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp KP_N1 &kp KP_N2 &kp KP_N3 + &kp LCTRL &uc LALT &uc LCMD &kp SPACE &uc RCMD &mo 1 &kp LEFT &kp UP &kp DOWN &kp RIGHT &kp KP_N0 &kp KP_DOT &kp KP_ENTER + &mo 2 &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //mac + layer_one { + bindings = < + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp F13 &trans &trans &trans &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AC_SEARCH &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LC(LG(SPACE)) &trans &trans &trans + &trans &trans &trans &trans &kp RCTRL &trans &kp HOME &kp PG_UP &kp PG_DN &kp END &trans &trans &trans + // + &none &none &none &none &none + >; + }; + //win + layer_two { + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp F13 &kp DEL &kp HOME &kp PG_UP &kp PG_DN + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp KP_NLCK &kp KP_SLASH &kp KP_ASTERISK &kp KP_MINUS + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NUHS &kp RET &kp KP_N4 &kp KP_N5 &kp KP_N6 + &kp LSHFT &kp NUBS &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp KP_N1 &kp KP_N2 &kp KP_N3 + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 3 &kp LEFT &kp UP &kp DOWN &kp RIGHT &kp KP_N0 &kp KP_DOT &kp KP_ENTER + // + &none &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //win + layer_three { + bindings = < + //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 + &trans &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &uc LG(TAB) &uc LG(E) &kp C_AC_SEARCH &uc LG(L) &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &uc LG(I) &trans &trans &trans &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AL_CALC &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LG(DOT) &trans &trans &trans + &trans &trans &trans &trans &kp RCTRL &trans &kp HOME &kp PG_UP &kp PG_DN &kp END &trans &trans &trans + // + &none &none &none &none &none + >; + }; + + + + + }; +}; + + diff --git a/app/boards/shields/keychron/keychron_b2_uk.overlay b/app/boards/shields/keychron/keychron_b2_uk.overlay new file mode 100644 index 00000000000..23a92e2599a --- /dev/null +++ b/app/boards/shields/keychron/keychron_b2_uk.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 Nick Winans + * + * SPDX-License-Identifier: MIT + */ + +#include + + +/ { + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <18>; + rows = <8>; + map = < + //esc //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //del //home //pgup //pgdn + RC(3,1) RC(6,2) RC(6,3) RC(1,3) RC(3,3) RC(7,0) RC(3,6) RC(1,7) RC(6,7) RC(6,10) RC(7,10) RC(3,10) RC(5,10) RC(3, 0) RC(6,11) RC(6,14) RC(6,13) RC(7,13) + //grave //1 //2 //3 //4 //5 //6 //7 //8 //9 //0 //- //+= //back //num // / //* // - + RC(6,1) RC(7,1) RC(7,2) RC(7,3) RC(7,4) RC(6,4) RC(6,5) RC(7,5) RC(7,6) RC(7,7) RC(7,8) RC(6,8) RC(6,6) RC(1,10) RC(4,11) RC(4,12) RC(4,13) RC(5,13) + //tab //q //w //e //r // t //y //u //i //o //p //[ //] //kp 7 //kp8 //kp 9 //kp + + RC(1,1) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(1,4) RC(1,5) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(1,8) RC(1,6) RC(0,11) RC(0,12) RC(0,13) RC(0,14) + //cap //a //s //d //f //g //h //j //k //l // ; //' " //NUHS //enter //4 //5 //6 + RC(1,2) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(3,8) RC(4,8) RC(4,10) RC(1,11) RC(1,12) RC(1,13) + //lshit //NUBS //z //x //c //v //b //n //m //,< //.> //?/ //rshit //1 //2 //3 + RC(1,15) RC(3,2) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(5,4) RC(5,5) RC(4,5) RC(4,6) RC(4,7) RC(5,8) RC(2,15) RC(2,11) RC(2,12) RC(2,13) + //lctrl //win l //alt l //space //alt gr //fn //left //up //down //right //0 //dot //kp enter + RC(6,0) RC(1,16) RC(3,9) RC(3,11) RC(5,9) RC(2,9) RC(5,14) RC(3,14) RC(5,11) RC(5,12) RC(3,12) RC(3,13) RC(2,14) + //m/w //bt //24g //ch //ch done + RC(8,0) RC(8,1) RC(8,2) RC(8,3) RC(8,4) + >; + }; + +}; + diff --git a/app/boards/shields/keychron/keychron_b2_us.conf b/app/boards/shields/keychron/keychron_b2_us.conf new file mode 100644 index 00000000000..911658fdad2 --- /dev/null +++ b/app/boards/shields/keychron/keychron_b2_us.conf @@ -0,0 +1,14 @@ +CONFIG_USB_DEVICE_PRODUCT="Keychron B2 Pro" +CONFIG_BT_DIS_MODEL="Keychron B2 Pro" +CONFIG_ZMK_KEYBOARD_NAME="Keychron B2 Pro" + +CONFIG_USB_DEVICE_VID=0x3434 +CONFIG_USB_DEVICE_PID=0x0720 +CONFIG_BT_DIS_PNP_VID=0x3434 +CONFIG_BT_DIS_PNP_PID=0x0720 +CONFIG_BT_DIS_FW_REV_STR="v1.0.2" +CONFIG_BT_DIS_HW_REV_STR="v1.0.0" +CONFIG_BT_DIS_SERIAL_NUMBER_STR="SN2024051614230078" + +#uart debug +#CONFIG_ZMK_UART_LOGGING=y \ No newline at end of file diff --git a/app/boards/shields/keychron/keychron_b2_us.keymap b/app/boards/shields/keychron/keychron_b2_us.keymap new file mode 100644 index 00000000000..dfd28a5fbed --- /dev/null +++ b/app/boards/shields/keychron/keychron_b2_us.keymap @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +/ { + ZMK_MACRO(recover, bindings = <&out OUT_RECOVER>;) + ZMK_MACRO(change, bindings = <&out OUT_FN>;) + ZMK_MACRO(fn_win, bindings = <&out OUT_FN_WIN>;) + + ZMK_MACRO(en_bootloader, bindings = <&bootloader>;) + ZMK_MACRO1(MA,bindings=<&kp 0x770000>;) + + long_press_recover:l1 { + compatible = "zmk,behavior-hold-tap"; + label = "l1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&recover>, <&none>; + }; + + long_press_change:l2{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_change"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&change>, <&none>; + }; + long_press_bootloader:l3{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_bootloader"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&en_bootloader>, <&none>; + }; + long_press_fn_win:l4{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_fn_win"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; + bindings = <&fn_win>, <&none>; + }; + + + combos1 { + compatible = "zmk,combos"; + combo_jz { + timeout-ms = <1000>; + layers = <1 3>; + key-positions = <61 71>; //fn+j+z + bindings = <&long_press_recover 0 0>; + }; + combo_xl { + timeout-ms = <1000>; + layers =< 1 3>; + key-positions = <72 63>; //fn+x+l + bindings = <&long_press_change 0 0>; + }; + combo_b { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <75>; //fn+b + bindings = <&out OUT_BAT>; + }; + + combo_win_l { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <86>; //fn+win + bindings = <&long_press_fn_win 0 0>; + }; + + combo_t0 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 90>; + bindings = <&to 3 >; + }; + combo_t1 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 91>; + bindings = <&tog 3 >; + }; + combo_t2 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 92>; + bindings = <&sl 3 >; + }; + combo_t3 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <70 93>; + bindings = << 3 SPACE>; + }; + combo_t4 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 94>; + bindings = <&sk LSHIFT>; + }; + combo_t5 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&mt LSHIFT SPACE>; + }; + combo_t6 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&gresc>; + }; + }; + + td0 { + compatible = "zmk,behavior-tap-dance"; + label = "TAPD_LAYER"; + #binding-cells = <1>; + tapping-term-ms = <350>; + bindings =<&mo 0>,<&mo 0>,<&mo 0>,<&mo 0>,<&to 0>; + }; + ZMK_MACRO(bt_pair0, bindings = <&bt BT_PAIR 0>;) + ZMK_MACRO(bt_pair1, bindings = <&bt BT_PAIR 1>;) + ZMK_MACRO(bt_pair2, bindings = <&bt BT_PAIR 2>;) + ZMK_MACRO(bt_pair3, bindings = <&bt BT_PAIR 3>;) + ZMK_MACRO(bt_recon_0, bindings = <&bt BT_SEL 0>;) + ZMK_MACRO(bt_recon_1, bindings = <&bt BT_SEL 1>;) + ZMK_MACRO(bt_recon_2, bindings = <&bt BT_SEL 2>;) + ZMK_MACRO(bt_recon_3, bindings = <&bt BT_SEL 3>;) + + + + bt_pair_0: bt_pair_0 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair0"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair0>, <&bt_recon_0>; + }; + bt_pair_1: bt_pair_1 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair1>, <&bt_recon_1>; + }; + bt_pair_2: bt_pair_2 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair2"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair2>, <&bt_recon_2>; + }; + bt_pair_3: bt_pair_3 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair3"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair3>, <&bt_recon_3>; + }; + uc:user_custom { + compatible = "zmk,behavior-key-press"; + label ="user_custom"; + #binding-cells =<1>; + }; + + keymap { + compatible = "zmk,keymap"; + //mac + default_layer { + bindings = < + //ESC //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //del //home //pgup //pgdn + &kp ESC &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &kp C_AC_MAC_LAUNCH &kp C_AC_SEARCH &kp C_AL_LOCK &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &uc LG(COMMA) &kp DEL &kp HOME &kp PG_UP &kp PG_DN + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp KP_NLCK &kp KP_SLASH &kp KP_ASTERISK &kp KP_MINUS + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp KP_N4 &kp KP_N5 &kp KP_N6 + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp KP_N1 &kp KP_N2 &kp KP_N3 + &kp LCTRL &uc LALT &uc LCMD &kp SPACE &uc RCMD &mo 1 &kp LEFT &kp UP &kp DOWN &kp RIGHT &kp KP_N0 &kp KP_DOT &kp KP_ENTER + &mo 2 &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //mac + layer_one { + bindings = < + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans &trans &trans &trans &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AC_SEARCH &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &uc LG(LS(N4)) &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LC(LG(SPACE)) &trans &trans &trans + &trans &trans &trans &trans &kp RCTRL &trans &kp HOME &kp PG_UP &kp PG_DN &kp END &trans &trans &trans + // + &none &none &none &none &none + >; + }; + //win + layer_two { + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp F13 &kp DEL &kp HOME &kp PG_UP &kp PG_DN + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp KP_NLCK &kp KP_SLASH &kp KP_ASTERISK &kp KP_MINUS + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp KP_N4 &kp KP_N5 &kp KP_N6 + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp KP_N1 &kp KP_N2 &kp KP_N3 + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 3 &kp LEFT &kp UP &kp DOWN &kp RIGHT &kp KP_N0 &kp KP_DOT &kp KP_ENTER + // + &none &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //win + layer_three { + bindings = < + //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 + &trans &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &uc LG(TAB) &uc LG(E) &kp C_AC_SEARCH &uc LG(L) &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &uc LG(I) &trans &trans &trans &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AL_CALC &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &uc LG(LS(S)) &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LG(DOT) &trans &trans &trans + &trans &trans &trans &trans &kp RCTRL &trans &kp HOME &kp PG_UP &kp PG_DN &kp END &trans &trans &trans + // + &none &none &none &none &none + >; + }; + + + + + }; +}; + + diff --git a/app/boards/shields/keychron/keychron_b2_us.overlay b/app/boards/shields/keychron/keychron_b2_us.overlay new file mode 100644 index 00000000000..031c649489f --- /dev/null +++ b/app/boards/shields/keychron/keychron_b2_us.overlay @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 Nick Winans + * + * SPDX-License-Identifier: MIT + */ + + +#include + + +/ { + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <18>; + rows = <8>; + map = < + //esc //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //del //home //pgup //pgdn + RC(3,1) RC(6,2) RC(6,3) RC(1,3) RC(3,3) RC(7,0) RC(3,6) RC(1,7) RC(6,7) RC(6,10) RC(7,10) RC(3,10) RC(5,10) RC(3, 0) RC(6,11) RC(6,14) RC(6,13) RC(7,13) + //grave //1 //2 //3 //4 //5 //6 //7 //8 //9 //0 //- //+= //back //num // / //* // - + RC(6,1) RC(7,1) RC(7,2) RC(7,3) RC(7,4) RC(6,4) RC(6,5) RC(7,5) RC(7,6) RC(7,7) RC(7,8) RC(6,8) RC(6,6) RC(1,10) RC(4,11) RC(4,12) RC(4,13) RC(5,13) + //tab //q //w //e //r // t //y //u //i //o //p //[ //] //'\' //kp 7 //kp8 //kp 9 //kp + + RC(1,1) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(1,4) RC(1,5) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(1,8) RC(1,6) RC(2,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) + //cap //a //s //d //f //g //h //j //k //l // ; //' " //enter //4 //5 //6 + RC(1,2) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(3,8) RC(4,10) RC(1,11) RC(1,12) RC(1,13) + //lshit //z //x //c //v //b //n //m //,< //.> //?/ //rshit //1 //2 //3 + RC(1,15) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(5,4) RC(5,5) RC(4,5) RC(4,6) RC(4,7) RC(5,8) RC(2,15) RC(2,11) RC(2,12) RC(2,13) + //lctrl //win l //alt l //space //alt r //fn //left //up //down //right //0 //dot //kp enter + RC(6,0) RC(1,16) RC(3,9) RC(3,11) RC(5,9) RC(2,9) RC(5,14) RC(3,14) RC(5,11) RC(5,12) RC(3,12) RC(3,13) RC(2,14) + //m/w //bt //24g //ch //ch done + RC(8,0) RC(8,1) RC(8,2) RC(8,3) RC(8,4) + >; + }; + +}; + +//&uart0{ +// status="okay"; +//}; \ No newline at end of file diff --git a/app/boards/shields/keychron/keychron_b6_jis.conf b/app/boards/shields/keychron/keychron_b6_jis.conf new file mode 100644 index 00000000000..ef048dcb9d6 --- /dev/null +++ b/app/boards/shields/keychron/keychron_b6_jis.conf @@ -0,0 +1,7 @@ +CONFIG_USB_DEVICE_VID=0x3434 +CONFIG_USB_DEVICE_PID=0x0763 +CONFIG_BT_DIS_PNP_VID=0x3434 +CONFIG_BT_DIS_PNP_PID=0x0763 +CONFIG_BT_DIS_FW_REV_STR="v1.3.3" +CONFIG_BT_DIS_HW_REV_STR="v1.0.0" +CONFIG_BT_DIS_SERIAL_NUMBER_STR="SN2024041614230078" \ No newline at end of file diff --git a/app/boards/shields/keychron/keychron_b6_jis.keymap b/app/boards/shields/keychron/keychron_b6_jis.keymap new file mode 100644 index 00000000000..5b8b6b4231e --- /dev/null +++ b/app/boards/shields/keychron/keychron_b6_jis.keymap @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +// &main_encoder { +// status = "okay"; +// }; + +/ { + ZMK_MACRO(recover, bindings = <&out OUT_RECOVER>;) + ZMK_MACRO(change, bindings = <&out OUT_FN>;) + ZMK_MACRO(fn_win, bindings = <&out OUT_FN_WIN>;) + + ZMK_MACRO(en_bootloader, bindings = <&bootloader>;) + ZMK_MACRO1(MA,bindings=<&kp 0x770000>;) + + long_press_recover:l1 { + compatible = "zmk,behavior-hold-tap"; + label = "l1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&recover>, <&none>; + }; + + long_press_change:l2{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_change"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&change>, <&none>; + }; + long_press_bootloader:l3{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_bootloader"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&en_bootloader>, <&none>; + }; + long_press_fn_win:l4{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_fn_win"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; + bindings = <&fn_win>, <&none>; + }; + + //fn = 95+7 -1 + //j = 63+8 -1 + //z = 79+2 -1 + //x = 79+3 -1 + //l = 63+10 -1 + combos1 { + compatible = "zmk,combos"; + combo_jz { + timeout-ms = <1000>; + layers = <1 3>; + key-positions = <70 81>; //fn+j+z + bindings = <&long_press_recover 0 0>; + }; + combo_xl { + timeout-ms = <1000>; + layers =< 1 3>; + key-positions = <82 72>; //fn+x+l + bindings = <&long_press_change 0 0>; + }; + combo_b { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <85>; //fn+b + bindings = <&out OUT_BAT>; + }; + + combo_win_l { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <98>; //fn+win + bindings = <&long_press_fn_win 0 0>; + }; + combo_win_r { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <106>; //fn+win + bindings = <&long_press_fn_win 0 0>; + }; + combo_t0 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 90>; + bindings = <&to 3 >; + }; + combo_t1 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 91>; + bindings = <&tog 3 >; + }; + combo_t2 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 92>; + bindings = <&sl 3 >; + }; + combo_t3 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <70 93>; + bindings = << 3 SPACE>; + }; + combo_t4 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 94>; + bindings = <&sk LSHIFT>; + }; + combo_t5 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&mt LSHIFT SPACE>; + }; + combo_t6 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&gresc>; + }; + }; + + td0 { + compatible = "zmk,behavior-tap-dance"; + label = "TAPD_LAYER"; + #binding-cells = <1>; + tapping-term-ms = <350>; + bindings =<&mo 0>,<&mo 0>,<&mo 0>,<&mo 0>,<&to 0>; + }; + ZMK_MACRO(bt_pair0, bindings = <&bt BT_PAIR 0>;) + ZMK_MACRO(bt_pair1, bindings = <&bt BT_PAIR 1>;) + ZMK_MACRO(bt_pair2, bindings = <&bt BT_PAIR 2>;) + ZMK_MACRO(bt_pair3, bindings = <&bt BT_PAIR 3>;) + ZMK_MACRO(bt_recon_0, bindings = <&bt BT_SEL 0>;) + ZMK_MACRO(bt_recon_1, bindings = <&bt BT_SEL 1>;) + ZMK_MACRO(bt_recon_2, bindings = <&bt BT_SEL 2>;) + ZMK_MACRO(bt_recon_3, bindings = <&bt BT_SEL 3>;) + + + // hold-tap that doesn't do anything on tap and BT_CLR on hold + bt_pair_0: bt_pair_0 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair0"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair0>, <&bt_recon_0>; + }; + bt_pair_1: bt_pair_1 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair1>, <&bt_recon_1>; + }; + bt_pair_2: bt_pair_2 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair2"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair2>, <&bt_recon_2>; + }; + bt_pair_3: bt_pair_3 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair3"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair3>, <&bt_recon_3>; + }; + uc:user_custom { + compatible = "zmk,behavior-key-press"; + label ="user_custom"; + #binding-cells =<1>; + }; + keymap { + compatible = "zmk,keymap"; + //mac + default_layer { + bindings = < + //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //f14 //f15 //f16 //f17 + &kp ESC &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &kp C_AC_MAC_LAUNCH &kp C_AC_SEARCH &kp C_AL_LOCK &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &uc LG(COMMA) &uc LG(LS(N4)) &none &none &kp C_AC_SEARCH &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &uc LC(LEFT) &uc LC(RIGHT) + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp INT3 &kp BSPC &kp INS &kp HOME &kp PG_UP &kp KP_NLCK &kp KP_SLASH &kp KP_ASTERISK &kp KP_MINUS + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp DEL &kp END &kp PG_DN &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NUHS &kp RET &kp KP_N4 &kp KP_N5 &kp KP_N6 + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp INT1 &kp RSHFT &kp UP &kp KP_N1 &kp KP_N2 &kp KP_N3 + &kp LCTRL &uc LALT &uc LCMD &kp LANG2 &kp SPACE &kp LANG1 &uc RCMD &mo 1 &uc RALT &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT &kp KP_N0 &kp KP_DOT &kp KP_ENTER + // + &mo 2 &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //mac + layer_one { + bindings = < + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp F13 &trans &trans &trans &trans &trans &trans &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AC_SEARCH &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LC(LG(SPACE)) &kp PG_UP &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp HOME &kp PG_DN &kp END &trans &trans &trans + // + &none &none &none &none &none + >; + }; + //win + layer_two { + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp F13 &kp PSCRN &kp SLCK &kp PAUS &kp C_AL_CALC &uc LG(TAB) &uc LG(LC(LEFT)) &uc LG(LC(RIGHT)) //21 + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp INT3 &kp BSPC &kp INS &kp HOME &kp PG_UP &kp KP_NLCK &kp KP_SLASH &kp KP_ASTERISK &kp KP_MINUS //42 + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp DEL &kp END &kp PG_DN &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS //63 + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NUHS &kp RET &kp KP_N4 &kp KP_N5 &kp KP_N6 //63+21-5 + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp INT1 &kp RSHFT &kp UP &kp KP_N1 &kp KP_N2 &kp KP_N3 //79+21-5 + &kp LCTRL &kp LGUI &kp LALT &kp INT5 &kp SPACE &kp INT4 &kp RALT &mo 3 &kp RGUI &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT &kp KP_N0 &kp KP_DOT &kp KP_ENTER + // + &none &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //win + layer_three { + bindings = < + //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //f14 //f15 //f16 //f17 + &trans &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &uc LG(TAB) &uc LG(E) &kp C_AC_SEARCH &uc LG(L) &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &uc LG(I) &trans &trans &trans &trans &trans &trans &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AL_CALC &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LG(DOT) &kp PG_UP &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp HOME &kp PG_DN &kp END &trans &trans &trans + // + &none &none &none &none &none + >; + }; + + + + + }; +}; + + diff --git a/app/boards/shields/keychron/keychron_b6_jis.overlay b/app/boards/shields/keychron/keychron_b6_jis.overlay new file mode 100644 index 00000000000..81dcf191550 --- /dev/null +++ b/app/boards/shields/keychron/keychron_b6_jis.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 Nick Winans + * + * SPDX-License-Identifier: MIT + */ + +#include + + +/ { + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <18>; + rows = <8>; + map = < + //esc //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //print //scr //pause + RC(3,1) RC(6,2) RC(6,3) RC(1,3) RC(3,3) RC(7,0) RC(3,6) RC(1,7) RC(6,7) RC(6,10) RC(7,10) RC(3,10) RC(5,10) RC(5,17) RC(7,9) RC(0,9) RC(0,0) RC(7,16) RC(4,16) RC(2,16) RC(5,16) + //grave //1 //2 //3 //4 //5 //6 //7 //8 //9 //0 //- //+= //int3 //back //ins //home //pg up //num // / //* // - + RC(6,1) RC(7,1) RC(7,2) RC(7,3) RC(7,4) RC(6,4) RC(6,5) RC(7,5) RC(7,6) RC(7,7) RC(7,8) RC(6,8) RC(6,6) RC(0,10) RC(1,10) RC(6,12) RC(6,14) RC(6,13) RC(4,11) RC(4,12) RC(4,13) RC(5,13) + //tab //q //w //e //r // t //y //u //i //o //p //[ //] //del //end //pg dn //kp 7 //kp8 //kp 9 //kp + + RC(1,1) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(1,4) RC(1,5) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(1,8) RC(1,6) RC(6,11) RC(7,14) RC(7,13) RC(0,11) RC(0,12) RC(0,13) RC(0,14) + //cap //a //s //d //f //g //h //j //k //l // ; //' " //NUHS //enter //4 //5 //6 + RC(1,2) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(3,8) RC(4, 8) RC(4,10) RC(1,11) RC(1,12) RC(1,13) + //lshit //z //x //c //v //b //n //m //,< //.> //?/ //int1 //rshit //up //1 //2 //3 + RC(1,15) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(5,4) RC(5,5) RC(4,5) RC(4,6) RC(4,7) RC(5,8) RC(5,6) RC(2,15) RC(3,14) RC(2,11) RC(2,12) RC(2,13) + //lctrl //win l //alt l //int5/lan2 //space //int4/lan1 //alt r //fn //win r //ctrl r //left //down //right //0 //dot //kp enter + RC(6,0) RC(1,16) RC(3,9) RC(5,1) RC(3,11) RC(5,2) RC(5,9) RC(2,9) RC(2,17) RC(4,0) RC(5,14) RC(5,11) RC(5,12) RC(3,12) RC(3,13) RC(2,14) + //m/w //bt //24g //ch //ch done + RC(8,0) RC(8,1) RC(8,2) RC(8,3) RC(8,4) + >; + }; + + +}; + diff --git a/app/boards/shields/keychron/keychron_b6_uk.conf b/app/boards/shields/keychron/keychron_b6_uk.conf new file mode 100644 index 00000000000..c1f61841b8e --- /dev/null +++ b/app/boards/shields/keychron/keychron_b6_uk.conf @@ -0,0 +1,7 @@ +CONFIG_USB_DEVICE_VID=0x3434 +CONFIG_USB_DEVICE_PID=0x0762 +CONFIG_BT_DIS_PNP_VID=0x3434 +CONFIG_BT_DIS_PNP_PID=0x0762 +CONFIG_BT_DIS_FW_REV_STR="v1.3.3" +CONFIG_BT_DIS_HW_REV_STR="v1.0.0" +CONFIG_BT_DIS_SERIAL_NUMBER_STR="SN2024040914230078" \ No newline at end of file diff --git a/app/boards/shields/keychron/keychron_b6_uk.keymap b/app/boards/shields/keychron/keychron_b6_uk.keymap new file mode 100644 index 00000000000..0646f763f2f --- /dev/null +++ b/app/boards/shields/keychron/keychron_b6_uk.keymap @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + + +#include +#include +#include +#include +#include + +/ { + ZMK_MACRO(recover, bindings = <&out OUT_RECOVER>;) + ZMK_MACRO(change, bindings = <&out OUT_FN>;) + ZMK_MACRO(fn_win, bindings = <&out OUT_FN_WIN>;) + + ZMK_MACRO(en_bootloader, bindings = <&bootloader>;) + ZMK_MACRO1(MA,bindings=<&kp 0x770000>;) + + long_press_recover:l1 { + compatible = "zmk,behavior-hold-tap"; + label = "l1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&recover>, <&none>; + }; + + long_press_change:l2{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_change"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&change>, <&none>; + }; + long_press_bootloader:l3{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_bootloader"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&en_bootloader>, <&none>; + }; + long_press_fn_win:l4{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_fn_win"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; + bindings = <&fn_win>, <&none>; + }; + + //fn = 95+7 -1 + //j = 63+8 -1 + //z = 79+2 -1 + //x = 79+3 -1 + //l = 63+10 -1 + combos1 { + compatible = "zmk,combos"; + combo_jz { + timeout-ms = <1000>; + layers = <1 3>; + key-positions = <69 81>; //fn+j+z + bindings = <&long_press_recover 0 0>; + }; + combo_xl { + timeout-ms = <1000>; + layers =< 1 3>; + key-positions = <82 71>; //fn+x+l + bindings = <&long_press_change 0 0>; + }; + combo_b { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <85>; //fn+b + bindings = <&out OUT_BAT>; + }; + + combo_win_l { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <97>; //fn+win + bindings = <&long_press_fn_win 0 0>; + }; + combo_win_r { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <101>; //fn+win + bindings = <&long_press_fn_win 0 0>; + }; + combo_t0 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 90>; + bindings = <&to 3 >; + }; + combo_t1 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 91>; + bindings = <&tog 3 >; + }; + combo_t2 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 92>; + bindings = <&sl 3 >; + }; + combo_t3 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <70 93>; + bindings = << 3 SPACE>; + }; + combo_t4 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 94>; + bindings = <&sk LSHIFT>; + }; + combo_t5 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&mt LSHIFT SPACE>; + }; + combo_t6 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&gresc>; + }; + }; + + td0 { + compatible = "zmk,behavior-tap-dance"; + label = "TAPD_LAYER"; + #binding-cells = <1>; + tapping-term-ms = <350>; + bindings =<&mo 0>,<&mo 0>,<&mo 0>,<&mo 0>,<&to 0>; + }; + ZMK_MACRO(bt_pair0, bindings = <&bt BT_PAIR 0>;) + ZMK_MACRO(bt_pair1, bindings = <&bt BT_PAIR 1>;) + ZMK_MACRO(bt_pair2, bindings = <&bt BT_PAIR 2>;) + ZMK_MACRO(bt_pair3, bindings = <&bt BT_PAIR 3>;) + ZMK_MACRO(bt_recon_0, bindings = <&bt BT_SEL 0>;) + ZMK_MACRO(bt_recon_1, bindings = <&bt BT_SEL 1>;) + ZMK_MACRO(bt_recon_2, bindings = <&bt BT_SEL 2>;) + ZMK_MACRO(bt_recon_3, bindings = <&bt BT_SEL 3>;) + + + // hold-tap that doesn't do anything on tap and BT_CLR on hold + bt_pair_0: bt_pair_0 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair0"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair0>, <&bt_recon_0>; + }; + bt_pair_1: bt_pair_1 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair1>, <&bt_recon_1>; + }; + bt_pair_2: bt_pair_2 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair2"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair2>, <&bt_recon_2>; + }; + bt_pair_3: bt_pair_3 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair3"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair3>, <&bt_recon_3>; + }; + uc:user_custom { + compatible = "zmk,behavior-key-press"; + label ="user_custom"; + #binding-cells =<1>; + }; + keymap { + compatible = "zmk,keymap"; + //mac + default_layer { + bindings = < + //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //f14 //f15 //f16 //f17 + &kp ESC &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &kp C_AC_MAC_LAUNCH &kp C_AC_SEARCH &kp C_AL_LOCK &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &uc LG(COMMA) &uc LG(LS(N4)) &none &none &kp C_AC_SEARCH &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &uc LC(LEFT) &uc LC(RIGHT) + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp INS &kp HOME &kp PG_UP &kp KP_NLCK &kp KP_SLASH &kp KP_ASTERISK &kp KP_MINUS + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp DEL &kp END &kp PG_DN &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NUHS &kp RET &kp KP_N4 &kp KP_N5 &kp KP_N6 + &kp LSHFT &kp NUBS &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp KP_N1 &kp KP_N2 &kp KP_N3 + &kp LCTRL &uc LALT &uc LCMD &kp SPACE &uc RCMD &uc RALT &mo 1 &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT &kp KP_N0 &kp KP_DOT &kp KP_ENTER + // + &mo 2 &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //mac + layer_one { + bindings = < + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp F13 &trans &trans &trans &trans &trans &trans &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AC_SEARCH &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LC(LG(SPACE)) &kp PG_UP &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp HOME &kp PG_DN &kp END &trans &trans &trans + // + &none &none &none &none &none + >; + }; + //win + layer_two { + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp F13 &kp PSCRN &kp SLCK &kp PAUS &kp C_AL_CALC &uc LG(TAB) &uc LG(LC(LEFT)) &uc LG(LC(RIGHT)) //21 + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp INS &kp HOME &kp PG_UP &kp KP_NLCK &kp KP_SLASH &kp KP_ASTERISK &kp KP_MINUS //42 + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp DEL &kp END &kp PG_DN &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS //63 + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NUHS &kp RET &kp KP_N4 &kp KP_N5 &kp KP_N6 //63+21-5 + &kp LSHFT &kp NUBS &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp KP_N1 &kp KP_N2 &kp KP_N3 //79+21-5 + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &kp RGUI &mo 3 &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT &kp KP_N0 &kp KP_DOT &kp KP_ENTER + // + &none &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //win + layer_three { + bindings = < + //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //f14 //f15 //f16 //f17 + &trans &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &uc LG(TAB) &uc LG(E) &kp C_AC_SEARCH &uc LG(L) &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &uc LG(I) &trans &trans &trans &trans &trans &trans &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AL_CALC &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LG(DOT) &kp PG_UP &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp HOME &kp PG_DN &kp END &trans &trans &trans + // + &none &none &none &none &none + >; + }; + + + + + }; +}; + + diff --git a/app/boards/shields/keychron/keychron_b6_uk.overlay b/app/boards/shields/keychron/keychron_b6_uk.overlay new file mode 100644 index 00000000000..9f696b6d055 --- /dev/null +++ b/app/boards/shields/keychron/keychron_b6_uk.overlay @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 Nick Winans + * + * SPDX-License-Identifier: MIT + */ + + + +#include + + +/ { + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <18>; + rows = <8>; + map = < + //esc //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //print //scr //pause + RC(3,1) RC(6,2) RC(6,3) RC(1,3) RC(3,3) RC(7,0) RC(3,6) RC(1,7) RC(6,7) RC(6,10) RC(7,10) RC(3,10) RC(5,10) RC(5,17) RC(7,9) RC(0,9) RC(0,0) RC(7,16) RC(4,16) RC(2,16) RC(5,16) + //grave //1 //2 //3 //4 //5 //6 //7 //8 //9 //0 //- //+= //back //ins //home //pg up //num // / //* // - + RC(6,1) RC(7,1) RC(7,2) RC(7,3) RC(7,4) RC(6,4) RC(6,5) RC(7,5) RC(7,6) RC(7,7) RC(7,8) RC(6,8) RC(6,6) RC(1,10) RC(6,12) RC(6,14) RC(6,13) RC(4,11) RC(4,12) RC(4,13) RC(5,13) + //tab //q //w //e //r // t //y //u //i //o //p //[ //] //del //end //pg dn //kp 7 //kp8 //kp 9 //kp + + RC(1,1) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(1,4) RC(1,5) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(1,8) RC(1,6) RC(6,11) RC(7,14) RC(7,13) RC(0,11) RC(0,12) RC(0,13) RC(0,14) + //cap //a //s //d //f //g //h //j //k //l // ; //' " //NUHS //enter //4 //5 //6 + RC(1,2) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(3,8) RC(2,10) RC(4,10) RC(1,11) RC(1,12) RC(1,13) + //lshit //NUBS //z //x //c //v //b //n //m //,< //.> //?/ //rshit //up //1 //2 //3 + RC(1,15) RC(3,2) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(5,4) RC(5,5) RC(4,5) RC(4,6) RC(4,7) RC(5,8) RC(2,15) RC(3,14) RC(2,11) RC(2,12) RC(2,13) + //lctrl //win l //alt l //space //alt r //win r //fn //ctrl r //left //down //right //0 //dot //kp enter + RC(6,0) RC(1,16) RC(3,9) RC(3,11) RC(5,9) RC(2,9) RC(5,7) RC(4,0) RC(5,14) RC(5,11) RC(5,12) RC(3,12) RC(3,13) RC(2,14) + //m/w //bt //24g //ch //ch done + RC(8,0) RC(8,1) RC(8,2) RC(8,3) RC(8,4) + >; + }; +}; + + \ No newline at end of file diff --git a/app/boards/shields/keychron/keychron_b6_us.conf b/app/boards/shields/keychron/keychron_b6_us.conf new file mode 100644 index 00000000000..1b23d1c66f2 --- /dev/null +++ b/app/boards/shields/keychron/keychron_b6_us.conf @@ -0,0 +1,7 @@ +CONFIG_USB_DEVICE_VID=0x3434 +CONFIG_USB_DEVICE_PID=0x0761 +CONFIG_BT_DIS_PNP_VID=0x3434 +CONFIG_BT_DIS_PNP_PID=0x0761 +CONFIG_BT_DIS_FW_REV_STR="v1.3.3" +CONFIG_BT_DIS_HW_REV_STR="v1.0.0" +CONFIG_BT_DIS_SERIAL_NUMBER_STR="SN2024013114230078" \ No newline at end of file diff --git a/app/boards/shields/keychron/keychron_b6_us.keymap b/app/boards/shields/keychron/keychron_b6_us.keymap new file mode 100644 index 00000000000..fbb7be638ae --- /dev/null +++ b/app/boards/shields/keychron/keychron_b6_us.keymap @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +// &main_encoder { +// status = "okay"; +// }; + +/ { + ZMK_MACRO(recover, bindings = <&out OUT_RECOVER>;) + ZMK_MACRO(change, bindings = <&out OUT_FN>;) + ZMK_MACRO(fn_win, bindings = <&out OUT_FN_WIN>;) + + ZMK_MACRO(en_bootloader, bindings = <&bootloader>;) + ZMK_MACRO1(MA,bindings=<&kp 0x770000>;) + + long_press_recover:l1 { + compatible = "zmk,behavior-hold-tap"; + label = "l1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&recover>, <&none>; + }; + + long_press_change:l2{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_change"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&change>, <&none>; + }; + long_press_bootloader:l3{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_bootloader"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&en_bootloader>, <&none>; + }; + long_press_fn_win:l4{ + compatible = "zmk,behavior-hold-tap"; + label = "lp_fn_win"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; + bindings = <&fn_win>, <&none>; + }; + + //fn = 95+7 -1 + //j = 63+8 -1 + //z = 79+2 -1 + //x = 79+3 -1 + //l = 63+10 -1 + combos1 { + compatible = "zmk,combos"; + combo_jz { + timeout-ms = <1000>; + layers = <1 3>; + key-positions = <70 80>; //fn+j+z + bindings = <&long_press_recover 0 0>; + }; + combo_xl { + timeout-ms = <1000>; + layers =< 1 3>; + key-positions = <81 72>; //fn+x+l + bindings = <&long_press_change 0 0>; + }; + combo_b { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <84>; //fn+b + bindings = <&out OUT_BAT>; + }; + + combo_win_l { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <96>; //fn+win + bindings = <&long_press_fn_win 0 0>; + }; + combo_win_r { + timeout-ms = <1000>; + layers =< 1 3>; + //slow-release = ; + key-positions = <100>; //fn+win + bindings = <&long_press_fn_win 0 0>; + }; + combo_t0 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 90>; + bindings = <&to 3 >; + }; + combo_t1 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 91>; + bindings = <&tog 3 >; + }; + combo_t2 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <80 92>; + bindings = <&sl 3 >; + }; + combo_t3 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <70 93>; + bindings = << 3 SPACE>; + }; + combo_t4 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 94>; + bindings = <&sk LSHIFT>; + }; + combo_t5 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&mt LSHIFT SPACE>; + }; + combo_t6 { + timeout-ms = <10 >; + layers =<4>; + + key-positions = <81 93>; + bindings = <&gresc>; + }; + }; + + td0 { + compatible = "zmk,behavior-tap-dance"; + label = "TAPD_LAYER"; + #binding-cells = <1>; + tapping-term-ms = <350>; + bindings =<&mo 0>,<&mo 0>,<&mo 0>,<&mo 0>,<&to 0>; + }; + ZMK_MACRO(bt_pair0, bindings = <&bt BT_PAIR 0>;) + ZMK_MACRO(bt_pair1, bindings = <&bt BT_PAIR 1>;) + ZMK_MACRO(bt_pair2, bindings = <&bt BT_PAIR 2>;) + ZMK_MACRO(bt_pair3, bindings = <&bt BT_PAIR 3>;) + ZMK_MACRO(bt_recon_0, bindings = <&bt BT_SEL 0>;) + ZMK_MACRO(bt_recon_1, bindings = <&bt BT_SEL 1>;) + ZMK_MACRO(bt_recon_2, bindings = <&bt BT_SEL 2>;) + ZMK_MACRO(bt_recon_3, bindings = <&bt BT_SEL 3>;) + + + // hold-tap that doesn't do anything on tap and BT_CLR on hold + bt_pair_0: bt_pair_0 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair0"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair0>, <&bt_recon_0>; + }; + bt_pair_1: bt_pair_1 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair1"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair1>, <&bt_recon_1>; + }; + bt_pair_2: bt_pair_2 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair2"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair2>, <&bt_recon_2>; + }; + bt_pair_3: bt_pair_3 { + compatible = "zmk,behavior-hold-tap"; + label = "bt_pair3"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <3000>; // delay amount in ms + bindings = <&bt_pair3>, <&bt_recon_3>; + }; + uc:user_custom { + compatible = "zmk,behavior-key-press"; + label ="user_custom"; + #binding-cells =<1>; + }; + keymap { + compatible = "zmk,keymap"; + //mac + default_layer { + bindings = < + //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //f14 //f15 //f16 //f17 + &kp ESC &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &kp C_AC_MAC_LAUNCH &kp C_AC_SEARCH &kp C_AL_LOCK &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &uc LG(COMMA) &uc LG(LS(N4)) &none &none &kp C_AC_SEARCH &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &uc LC(LEFT) &uc LC(RIGHT) + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp INS &kp HOME &kp PG_UP &kp KP_NLCK &kp KP_SLASH &kp KP_ASTERISK &kp KP_MINUS + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp DEL &kp END &kp PG_DN &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp KP_N4 &kp KP_N5 &kp KP_N6 + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp KP_N1 &kp KP_N2 &kp KP_N3 + &kp LCTRL &uc LALT &uc LCMD &kp SPACE &uc RCMD &uc RALT &mo 1 &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT &kp KP_N0 &kp KP_DOT &kp KP_ENTER + // + &mo 2 &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //mac + layer_one { + bindings = < + &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp F13 &trans &trans &trans &trans &trans &trans &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AC_SEARCH &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &uc LG(LS(N4)) &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LC(LG(SPACE)) &kp PG_UP &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp HOME &kp PG_DN &kp END &trans &trans &trans + &none &none &none &none &none + >; + }; + //win + layer_two { + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp F13 &kp PSCRN &kp SLCK &kp PAUS &kp C_AL_CALC &uc LG(TAB) &uc LG(LC(LEFT)) &uc LG(LC(RIGHT)) //21 + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp INS &kp HOME &kp PG_UP &kp KP_NLCK &kp KP_SLASH &kp KP_ASTERISK &kp KP_MINUS //42 + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp DEL &kp END &kp PG_DN &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_PLUS //63 + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp KP_N4 &kp KP_N5 &kp KP_N6 //63+21-5 + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp KP_N1 &kp KP_N2 &kp KP_N3 //79+21-5 + &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &kp RGUI &mo 3 &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT &kp KP_N0 &kp KP_DOT &kp KP_ENTER + // + &none &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD + >; + }; + //win + layer_three { + bindings = < + //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f14 //f15 //f16 //f17 + &trans &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &uc LG(TAB) &uc LG(E) &kp C_AC_SEARCH &uc LG(L) &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &uc LG(I) &trans &trans &trans &trans &trans &trans &trans + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AL_CALC &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &uc LG(LS(S)) &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LG(DOT) &kp PG_UP &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &kp HOME &kp PG_DN &kp END &trans &trans &trans + &none &none &none &none &none + >; + }; + + + + + }; +}; + + diff --git a/app/boards/shields/keychron/keychron_b6_us.overlay b/app/boards/shields/keychron/keychron_b6_us.overlay new file mode 100644 index 00000000000..92e54e3a6fe --- /dev/null +++ b/app/boards/shields/keychron/keychron_b6_us.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 Nick Winans + * + * SPDX-License-Identifier: MIT + */ + +#include + + +/ { + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <18>; + rows = <8>; + map = < + //esc //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //f13 //print //scr //pause + RC(3,1) RC(6,2) RC(6,3) RC(1,3) RC(3,3) RC(7,0) RC(3,6) RC(1,7) RC(6,7) RC(6,10) RC(7,10) RC(3,10) RC(5,10) RC(5,17) RC(7,9) RC(0,9) RC(0,0) RC(7,16) RC(4,16) RC(2,16) RC(5,16) + //grave //1 //2 //3 //4 //5 //6 //7 //8 //9 //0 //- //+= //back //ins //home //pg up //num // / //* // - + RC(6,1) RC(7,1) RC(7,2) RC(7,3) RC(7,4) RC(6,4) RC(6,5) RC(7,5) RC(7,6) RC(7,7) RC(7,8) RC(6,8) RC(6,6) RC(1,10) RC(6,12) RC(6,14) RC(6,13) RC(4,11) RC(4,12) RC(4,13) RC(5,13) + //tab //q //w //e //r // t //y //u //i //o //p //[ //] //\ //del //end //pg dn //kp 7 //kp8 //kp 9 //kp + + RC(1,1) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(1,4) RC(1,5) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(1,8) RC(1,6) RC(2,10) RC(6,11) RC(7,14) RC(7,13) RC(0,11) RC(0,12) RC(0,13) RC(0,14) + //cap //a //s //d //f //g //h //j //k //l // ; //' " //enter //4 //5 //6 + RC(1,2) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(3,8) RC(4,10) RC(1,11) RC(1,12) RC(1,13) + //lshit //z //x //c //v //b //n //m //,< //.> //?/ //rshit //up //1 //2 //3 + RC(1,15) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(5,4) RC(5,5) RC(4,5) RC(4,6) RC(4,7) RC(5,8) RC(2,15) RC(3,14) RC(2,11) RC(2,12) RC(2,13) + //lctrl //win l //alt l //space //alt r //win r //fn //ctrl r //left //down //right //0 //dot //kp enter + RC(6,0) RC(1,16) RC(3,9) RC(3,11) RC(5,9) RC(2,9) RC(5,7) RC(4,0) RC(5,14) RC(5,11) RC(5,12) RC(3,12) RC(3,13) RC(2,14) + //m/w //bt //24g //ch //ch done + RC(8,0) RC(8,1) RC(8,2) RC(8,3) RC(8,4) + >; + }; + +}; + diff --git a/app/boards/shields/keychron/keychron_rgb.conf b/app/boards/shields/keychron/keychron_rgb.conf new file mode 100644 index 00000000000..e0a71176ce7 --- /dev/null +++ b/app/boards/shields/keychron/keychron_rgb.conf @@ -0,0 +1,20 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Uncomment to enable Encoders +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y +#CONFIG_NEWLIB_LIBC=y +CONFIG_MINIMAL_LIBC_RAND=y +CONFIG_I2C=y +CONFIG_LED_STRIP=y +CONFIG_CKLED2001=y + +#log +CONFIG_ZMK_RTT_LOGGING=y +#CONFIG_ZMK_USB_LOGGING=y +CONFIG_GPIO_AS_PINRESET=y + +#CONFIG_USB_DEVICE_SOF=n +#CONFIG_ZMK_LOW_PRIORITY_THREAD_STACK_SIZE=1024 + diff --git a/app/boards/shields/keychron/keychron_rgb.keymap b/app/boards/shields/keychron/keychron_rgb.keymap new file mode 100644 index 00000000000..24651b68e0d --- /dev/null +++ b/app/boards/shields/keychron/keychron_rgb.keymap @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +/ { + keymap { + compatible = "zmk,keymap"; + default_layer { + bindings = < + &kp K_MUTE &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 + &kp PG_UP &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 + &kp PG_DN &kp TAB &kp Q &kp W &kp E &kp R &kp T &none + &kp HOME &kp CLCK &kp A &kp S &kp D &kp F &kp G &none + &kp END &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &none + &kp INS &kp LCTRL &kp LALT &kp LGUI &mo 1 &kp SPACE &none &none + >; + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + one { + bindings = < + &rgb_ug RGB_TOG &rgb_ug RGB_HUI &rgb_ug RGB_HUD &trans &trans &trans &trans &trans + &rgb_ug RGB_EFF &rgb_ug RGB_BRI &rgb_ug RGB_SPI &trans &trans &trans &trans &trans + &rgb_ug RGB_EFR &rgb_ug RGB_BRD &rgb_ug RGB_SPD &trans &trans &trans &trans &none + &rgb_ug RGB_BRD &trans &trans &trans &trans &trans &trans &none + &bootloader &trans &trans &trans &trans &trans &trans &none + &out OUT_BLE &trans &trans &trans &trans &trans &none &none + >; + }; + two { + bindings = < + &kp K_MUTE &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 + &kp PG_UP &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 + &kp PG_DN &kp TAB &kp Q &kp W &kp E &kp R &kp T + &kp HOME &kp CLCK &kp A &kp S &kp D &kp F &kp G + &kp END &kp LSHFT &kp Z &kp X &kp C &kp V &kp B + &kp INS &kp LCTRL &kp LALT &kp LGUI &mo 1 &kp SPACE + >; + }; + three { + bindings = < + &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans + >; + }; + + }; +}; + diff --git a/app/boards/shields/keychron/keychron_rgb.overlay b/app/boards/shields/keychron/keychron_rgb.overlay new file mode 100644 index 00000000000..5af9691976f --- /dev/null +++ b/app/boards/shields/keychron/keychron_rgb.overlay @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + chosen { + zmk,underglow = &led_strip_0; + zmk,kscan = &kscan0; + //zephyr,console =&cdc_acm_uart; + }; + left_encoder: encoder_left { + compatible = "alps,ec11"; + status = "okay"; + label = "Encoder left"; + a-gpios = <&gpio0 13 (GPIO_ACTIVE_HIGH )>; + b-gpios = <&gpio0 15 (GPIO_ACTIVE_HIGH )>; + steps = <80>; + }; + sensors: sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder>; + triggers-per-rotation = <20>; + }; +}; + +&kscan0 { + + row-gpios + = <&gpio0 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r0 + , <&gpio0 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r1 + , <&gpio0 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r2 + , <&gpio1 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r3 + , <&gpio0 12 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r4 + , <&gpio0 29 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r5 + ; + col-gpios + = <&gpio0 10 (GPIO_ACTIVE_HIGH )> //c0 + , <&gpio0 9 (GPIO_ACTIVE_HIGH)> //c1 + , <&gpio1 6 (GPIO_ACTIVE_HIGH)> //c2 + , <&gpio1 4 (GPIO_ACTIVE_HIGH)> //c3 + , <&gpio1 2 (GPIO_ACTIVE_HIGH)> //c4 + , <&gpio1 1 (GPIO_ACTIVE_HIGH)> //c5 + , <&gpio1 0 (GPIO_ACTIVE_HIGH)> //c6 + , <&gpio0 24 (GPIO_ACTIVE_HIGH)> //c7 + ; +}; +&kscan1 { + + input-gpios + = <&gpio0 19 GPIO_ACTIVE_LOW> //mac/win + , <&gpio0 25 (GPIO_ACTIVE_LOW|GPIO_PULL_UP)> //bt + , <&gpio0 23 (GPIO_ACTIVE_LOW|GPIO_PULL_UP)> //24g + , <&gpio0 21 GPIO_ACTIVE_LOW> //charging + , <&gpio0 22 GPIO_ACTIVE_LOW> //charge done + ; +}; +//&default_transform { +// columns = <8>; +// rows = <6>; +// map =< +// RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) +// RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) +// RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) +// RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) +// RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) +// RC(5,0) RC(5,1) RC(5,2) RC(5,3) RC(5,4) RC(5,5) +// >; + +//}; + +&i2c0 { + status = "okay"; + zephyr,concat-buf-size = <200>; +}; + +&led_strip_0 { + chain-length = <42>; + map = < + /* R G B */ + //row0 + CK(0, 13) CK(1, 13) CK(2, 13) + CK(3, 13) CK(4, 13) CK(5, 13) + CK(6, 13) CK(7, 13) CK(8, 13) + CK(9, 13) CK(10,13) CK(11,13) + CK(0, 7) CK(1, 7) CK(2, 7) + CK(3, 7) CK(4, 7) CK(5, 7) + CK(6, 7) CK(7, 7) CK(8, 7) + + //row1 + CK(0, 1) CK(1, 1) CK(2, 1) + CK(0, 12) CK(1, 12) CK(2, 12) + CK(3, 12) CK(4, 12) CK(5, 12) + CK(6, 12) CK(7, 12) CK(8, 12) + CK(9, 12) CK(10,12) CK(11,12) + CK(0, 6) CK(1, 6) CK(2, 6) + CK(3, 6) CK(4, 6) CK(5, 6) + CK(6, 6) CK(7, 6) CK(8, 6) + + //row2 + CK(3, 1) CK(4, 1) CK(5, 1) + CK(0, 11) CK(1, 11) CK(2, 11) + CK(3, 11) CK(4, 11) CK(5, 11) + CK(6, 11) CK(7, 11) CK(8, 11) + CK(9, 11) CK(10,11) CK(11,11) + CK(0, 5) CK(1, 5) CK(2, 5) + CK(3, 5) CK(4, 5) CK(5, 5) + + //row3 + CK(6, 1) CK(7, 1) CK(8, 1) + CK(0, 10) CK(1, 10) CK(2, 10) + CK(3, 10) CK(4, 10) CK(5, 10) + CK(6, 10) CK(7, 10) CK(8, 10) + CK(9, 10) CK(10,10) CK(11,10) + CK(0, 4) CK(1, 4) CK(2, 4) + CK(3, 4) CK(4, 4) CK(5, 4) + + //row4 + CK(9, 1) CK(10, 1) CK(11, 1) + CK(0, 9) CK(1, 9) CK(2, 9) + CK(3, 9) CK(4, 9) CK(5, 9) + CK(6, 9) CK(7, 9) CK(8, 9) + CK(9, 9) CK(10, 9) CK(11, 9) + CK(0, 3) CK(1, 3) CK(2, 3) + CK(3, 3) CK(4, 3) CK(5, 3) + + //row5 + CK(0, 0) CK(1, 0) CK(2, 0) + CK(0, 8) CK(1, 8) CK(2, 8) + CK(3, 8) CK(4, 8) CK(5, 8) + CK(6, 8) CK(7, 8) CK(8, 8) + CK(9, 8) CK(10, 8) CK(11, 8) + CK(0, 2) CK(1, 2) CK(2, 2) + + >; + + current_tune = + <0x60 0xC4 0xC4 0x60 0xC4 0xC4 0x60 0xC4 0xC4 0x60 0xC4 0xC4>; +}; +//&usbd { +// cdc_acm_uart: cdc_acm_uart { +// compatible = "zephyr,cdc-acm-uart"; +// label = "CDC_ACM_0"; +// }; +//}; +&vbatt { + io-channels = <&adc 0>; +}; + +&led_blue { + blue_led { + gpios = <&gpio0 7 GPIO_ACTIVE_LOW>; + + }; +}; + +&led_numlock { + numlock_led { + gpios = <&gpio0 3 GPIO_ACTIVE_LOW>; + + }; + +}; + +&led_CAPS { + caps_led { + gpios = <&gpio0 4 GPIO_ACTIVE_LOW>; + + }; +}; + +&led_24G { + led_24g { + gpios = <&gpio0 11 GPIO_ACTIVE_LOW>; + + }; +}; + +&led_rgb { + + + myled_r: led_r { + gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; + + }; + myled_g: led_g { + gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; + + }; + myled_b: led_b { + gpios = <&gpio0 30 GPIO_ACTIVE_LOW>; + + }; +}; \ No newline at end of file diff --git a/app/include/zmk/leds.h b/app/include/zmk/leds.h new file mode 100644 index 00000000000..dd64ecee370 --- /dev/null +++ b/app/include/zmk/leds.h @@ -0,0 +1,34 @@ +#ifndef __LEDS_H__ +#define __LEDS_H__ +// int leds_init(void); +void leds_start(void); +void leds_stop(void); +void blue_led_set_state(uint8_t led_state); +void keyboad_led_set_onoff(uint8_t led_state); +void led_24G_set_state(uint8_t led_state); +void led_charge_set_state(uint8_t led_state); +void led_recover(void); +void led_bat_display(void); +void led_bat_display_off(void); +uint8_t get_charge_led_state(void); +enum { + LED_PEER_STATE_DISCONNECTED, + LED_PEER_STATE_CONNECTED, + LED_PEER_STATE_PAIR, + LED_PEER_STATE_RECONN, + LED_PEER_STATE_FAILE, + LED_PEER_STATE_POWER_ON, + LED_PEER_STATE_ON_100MS, + LED_PEER_STATE_BAT_LOW, + LED_PEER_STATE_BAT_CHARGING, + LED_PEER_STATE_BAT_CHARGEDONE, + LED_PEER_STATE_RECOVER, +}; +enum { + LED_BAT_NONE, + LED_BAT_CHARGING, + LED_BAT_CHARGE_DONE, + LED_BAT_LOW, + LED_BAT_SHUT_DOWN, +}; +#endif \ No newline at end of file diff --git a/app/src/24G/CMakeLists.txt b/app/src/24G/CMakeLists.txt new file mode 100644 index 00000000000..dc32d9ea8b3 --- /dev/null +++ b/app/src/24G/CMakeLists.txt @@ -0,0 +1,8 @@ +# +# Copyright (c) 2019 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# +zephyr_link_libraries(${CMAKE_CURRENT_SOURCE_DIR}/lib_nrf_esb_24G.a) + + diff --git a/app/src/24G/lib_nrf_esb_24G.a b/app/src/24G/lib_nrf_esb_24G.a new file mode 100644 index 0000000000000000000000000000000000000000..c8769e7eae239ae7bef00ec2404cd18c3ea64a2e GIT binary patch literal 369352 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 z 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 literal 0 HcmV?d00001 diff --git a/app/src/dfu/CMakeLists.txt b/app/src/dfu/CMakeLists.txt new file mode 100644 index 00000000000..3db24e45a8f --- /dev/null +++ b/app/src/dfu/CMakeLists.txt @@ -0,0 +1,3 @@ +# zephyr_sources(usb_dfu.c) +zephyr_sources(tdfu_prv.c) +zephyr_sources(tdfu.c) \ No newline at end of file diff --git a/app/src/dfu/tdfu.c b/app/src/dfu/tdfu.c new file mode 100644 index 00000000000..5dbdbb07656 --- /dev/null +++ b/app/src/dfu/tdfu.c @@ -0,0 +1,739 @@ + +#include "tdfu.h" +#include "tdfu_prv.h" +#include +#if EN_ZEPHYR_DFU +#include +#include +#include +#include +#include +#endif +#include +#include +#include +LOG_MODULE_REGISTER(usb_dfu, 4); + +unsigned char my_scdfu_is_active(void) ; + + + +#define USE_VIA_USAGE_PAGE + +static unsigned char sc_dfu_rsp_buf[128]; +static unsigned char sc_dfu_sn =1; +static unsigned char sc_dfu_security_mode = DFU_ENC_NONE; +static unsigned char sc_dfu_enable = 0; +static unsigned short sc_dfu_sq=0xffff; +static unsigned char sc_dfu_wait_reboot=0; + + +UINT32 Dfu_CRC_Val = 0xFFFFFFFF; +UINT32 Dfu_CRC_Val_for_XXTEA = 0xFFFFFFFF; +static unsigned int dfu_location=0; + +static unsigned int last_sn = 0; + +// #define FLASH_WR_TEMP_BUFF_MAX_IDX 512 +static unsigned short flash_wr_temp_idx=0; +// static unsigned char flash_wr_temp_buff[FLASH_WR_TEMP_BUFF_MAX_IDX]; + +int zmk_usb_hid_send_report(const uint8_t *report, size_t len); +int zmk_usb_hid_via_send(const uint8_t *report, size_t len); +#if EN_ZEPHYR_DFU +#define SLOT0_PARTITION slot0_partition +#define SLOT1_PARTITION slot1_partition + +#define FIRMWARE_IMAGE_0_LABEL "image_0" +#define FIRMWARE_IMAGE_1_LABEL "image_1" + +#define USB_DFU_MAX_XFER_SIZE 32//CONFIG_USB_REQUEST_BUFFER_SIZE +enum dfu_state { + appIDLE, + appDETACH, + dfuIDLE, + dfuDNLOAD_SYNC, + dfuDNBUSY, + dfuDNLOAD_IDLE, + dfuMANIFEST_SYNC, + dfuMANIFEST, + dfuMANIFEST_WAIT_RST, + dfuUPLOAD_IDLE, + dfuERROR, +}; +enum dfu_status { + statusOK, + errTARGET, + errFILE, + errWRITE, + errERASE, + errCHECK_ERASED, + errPROG, + errVERIFY, + errADDRESS, + errNOTDONE, + errFIRMWARE, + errVENDOR, + errUSB, + errPOR, + errUNKNOWN, + errSTALLEDPKT +}; +#if FIXED_PARTITION_EXISTS(SLOT1_PARTITION) + #define DOWNLOAD_FLASH_AREA_ID FIXED_PARTITION_ID(SLOT1_PARTITION) +#else + #define DOWNLOAD_FLASH_AREA_ID FIXED_PARTITION_ID(SLOT0_PARTITION) +#endif +struct dfu_worker_data_t { + uint8_t buf[USB_DFU_MAX_XFER_SIZE]; + enum dfu_state worker_state; + uint16_t worker_len; +}; +struct dfu_data_t { + uint8_t flash_area_id; + uint32_t flash_upload_size; + /* Number of bytes sent during upload */ + uint32_t bytes_sent; + uint32_t alt_setting; /* DFU alternate setting */ + struct flash_img_context ctx; + enum dfu_state state; /* State of the DFU device */ + enum dfu_status status; /* Status of the DFU device */ + uint16_t block_nr; /* DFU block number */ + uint16_t bwPollTimeout; +}; +static struct dfu_data_t dfu_data = { + .state = appIDLE, + .status = statusOK, + .flash_area_id = DOWNLOAD_FLASH_AREA_ID, + .alt_setting = 0, + .bwPollTimeout = 0, +}; +static struct dfu_worker_data_t dfu_data_worker; +static struct k_work dfu_work; +static void dfu_work_handler(struct k_work *item); +#endif +#ifndef USE_VIA_USAGE_PAGE +int usb_send_user_if_data(uint8_t id, uint8_t *data,uint8_t len) +{ + uint8_t buf[33]={0}; + buf[0]=id; + memcpy(buf+1,data,len); + // LOG_HEXDUMP_DBG(buf,33,"tx"); + return zmk_usb_hid_send_report(buf,sizeof(buf)); + +} +#else +int usb_send_user_if_data(uint8_t id, uint8_t *data,uint8_t len) +{ + uint8_t buf[32]={0}; + buf[0]=0x03; + memcpy(buf+1,data,len>31?31:len); + return zmk_usb_hid_via_send(buf,sizeof(buf)); +} +int usb_send_user_if_data_1(uint8_t id, uint8_t *data,uint8_t len) +{ + uint8_t buf[32]={0}; + + memcpy(buf,data,len); + return zmk_usb_hid_via_send(buf,sizeof(buf)); +} +#endif +#if EN_ZEPHYR_DFU +static void dfu_reset_counters(void) +{ + dfu_data.bytes_sent = 0U; + dfu_data.block_nr = 0U; + dfu_data.state = dfuIDLE; + if (flash_img_init(&dfu_data.ctx)) { + LOG_ERR("flash img init error"); + dfu_data.state = dfuERROR; + dfu_data.status = errUNKNOWN; + } + + LOG_DBG("."); +} +static void dfu_flash_write(uint8_t *data, size_t len) +{ + bool flush = false; + + if (!len) { + /* Download completed */ + flush = true; + } + + if (flash_img_buffered_write(&dfu_data.ctx, data, len, flush)) { + LOG_ERR("flash write error"); + dfu_data.state = dfuERROR; + dfu_data.status = errWRITE; + sc_dfu_enable =0; + } else if (!len) { + const bool should_confirm = true;//IS_ENABLED(CONFIG_USB_DFU_PERMANENT_DOWNLOAD); + + LOG_DBG("flash write done"); + dfu_data.state = dfuMANIFEST_SYNC; + + + LOG_DBG("Should confirm: %d", should_confirm); + if (boot_request_upgrade(should_confirm)) { + dfu_data.state = dfuERROR; + dfu_data.status = errWRITE; + } + + } else { + dfu_data.state = dfuDNLOAD_IDLE; + } + + // LOG_DBG("bytes written 0x%x", flash_img_bytes_written(&dfu_data.ctx)); +} +static void dfu_work_handler(struct k_work *item) +{ + ARG_UNUSED(item); + + switch (dfu_data_worker.worker_state) { + case dfuIDLE: +/* + * If progressive erase is enabled, then erase take place while + * image collection, so not erase whole bank at DFU beginning + */ +#ifndef CONFIG_IMG_ERASE_PROGRESSIVELY + if (boot_erase_img_bank(DOWNLOAD_FLASH_AREA_ID)) { + dfu_data.state = dfuERROR; + dfu_data.status = errERASE; + break; + } +#endif + case dfuDNLOAD_IDLE: + dfu_flash_write(dfu_data_worker.buf, + dfu_data_worker.worker_len); + break; + default: + LOG_ERR("OUT of state machine"); + break; + } +} +#endif +void my_scdfu_init(void) +{ + +} + +static unsigned char fw_sc_upgrade_over_myhid_start(void) +{ + sc_dfu_enable=1; + dfu_location=0; + sc_dfu_sq=0; + sc_dfu_wait_reboot=0; + Dfu_CRC_Val = 0xFFFFFFFF; + Dfu_CRC_Val_for_XXTEA =0xFFFFFFFF; + + flash_wr_temp_idx=0; + last_sn = 0; + +#if (WATCH_DOG_ENABLE == 1) + app_watchdog_close(); + app_watchdog_open(MY_DFU_WATCH_DOG_TIMEOUT_MS, RESET_ALL_EXCEPT_AON); +#endif +#if EN_ZEPHYR_DFU + k_work_init(&dfu_work, dfu_work_handler); + dfu_reset_counters(); +#endif + return 0; +} + + +static void dfu_commit_temp_buff_to_flash(void) +{ +#if EN_ZEPHYR_DFU + dfu_flash_write(NULL,0); +#endif +} + +static unsigned char fw_sc_upgrade_over_myhid_write_to_flash(unsigned char *pdata ,unsigned char len) +{ + + +#if EN_ZEPHYR_DFU + switch (dfu_data.state) { + case dfuIDLE: + LOG_DBG("DFU_DNLOAD start"); + dfu_reset_counters(); + + if (dfu_data.flash_area_id != DOWNLOAD_FLASH_AREA_ID) { + dfu_data.status = errWRITE; + dfu_data.state = dfuERROR; + LOG_ERR("This area can not be overwritten"); + break; + } + LOG_INF("flash id:%d",dfu_data.flash_area_id); + dfu_data.state = dfuDNBUSY; + dfu_data_worker.worker_state = dfuIDLE; + dfu_data_worker.worker_len = len; + memcpy(dfu_data_worker.buf, pdata, len); + k_work_submit_to_queue(&USB_WORK_Q, &dfu_work); + break; + case dfuDNLOAD_IDLE: + dfu_data.state = dfuDNBUSY; + dfu_data_worker.worker_state = dfuDNLOAD_IDLE; + dfu_data_worker.worker_len = len; + + memcpy(dfu_data_worker.buf, pdata, len); + k_work_submit_to_queue(&USB_WORK_Q, &dfu_work); + break; + default: + LOG_ERR("DFU_DNLOAD wrong state %d", dfu_data.state); + dfu_data.state = dfuERROR; + dfu_data.status = errUNKNOWN; + dfu_reset_counters(); + return -EINVAL; + } + + return dfu_data.state !=dfuERROR; +#else + return 0; +#endif +} + +/* +*/ +static void fw_sc_upgrade_rsp_ack(unsigned char *pdata,unsigned char len) +{ +#ifdef USE_VIA_USAGE_PAGE + #define MAX_SIZE (32-1) +#else + #define MAX_SIZE (32) +#endif + CMD_RSP_HDR *ackhdr=(CMD_RSP_HDR *)pdata; + unsigned short sum; + + len+=2; //len of sum + + ackhdr->hdr_h = 0x55; + ackhdr->hdr_l = 0xaa; + ackhdr->len = len; + ackhdr->len_n = ~len; + ackhdr->sn = sc_dfu_sn++; + + if(sc_dfu_sn==0) + sc_dfu_sn=1; + + sum=0; + for(unsigned char i=0;i<(len-2);i++) + sum+=sc_dfu_rsp_buf[i+5]; + + pdata[5+len-2] = sum&0xff; + pdata[5+len-1] = (sum>>8)&0xff; + + int ret = FW_SC_UPGRADE_HID_REPORT_SEND(MY_DFU_RPT_INPUT_ID,pdata,MAX_SIZE); + + + + //retry again + if(ret) + { + + ret = FW_SC_UPGRADE_HID_REPORT_SEND(MY_DFU_RPT_INPUT_ID,pdata,MAX_SIZE); + } + + if(ret==0) + { + if((len+5)>MAX_SIZE) + { + + #ifndef USE_VIA_USAGE_PAGE + ret = FW_SC_UPGRADE_HID_REPORT_SEND(MY_DFU_RPT_INPUT_ID,(pdata+MAX_SIZE),MAX_SIZE); + #else + ret = usb_send_user_if_data_1(MY_DFU_RPT_INPUT_ID,(pdata+MAX_SIZE),MAX_SIZE); + #endif + + if(ret) + { + #ifndef USE_VIA_USAGE_PAGE + ret = FW_SC_UPGRADE_HID_REPORT_SEND(MY_DFU_RPT_INPUT_ID,(pdata+32),MAX_SIZE); + #else + ret=usb_send_user_if_data_1(MY_DFU_RPT_INPUT_ID,(pdata+MAX_SIZE),MAX_SIZE); + #endif + } + } + } + + if(ret) + { + LOG_DBG("fw_sc_upgrade_rsp_ack fail,ret = %d",ret); + sc_dfu_enable = 0; + } +} + +static void fw_sc_upgrade_rsp_model_info(unsigned char sn) +{ + //unsigned char rsp_idx=0; + BT_INFORMATION_TYPE *ackpkt = (BT_INFORMATION_TYPE *)(&sc_dfu_rsp_buf[9]); + unsigned char str_len; + CMD_RSP_HDR *ackhdr=(CMD_RSP_HDR *)sc_dfu_rsp_buf; + + memset(sc_dfu_rsp_buf,0,sizeof(sc_dfu_rsp_buf)); + + ackhdr->rsp_cmd = TX__OTA_REPORT; //rsp type + ackhdr->ack_sn = sn; + ackhdr->ack_cmd =SCFWU_OPCODE_GET_MODEL_INFO; + ackhdr->ack_status = 0; + + ackpkt->BR_LE_mode = SUPPORT_LE|SUPPORT_RF; + ackpkt->bluetooth_version = 0x03; + ackpkt->command_version[0] = 0x01; + + //model string + for(unsigned char i=0;i<10;i++) + { + ackpkt->model_number[i]=0; + ackpkt->fw_version[i]=0; + ackpkt->hw_version[i]=0; + } + + str_len=sizeof(MY_FWU_STRING_NAME)-1; + if(str_len>10) + str_len=10; + memcpy(((unsigned char*)(ackpkt->model_number)),MY_FWU_STRING_NAME,str_len); + + str_len=sizeof(MY_FW_VERSION)-1; + if(str_len>10) + str_len=10; + memcpy(((unsigned char*)(ackpkt->fw_version)),MY_FW_VERSION,str_len); + + str_len=sizeof(MY_HW_VERSION)-1; + if(str_len>10) + str_len=10; + memcpy(((unsigned char*)(ackpkt->hw_version)),MY_HW_VERSION,str_len); + + fw_sc_upgrade_rsp_ack(sc_dfu_rsp_buf,sizeof(BT_INFORMATION_TYPE)+4); +} + + +static void fw_sc_upgrade_rsp_dfu_version(unsigned char sn) +{ + tDFU_VERSION *ackpkt = (tDFU_VERSION *)(&sc_dfu_rsp_buf[9]); + CMD_RSP_HDR *ackhdr= (CMD_RSP_HDR *)sc_dfu_rsp_buf; + + memset(sc_dfu_rsp_buf,0,sizeof(sc_dfu_rsp_buf)); + + ackpkt->dfu_version_l = DFU_VERSION_VALUE&0xff; + ackpkt->dfu_version_h = (DFU_VERSION_VALUE>>8) & 0xff; + ackpkt->encrytion_m = DFU_ENC_SUPPORT; + + ackhdr->rsp_cmd = TX__OTA_REPORT; //rsp type + ackhdr->ack_sn = sn; + ackhdr->ack_cmd =SCFWU_OPCODE_GET_DFU_VERSION; + ackhdr->ack_status = 0; + + fw_sc_upgrade_rsp_ack(sc_dfu_rsp_buf,sizeof(tDFU_VERSION)+4); +} + +static void fw_sc_upgrade_set_security_level(unsigned char sn,unsigned char mode) +{ + CMD_RSP_HDR *ackhdr=(CMD_RSP_HDR *)sc_dfu_rsp_buf; + + memset(sc_dfu_rsp_buf,0,sizeof(sc_dfu_rsp_buf)); + + if(mode<=DFU_ENC_AES128) + sc_dfu_security_mode=mode; + +#if(MY_DFU_TRACE_ENABLE) + + LOG_DBG("sc_dfu_security_mode = %d \r\n",sc_dfu_security_mode); + +#endif + + ackhdr->rsp_cmd = TX__OTA_REPORT; //rsp type + ackhdr->ack_sn = sn; + ackhdr->ack_cmd =SCFWU_OPCODE_SET_SC_METHOED; + ackhdr->ack_status =(mode<=DFU_ENC_AES128)?0:1; + + fw_sc_upgrade_rsp_ack(sc_dfu_rsp_buf,5+4); +} + +static void fw_sc_upgrade_ack_success(unsigned char sn,unsigned char rx_cmd) +{ + CMD_RSP_HDR *ackhdr=(CMD_RSP_HDR *)sc_dfu_rsp_buf; + memset(sc_dfu_rsp_buf,0,sizeof(sc_dfu_rsp_buf)); + + ackhdr->rsp_cmd = TX__RSP_RX_CMD_SUCCESS; //rsp type + ackhdr->ack_sn = sn; + ackhdr->ack_cmd = rx_cmd; + ackhdr->ack_status = 0; + + fw_sc_upgrade_rsp_ack(sc_dfu_rsp_buf,1+4); +} + +static void fw_sc_upgrade_ack_fail(unsigned char sn,unsigned char rx_cmd,unsigned char reason) +{ + CMD_RSP_HDR *ackhdr=(CMD_RSP_HDR *)sc_dfu_rsp_buf; + memset(sc_dfu_rsp_buf,0,sizeof(sc_dfu_rsp_buf)); + + ackhdr->rsp_cmd = TX__RSP_RX_CMD_SUCCESS; //rsp type + ackhdr->ack_sn = sn; + ackhdr->ack_cmd = rx_cmd; + ackhdr->ack_status = reason; + + fw_sc_upgrade_rsp_ack(sc_dfu_rsp_buf,4); +} + +UINT32 CRC32(UINT32 crcval, UINT8 *buf, UINT32 length) +{ + UINT32 crc32_table = 0; + UINT32 bit = 0; + + while(length--) + { + crc32_table = ((crcval ^ *buf++)&0xff); + + for(bit = 0; bit < 8; bit++) + { + if(crc32_table&1) + { + crc32_table = (crc32_table >> 1)^(0xEDB88320); + } + else + { + crc32_table = crc32_table >> 1; + } + + } + + crcval = (crcval >> 8)^crc32_table; + } + + return crcval; +} + + + + +static void fw_sc_upgrade_write_bin_handle(unsigned char sn, unsigned char *dfu_data,unsigned char len) +{ + unsigned char ret=0; + + if(!sc_dfu_enable) + { + fw_sc_upgrade_ack_fail(sn,SCFWU_OPCODE_SEND_BIN,0x01); + return ; + } + + if(last_sn==sn) + { + fw_sc_upgrade_ack_success(sn,SCFWU_OPCODE_SEND_BIN); + return ; + } + + last_sn = sn; + + + if(sc_dfu_security_mode==DFU_ENC_NONE) + { + Dfu_CRC_Val = CRC32(Dfu_CRC_Val, dfu_data, len); + } + + + ret=fw_sc_upgrade_over_myhid_write_to_flash(dfu_data,len); + + + if(ret==0) + fw_sc_upgrade_ack_success(sn,SCFWU_OPCODE_SEND_BIN); + else + fw_sc_upgrade_ack_fail(sn,SCFWU_OPCODE_SEND_BIN,0x01); + +} + +static void fw_sc_upgrade_verify_crc(unsigned char sn,unsigned char *pdata ,unsigned char len) +{ + unsigned int Ciphertext_CRC32; + unsigned int Plaintext_CRC32; + unsigned char crc=1; + + unsigned char *ackpkt = &sc_dfu_rsp_buf[9]; + CMD_RSP_HDR *ackhdr=(CMD_RSP_HDR *)sc_dfu_rsp_buf; + + memset(sc_dfu_rsp_buf,0,sizeof(sc_dfu_rsp_buf)); + + Ciphertext_CRC32=0; + Ciphertext_CRC32|= (pdata[0] & 0xff); + Ciphertext_CRC32|= ((pdata[1]<<8) & 0xff00); + Ciphertext_CRC32|= ((pdata[2]<<16) & 0xff0000); + Ciphertext_CRC32|= ((pdata[3]<<24) & 0xff000000); + + Plaintext_CRC32=0; + Plaintext_CRC32|= (pdata[4] & 0xff); + Plaintext_CRC32|= ((pdata[5]<<8) & 0xff00); + Plaintext_CRC32|= ((pdata[6]<<16) & 0xff0000); + Plaintext_CRC32|= ((pdata[7]<<24) & 0xff000000); + +#if(MY_DFU_TRACE_ENABLE) + + LOG_DBG("fw_sc_upgrade_verify_crc(%d),rx crc:%x,%x,cal crc:%x,%x\r\n",sc_dfu_security_mode,Ciphertext_CRC32,Plaintext_CRC32,Dfu_CRC_Val,Dfu_CRC_Val_for_XXTEA); + +#endif + + if(sc_dfu_security_mode==DFU_ENC_NONE) + { + if((Ciphertext_CRC32==Plaintext_CRC32) + && (Ciphertext_CRC32==Dfu_CRC_Val)) + { + crc=0; + } + } + + + ackhdr->rsp_cmd = TX__OTA_REPORT; //rsp type + ackhdr->ack_sn = sn; + ackhdr->ack_cmd = SCFWU_OPCODE_VERIFY_CRC32; + ackhdr->ack_status = 0; + + if(crc==0) + { + bool check_result = false; + #if EN_ZEPHYR_DFU + check_result = dfu_data.state != dfuERROR; + #endif + if(check_result==false) + { + crc = 2;//error + LOG_ERR("crc:%d",crc); + } + } + + ackpkt[0]= crc; + + fw_sc_upgrade_rsp_ack(sc_dfu_rsp_buf,1+4); +} + +static unsigned char fw_sc_upgrade_image_switch(unsigned char sn) +{ + + if(sc_dfu_enable) + sys_reboot(SYS_REBOOT_WARM); + return 1; +} + +static void fw_sc_upgrade_build_info(unsigned char sn) +{ + CMD_RSP_HDR *ackhdr=(CMD_RSP_HDR *)sc_dfu_rsp_buf; + unsigned char *str_buf = &sc_dfu_rsp_buf[9]; + unsigned char offset=0; + + memset(sc_dfu_rsp_buf,0,sizeof(sc_dfu_rsp_buf)); + + ackhdr->rsp_cmd = TX__OTA_REPORT; //rsp type + ackhdr->ack_sn = sn; + ackhdr->ack_cmd =APP_CMD_DFU_BUILD_INFO; + ackhdr->ack_status = 0; + + memcpy(str_buf,__DATE__,sizeof(__DATE__)); + str_buf[sizeof(__DATE__)-1]=' '; + offset += sizeof(__DATE__); + memcpy(str_buf+sizeof(__DATE__),__TIME__,sizeof(__TIME__)); + offset += sizeof(__TIME__); + + fw_sc_upgrade_rsp_ack(sc_dfu_rsp_buf,offset+4); +} + + +void my_scdfu_data_handle(unsigned char *pdata,unsigned char rxlen) +{ + unsigned short hdr = 0; + unsigned char len = pdata[2]; + unsigned char len_n = (~pdata[3]); + unsigned char sn = pdata[4]; + + hdr= pdata[1]; + hdr |= pdata[0]<<8; + + if((hdr == SC_FWU_HEADER)||(hdr == SC_FWU_HEADER_ACK)) + { + if((len == len_n) && (len >2)) + { + unsigned short sum = 0; + unsigned short sum_rx=0; + unsigned char len_of_dfu = len -2; + unsigned char op_code = pdata[5]; + + for(unsigned char i=0;irsp_cmd = TX__OTA_REPORT; //rsp type + ackhdr->ack_sn = sn; + ackhdr->ack_cmd = 0xf2; + ackhdr->ack_status = 0; + + if(len>50) + len=50; + + for(unsigned char i=0;i +unsigned char *my_dfu_get_prv_data(void); +unsigned char my_dfu_get_prv_len(void); + +#if CONFIG_SHIELD_KEYCHRON_B1 +#define MY_FWU_STRING_NAME "ZMK_KB_B1" +#define MY_FW_VERSION APP_VERSION_STRING +#define MY_HW_VERSION "B1N_v1.0" +#elif CONFIG_SHIELD_KEYCHRON_B2 +#define MY_FWU_STRING_NAME "ZMK_KB_B2" +#define MY_FW_VERSION APP_VERSION_STRING +#define MY_HW_VERSION "B2N_v1.0" +#else +#define MY_FWU_STRING_NAME "ZMK_KB_B6" +#define MY_FW_VERSION APP_VERSION_STRING +#define MY_HW_VERSION "B6N_v1.0" +#endif + +#endif + diff --git a/app/src/launcher/CMakeLists.txt b/app/src/launcher/CMakeLists.txt new file mode 100644 index 00000000000..e35dd393ec5 --- /dev/null +++ b/app/src/launcher/CMakeLists.txt @@ -0,0 +1,6 @@ + +target_sources_ifdef(CONFIG_ZMK_LAUNCHER app PRIVATE launcher.c) +target_sources_ifdef(CONFIG_ZMK_LAUNCHER app PRIVATE dynamic_keymap.c) +target_sources_ifdef(CONFIG_ZMK_LAUNCHER app PRIVATE map_keycode.c) +target_sources_ifdef(CONFIG_ZMK_LAUNCHER app PRIVATE send_string.c) +target_sources_ifdef(CONFIG_ZMK_LAUNCHER app PRIVATE mousekey.c) \ No newline at end of file diff --git a/app/src/launcher/dynamic_keymap.c b/app/src/launcher/dynamic_keymap.c new file mode 100644 index 00000000000..a12ed05163c --- /dev/null +++ b/app/src/launcher/dynamic_keymap.c @@ -0,0 +1,509 @@ +/* Copyright 2017 Jason Williams (Wilba) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dynamic_keymap.h" +#include "keycodes.h" +#include "send_string.h" +#include "launcher.h" +#include +#include + +LOG_MODULE_DECLARE(zmk, 4);//CONFIG_ZMK_LOG_LEVEL); +uint8_t behavior_queue_is_full(void); +void send_string_end(void); +void macro_timer_expiry(struct k_timer *timer); +void macro_exec(void); + +K_TIMER_DEFINE(macro_timer, macro_timer_expiry, NULL); +static uint16_t p_macro; +enum { + SAVE_VIA_LAYOUT =0x01, + SAVE_VIA_ENCODER =0x02, + SAVE_VIA_CUSTOM =0x04, + SAVE_VIA_MACROS =0x08, + SAVE_VIA_KEYMAPS =0x10, + SAVE_VIA_CHANGED =0x20, + SAVE_VIA_KEYMAPS_RESET =0x40, + SAVE_VIA_MACROS_RESET =0x80, + SAVE_VIA_DEBOUNCE =0x20, + SAVE_VIA_MAX =8 +}; + +struct _save_info { + uint16_t save_type; + uint16_t save_index; +}; + +static struct _save_info save_info; +void storage_via_worker(struct k_work *work) +{ + LOG_DBG("save,type:%x,index:%d",save_info.save_type,save_info.save_index); + uint8_t bits=0x80; + for(int i=0;i>=1; + } +} +K_WORK_DELAYABLE_DEFINE(storage_via_work, storage_via_worker); + +extern uint16_t gen_via_keymaps[DYNAMIC_KEYMAP_LAYER_COUNT][MATRIX_ROWS][MATRIX_COLS]; +uint16_t keycode_at_keymap_location_raw(uint8_t layer_num, uint8_t row, uint8_t column) { + if (layer_num < NUM_KEYMAP_LAYERS_RAW && row < MATRIX_ROWS && column < MATRIX_COLS) { + // return (layer_num <<8) | (row*MATRIX_COLS+column);//via_ee_device.keymaps[layer_num][row][column]; + return gen_via_keymaps[layer_num][row][column]; + } + return KC_TRNS; +} +uint8_t dynamic_keymap_get_layer_count(void) { + return DYNAMIC_KEYMAP_LAYER_COUNT; +} + +inline uint16_t dynamic_keymap_key_to_eeprom_address(uint8_t layer, uint8_t row, uint8_t column) { + // TODO: optimize this with some left shifts + return (DYNAMIC_KEYMAP_EEPROM_ADDR) + (layer * MATRIX_ROWS * MATRIX_COLS * 2) + (row * MATRIX_COLS * 2) + (column * 2); +} + +uint16_t dynamic_keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t column) { + if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || row >= MATRIX_ROWS || column >= MATRIX_COLS) return KC_NO; + uint16_t address = dynamic_keymap_key_to_eeprom_address(layer, row, column); + // Big endian, so we can read/write EEPROM directly from host if we want + uint16_t keycode = eeprom_read_byte(address) << 8; + keycode |= eeprom_read_byte(address + 1); + return keycode; +} +void dynamic_keymap_set_keycode_no_update(uint8_t layer, uint8_t row, uint8_t column, uint16_t keycode) { + if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || row >= MATRIX_ROWS || column >= MATRIX_COLS) return; + uint16_t address = dynamic_keymap_key_to_eeprom_address(layer, row, column); + // Big endian, so we can read/write EEPROM directly from host if we want + eeprom_update_byte(address, (uint8_t)(keycode >> 8)); + eeprom_update_byte(address + 1, (uint8_t)(keycode & 0xFF)); +} +void dynamic_keymap_set_keycode(uint8_t layer, uint8_t row, uint8_t column, uint16_t keycode) { + if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || row >= MATRIX_ROWS || column >= MATRIX_COLS) return; + uint16_t address = dynamic_keymap_key_to_eeprom_address(layer, row, column); + // Big endian, so we can read/write EEPROM directly from host if we want + eeprom_update_byte(address, (uint8_t)(keycode >> 8)); + eeprom_update_byte(address + 1, (uint8_t)(keycode & 0xFF)); + + // via_set_changed_key(layer,row,column); + set_zmk_keymap(layer,row,column,keycode); + + save_info.save_type |= SAVE_VIA_KEYMAPS ; + save_info.save_index |= 1<= DYNAMIC_KEYMAP_LAYER_COUNT || encoder_id >= NUM_ENCODERS) return KC_NO; + uint16_t address = dynamic_keymap_encoder_to_eeprom_address(layer, encoder_id); + // Big endian, so we can read/write EEPROM directly from host if we want + uint16_t keycode = ((uint16_t)eeprom_read_byte(address + (clockwise ? 0 : 2))) << 8; + keycode |= eeprom_read_byte(address + (clockwise ? 0 : 2) + 1); + return keycode; +} + +void dynamic_keymap_set_encoder(uint8_t layer, uint8_t encoder_id, bool clockwise, uint16_t keycode) { + if (layer >= DYNAMIC_KEYMAP_LAYER_COUNT || encoder_id >= NUM_ENCODERS) return; + uint16_t address = dynamic_keymap_encoder_to_eeprom_address(layer, encoder_id); + // Big endian, so we can read/write EEPROM directly from host if we want + eeprom_update_byte(address + (clockwise ? 0 : 2), (uint8_t)(keycode >> 8)); + eeprom_update_byte(address + (clockwise ? 0 : 2) + 1, (uint8_t)(keycode & 0xFF)); + + save_info.save_type |= SAVE_VIA_ENCODER; + + k_work_reschedule(&storage_via_work, K_MSEC(1500)); +} +#endif // ENCODER_MAP_ENABLE + +void dynamic_keymap_reset(bool save) { + // Reset the keymaps in EEPROM to what is in flash. + for (int layer = 0; layer < DYNAMIC_KEYMAP_LAYER_COUNT; layer++) { + #if 1 + for (int row = 0; row < MATRIX_ROWS; row++) { + for (int column = 0; column < MATRIX_COLS; column++) { + dynamic_keymap_set_keycode_no_update(layer, row, column, keycode_at_keymap_location_raw(layer, row, column)); + set_zmk_keymap(layer, row, column, keycode_at_keymap_location_raw(layer, row, column)); + } + } + #endif + // memcpy(&via_ee_device.keymaps[layer*KEYMAP_LEN],&gen_via_keymaps[layer],KEYMAP_LEN); +#ifdef ENCODER_MAP_ENABLE + for (int encoder = 0; encoder < NUM_ENCODERS; encoder++) { + dynamic_keymap_set_encoder(layer, encoder, true, keycode_at_encodermap_location_raw(layer, encoder, true)); + dynamic_keymap_set_encoder(layer, encoder, false, keycode_at_encodermap_location_raw(layer, encoder, false)); + } +#endif // ENCODER_MAP_ENABLE + } + LOG_DBG("MATRIX_ROWS:%d,MATRIX_COLS:%d",MATRIX_ROWS,MATRIX_COLS); + LOG_HEXDUMP_DBG(&via_ee_device.keymaps[0],32,"keymap"); + + if(save) + { + save_info.save_type = SAVE_VIA_KEYMAPS_RESET; + save_info.save_index =0xff; + k_work_reschedule(&storage_via_work,K_MSEC(100)); + } +} + +void dynamic_keymap_get_buffer(uint16_t offset, uint16_t size, uint8_t *data) { + uint16_t dynamic_keymap_eeprom_size = DYNAMIC_KEYMAP_LAYER_COUNT * MATRIX_ROWS * MATRIX_COLS * 2; + uint16_t source = (DYNAMIC_KEYMAP_EEPROM_ADDR + offset); + uint8_t *target = data; + for (uint16_t i = 0; i < size; i++) { + if (offset + i < dynamic_keymap_eeprom_size) { + *target = eeprom_read_byte(source); + } else { + *target = 0x00; + } + source++; + target++; + } +} + +void dynamic_keymap_set_buffer(uint16_t offset, uint16_t size, uint8_t *data) { + uint16_t dynamic_keymap_eeprom_size = DYNAMIC_KEYMAP_LAYER_COUNT * MATRIX_ROWS * MATRIX_COLS * 2; + uint16_t target = (DYNAMIC_KEYMAP_EEPROM_ADDR + offset); + uint8_t *source = data; + for (uint16_t i = 0; i < size; i++) { + if (offset + i < dynamic_keymap_eeprom_size) { + eeprom_update_byte(target, *source); + } + source++; + target++; + } + //TODO: + LOG_DBG("."); +} + +uint16_t keycode_at_keymap_location(uint8_t layer_num, uint8_t row, uint8_t column) { + if (layer_num < DYNAMIC_KEYMAP_LAYER_COUNT && row < MATRIX_ROWS && column < MATRIX_COLS) { + return dynamic_keymap_get_keycode(layer_num, row, column); + } + return KC_NO; +} + +#ifdef ENCODER_MAP_ENABLE +uint16_t keycode_at_encodermap_location(uint8_t layer_num, uint8_t encoder_idx, bool clockwise) { + if (layer_num < DYNAMIC_KEYMAP_LAYER_COUNT && encoder_idx < NUM_ENCODERS) { + return dynamic_keymap_get_encoder(layer_num, encoder_idx, clockwise); + } + return KC_NO; +} +#endif // ENCODER_MAP_ENABLE + +uint8_t dynamic_keymap_macro_get_count(void) { + return DYNAMIC_KEYMAP_MACRO_COUNT; +} + +uint16_t dynamic_keymap_macro_get_buffer_size(void) { + return DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE; +} + +void dynamic_keymap_macro_get_buffer(uint16_t offset, uint16_t size, uint8_t *data) { + uint16_t source = (DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + offset); + uint8_t *target = data; + for (uint16_t i = 0; i < size; i++) { + if (offset + i < DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE) { + *target = eeprom_read_byte(source); + } else { + *target = 0x00; + } + source++; + target++; + } +} + +void dynamic_keymap_macro_set_buffer(uint16_t offset, uint16_t size, uint8_t *data) { + uint16_t target = (DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + offset); + uint8_t *source = data; + for (uint16_t i = 0; i < size; i++) { + if (offset + i < DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE) { + eeprom_update_byte(target, *source); + } + source++; + target++; + } + + save_info.save_type |= SAVE_VIA_MACROS; + + k_work_reschedule(&storage_via_work, K_MSEC(1500)); +} + +void dynamic_keymap_macro_reset(bool save) { + uint16_t p = (DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR); + uint16_t end = (DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE); + // int i=0; + while (p != end) { + eeprom_update_byte(p, 0); + ++p; + } + if(save) + { + save_info.save_type = SAVE_VIA_MACROS_RESET; + k_work_reschedule(&storage_via_work,K_MSEC(100)); + } +} +void via_save_debounce(void) +{ + save_info.save_type |= SAVE_VIA_DEBOUNCE; + k_work_reschedule(&storage_via_work,K_MSEC(1000)); +} +uint32_t convert_time(uint8_t *ch); +void send_string_delay(uint32_t delay_time); +void dynamic_keymap_macro_send(uint8_t id) { + if (id >= DYNAMIC_KEYMAP_MACRO_COUNT || (p_macro !=0)) { + return; + } + + // Check the last byte of the buffer. + // If it's not zero, then we are in the middle + // of buffer writing, possibly an aborted buffer + // write. So do nothing. + uint16_t p = (DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE - 1); + if (eeprom_read_byte(p) != 0) { + return; + } + + // Skip N null characters + // p will then point to the Nth macro + p = (DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR); + uint16_t end = (DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE); + while (id > 0) { + // If we are past the end of the buffer, then there is + // no Nth macro in the buffer. + if (p == end) { + return; + } + if (eeprom_read_byte(p) == 0) { + --id; + } + ++p; + } + p_macro =p; + macro_exec(); + +} +#include +uint32_t convert_time(uint8_t *ch) +{ + uint32_t ms=0; + while(isdigit(*ch)) + { + ms *= 10; + ms += *ch - '0'; + ch++; + } + return ms; +} +void send_string_delay(uint32_t delay_time) +{ + uint8_t data[8]={SS_QMK_PREFIX,SS_DELAY_CODE}; + if(delay_time>9999) delay_time =9999; + sprintf(&data[2],"%d",delay_time); + send_string_with_delay(data, DYNAMIC_KEYMAP_MACRO_DELAY); +} + +void macro_exec(void) +{ + static uint16_t total=0; + uint8_t err=0; + uint32_t delay_time =0; + // Send the macro string by making a temporary string. + char data[8] = {0}; + // We already checked there was a null at the end of + // the buffer, so this cannot go past the end + uint8_t count=0; + if(behavior_queue_is_full()) + { + LOG_WRN("behavior_queue_is_full!"); + k_timer_start(¯o_timer,K_MSEC(10),K_FOREVER); + return; + } + while (1) { + data[0] = eeprom_read_byte(p_macro++); + data[1] = 0; + // Stop at the null terminator of this macro string + if (data[0] == 0) { + err=2; + break; + } + if (data[0] == SS_QMK_PREFIX) { + // Get the code + data[1] = eeprom_read_byte(p_macro++); + // Unexpected null, abort. + if (data[1] == 0) { + err=1; + break; + } + if (data[1] == SS_TAP_CODE || data[1] == SS_DOWN_CODE || data[1] == SS_UP_CODE) { + // Get the keycode + data[2] = eeprom_read_byte(p_macro++); + // Unexpected null, abort. + if (data[2] == 0) { + err=1; + break; + } + // Null terminate + data[3] = 0; + } else if (data[1] == SS_DELAY_CODE) { + // Get the number and '|' + // At most this is 4 digits plus '|' + uint8_t i = 2; + while (1) { + data[i] = eeprom_read_byte(p_macro++); + // Unexpected null, abort + if (data[i] == 0) { + err=1; + break; + } + // Found '|', send it + if (data[i] == '|') { + data[i + 1] = 0; + break; + } + // If haven't found '|' by i==6 then + // number too big, abort + if (i == 6) { + err=1; + break; + } + ++i; + } + delay_time += convert_time(&data[2]); + } + } + // LOG_HEXDUMP_DBG(data,sizeof(data),"macro"); + LOG_DBG("macro:%d,data:%02x",total,data[0]); + if(data[1]!=SS_DELAY_CODE) + { + if(delay_time) + { + send_string_delay(delay_time); + LOG_DBG("send_string_delay:%d",delay_time); + } + send_string_with_delay(data, DYNAMIC_KEYMAP_MACRO_DELAY); + delay_time =0; + } + total ++; + if(++count>=10) + { + break; + } + + } + if(err==0) + { + LOG_DBG("macro continue"); + k_timer_start(¯o_timer,K_MSEC(10),K_FOREVER); + } + else if(err==2) + { + LOG_DBG("macro done,t:%d",total); + send_string_end(); + total=0; + p_macro =0; + } + else if(err ==1) + { + LOG_ERR("macro ERR"); + p_macro =0; + } +} +void macro_timer_expiry(struct k_timer *timer) +{ + macro_exec(); +} diff --git a/app/src/launcher/dynamic_keymap.h b/app/src/launcher/dynamic_keymap.h new file mode 100644 index 00000000000..ec476bc4621 --- /dev/null +++ b/app/src/launcher/dynamic_keymap.h @@ -0,0 +1,73 @@ +/* Copyright 2017 Jason Williams (Wilba) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include +#include + +uint8_t dynamic_keymap_get_layer_count(void); +uint16_t dynamic_keymap_key_to_eeprom_address(uint8_t layer, uint8_t row, uint8_t column); +uint16_t dynamic_keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t column); +void dynamic_keymap_set_keycode(uint8_t layer, uint8_t row, uint8_t column, uint16_t keycode); +#ifdef ENCODER_MAP_ENABLE +uint16_t dynamic_keymap_get_encoder(uint8_t layer, uint8_t encoder_id, bool clockwise); +void dynamic_keymap_set_encoder(uint8_t layer, uint8_t encoder_id, bool clockwise, uint16_t keycode); +#endif // ENCODER_MAP_ENABLE +void dynamic_keymap_reset(bool save); +// These get/set the keycodes as stored in the EEPROM buffer +// Data is big-endian 16-bit values (the keycodes) +// Order is by layer/row/column +// Thus offset 0 = 0,0,0, offset MATRIX_COLS*2 = 0,1,0, offset MATRIX_ROWS*MATRIX_COLS*2 = 1,0,0 +// Note the *2, because offset is in bytes and keycodes are two bytes +// This is only really useful for host applications that want to get a whole keymap fast, +// by reading 14 keycodes (28 bytes) at a time, reducing the number of raw HID transfers by +// a factor of 14. +void dynamic_keymap_get_buffer(uint16_t offset, uint16_t size, uint8_t *data); +void dynamic_keymap_set_buffer(uint16_t offset, uint16_t size, uint8_t *data); + +// This overrides the one in quantum/keymap_common.c +// uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key); + +// Note regarding dynamic_keymap_macro_set_buffer(): +// The last byte of the buffer is used as a valid flag, +// so macro sending is disabled during writing a new buffer, +// should it happen during, or after an interrupted transfer. +// +// Users writing to the buffer must first set the last byte of the buffer +// to non-zero (i.e. 0xFF). After (or during) the final write, set the +// last byte of the buffer to zero. +// +// Since the contents of the buffer must be a list of null terminated +// strings, the last byte must be a null when at maximum capacity, +// and it not being null means the buffer can be considered in an +// invalid state. +// +// The buffer *may* contain less macro strings than the maximum. +// This allows a higher maximum number of macros without requiring that +// number of nulls to be in the buffer. +// Note: dynamic_keymap_macro_get_count() returns the maximum that *can* be +// stored, not the current count of macros in the buffer. + +uint8_t dynamic_keymap_macro_get_count(void); +uint16_t dynamic_keymap_macro_get_buffer_size(void); +void dynamic_keymap_macro_get_buffer(uint16_t offset, uint16_t size, uint8_t *data); +void dynamic_keymap_macro_set_buffer(uint16_t offset, uint16_t size, uint8_t *data); +void dynamic_keymap_macro_reset(bool save); + +void dynamic_keymap_macro_send(uint8_t id); +void dynamic_keymap_set_keycode_no_update(uint8_t layer, uint8_t row, uint8_t column, uint16_t keycode); +void dynamic_keymap_set_keycode(uint8_t layer, uint8_t row, uint8_t column, uint16_t keycode); +uint16_t keycode_at_keymap_location_raw(uint8_t layer_num, uint8_t row, uint8_t column); \ No newline at end of file diff --git a/app/src/launcher/dynamic_macro.h b/app/src/launcher/dynamic_macro.h new file mode 100644 index 00000000000..64c532e6ce5 --- /dev/null +++ b/app/src/launcher/dynamic_macro.h @@ -0,0 +1,264 @@ +/* Copyright 2016 Jack Humbert + * + * 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 . + */ + +/* Author: Wojciech Siewierski < wojciech dot siewierski at onet dot pl > */ +#pragma once + +/* Warn users that this is now deprecated and they should use the core feature instead. */ +#pragma message "Dynamic Macros is now a core feature. See updated documentation to see how to configure it: https://docs.qmk.fm/#/feature_dynamic_macros" + +#include "action_layer.h" + +#ifndef DYNAMIC_MACRO_SIZE +/* May be overridden with a custom value. Be aware that the effective + * macro length is half of this value: each keypress is recorded twice + * because of the down-event and up-event. This is not a bug, it's the + * intended behavior. + * + * Usually it should be fine to set the macro size to at least 256 but + * there have been reports of it being too much in some users' cases, + * so 128 is considered a safe default. + */ +# define DYNAMIC_MACRO_SIZE 128 +#endif + +/* Blink the LEDs to notify the user about some event. */ +void dynamic_macro_led_blink(void) { +#ifdef BACKLIGHT_ENABLE + backlight_toggle(); + wait_ms(100); + backlight_toggle(); +#endif +} + +/* Convenience macros used for retrieving the debug info. All of them + * need a `direction` variable accessible at the call site. + */ +#define DYNAMIC_MACRO_CURRENT_SLOT() (direction > 0 ? 1 : 2) +#define DYNAMIC_MACRO_CURRENT_LENGTH(BEGIN, POINTER) ((int)(direction * ((POINTER) - (BEGIN)))) +#define DYNAMIC_MACRO_CURRENT_CAPACITY(BEGIN, END2) ((int)(direction * ((END2) - (BEGIN)) + 1)) + +/** + * Start recording of the dynamic macro. + * + * @param[out] macro_pointer The new macro buffer iterator. + * @param[in] macro_buffer The macro buffer used to initialize macro_pointer. + */ +void dynamic_macro_record_start(keyrecord_t **macro_pointer, keyrecord_t *macro_buffer) { + dprintln("dynamic macro recording: started"); + + dynamic_macro_led_blink(); + + clear_keyboard(); + layer_clear(); + *macro_pointer = macro_buffer; +} + +/** + * Play the dynamic macro. + * + * @param macro_buffer[in] The beginning of the macro buffer being played. + * @param macro_end[in] The element after the last macro buffer element. + * @param direction[in] Either +1 or -1, which way to iterate the buffer. + */ +void dynamic_macro_play(keyrecord_t *macro_buffer, keyrecord_t *macro_end, int8_t direction) { + dprintf("dynamic macro: slot %d playback\n", DYNAMIC_MACRO_CURRENT_SLOT()); + + uint32_t saved_layer_state = layer_state; + + clear_keyboard(); + layer_clear(); + + while (macro_buffer != macro_end) { + process_record(macro_buffer); + macro_buffer += direction; + } + + clear_keyboard(); + + layer_state = saved_layer_state; +} + +/** + * Record a single key in a dynamic macro. + * + * @param macro_buffer[in] The start of the used macro buffer. + * @param macro_pointer[in,out] The current buffer position. + * @param macro2_end[in] The end of the other macro. + * @param direction[in] Either +1 or -1, which way to iterate the buffer. + * @param record[in] The current keypress. + */ +void dynamic_macro_record_key(keyrecord_t *macro_buffer, keyrecord_t **macro_pointer, keyrecord_t *macro2_end, int8_t direction, keyrecord_t *record) { + /* If we've just started recording, ignore all the key releases. */ + if (!record->event.pressed && *macro_pointer == macro_buffer) { + dprintln("dynamic macro: ignoring a leading key-up event"); + return; + } + + /* The other end of the other macro is the last buffer element it + * is safe to use before overwriting the other macro. + */ + if (*macro_pointer - direction != macro2_end) { + **macro_pointer = *record; + *macro_pointer += direction; + } else { + dynamic_macro_led_blink(); + } + + dprintf("dynamic macro: slot %d length: %d/%d\n", DYNAMIC_MACRO_CURRENT_SLOT(), DYNAMIC_MACRO_CURRENT_LENGTH(macro_buffer, *macro_pointer), DYNAMIC_MACRO_CURRENT_CAPACITY(macro_buffer, macro2_end)); +} + +/** + * End recording of the dynamic macro. Essentially just update the + * pointer to the end of the macro. + */ +void dynamic_macro_record_end(keyrecord_t *macro_buffer, keyrecord_t *macro_pointer, int8_t direction, keyrecord_t **macro_end) { + dynamic_macro_led_blink(); + + /* Do not save the keys being held when stopping the recording, + * i.e. the keys used to access the layer DM_RSTP is on. + */ + while (macro_pointer != macro_buffer && (macro_pointer - direction)->event.pressed) { + dprintln("dynamic macro: trimming a trailing key-down event"); + macro_pointer -= direction; + } + + dprintf("dynamic macro: slot %d saved, length: %d\n", DYNAMIC_MACRO_CURRENT_SLOT(), DYNAMIC_MACRO_CURRENT_LENGTH(macro_buffer, macro_pointer)); + + *macro_end = macro_pointer; +} + +/* Handle the key events related to the dynamic macros. Should be + * called from process_record_user() like this: + * + * bool process_record_user(uint16_t keycode, keyrecord_t *record) { + * if (!process_record_dynamic_macro(keycode, record)) { + * return false; + * } + * <...THE REST OF THE FUNCTION...> + * } + */ +bool process_record_dynamic_macro(uint16_t keycode, keyrecord_t *record) { + /* Both macros use the same buffer but read/write on different + * ends of it. + * + * Macro1 is written left-to-right starting from the beginning of + * the buffer. + * + * Macro2 is written right-to-left starting from the end of the + * buffer. + * + * ¯o_buffer macro_end + * v v + * +------------------------------------------------------------+ + * |>>>>>> MACRO1 >>>>>> <<<<<<<<<<<<< MACRO2 <<<<<<<<<<<<<| + * +------------------------------------------------------------+ + * ^ ^ + * r_macro_end r_macro_buffer + * + * During the recording when one macro encounters the end of the + * other macro, the recording is stopped. Apart from this, there + * are no arbitrary limits for the macros' length in relation to + * each other: for example one can either have two medium sized + * macros or one long macro and one short macro. Or even one empty + * and one using the whole buffer. + */ + static keyrecord_t macro_buffer[DYNAMIC_MACRO_SIZE]; + + /* Pointer to the first buffer element after the first macro. + * Initially points to the very beginning of the buffer since the + * macro is empty. */ + static keyrecord_t *macro_end = macro_buffer; + + /* The other end of the macro buffer. Serves as the beginning of + * the second macro. */ + static keyrecord_t *const r_macro_buffer = macro_buffer + DYNAMIC_MACRO_SIZE - 1; + + /* Like macro_end but for the second macro. */ + static keyrecord_t *r_macro_end = r_macro_buffer; + + /* A persistent pointer to the current macro position (iterator) + * used during the recording. */ + static keyrecord_t *macro_pointer = NULL; + + /* 0 - no macro is being recorded right now + * 1,2 - either macro 1 or 2 is being recorded */ + static uint8_t macro_id = 0; + + if (macro_id == 0) { + /* No macro recording in progress. */ + if (!record->event.pressed) { + switch (keycode) { + case QK_DYNAMIC_MACRO_RECORD_START_1: + dynamic_macro_record_start(¯o_pointer, macro_buffer); + macro_id = 1; + return false; + case QK_DYNAMIC_MACRO_RECORD_START_2: + dynamic_macro_record_start(¯o_pointer, r_macro_buffer); + macro_id = 2; + return false; + case QK_DYNAMIC_MACRO_PLAY_1: + dynamic_macro_play(macro_buffer, macro_end, +1); + return false; + case QK_DYNAMIC_MACRO_PLAY_2: + dynamic_macro_play(r_macro_buffer, r_macro_end, -1); + return false; + } + } + } else { + /* A macro is being recorded right now. */ + switch (keycode) { + case QK_DYNAMIC_MACRO_RECORD_STOP: + /* Stop the macro recording. */ + if (record->event.pressed) { /* Ignore the initial release + * just after the recoding + * starts. */ + switch (macro_id) { + case 1: + dynamic_macro_record_end(macro_buffer, macro_pointer, +1, ¯o_end); + break; + case 2: + dynamic_macro_record_end(r_macro_buffer, macro_pointer, -1, &r_macro_end); + break; + } + macro_id = 0; + } + return false; + case QK_DYNAMIC_MACRO_PLAY_1: + case QK_DYNAMIC_MACRO_PLAY_2: + dprintln("dynamic macro: ignoring macro play key while recording"); + return false; + default: + /* Store the key in the macro buffer and process it normally. */ + switch (macro_id) { + case 1: + dynamic_macro_record_key(macro_buffer, ¯o_pointer, r_macro_end, +1, record); + break; + case 2: + dynamic_macro_record_key(r_macro_buffer, ¯o_pointer, macro_end, -1, record); + break; + } + return true; + break; + } + } + + return true; +} + +#undef DYNAMIC_MACRO_CURRENT_SLOT +#undef DYNAMIC_MACRO_CURRENT_LENGTH +#undef DYNAMIC_MACRO_CURRENT_CAPACITY diff --git a/app/src/launcher/keycodes.h b/app/src/launcher/keycodes.h new file mode 100644 index 00000000000..da0d887f0c6 --- /dev/null +++ b/app/src/launcher/keycodes.h @@ -0,0 +1,1519 @@ +// Copyright 2023 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +/******************************************************************************* + 88888888888 888 d8b .d888 d8b 888 d8b + 888 888 Y8P d88P" Y8P 888 Y8P + 888 888 888 888 + 888 88888b. 888 .d8888b 888888 888 888 .d88b. 888 .d8888b + 888 888 "88b 888 88K 888 888 888 d8P Y8b 888 88K + 888 888 888 888 "Y8888b. 888 888 888 88888888 888 "Y8888b. + 888 888 888 888 X88 888 888 888 Y8b. 888 X88 + 888 888 888 888 88888P' 888 888 888 "Y8888 888 88888P' + 888 888 + 888 888 + 888 888 + .d88b. .d88b. 88888b. .d88b. 888d888 8888b. 888888 .d88b. .d88888 + d88P"88b d8P Y8b 888 "88b d8P Y8b 888P" "88b 888 d8P Y8b d88" 888 + 888 888 88888888 888 888 88888888 888 .d888888 888 88888888 888 888 + Y88b 888 Y8b. 888 888 Y8b. 888 888 888 Y88b. Y8b. Y88b 888 + "Y88888 "Y8888 888 888 "Y8888 888 "Y888888 "Y888 "Y8888 "Y88888 + 888 + Y8b d88P + "Y88P" +*******************************************************************************/ + +#pragma once +// clang-format off + +enum qk_keycode_ranges { +// Ranges + QK_BASIC = 0x0000, + QK_BASIC_MAX = 0x00FF, + QK_MODS = 0x0100, + QK_MODS_MAX = 0x1FFF, + QK_MOD_TAP = 0x2000, + QK_MOD_TAP_MAX = 0x3FFF, + QK_LAYER_TAP = 0x4000, + QK_LAYER_TAP_MAX = 0x4FFF, + QK_LAYER_MOD = 0x5000, + QK_LAYER_MOD_MAX = 0x51FF, + QK_TO = 0x5200, + QK_TO_MAX = 0x521F, + QK_MOMENTARY = 0x5220, + QK_MOMENTARY_MAX = 0x523F, + QK_DEF_LAYER = 0x5240, + QK_DEF_LAYER_MAX = 0x525F, + QK_TOGGLE_LAYER = 0x5260, + QK_TOGGLE_LAYER_MAX = 0x527F, + QK_ONE_SHOT_LAYER = 0x5280, + QK_ONE_SHOT_LAYER_MAX = 0x529F, + QK_ONE_SHOT_MOD = 0x52A0, + QK_ONE_SHOT_MOD_MAX = 0x52BF, + QK_LAYER_TAP_TOGGLE = 0x52C0, + QK_LAYER_TAP_TOGGLE_MAX = 0x52DF, + QK_SWAP_HANDS = 0x5600, + QK_SWAP_HANDS_MAX = 0x56FF, + QK_TAP_DANCE = 0x5700, + QK_TAP_DANCE_MAX = 0x57FF, + QK_MAGIC = 0x7000, + QK_MAGIC_MAX = 0x70FF, + QK_MIDI = 0x7100, + QK_MIDI_MAX = 0x71FF, + QK_SEQUENCER = 0x7200, + QK_SEQUENCER_MAX = 0x73FF, + QK_JOYSTICK = 0x7400, + QK_JOYSTICK_MAX = 0x743F, + QK_PROGRAMMABLE_BUTTON = 0x7440, + QK_PROGRAMMABLE_BUTTON_MAX = 0x747F, + QK_AUDIO = 0x7480, + QK_AUDIO_MAX = 0x74BF, + QK_STENO = 0x74C0, + QK_STENO_MAX = 0x74FF, + QK_MACRO = 0x7700, + QK_MACRO_MAX = 0x777F, + QK_LIGHTING = 0x7800, + QK_LIGHTING_MAX = 0x78FF, + QK_QUANTUM = 0x7C00, + QK_QUANTUM_MAX = 0x7DFF, + QK_KB = 0x7E00, + QK_KB_MAX = 0x7E3F, + QK_USER = 0x7E40, + QK_USER_MAX = 0x7FFF, + QK_UNICODEMAP = 0x8000, + QK_UNICODEMAP_MAX = 0xBFFF, + QK_UNICODE = 0x8000, + QK_UNICODE_MAX = 0xFFFF, + QK_UNICODEMAP_PAIR = 0xC000, + QK_UNICODEMAP_PAIR_MAX = 0xFFFF, +}; + +enum qk_keycode_defines { +// Keycodes + KC_NO = 0x0000, + KC_TRANSPARENT = 0x0001, + KC_A = 0x0004, + KC_B = 0x0005, + KC_C = 0x0006, + KC_D = 0x0007, + KC_E = 0x0008, + KC_F = 0x0009, + KC_G = 0x000A, + KC_H = 0x000B, + KC_I = 0x000C, + KC_J = 0x000D, + KC_K = 0x000E, + KC_L = 0x000F, + KC_M = 0x0010, + KC_N = 0x0011, + KC_O = 0x0012, + KC_P = 0x0013, + KC_Q = 0x0014, + KC_R = 0x0015, + KC_S = 0x0016, + KC_T = 0x0017, + KC_U = 0x0018, + KC_V = 0x0019, + KC_W = 0x001A, + KC_X = 0x001B, + KC_Y = 0x001C, + KC_Z = 0x001D, + KC_1 = 0x001E, + KC_2 = 0x001F, + KC_3 = 0x0020, + KC_4 = 0x0021, + KC_5 = 0x0022, + KC_6 = 0x0023, + KC_7 = 0x0024, + KC_8 = 0x0025, + KC_9 = 0x0026, + KC_0 = 0x0027, + KC_ENTER = 0x0028, + KC_ESCAPE = 0x0029, + KC_BACKSPACE = 0x002A, + KC_TAB = 0x002B, + KC_SPACE = 0x002C, + KC_MINUS = 0x002D, + KC_EQUAL = 0x002E, + KC_LEFT_BRACKET = 0x002F, + KC_RIGHT_BRACKET = 0x0030, + KC_BACKSLASH = 0x0031, + KC_NONUS_HASH = 0x0032, + KC_SEMICOLON = 0x0033, + KC_QUOTE = 0x0034, + KC_GRAVE = 0x0035, + KC_COMMA = 0x0036, + KC_DOT = 0x0037, + KC_SLASH = 0x0038, + KC_CAPS_LOCK = 0x0039, + KC_F1 = 0x003A, + KC_F2 = 0x003B, + KC_F3 = 0x003C, + KC_F4 = 0x003D, + KC_F5 = 0x003E, + KC_F6 = 0x003F, + KC_F7 = 0x0040, + KC_F8 = 0x0041, + KC_F9 = 0x0042, + KC_F10 = 0x0043, + KC_F11 = 0x0044, + KC_F12 = 0x0045, + KC_PRINT_SCREEN = 0x0046, + KC_SCROLL_LOCK = 0x0047, + KC_PAUSE = 0x0048, + KC_INSERT = 0x0049, + KC_HOME = 0x004A, + KC_PAGE_UP = 0x004B, + KC_DELETE = 0x004C, + KC_END = 0x004D, + KC_PAGE_DOWN = 0x004E, + KC_RIGHT = 0x004F, + KC_LEFT = 0x0050, + KC_DOWN = 0x0051, + KC_UP = 0x0052, + KC_NUM_LOCK = 0x0053, + KC_KP_SLASH = 0x0054, + KC_KP_ASTERISK = 0x0055, + KC_KP_MINUS = 0x0056, + KC_KP_PLUS = 0x0057, + KC_KP_ENTER = 0x0058, + KC_KP_1 = 0x0059, + KC_KP_2 = 0x005A, + KC_KP_3 = 0x005B, + KC_KP_4 = 0x005C, + KC_KP_5 = 0x005D, + KC_KP_6 = 0x005E, + KC_KP_7 = 0x005F, + KC_KP_8 = 0x0060, + KC_KP_9 = 0x0061, + KC_KP_0 = 0x0062, + KC_KP_DOT = 0x0063, + KC_NONUS_BACKSLASH = 0x0064, + KC_APPLICATION = 0x0065, + KC_KB_POWER = 0x0066, + KC_KP_EQUAL = 0x0067, + KC_F13 = 0x0068, + KC_F14 = 0x0069, + KC_F15 = 0x006A, + KC_F16 = 0x006B, + KC_F17 = 0x006C, + KC_F18 = 0x006D, + KC_F19 = 0x006E, + KC_F20 = 0x006F, + KC_F21 = 0x0070, + KC_F22 = 0x0071, + KC_F23 = 0x0072, + KC_F24 = 0x0073, + KC_EXECUTE = 0x0074, + KC_HELP = 0x0075, + KC_MENU = 0x0076, + KC_SELECT = 0x0077, + KC_STOP = 0x0078, + KC_AGAIN = 0x0079, + KC_UNDO = 0x007A, + KC_CUT = 0x007B, + KC_COPY = 0x007C, + KC_PASTE = 0x007D, + KC_FIND = 0x007E, + KC_KB_MUTE = 0x007F, + KC_KB_VOLUME_UP = 0x0080, + KC_KB_VOLUME_DOWN = 0x0081, + KC_LOCKING_CAPS_LOCK = 0x0082, + KC_LOCKING_NUM_LOCK = 0x0083, + KC_LOCKING_SCROLL_LOCK = 0x0084, + KC_KP_COMMA = 0x0085, + KC_KP_EQUAL_AS400 = 0x0086, + KC_INTERNATIONAL_1 = 0x0087, + KC_INTERNATIONAL_2 = 0x0088, + KC_INTERNATIONAL_3 = 0x0089, + KC_INTERNATIONAL_4 = 0x008A, + KC_INTERNATIONAL_5 = 0x008B, + KC_INTERNATIONAL_6 = 0x008C, + KC_INTERNATIONAL_7 = 0x008D, + KC_INTERNATIONAL_8 = 0x008E, + KC_INTERNATIONAL_9 = 0x008F, + KC_LANGUAGE_1 = 0x0090, + KC_LANGUAGE_2 = 0x0091, + KC_LANGUAGE_3 = 0x0092, + KC_LANGUAGE_4 = 0x0093, + KC_LANGUAGE_5 = 0x0094, + KC_LANGUAGE_6 = 0x0095, + KC_LANGUAGE_7 = 0x0096, + KC_LANGUAGE_8 = 0x0097, + KC_LANGUAGE_9 = 0x0098, + KC_ALTERNATE_ERASE = 0x0099, + KC_SYSTEM_REQUEST = 0x009A, + KC_CANCEL = 0x009B, + KC_CLEAR = 0x009C, + KC_PRIOR = 0x009D, + KC_RETURN = 0x009E, + KC_SEPARATOR = 0x009F, + KC_OUT = 0x00A0, + KC_OPER = 0x00A1, + KC_CLEAR_AGAIN = 0x00A2, + KC_CRSEL = 0x00A3, + KC_EXSEL = 0x00A4, + KC_SYSTEM_POWER = 0x00A5, + KC_SYSTEM_SLEEP = 0x00A6, + KC_SYSTEM_WAKE = 0x00A7, + KC_AUDIO_MUTE = 0x00A8, + KC_AUDIO_VOL_UP = 0x00A9, + KC_AUDIO_VOL_DOWN = 0x00AA, + KC_MEDIA_NEXT_TRACK = 0x00AB, + KC_MEDIA_PREV_TRACK = 0x00AC, + KC_MEDIA_STOP = 0x00AD, + KC_MEDIA_PLAY_PAUSE = 0x00AE, + KC_MEDIA_SELECT = 0x00AF, + KC_MEDIA_EJECT = 0x00B0, + KC_MAIL = 0x00B1, + KC_CALCULATOR = 0x00B2, + KC_MY_COMPUTER = 0x00B3, + KC_WWW_SEARCH = 0x00B4, + KC_WWW_HOME = 0x00B5, + KC_WWW_BACK = 0x00B6, + KC_WWW_FORWARD = 0x00B7, + KC_WWW_STOP = 0x00B8, + KC_WWW_REFRESH = 0x00B9, + KC_WWW_FAVORITES = 0x00BA, + KC_MEDIA_FAST_FORWARD = 0x00BB, + KC_MEDIA_REWIND = 0x00BC, + KC_BRIGHTNESS_UP = 0x00BD, + KC_BRIGHTNESS_DOWN = 0x00BE, + KC_CONTROL_PANEL = 0x00BF, + KC_ASSISTANT = 0x00C0, + KC_MISSION_CONTROL = 0x00C1, + KC_LAUNCHPAD = 0x00C2, + KC_MS_UP = 0x00CD, + KC_MS_DOWN = 0x00CE, + KC_MS_LEFT = 0x00CF, + KC_MS_RIGHT = 0x00D0, + KC_MS_BTN1 = 0x00D1, + KC_MS_BTN2 = 0x00D2, + KC_MS_BTN3 = 0x00D3, + KC_MS_BTN4 = 0x00D4, + KC_MS_BTN5 = 0x00D5, + KC_MS_BTN6 = 0x00D6, + KC_MS_BTN7 = 0x00D7, + KC_MS_BTN8 = 0x00D8, + KC_MS_WH_UP = 0x00D9, + KC_MS_WH_DOWN = 0x00DA, + KC_MS_WH_LEFT = 0x00DB, + KC_MS_WH_RIGHT = 0x00DC, + KC_MS_ACCEL0 = 0x00DD, + KC_MS_ACCEL1 = 0x00DE, + KC_MS_ACCEL2 = 0x00DF, + KC_LEFT_CTRL = 0x00E0, + KC_LEFT_SHIFT = 0x00E1, + KC_LEFT_ALT = 0x00E2, + KC_LEFT_GUI = 0x00E3, + KC_RIGHT_CTRL = 0x00E4, + KC_RIGHT_SHIFT = 0x00E5, + KC_RIGHT_ALT = 0x00E6, + KC_RIGHT_GUI = 0x00E7, + QK_SWAP_HANDS_TOGGLE = 0x56F0, + QK_SWAP_HANDS_TAP_TOGGLE = 0x56F1, + QK_SWAP_HANDS_MOMENTARY_ON = 0x56F2, + QK_SWAP_HANDS_MOMENTARY_OFF = 0x56F3, + QK_SWAP_HANDS_OFF = 0x56F4, + QK_SWAP_HANDS_ON = 0x56F5, + QK_SWAP_HANDS_ONE_SHOT = 0x56F6, + QK_MAGIC_SWAP_CONTROL_CAPS_LOCK = 0x7000, + QK_MAGIC_UNSWAP_CONTROL_CAPS_LOCK = 0x7001, + QK_MAGIC_TOGGLE_CONTROL_CAPS_LOCK = 0x7002, + QK_MAGIC_CAPS_LOCK_AS_CONTROL_OFF = 0x7003, + QK_MAGIC_CAPS_LOCK_AS_CONTROL_ON = 0x7004, + QK_MAGIC_SWAP_LALT_LGUI = 0x7005, + QK_MAGIC_UNSWAP_LALT_LGUI = 0x7006, + QK_MAGIC_SWAP_RALT_RGUI = 0x7007, + QK_MAGIC_UNSWAP_RALT_RGUI = 0x7008, + QK_MAGIC_GUI_ON = 0x7009, + QK_MAGIC_GUI_OFF = 0x700A, + QK_MAGIC_TOGGLE_GUI = 0x700B, + QK_MAGIC_SWAP_GRAVE_ESC = 0x700C, + QK_MAGIC_UNSWAP_GRAVE_ESC = 0x700D, + QK_MAGIC_SWAP_BACKSLASH_BACKSPACE = 0x700E, + QK_MAGIC_UNSWAP_BACKSLASH_BACKSPACE = 0x700F, + QK_MAGIC_TOGGLE_BACKSLASH_BACKSPACE = 0x7010, + QK_MAGIC_NKRO_ON = 0x7011, + QK_MAGIC_NKRO_OFF = 0x7012, + QK_MAGIC_TOGGLE_NKRO = 0x7013, + QK_MAGIC_SWAP_ALT_GUI = 0x7014, + QK_MAGIC_UNSWAP_ALT_GUI = 0x7015, + QK_MAGIC_TOGGLE_ALT_GUI = 0x7016, + QK_MAGIC_SWAP_LCTL_LGUI = 0x7017, + QK_MAGIC_UNSWAP_LCTL_LGUI = 0x7018, + QK_MAGIC_SWAP_RCTL_RGUI = 0x7019, + QK_MAGIC_UNSWAP_RCTL_RGUI = 0x701A, + QK_MAGIC_SWAP_CTL_GUI = 0x701B, + QK_MAGIC_UNSWAP_CTL_GUI = 0x701C, + QK_MAGIC_TOGGLE_CTL_GUI = 0x701D, + QK_MAGIC_EE_HANDS_LEFT = 0x701E, + QK_MAGIC_EE_HANDS_RIGHT = 0x701F, + QK_MAGIC_SWAP_ESCAPE_CAPS_LOCK = 0x7020, + QK_MAGIC_UNSWAP_ESCAPE_CAPS_LOCK = 0x7021, + QK_MAGIC_TOGGLE_ESCAPE_CAPS_LOCK = 0x7022, + QK_MIDI_ON = 0x7100, + QK_MIDI_OFF = 0x7101, + QK_MIDI_TOGGLE = 0x7102, + QK_MIDI_NOTE_C_0 = 0x7103, + QK_MIDI_NOTE_C_SHARP_0 = 0x7104, + QK_MIDI_NOTE_D_0 = 0x7105, + QK_MIDI_NOTE_D_SHARP_0 = 0x7106, + QK_MIDI_NOTE_E_0 = 0x7107, + QK_MIDI_NOTE_F_0 = 0x7108, + QK_MIDI_NOTE_F_SHARP_0 = 0x7109, + QK_MIDI_NOTE_G_0 = 0x710A, + QK_MIDI_NOTE_G_SHARP_0 = 0x710B, + QK_MIDI_NOTE_A_0 = 0x710C, + QK_MIDI_NOTE_A_SHARP_0 = 0x710D, + QK_MIDI_NOTE_B_0 = 0x710E, + QK_MIDI_NOTE_C_1 = 0x710F, + QK_MIDI_NOTE_C_SHARP_1 = 0x7110, + QK_MIDI_NOTE_D_1 = 0x7111, + QK_MIDI_NOTE_D_SHARP_1 = 0x7112, + QK_MIDI_NOTE_E_1 = 0x7113, + QK_MIDI_NOTE_F_1 = 0x7114, + QK_MIDI_NOTE_F_SHARP_1 = 0x7115, + QK_MIDI_NOTE_G_1 = 0x7116, + QK_MIDI_NOTE_G_SHARP_1 = 0x7117, + QK_MIDI_NOTE_A_1 = 0x7118, + QK_MIDI_NOTE_A_SHARP_1 = 0x7119, + QK_MIDI_NOTE_B_1 = 0x711A, + QK_MIDI_NOTE_C_2 = 0x711B, + QK_MIDI_NOTE_C_SHARP_2 = 0x711C, + QK_MIDI_NOTE_D_2 = 0x711D, + QK_MIDI_NOTE_D_SHARP_2 = 0x711E, + QK_MIDI_NOTE_E_2 = 0x711F, + QK_MIDI_NOTE_F_2 = 0x7120, + QK_MIDI_NOTE_F_SHARP_2 = 0x7121, + QK_MIDI_NOTE_G_2 = 0x7122, + QK_MIDI_NOTE_G_SHARP_2 = 0x7123, + QK_MIDI_NOTE_A_2 = 0x7124, + QK_MIDI_NOTE_A_SHARP_2 = 0x7125, + QK_MIDI_NOTE_B_2 = 0x7126, + QK_MIDI_NOTE_C_3 = 0x7127, + QK_MIDI_NOTE_C_SHARP_3 = 0x7128, + QK_MIDI_NOTE_D_3 = 0x7129, + QK_MIDI_NOTE_D_SHARP_3 = 0x712A, + QK_MIDI_NOTE_E_3 = 0x712B, + QK_MIDI_NOTE_F_3 = 0x712C, + QK_MIDI_NOTE_F_SHARP_3 = 0x712D, + QK_MIDI_NOTE_G_3 = 0x712E, + QK_MIDI_NOTE_G_SHARP_3 = 0x712F, + QK_MIDI_NOTE_A_3 = 0x7130, + QK_MIDI_NOTE_A_SHARP_3 = 0x7131, + QK_MIDI_NOTE_B_3 = 0x7132, + QK_MIDI_NOTE_C_4 = 0x7133, + QK_MIDI_NOTE_C_SHARP_4 = 0x7134, + QK_MIDI_NOTE_D_4 = 0x7135, + QK_MIDI_NOTE_D_SHARP_4 = 0x7136, + QK_MIDI_NOTE_E_4 = 0x7137, + QK_MIDI_NOTE_F_4 = 0x7138, + QK_MIDI_NOTE_F_SHARP_4 = 0x7139, + QK_MIDI_NOTE_G_4 = 0x713A, + QK_MIDI_NOTE_G_SHARP_4 = 0x713B, + QK_MIDI_NOTE_A_4 = 0x713C, + QK_MIDI_NOTE_A_SHARP_4 = 0x713D, + QK_MIDI_NOTE_B_4 = 0x713E, + QK_MIDI_NOTE_C_5 = 0x713F, + QK_MIDI_NOTE_C_SHARP_5 = 0x7140, + QK_MIDI_NOTE_D_5 = 0x7141, + QK_MIDI_NOTE_D_SHARP_5 = 0x7142, + QK_MIDI_NOTE_E_5 = 0x7143, + QK_MIDI_NOTE_F_5 = 0x7144, + QK_MIDI_NOTE_F_SHARP_5 = 0x7145, + QK_MIDI_NOTE_G_5 = 0x7146, + QK_MIDI_NOTE_G_SHARP_5 = 0x7147, + QK_MIDI_NOTE_A_5 = 0x7148, + QK_MIDI_NOTE_A_SHARP_5 = 0x7149, + QK_MIDI_NOTE_B_5 = 0x714A, + QK_MIDI_OCTAVE_N2 = 0x714B, + QK_MIDI_OCTAVE_N1 = 0x714C, + QK_MIDI_OCTAVE_0 = 0x714D, + QK_MIDI_OCTAVE_1 = 0x714E, + QK_MIDI_OCTAVE_2 = 0x714F, + QK_MIDI_OCTAVE_3 = 0x7150, + QK_MIDI_OCTAVE_4 = 0x7151, + QK_MIDI_OCTAVE_5 = 0x7152, + QK_MIDI_OCTAVE_6 = 0x7153, + QK_MIDI_OCTAVE_7 = 0x7154, + QK_MIDI_OCTAVE_DOWN = 0x7155, + QK_MIDI_OCTAVE_UP = 0x7156, + QK_MIDI_TRANSPOSE_N6 = 0x7157, + QK_MIDI_TRANSPOSE_N5 = 0x7158, + QK_MIDI_TRANSPOSE_N4 = 0x7159, + QK_MIDI_TRANSPOSE_N3 = 0x715A, + QK_MIDI_TRANSPOSE_N2 = 0x715B, + QK_MIDI_TRANSPOSE_N1 = 0x715C, + QK_MIDI_TRANSPOSE_0 = 0x715D, + QK_MIDI_TRANSPOSE_1 = 0x715E, + QK_MIDI_TRANSPOSE_2 = 0x715F, + QK_MIDI_TRANSPOSE_3 = 0x7160, + QK_MIDI_TRANSPOSE_4 = 0x7161, + QK_MIDI_TRANSPOSE_5 = 0x7162, + QK_MIDI_TRANSPOSE_6 = 0x7163, + QK_MIDI_TRANSPOSE_DOWN = 0x7164, + QK_MIDI_TRANSPOSE_UP = 0x7165, + QK_MIDI_VELOCITY_0 = 0x7166, + QK_MIDI_VELOCITY_1 = 0x7167, + QK_MIDI_VELOCITY_2 = 0x7168, + QK_MIDI_VELOCITY_3 = 0x7169, + QK_MIDI_VELOCITY_4 = 0x716A, + QK_MIDI_VELOCITY_5 = 0x716B, + QK_MIDI_VELOCITY_6 = 0x716C, + QK_MIDI_VELOCITY_7 = 0x716D, + QK_MIDI_VELOCITY_8 = 0x716E, + QK_MIDI_VELOCITY_9 = 0x716F, + QK_MIDI_VELOCITY_10 = 0x7170, + QK_MIDI_VELOCITY_DOWN = 0x7171, + QK_MIDI_VELOCITY_UP = 0x7172, + QK_MIDI_CHANNEL_1 = 0x7173, + QK_MIDI_CHANNEL_2 = 0x7174, + QK_MIDI_CHANNEL_3 = 0x7175, + QK_MIDI_CHANNEL_4 = 0x7176, + QK_MIDI_CHANNEL_5 = 0x7177, + QK_MIDI_CHANNEL_6 = 0x7178, + QK_MIDI_CHANNEL_7 = 0x7179, + QK_MIDI_CHANNEL_8 = 0x717A, + QK_MIDI_CHANNEL_9 = 0x717B, + QK_MIDI_CHANNEL_10 = 0x717C, + QK_MIDI_CHANNEL_11 = 0x717D, + QK_MIDI_CHANNEL_12 = 0x717E, + QK_MIDI_CHANNEL_13 = 0x717F, + QK_MIDI_CHANNEL_14 = 0x7180, + QK_MIDI_CHANNEL_15 = 0x7181, + QK_MIDI_CHANNEL_16 = 0x7182, + QK_MIDI_CHANNEL_DOWN = 0x7183, + QK_MIDI_CHANNEL_UP = 0x7184, + QK_MIDI_ALL_NOTES_OFF = 0x7185, + QK_MIDI_SUSTAIN = 0x7186, + QK_MIDI_PORTAMENTO = 0x7187, + QK_MIDI_SOSTENUTO = 0x7188, + QK_MIDI_SOFT = 0x7189, + QK_MIDI_LEGATO = 0x718A, + QK_MIDI_MODULATION = 0x718B, + QK_MIDI_MODULATION_SPEED_DOWN = 0x718C, + QK_MIDI_MODULATION_SPEED_UP = 0x718D, + QK_MIDI_PITCH_BEND_DOWN = 0x718E, + QK_MIDI_PITCH_BEND_UP = 0x718F, + QK_SEQUENCER_ON = 0x7200, + QK_SEQUENCER_OFF = 0x7201, + QK_SEQUENCER_TOGGLE = 0x7202, + QK_SEQUENCER_TEMPO_DOWN = 0x7203, + QK_SEQUENCER_TEMPO_UP = 0x7204, + QK_SEQUENCER_RESOLUTION_DOWN = 0x7205, + QK_SEQUENCER_RESOLUTION_UP = 0x7206, + QK_SEQUENCER_STEPS_ALL = 0x7207, + QK_SEQUENCER_STEPS_CLEAR = 0x7208, + QK_JOYSTICK_BUTTON_0 = 0x7400, + QK_JOYSTICK_BUTTON_1 = 0x7401, + QK_JOYSTICK_BUTTON_2 = 0x7402, + QK_JOYSTICK_BUTTON_3 = 0x7403, + QK_JOYSTICK_BUTTON_4 = 0x7404, + QK_JOYSTICK_BUTTON_5 = 0x7405, + QK_JOYSTICK_BUTTON_6 = 0x7406, + QK_JOYSTICK_BUTTON_7 = 0x7407, + QK_JOYSTICK_BUTTON_8 = 0x7408, + QK_JOYSTICK_BUTTON_9 = 0x7409, + QK_JOYSTICK_BUTTON_10 = 0x740A, + QK_JOYSTICK_BUTTON_11 = 0x740B, + QK_JOYSTICK_BUTTON_12 = 0x740C, + QK_JOYSTICK_BUTTON_13 = 0x740D, + QK_JOYSTICK_BUTTON_14 = 0x740E, + QK_JOYSTICK_BUTTON_15 = 0x740F, + QK_JOYSTICK_BUTTON_16 = 0x7410, + QK_JOYSTICK_BUTTON_17 = 0x7411, + QK_JOYSTICK_BUTTON_18 = 0x7412, + QK_JOYSTICK_BUTTON_19 = 0x7413, + QK_JOYSTICK_BUTTON_20 = 0x7414, + QK_JOYSTICK_BUTTON_21 = 0x7415, + QK_JOYSTICK_BUTTON_22 = 0x7416, + QK_JOYSTICK_BUTTON_23 = 0x7417, + QK_JOYSTICK_BUTTON_24 = 0x7418, + QK_JOYSTICK_BUTTON_25 = 0x7419, + QK_JOYSTICK_BUTTON_26 = 0x741A, + QK_JOYSTICK_BUTTON_27 = 0x741B, + QK_JOYSTICK_BUTTON_28 = 0x741C, + QK_JOYSTICK_BUTTON_29 = 0x741D, + QK_JOYSTICK_BUTTON_30 = 0x741E, + QK_JOYSTICK_BUTTON_31 = 0x741F, + QK_PROGRAMMABLE_BUTTON_1 = 0x7440, + QK_PROGRAMMABLE_BUTTON_2 = 0x7441, + QK_PROGRAMMABLE_BUTTON_3 = 0x7442, + QK_PROGRAMMABLE_BUTTON_4 = 0x7443, + QK_PROGRAMMABLE_BUTTON_5 = 0x7444, + QK_PROGRAMMABLE_BUTTON_6 = 0x7445, + QK_PROGRAMMABLE_BUTTON_7 = 0x7446, + QK_PROGRAMMABLE_BUTTON_8 = 0x7447, + QK_PROGRAMMABLE_BUTTON_9 = 0x7448, + QK_PROGRAMMABLE_BUTTON_10 = 0x7449, + QK_PROGRAMMABLE_BUTTON_11 = 0x744A, + QK_PROGRAMMABLE_BUTTON_12 = 0x744B, + QK_PROGRAMMABLE_BUTTON_13 = 0x744C, + QK_PROGRAMMABLE_BUTTON_14 = 0x744D, + QK_PROGRAMMABLE_BUTTON_15 = 0x744E, + QK_PROGRAMMABLE_BUTTON_16 = 0x744F, + QK_PROGRAMMABLE_BUTTON_17 = 0x7450, + QK_PROGRAMMABLE_BUTTON_18 = 0x7451, + QK_PROGRAMMABLE_BUTTON_19 = 0x7452, + QK_PROGRAMMABLE_BUTTON_20 = 0x7453, + QK_PROGRAMMABLE_BUTTON_21 = 0x7454, + QK_PROGRAMMABLE_BUTTON_22 = 0x7455, + QK_PROGRAMMABLE_BUTTON_23 = 0x7456, + QK_PROGRAMMABLE_BUTTON_24 = 0x7457, + QK_PROGRAMMABLE_BUTTON_25 = 0x7458, + QK_PROGRAMMABLE_BUTTON_26 = 0x7459, + QK_PROGRAMMABLE_BUTTON_27 = 0x745A, + QK_PROGRAMMABLE_BUTTON_28 = 0x745B, + QK_PROGRAMMABLE_BUTTON_29 = 0x745C, + QK_PROGRAMMABLE_BUTTON_30 = 0x745D, + QK_PROGRAMMABLE_BUTTON_31 = 0x745E, + QK_PROGRAMMABLE_BUTTON_32 = 0x745F, + QK_AUDIO_ON = 0x7480, + QK_AUDIO_OFF = 0x7481, + QK_AUDIO_TOGGLE = 0x7482, + QK_AUDIO_CLICKY_TOGGLE = 0x748A, + QK_AUDIO_CLICKY_ON = 0x748B, + QK_AUDIO_CLICKY_OFF = 0x748C, + QK_AUDIO_CLICKY_UP = 0x748D, + QK_AUDIO_CLICKY_DOWN = 0x748E, + QK_AUDIO_CLICKY_RESET = 0x748F, + QK_MUSIC_ON = 0x7490, + QK_MUSIC_OFF = 0x7491, + QK_MUSIC_TOGGLE = 0x7492, + QK_MUSIC_MODE_NEXT = 0x7493, + QK_AUDIO_VOICE_NEXT = 0x7494, + QK_AUDIO_VOICE_PREVIOUS = 0x7495, + QK_STENO_BOLT = 0x74F0, + QK_STENO_GEMINI = 0x74F1, + QK_STENO_COMB = 0x74F2, + QK_STENO_COMB_MAX = 0x74FC, + QK_MACRO_0 = 0x7700, + QK_MACRO_1 = 0x7701, + QK_MACRO_2 = 0x7702, + QK_MACRO_3 = 0x7703, + QK_MACRO_4 = 0x7704, + QK_MACRO_5 = 0x7705, + QK_MACRO_6 = 0x7706, + QK_MACRO_7 = 0x7707, + QK_MACRO_8 = 0x7708, + QK_MACRO_9 = 0x7709, + QK_MACRO_10 = 0x770A, + QK_MACRO_11 = 0x770B, + QK_MACRO_12 = 0x770C, + QK_MACRO_13 = 0x770D, + QK_MACRO_14 = 0x770E, + QK_MACRO_15 = 0x770F, + QK_MACRO_16 = 0x7710, + QK_MACRO_17 = 0x7711, + QK_MACRO_18 = 0x7712, + QK_MACRO_19 = 0x7713, + QK_MACRO_20 = 0x7714, + QK_MACRO_21 = 0x7715, + QK_MACRO_22 = 0x7716, + QK_MACRO_23 = 0x7717, + QK_MACRO_24 = 0x7718, + QK_MACRO_25 = 0x7719, + QK_MACRO_26 = 0x771A, + QK_MACRO_27 = 0x771B, + QK_MACRO_28 = 0x771C, + QK_MACRO_29 = 0x771D, + QK_MACRO_30 = 0x771E, + QK_MACRO_31 = 0x771F, + QK_BACKLIGHT_ON = 0x7800, + QK_BACKLIGHT_OFF = 0x7801, + QK_BACKLIGHT_TOGGLE = 0x7802, + QK_BACKLIGHT_DOWN = 0x7803, + QK_BACKLIGHT_UP = 0x7804, + QK_BACKLIGHT_STEP = 0x7805, + QK_BACKLIGHT_TOGGLE_BREATHING = 0x7806, + RGB_TOG = 0x7820, + RGB_MODE_FORWARD = 0x7821, + RGB_MODE_REVERSE = 0x7822, + RGB_HUI = 0x7823, + RGB_HUD = 0x7824, + RGB_SAI = 0x7825, + RGB_SAD = 0x7826, + RGB_VAI = 0x7827, + RGB_VAD = 0x7828, + RGB_SPI = 0x7829, + RGB_SPD = 0x782A, + RGB_MODE_PLAIN = 0x782B, + RGB_MODE_BREATHE = 0x782C, + RGB_MODE_RAINBOW = 0x782D, + RGB_MODE_SWIRL = 0x782E, + RGB_MODE_SNAKE = 0x782F, + RGB_MODE_KNIGHT = 0x7830, + RGB_MODE_XMAS = 0x7831, + RGB_MODE_GRADIENT = 0x7832, + RGB_MODE_RGBTEST = 0x7833, + RGB_MODE_TWINKLE = 0x7834, + QK_BOOTLOADER = 0x7C00, + QK_REBOOT = 0x7C01, + QK_DEBUG_TOGGLE = 0x7C02, + QK_CLEAR_EEPROM = 0x7C03, + QK_MAKE = 0x7C04, + QK_AUTO_SHIFT_DOWN = 0x7C10, + QK_AUTO_SHIFT_UP = 0x7C11, + QK_AUTO_SHIFT_REPORT = 0x7C12, + QK_AUTO_SHIFT_ON = 0x7C13, + QK_AUTO_SHIFT_OFF = 0x7C14, + QK_AUTO_SHIFT_TOGGLE = 0x7C15, + QK_GRAVE_ESCAPE = 0x7C16, + QK_VELOCIKEY_TOGGLE = 0x7C17, + QK_SPACE_CADET_LEFT_CTRL_PARENTHESIS_OPEN = 0x7C18, + QK_SPACE_CADET_RIGHT_CTRL_PARENTHESIS_CLOSE = 0x7C19, + QK_SPACE_CADET_LEFT_SHIFT_PARENTHESIS_OPEN = 0x7C1A, + QK_SPACE_CADET_RIGHT_SHIFT_PARENTHESIS_CLOSE = 0x7C1B, + QK_SPACE_CADET_LEFT_ALT_PARENTHESIS_OPEN = 0x7C1C, + QK_SPACE_CADET_RIGHT_ALT_PARENTHESIS_CLOSE = 0x7C1D, + QK_SPACE_CADET_RIGHT_SHIFT_ENTER = 0x7C1E, + QK_OUTPUT_AUTO = 0x7C20, + QK_OUTPUT_USB = 0x7C21, + QK_OUTPUT_BLUETOOTH = 0x7C22, + QK_UNICODE_MODE_NEXT = 0x7C30, + QK_UNICODE_MODE_PREVIOUS = 0x7C31, + QK_UNICODE_MODE_MACOS = 0x7C32, + QK_UNICODE_MODE_LINUX = 0x7C33, + QK_UNICODE_MODE_WINDOWS = 0x7C34, + QK_UNICODE_MODE_BSD = 0x7C35, + QK_UNICODE_MODE_WINCOMPOSE = 0x7C36, + QK_UNICODE_MODE_EMACS = 0x7C37, + QK_HAPTIC_ON = 0x7C40, + QK_HAPTIC_OFF = 0x7C41, + QK_HAPTIC_TOGGLE = 0x7C42, + QK_HAPTIC_RESET = 0x7C43, + QK_HAPTIC_FEEDBACK_TOGGLE = 0x7C44, + QK_HAPTIC_BUZZ_TOGGLE = 0x7C45, + QK_HAPTIC_MODE_NEXT = 0x7C46, + QK_HAPTIC_MODE_PREVIOUS = 0x7C47, + QK_HAPTIC_CONTINUOUS_TOGGLE = 0x7C48, + QK_HAPTIC_CONTINUOUS_UP = 0x7C49, + QK_HAPTIC_CONTINUOUS_DOWN = 0x7C4A, + QK_HAPTIC_DWELL_UP = 0x7C4B, + QK_HAPTIC_DWELL_DOWN = 0x7C4C, + QK_COMBO_ON = 0x7C50, + QK_COMBO_OFF = 0x7C51, + QK_COMBO_TOGGLE = 0x7C52, + QK_DYNAMIC_MACRO_RECORD_START_1 = 0x7C53, + QK_DYNAMIC_MACRO_RECORD_START_2 = 0x7C54, + QK_DYNAMIC_MACRO_RECORD_STOP = 0x7C55, + QK_DYNAMIC_MACRO_PLAY_1 = 0x7C56, + QK_DYNAMIC_MACRO_PLAY_2 = 0x7C57, + QK_LEADER = 0x7C58, + QK_LOCK = 0x7C59, + QK_ONE_SHOT_ON = 0x7C5A, + QK_ONE_SHOT_OFF = 0x7C5B, + QK_ONE_SHOT_TOGGLE = 0x7C5C, + QK_KEY_OVERRIDE_TOGGLE = 0x7C5D, + QK_KEY_OVERRIDE_ON = 0x7C5E, + QK_KEY_OVERRIDE_OFF = 0x7C5F, + QK_SECURE_LOCK = 0x7C60, + QK_SECURE_UNLOCK = 0x7C61, + QK_SECURE_TOGGLE = 0x7C62, + QK_SECURE_REQUEST = 0x7C63, + QK_DYNAMIC_TAPPING_TERM_PRINT = 0x7C70, + QK_DYNAMIC_TAPPING_TERM_UP = 0x7C71, + QK_DYNAMIC_TAPPING_TERM_DOWN = 0x7C72, + QK_CAPS_WORD_TOGGLE = 0x7C73, + QK_AUTOCORRECT_ON = 0x7C74, + QK_AUTOCORRECT_OFF = 0x7C75, + QK_AUTOCORRECT_TOGGLE = 0x7C76, + QK_TRI_LAYER_LOWER = 0x7C77, + QK_TRI_LAYER_UPPER = 0x7C78, + QK_REPEAT_KEY = 0x7C79, + QK_ALT_REPEAT_KEY = 0x7C7A, + QK_KB_0 = 0x7E00, + QK_KB_1 = 0x7E01, + QK_KB_2 = 0x7E02, + QK_KB_3 = 0x7E03, + QK_KB_4 = 0x7E04, + QK_KB_5 = 0x7E05, + QK_KB_6 = 0x7E06, + QK_KB_7 = 0x7E07, + QK_KB_8 = 0x7E08, + QK_KB_9 = 0x7E09, + QK_KB_10 = 0x7E0A, + QK_KB_11 = 0x7E0B, + QK_KB_12 = 0x7E0C, + QK_KB_13 = 0x7E0D, + QK_KB_14 = 0x7E0E, + QK_KB_15 = 0x7E0F, + QK_KB_16 = 0x7E10, + QK_KB_17 = 0x7E11, + QK_KB_18 = 0x7E12, + QK_KB_19 = 0x7E13, + QK_KB_20 = 0x7E14, + QK_KB_21 = 0x7E15, + QK_KB_22 = 0x7E16, + QK_KB_23 = 0x7E17, + QK_KB_24 = 0x7E18, + QK_KB_25 = 0x7E19, + QK_KB_26 = 0x7E1A, + QK_KB_27 = 0x7E1B, + QK_KB_28 = 0x7E1C, + QK_KB_29 = 0x7E1D, + QK_KB_30 = 0x7E1E, + QK_KB_31 = 0x7E1F, + QK_USER_0 = 0x7E40, + QK_USER_1 = 0x7E41, + QK_USER_2 = 0x7E42, + QK_USER_3 = 0x7E43, + QK_USER_4 = 0x7E44, + QK_USER_5 = 0x7E45, + QK_USER_6 = 0x7E46, + QK_USER_7 = 0x7E47, + QK_USER_8 = 0x7E48, + QK_USER_9 = 0x7E49, + QK_USER_10 = 0x7E4A, + QK_USER_11 = 0x7E4B, + QK_USER_12 = 0x7E4C, + QK_USER_13 = 0x7E4D, + QK_USER_14 = 0x7E4E, + QK_USER_15 = 0x7E4F, + QK_USER_16 = 0x7E50, + QK_USER_17 = 0x7E51, + QK_USER_18 = 0x7E52, + QK_USER_19 = 0x7E53, + QK_USER_20 = 0x7E54, + QK_USER_21 = 0x7E55, + QK_USER_22 = 0x7E56, + QK_USER_23 = 0x7E57, + QK_USER_24 = 0x7E58, + QK_USER_25 = 0x7E59, + QK_USER_26 = 0x7E5A, + QK_USER_27 = 0x7E5B, + QK_USER_28 = 0x7E5C, + QK_USER_29 = 0x7E5D, + QK_USER_30 = 0x7E5E, + QK_USER_31 = 0x7E5F, + +// Alias + XXXXXXX = KC_NO, + _______ = KC_TRANSPARENT, + KC_TRNS = KC_TRANSPARENT, + KC_ENT = KC_ENTER, + KC_ESC = KC_ESCAPE, + KC_BSPC = KC_BACKSPACE, + KC_SPC = KC_SPACE, + KC_MINS = KC_MINUS, + KC_EQL = KC_EQUAL, + KC_LBRC = KC_LEFT_BRACKET, + KC_RBRC = KC_RIGHT_BRACKET, + KC_BSLS = KC_BACKSLASH, + KC_NUHS = KC_NONUS_HASH, + KC_SCLN = KC_SEMICOLON, + KC_QUOT = KC_QUOTE, + KC_GRV = KC_GRAVE, + KC_COMM = KC_COMMA, + KC_SLSH = KC_SLASH, + KC_CAPS = KC_CAPS_LOCK, + KC_PSCR = KC_PRINT_SCREEN, + KC_SCRL = KC_SCROLL_LOCK, + KC_BRMD = KC_SCROLL_LOCK, + KC_PAUS = KC_PAUSE, + KC_BRK = KC_PAUSE, + KC_BRMU = KC_PAUSE, + KC_INS = KC_INSERT, + KC_PGUP = KC_PAGE_UP, + KC_DEL = KC_DELETE, + KC_PGDN = KC_PAGE_DOWN, + KC_RGHT = KC_RIGHT, + KC_NUM = KC_NUM_LOCK, + KC_PSLS = KC_KP_SLASH, + KC_PAST = KC_KP_ASTERISK, + KC_PMNS = KC_KP_MINUS, + KC_PPLS = KC_KP_PLUS, + KC_PENT = KC_KP_ENTER, + KC_P1 = KC_KP_1, + KC_P2 = KC_KP_2, + KC_P3 = KC_KP_3, + KC_P4 = KC_KP_4, + KC_P5 = KC_KP_5, + KC_P6 = KC_KP_6, + KC_P7 = KC_KP_7, + KC_P8 = KC_KP_8, + KC_P9 = KC_KP_9, + KC_P0 = KC_KP_0, + KC_PDOT = KC_KP_DOT, + KC_NUBS = KC_NONUS_BACKSLASH, + KC_APP = KC_APPLICATION, + KC_PEQL = KC_KP_EQUAL, + KC_EXEC = KC_EXECUTE, + KC_SLCT = KC_SELECT, + KC_AGIN = KC_AGAIN, + KC_PSTE = KC_PASTE, + KC_LCAP = KC_LOCKING_CAPS_LOCK, + KC_LNUM = KC_LOCKING_NUM_LOCK, + KC_LSCR = KC_LOCKING_SCROLL_LOCK, + KC_PCMM = KC_KP_COMMA, + KC_INT1 = KC_INTERNATIONAL_1, + KC_INT2 = KC_INTERNATIONAL_2, + KC_INT3 = KC_INTERNATIONAL_3, + KC_INT4 = KC_INTERNATIONAL_4, + KC_INT5 = KC_INTERNATIONAL_5, + KC_INT6 = KC_INTERNATIONAL_6, + KC_INT7 = KC_INTERNATIONAL_7, + KC_INT8 = KC_INTERNATIONAL_8, + KC_INT9 = KC_INTERNATIONAL_9, + KC_LNG1 = KC_LANGUAGE_1, + KC_LNG2 = KC_LANGUAGE_2, + KC_LNG3 = KC_LANGUAGE_3, + KC_LNG4 = KC_LANGUAGE_4, + KC_LNG5 = KC_LANGUAGE_5, + KC_LNG6 = KC_LANGUAGE_6, + KC_LNG7 = KC_LANGUAGE_7, + KC_LNG8 = KC_LANGUAGE_8, + KC_LNG9 = KC_LANGUAGE_9, + KC_ERAS = KC_ALTERNATE_ERASE, + KC_SYRQ = KC_SYSTEM_REQUEST, + KC_CNCL = KC_CANCEL, + KC_CLR = KC_CLEAR, + KC_PRIR = KC_PRIOR, + KC_RETN = KC_RETURN, + KC_SEPR = KC_SEPARATOR, + KC_CLAG = KC_CLEAR_AGAIN, + KC_CRSL = KC_CRSEL, + KC_EXSL = KC_EXSEL, + KC_PWR = KC_SYSTEM_POWER, + KC_SLEP = KC_SYSTEM_SLEEP, + KC_WAKE = KC_SYSTEM_WAKE, + KC_MUTE = KC_AUDIO_MUTE, + KC_VOLU = KC_AUDIO_VOL_UP, + KC_VOLD = KC_AUDIO_VOL_DOWN, + KC_MNXT = KC_MEDIA_NEXT_TRACK, + KC_MPRV = KC_MEDIA_PREV_TRACK, + KC_MSTP = KC_MEDIA_STOP, + KC_MPLY = KC_MEDIA_PLAY_PAUSE, + KC_MSEL = KC_MEDIA_SELECT, + KC_EJCT = KC_MEDIA_EJECT, + KC_CALC = KC_CALCULATOR, + KC_MYCM = KC_MY_COMPUTER, + KC_WSCH = KC_WWW_SEARCH, + KC_WHOM = KC_WWW_HOME, + KC_WBAK = KC_WWW_BACK, + KC_WFWD = KC_WWW_FORWARD, + KC_WSTP = KC_WWW_STOP, + KC_WREF = KC_WWW_REFRESH, + KC_WFAV = KC_WWW_FAVORITES, + KC_MFFD = KC_MEDIA_FAST_FORWARD, + KC_MRWD = KC_MEDIA_REWIND, + KC_BRIU = KC_BRIGHTNESS_UP, + KC_BRID = KC_BRIGHTNESS_DOWN, + KC_CPNL = KC_CONTROL_PANEL, + KC_ASST = KC_ASSISTANT, + KC_MCTL = KC_MISSION_CONTROL, + KC_LPAD = KC_LAUNCHPAD, + KC_MS_U = KC_MS_UP, + KC_MS_D = KC_MS_DOWN, + KC_MS_L = KC_MS_LEFT, + KC_MS_R = KC_MS_RIGHT, + KC_BTN1 = KC_MS_BTN1, + KC_BTN2 = KC_MS_BTN2, + KC_BTN3 = KC_MS_BTN3, + KC_BTN4 = KC_MS_BTN4, + KC_BTN5 = KC_MS_BTN5, + KC_BTN6 = KC_MS_BTN6, + KC_BTN7 = KC_MS_BTN7, + KC_BTN8 = KC_MS_BTN8, + KC_WH_U = KC_MS_WH_UP, + KC_WH_D = KC_MS_WH_DOWN, + KC_WH_L = KC_MS_WH_LEFT, + KC_WH_R = KC_MS_WH_RIGHT, + KC_ACL0 = KC_MS_ACCEL0, + KC_ACL1 = KC_MS_ACCEL1, + KC_ACL2 = KC_MS_ACCEL2, + KC_LCTL = KC_LEFT_CTRL, + KC_LSFT = KC_LEFT_SHIFT, + KC_LALT = KC_LEFT_ALT, + KC_LOPT = KC_LEFT_ALT, + KC_LGUI = KC_LEFT_GUI, + KC_LCMD = KC_LEFT_GUI, + KC_LWIN = KC_LEFT_GUI, + KC_RCTL = KC_RIGHT_CTRL, + KC_RSFT = KC_RIGHT_SHIFT, + KC_RALT = KC_RIGHT_ALT, + KC_ROPT = KC_RIGHT_ALT, + KC_ALGR = KC_RIGHT_ALT, + KC_RGUI = KC_RIGHT_GUI, + KC_RCMD = KC_RIGHT_GUI, + KC_RWIN = KC_RIGHT_GUI, + SH_TOGG = QK_SWAP_HANDS_TOGGLE, + SH_TT = QK_SWAP_HANDS_TAP_TOGGLE, + SH_MON = QK_SWAP_HANDS_MOMENTARY_ON, + SH_MOFF = QK_SWAP_HANDS_MOMENTARY_OFF, + SH_OFF = QK_SWAP_HANDS_OFF, + SH_ON = QK_SWAP_HANDS_ON, + SH_OS = QK_SWAP_HANDS_ONE_SHOT, + CL_SWAP = QK_MAGIC_SWAP_CONTROL_CAPS_LOCK, + CL_NORM = QK_MAGIC_UNSWAP_CONTROL_CAPS_LOCK, + CL_TOGG = QK_MAGIC_TOGGLE_CONTROL_CAPS_LOCK, + CL_CAPS = QK_MAGIC_CAPS_LOCK_AS_CONTROL_OFF, + CL_CTRL = QK_MAGIC_CAPS_LOCK_AS_CONTROL_ON, + AG_LSWP = QK_MAGIC_SWAP_LALT_LGUI, + AG_LNRM = QK_MAGIC_UNSWAP_LALT_LGUI, + AG_RSWP = QK_MAGIC_SWAP_RALT_RGUI, + AG_RNRM = QK_MAGIC_UNSWAP_RALT_RGUI, + GU_ON = QK_MAGIC_GUI_ON, + GU_OFF = QK_MAGIC_GUI_OFF, + GU_TOGG = QK_MAGIC_TOGGLE_GUI, + GE_SWAP = QK_MAGIC_SWAP_GRAVE_ESC, + GE_NORM = QK_MAGIC_UNSWAP_GRAVE_ESC, + BS_SWAP = QK_MAGIC_SWAP_BACKSLASH_BACKSPACE, + BS_NORM = QK_MAGIC_UNSWAP_BACKSLASH_BACKSPACE, + BS_TOGG = QK_MAGIC_TOGGLE_BACKSLASH_BACKSPACE, + NK_ON = QK_MAGIC_NKRO_ON, + NK_OFF = QK_MAGIC_NKRO_OFF, + NK_TOGG = QK_MAGIC_TOGGLE_NKRO, + AG_SWAP = QK_MAGIC_SWAP_ALT_GUI, + AG_NORM = QK_MAGIC_UNSWAP_ALT_GUI, + AG_TOGG = QK_MAGIC_TOGGLE_ALT_GUI, + CG_LSWP = QK_MAGIC_SWAP_LCTL_LGUI, + CG_LNRM = QK_MAGIC_UNSWAP_LCTL_LGUI, + CG_RSWP = QK_MAGIC_SWAP_RCTL_RGUI, + CG_RNRM = QK_MAGIC_UNSWAP_RCTL_RGUI, + CG_SWAP = QK_MAGIC_SWAP_CTL_GUI, + CG_NORM = QK_MAGIC_UNSWAP_CTL_GUI, + CG_TOGG = QK_MAGIC_TOGGLE_CTL_GUI, + EH_LEFT = QK_MAGIC_EE_HANDS_LEFT, + EH_RGHT = QK_MAGIC_EE_HANDS_RIGHT, + EC_SWAP = QK_MAGIC_SWAP_ESCAPE_CAPS_LOCK, + EC_NORM = QK_MAGIC_UNSWAP_ESCAPE_CAPS_LOCK, + EC_TOGG = QK_MAGIC_TOGGLE_ESCAPE_CAPS_LOCK, + MI_ON = QK_MIDI_ON, + MI_OFF = QK_MIDI_OFF, + MI_TOGG = QK_MIDI_TOGGLE, + MI_C = QK_MIDI_NOTE_C_0, + MI_Cs = QK_MIDI_NOTE_C_SHARP_0, + MI_Db = QK_MIDI_NOTE_C_SHARP_0, + MI_D = QK_MIDI_NOTE_D_0, + MI_Ds = QK_MIDI_NOTE_D_SHARP_0, + MI_Eb = QK_MIDI_NOTE_D_SHARP_0, + MI_E = QK_MIDI_NOTE_E_0, + MI_F = QK_MIDI_NOTE_F_0, + MI_Fs = QK_MIDI_NOTE_F_SHARP_0, + MI_Gb = QK_MIDI_NOTE_F_SHARP_0, + MI_G = QK_MIDI_NOTE_G_0, + MI_Gs = QK_MIDI_NOTE_G_SHARP_0, + MI_Ab = QK_MIDI_NOTE_G_SHARP_0, + MI_A = QK_MIDI_NOTE_A_0, + MI_As = QK_MIDI_NOTE_A_SHARP_0, + MI_Bb = QK_MIDI_NOTE_A_SHARP_0, + MI_B = QK_MIDI_NOTE_B_0, + MI_C1 = QK_MIDI_NOTE_C_1, + MI_Cs1 = QK_MIDI_NOTE_C_SHARP_1, + MI_Db1 = QK_MIDI_NOTE_C_SHARP_1, + MI_D1 = QK_MIDI_NOTE_D_1, + MI_Ds1 = QK_MIDI_NOTE_D_SHARP_1, + MI_Eb1 = QK_MIDI_NOTE_D_SHARP_1, + MI_E1 = QK_MIDI_NOTE_E_1, + MI_F1 = QK_MIDI_NOTE_F_1, + MI_Fs1 = QK_MIDI_NOTE_F_SHARP_1, + MI_Gb1 = QK_MIDI_NOTE_F_SHARP_1, + MI_G1 = QK_MIDI_NOTE_G_1, + MI_Gs1 = QK_MIDI_NOTE_G_SHARP_1, + MI_Ab1 = QK_MIDI_NOTE_G_SHARP_1, + MI_A1 = QK_MIDI_NOTE_A_1, + MI_As1 = QK_MIDI_NOTE_A_SHARP_1, + MI_Bb1 = QK_MIDI_NOTE_A_SHARP_1, + MI_B1 = QK_MIDI_NOTE_B_1, + MI_C2 = QK_MIDI_NOTE_C_2, + MI_Cs2 = QK_MIDI_NOTE_C_SHARP_2, + MI_Db2 = QK_MIDI_NOTE_C_SHARP_2, + MI_D2 = QK_MIDI_NOTE_D_2, + MI_Ds2 = QK_MIDI_NOTE_D_SHARP_2, + MI_Eb2 = QK_MIDI_NOTE_D_SHARP_2, + MI_E2 = QK_MIDI_NOTE_E_2, + MI_F2 = QK_MIDI_NOTE_F_2, + MI_Fs2 = QK_MIDI_NOTE_F_SHARP_2, + MI_Gb2 = QK_MIDI_NOTE_F_SHARP_2, + MI_G2 = QK_MIDI_NOTE_G_2, + MI_Gs2 = QK_MIDI_NOTE_G_SHARP_2, + MI_Ab2 = QK_MIDI_NOTE_G_SHARP_2, + MI_A2 = QK_MIDI_NOTE_A_2, + MI_As2 = QK_MIDI_NOTE_A_SHARP_2, + MI_Bb2 = QK_MIDI_NOTE_A_SHARP_2, + MI_B2 = QK_MIDI_NOTE_B_2, + MI_C3 = QK_MIDI_NOTE_C_3, + MI_Cs3 = QK_MIDI_NOTE_C_SHARP_3, + MI_Db3 = QK_MIDI_NOTE_C_SHARP_3, + MI_D3 = QK_MIDI_NOTE_D_3, + MI_Ds3 = QK_MIDI_NOTE_D_SHARP_3, + MI_Eb3 = QK_MIDI_NOTE_D_SHARP_3, + MI_E3 = QK_MIDI_NOTE_E_3, + MI_F3 = QK_MIDI_NOTE_F_3, + MI_Fs3 = QK_MIDI_NOTE_F_SHARP_3, + MI_Gb3 = QK_MIDI_NOTE_F_SHARP_3, + MI_G3 = QK_MIDI_NOTE_G_3, + MI_Gs3 = QK_MIDI_NOTE_G_SHARP_3, + MI_Ab3 = QK_MIDI_NOTE_G_SHARP_3, + MI_A3 = QK_MIDI_NOTE_A_3, + MI_As3 = QK_MIDI_NOTE_A_SHARP_3, + MI_Bb3 = QK_MIDI_NOTE_A_SHARP_3, + MI_B3 = QK_MIDI_NOTE_B_3, + MI_C4 = QK_MIDI_NOTE_C_4, + MI_Cs4 = QK_MIDI_NOTE_C_SHARP_4, + MI_Db4 = QK_MIDI_NOTE_C_SHARP_4, + MI_D4 = QK_MIDI_NOTE_D_4, + MI_Ds4 = QK_MIDI_NOTE_D_SHARP_4, + MI_Eb4 = QK_MIDI_NOTE_D_SHARP_4, + MI_E4 = QK_MIDI_NOTE_E_4, + MI_F4 = QK_MIDI_NOTE_F_4, + MI_Fs4 = QK_MIDI_NOTE_F_SHARP_4, + MI_Gb4 = QK_MIDI_NOTE_F_SHARP_4, + MI_G4 = QK_MIDI_NOTE_G_4, + MI_Gs4 = QK_MIDI_NOTE_G_SHARP_4, + MI_Ab4 = QK_MIDI_NOTE_G_SHARP_4, + MI_A4 = QK_MIDI_NOTE_A_4, + MI_As4 = QK_MIDI_NOTE_A_SHARP_4, + MI_Bb4 = QK_MIDI_NOTE_A_SHARP_4, + MI_B4 = QK_MIDI_NOTE_B_4, + MI_C5 = QK_MIDI_NOTE_C_5, + MI_Cs5 = QK_MIDI_NOTE_C_SHARP_5, + MI_Db5 = QK_MIDI_NOTE_C_SHARP_5, + MI_D5 = QK_MIDI_NOTE_D_5, + MI_Ds5 = QK_MIDI_NOTE_D_SHARP_5, + MI_Eb5 = QK_MIDI_NOTE_D_SHARP_5, + MI_E5 = QK_MIDI_NOTE_E_5, + MI_F5 = QK_MIDI_NOTE_F_5, + MI_Fs5 = QK_MIDI_NOTE_F_SHARP_5, + MI_Gb5 = QK_MIDI_NOTE_F_SHARP_5, + MI_G5 = QK_MIDI_NOTE_G_5, + MI_Gs5 = QK_MIDI_NOTE_G_SHARP_5, + MI_Ab5 = QK_MIDI_NOTE_G_SHARP_5, + MI_A5 = QK_MIDI_NOTE_A_5, + MI_As5 = QK_MIDI_NOTE_A_SHARP_5, + MI_Bb5 = QK_MIDI_NOTE_A_SHARP_5, + MI_B5 = QK_MIDI_NOTE_B_5, + MI_OCN2 = QK_MIDI_OCTAVE_N2, + MI_OCN1 = QK_MIDI_OCTAVE_N1, + MI_OC0 = QK_MIDI_OCTAVE_0, + MI_OC1 = QK_MIDI_OCTAVE_1, + MI_OC2 = QK_MIDI_OCTAVE_2, + MI_OC3 = QK_MIDI_OCTAVE_3, + MI_OC4 = QK_MIDI_OCTAVE_4, + MI_OC5 = QK_MIDI_OCTAVE_5, + MI_OC6 = QK_MIDI_OCTAVE_6, + MI_OC7 = QK_MIDI_OCTAVE_7, + MI_OCTD = QK_MIDI_OCTAVE_DOWN, + MI_OCTU = QK_MIDI_OCTAVE_UP, + MI_TRN6 = QK_MIDI_TRANSPOSE_N6, + MI_TRN5 = QK_MIDI_TRANSPOSE_N5, + MI_TRN4 = QK_MIDI_TRANSPOSE_N4, + MI_TRN3 = QK_MIDI_TRANSPOSE_N3, + MI_TRN2 = QK_MIDI_TRANSPOSE_N2, + MI_TRN1 = QK_MIDI_TRANSPOSE_N1, + MI_TR0 = QK_MIDI_TRANSPOSE_0, + MI_TR1 = QK_MIDI_TRANSPOSE_1, + MI_TR2 = QK_MIDI_TRANSPOSE_2, + MI_TR3 = QK_MIDI_TRANSPOSE_3, + MI_TR4 = QK_MIDI_TRANSPOSE_4, + MI_TR5 = QK_MIDI_TRANSPOSE_5, + MI_TR6 = QK_MIDI_TRANSPOSE_6, + MI_TRSD = QK_MIDI_TRANSPOSE_DOWN, + MI_TRSU = QK_MIDI_TRANSPOSE_UP, + MI_VL0 = QK_MIDI_VELOCITY_0, + MI_VL1 = QK_MIDI_VELOCITY_1, + MI_VL2 = QK_MIDI_VELOCITY_2, + MI_VL3 = QK_MIDI_VELOCITY_3, + MI_VL4 = QK_MIDI_VELOCITY_4, + MI_VL5 = QK_MIDI_VELOCITY_5, + MI_VL6 = QK_MIDI_VELOCITY_6, + MI_VL7 = QK_MIDI_VELOCITY_7, + MI_VL8 = QK_MIDI_VELOCITY_8, + MI_VL9 = QK_MIDI_VELOCITY_9, + MI_VL10 = QK_MIDI_VELOCITY_10, + MI_VELD = QK_MIDI_VELOCITY_DOWN, + MI_VELU = QK_MIDI_VELOCITY_UP, + MI_CH1 = QK_MIDI_CHANNEL_1, + MI_CH2 = QK_MIDI_CHANNEL_2, + MI_CH3 = QK_MIDI_CHANNEL_3, + MI_CH4 = QK_MIDI_CHANNEL_4, + MI_CH5 = QK_MIDI_CHANNEL_5, + MI_CH6 = QK_MIDI_CHANNEL_6, + MI_CH7 = QK_MIDI_CHANNEL_7, + MI_CH8 = QK_MIDI_CHANNEL_8, + MI_CH9 = QK_MIDI_CHANNEL_9, + MI_CH10 = QK_MIDI_CHANNEL_10, + MI_CH11 = QK_MIDI_CHANNEL_11, + MI_CH12 = QK_MIDI_CHANNEL_12, + MI_CH13 = QK_MIDI_CHANNEL_13, + MI_CH14 = QK_MIDI_CHANNEL_14, + MI_CH15 = QK_MIDI_CHANNEL_15, + MI_CH16 = QK_MIDI_CHANNEL_16, + MI_CHND = QK_MIDI_CHANNEL_DOWN, + MI_CHNU = QK_MIDI_CHANNEL_UP, + MI_AOFF = QK_MIDI_ALL_NOTES_OFF, + MI_SUST = QK_MIDI_SUSTAIN, + MI_PORT = QK_MIDI_PORTAMENTO, + MI_SOST = QK_MIDI_SOSTENUTO, + MI_SOFT = QK_MIDI_SOFT, + MI_LEG = QK_MIDI_LEGATO, + MI_MOD = QK_MIDI_MODULATION, + MI_MODD = QK_MIDI_MODULATION_SPEED_DOWN, + MI_MODU = QK_MIDI_MODULATION_SPEED_UP, + MI_BNDD = QK_MIDI_PITCH_BEND_DOWN, + MI_BNDU = QK_MIDI_PITCH_BEND_UP, + SQ_ON = QK_SEQUENCER_ON, + SQ_OFF = QK_SEQUENCER_OFF, + SQ_TOGG = QK_SEQUENCER_TOGGLE, + SQ_TMPD = QK_SEQUENCER_TEMPO_DOWN, + SQ_TMPU = QK_SEQUENCER_TEMPO_UP, + SQ_RESD = QK_SEQUENCER_RESOLUTION_DOWN, + SQ_RESU = QK_SEQUENCER_RESOLUTION_UP, + SQ_SALL = QK_SEQUENCER_STEPS_ALL, + SQ_SCLR = QK_SEQUENCER_STEPS_CLEAR, + JS_0 = QK_JOYSTICK_BUTTON_0, + JS_1 = QK_JOYSTICK_BUTTON_1, + JS_2 = QK_JOYSTICK_BUTTON_2, + JS_3 = QK_JOYSTICK_BUTTON_3, + JS_4 = QK_JOYSTICK_BUTTON_4, + JS_5 = QK_JOYSTICK_BUTTON_5, + JS_6 = QK_JOYSTICK_BUTTON_6, + JS_7 = QK_JOYSTICK_BUTTON_7, + JS_8 = QK_JOYSTICK_BUTTON_8, + JS_9 = QK_JOYSTICK_BUTTON_9, + JS_10 = QK_JOYSTICK_BUTTON_10, + JS_11 = QK_JOYSTICK_BUTTON_11, + JS_12 = QK_JOYSTICK_BUTTON_12, + JS_13 = QK_JOYSTICK_BUTTON_13, + JS_14 = QK_JOYSTICK_BUTTON_14, + JS_15 = QK_JOYSTICK_BUTTON_15, + JS_16 = QK_JOYSTICK_BUTTON_16, + JS_17 = QK_JOYSTICK_BUTTON_17, + JS_18 = QK_JOYSTICK_BUTTON_18, + JS_19 = QK_JOYSTICK_BUTTON_19, + JS_20 = QK_JOYSTICK_BUTTON_20, + JS_21 = QK_JOYSTICK_BUTTON_21, + JS_22 = QK_JOYSTICK_BUTTON_22, + JS_23 = QK_JOYSTICK_BUTTON_23, + JS_24 = QK_JOYSTICK_BUTTON_24, + JS_25 = QK_JOYSTICK_BUTTON_25, + JS_26 = QK_JOYSTICK_BUTTON_26, + JS_27 = QK_JOYSTICK_BUTTON_27, + JS_28 = QK_JOYSTICK_BUTTON_28, + JS_29 = QK_JOYSTICK_BUTTON_29, + JS_30 = QK_JOYSTICK_BUTTON_30, + JS_31 = QK_JOYSTICK_BUTTON_31, + PB_1 = QK_PROGRAMMABLE_BUTTON_1, + PB_2 = QK_PROGRAMMABLE_BUTTON_2, + PB_3 = QK_PROGRAMMABLE_BUTTON_3, + PB_4 = QK_PROGRAMMABLE_BUTTON_4, + PB_5 = QK_PROGRAMMABLE_BUTTON_5, + PB_6 = QK_PROGRAMMABLE_BUTTON_6, + PB_7 = QK_PROGRAMMABLE_BUTTON_7, + PB_8 = QK_PROGRAMMABLE_BUTTON_8, + PB_9 = QK_PROGRAMMABLE_BUTTON_9, + PB_10 = QK_PROGRAMMABLE_BUTTON_10, + PB_11 = QK_PROGRAMMABLE_BUTTON_11, + PB_12 = QK_PROGRAMMABLE_BUTTON_12, + PB_13 = QK_PROGRAMMABLE_BUTTON_13, + PB_14 = QK_PROGRAMMABLE_BUTTON_14, + PB_15 = QK_PROGRAMMABLE_BUTTON_15, + PB_16 = QK_PROGRAMMABLE_BUTTON_16, + PB_17 = QK_PROGRAMMABLE_BUTTON_17, + PB_18 = QK_PROGRAMMABLE_BUTTON_18, + PB_19 = QK_PROGRAMMABLE_BUTTON_19, + PB_20 = QK_PROGRAMMABLE_BUTTON_20, + PB_21 = QK_PROGRAMMABLE_BUTTON_21, + PB_22 = QK_PROGRAMMABLE_BUTTON_22, + PB_23 = QK_PROGRAMMABLE_BUTTON_23, + PB_24 = QK_PROGRAMMABLE_BUTTON_24, + PB_25 = QK_PROGRAMMABLE_BUTTON_25, + PB_26 = QK_PROGRAMMABLE_BUTTON_26, + PB_27 = QK_PROGRAMMABLE_BUTTON_27, + PB_28 = QK_PROGRAMMABLE_BUTTON_28, + PB_29 = QK_PROGRAMMABLE_BUTTON_29, + PB_30 = QK_PROGRAMMABLE_BUTTON_30, + PB_31 = QK_PROGRAMMABLE_BUTTON_31, + PB_32 = QK_PROGRAMMABLE_BUTTON_32, + AU_ON = QK_AUDIO_ON, + AU_OFF = QK_AUDIO_OFF, + AU_TOGG = QK_AUDIO_TOGGLE, + CK_TOGG = QK_AUDIO_CLICKY_TOGGLE, + CK_ON = QK_AUDIO_CLICKY_ON, + CK_OFF = QK_AUDIO_CLICKY_OFF, + CK_UP = QK_AUDIO_CLICKY_UP, + CK_DOWN = QK_AUDIO_CLICKY_DOWN, + CK_RST = QK_AUDIO_CLICKY_RESET, + MU_ON = QK_MUSIC_ON, + MU_OFF = QK_MUSIC_OFF, + MU_TOGG = QK_MUSIC_TOGGLE, + MU_NEXT = QK_MUSIC_MODE_NEXT, + AU_NEXT = QK_AUDIO_VOICE_NEXT, + AU_PREV = QK_AUDIO_VOICE_PREVIOUS, + MC_0 = QK_MACRO_0, + MC_1 = QK_MACRO_1, + MC_2 = QK_MACRO_2, + MC_3 = QK_MACRO_3, + MC_4 = QK_MACRO_4, + MC_5 = QK_MACRO_5, + MC_6 = QK_MACRO_6, + MC_7 = QK_MACRO_7, + MC_8 = QK_MACRO_8, + MC_9 = QK_MACRO_9, + MC_10 = QK_MACRO_10, + MC_11 = QK_MACRO_11, + MC_12 = QK_MACRO_12, + MC_13 = QK_MACRO_13, + MC_14 = QK_MACRO_14, + MC_15 = QK_MACRO_15, + MC_16 = QK_MACRO_16, + MC_17 = QK_MACRO_17, + MC_18 = QK_MACRO_18, + MC_19 = QK_MACRO_19, + MC_20 = QK_MACRO_20, + MC_21 = QK_MACRO_21, + MC_22 = QK_MACRO_22, + MC_23 = QK_MACRO_23, + MC_24 = QK_MACRO_24, + MC_25 = QK_MACRO_25, + MC_26 = QK_MACRO_26, + MC_27 = QK_MACRO_27, + MC_28 = QK_MACRO_28, + MC_29 = QK_MACRO_29, + MC_30 = QK_MACRO_30, + MC_31 = QK_MACRO_31, + BL_ON = QK_BACKLIGHT_ON, + BL_OFF = QK_BACKLIGHT_OFF, + BL_TOGG = QK_BACKLIGHT_TOGGLE, + BL_DOWN = QK_BACKLIGHT_DOWN, + BL_UP = QK_BACKLIGHT_UP, + BL_STEP = QK_BACKLIGHT_STEP, + BL_BRTG = QK_BACKLIGHT_TOGGLE_BREATHING, + RGB_MOD = RGB_MODE_FORWARD, + RGB_RMOD = RGB_MODE_REVERSE, + RGB_M_P = RGB_MODE_PLAIN, + RGB_M_B = RGB_MODE_BREATHE, + RGB_M_R = RGB_MODE_RAINBOW, + RGB_M_SW = RGB_MODE_SWIRL, + RGB_M_SN = RGB_MODE_SNAKE, + RGB_M_K = RGB_MODE_KNIGHT, + RGB_M_X = RGB_MODE_XMAS, + RGB_M_G = RGB_MODE_GRADIENT, + RGB_M_T = RGB_MODE_RGBTEST, + RGB_M_TW = RGB_MODE_TWINKLE, + QK_BOOT = QK_BOOTLOADER, + QK_RBT = QK_REBOOT, + DB_TOGG = QK_DEBUG_TOGGLE, + EE_CLR = QK_CLEAR_EEPROM, + AS_DOWN = QK_AUTO_SHIFT_DOWN, + AS_UP = QK_AUTO_SHIFT_UP, + AS_RPT = QK_AUTO_SHIFT_REPORT, + AS_ON = QK_AUTO_SHIFT_ON, + AS_OFF = QK_AUTO_SHIFT_OFF, + AS_TOGG = QK_AUTO_SHIFT_TOGGLE, + QK_GESC = QK_GRAVE_ESCAPE, + VK_TOGG = QK_VELOCIKEY_TOGGLE, + SC_LCPO = QK_SPACE_CADET_LEFT_CTRL_PARENTHESIS_OPEN, + SC_RCPC = QK_SPACE_CADET_RIGHT_CTRL_PARENTHESIS_CLOSE, + SC_LSPO = QK_SPACE_CADET_LEFT_SHIFT_PARENTHESIS_OPEN, + SC_RSPC = QK_SPACE_CADET_RIGHT_SHIFT_PARENTHESIS_CLOSE, + SC_LAPO = QK_SPACE_CADET_LEFT_ALT_PARENTHESIS_OPEN, + SC_RAPC = QK_SPACE_CADET_RIGHT_ALT_PARENTHESIS_CLOSE, + SC_SENT = QK_SPACE_CADET_RIGHT_SHIFT_ENTER, + OU_AUTO = QK_OUTPUT_AUTO, + OU_USB = QK_OUTPUT_USB, + OU_BT = QK_OUTPUT_BLUETOOTH, + UC_NEXT = QK_UNICODE_MODE_NEXT, + UC_PREV = QK_UNICODE_MODE_PREVIOUS, + UC_MAC = QK_UNICODE_MODE_MACOS, + UC_LINX = QK_UNICODE_MODE_LINUX, + UC_WIN = QK_UNICODE_MODE_WINDOWS, + UC_BSD = QK_UNICODE_MODE_BSD, + UC_WINC = QK_UNICODE_MODE_WINCOMPOSE, + UC_EMAC = QK_UNICODE_MODE_EMACS, + HF_ON = QK_HAPTIC_ON, + HF_OFF = QK_HAPTIC_OFF, + HF_TOGG = QK_HAPTIC_TOGGLE, + HF_RST = QK_HAPTIC_RESET, + HF_FDBK = QK_HAPTIC_FEEDBACK_TOGGLE, + HF_BUZZ = QK_HAPTIC_BUZZ_TOGGLE, + HF_NEXT = QK_HAPTIC_MODE_NEXT, + HF_PREV = QK_HAPTIC_MODE_PREVIOUS, + HF_CONT = QK_HAPTIC_CONTINUOUS_TOGGLE, + HF_CONU = QK_HAPTIC_CONTINUOUS_UP, + HF_COND = QK_HAPTIC_CONTINUOUS_DOWN, + HF_DWLU = QK_HAPTIC_DWELL_UP, + HF_DWLD = QK_HAPTIC_DWELL_DOWN, + CM_ON = QK_COMBO_ON, + CM_OFF = QK_COMBO_OFF, + CM_TOGG = QK_COMBO_TOGGLE, + DM_REC1 = QK_DYNAMIC_MACRO_RECORD_START_1, + DM_REC2 = QK_DYNAMIC_MACRO_RECORD_START_2, + DM_RSTP = QK_DYNAMIC_MACRO_RECORD_STOP, + DM_PLY1 = QK_DYNAMIC_MACRO_PLAY_1, + DM_PLY2 = QK_DYNAMIC_MACRO_PLAY_2, + QK_LEAD = QK_LEADER, + OS_ON = QK_ONE_SHOT_ON, + OS_OFF = QK_ONE_SHOT_OFF, + OS_TOGG = QK_ONE_SHOT_TOGGLE, + KO_TOGG = QK_KEY_OVERRIDE_TOGGLE, + KO_ON = QK_KEY_OVERRIDE_ON, + KO_OFF = QK_KEY_OVERRIDE_OFF, + SE_LOCK = QK_SECURE_LOCK, + SE_UNLK = QK_SECURE_UNLOCK, + SE_TOGG = QK_SECURE_TOGGLE, + SE_REQ = QK_SECURE_REQUEST, + DT_PRNT = QK_DYNAMIC_TAPPING_TERM_PRINT, + DT_UP = QK_DYNAMIC_TAPPING_TERM_UP, + DT_DOWN = QK_DYNAMIC_TAPPING_TERM_DOWN, + CW_TOGG = QK_CAPS_WORD_TOGGLE, + AC_ON = QK_AUTOCORRECT_ON, + AC_OFF = QK_AUTOCORRECT_OFF, + AC_TOGG = QK_AUTOCORRECT_TOGGLE, + TL_LOWR = QK_TRI_LAYER_LOWER, + TL_UPPR = QK_TRI_LAYER_UPPER, + QK_REP = QK_REPEAT_KEY, + QK_AREP = QK_ALT_REPEAT_KEY, +}; + +// Range Helpers +#define IS_QK_BASIC(code) ((code) >= QK_BASIC && (code) <= QK_BASIC_MAX) +#define IS_QK_MODS(code) ((code) >= QK_MODS && (code) <= QK_MODS_MAX) +#define IS_QK_MOD_TAP(code) ((code) >= QK_MOD_TAP && (code) <= QK_MOD_TAP_MAX) +#define IS_QK_LAYER_TAP(code) ((code) >= QK_LAYER_TAP && (code) <= QK_LAYER_TAP_MAX) +#define IS_QK_LAYER_MOD(code) ((code) >= QK_LAYER_MOD && (code) <= QK_LAYER_MOD_MAX) +#define IS_QK_TO(code) ((code) >= QK_TO && (code) <= QK_TO_MAX) +#define IS_QK_MOMENTARY(code) ((code) >= QK_MOMENTARY && (code) <= QK_MOMENTARY_MAX) +#define IS_QK_DEF_LAYER(code) ((code) >= QK_DEF_LAYER && (code) <= QK_DEF_LAYER_MAX) +#define IS_QK_TOGGLE_LAYER(code) ((code) >= QK_TOGGLE_LAYER && (code) <= QK_TOGGLE_LAYER_MAX) +#define IS_QK_ONE_SHOT_LAYER(code) ((code) >= QK_ONE_SHOT_LAYER && (code) <= QK_ONE_SHOT_LAYER_MAX) +#define IS_QK_ONE_SHOT_MOD(code) ((code) >= QK_ONE_SHOT_MOD && (code) <= QK_ONE_SHOT_MOD_MAX) +#define IS_QK_LAYER_TAP_TOGGLE(code) ((code) >= QK_LAYER_TAP_TOGGLE && (code) <= QK_LAYER_TAP_TOGGLE_MAX) +#define IS_QK_SWAP_HANDS(code) ((code) >= QK_SWAP_HANDS && (code) <= QK_SWAP_HANDS_MAX) +#define IS_QK_TAP_DANCE(code) ((code) >= QK_TAP_DANCE && (code) <= QK_TAP_DANCE_MAX) +#define IS_QK_MAGIC(code) ((code) >= QK_MAGIC && (code) <= QK_MAGIC_MAX) +#define IS_QK_MIDI(code) ((code) >= QK_MIDI && (code) <= QK_MIDI_MAX) +#define IS_QK_SEQUENCER(code) ((code) >= QK_SEQUENCER && (code) <= QK_SEQUENCER_MAX) +#define IS_QK_JOYSTICK(code) ((code) >= QK_JOYSTICK && (code) <= QK_JOYSTICK_MAX) +#define IS_QK_PROGRAMMABLE_BUTTON(code) ((code) >= QK_PROGRAMMABLE_BUTTON && (code) <= QK_PROGRAMMABLE_BUTTON_MAX) +#define IS_QK_AUDIO(code) ((code) >= QK_AUDIO && (code) <= QK_AUDIO_MAX) +#define IS_QK_STENO(code) ((code) >= QK_STENO && (code) <= QK_STENO_MAX) +#define IS_QK_MACRO(code) ((code) >= QK_MACRO && (code) <= QK_MACRO_MAX) +#define IS_QK_LIGHTING(code) ((code) >= QK_LIGHTING && (code) <= QK_LIGHTING_MAX) +#define IS_QK_QUANTUM(code) ((code) >= QK_QUANTUM && (code) <= QK_QUANTUM_MAX) +#define IS_QK_KB(code) ((code) >= QK_KB && (code) <= QK_KB_MAX) +#define IS_QK_USER(code) ((code) >= QK_USER && (code) <= QK_USER_MAX) +#define IS_QK_UNICODEMAP(code) ((code) >= QK_UNICODEMAP && (code) <= QK_UNICODEMAP_MAX) +#define IS_QK_UNICODE(code) ((code) >= QK_UNICODE && (code) <= QK_UNICODE_MAX) +#define IS_QK_UNICODEMAP_PAIR(code) ((code) >= QK_UNICODEMAP_PAIR && (code) <= QK_UNICODEMAP_PAIR_MAX) + +// Group Helpers +#define IS_INTERNAL_KEYCODE(code) ((code) >= KC_NO && (code) <= KC_TRANSPARENT) +#define IS_BASIC_KEYCODE(code) ((code) >= KC_A && (code) <= KC_EXSEL) +#define IS_SYSTEM_KEYCODE(code) ((code) >= KC_SYSTEM_POWER && (code) <= KC_SYSTEM_WAKE) +#define IS_CONSUMER_KEYCODE(code) ((code) >= KC_AUDIO_MUTE && (code) <= KC_LAUNCHPAD) +#define IS_MOUSE_KEYCODE(code) ((code) >= KC_MS_UP && (code) <= KC_MS_ACCEL2) +#define IS_MODIFIER_KEYCODE(code) ((code) >= KC_LEFT_CTRL && (code) <= KC_RIGHT_GUI) +#define IS_SWAP_HANDS_KEYCODE(code) ((code) >= QK_SWAP_HANDS_TOGGLE && (code) <= QK_SWAP_HANDS_ONE_SHOT) +#define IS_MAGIC_KEYCODE(code) ((code) >= QK_MAGIC_SWAP_CONTROL_CAPS_LOCK && (code) <= QK_MAGIC_TOGGLE_ESCAPE_CAPS_LOCK) +#define IS_MIDI_KEYCODE(code) ((code) >= QK_MIDI_ON && (code) <= QK_MIDI_PITCH_BEND_UP) +#define IS_SEQUENCER_KEYCODE(code) ((code) >= QK_SEQUENCER_ON && (code) <= QK_SEQUENCER_STEPS_CLEAR) +#define IS_JOYSTICK_KEYCODE(code) ((code) >= QK_JOYSTICK_BUTTON_0 && (code) <= QK_JOYSTICK_BUTTON_31) +#define IS_PROGRAMMABLE_BUTTON_KEYCODE(code) ((code) >= QK_PROGRAMMABLE_BUTTON_1 && (code) <= QK_PROGRAMMABLE_BUTTON_32) +#define IS_AUDIO_KEYCODE(code) ((code) >= QK_AUDIO_ON && (code) <= QK_AUDIO_VOICE_PREVIOUS) +#define IS_STENO_KEYCODE(code) ((code) >= QK_STENO_BOLT && (code) <= QK_STENO_COMB_MAX) +#define IS_MACRO_KEYCODE(code) ((code) >= QK_MACRO_0 && (code) <= QK_MACRO_31) +#define IS_BACKLIGHT_KEYCODE(code) ((code) >= QK_BACKLIGHT_ON && (code) <= QK_BACKLIGHT_TOGGLE_BREATHING) +#define IS_RGB_KEYCODE(code) ((code) >= RGB_TOG && (code) <= RGB_MODE_TWINKLE) +#define IS_QUANTUM_KEYCODE(code) ((code) >= QK_BOOTLOADER && (code) <= QK_ALT_REPEAT_KEY) +#define IS_KB_KEYCODE(code) ((code) >= QK_KB_0 && (code) <= QK_KB_31) +#define IS_USER_KEYCODE(code) ((code) >= QK_USER_0 && (code) <= QK_USER_31) + +// Switch statement Helpers +#define INTERNAL_KEYCODE_RANGE KC_NO ... KC_TRANSPARENT +#define BASIC_KEYCODE_RANGE KC_A ... KC_EXSEL +#define SYSTEM_KEYCODE_RANGE KC_SYSTEM_POWER ... KC_SYSTEM_WAKE +#define CONSUMER_KEYCODE_RANGE KC_AUDIO_MUTE ... KC_LAUNCHPAD +#define MOUSE_KEYCODE_RANGE KC_MS_UP ... KC_MS_ACCEL2 +#define MODIFIER_KEYCODE_RANGE KC_LEFT_CTRL ... KC_RIGHT_GUI +#define SWAP_HANDS_KEYCODE_RANGE QK_SWAP_HANDS_TOGGLE ... QK_SWAP_HANDS_ONE_SHOT +#define MAGIC_KEYCODE_RANGE QK_MAGIC_SWAP_CONTROL_CAPS_LOCK ... QK_MAGIC_TOGGLE_ESCAPE_CAPS_LOCK +#define MIDI_KEYCODE_RANGE QK_MIDI_ON ... QK_MIDI_PITCH_BEND_UP +#define SEQUENCER_KEYCODE_RANGE QK_SEQUENCER_ON ... QK_SEQUENCER_STEPS_CLEAR +#define JOYSTICK_KEYCODE_RANGE QK_JOYSTICK_BUTTON_0 ... QK_JOYSTICK_BUTTON_31 +#define PROGRAMMABLE_BUTTON_KEYCODE_RANGE QK_PROGRAMMABLE_BUTTON_1 ... QK_PROGRAMMABLE_BUTTON_32 +#define AUDIO_KEYCODE_RANGE QK_AUDIO_ON ... QK_AUDIO_VOICE_PREVIOUS +#define STENO_KEYCODE_RANGE QK_STENO_BOLT ... QK_STENO_COMB_MAX +#define MACRO_KEYCODE_RANGE QK_MACRO_0 ... QK_MACRO_31 +#define BACKLIGHT_KEYCODE_RANGE QK_BACKLIGHT_ON ... QK_BACKLIGHT_TOGGLE_BREATHING +#define RGB_KEYCODE_RANGE RGB_TOG ... RGB_MODE_TWINKLE +#define QUANTUM_KEYCODE_RANGE QK_BOOTLOADER ... QK_ALT_REPEAT_KEY +#define KB_KEYCODE_RANGE QK_KB_0 ... QK_KB_31 +#define USER_KEYCODE_RANGE QK_USER_0 ... QK_USER_31 + +/* Consumer Page (0x0C) + * + * See https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf#page=75 + */ +enum consumer_usages { + // 15.5 Display Controls + SNAPSHOT = 0x065, + BRIGHTNESS_UP = 0x06F, // https://www.usb.org/sites/default/files/hutrr41_0.pdf + BRIGHTNESS_DOWN = 0x070, + // 15.7 Transport Controls + TRANSPORT_RECORD = 0x0B2, + TRANSPORT_FAST_FORWARD = 0x0B3, + TRANSPORT_REWIND = 0x0B4, + TRANSPORT_NEXT_TRACK = 0x0B5, + TRANSPORT_PREV_TRACK = 0x0B6, + TRANSPORT_STOP = 0x0B7, + TRANSPORT_EJECT = 0x0B8, + TRANSPORT_RANDOM_PLAY = 0x0B9, + TRANSPORT_STOP_EJECT = 0x0CC, + TRANSPORT_PLAY_PAUSE = 0x0CD, + // 15.9.1 Audio Controls - Volume + AUDIO_MUTE = 0x0E2, + AUDIO_VOL_UP = 0x0E9, + AUDIO_VOL_DOWN = 0x0EA, + // 15.15 Application Launch Buttons + AL_CC_CONFIG = 0x183, + AL_EMAIL = 0x18A, + AL_CALCULATOR = 0x192, + AL_LOCAL_BROWSER = 0x194, + AL_LOCK = 0x19E, + AL_CONTROL_PANEL = 0x19F, + AL_ASSISTANT = 0x1CB, + AL_KEYBOARD_LAYOUT = 0x1AE, + // 15.16 Generic GUI Application Controls + AC_NEW = 0x201, + AC_OPEN = 0x202, + AC_CLOSE = 0x203, + AC_EXIT = 0x204, + AC_MAXIMIZE = 0x205, + AC_MINIMIZE = 0x206, + AC_SAVE = 0x207, + AC_PRINT = 0x208, + AC_PROPERTIES = 0x209, + AC_UNDO = 0x21A, + AC_COPY = 0x21B, + AC_CUT = 0x21C, + AC_PASTE = 0x21D, + AC_SELECT_ALL = 0x21E, + AC_FIND = 0x21F, + AC_SEARCH = 0x221, + AC_HOME = 0x223, + AC_BACK = 0x224, + AC_FORWARD = 0x225, + AC_STOP = 0x226, + AC_REFRESH = 0x227, + AC_BOOKMARKS = 0x22A, + AC_NEXT_KEYBOARD_LAYOUT_SELECT = 0x29D, + AC_DESKTOP_SHOW_ALL_WINDOWS = 0x29F, + AC_SOFT_KEY_LEFT = 0x2A0 +}; + +/* Generic Desktop Page (0x01) + * + * See https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf#page=26 + */ +enum desktop_usages { + // 4.5.1 System Controls - Power Controls + SYSTEM_POWER_DOWN = 0x81, + SYSTEM_SLEEP_0 = 0x82, + SYSTEM_WAKE_UP_0 = 0x83, + SYSTEM_RESTART = 0x8F, + // 4.10 System Display Controls + SYSTEM_DISPLAY_TOGGLE_INT_EXT = 0xB5 +}; diff --git a/app/src/launcher/keymap_japanese.h b/app/src/launcher/keymap_japanese.h new file mode 100644 index 00000000000..947317833ed --- /dev/null +++ b/app/src/launcher/keymap_japanese.h @@ -0,0 +1,106 @@ +// Copyright 2023 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +/******************************************************************************* + 88888888888 888 d8b .d888 d8b 888 d8b + 888 888 Y8P d88P" Y8P 888 Y8P + 888 888 888 888 + 888 88888b. 888 .d8888b 888888 888 888 .d88b. 888 .d8888b + 888 888 "88b 888 88K 888 888 888 d8P Y8b 888 88K + 888 888 888 888 "Y8888b. 888 888 888 88888888 888 "Y8888b. + 888 888 888 888 X88 888 888 888 Y8b. 888 X88 + 888 888 888 888 88888P' 888 888 888 "Y8888 888 88888P' + 888 888 + 888 888 + 888 888 + .d88b. .d88b. 88888b. .d88b. 888d888 8888b. 888888 .d88b. .d88888 + d88P"88b d8P Y8b 888 "88b d8P Y8b 888P" "88b 888 d8P Y8b d88" 888 + 888 888 88888888 888 888 88888888 888 .d888888 888 88888888 888 888 + Y88b 888 Y8b. 888 888 Y8b. 888 888 888 Y88b. Y8b. Y88b 888 + "Y88888 "Y8888 888 888 "Y8888 888 "Y888888 "Y888 "Y8888 "Y88888 + 888 + Y8b d88P + "Y88P" +*******************************************************************************/ + +#pragma once +#include "keycodes.h" +// clang-format off + +// Aliases +#define JP_ZKHK KC_GRV // Zenkaku ↔ Hankaku ↔ Kanji (半角 ↔ 全角 ↔ 漢字) +#define JP_1 KC_1 // 1 +#define JP_2 KC_2 // 2 +#define JP_3 KC_3 // 3 +#define JP_4 KC_4 // 4 +#define JP_5 KC_5 // 5 +#define JP_6 KC_6 // 6 +#define JP_7 KC_7 // 7 +#define JP_8 KC_8 // 8 +#define JP_9 KC_9 // 9 +#define JP_0 KC_0 // 0 +#define JP_MINS KC_MINS // - +#define JP_CIRC KC_EQL // ^ +#define JP_YEN KC_INT3 // ¥ +#define JP_Q KC_Q // Q +#define JP_W KC_W // W +#define JP_E KC_E // E +#define JP_R KC_R // R +#define JP_T KC_T // T +#define JP_Y KC_Y // Y +#define JP_U KC_U // U +#define JP_I KC_I // I +#define JP_O KC_O // O +#define JP_P KC_P // P +#define JP_AT KC_LBRC // @ +#define JP_LBRC KC_RBRC // [ +#define JP_EISU KC_CAPS // Eisū (英数) +#define JP_A KC_A // A +#define JP_S KC_S // S +#define JP_D KC_D // D +#define JP_F KC_F // F +#define JP_G KC_G // G +#define JP_H KC_H // H +#define JP_J KC_J // J +#define JP_K KC_K // K +#define JP_L KC_L // L +#define JP_SCLN KC_SCLN // ; +#define JP_COLN KC_QUOT // : +#define JP_RBRC KC_NUHS // ] +#define JP_Z KC_Z // Z +#define JP_X KC_X // X +#define JP_C KC_C // C +#define JP_V KC_V // V +#define JP_B KC_B // B +#define JP_N KC_N // N +#define JP_M KC_M // M +#define JP_COMM KC_COMM // , +#define JP_DOT KC_DOT // . +#define JP_SLSH KC_SLSH // / +#define JP_BSLS KC_INT1 // (backslash) +#define JP_MHEN KC_INT5 // Muhenkan (無変換) +#define JP_HENK KC_INT4 // Henkan (変換) +#define JP_KANA KC_INT2 // Katakana ↔ Hiragana ↔ Rōmaji (カタカナ ↔ ひらがな ↔ ローマ字) +#define JP_EXLM S(JP_1) // ! +#define JP_DQUO S(JP_2) // " +#define JP_HASH S(JP_3) // # +#define JP_DLR S(JP_4) // $ +#define JP_PERC S(JP_5) // % +#define JP_AMPR S(JP_6) // & +#define JP_QUOT S(JP_7) // ' +#define JP_LPRN S(JP_8) // ( +#define JP_RPRN S(JP_9) // ) +#define JP_EQL S(JP_MINS) // = +#define JP_TILD S(JP_CIRC) // ~ +#define JP_PIPE S(JP_YEN) // | +#define JP_GRV S(JP_AT) // ` +#define JP_LCBR S(JP_LBRC) // { +#define JP_CAPS S(JP_EISU) // Caps Lock +#define JP_PLUS S(JP_SCLN) // + +#define JP_ASTR S(JP_COLN) // * +#define JP_RCBR S(JP_RBRC) // } +#define JP_LABK S(JP_COMM) // < +#define JP_RABK S(JP_DOT) // > +#define JP_QUES S(JP_SLSH) // ? +#define JP_UNDS S(JP_BSLS) // _ + diff --git a/app/src/launcher/launcher.c b/app/src/launcher/launcher.c new file mode 100644 index 00000000000..1825f58777c --- /dev/null +++ b/app/src/launcher/launcher.c @@ -0,0 +1,1527 @@ + +#include "../version.h" +#include "launcher.h" + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include "keycodes.h" +#include "dynamic_keymap.h" +#include +#include +#include +#if (CONFIG_SHIELD_KEYCHRON_B6_JIS||CONFIG_SHIELD_KEYCHRON_B1_JIS ||CONFIG_SHIELD_KEYCHRON_B2_JIS) +//for jis layout! +#include "sendstring_japanese.h" +#endif + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +enum { + VIA_PATH_USB, + VIA_PATH_BLE, + VIA_PATH_24G, +}; +static uint8_t via_path; + +void via_set_path(uint8_t path) +{ + via_path = path; +} +void user_set_debounce(uint32_t scan_period_ms,uint32_t debounce_press_ms,uint32_t debounce_release_ms); + +uint8_t zmk_keymap_highest_layer_active(); + +int zmk_24g_send_via_report(uint8_t *payload,uint8_t payload_len); +static uint8_t report_os_sw_state; +void factory_test_rx(uint8_t *data, uint8_t length); +K_MSGQ_DEFINE(via_usb_msgq, 32,16, 4); +void via_usb_worker(struct k_work *work); +K_WORK_DEFINE(via_usb_work, via_usb_worker); + +static const struct device *hid_via_dev; + +static K_SEM_DEFINE(hid_via_sem, 1, 1); + +void via_usb_worker(struct k_work *work) +{ + uint8_t usb_data[32]; + while (k_msgq_get(&via_usb_msgq, usb_data, K_NO_WAIT) == 0) { + raw_hid_receive(usb_data,sizeof(usb_data)); + } +} + +static void in_ready_cb(const struct device *dev) { k_sem_give(&hid_via_sem); } + +static void out_ready_cb(const struct device *dev) +{ + uint8_t rev_buf[32]={0}; + uint32_t rev_bytes =0; + hid_int_ep_read(dev,rev_buf,sizeof(rev_buf),&rev_bytes); + LOG_HEXDUMP_DBG(rev_buf,8,"rx"); + // raw_hid_receive(rev_buf,rev_bytes); + uint16_t hdr = (rev_buf[0]<<8) | rev_buf[1]; + if(hdr == 0xaa55 || hdr== 0xaa56) + { + void my_scdfu_data_handle(unsigned char *pdata,unsigned char rxlen); + return my_scdfu_data_handle(&rev_buf[0],rev_bytes); + } + via_path = VIA_PATH_USB; + int err = k_msgq_put(&via_usb_msgq, rev_buf, K_MSEC(100)); + if (err) { + switch (err) { + case -EAGAIN: { + LOG_WRN("queue full"); + uint8_t buf[32]; + k_msgq_get(&via_usb_msgq, buf, K_NO_WAIT); + k_msgq_put(&via_usb_msgq, rev_buf, K_MSEC(100)); + } + default: + LOG_WRN("Failed to queue via data (%d)", err); + } + } + + err = k_work_submit(&via_usb_work); +} + +static const struct hid_ops ops = { + .int_in_ready = in_ready_cb, + .int_out_ready = out_ready_cb, +}; + +int zmk_usb_hid_via_send(const uint8_t *report, size_t len) { + switch (zmk_usb_get_status()) { + + case USB_DC_ERROR: + case USB_DC_RESET: + case USB_DC_DISCONNECTED: + case USB_DC_UNKNOWN: + return -ENODEV; + case USB_DC_SUSPEND: + usb_wakeup_request(); + k_msleep(20); + default: + k_sem_take(&hid_via_sem, K_MSEC(10)); + LOG_HEXDUMP_DBG(report,8,"usb"); + int err = hid_int_ep_write(hid_via_dev, report, len, NULL); + + if (err!=0) { + LOG_ERR("write err:%d",err); + // k_sem_give(&hid_via_sem); + } + + return err; + } +} + +static int zmk_usb_hid_via_init(const struct device *_arg) { + hid_via_dev = device_get_binding("HID_1"); + if (hid_via_dev == NULL) { + LOG_ERR("Unable to locate HID device"); + return -EINVAL; + } + + usb_hid_register_device(hid_via_dev, zmk_hid_via_report_desc, sizeof(zmk_hid_via_report_desc), &ops); + usb_hid_init(hid_via_dev); + via_init(); + return 0; +} + +SYS_INIT(zmk_usb_hid_via_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); + +_via_ee_device via_ee_device; + +static struct user_debounce debouce; + +struct direct_immediate_value { + size_t len; + void *dest; + uint8_t fetched; +}; +static int direct_loader_immediate_value(const char *name, size_t len, + settings_read_cb read_cb, void *cb_arg, + void *param) +{ + const char *next; + size_t name_len; + int rc; + struct direct_immediate_value *one_value = + (struct direct_immediate_value *)param; + + name_len = settings_name_next(name, &next); + + if (name_len == 0) { + if (len == one_value->len) { + rc = read_cb(cb_arg, one_value->dest, len); + if (rc >= 0) { + one_value->fetched = 1; + LOG_DBG("immediate load: OK.\n"); + return 0; + } + + LOG_DBG("err:%d", rc); + return rc; + } + return -EINVAL; + } + + /* other keys aren't served by the callback + * Return success in order to skip them + * and keep storage processing. + */ + return 0; +} + +int load_immediate_value(const char *name, void *dest, size_t len) +{ + int rc; + struct direct_immediate_value dov; + + dov.fetched = 0; + dov.len = len; + dov.dest = dest; + + rc = settings_load_subtree_direct(name, direct_loader_immediate_value, + (void *)&dov); + if (rc == 0) { + if (!dov.fetched) { + rc = -ENOENT; + } + } + + return rc; +} +void via_ee_delete(void) +{ + LOG_DBG("."); + settings_delete("via_ee/magic"); + settings_delete("via_ee/layout"); + settings_delete("via_ee/custom"); + // settings_delete("via_ee/keymaps"); + settings_delete("via_ee/encoder"); + settings_delete("via_ee/macros/len"); + settings_delete("via_ee/macros/datas"); + settings_delete("via_ee/debounce"); + // settings_delete("via_ee/changed"); + char setting_name[20]={0}; + for(int i=0;i=DYNAMIC_KEYMAP_LAYER_COUNT) return; + int rc; + char setting_name[20]; + sprintf(setting_name,"via_ee/keymaps/%d",i); + rc = settings_save_one(setting_name, &via_ee_device.keymaps[i*KEYMAP_LEN], KEYMAP_LEN); + if (rc) { + LOG_DBG("write failed:%d", rc); + } else { + LOG_DBG("OK.\n"); + } + + // via_ee_update_changed_keys(i); +} +void via_ee_read_keymap(uint8_t layer) +{ + if(layer >=DYNAMIC_KEYMAP_LAYER_COUNT) return; + int rc; + char setting_name[20]; + sprintf(setting_name,"via_ee/keymaps/%d",layer); + LOG_HEXDUMP_DBG(&via_ee_device.keymaps[layer*KEYMAP_LEN],32,"keymap"); + rc = load_immediate_value(setting_name, &via_ee_device.keymaps[layer*KEYMAP_LEN], KEYMAP_LEN); + if (rc == -ENOENT) { + LOG_DBG("via_ee/keymaps/%d:%02x (default)\n",layer,via_ee_device.keymaps[layer*KEYMAP_LEN]); + } else if (rc == 0) { + LOG_HEXDUMP_DBG(&via_ee_device.keymaps[layer*KEYMAP_LEN],32,"store keymap"); + + for (int row = 0; row < MATRIX_ROWS; row++) { + for (int column = 0; column < MATRIX_COLS; column++) { + uint16_t keycode=(via_ee_device.keymaps[layer * KEYMAP_LEN+row*MATRIX_COLS*2+ column*2]<<8) +via_ee_device.keymaps[layer * KEYMAP_LEN+row*MATRIX_COLS*2+ column*2+1]; + if(keycode !=keycode_at_keymap_location_raw(layer, row, column)) + { + LOG_DBG("set layer:%d,row:%d,column:%d,keycode:%x",layer,row,column,keycode); + set_zmk_keymap(layer,row,column,keycode); + } + } + } + } +} + +void via_ee_read_keymaps(void) +{ + for(int i=0;i=0;i--) + { + if(via_ee_device.macros[i]!=0) + break; + } + return i+1; +} +void via_ee_update_macros(void) +{ + int rc; + int len =check_macros_len(); + LOG_DBG("macros len:%d",len); + if(len >0) + { + rc = settings_save_one("via_ee/macros/len", (const void *)&len, sizeof(len)); + if (rc) { + LOG_DBG("write failed:%d", rc); + } else { + LOG_DBG("OK.\n"); + } + rc = settings_save_one("via_ee/macros/datas", (const void *)&via_ee_device.macros[0], len); + if (rc) { + LOG_DBG("write failed:%d", rc); + } else { + LOG_DBG("OK.\n"); + } + } +} +void via_ee_delete_macros(void) +{ + LOG_DBG("."); + settings_delete("via_ee/macros/len"); + settings_delete("via_ee/macros/datas"); +} +void via_ee_read_macros(void) +{ + int rc; + int len=0; + rc=load_immediate_value("via_ee/macros/len", &len, sizeof(len)); + if (rc == -ENOENT) { + LOG_DBG("via_ee/macros/len:%02x (default)\n",len); + memset(&via_ee_device.macros,0,sizeof(via_ee_device.macros)); + } else if (rc == 0) { + LOG_DBG("via_ee/macros/len:%02x \n",len); + } + + if(len >0) + { + rc=load_immediate_value("via_ee/macros/datas", &via_ee_device.macros[0], len); + if (rc == -ENOENT) { + + LOG_DBG("via_ee/macros/data:%02x (default)\n",len); + } else if (rc == 0) { + + LOG_HEXDUMP_DBG(&via_ee_device.macros[0],32,"macros"); + } + } +} +// void via_ee_read_changed_keys(void) +// { +// int rc; + +// char setting_name[20]={0}; +// for(int i=0;i=DYNAMIC_KEYMAP_LAYER_COUNT) return; +// int rc; +// char setting_name[20]={0}; +// sprintf(setting_name,"via_ee/changed/%d",layer); +// rc = settings_save_one(setting_name, &via_ee_device.changed_keys[layer], 20); +// if (rc) { +// LOG_DBG("write failed:%d", rc); +// } else { +// LOG_DBG("OK.\n"); +// } +// } +// void via_set_changed_key(uint8_t layer,uint8_t row,uint8_t col) +// { +// uint8_t index = row*MATRIX_COLS +col; +// uint8_t pos = index/8; +// uint8_t bits = 1<<(index %8); +// via_ee_device.changed_keys[layer][pos] |= bits; +// LOG_DBG("layer:%d,row:%d,col:%d,pos:%d,bits:%x",layer,row,col,pos,bits); +// } +// void via_ee_reset_changed_keys(void) +// { +// // settings_delete("via_ee/changed"); +// char setting_name[20]={0}; +// for(int i=0;i> 8; + target--; + } + via_ee_update_layout(); +} + +#if defined(AUDIO_ENABLE) +float via_device_indication_song[][2] = SONG(STARTUP_SOUND); +#endif // AUDIO_ENABLE + +// Used by VIA to tell a device to flash LEDs (or do something else) when that +// device becomes the active device being configured, on startup or switching +// between devices. This function will be called six times, at 200ms interval, +// with an incrementing value starting at zero. Since this function is called +// an even number of times, it can call a toggle function and leave things in +// the original state. +__attribute__((weak)) void via_set_device_indication(uint8_t value) { +#if defined(BACKLIGHT_ENABLE) + backlight_toggle(); +#endif // BACKLIGHT_ENABLE +#if defined(RGBLIGHT_ENABLE) + rgblight_toggle_noeeprom(); +#endif // RGBLIGHT_ENABLE +#if defined(RGB_MATRIX_ENABLE) + rgb_matrix_toggle_noeeprom(); +#endif // RGB_MATRIX_ENABLE +#if defined(LED_MATRIX_ENABLE) + led_matrix_toggle_noeeprom(); +#endif // LED_MATRIX_ENABLE +#if defined(AUDIO_ENABLE) + if (value == 0) { + wait_ms(10); + PLAY_SONG(via_device_indication_song); + } +#endif // AUDIO_ENABLE +} + +// Called by QMK core to process VIA-specific keycodes. +// bool process_record_via(uint16_t keycode, keyrecord_t *record) { +// // Handle macros +// if (record->event.pressed) { +// if (keycode >= QK_MACRO && keycode <= QK_MACRO_MAX) { +// uint8_t id = keycode - QK_MACRO; +// dynamic_keymap_macro_send(id); +// return false; +// } +// } + +// return true; +// } + +// +// via_custom_value_command() has the default handling of custom values for Core modules. +// If a keyboard is using the default Core modules, it does not need to be overridden, +// the VIA keyboard definition will have matching channel/IDs. +// +// If a keyboard has some extra custom values, then via_custom_value_command_kb() can be +// overridden to handle the extra custom values, leaving via_custom_value_command() to +// handle the custom values for Core modules. +// +// If a keyboard has custom values and code that are overlapping with Core modules, +// then via_custom_value_command() can be overridden and call the same functions +// as the default implementation, or do whatever else is required. +// +// DO NOT call raw_hid_send() in the override function. +// + +// This is the default handler for "extra" custom values, i.e. keyboard-specific custom values +// that are not handled by via_custom_value_command(). +__attribute__((weak)) void via_custom_value_command_kb(uint8_t *data, uint8_t length) { + // data = [ command_id, channel_id, value_id, value_data ] + uint8_t *command_id = &(data[0]); + // Return the unhandled state + *command_id = id_unhandled; +} + +// This is the default handler for custom value commands. +// It routes commands with channel IDs to command handlers as such: +// +// id_qmk_backlight_channel -> via_qmk_backlight_command() +// id_qmk_rgblight_channel -> via_qmk_rgblight_command() +// id_qmk_rgb_matrix_channel -> via_qmk_rgb_matrix_command() +// id_qmk_led_matrix_channel -> via_qmk_led_matrix_command() +// id_qmk_audio_channel -> via_qmk_audio_command() +// +__attribute__((weak)) void via_custom_value_command(uint8_t *data, uint8_t length) { + // data = [ command_id, channel_id, value_id, value_data ] + uint8_t *channel_id = &(data[1]); + +#if defined(BACKLIGHT_ENABLE) + if (*channel_id == id_qmk_backlight_channel) { + via_qmk_backlight_command(data, length); + return; + } +#endif // BACKLIGHT_ENABLE + +#if defined(RGBLIGHT_ENABLE) + if (*channel_id == id_qmk_rgblight_channel) { + via_qmk_rgblight_command(data, length); + return; + } +#endif // RGBLIGHT_ENABLE + +#if defined(RGB_MATRIX_ENABLE) + if (*channel_id == id_qmk_rgb_matrix_channel) { + via_qmk_rgb_matrix_command(data, length); + return; + } +#endif // RGB_MATRIX_ENABLE + +#if defined(LED_MATRIX_ENABLE) + if (*channel_id == id_qmk_led_matrix_channel) { + via_qmk_led_matrix_command(data, length); + return; + } +#endif // LED_MATRIX_ENABLE + +#if defined(AUDIO_ENABLE) + if (*channel_id == id_qmk_audio_channel) { + via_qmk_audio_command(data, length); + return; + } +#endif // AUDIO_ENABLE + + (void)channel_id; // force use of variable + + // If we haven't returned before here, then let the keyboard level code + // handle this, if it is overridden, otherwise by default, this will + // return the unhandled state. + via_custom_value_command_kb(data, length); +} + +// Keyboard level code can override this, but shouldn't need to. +// Controlling custom features should be done by overriding +// via_custom_value_command_kb() instead. +__attribute__((weak)) bool via_command_kb(uint8_t *data, uint8_t length) { + return false; +} + +void raw_hid_receive(uint8_t *data, uint8_t length) { + uint8_t *command_id = &(data[0]); + uint8_t *command_data = &(data[1]); + + // If via_command_kb() returns true, the command was fully + // handled, including calling raw_hid_send() + if (via_command_kb(data, length)) { + return; + } + + switch (*command_id) { + case id_bootloader_jump: + sys_reboot(0x4e); + break; + case kc_get_protocol_version: + command_data[0]=1; + break; + case kc_get_default_layer: + command_data[0]=zmk_keymap_highest_layer_active(); + break; + case kc_get_firmware_version: + // uint32_t value = ZMK_VERSION; + // command_data[1] = (value >> 24) & 0xFF; + // command_data[2] = (value >> 16) & 0xFF; + // command_data[3] = (value >> 8) & 0xFF; + // command_data[4] = value & 0xFF; + uint8_t offset =0; + uint8_t len =strlen(APP_VERSION_STRING); + memcpy(&command_data[offset],APP_VERSION_STRING,len); + + offset += len; + command_data[offset++] =' '; + len =strlen(__DATE__); + memcpy(&command_data[offset],__DATE__,len); + + offset += len; + command_data[offset++] =' '; + + len =strlen(__TIME__); + memcpy(&command_data[offset],__TIME__,len); + + break; + + case id_get_protocol_version: { + command_data[0] = VIA_PROTOCOL_VERSION >> 8; + command_data[1] = VIA_PROTOCOL_VERSION & 0xFF; + break; + } + case id_get_keyboard_value: { + switch (command_data[0]) { + case id_uptime: { + uint32_t value = k_uptime_get();//timer_read32(); + command_data[1] = (value >> 24) & 0xFF; + command_data[2] = (value >> 16) & 0xFF; + command_data[3] = (value >> 8) & 0xFF; + command_data[4] = value & 0xFF; + break; + } + case id_layout_options: { + uint32_t value = via_get_layout_options(); + command_data[1] = (value >> 24) & 0xFF; + command_data[2] = (value >> 16) & 0xFF; + command_data[3] = (value >> 8) & 0xFF; + command_data[4] = value & 0xFF; + break; + } + case id_switch_matrix_state: { + uint8_t offset = command_data[1]; + uint8_t rows = 28 / ((MATRIX_COLS + 7) / 8); + uint8_t i = 2; + for (uint8_t row = 0; row < rows && row + offset < MATRIX_ROWS; row++) { + matrix_row_t value = matrix_get_row(row + offset); +#if (MATRIX_COLS > 24) + command_data[i++] = (value >> 24) & 0xFF; +#endif +#if (MATRIX_COLS > 16) + command_data[i++] = (value >> 16) & 0xFF; +#endif +#if (MATRIX_COLS > 8) + command_data[i++] = (value >> 8) & 0xFF; +#endif + command_data[i++] = value & 0xFF; + } + break; + } + case id_firmware_version: { + uint32_t value = VIA_FIRMWARE_VERSION; + command_data[1] = (value >> 24) & 0xFF; + command_data[2] = (value >> 16) & 0xFF; + command_data[3] = (value >> 8) & 0xFF; + command_data[4] = value & 0xFF; + break; + } + default: { + // The value ID is not known + // Return the unhandled state + *command_id = id_unhandled; + break; + } + } + break; + } + case id_set_keyboard_value: { + switch (command_data[0]) { + case id_layout_options: { + uint32_t value = ((uint32_t)command_data[1] << 24) | ((uint32_t)command_data[2] << 16) | ((uint32_t)command_data[3] << 8) | (uint32_t)command_data[4]; + via_set_layout_options(value); + break; + } + case id_device_indication: { + uint8_t value = command_data[1]; + via_set_device_indication(value); + break; + } + default: { + // The value ID is not known + // Return the unhandled state + *command_id = id_unhandled; + break; + } + } + break; + } + case id_dynamic_keymap_get_keycode: { + uint16_t keycode = dynamic_keymap_get_keycode(command_data[0], command_data[1], command_data[2]); + command_data[3] = keycode >> 8; + command_data[4] = keycode & 0xFF; + break; + } + case id_dynamic_keymap_set_keycode: { + dynamic_keymap_set_keycode(command_data[0], command_data[1], command_data[2], (command_data[3] << 8) | command_data[4]); + break; + } + case id_dynamic_keymap_reset: { + dynamic_keymap_reset(true); + + break; + } + case id_custom_set_value: + case id_custom_get_value: + case id_custom_save: { + via_custom_value_command(data, length); + break; + } +#ifdef VIA_EEPROM_ALLOW_RESET + case id_eeprom_reset: { + via_eeprom_set_valid(false); + eeconfig_init_via(); + break; + } +#endif + case id_dynamic_keymap_macro_get_count: { + command_data[0] = dynamic_keymap_macro_get_count(); + break; + } + case id_dynamic_keymap_macro_get_buffer_size: { + uint16_t size = dynamic_keymap_macro_get_buffer_size(); + command_data[0] = size >> 8; + command_data[1] = size & 0xFF; + break; + } + case id_dynamic_keymap_macro_get_buffer: { + uint16_t offset = (command_data[0] << 8) | command_data[1]; + uint16_t size = command_data[2]; // size <= 28 + dynamic_keymap_macro_get_buffer(offset, size, &command_data[3]); + break; + } + case id_dynamic_keymap_macro_set_buffer: { + uint16_t offset = (command_data[0] << 8) | command_data[1]; + uint16_t size = command_data[2]; // size <= 28 + dynamic_keymap_macro_set_buffer(offset, size, &command_data[3]); + break; + } + case id_dynamic_keymap_macro_reset: { + dynamic_keymap_macro_reset(true); + break; + } + case id_dynamic_keymap_get_layer_count: { + command_data[0] = dynamic_keymap_get_layer_count(); + break; + } + case id_dynamic_keymap_get_buffer: { + uint16_t offset = (command_data[0] << 8) | command_data[1]; + uint16_t size = command_data[2]; // size <= 28 + dynamic_keymap_get_buffer(offset, size, &command_data[3]); + break; + } + case id_dynamic_keymap_set_buffer: { + uint16_t offset = (command_data[0] << 8) | command_data[1]; + uint16_t size = command_data[2]; // size <= 28 + dynamic_keymap_set_buffer(offset, size, &command_data[3]); + break; + } +#ifdef ENCODER_MAP_ENABLE + case id_dynamic_keymap_get_encoder: { + uint16_t keycode = dynamic_keymap_get_encoder(command_data[0], command_data[1], command_data[2] != 0); + command_data[3] = keycode >> 8; + command_data[4] = keycode & 0xFF; + break; + } + case id_dynamic_keymap_set_encoder: { + dynamic_keymap_set_encoder(command_data[0], command_data[1], command_data[2] != 0, (command_data[3] << 8) | command_data[4]); + break; + } +#endif + case 0xAB: + factory_test_rx(data, length); + break; + + case kc_set_key_debounce: + if(command_data[0]==0 || command_data[1]==0 ||command_data[2] ==0) + { + break; + } + user_set_debounce(command_data[0],command_data[1],command_data[2]); + debouce.scan_period_ms =command_data[0]; + debouce.debounce_press_ms = command_data[1]; + debouce.debounce_release_ms = command_data[2]; + via_save_debounce(); + break; + case kc_get_key_debounce: + command_data[0] =debouce.scan_period_ms; + command_data[1] =debouce.debounce_press_ms; + command_data[2] =debouce.debounce_release_ms; + break; + default: { + // The command ID is not known + // Return the unhandled state + *command_id = id_unhandled; + break; + } + } + + // Return the same buffer, optionally with values changed + // (i.e. returning state to the host, or the unhandled state). + raw_hid_send(data, length); +} + +#if defined(BACKLIGHT_ENABLE) + +void via_qmk_backlight_command(uint8_t *data, uint8_t length) { + // data = [ command_id, channel_id, value_id, value_data ] + uint8_t *command_id = &(data[0]); + uint8_t *value_id_and_data = &(data[2]); + + switch (*command_id) { + case id_custom_set_value: { + via_qmk_backlight_set_value(value_id_and_data); + break; + } + case id_custom_get_value: { + via_qmk_backlight_get_value(value_id_and_data); + break; + } + case id_custom_save: { + via_qmk_backlight_save(); + break; + } + default: { + *command_id = id_unhandled; + break; + } + } +} + +# if BACKLIGHT_LEVELS == 0 +# error BACKLIGHT_LEVELS == 0 +# endif + +void via_qmk_backlight_get_value(uint8_t *data) { + // data = [ value_id, value_data ] + uint8_t *value_id = &(data[0]); + uint8_t *value_data = &(data[1]); + switch (*value_id) { + case id_qmk_backlight_brightness: { + // level / BACKLIGHT_LEVELS * 255 + value_data[0] = ((uint16_t)get_backlight_level() * UINT8_MAX) / BACKLIGHT_LEVELS; + break; + } + case id_qmk_backlight_effect: { +# ifdef BACKLIGHT_BREATHING + value_data[0] = is_backlight_breathing() ? 1 : 0; +# else + value_data[0] = 0; +# endif + break; + } + } +} + +void via_qmk_backlight_set_value(uint8_t *data) { + // data = [ value_id, value_data ] + uint8_t *value_id = &(data[0]); + uint8_t *value_data = &(data[1]); + switch (*value_id) { + case id_qmk_backlight_brightness: { + // level / 255 * BACKLIGHT_LEVELS + backlight_level_noeeprom(((uint16_t)value_data[0] * BACKLIGHT_LEVELS) / UINT8_MAX); + break; + } + case id_qmk_backlight_effect: { +# ifdef BACKLIGHT_BREATHING + if (value_data[0] == 0) { + backlight_disable_breathing(); + } else { + backlight_enable_breathing(); + } +# endif + break; + } + } +} + +void via_qmk_backlight_save(void) { + eeconfig_update_backlight_current(); +} + +#endif // BACKLIGHT_ENABLE + +#if defined(RGBLIGHT_ENABLE) +# ifndef RGBLIGHT_LIMIT_VAL +# define RGBLIGHT_LIMIT_VAL 255 +# endif + +void via_qmk_rgblight_command(uint8_t *data, uint8_t length) { + // data = [ command_id, channel_id, value_id, value_data ] + uint8_t *command_id = &(data[0]); + uint8_t *value_id_and_data = &(data[2]); + + switch (*command_id) { + case id_custom_set_value: { + via_qmk_rgblight_set_value(value_id_and_data); + break; + } + case id_custom_get_value: { + via_qmk_rgblight_get_value(value_id_and_data); + break; + } + case id_custom_save: { + via_qmk_rgblight_save(); + break; + } + default: { + *command_id = id_unhandled; + break; + } + } +} + +void via_qmk_rgblight_get_value(uint8_t *data) { + // data = [ value_id, value_data ] + uint8_t *value_id = &(data[0]); + uint8_t *value_data = &(data[1]); + switch (*value_id) { + case id_qmk_rgblight_brightness: { + value_data[0] = ((uint16_t)rgblight_get_val() * UINT8_MAX) / RGBLIGHT_LIMIT_VAL; + break; + } + case id_qmk_rgblight_effect: { + value_data[0] = rgblight_is_enabled() ? rgblight_get_mode() : 0; + break; + } + case id_qmk_rgblight_effect_speed: { + value_data[0] = rgblight_get_speed(); + break; + } + case id_qmk_rgblight_color: { + value_data[0] = rgblight_get_hue(); + value_data[1] = rgblight_get_sat(); + break; + } + } +} + +void via_qmk_rgblight_set_value(uint8_t *data) { + // data = [ value_id, value_data ] + uint8_t *value_id = &(data[0]); + uint8_t *value_data = &(data[1]); + switch (*value_id) { + case id_qmk_rgblight_brightness: { + rgblight_sethsv_noeeprom(rgblight_get_hue(), rgblight_get_sat(), ((uint16_t)value_data[0] * RGBLIGHT_LIMIT_VAL) / UINT8_MAX); + break; + } + case id_qmk_rgblight_effect: { + if (value_data[0] == 0) { + rgblight_disable_noeeprom(); + } else { + rgblight_enable_noeeprom(); + rgblight_mode_noeeprom(value_data[0]); + } + break; + } + case id_qmk_rgblight_effect_speed: { + rgblight_set_speed_noeeprom(value_data[0]); + break; + } + case id_qmk_rgblight_color: { + rgblight_sethsv_noeeprom(value_data[0], value_data[1], rgblight_get_val()); + break; + } + } +} + +void via_qmk_rgblight_save(void) { + eeconfig_update_rgblight_current(); +} + +#endif // QMK_RGBLIGHT_ENABLE + +#if defined(RGB_MATRIX_ENABLE) + +void via_qmk_rgb_matrix_command(uint8_t *data, uint8_t length) { + // data = [ command_id, channel_id, value_id, value_data ] + uint8_t *command_id = &(data[0]); + uint8_t *value_id_and_data = &(data[2]); + + switch (*command_id) { + case id_custom_set_value: { + via_qmk_rgb_matrix_set_value(value_id_and_data); + break; + } + case id_custom_get_value: { + via_qmk_rgb_matrix_get_value(value_id_and_data); + break; + } + case id_custom_save: { + via_qmk_rgb_matrix_save(); + break; + } + default: { + *command_id = id_unhandled; + break; + } + } +} + +void via_qmk_rgb_matrix_get_value(uint8_t *data) { + // data = [ value_id, value_data ] + uint8_t *value_id = &(data[0]); + uint8_t *value_data = &(data[1]); + + switch (*value_id) { + case id_qmk_rgb_matrix_brightness: { + value_data[0] = ((uint16_t)rgb_matrix_get_val() * UINT8_MAX) / RGB_MATRIX_MAXIMUM_BRIGHTNESS; + break; + } + case id_qmk_rgb_matrix_effect: { + value_data[0] = rgb_matrix_is_enabled() ? rgb_matrix_get_mode() : 0; + break; + } + case id_qmk_rgb_matrix_effect_speed: { + value_data[0] = rgb_matrix_get_speed(); + break; + } + case id_qmk_rgb_matrix_color: { + value_data[0] = rgb_matrix_get_hue(); + value_data[1] = rgb_matrix_get_sat(); + break; + } + } +} + +void via_qmk_rgb_matrix_set_value(uint8_t *data) { + // data = [ value_id, value_data ] + uint8_t *value_id = &(data[0]); + uint8_t *value_data = &(data[1]); + switch (*value_id) { + case id_qmk_rgb_matrix_brightness: { + rgb_matrix_sethsv_noeeprom(rgb_matrix_get_hue(), rgb_matrix_get_sat(), scale8(value_data[0], RGB_MATRIX_MAXIMUM_BRIGHTNESS)); + break; + } + case id_qmk_rgb_matrix_effect: { + if (value_data[0] == 0) { + rgb_matrix_disable_noeeprom(); + } else { + rgb_matrix_enable_noeeprom(); + rgb_matrix_mode_noeeprom(value_data[0]); + } + break; + } + case id_qmk_rgb_matrix_effect_speed: { + rgb_matrix_set_speed_noeeprom(value_data[0]); + break; + } + case id_qmk_rgb_matrix_color: { + rgb_matrix_sethsv_noeeprom(value_data[0], value_data[1], rgb_matrix_get_val()); + break; + } + } +} + +void via_qmk_rgb_matrix_save(void) { + eeconfig_update_rgb_matrix(); +} + +#endif // RGB_MATRIX_ENABLE + +#if defined(LED_MATRIX_ENABLE) + +void via_qmk_led_matrix_command(uint8_t *data, uint8_t length) { + // data = [ command_id, channel_id, value_id, value_data ] + uint8_t *command_id = &(data[0]); + uint8_t *value_id_and_data = &(data[2]); + + switch (*command_id) { + case id_custom_set_value: { + via_qmk_led_matrix_set_value(value_id_and_data); + break; + } + case id_custom_get_value: { + via_qmk_led_matrix_get_value(value_id_and_data); + break; + } + case id_custom_save: { + via_qmk_led_matrix_save(); + break; + } + default: { + *command_id = id_unhandled; + break; + } + } +} + +void via_qmk_led_matrix_get_value(uint8_t *data) { + // data = [ value_id, value_data ] + uint8_t *value_id = &(data[0]); + uint8_t *value_data = &(data[1]); + + switch (*value_id) { + case id_qmk_led_matrix_brightness: { + value_data[0] = ((uint16_t)led_matrix_get_val() * UINT8_MAX) / LED_MATRIX_MAXIMUM_BRIGHTNESS; + break; + } + case id_qmk_led_matrix_effect: { + value_data[0] = led_matrix_is_enabled() ? led_matrix_get_mode() : 0; + break; + } + case id_qmk_led_matrix_effect_speed: { + value_data[0] = led_matrix_get_speed(); + break; + } + } +} + +void via_qmk_led_matrix_set_value(uint8_t *data) { + // data = [ value_id, value_data ] + uint8_t *value_id = &(data[0]); + uint8_t *value_data = &(data[1]); + switch (*value_id) { + case id_qmk_led_matrix_brightness: { + led_matrix_set_val_noeeprom(scale8(value_data[0], LED_MATRIX_MAXIMUM_BRIGHTNESS)); + break; + } + case id_qmk_led_matrix_effect: { + if (value_data[0] == 0) { + led_matrix_disable_noeeprom(); + } else { + led_matrix_enable_noeeprom(); + led_matrix_mode_noeeprom(value_data[0]); + } + break; + } + case id_qmk_led_matrix_effect_speed: { + led_matrix_set_speed_noeeprom(value_data[0]); + break; + } + } +} + +void via_qmk_led_matrix_save(void) { + eeconfig_update_led_matrix(); +} + +#endif // LED_MATRIX_ENABLE + +#if defined(AUDIO_ENABLE) + +extern audio_config_t audio_config; + +void via_qmk_audio_command(uint8_t *data, uint8_t length) { + // data = [ command_id, channel_id, value_id, value_data ] + uint8_t *command_id = &(data[0]); + uint8_t *value_id_and_data = &(data[2]); + + switch (*command_id) { + case id_custom_set_value: { + via_qmk_audio_set_value(value_id_and_data); + break; + } + case id_custom_get_value: { + via_qmk_audio_get_value(value_id_and_data); + break; + } + case id_custom_save: { + via_qmk_audio_save(); + break; + } + default: { + *command_id = id_unhandled; + break; + } + } +} + +void via_qmk_audio_get_value(uint8_t *data) { + // data = [ value_id, value_data ] + uint8_t *value_id = &(data[0]); + uint8_t *value_data = &(data[1]); + switch (*value_id) { + case id_qmk_audio_enable: { + value_data[0] = audio_config.enable ? 1 : 0; + break; + } + case id_qmk_audio_clicky_enable: { + value_data[0] = audio_config.clicky_enable ? 1 : 0; + break; + } + } +} + +void via_qmk_audio_set_value(uint8_t *data) { + // data = [ value_id, value_data ] + uint8_t *value_id = &(data[0]); + uint8_t *value_data = &(data[1]); + switch (*value_id) { + case id_qmk_audio_enable: { + audio_config.enable = value_data[0] ? 1 : 0; + break; + } + case id_qmk_audio_clicky_enable: { + audio_config.clicky_enable = value_data[0] ? 1 : 0; + break; + } + } +} + +void via_qmk_audio_save(void) { + eeconfig_update_audio(audio_config.raw); +} + +#endif // QMK_AUDIO_ENABLE + +void factory_test_send(uint8_t *payload, uint8_t length) { + + uint16_t checksum = 0; + uint8_t data[RAW_EPSIZE] = {0}; + + uint8_t i = 0; + data[i++] = 0xAB; + + memcpy(&data[i], payload, length); + i += length; + + for (uint8_t i = 1; i < RAW_EPSIZE - 3; i++) + checksum += data[i]; + data[RAW_EPSIZE - 2] = checksum & 0xFF; + data[RAW_EPSIZE - 1] = (checksum >> 8) & 0xFF; + + raw_hid_send(data, RAW_EPSIZE); + +} +enum { + FACTORY_TEST_CMD_BACKLIGHT = 0x01, + FACTORY_TEST_CMD_OS_SWITCH, + FACTORY_TEST_CMD_JUMP_TO_BL, + FACTORY_TEST_CMD_INT_PIN, + FACTORY_TEST_CMD_GET_TRANSPORT, + FACTORY_TEST_CMD_CHARGING_ADC, + FACTORY_TEST_CMD_RADIO_CARRIER, + FACTORY_TEST_CMD_GET_BUILD_TIME, +}; +enum { + OS_SWITCH = 0x01, +}; +void factory_test_rx(uint8_t *data, uint8_t length) { + if (data[0] == 0xAB) { + uint16_t checksum = 0; + + for (uint8_t i = 1; i < RAW_EPSIZE - 3; i++) { + checksum += data[i]; + } + /* Verify checksum */ + if ((checksum & 0xFF) != data[RAW_EPSIZE - 2] || checksum >> 8 != data[RAW_EPSIZE - 1]) return; + + + + switch (data[1]) { + + case FACTORY_TEST_CMD_OS_SWITCH: + report_os_sw_state = data[2]; + if (report_os_sw_state) { + // dip_switch_read(true); + } + break; + + } + } +} + +bool dip_switch_update_user(uint8_t index, bool active) { + LOG_ERR("index:%d,active:%d",index,active); + if (report_os_sw_state) { + + uint8_t payload[3] = {FACTORY_TEST_CMD_OS_SWITCH, OS_SWITCH, active}; + factory_test_send(payload, 3); + } + + return true; +} + +void via_ee_read_debounce(void) +{ + int rc; + rc = load_immediate_value("via_ee/debounce", &debouce, sizeof(debouce)); + if (rc == -ENOENT) { + + LOG_DBG("via_ee/debounce,(default)\n"); + debouce.scan_period_ms = DT_PROP(DT_NODELABEL(kscan0), debounce_scan_period_ms); + debouce.debounce_press_ms = DT_PROP(DT_NODELABEL(kscan0), debounce_press_ms); + debouce.debounce_release_ms = DT_PROP(DT_NODELABEL(kscan0), debounce_release_ms); + } else if (rc == 0) { + user_set_debounce(debouce.scan_period_ms,debouce.debounce_press_ms,debouce.debounce_release_ms); + } + LOG_ERR("via_ee/debounce:%02x%02x%02x\n",debouce.scan_period_ms,debouce.debounce_press_ms,debouce.debounce_release_ms ); + +} +void via_ee_update_debounce(void) +{ + int rc; + rc = settings_save_one("via_ee/debounce", (const void *)&debouce, sizeof(debouce)); + if (rc) { + LOG_DBG("write failed:%d", rc); + } else { + LOG_DBG("OK.\n"); + } +} + diff --git a/app/src/launcher/launcher.h b/app/src/launcher/launcher.h new file mode 100644 index 00000000000..3d35d78f553 --- /dev/null +++ b/app/src/launcher/launcher.h @@ -0,0 +1,466 @@ +#pragma once + +#include +#include +#include +// #include +#include +#include "keycodes.h" + +// #define VIA_FIRMWARE_VERSION 0x000102002 + +#define ZMK_HID_MAIN_VAL_DATA (0x00 << 0) +#define ZMK_HID_MAIN_VAL_CONST (0x01 << 0) + +#define ZMK_HID_MAIN_VAL_ARRAY (0x00 << 1) +#define ZMK_HID_MAIN_VAL_VAR (0x01 << 1) + +#define ZMK_HID_MAIN_VAL_ABS (0x00 << 2) +#define ZMK_HID_MAIN_VAL_REL (0x01 << 2) + +#define ZMK_HID_MAIN_VAL_NO_WRAP (0x00 << 3) +#define ZMK_HID_MAIN_VAL_WRAP (0x01 << 3) + +#define ZMK_HID_MAIN_VAL_LIN (0x00 << 4) +#define ZMK_HID_MAIN_VAL_NON_LIN (0x01 << 4) + +#define ZMK_HID_MAIN_VAL_PREFERRED (0x00 << 5) +#define ZMK_HID_MAIN_VAL_NO_PREFERRED (0x01 << 5) + +#define ZMK_HID_MAIN_VAL_NO_NULL (0x00 << 6) +#define ZMK_HID_MAIN_VAL_NULL (0x01 << 6) + +#define ZMK_HID_MAIN_VAL_NON_VOL (0x00 << 7) +#define ZMK_HID_MAIN_VAL_VOL (0x01 << 7) + +#define HID_USAGE_PAGE_2(a,b) \ + HID_ITEM(HID_ITEM_TAG_USAGE_PAGE, HID_ITEM_TYPE_GLOBAL, 2), a,b + + +#define RAW_USAGE_PAGE 0xFF60 +#define RAW_USAGE_ID 0x61 +#define RAW_EPSIZE 32 + +static const uint8_t zmk_hid_via_report_desc[]= { + HID_USAGE_PAGE_2((RAW_USAGE_PAGE &0xff),(RAW_USAGE_PAGE>>8) ), // Vendor Defined + HID_USAGE(RAW_USAGE_ID), // Vendor Defined + HID_COLLECTION(0x01), // Application + // Data to host + HID_USAGE( 0x62), // Vendor Defined + HID_LOGICAL_MIN8(0x00), + HID_LOGICAL_MAX16(0xFF,0x00), + HID_REPORT_COUNT(RAW_EPSIZE), + HID_REPORT_SIZE(0x08), + HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS), + + // Data from host + HID_USAGE(0x63), // Vendor Defined + HID_LOGICAL_MIN8(0x00), + HID_LOGICAL_MAX16(0xFF,0x00), + HID_REPORT_COUNT(RAW_EPSIZE), + HID_REPORT_SIZE(0x08), + HID_OUTPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS | ZMK_HID_MAIN_VAL_NON_VOL), + + HID_END_COLLECTION +}; + +enum via_command_id { + id_get_protocol_version = 0x01, // always 0x01 + id_get_keyboard_value = 0x02, + id_set_keyboard_value = 0x03, + id_dynamic_keymap_get_keycode = 0x04, + id_dynamic_keymap_set_keycode = 0x05, + id_dynamic_keymap_reset = 0x06, + id_custom_set_value = 0x07, + id_custom_get_value = 0x08, + id_custom_save = 0x09, + id_eeprom_reset = 0x0A, + id_bootloader_jump = 0x0B, + id_dynamic_keymap_macro_get_count = 0x0C, + id_dynamic_keymap_macro_get_buffer_size = 0x0D, + id_dynamic_keymap_macro_get_buffer = 0x0E, + id_dynamic_keymap_macro_set_buffer = 0x0F, + id_dynamic_keymap_macro_reset = 0x10, + id_dynamic_keymap_get_layer_count = 0x11, + id_dynamic_keymap_get_buffer = 0x12, + id_dynamic_keymap_set_buffer = 0x13, + id_dynamic_keymap_get_encoder = 0x14, + id_dynamic_keymap_set_encoder = 0x15, + + kc_get_protocol_version = 0xa0, + kc_get_firmware_version = 0xa1, //ascii ver + kc_get_support_feature = 0xa2, + kc_get_default_layer = 0xa3, + kc_set_key_debounce = 0xb0, + kc_get_key_debounce = 0xb1, + + id_unhandled = 0xFF, +}; + +enum via_keyboard_value_id { + id_uptime = 0x01, + id_layout_options = 0x02, + id_switch_matrix_state = 0x03, + id_firmware_version = 0x04, + id_device_indication = 0x05, +}; + +enum via_channel_id { + id_custom_channel = 0, + id_qmk_backlight_channel = 1, + id_qmk_rgblight_channel = 2, + id_qmk_rgb_matrix_channel = 3, + id_qmk_audio_channel = 4, + id_qmk_led_matrix_channel = 5, +}; + +enum via_qmk_backlight_value { + id_qmk_backlight_brightness = 1, + id_qmk_backlight_effect = 2, +}; + +enum via_qmk_rgblight_value { + id_qmk_rgblight_brightness = 1, + id_qmk_rgblight_effect = 2, + id_qmk_rgblight_effect_speed = 3, + id_qmk_rgblight_color = 4, +}; + +enum via_qmk_rgb_matrix_value { + id_qmk_rgb_matrix_brightness = 1, + id_qmk_rgb_matrix_effect = 2, + id_qmk_rgb_matrix_effect_speed = 3, + id_qmk_rgb_matrix_color = 4, +}; + +enum via_qmk_led_matrix_value { + id_qmk_led_matrix_brightness = 1, + id_qmk_led_matrix_effect = 2, + id_qmk_led_matrix_effect_speed = 3, +}; + +enum via_qmk_audio_value { + id_qmk_audio_enable = 1, + id_qmk_audio_clicky_enable = 2, +}; + +typedef uint32_t matrix_row_t ; + +#if CONFIG_ZMK_LAUNCHER +#define VIA_ENABLE +#endif + +enum{ + BT_HST1 = QK_KB_0, + BT_HST2 , + BT_HST3 , + KC_BOOT , + PAIR_24G , + KC_SCRN_LOCK, + UC_CMD_CMA,//Command-Comma (,): Open preferences for the front app. + UC_LOPT,//Left Option + UC_ROPT,//Right Option + UC_LCMD,//Left Command + UC_RCMD,//Right Command + UC_CTRL_LEFT,//ctrl+ <- ,switch desktops + UC_CTRL_RIGHT,//ctrl+ -> ,switch desktops + UC_EMOJI_MAC,//Command+Control+space open emoji in mac + UC_TASK_VIEW,//LG(TAB) Open Task View + UC_SWITCH_DESKTOP_LEFT,//LG(LC(LEFT)) switch desktops + UC_SWITCH_DESKTOP_RIGHT,//LG(LC(RIGHT)) switch desktops + UC_FILE_EXPLORER,//LG(E) ,Open File Explorer. + UC_LOCK,//LG(L),Lock your PC or switch accounts. + UC_SETTINGS,//LG(I),Open Settings. + UC_EMOJI_WIN,//LG(DOT),open emoji in win + UC_PRNS_WIN,//LG(LS(S)) + UC_PRNS_MAC,//LG(LS(N4)) + UC_KEYCHRON,//0x770100 +}; + +#if CONFIG_SHIELD_KEYCHRON_B6_UK +#define QMK_BUILDDATE "2024-03-02" +#elif CONFIG_SHIELD_KEYCHRON_B6_US +#define QMK_BUILDDATE "2024-03-03" +#elif CONFIG_SHIELD_KEYCHRON_B6_JIS +#define QMK_BUILDDATE "2024-03-04" +#elif CONFIG_SHIELD_KEYCHRON_B1_US +#define QMK_BUILDDATE "2024-04-05" +#elif CONFIG_SHIELD_KEYCHRON_B1_UK +#define QMK_BUILDDATE "2024-04-06" +#elif CONFIG_SHIELD_KEYCHRON_B1_JIS +#define QMK_BUILDDATE "2024-04-07" +#elif CONFIG_SHIELD_KEYCHRON_B2_JIS +#define QMK_BUILDDATE "2024-05-08" +#elif CONFIG_SHIELD_KEYCHRON_B2_US +#define QMK_BUILDDATE "2024-05-09" +#elif CONFIG_SHIELD_KEYCHRON_B2_UK +#define QMK_BUILDDATE "2024-05-10" +#elif CONFIG_SHIELD_KEYCHRON_B2_KR +#define QMK_BUILDDATE "2024-08-21" +#else +#define QMK_BUILDDATE "2024-05-27" +#endif + +#define EECONFIG_SIZE 0 +#define MATRIX_COLS DT_PROP_LEN(DT_NODELABEL(kscan0), col_gpios) +#define MATRIX_ROWS DT_PROP_LEN(DT_NODELABEL(kscan0), row_gpios) +#define DYNAMIC_KEYMAP_LAYER_COUNT ZMK_KEYMAP_LAYERS_LEN +#define TOTAL_EEPROM_BYTE_COUNT 2560//4000 +#define KEYMAP_LEN (MATRIX_COLS*MATRIX_ROWS*2) +// Keyboard level code can change where VIA stores the magic. +// The magic is the build date YYMMDD encoded as BCD in 3 bytes, +// thus installing firmware built on a different date to the one +// already installed can be detected and the EEPROM data is reset. +// The only reason this is important is in case EEPROM usage changes +// and the EEPROM was not explicitly reset by bootmagic lite. +#ifndef VIA_EEPROM_MAGIC_ADDR +# define VIA_EEPROM_MAGIC_ADDR (EECONFIG_SIZE) +#endif + +#define VIA_EEPROM_LAYOUT_OPTIONS_ADDR (VIA_EEPROM_MAGIC_ADDR + 3) + +// Changing the layout options size after release will invalidate EEPROM, +// but this is something that should be set correctly on initial implementation. +// 1 byte is enough for most uses (i.e. 8 binary states, or 6 binary + 1 ternary/quaternary ) +#ifndef VIA_EEPROM_LAYOUT_OPTIONS_SIZE +# define VIA_EEPROM_LAYOUT_OPTIONS_SIZE 1 +#endif + +// Allow override of the layout options default value. +// This requires advanced knowledge of how VIA stores layout options +// and is only really useful for setting a boolean layout option +// state to true by default. +#ifndef VIA_EEPROM_LAYOUT_OPTIONS_DEFAULT +# define VIA_EEPROM_LAYOUT_OPTIONS_DEFAULT 0x00000000 +#endif + +// The end of the EEPROM memory used by VIA +// By default, dynamic keymaps will start at this if there is no +// custom config +#define VIA_EEPROM_CUSTOM_CONFIG_ADDR (VIA_EEPROM_LAYOUT_OPTIONS_ADDR + VIA_EEPROM_LAYOUT_OPTIONS_SIZE) + +#ifndef VIA_EEPROM_CUSTOM_CONFIG_SIZE +# define VIA_EEPROM_CUSTOM_CONFIG_SIZE 0 +#endif + +#define VIA_EEPROM_CONFIG_END (VIA_EEPROM_CUSTOM_CONFIG_ADDR + VIA_EEPROM_CUSTOM_CONFIG_SIZE) + +#ifdef VIA_ENABLE +# define DYNAMIC_KEYMAP_EEPROM_START (VIA_EEPROM_CONFIG_END) +#else +# include "eeconfig.h" +# define DYNAMIC_KEYMAP_EEPROM_START (EECONFIG_SIZE) +#endif + +#ifdef ENCODER_ENABLE +# include "encoder.h" +#else +# define NUM_ENCODERS 0 +#endif + +#ifndef DYNAMIC_KEYMAP_LAYER_COUNT +# define DYNAMIC_KEYMAP_LAYER_COUNT 4 +#endif + +#ifndef DYNAMIC_KEYMAP_MACRO_COUNT +# define DYNAMIC_KEYMAP_MACRO_COUNT 16 +#endif + +#ifndef TOTAL_EEPROM_BYTE_COUNT +# error Unknown total EEPROM size. Cannot derive maximum for dynamic keymaps. +#endif + +#ifndef DYNAMIC_KEYMAP_EEPROM_MAX_ADDR +# define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR (TOTAL_EEPROM_BYTE_COUNT - 1) +#endif + +#if DYNAMIC_KEYMAP_EEPROM_MAX_ADDR > (TOTAL_EEPROM_BYTE_COUNT - 1) +# pragma message STR(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR) " > " STR((TOTAL_EEPROM_BYTE_COUNT - 1)) +# error DYNAMIC_KEYMAP_EEPROM_MAX_ADDR is configured to use more space than what is available for the selected EEPROM driver +#endif + +// Due to usage of uint16_t check for max 65535 +#if DYNAMIC_KEYMAP_EEPROM_MAX_ADDR > 65535 +# pragma message STR(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR) " > 65535" +# error DYNAMIC_KEYMAP_EEPROM_MAX_ADDR must be less than 65536 +#endif + +// If DYNAMIC_KEYMAP_EEPROM_ADDR not explicitly defined in config.h, +#ifndef DYNAMIC_KEYMAP_EEPROM_ADDR +# define DYNAMIC_KEYMAP_EEPROM_ADDR DYNAMIC_KEYMAP_EEPROM_START +#endif + +// Dynamic encoders starts after dynamic keymaps +#ifndef DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR +# define DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR (DYNAMIC_KEYMAP_EEPROM_ADDR + (DYNAMIC_KEYMAP_LAYER_COUNT * MATRIX_ROWS * MATRIX_COLS * 2)) +#endif + +// Dynamic macro starts after dynamic encoders, but only when using ENCODER_MAP +#ifdef ENCODER_MAP_ENABLE +# ifndef DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR +# define DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR (DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR + (DYNAMIC_KEYMAP_LAYER_COUNT * NUM_ENCODERS * 2 * 2)) +# endif // DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR +#else // ENCODER_MAP_ENABLE +# ifndef DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR +# define DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR (DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR) +# endif // DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR +#endif // ENCODER_MAP_ENABLE + +// Sanity check that dynamic keymaps fit in available EEPROM +// If there's not 100 bytes available for macros, then something is wrong. +// The keyboard should override DYNAMIC_KEYMAP_LAYER_COUNT to reduce it, +// or DYNAMIC_KEYMAP_EEPROM_MAX_ADDR to increase it, *only if* the microcontroller has +// more than the default. +_Static_assert((DYNAMIC_KEYMAP_EEPROM_MAX_ADDR) - (DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR) >= 100, "Dynamic keymaps are configured to use more EEPROM than is available."); + +// Dynamic macros are stored after the keymaps and use what is available +// up to and including DYNAMIC_KEYMAP_EEPROM_MAX_ADDR. +#ifndef DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE +# define DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE (DYNAMIC_KEYMAP_EEPROM_MAX_ADDR - DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + 1) +#endif + +#ifndef DYNAMIC_KEYMAP_MACRO_DELAY +# define DYNAMIC_KEYMAP_MACRO_DELAY TAP_CODE_DELAY +#endif +//keympas[][] + +#define NUM_KEYMAP_LAYERS_RAW DYNAMIC_KEYMAP_LAYER_COUNT //((uint8_t)(sizeof(keymaps) / ((MATRIX_ROWS) * (MATRIX_COLS) * sizeof(uint16_t)))) +// +// This is changed only when the command IDs change, +// so VIA Configurator can detect compatible firmware. +#define VIA_PROTOCOL_VERSION 0x000C + +// This is a version number for the firmware for the keyboard. +// It can be used to ensure the VIA keyboard definition and the firmware +// have the same version, especially if there are changes to custom values. +// Define this in config.h to override and bump this number. +// This is *not* required if the keyboard is only using basic functionality +// and not using custom values for lighting, rotary encoders, etc. +#ifndef VIA_FIRMWARE_VERSION +# define VIA_FIRMWARE_VERSION 0x00000000 +#endif + +#ifndef TAP_CODE_DELAY +# define TAP_CODE_DELAY 10 +#endif + +// Can be called in an overriding via_init_kb() to test if keyboard level code usage of +// EEPROM is invalid and use/save defaults. +bool via_eeprom_is_valid(void); + +// Sets VIA/keyboard level usage of EEPROM to valid/invalid +// Keyboard level code (eg. via_init_kb()) should not call this +void via_eeprom_set_valid(bool valid); + +// Called by QMK core to initialize dynamic keymaps etc. +void eeconfig_init_via(void); +void via_init(void); + +// Used by VIA to store and retrieve the layout options. +uint32_t via_get_layout_options(void); +void via_set_layout_options(uint32_t value); +void via_set_layout_options_kb(uint32_t value); + +// Used by VIA to tell a device to flash LEDs (or do something else) when that +// device becomes the active device being configured, on startup or switching +// between devices. +void via_set_device_indication(uint8_t value); + +// Called by QMK core to process VIA-specific keycodes. +// bool process_record_via(uint16_t keycode, keyrecord_t *record); + +// These are made external so that keyboard level custom value handlers can use them. +#if defined(BACKLIGHT_ENABLE) +void via_qmk_backlight_command(uint8_t *data, uint8_t length); +void via_qmk_backlight_set_value(uint8_t *data); +void via_qmk_backlight_get_value(uint8_t *data); +void via_qmk_backlight_save(void); +#endif + +#if defined(RGBLIGHT_ENABLE) +void via_qmk_rgblight_command(uint8_t *data, uint8_t length); +void via_qmk_rgblight_set_value(uint8_t *data); +void via_qmk_rgblight_get_value(uint8_t *data); +void via_qmk_rgblight_save(void); +#endif + +#if defined(RGB_MATRIX_ENABLE) +void via_qmk_rgb_matrix_command(uint8_t *data, uint8_t length); +void via_qmk_rgb_matrix_set_value(uint8_t *data); +void via_qmk_rgb_matrix_get_value(uint8_t *data); +void via_qmk_rgb_matrix_save(void); +#endif + +#if defined(LED_MATRIX_ENABLE) +void via_qmk_led_matrix_command(uint8_t *data, uint8_t length); +void via_qmk_led_matrix_set_value(uint8_t *data); +void via_qmk_led_matrix_get_value(uint8_t *data); +void via_qmk_led_matrix_save(void); +#endif + +#if defined(AUDIO_ENABLE) +void via_qmk_audio_command(uint8_t *data, uint8_t length); +void via_qmk_audio_set_value(uint8_t *data); +void via_qmk_audio_get_value(uint8_t *data); +void via_qmk_audio_save(void); +#endif + +void raw_hid_receive(uint8_t *data, uint8_t length); + +union VIA_EE_DEVICE { + uint8_t raw[TOTAL_EEPROM_BYTE_COUNT]; + struct { + uint8_t magic[3]; + uint8_t layout_options[VIA_EEPROM_LAYOUT_OPTIONS_SIZE]; + #if VIA_EEPROM_CUSTOM_CONFIG_SIZE + uint8_t custom[VIA_EEPROM_CUSTOM_CONFIG_SIZE]; + #endif + uint8_t keymaps[(DYNAMIC_KEYMAP_LAYER_COUNT * KEYMAP_LEN)]; + #ifdef ENCODER_MAP_ENABLE + uint8_t encoder[DYNAMIC_KEYMAP_LAYER_COUNT * NUM_ENCODERS * 2 * 2]; + #endif + uint8_t macros[DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE]; + uint8_t changed_keys[DYNAMIC_KEYMAP_LAYER_COUNT][20]; + } __packed; +}; + +typedef union VIA_EE_DEVICE _via_ee_device; +extern _via_ee_device via_ee_device; + +struct user_debounce{ + uint8_t scan_period_ms; + uint8_t debounce_press_ms; + uint8_t debounce_release_ms; +}; + +void via_ee_read_all(void); +void via_ee_read_macros(void); +void via_ee_read_keymaps(void); +void via_ee_read_magic(void); +void via_ee_read_debounce(void); +void via_ee_update_debounce(void); +void via_ee_update_magic(void); +void via_ee_update_layout(void); +void via_ee_update_custom(void); +void via_ee_update_keymaps(void); +void via_ee_update_keymap(uint8_t i); +void via_ee_update_encoder(void); +void via_ee_update_macros(void); +void via_ee_delete_macros(void); +void via_ee_read_changed_keys(void); +void via_ee_update_changed_keys(uint8_t layer); +void via_set_changed_key(uint8_t layer,uint8_t row,uint8_t col); +void via_ee_reset_changed_keys(void); +void via_ee_reset_keymaps(void); +void set_zmk_keymap(uint8_t layer,uint8_t row ,uint8_t column ,uint16_t keycode) ; +void generate_via_keymaps(void); +void via_save_debounce(void); + +static inline uint8_t eeprom_read_byte(uint16_t addr) +{ + return via_ee_device.raw[addr]; +} +static inline void eeprom_update_byte(uint16_t addr, uint8_t value) +{ + via_ee_device.raw[addr]=value; +} \ No newline at end of file diff --git a/app/src/launcher/map_keycode.c b/app/src/launcher/map_keycode.c new file mode 100644 index 00000000000..0afb2627a26 --- /dev/null +++ b/app/src/launcher/map_keycode.c @@ -0,0 +1,703 @@ + +#include "launcher.h" +#include "keycodes.h" +#include +#include +#include +#include +#include +#include "dynamic_keymap.h" + + +LOG_MODULE_DECLARE(zmk,4);// CONFIG_ZMK_LOG_LEVEL); + +uint16_t gen_via_keymaps[DYNAMIC_KEYMAP_LAYER_COUNT][MATRIX_ROWS][MATRIX_COLS]; +void update_zmk_keymap(uint8_t layer,uint8_t pos,struct zmk_behavior_binding* binding); +struct zmk_behavior_binding * get_zmk_keymap(uint8_t layer ,uint8_t pos); + +static inline uint16_t KEYCODE2SYSTEM_R(uint16_t key) { + switch (key) { + case SYSTEM_POWER_DOWN: + return KC_SYSTEM_POWER; + case SYSTEM_SLEEP_0: + return KC_SYSTEM_SLEEP; + case SYSTEM_WAKE_UP_0: + return KC_SYSTEM_WAKE; + default: + return 0; + } +} +static inline uint16_t KEYCODE2CONSUMER_R(uint16_t key) { + switch (key) { + case AUDIO_MUTE: + return KC_AUDIO_MUTE; + case AUDIO_VOL_UP: + return KC_AUDIO_VOL_UP; + case AUDIO_VOL_DOWN: + return KC_AUDIO_VOL_DOWN; + case TRANSPORT_NEXT_TRACK: + return KC_MEDIA_NEXT_TRACK; + case TRANSPORT_PREV_TRACK: + return KC_MEDIA_PREV_TRACK; + case TRANSPORT_FAST_FORWARD: + return KC_MEDIA_FAST_FORWARD; + case TRANSPORT_REWIND: + return KC_MEDIA_REWIND; + case TRANSPORT_STOP: + return KC_MEDIA_STOP; + case TRANSPORT_STOP_EJECT: + return KC_MEDIA_EJECT; + case TRANSPORT_PLAY_PAUSE: + return KC_MEDIA_PLAY_PAUSE; + case AL_CC_CONFIG: + return KC_MEDIA_SELECT; + case AL_EMAIL: + return KC_MAIL; + case AL_CALCULATOR: + return KC_CALCULATOR; + case AL_LOCAL_BROWSER: + return KC_MY_COMPUTER; + case AL_CONTROL_PANEL: + return KC_CONTROL_PANEL; + case AL_ASSISTANT: + return KC_ASSISTANT; + case AC_SEARCH: + return KC_WWW_SEARCH; + case AC_HOME: + return KC_WWW_HOME; + case AC_BACK: + return KC_WWW_BACK; + case AC_FORWARD: + return KC_WWW_FORWARD; + case AC_STOP: + return KC_WWW_STOP; + case AC_REFRESH: + return KC_WWW_REFRESH; + case BRIGHTNESS_UP: + return KC_BRIGHTNESS_UP; + case BRIGHTNESS_DOWN: + return KC_BRIGHTNESS_DOWN; + case AC_BOOKMARKS: + return KC_WWW_FAVORITES; + case AC_DESKTOP_SHOW_ALL_WINDOWS: + return KC_MISSION_CONTROL; + case AC_SOFT_KEY_LEFT: + return KC_LAUNCHPAD; + default: + return 0; + } +} +/* keycode to system usage */ +static inline uint16_t KEYCODE2SYSTEM(uint8_t key) { + switch (key) { + case KC_SYSTEM_POWER: + return SYSTEM_POWER_DOWN; + case KC_SYSTEM_SLEEP: + return SYSTEM_SLEEP_0; + case KC_SYSTEM_WAKE: + return SYSTEM_WAKE_UP_0; + default: + return 0; + } +} + +/* keycode to consumer usage */ +static inline uint16_t KEYCODE2CONSUMER(uint8_t key) { + switch (key) { + case KC_AUDIO_MUTE: + return AUDIO_MUTE; + case KC_AUDIO_VOL_UP: + return AUDIO_VOL_UP; + case KC_AUDIO_VOL_DOWN: + return AUDIO_VOL_DOWN; + case KC_MEDIA_NEXT_TRACK: + return TRANSPORT_NEXT_TRACK; + case KC_MEDIA_PREV_TRACK: + return TRANSPORT_PREV_TRACK; + case KC_MEDIA_FAST_FORWARD: + return TRANSPORT_FAST_FORWARD; + case KC_MEDIA_REWIND: + return TRANSPORT_REWIND; + case KC_MEDIA_STOP: + return TRANSPORT_STOP; + case KC_MEDIA_EJECT: + return TRANSPORT_STOP_EJECT; + case KC_MEDIA_PLAY_PAUSE: + return TRANSPORT_PLAY_PAUSE; + case KC_MEDIA_SELECT: + return AL_CC_CONFIG; + case KC_MAIL: + return AL_EMAIL; + case KC_CALCULATOR: + return AL_CALCULATOR; + case KC_MY_COMPUTER: + return AL_LOCAL_BROWSER; + case KC_CONTROL_PANEL: + return AL_CONTROL_PANEL; + case KC_ASSISTANT: + return AL_ASSISTANT; + case KC_WWW_SEARCH: + return AC_SEARCH; + case KC_WWW_HOME: + return AC_HOME; + case KC_WWW_BACK: + return AC_BACK; + case KC_WWW_FORWARD: + return AC_FORWARD; + case KC_WWW_STOP: + return AC_STOP; + case KC_WWW_REFRESH: + return AC_REFRESH; + case KC_BRIGHTNESS_UP: + return BRIGHTNESS_UP; + case KC_BRIGHTNESS_DOWN: + return BRIGHTNESS_DOWN; + case KC_WWW_FAVORITES: + return AC_BOOKMARKS; + case KC_MISSION_CONTROL: + return AC_DESKTOP_SHOW_ALL_WINDOWS; + case KC_LAUNCHPAD: + return AC_SOFT_KEY_LEFT; + default: + return 0; + } +} +uint8_t mod_to_zmk(uint8_t mod) +{ + if(mod &0x10) + { + mod &= 0x0f; + mod <<= 4; + return mod; + } + else + { + return mod ; + } +} +uint8_t mod_to_zmk_keycode(uint8_t mod_5bits) +{ + uint8_t mod=mod_to_zmk(mod_5bits); + for(int i=0;i<8;i++) + { + if(mod &(1<>4; + if(left_mode) + { + mod = left_mode; + } + else if(right_mode) + { + mod =0x10 | right_mode; + } + return mod; +} +uint8_t mod_kc_to_via(uint8_t kc) +{ + uint8_t mod =1<< (kc-LCTRL); + return mod_to_via(mod); +} +#define QK_MODS_GET_MODS(kc) (((kc) >> 8) & 0x1F) +#define QK_MODS_GET_BASIC_KEYCODE(kc) ((kc)&0xFF) + +void via_keycode_to_binding(uint8_t keycode,struct zmk_behavior_binding * binding) +{ + switch (keycode) { + case BASIC_KEYCODE_RANGE: + case MODIFIER_KEYCODE_RANGE: + binding->behavior_dev="KEY_PRESS";//"&kp"; + binding->param1 =keycode; + break; + + case SYSTEM_KEYCODE_RANGE: + binding->behavior_dev="KEY_PRESS";//"&kp"; + binding->param1 =KEYCODE2SYSTEM(keycode)|(HID_USAGE_GD<<16); + break; + case CONSUMER_KEYCODE_RANGE: + binding->behavior_dev="KEY_PRESS";//"&kp"; + binding->param1 =KEYCODE2CONSUMER(keycode)|(HID_USAGE_CONSUMER<<16); + break; + } +} + +void set_zmk_keymap(uint8_t layer,uint8_t row ,uint8_t column ,uint16_t keycode) { + + int32_t position = zmk_matrix_transform_row_column_to_position(row, column); + if(position<0) return; + struct zmk_behavior_binding binding; + memset(&binding,0,sizeof(binding)); + + switch (keycode) { + case BASIC_KEYCODE_RANGE: + case MODIFIER_KEYCODE_RANGE: + binding.behavior_dev="KEY_PRESS";//"&kp"; + binding.param1 =keycode; + break; + + case SYSTEM_KEYCODE_RANGE: + binding.behavior_dev="KEY_PRESS";//"&kp"; + binding.param1 =KEYCODE2SYSTEM(keycode)|(HID_USAGE_GD<<16); + break; + case CONSUMER_KEYCODE_RANGE: + binding.behavior_dev="KEY_PRESS";//"&kp"; + binding.param1 =KEYCODE2CONSUMER(keycode)|(HID_USAGE_CONSUMER<<16); + break; + + case MOUSE_KEYCODE_RANGE: + binding.behavior_dev="KEY_PRESS";//"&kp"; + binding.param1 = keycode|(HID_USAGE_GEN_BUTTON<<16); + break; + case KC_NO: + binding.behavior_dev="NONE";//"&none"; + break; + case KC_TRANSPARENT: + binding.behavior_dev="TRANS";//"&trans"; + break; + case QK_MODS ... QK_MODS_MAX: + binding.behavior_dev="KEY_PRESS";//"&kp"; + binding.param1 =(mod_to_zmk(QK_MODS_GET_MODS(keycode))<<24) | (HID_USAGE_KEY<<16)|QK_MODS_GET_BASIC_KEYCODE(keycode); + + break; + case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: + binding.behavior_dev="LAYER_TAP"; + binding.param1= (keycode>>8) &0x0f; + binding.param2= keycode&0xff; + break; + + case QK_TO ... QK_TO_MAX:; + // Layer set "GOTO" + binding.behavior_dev="TO_LAYER";//"&to"; + binding.param1= keycode &0x1f; + break; + case QK_MOMENTARY ... QK_MOMENTARY_MAX:; + // Momentary action_layer + binding.behavior_dev="MO";// "&mo"; + binding.param1= keycode &0x1f; + break; + // case QK_DEF_LAYER ... QK_DEF_LAYER_MAX:; + // // Set default action_layer + // action_layer = QK_DEF_LAYER_GET_LAYER(keycode); + // action.code = ACTION_DEFAULT_LAYER_SET(action_layer); + // break; + case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX:; + // Set toggle + binding.behavior_dev="TOGGLE_LAYER";//"&tog"; + binding.param1= keycode &0x1f; + break; + + case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX:; + // OSL(action_layer) - One-shot action_layer + binding.behavior_dev="STICKY_LAYER";//"&sl"; + binding.param1= keycode &0x1f; + break; + case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX: + binding.behavior_dev="TAPD_LAYER"; + // void update_td_layer(uint32_t pos,uint8_t layer); + // update_td_layer(position,keycode&0x1f); + binding.param1 =keycode&0x1f; + break; + + case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX:; + // OSM(mod) - One-shot mod + binding.behavior_dev="STICKY_KEY";//"&sk"; + binding.param1= keycode &0x1f; + break; + + // case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX: + // binding.behavior_dev="LAYER_TAP";//"<"; + // binding.param1= (keycode>>8) &0x0f; + // binding.param2= keycode &0xff; + // break; + // case QK_LAYER_MOD ... QK_LAYER_MOD_MAX: + // mod = mod_config(QK_LAYER_MOD_GET_MODS(keycode)); + // action_layer = QK_LAYER_MOD_GET_LAYER(keycode); + // action.code = ACTION_LAYER_MODS(action_layer, (mod & 0x10) ? mod << 4 : mod); + // break; + + case QK_MOD_TAP ... QK_MOD_TAP_MAX: + binding.behavior_dev="MOD_TAP";//"&mt"; + binding.param1 =mod_to_zmk_keycode(QK_MODS_GET_MODS(keycode));//fix mod + binding.param2 =QK_MODS_GET_BASIC_KEYCODE(keycode); + break; + case QK_MACRO ... QK_MACRO_MAX: + binding.behavior_dev="ZM_MA"; + binding.param1 =0x770000 |(keycode&0xff); + break; + case QK_GRAVE_ESCAPE: + binding.behavior_dev="GRAVE_ESCAPE"; + break; + case QK_SPACE_CADET_LEFT_CTRL_PARENTHESIS_OPEN: + binding.behavior_dev="MOD_TAP"; + binding.param1 =LCTRL; + binding.param2 =LS(N9); + break; + case QK_SPACE_CADET_RIGHT_CTRL_PARENTHESIS_CLOSE: + binding.behavior_dev="MOD_TAP"; + binding.param1 =RCTRL; + binding.param2 =LS(N0); + break; + case QK_SPACE_CADET_LEFT_SHIFT_PARENTHESIS_OPEN: + binding.behavior_dev="MOD_TAP"; + binding.param1 =LSHFT; + binding.param2 =LS(N9); + break; + case QK_SPACE_CADET_RIGHT_SHIFT_PARENTHESIS_CLOSE: + binding.behavior_dev="MOD_TAP"; + binding.param1 =RSHFT; + binding.param2 =LS(N0); + break; + case QK_SPACE_CADET_LEFT_ALT_PARENTHESIS_OPEN: + binding.behavior_dev="MOD_TAP"; + binding.param1 =LALT; + binding.param2 =LS(N9); + break; + case QK_SPACE_CADET_RIGHT_ALT_PARENTHESIS_CLOSE: + binding.behavior_dev="MOD_TAP"; + binding.param1 =RALT; + binding.param2 =LS(N0); + break; + case QK_SPACE_CADET_RIGHT_SHIFT_ENTER: + binding.behavior_dev="MOD_TAP"; + binding.param1 =RSHFT; + binding.param2 =RET; + break; + + case QK_KB ... QK_KB_MAX: + switch(keycode) + { + case BT_HST1: + binding.behavior_dev="bt_pair0"; + break; + case BT_HST2: + binding.behavior_dev="bt_pair1"; + break; + case BT_HST3: + binding.behavior_dev="bt_pair2"; + break; + case PAIR_24G: + binding.behavior_dev="bt_pair3"; + break; + case KC_BOOT: + binding.behavior_dev="lp_bootloader"; + break; + case KC_SCRN_LOCK: + binding.behavior_dev="KEY_PRESS";//"&kp"; + binding.param1 =C_AL_LOCK; + break; + case UC_CMD_CMA: + binding.behavior_dev="user_custom";//"&kp"; + binding.param1 =LG(COMMA); + break; + case UC_LOPT: + binding.behavior_dev="user_custom";//"&kp"; + binding.param1 =LALT; + break; + case UC_ROPT: + binding.behavior_dev="user_custom";//"&kp"; + binding.param1 =RALT; + break; + case UC_LCMD: + binding.behavior_dev="user_custom";//"&kp"; + binding.param1 =LCMD; + break; + case UC_RCMD: + binding.behavior_dev="user_custom";//"&kp"; + binding.param1 =RCMD; + break; + case UC_CTRL_LEFT: + binding.behavior_dev="user_custom";//"&kp"; + binding.param1 =LC(LEFT); + break; + case UC_CTRL_RIGHT: + binding.behavior_dev="user_custom";//"&kp"; + binding.param1 =LC(RIGHT); + break; + case UC_EMOJI_MAC: + binding.behavior_dev="user_custom";//"&kp"; + binding.param1 =LC(LG(SPACE)); + break; + case UC_TASK_VIEW: + binding.behavior_dev="user_custom";//"&kp"; + binding.param1 =LG(TAB); + break; + case UC_SWITCH_DESKTOP_LEFT: + binding.behavior_dev="user_custom";//"&kp"; + binding.param1 =LG(LC(LEFT)); + break; + case UC_SWITCH_DESKTOP_RIGHT: + binding.behavior_dev="user_custom";//"&kp"; + binding.param1 =LG(LC(RIGHT)); + break; + case UC_FILE_EXPLORER: + binding.behavior_dev="user_custom";//"&kp"; + binding.param1 =LG(E); + break; + case UC_LOCK: + binding.behavior_dev="user_custom";//"&kp"; + binding.param1 =LG(L); + break; + case UC_SETTINGS: + binding.behavior_dev="user_custom";//"&kp"; + binding.param1 =LG(I); + break; + case UC_EMOJI_WIN: + binding.behavior_dev="user_custom";//"&kp"; + binding.param1 =LG(DOT); + break; + case UC_PRNS_WIN: + binding.behavior_dev="user_custom";//"&kp"; + binding.param1 =LG(LS(S)); + break; + case UC_PRNS_MAC: + binding.behavior_dev="user_custom";//"&kp"; + binding.param1 =LG(LS(N4)); + break; + case UC_KEYCHRON: + binding.behavior_dev="ZM_MA";//"&kp"; + binding.param1 =0x770100; + break; + } + break; + default: + binding.behavior_dev="NONE";//"&none"; + break; + } + // LOG_DBG("layer:%d,row:%d,col:%d,keycode:%d to binding:%s,p1:%x,p2:%x",layer,row,column,keycode,binding.behavior_dev,binding.param1,binding.param2); + update_zmk_keymap(layer,position,&binding); +} +void generate_via_keymaps(void) +{ + for (int layer = 0; layer < DYNAMIC_KEYMAP_LAYER_COUNT; layer++) { + for (int row = 0; row < MATRIX_ROWS; row++) { + for (int column = 0; column < MATRIX_COLS; column++) { + int32_t position = zmk_matrix_transform_row_column_to_position(row, column); + if(position>=0) + { + struct zmk_behavior_binding * binding =get_zmk_keymap(layer,position); + char * behavior_dev=binding->behavior_dev; + if(memcmp(behavior_dev,"KEY_PRESS",9)==0)//&kp + { + uint16_t keycode= binding->param1 &0xffff; + uint8_t page = binding->param1 >>16 &0xff; + uint8_t mod = binding->param1>>24; + + switch(page) + { + case HID_USAGE_GD: + gen_via_keymaps[layer][row][column]=KEYCODE2SYSTEM_R(keycode); + break; + case HID_USAGE_KEY: + gen_via_keymaps[layer][row][column]=keycode; + if(mod) gen_via_keymaps[layer][row][column]|=mod_to_via(mod) <<8; + break; + case HID_USAGE_CONSUMER: + if(keycode == HID_USAGE_CONSUMER_AL_TERMINAL_LOCK_SCREENSAVER) + { + gen_via_keymaps[layer][row][column]=KC_SCRN_LOCK; //custom + } + else + gen_via_keymaps[layer][row][column]=KEYCODE2CONSUMER_R(keycode); + break; + case HID_USAGE_GEN_BUTTON: + gen_via_keymaps[layer][row][column] =keycode; + break; + } + + } else if(memcmp(behavior_dev,"MO",2)==0) { //&mo + uint16_t keycode= binding->param1 &0xffff; + gen_via_keymaps[layer][row][column]=QK_MOMENTARY | (keycode &0x1f); + + } else if(memcmp(behavior_dev,"TO_LAYER",8)==0) {//&to + uint16_t keycode= binding->param1 &0xffff; + gen_via_keymaps[layer][row][column]=QK_TO | (keycode &0x1f); + + } else if(memcmp(behavior_dev,"TOGGLE_LAYER",12)==0) {//&tog + uint16_t keycode= binding->param1 &0xffff; + gen_via_keymaps[layer][row][column]=QK_TOGGLE_LAYER | (keycode &0x1f); + + } else if(memcmp(behavior_dev,"TAPD_LAYER",10)==0) {//&tog + uint16_t keycode= binding->param1 &0x1f; + gen_via_keymaps[layer][row][column]=QK_LAYER_TAP_TOGGLE | (keycode ); + + } else if(memcmp(behavior_dev,"LAYER_TAP",9)==0) {//< + + uint8_t layer=binding->param1&0x0f; + uint8_t keycode =binding->param2&0xff; + gen_via_keymaps[layer][row][column]=QK_LAYER_TAP | (layer<<8)| (keycode); + + } else if(memcmp(behavior_dev,"MOD_TAP",7)==0) {//&mt + + uint8_t mod=binding->param1; + uint32_t keycode =binding->param2; + LOG_DBG("mod_tap,mod:%d,keycode:%x",mod,keycode); + if(mod ==RSHFT && keycode == RET ) + { + gen_via_keymaps[layer][row][column] =SC_SENT; + } + else if(keycode >0xffff) + { + switch(keycode) + { + case LS(N9): + if(mod ==LSHFT) + { + gen_via_keymaps[layer][row][column]=SC_LSPO; + }else if (mod ==LCTRL) + { + gen_via_keymaps[layer][row][column]=SC_LCPO; + }else if (mod ==LALT) + { + gen_via_keymaps[layer][row][column]=SC_LAPO; + } + break; + case LS(N0): + if(mod ==RSHFT) + { + gen_via_keymaps[layer][row][column]=SC_RSPC; + }else if (mod ==RCTRL) + { + gen_via_keymaps[layer][row][column]=SC_RCPC; + }else if (mod ==RALT) + { + gen_via_keymaps[layer][row][column]=SC_RAPC; + } + break; + + } + } + else + gen_via_keymaps[layer][row][column]=QK_MOD_TAP | (mod_kc_to_via(mod)<<8) | (keycode &0xff); + + } else if(memcmp(behavior_dev,"STICKY_LAYER",12)==0) {//&sl + + uint8_t layer =binding->param1&0x1f; + gen_via_keymaps[layer][row][column]=QK_ONE_SHOT_LAYER | (layer); + + } else if(memcmp(behavior_dev,"STICKY_KEY",9)==0) {//&sk + + uint8_t mod =binding->param1&0x1f; + gen_via_keymaps[layer][row][column]=QK_ONE_SHOT_MOD | (mod); + + } else if(memcmp(behavior_dev,"TRANS",5)==0) {//&trans + + gen_via_keymaps[layer][row][column]=KC_TRANSPARENT; + + } else if(memcmp(behavior_dev,"NONE",4)==0) {//&none + + gen_via_keymaps[layer][row][column]=KC_NO; + + } else if(memcmp(behavior_dev,"ZM_MA",5)==0){ + + if(binding->param1 ==0x770100) + { + gen_via_keymaps[layer][row][column]=UC_KEYCHRON; + } + else + gen_via_keymaps[layer][row][column]=QK_MACRO | (binding->param1 &0xff); + + } else if(memcmp(behavior_dev,"bt_pair0",8)==0){ + + gen_via_keymaps[layer][row][column] =BT_HST1; + } else if(memcmp(behavior_dev,"bt_pair1",8)==0){ + + gen_via_keymaps[layer][row][column] =BT_HST2; + + } else if(memcmp(behavior_dev,"bt_pair2",8)==0){ + + gen_via_keymaps[layer][row][column] =BT_HST3; + + } else if(memcmp(behavior_dev,"bt_pair3",8)==0){ + + gen_via_keymaps[layer][row][column] =PAIR_24G; + + } else if(memcmp(behavior_dev,"lp_bootloader",13)==0){ + + gen_via_keymaps[layer][row][column] =KC_BOOT; + + } else if(memcmp(behavior_dev,"GRAVE_ESCAPE",12)==0){ + + gen_via_keymaps[layer][row][column] =QK_GRAVE_ESCAPE; + + } else if(memcmp(behavior_dev,"user_custom",11)==0) { + + switch(binding->param1) + { + case LG(COMMA): + gen_via_keymaps[layer][row][column] =UC_CMD_CMA; + break; + case LALT: + gen_via_keymaps[layer][row][column] =UC_LOPT; + break; + case RALT: + gen_via_keymaps[layer][row][column] =UC_ROPT; + break; + case LCMD: + gen_via_keymaps[layer][row][column] =UC_LCMD; + break; + case RCMD: + gen_via_keymaps[layer][row][column] =UC_RCMD; + break; + case LC(LEFT): + gen_via_keymaps[layer][row][column] =UC_CTRL_LEFT; + break; + case LC(RIGHT): + gen_via_keymaps[layer][row][column] =UC_CTRL_RIGHT; + break; + case LC(LG(SPACE)): + gen_via_keymaps[layer][row][column] =UC_EMOJI_MAC; + break; + case LG(TAB): + gen_via_keymaps[layer][row][column] =UC_TASK_VIEW; + break; + case LG(LC(LEFT)): + gen_via_keymaps[layer][row][column] =UC_SWITCH_DESKTOP_LEFT; + break; + case LG(LC(RIGHT)): + gen_via_keymaps[layer][row][column] =UC_SWITCH_DESKTOP_RIGHT; + break; + case LG(E): + gen_via_keymaps[layer][row][column] =UC_FILE_EXPLORER; + break; + case LG(L): + gen_via_keymaps[layer][row][column] =UC_LOCK; + break; + case LG(I): + gen_via_keymaps[layer][row][column] =UC_SETTINGS; + break; + case LG(DOT): + gen_via_keymaps[layer][row][column] =UC_EMOJI_WIN; + break; + case LG(LS(N4)): + gen_via_keymaps[layer][row][column] =UC_PRNS_MAC; + break; + case LG(LS(S)): + gen_via_keymaps[layer][row][column] =UC_PRNS_WIN; + break; + + } + + } + + else { + gen_via_keymaps[layer][row][column]=KC_NO; + } + dynamic_keymap_set_keycode_no_update(layer, row, column, gen_via_keymaps[layer][row][column]); + //if(memcmp(behavior_dev,"TRANS",5)&&memcmp(behavior_dev,"KEY_PRESS",9) || layer ==3) + // if(memcmp(behavior_dev,"TRANS",5) && layer ==3) + // LOG_DBG("layer:%d,row:%d,col:%d,pos:%d,binding:%s,p1:%x,p2:%x,via keycode:%x",layer,row,column,position, binding->behavior_dev, binding->param1,binding->param2, gen_via_keymaps[layer][row][column]); + } + } + } + } +} diff --git a/app/src/launcher/mousekey.c b/app/src/launcher/mousekey.c new file mode 100644 index 00000000000..edb90abfb38 --- /dev/null +++ b/app/src/launcher/mousekey.c @@ -0,0 +1,785 @@ +/* + * Copyright 2011 Jun Wako + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "mousekey.h" +#include "keycodes.h" +#include +#include +#include +#include +#include +#include +#include +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#define IS_MOUSEKEY_BUTTON(code) (KC_MS_BTN1 <= (code) && (code) <= KC_MS_BTN8) + +static uint32_t timer_read(void){ + return k_uptime_get_32(); +} +uint32_t timer_elapsed(uint32_t last) { + return TIMER_DIFF_32(k_uptime_get_32(), last); +} + +static inline int8_t times_inv_sqrt2(int8_t x) { + // 181/256 (0.70703125) is used as an approximation for 1/sqrt(2) + // because it is close to the exact value which is 0.707106781 + const int16_t n = x * 181; + const uint16_t d = 256; + + // To ensure that the integer result is rounded accurately after + // division, check the sign of the numerator: + // If negative, subtract half of the denominator before dividing + // Otherwise, add half of the denominator before dividing + return n < 0 ? (n - d / 2) / d : (n + d / 2) / d; +} + +static report_mouse_t mouse_report = {ZMK_HID_REPORT_ID_MOUSE,0}; +static void mousekey_debug(void); +static uint8_t mousekey_accel = 0; +static uint8_t mousekey_repeat = 0; +static uint8_t mousekey_wheel_repeat = 0; +#ifdef MOUSEKEY_INERTIA +static uint8_t mousekey_frame = 0; // track whether gesture is inactive, first frame, or repeating +static int8_t mousekey_x_dir = 0; // -1 / 0 / 1 = left / neutral / right +static int8_t mousekey_y_dir = 0; // -1 / 0 / 0 = up / neutral / down +static int8_t mousekey_x_inertia = 0; // current velocity, limit +/- MOUSEKEY_TIME_TO_MAX +static int8_t mousekey_y_inertia = 0; // ... +#endif +#ifdef MK_KINETIC_SPEED +static uint32_t mouse_timer = 0; +#endif + +#ifndef MK_3_SPEED + +static uint32_t last_timer_c = 0; +static uint32_t last_timer_w = 0; + +/* + * Mouse keys acceleration algorithm + * http://en.wikipedia.org/wiki/Mouse_keys + * + * speed = delta * max_speed * (repeat / time_to_max)**((1000+curve)/1000) + */ +/* milliseconds between the initial key press and first repeated motion event (0-2550) */ +uint8_t mk_delay = MOUSEKEY_DELAY / 10; +/* milliseconds between repeated motion events (0-255) */ +uint8_t mk_interval = MOUSEKEY_INTERVAL; +/* steady speed (in action_delta units) applied each event (0-255) */ +uint8_t mk_max_speed = MOUSEKEY_MAX_SPEED; +/* number of events (count) accelerating to steady speed (0-255) */ +uint8_t mk_time_to_max = MOUSEKEY_TIME_TO_MAX; +/* ramp used to reach maximum pointer speed (NOT SUPPORTED) */ +// int8_t mk_curve = 0; +/* wheel params */ +/* milliseconds between the initial key press and first repeated motion event (0-2550) */ +uint8_t mk_wheel_delay = MOUSEKEY_WHEEL_DELAY / 10; +/* milliseconds between repeated motion events (0-255) */ +# ifdef MK_KINETIC_SPEED +uint16_t mk_wheel_interval = 1000U / MOUSEKEY_WHEEL_INITIAL_MOVEMENTS; +# else +uint8_t mk_wheel_interval = MOUSEKEY_WHEEL_INTERVAL; +# endif +uint8_t mk_wheel_max_speed = MOUSEKEY_WHEEL_MAX_SPEED; +uint8_t mk_wheel_time_to_max = MOUSEKEY_WHEEL_TIME_TO_MAX; + +# ifndef MK_COMBINED +# ifndef MK_KINETIC_SPEED +# ifndef MOUSEKEY_INERTIA + +/* Default accelerated mode */ + +static uint8_t move_unit(void) { + uint16_t unit; + if (mousekey_accel & (1 << 0)) { + unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed) / 4; + } else if (mousekey_accel & (1 << 1)) { + unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed) / 2; + } else if (mousekey_accel & (1 << 2)) { + unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed); + } else if (mousekey_repeat == 0) { + unit = MOUSEKEY_MOVE_DELTA; + } else if (mousekey_repeat >= mk_time_to_max) { + unit = MOUSEKEY_MOVE_DELTA * mk_max_speed; + } else { + unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed * mousekey_repeat) / mk_time_to_max; + } + return (unit > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : (unit == 0 ? 1 : unit)); +} + +# else // MOUSEKEY_INERTIA mode + +static int8_t move_unit(uint8_t axis) { + int16_t unit; + + // handle X or Y axis + int8_t inertia, dir; + if (axis) { + inertia = mousekey_y_inertia; + dir = mousekey_y_dir; + } else { + inertia = mousekey_x_inertia; + dir = mousekey_x_dir; + } + + if (mousekey_frame < 2) { // first frame(s): initial keypress moves one pixel + mousekey_frame = 1; + unit = dir * MOUSEKEY_MOVE_DELTA; + } else { // acceleration + // linear acceleration (is here for reference, but doesn't feel as good during use) + // unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed * inertia) / mk_time_to_max; + + // x**2 acceleration (quadratic, more precise for short movements) + int16_t percent = (inertia << 8) / mk_time_to_max; + percent = ((int32_t)percent * percent) >> 8; + if (inertia < 0) percent = -percent; + + // unit = sign(inertia) + (percent of max speed) + if (inertia > 0) + unit = 1; + else if (inertia < 0) + unit = -1; + else + unit = 0; + + unit = unit + ((mk_max_speed * percent) >> 8); + } + + if (unit > MOUSEKEY_MOVE_MAX) + unit = MOUSEKEY_MOVE_MAX; + else if (unit < -MOUSEKEY_MOVE_MAX) + unit = -MOUSEKEY_MOVE_MAX; + return unit; +} + +# endif // end MOUSEKEY_INERTIA mode + +static uint8_t wheel_unit(void) { + uint16_t unit; + if (mousekey_accel & (1 << 0)) { + unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed) / 4; + } else if (mousekey_accel & (1 << 1)) { + unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed) / 2; + } else if (mousekey_accel & (1 << 2)) { + unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed); + } else if (mousekey_wheel_repeat == 0) { + unit = MOUSEKEY_WHEEL_DELTA; + } else if (mousekey_wheel_repeat >= mk_wheel_time_to_max) { + unit = MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed; + } else { + unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed * mousekey_wheel_repeat) / mk_wheel_time_to_max; + } + return (unit > MOUSEKEY_WHEEL_MAX ? MOUSEKEY_WHEEL_MAX : (unit == 0 ? 1 : unit)); +} + +# else /* #ifndef MK_KINETIC_SPEED */ + +/* + * Kinetic movement acceleration algorithm + * + * current speed = I + A * T/50 + A * (T/50)^2 * 1/2 | maximum B + * + * T: time since the mouse movement started + * E: mouse events per second (set through MOUSEKEY_INTERVAL, UHK sends 250, the + * pro micro on my Signum 3.0 sends only 125!) + * I: initial speed at time 0 + * A: acceleration + * B: base mouse travel speed + */ +const uint16_t mk_accelerated_speed = MOUSEKEY_ACCELERATED_SPEED; +const uint16_t mk_base_speed = MOUSEKEY_BASE_SPEED; +const uint16_t mk_decelerated_speed = MOUSEKEY_DECELERATED_SPEED; +const uint16_t mk_initial_speed = MOUSEKEY_INITIAL_SPEED; + +static uint8_t move_unit(void) { + uint16_t speed = mk_initial_speed; + + if (mousekey_accel & (1 << 0)) { + speed = mk_decelerated_speed; + } else if (mousekey_accel & (1 << 2)) { + speed = mk_accelerated_speed; + } else if (mousekey_repeat && mouse_timer) { + const uint16_t time_elapsed = timer_elapsed(mouse_timer) / 50; + speed = mk_initial_speed + MOUSEKEY_MOVE_DELTA * time_elapsed + (MOUSEKEY_MOVE_DELTA * time_elapsed * time_elapsed) / 2; + if (speed > mk_base_speed) { + speed = mk_base_speed; + } + } + /* convert speed to USB mouse speed 1 to 127 */ + speed = (uint8_t)(speed / (1000U / mk_interval)); + + if (speed > MOUSEKEY_MOVE_MAX) { + speed = MOUSEKEY_MOVE_MAX; + } else if (speed < 1) { + speed = 1; + } + return speed; +} + +static uint8_t wheel_unit(void) { + uint16_t speed = MOUSEKEY_WHEEL_INITIAL_MOVEMENTS; + + if (mousekey_accel & (1 << 0)) { + speed = MOUSEKEY_WHEEL_DECELERATED_MOVEMENTS; + } else if (mousekey_accel & (1 << 2)) { + speed = MOUSEKEY_WHEEL_ACCELERATED_MOVEMENTS; + } else if (mousekey_wheel_repeat && mouse_timer) { + if (mk_wheel_interval != MOUSEKEY_WHEEL_BASE_MOVEMENTS) { + const uint16_t time_elapsed = timer_elapsed(mouse_timer) / 50; + speed = MOUSEKEY_WHEEL_INITIAL_MOVEMENTS + 1 * time_elapsed + (1 * time_elapsed * time_elapsed) / 2; + } + if (speed > MOUSEKEY_WHEEL_BASE_MOVEMENTS) { + speed = MOUSEKEY_WHEEL_BASE_MOVEMENTS; + } + } + mk_wheel_interval = 1000U / speed; + return 1; +} + +# endif /* #ifndef MK_KINETIC_SPEED */ +# else /* #ifndef MK_COMBINED */ + +/* Combined mode */ + +static uint8_t move_unit(void) { + uint16_t unit; + if (mousekey_accel & (1 << 0)) { + unit = 1; + } else if (mousekey_accel & (1 << 1)) { + unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed) / 2; + } else if (mousekey_accel & (1 << 2)) { + unit = MOUSEKEY_MOVE_MAX; + } else if (mousekey_repeat == 0) { + unit = MOUSEKEY_MOVE_DELTA; + } else if (mousekey_repeat >= mk_time_to_max) { + unit = MOUSEKEY_MOVE_DELTA * mk_max_speed; + } else { + unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed * mousekey_repeat) / mk_time_to_max; + } + return (unit > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : (unit == 0 ? 1 : unit)); +} + +static uint8_t wheel_unit(void) { + uint16_t unit; + if (mousekey_accel & (1 << 0)) { + unit = 1; + } else if (mousekey_accel & (1 << 1)) { + unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed) / 2; + } else if (mousekey_accel & (1 << 2)) { + unit = MOUSEKEY_WHEEL_MAX; + } else if (mousekey_repeat == 0) { + unit = MOUSEKEY_WHEEL_DELTA; + } else if (mousekey_repeat >= mk_wheel_time_to_max) { + unit = MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed; + } else { + unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed * mousekey_repeat) / mk_wheel_time_to_max; + } + return (unit > MOUSEKEY_WHEEL_MAX ? MOUSEKEY_WHEEL_MAX : (unit == 0 ? 1 : unit)); +} + +# endif /* #ifndef MK_COMBINED */ + +# ifdef MOUSEKEY_INERTIA + +static int8_t calc_inertia(int8_t direction, int8_t velocity) { + // simulate acceleration and deceleration + + // deceleration + if ((direction > -1) && (velocity < 0)) + velocity = (velocity + 1) * (256 - MOUSEKEY_FRICTION) / 256; + else if ((direction < 1) && (velocity > 0)) + velocity = velocity * (256 - MOUSEKEY_FRICTION) / 256; + + // acceleration + if ((direction > 0) && (velocity < mk_time_to_max)) + velocity++; + else if ((direction < 0) && (velocity > -mk_time_to_max)) + velocity--; + + return velocity; +} + +# endif + +void mousekey_task(void) { + // report cursor and scroll movement independently + report_mouse_t tmpmr = mouse_report; + + mouse_report.x = 0; + mouse_report.y = 0; + mouse_report.v = 0; + mouse_report.h = 0; + +# ifdef MOUSEKEY_INERTIA + + // if an animation is in progress and it's time for the next frame + if ((mousekey_frame) && timer_elapsed(last_timer_c) > ((mousekey_frame > 1) ? mk_interval : mk_delay * 10)) { + mousekey_x_inertia = calc_inertia(mousekey_x_dir, mousekey_x_inertia); + mousekey_y_inertia = calc_inertia(mousekey_y_dir, mousekey_y_inertia); + + mouse_report.x = move_unit(0); + mouse_report.y = move_unit(1); + + // prevent sticky "drift" + if ((!mousekey_x_dir) && (!mousekey_x_inertia)) tmpmr.x = 0; + if ((!mousekey_y_dir) && (!mousekey_y_inertia)) tmpmr.y = 0; + + if (mousekey_frame < 2) mousekey_frame++; + } + + // reset if not moving and no movement keys are held + if ((!mousekey_x_dir) && (!mousekey_y_dir) && (!mousekey_x_inertia) && (!mousekey_y_inertia)) { + mousekey_frame = 0; + tmpmr.x = 0; + tmpmr.y = 0; + } + +# else // default acceleration + + if ((tmpmr.x || tmpmr.y) && timer_elapsed(last_timer_c) > (mousekey_repeat ? mk_interval : mk_delay * 10)) { + if (mousekey_repeat != UINT8_MAX) mousekey_repeat++; + if (tmpmr.x != 0) mouse_report.x = move_unit() * ((tmpmr.x > 0) ? 1 : -1); + if (tmpmr.y != 0) mouse_report.y = move_unit() * ((tmpmr.y > 0) ? 1 : -1); + + /* diagonal move [1/sqrt(2)] */ + if (mouse_report.x && mouse_report.y) { + mouse_report.x = times_inv_sqrt2(mouse_report.x); + if (mouse_report.x == 0) { + mouse_report.x = 1; + } + mouse_report.y = times_inv_sqrt2(mouse_report.y); + if (mouse_report.y == 0) { + mouse_report.y = 1; + } + } + } + +# endif // MOUSEKEY_INERTIA or not + + if ((tmpmr.v || tmpmr.h) && timer_elapsed(last_timer_w) > (mousekey_wheel_repeat ? mk_wheel_interval : mk_wheel_delay * 10)) { + if (mousekey_wheel_repeat != UINT8_MAX) mousekey_wheel_repeat++; + if (tmpmr.v != 0) mouse_report.v = wheel_unit() * ((tmpmr.v > 0) ? 1 : -1); + if (tmpmr.h != 0) mouse_report.h = wheel_unit() * ((tmpmr.h > 0) ? 1 : -1); + + /* diagonal move [1/sqrt(2)] */ + if (mouse_report.v && mouse_report.h) { + mouse_report.v = times_inv_sqrt2(mouse_report.v); + if (mouse_report.v == 0) { + mouse_report.v = 1; + } + mouse_report.h = times_inv_sqrt2(mouse_report.h); + if (mouse_report.h == 0) { + mouse_report.h = 1; + } + } + } + + if (has_mouse_report_changed(&mouse_report, &tmpmr) || should_mousekey_report_send(&mouse_report)) { + mousekey_send(); + } + // save the state for later + memcpy(&mouse_report, &tmpmr, sizeof(tmpmr)); +} + +void mousekey_on(uint8_t code) { +# ifdef MK_KINETIC_SPEED + if (mouse_timer == 0) { + mouse_timer = timer_read(); + } +# endif + +# ifndef MOUSEKEY_INERTIA + // If mouse report is not zero, the current mousekey press is overlapping + // with another. Restart acceleration for smoother directional transition. + if (mouse_report.x || mouse_report.y || mouse_report.h || mouse_report.v) { +# ifdef MK_KINETIC_SPEED + mouse_timer = timer_read() - (MOUSEKEY_INTERVAL << 2); +# else + mousekey_repeat = MOUSEKEY_MOVE_DELTA; + mousekey_wheel_repeat = MOUSEKEY_WHEEL_DELTA; +# endif + } +# endif // ifndef MOUSEKEY_INERTIA + +# ifdef MOUSEKEY_INERTIA + + // initial keypress sets impulse and activates first frame of movement + if ((code == KC_MS_UP) || (code == KC_MS_DOWN)) { + mousekey_y_dir = (code == KC_MS_DOWN) ? 1 : -1; + if (mousekey_frame < 2) mouse_report.y = move_unit(1); + } else if ((code == KC_MS_LEFT) || (code == KC_MS_RIGHT)) { + mousekey_x_dir = (code == KC_MS_RIGHT) ? 1 : -1; + if (mousekey_frame < 2) mouse_report.x = move_unit(0); + } + +# else // no inertia + + if (code == KC_MS_UP) + mouse_report.y = move_unit() * -1; + else if (code == KC_MS_DOWN) + mouse_report.y = move_unit(); + else if (code == KC_MS_LEFT) + mouse_report.x = move_unit() * -1; + else if (code == KC_MS_RIGHT) + mouse_report.x = move_unit(); + +# endif // inertia or not + + else if (code == KC_MS_WH_UP) + mouse_report.v = wheel_unit(); + else if (code == KC_MS_WH_DOWN) + mouse_report.v = wheel_unit() * -1; + else if (code == KC_MS_WH_LEFT) + mouse_report.h = wheel_unit() * -1; + else if (code == KC_MS_WH_RIGHT) + mouse_report.h = wheel_unit(); + else if (IS_MOUSEKEY_BUTTON(code)) + mouse_report.buttons |= 1 << (code - KC_MS_BTN1); + else if (code == KC_MS_ACCEL0) + mousekey_accel |= (1 << 0); + else if (code == KC_MS_ACCEL1) + mousekey_accel |= (1 << 1); + else if (code == KC_MS_ACCEL2) + mousekey_accel |= (1 << 2); +} + +void mousekey_off(uint8_t code) { +# ifdef MOUSEKEY_INERTIA + + // key release clears impulse unless opposite direction is held + if ((code == KC_MS_UP) && (mousekey_y_dir < 1)) + mousekey_y_dir = 0; + else if ((code == KC_MS_DOWN) && (mousekey_y_dir > -1)) + mousekey_y_dir = 0; + else if ((code == KC_MS_LEFT) && (mousekey_x_dir < 1)) + mousekey_x_dir = 0; + else if ((code == KC_MS_RIGHT) && (mousekey_x_dir > -1)) + mousekey_x_dir = 0; + +# else // no inertia + + if (code == KC_MS_UP && mouse_report.y < 0) + mouse_report.y = 0; + else if (code == KC_MS_DOWN && mouse_report.y > 0) + mouse_report.y = 0; + else if (code == KC_MS_LEFT && mouse_report.x < 0) + mouse_report.x = 0; + else if (code == KC_MS_RIGHT && mouse_report.x > 0) + mouse_report.x = 0; + +# endif // inertia or not + + else if (code == KC_MS_WH_UP && mouse_report.v > 0) + mouse_report.v = 0; + else if (code == KC_MS_WH_DOWN && mouse_report.v < 0) + mouse_report.v = 0; + else if (code == KC_MS_WH_LEFT && mouse_report.h < 0) + mouse_report.h = 0; + else if (code == KC_MS_WH_RIGHT && mouse_report.h > 0) + mouse_report.h = 0; + else if (IS_MOUSEKEY_BUTTON(code)) + mouse_report.buttons &= ~(1 << (code - KC_MS_BTN1)); + else if (code == KC_MS_ACCEL0) + mousekey_accel &= ~(1 << 0); + else if (code == KC_MS_ACCEL1) + mousekey_accel &= ~(1 << 1); + else if (code == KC_MS_ACCEL2) + mousekey_accel &= ~(1 << 2); + if (mouse_report.x == 0 && mouse_report.y == 0) { + mousekey_repeat = 0; +# ifdef MK_KINETIC_SPEED + mouse_timer = 0; +# endif /* #ifdef MK_KINETIC_SPEED */ + } + if (mouse_report.v == 0 && mouse_report.h == 0) mousekey_wheel_repeat = 0; +} + +#else /* #ifndef MK_3_SPEED */ + +enum { mkspd_unmod, mkspd_0, mkspd_1, mkspd_2, mkspd_COUNT }; +# ifndef MK_MOMENTARY_ACCEL +static uint8_t mk_speed = mkspd_1; +# else +static uint8_t mk_speed = mkspd_unmod; +static uint8_t mkspd_DEFAULT = mkspd_unmod; +# endif +static uint16_t last_timer_c = 0; +static uint16_t last_timer_w = 0; +uint16_t c_offsets[mkspd_COUNT] = {MK_C_OFFSET_UNMOD, MK_C_OFFSET_0, MK_C_OFFSET_1, MK_C_OFFSET_2}; +uint16_t c_intervals[mkspd_COUNT] = {MK_C_INTERVAL_UNMOD, MK_C_INTERVAL_0, MK_C_INTERVAL_1, MK_C_INTERVAL_2}; +uint16_t w_offsets[mkspd_COUNT] = {MK_W_OFFSET_UNMOD, MK_W_OFFSET_0, MK_W_OFFSET_1, MK_W_OFFSET_2}; +uint16_t w_intervals[mkspd_COUNT] = {MK_W_INTERVAL_UNMOD, MK_W_INTERVAL_0, MK_W_INTERVAL_1, MK_W_INTERVAL_2}; + +void mousekey_task(void) { + // report cursor and scroll movement independently + report_mouse_t tmpmr = mouse_report; + mouse_report.x = 0; + mouse_report.y = 0; + mouse_report.v = 0; + mouse_report.h = 0; + + if ((tmpmr.x || tmpmr.y) && timer_elapsed(last_timer_c) > c_intervals[mk_speed]) { + mouse_report.x = tmpmr.x; + mouse_report.y = tmpmr.y; + } + if ((tmpmr.h || tmpmr.v) && timer_elapsed(last_timer_w) > w_intervals[mk_speed]) { + mouse_report.v = tmpmr.v; + mouse_report.h = tmpmr.h; + } + + if (has_mouse_report_changed(&mouse_report, &tmpmr) || should_mousekey_report_send(&mouse_report)) { + mousekey_send(); + } + memcpy(&mouse_report, &tmpmr, sizeof(tmpmr)); +} + +void adjust_speed(void) { + uint16_t const c_offset = c_offsets[mk_speed]; + uint16_t const w_offset = w_offsets[mk_speed]; + if (mouse_report.x > 0) mouse_report.x = c_offset; + if (mouse_report.x < 0) mouse_report.x = c_offset * -1; + if (mouse_report.y > 0) mouse_report.y = c_offset; + if (mouse_report.y < 0) mouse_report.y = c_offset * -1; + if (mouse_report.h > 0) mouse_report.h = w_offset; + if (mouse_report.h < 0) mouse_report.h = w_offset * -1; + if (mouse_report.v > 0) mouse_report.v = w_offset; + if (mouse_report.v < 0) mouse_report.v = w_offset * -1; + // adjust for diagonals + if (mouse_report.x && mouse_report.y) { + mouse_report.x = times_inv_sqrt2(mouse_report.x); + if (mouse_report.x == 0) { + mouse_report.x = 1; + } + mouse_report.y = times_inv_sqrt2(mouse_report.y); + if (mouse_report.y == 0) { + mouse_report.y = 1; + } + } + if (mouse_report.h && mouse_report.v) { + mouse_report.h = times_inv_sqrt2(mouse_report.h); + mouse_report.v = times_inv_sqrt2(mouse_report.v); + } +} + +void mousekey_on(uint8_t code) { + uint16_t const c_offset = c_offsets[mk_speed]; + uint16_t const w_offset = w_offsets[mk_speed]; + uint8_t const old_speed = mk_speed; + if (code == KC_MS_UP) + mouse_report.y = c_offset * -1; + else if (code == KC_MS_DOWN) + mouse_report.y = c_offset; + else if (code == KC_MS_LEFT) + mouse_report.x = c_offset * -1; + else if (code == KC_MS_RIGHT) + mouse_report.x = c_offset; + else if (code == KC_MS_WH_UP) + mouse_report.v = w_offset; + else if (code == KC_MS_WH_DOWN) + mouse_report.v = w_offset * -1; + else if (code == KC_MS_WH_LEFT) + mouse_report.h = w_offset * -1; + else if (code == KC_MS_WH_RIGHT) + mouse_report.h = w_offset; + else if (IS_MOUSEKEY_BUTTON(code)) + mouse_report.buttons |= 1 << (code - KC_MS_BTN1); + else if (code == KC_MS_ACCEL0) + mk_speed = mkspd_0; + else if (code == KC_MS_ACCEL1) + mk_speed = mkspd_1; + else if (code == KC_MS_ACCEL2) + mk_speed = mkspd_2; + if (mk_speed != old_speed) adjust_speed(); +} + +void mousekey_off(uint8_t code) { +# ifdef MK_MOMENTARY_ACCEL + uint8_t const old_speed = mk_speed; +# endif + if (code == KC_MS_UP && mouse_report.y < 0) + mouse_report.y = 0; + else if (code == KC_MS_DOWN && mouse_report.y > 0) + mouse_report.y = 0; + else if (code == KC_MS_LEFT && mouse_report.x < 0) + mouse_report.x = 0; + else if (code == KC_MS_RIGHT && mouse_report.x > 0) + mouse_report.x = 0; + else if (code == KC_MS_WH_UP && mouse_report.v > 0) + mouse_report.v = 0; + else if (code == KC_MS_WH_DOWN && mouse_report.v < 0) + mouse_report.v = 0; + else if (code == KC_MS_WH_LEFT && mouse_report.h < 0) + mouse_report.h = 0; + else if (code == KC_MS_WH_RIGHT && mouse_report.h > 0) + mouse_report.h = 0; + else if (IS_MOUSEKEY_BUTTON(code)) + mouse_report.buttons &= ~(1 << (code - KC_MS_BTN1)); +# ifdef MK_MOMENTARY_ACCEL + else if (code == KC_MS_ACCEL0) + mk_speed = mkspd_DEFAULT; + else if (code == KC_MS_ACCEL1) + mk_speed = mkspd_DEFAULT; + else if (code == KC_MS_ACCEL2) + mk_speed = mkspd_DEFAULT; + if (mk_speed != old_speed) adjust_speed(); +# endif +} + +#endif /* #ifndef MK_3_SPEED */ + +void mousekey_send(void) { + mousekey_debug(); + uint32_t time = timer_read(); + if (mouse_report.x || mouse_report.y) last_timer_c = time; + if (mouse_report.v || mouse_report.h) last_timer_w = time; + host_mouse_send(&mouse_report); +} + +void mousekey_clear(void) { + mouse_report = (report_mouse_t){}; + mousekey_repeat = 0; + mousekey_wheel_repeat = 0; + mousekey_accel = 0; +#ifdef MOUSEKEY_INERTIA + mousekey_frame = 0; + mousekey_x_inertia = 0; + mousekey_y_inertia = 0; + mousekey_x_dir = 0; + mousekey_y_dir = 0; +#endif +} + +static inline void mousekey_debug(void) { + LOG_DBG("mousekey [btn|x y v h](rep/acl): [%02x|%d %d %d %d](%d/%d)",mouse_report.buttons,mouse_report.x,mouse_report.y,mouse_report.v,mouse_report.h,mousekey_repeat,mousekey_accel); + // if (!debug_mouse) return; + // print("mousekey [btn|x y v h](rep/acl): ["); + // print_hex8(mouse_report.buttons); + // print("|"); + // print_decs(mouse_report.x); + // print(" "); + // print_decs(mouse_report.y); + // print(" "); + // print_decs(mouse_report.v); + // print(" "); + // print_decs(mouse_report.h); + // print("]("); + // print_dec(mousekey_repeat); + // print("/"); + // print_dec(mousekey_accel); + // print(")\n"); +} + +report_mouse_t mousekey_get_report(void) { + return mouse_report; +} + +bool should_mousekey_report_send(report_mouse_t *mouse_report) { + return mouse_report->x || mouse_report->y || mouse_report->v || mouse_report->h; +} +__attribute__((weak)) bool has_mouse_report_changed(report_mouse_t* new_report, report_mouse_t* old_report) { + // memcmp doesn't work here because of the `report_id` field when using + // shared mouse endpoint + bool changed = ((new_report->buttons != old_report->buttons) || + (new_report->x != 0 && new_report->x != old_report->x) || (new_report->y != 0 && new_report->y != old_report->y) || (new_report->h != 0 && new_report->h != old_report->h) || (new_report->v != 0 && new_report->v != old_report->v)); + return changed; +} + +#define MY_STACK_SIZE 1024 +#define MY_PRIORITY 2 +void zmk_mouse_thread(void); +static void mouse_sleep_worker(struct k_work *work) ; + +K_THREAD_DEFINE(zmk_mouse_tid, MY_STACK_SIZE, + zmk_mouse_thread, NULL, NULL, NULL, + MY_PRIORITY, 0, 0); + +static K_WORK_DELAYABLE_DEFINE(mouse_sleep_work, mouse_sleep_worker); + +static K_SEM_DEFINE(thread_wait_sem, 0, 1); +static bool zmk_mouse_enable; +static void mouse_sleep_worker(struct k_work *work) +{ + // k_thread_suspend(zmk_mouse_tid); + zmk_mouse_enable =false; + LOG_DBG("."); +} +void zmk_mouse_thread(void) +{ + // k_sem_take(&thread_wait_sem,K_FOREVER); + LOG_DBG("."); + static uint8_t count=0; + while(1) + { + if(!zmk_mouse_enable) + { + k_sem_take(&thread_wait_sem,K_FOREVER); + zmk_mouse_enable =true; + } + mousekey_task(); + k_msleep(8); + if(count++>125) + { + LOG_DBG("."); + count=0; + } + } +} + +static int mouse_listener_keycode_pressed(const struct zmk_keycode_state_changed *ev) { + LOG_DBG("usage_page 0x%02X keycode 0x%02X", + ev->usage_page, ev->keycode); + if(ev->usage_page ==HID_USAGE_GEN_BUTTON) + { + if(!zmk_mouse_enable) + k_sem_give(&thread_wait_sem); + k_work_cancel_delayable(&mouse_sleep_work); + // k_thread_resume(zmk_mouse_tid); + mousekey_on(ev->keycode); + return zmk_endpoints_send_report(ev->usage_page); + } + return 0; +} +static int mouse_listener_keycode_released(const struct zmk_keycode_state_changed *ev) { + LOG_DBG("usage_page 0x%02X keycode 0x%02X ", + ev->usage_page, ev->keycode); + if(ev->usage_page ==HID_USAGE_GEN_BUTTON) + { + mousekey_off(ev->keycode); + k_work_reschedule(&mouse_sleep_work,K_MSEC(200)); + return zmk_endpoints_send_report(ev->usage_page); + } + return 0; +} +int mouse_listener(const zmk_event_t *eh) { + const struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh); + if (ev) { + if (ev->state) { + mouse_listener_keycode_pressed(ev); + } else { + mouse_listener_keycode_released(ev); + } + } + return 0; +} +ZMK_LISTENER(mouse_listener, mouse_listener); +ZMK_SUBSCRIPTION(mouse_listener, zmk_keycode_state_changed); + + diff --git a/app/src/launcher/mousekey.h b/app/src/launcher/mousekey.h new file mode 100644 index 00000000000..b10a159adf0 --- /dev/null +++ b/app/src/launcher/mousekey.h @@ -0,0 +1,220 @@ +/* +Copyright 2011 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#pragma once + +#include + + +#ifndef MK_3_SPEED + +/* max value on report descriptor */ +# ifndef MOUSEKEY_MOVE_MAX +# define MOUSEKEY_MOVE_MAX 127 +# elif MOUSEKEY_MOVE_MAX > 127 +# error MOUSEKEY_MOVE_MAX needs to be smaller than 127 +# endif + +# ifndef MOUSEKEY_WHEEL_MAX +# define MOUSEKEY_WHEEL_MAX 127 +# elif MOUSEKEY_WHEEL_MAX > 127 +# error MOUSEKEY_WHEEL_MAX needs to be smaller than 127 +# endif + +# ifndef MOUSEKEY_MOVE_DELTA +# if defined(MK_KINETIC_SPEED) +# define MOUSEKEY_MOVE_DELTA 16 +# elif defined(MOUSEKEY_INERTIA) +# define MOUSEKEY_MOVE_DELTA 1 +# else +# define MOUSEKEY_MOVE_DELTA 8 +# endif +# endif +# ifndef MOUSEKEY_DELAY +# if defined(MK_KINETIC_SPEED) +# define MOUSEKEY_DELAY 5 +# elif defined(MOUSEKEY_INERTIA) +# define MOUSEKEY_DELAY 150 // allow single-pixel movements before repeat activates +# else +# define MOUSEKEY_DELAY 10 +# endif +# endif +# ifndef MOUSEKEY_INTERVAL +# if defined(MK_KINETIC_SPEED) +# define MOUSEKEY_INTERVAL 10 +# elif defined(MOUSEKEY_INERTIA) +# define MOUSEKEY_INTERVAL 16 // 60 fps +# else +# define MOUSEKEY_INTERVAL 20 +# endif +# endif +# ifndef MOUSEKEY_MAX_SPEED +# if defined(MOUSEKEY_INERTIA) +# define MOUSEKEY_MAX_SPEED 32 +# else +# define MOUSEKEY_MAX_SPEED 10 +# endif +# endif +# ifndef MOUSEKEY_TIME_TO_MAX +# if defined(MOUSEKEY_INERTIA) +# define MOUSEKEY_TIME_TO_MAX 32 +# else +# define MOUSEKEY_TIME_TO_MAX 30 +# endif +# endif +# ifndef MOUSEKEY_WHEEL_DELAY +# define MOUSEKEY_WHEEL_DELAY 10 +# endif +# ifndef MOUSEKEY_WHEEL_INTERVAL +# define MOUSEKEY_WHEEL_INTERVAL 80 +# endif +# ifndef MOUSEKEY_WHEEL_DELTA +# define MOUSEKEY_WHEEL_DELTA 1 +# endif +# ifndef MOUSEKEY_WHEEL_MAX_SPEED +# define MOUSEKEY_WHEEL_MAX_SPEED 8 +# endif +# ifndef MOUSEKEY_WHEEL_TIME_TO_MAX +# define MOUSEKEY_WHEEL_TIME_TO_MAX 40 +# endif + +# ifndef MOUSEKEY_FRICTION +# define MOUSEKEY_FRICTION 24 // 0 to 255 +# endif +# ifndef MOUSEKEY_INITIAL_SPEED +# define MOUSEKEY_INITIAL_SPEED 100 +# endif +# ifndef MOUSEKEY_BASE_SPEED +# define MOUSEKEY_BASE_SPEED 5000 +# endif +# ifndef MOUSEKEY_DECELERATED_SPEED +# define MOUSEKEY_DECELERATED_SPEED 400 +# endif +# ifndef MOUSEKEY_ACCELERATED_SPEED +# define MOUSEKEY_ACCELERATED_SPEED 3000 +# endif +# ifndef MOUSEKEY_WHEEL_INITIAL_MOVEMENTS +# define MOUSEKEY_WHEEL_INITIAL_MOVEMENTS 16 +# endif +# ifndef MOUSEKEY_WHEEL_BASE_MOVEMENTS +# define MOUSEKEY_WHEEL_BASE_MOVEMENTS 32 +# endif +# ifndef MOUSEKEY_WHEEL_ACCELERATED_MOVEMENTS +# define MOUSEKEY_WHEEL_ACCELERATED_MOVEMENTS 48 +# endif +# ifndef MOUSEKEY_WHEEL_DECELERATED_MOVEMENTS +# define MOUSEKEY_WHEEL_DECELERATED_MOVEMENTS 8 +# endif + +#else /* #ifndef MK_3_SPEED */ + +# ifndef MK_C_OFFSET_UNMOD +# define MK_C_OFFSET_UNMOD 16 +# endif +# ifndef MK_C_INTERVAL_UNMOD +# define MK_C_INTERVAL_UNMOD 16 +# endif +# ifndef MK_C_OFFSET_0 +# define MK_C_OFFSET_0 1 +# endif +# ifndef MK_C_INTERVAL_0 +# define MK_C_INTERVAL_0 32 +# endif +# ifndef MK_C_OFFSET_1 +# define MK_C_OFFSET_1 4 +# endif +# ifndef MK_C_INTERVAL_1 +# define MK_C_INTERVAL_1 16 +# endif +# ifndef MK_C_OFFSET_2 +# define MK_C_OFFSET_2 32 +# endif +# ifndef MK_C_INTERVAL_2 +# define MK_C_INTERVAL_2 16 +# endif + +# ifndef MK_W_OFFSET_UNMOD +# define MK_W_OFFSET_UNMOD 1 +# endif +# ifndef MK_W_INTERVAL_UNMOD +# define MK_W_INTERVAL_UNMOD 40 +# endif +# ifndef MK_W_OFFSET_0 +# define MK_W_OFFSET_0 1 +# endif +# ifndef MK_W_INTERVAL_0 +# define MK_W_INTERVAL_0 360 +# endif +# ifndef MK_W_OFFSET_1 +# define MK_W_OFFSET_1 1 +# endif +# ifndef MK_W_INTERVAL_1 +# define MK_W_INTERVAL_1 120 +# endif +# ifndef MK_W_OFFSET_2 +# define MK_W_OFFSET_2 1 +# endif +# ifndef MK_W_INTERVAL_2 +# define MK_W_INTERVAL_2 20 +# endif + +#endif /* #ifndef MK_3_SPEED */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint8_t mk_delay; +extern uint8_t mk_interval; +extern uint8_t mk_max_speed; +extern uint8_t mk_time_to_max; +extern uint8_t mk_wheel_max_speed; +extern uint8_t mk_wheel_time_to_max; + +struct _report_mouse { + uint8_t report_id; + uint8_t buttons; + + int8_t x; + int8_t y; + int8_t v; + int8_t h; +} __packed; + +typedef struct _report_mouse report_mouse_t; + +#define TIMER_DIFF(a, b, max) ((max == UINT8_MAX) ? ((uint8_t)((a) - (b))) : ((max == UINT16_MAX) ? ((uint16_t)((a) - (b))) : ((max == UINT32_MAX) ? ((uint32_t)((a) - (b))) : ((a) >= (b) ? (a) - (b) : (max) + 1 - (b) + (a))))) +#define TIMER_DIFF_8(a, b) TIMER_DIFF(a, b, UINT8_MAX) +#define TIMER_DIFF_16(a, b) TIMER_DIFF(a, b, UINT16_MAX) +#define TIMER_DIFF_32(a, b) TIMER_DIFF(a, b, UINT32_MAX) +#define TIMER_DIFF_RAW(a, b) TIMER_DIFF_8(a, b) + + + +void mousekey_task(void); +void mousekey_on(uint8_t code); +void mousekey_off(uint8_t code); +void mousekey_clear(void); +void mousekey_send(void); +report_mouse_t mousekey_get_report(void); +bool should_mousekey_report_send(report_mouse_t *mouse_report); +int host_mouse_send(report_mouse_t *rp); +bool has_mouse_report_changed(report_mouse_t* new_report, report_mouse_t* old_report); + +#ifdef __cplusplus +} +#endif diff --git a/app/src/launcher/send_string.c b/app/src/launcher/send_string.c new file mode 100644 index 00000000000..1b71cd1123b --- /dev/null +++ b/app/src/launcher/send_string.c @@ -0,0 +1,341 @@ +/* Copyright 2021 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "send_string.h" + +#include +#include +#include "keycodes.h" + +#include + +#include +#include +#include +LOG_MODULE_DECLARE(zmk,CONFIG_ZMK_LOG_LEVEL); + +#define PROGMEM + + +// clang-format off + +/* Bit-Packed look-up table to convert an ASCII character to whether + * [Shift] needs to be sent with the keycode. + */ +__attribute__((weak)) const uint8_t ascii_to_shift_lut[16] PROGMEM = { + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + + KCLUT_ENTRY(0, 1, 1, 1, 1, 1, 1, 0), + KCLUT_ENTRY(1, 1, 1, 1, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 1, 0, 1, 0, 1, 1), + KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1), + KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1), + KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1), + KCLUT_ENTRY(1, 1, 1, 0, 0, 0, 1, 1), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0) +}; + +/* Bit-Packed look-up table to convert an ASCII character to whether + * [AltGr] needs to be sent with the keycode. + */ +__attribute__((weak)) const uint8_t ascii_to_altgr_lut[16] PROGMEM = { + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0) +}; + +/* Bit-Packed look-up table to convert an ASCII character to whether + * [Space] needs to be sent after the keycode + */ +__attribute__((weak)) const uint8_t ascii_to_dead_lut[16] PROGMEM = { + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0) +}; + +/* Look-up table to convert an ASCII character to a keycode. + */ +__attribute__((weak)) const uint8_t ascii_to_keycode_lut[128] PROGMEM = { + // NUL SOH STX ETX EOT ENQ ACK BEL + XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, + // BS TAB LF VT FF CR SO SI + KC_BSPC, KC_TAB, KC_ENT, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, + // DLE DC1 DC2 DC3 DC4 NAK SYN ETB + XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, + // CAN EM SUB ESC FS GS RS US + XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, + + // ! " # $ % & ' + KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT, + // ( ) * + , - . / + KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH, + // 0 1 2 3 4 5 6 7 + KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, + // 8 9 : ; < = > ? + KC_8, KC_9, KC_SCLN, KC_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH, + // @ A B C D E F G + KC_2, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G, + // H I J K L M N O + KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O, + // P Q R S T U V W + KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W, + // X Y Z [ \ ] ^ _ + KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS, + // ` a b c d e f g + KC_GRV, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G, + // h i j k l m n o + KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O, + // p q r s t u v w + KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W, + // x y z { | } ~ DEL + KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL +}; + +// clang-format on + +// Note: we bit-pack in "reverse" order to optimize loading +#define PGM_LOADBIT(mem, pos) ((mem[(pos) / 8] >> ((pos) % 8)) & 0x01) + +#ifndef TAP_CODE_DELAY +# define TAP_CODE_DELAY 10 +#endif +#ifndef TAP_HOLD_CAPS_DELAY +# define TAP_HOLD_CAPS_DELAY 80 +#endif +void via_keycode_to_binding(uint8_t keycode,struct zmk_behavior_binding * binding); +int zmk_macro_queue_add(uint8_t code,uint8_t type ,uint16_t delay); + + +struct q_item { + uint8_t code; + uint8_t type; + uint16_t delay; +}; +K_MSGQ_DEFINE(zmk_macro_queue_msgq, sizeof(struct q_item), 256, 4); +void send_string_with_delay(const char *string, uint8_t interval) { + + while (1) { + char ascii_code = *string; + if (!ascii_code) break; + if (ascii_code == SS_QMK_PREFIX) { + ascii_code = *(++string); + if (ascii_code == SS_TAP_CODE) { + // tap + uint8_t keycode = *(++string); + zmk_macro_queue_add(keycode,SS_TAP_CODE,0); + + } else if (ascii_code == SS_DOWN_CODE) { + // down + uint8_t keycode = *(++string); + // register_code(keycode); + zmk_macro_queue_add(keycode,SS_DOWN_CODE,0); + LOG_DBG("press,code:%x",keycode); + + } else if (ascii_code == SS_UP_CODE) { + // up + uint8_t keycode = *(++string); + // unregister_code(keycode); + zmk_macro_queue_add(keycode,SS_UP_CODE,0); + LOG_DBG("release,code:%x",keycode); + + } else if (ascii_code == SS_DELAY_CODE) { + // delay + int ms = 0; + uint8_t keycode = *(++string); + while (isdigit(keycode)) { + ms *= 10; + ms += keycode - '0'; + keycode = *(++string); + } + LOG_DBG("delay:%d",ms); + zmk_macro_queue_add(0,SS_DELAY_CODE,ms); + } + } else { + send_char(ascii_code); + + } + ++string; + + } +} +void send_string_end(void) +{ + struct q_item item; + + uint16_t num = k_msgq_num_used_get(&zmk_macro_queue_msgq); + LOG_DBG("queue num:%d",num); + const int ret = k_msgq_get(&zmk_macro_queue_msgq, &item, K_NO_WAIT); + if (ret < 0) { + return ; + } + LOG_DBG("item type:%d,code:%x,delay:%d",item.type,item.code,item.delay); + struct zmk_behavior_binding keycode_binding; + via_keycode_to_binding(item.code,&keycode_binding); + + switch(item.type) + { + + case SS_TAP_CODE: + { + uint16_t delay = (item.code == KC_CAPS_LOCK) ? TAP_HOLD_CAPS_DELAY : TAP_CODE_DELAY; + + zmk_behavior_queue_add(0,keycode_binding,true,delay); + zmk_behavior_queue_add(0,keycode_binding,false,TAP_CODE_DELAY); + } + break; + case SS_DOWN_CODE: + zmk_behavior_queue_add(0,keycode_binding,true,TAP_CODE_DELAY); + break; + + case SS_UP_CODE: + zmk_behavior_queue_add(0,keycode_binding,false,TAP_CODE_DELAY); + break; + } +} +void send_char(char ascii_code) { + + + uint8_t keycode = ascii_to_keycode_lut[(uint8_t)ascii_code]; + bool is_shifted = PGM_LOADBIT(ascii_to_shift_lut, (uint8_t)ascii_code); + bool is_altgred = PGM_LOADBIT(ascii_to_altgr_lut, (uint8_t)ascii_code); + bool is_dead = PGM_LOADBIT(ascii_to_dead_lut, (uint8_t)ascii_code); + + if (is_shifted) { + // register_code(KC_LEFT_SHIFT); + zmk_macro_queue_add(KC_LEFT_SHIFT,SS_DOWN_CODE,0); + } + if (is_altgred) { + // register_code(KC_RIGHT_ALT); + + zmk_macro_queue_add(KC_RIGHT_ALT,SS_DOWN_CODE,0); + } + // tap_code(keycode); + zmk_macro_queue_add(keycode,SS_TAP_CODE,0); + + + if (is_altgred) { + // unregister_code(KC_RIGHT_ALT); + zmk_macro_queue_add(KC_RIGHT_ALT,SS_UP_CODE,0); + } + if (is_shifted) { + // unregister_code(KC_LEFT_SHIFT); + zmk_macro_queue_add(KC_LEFT_SHIFT,SS_UP_CODE,0); + } + if (is_dead) { + // tap_code(KC_SPACE); + zmk_macro_queue_add(KC_SPACE,SS_TAP_CODE,0); + + } +} + + + +int zmk_macro_queue_add(uint8_t code,uint8_t type ,uint16_t delay) { + + struct q_item item = {.code = code, .type = type, .delay = delay}; + + int ret = k_msgq_put(&zmk_macro_queue_msgq, &item, K_NO_WAIT); + if (ret < 0) { + LOG_ERR("macro queue full"); + return ret; + } + LOG_DBG("macro queue num:%d",k_msgq_num_used_get(&zmk_macro_queue_msgq)); + if(k_msgq_num_used_get(&zmk_macro_queue_msgq)>=2) + { + struct q_item item1={.delay =0}; + struct q_item item2={.delay =0}; + ret =k_msgq_get(&zmk_macro_queue_msgq,&item1,K_NO_WAIT); + if(ret <0) + { + return ret; + } + LOG_DBG("item1 type:%d,char:%c,delay:%d",item1.type,item1.code,item1.delay); + ret =k_msgq_peek(&zmk_macro_queue_msgq,&item2); + if(ret <0 ) + { + return ret; + } + LOG_DBG("item2 type:%d,char:%c,delay:%d",item2.type,item2.code,item2.delay); + if(item2.type ==SS_DELAY_CODE) + { + k_msgq_get(&zmk_macro_queue_msgq,&item2,K_NO_WAIT); + } + + struct zmk_behavior_binding keycode_binding; + via_keycode_to_binding(item1.code,&keycode_binding); + switch(item1.type) + { + case SS_TAP_CODE: + { + uint16_t delay = (item1.code == KC_CAPS_LOCK) ? TAP_HOLD_CAPS_DELAY : TAP_CODE_DELAY; + + zmk_behavior_queue_add(0,keycode_binding,true,delay); + zmk_behavior_queue_add(0,keycode_binding,false,item2.delay ? item2.delay: TAP_CODE_DELAY); + + } + break; + + case SS_DOWN_CODE: + zmk_behavior_queue_add(0,keycode_binding,true,item2.delay ? item2.delay: TAP_CODE_DELAY); + + break; + case SS_UP_CODE: + zmk_behavior_queue_add(0,keycode_binding,false,item2.delay ? item2.delay: TAP_CODE_DELAY); + break; + + } + + + } + return 0; +} + + diff --git a/app/src/launcher/send_string.h b/app/src/launcher/send_string.h new file mode 100644 index 00000000000..4f78d2938da --- /dev/null +++ b/app/src/launcher/send_string.h @@ -0,0 +1,156 @@ +/* Copyright 2021 + * + * 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 . + */ + +/** + * \file + * + * \defgroup send_string Send String API + * + * \brief These functions allow you to create macros by typing out sequences of keystrokes. + * \{ + */ + +#include + +// #include "progmem.h" +#include "send_string_keycodes.h" + +// Look-Up Tables (LUTs) to convert ASCII character to keycode sequence. +extern const uint8_t ascii_to_shift_lut[16]; +extern const uint8_t ascii_to_altgr_lut[16]; +extern const uint8_t ascii_to_dead_lut[16]; +extern const uint8_t ascii_to_keycode_lut[128]; + +// clang-format off +#define KCLUT_ENTRY(a, b, c, d, e, f, g, h) \ + ( ((a) ? 1 : 0) << 0 \ + | ((b) ? 1 : 0) << 1 \ + | ((c) ? 1 : 0) << 2 \ + | ((d) ? 1 : 0) << 3 \ + | ((e) ? 1 : 0) << 4 \ + | ((f) ? 1 : 0) << 5 \ + | ((g) ? 1 : 0) << 6 \ + | ((h) ? 1 : 0) << 7 ) +// clang-format on + +/** + * \brief Type out a string of ASCII characters. + * + * This function simply calls `send_string_with_delay(string, 0)`. + * + * Most keycodes from the basic keycode range are also supported by way of a special sequence - see `send_string_keycodes.h`. + * + * \param string The string to type out. + */ +void send_string(const char *string); + +/** + * \brief Type out a string of ASCII characters, with a delay between each character. + * + * \param string The string to type out. + * \param interval The amount of time, in milliseconds, to wait before typing the next character. + */ +void send_string_with_delay(const char *string, uint8_t interval); + +/** + * \brief Type out an ASCII character. + * + * \param ascii_code The character to type. + */ +void send_char(char ascii_code); + +void send_string_end(void); + +/** + * \brief Type out an eight digit (unsigned 32-bit) hexadecimal value. + * + * The format is `[0-9a-f]{8}`, eg. `00000000` through `ffffffff`. + * + * \param number The value to type, from 0 to 4,294,967,295. + */ +void send_dword(uint32_t number); + +/** + * \brief Type out a four digit (unsigned 16-bit) hexadecimal value. + * + * The format is `[0-9a-f]{4}`, eg. `0000` through `ffff`. + * + * \param number The value to type, from 0 to 65,535. + */ +void send_word(uint16_t number); + +/** + * \brief Type out a two digit (8-bit) hexadecimal value. + * + * The format is `[0-9a-f]{2}`, eg. `00` through `ff`. + * + * \param number The value to type, from 0 to 255. + */ +void send_byte(uint8_t number); + +/** + * \brief Type out a single hexadecimal digit. + * + * The format is `[0-9a-f]{1}`, eg. `0` through `f`. + * + * \param number The value to type, from 0 to 15. + */ +void send_nibble(uint8_t number); + +/** + * \brief Type a pseudorandom character from the set `A-Z`, `a-z`, `0-9`, `+` and `/`. + */ +void tap_random_base64(void); + +#if defined(__AVR__) || defined(__DOXYGEN__) +/** + * \brief Type out a PROGMEM string of ASCII characters. + * + * On ARM devices, this function is simply an alias for send_string_with_delay(string, 0). + * + * \param string The string to type out. + */ +void send_string_P(const char *string); + +/** + * \brief Type out a PROGMEM string of ASCII characters, with a delay between each character. + * + * On ARM devices, this function is simply an alias for send_string_with_delay(string, interval). + * + * \param string The string to type out. + * \param interval The amount of time, in milliseconds, to wait before typing the next character. + */ +void send_string_with_delay_P(const char *string, uint8_t interval); +#else +# define send_string_P(string) send_string_with_delay(string, 0) +# define send_string_with_delay_P(string, interval) send_string_with_delay(string, interval) +#endif + +/** + * \brief Shortcut macro for send_string_with_delay_P(PSTR(string), 0). + * + * On ARM devices, this define evaluates to send_string_with_delay(string, 0). + */ +#define SEND_STRING(string) send_string_with_delay_P(PSTR(string), 0) + +/** + * \brief Shortcut macro for send_string_with_delay_P(PSTR(string), interval). + * + * On ARM devices, this define evaluates to send_string_with_delay(string, interval). + */ +#define SEND_STRING_DELAY(string, interval) send_string_with_delay_P(PSTR(string), interval) + +/** \} */ diff --git a/app/src/launcher/send_string_keycodes.h b/app/src/launcher/send_string_keycodes.h new file mode 100644 index 00000000000..54b83820531 --- /dev/null +++ b/app/src/launcher/send_string_keycodes.h @@ -0,0 +1,445 @@ +/* Copyright 2019 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +// clang-format off + +/* Punctuation */ +#define X_ENT X_ENTER +#define X_ESC X_ESCAPE +#define X_BSPC X_BACKSPACE +#define X_SPC X_SPACE +#define X_MINS X_MINUS +#define X_EQL X_EQUAL +#define X_LBRC X_LEFT_BRACKET +#define X_RBRC X_RIGHT_BRACKET +#define X_BSLS X_BACKSLASH +#define X_NUHS X_NONUS_HASH +#define X_SCLN X_SEMICOLON +#define X_QUOT X_QUOTE +#define X_GRV X_GRAVE +#define X_COMM X_COMMA +#define X_SLSH X_SLASH +#define X_NUBS X_NONUS_BACKSLASH + +/* Lock Keys */ +#define X_CAPS X_CAPS_LOCK +#define X_SCRL X_SCROLL_LOCK +#define X_NUM X_NUM_LOCK +#define X_LCAP X_LOCKING_CAPS_LOCK +#define X_LNUM X_LOCKING_NUM_LOCK +#define X_LSCR X_LOCKING_SCROLL_LOCK + +/* Commands */ +#define X_PSCR X_PRINT_SCREEN +#define X_PAUS X_PAUSE +#define X_BRK X_PAUSE +#define X_INS X_INSERT +#define X_PGUP X_PAGE_UP +#define X_DEL X_DELETE +#define X_PGDN X_PAGE_DOWN +#define X_RGHT X_RIGHT +#define X_APP X_APPLICATION +#define X_EXEC X_EXECUTE +#define X_SLCT X_SELECT +#define X_AGIN X_AGAIN +#define X_PSTE X_PASTE +#define X_ERAS X_ALTERNATE_ERASE +#define X_SYRQ X_SYSTEM_REQUEST +#define X_CNCL X_CANCEL +#define X_CLR X_CLEAR +#define X_PRIR X_PRIOR +#define X_RETN X_RETURN +#define X_SEPR X_SEPARATOR +#define X_CLAG X_CLEAR_AGAIN +#define X_CRSL X_CRSEL +#define X_EXSL X_EXSEL + +/* Keypad */ +#define X_PSLS X_KP_SLASH +#define X_PAST X_KP_ASTERISK +#define X_PMNS X_KP_MINUS +#define X_PPLS X_KP_PLUS +#define X_PENT X_KP_ENTER +#define X_P1 X_KP_1 +#define X_P2 X_KP_2 +#define X_P3 X_KP_3 +#define X_P4 X_KP_4 +#define X_P5 X_KP_5 +#define X_P6 X_KP_6 +#define X_P7 X_KP_7 +#define X_P8 X_KP_8 +#define X_P9 X_KP_9 +#define X_P0 X_KP_0 +#define X_PDOT X_KP_DOT +#define X_PEQL X_KP_EQUAL +#define X_PCMM X_KP_COMMA + +/* Language Specific */ +#define X_INT1 X_INTERNATIONAL_1 +#define X_INT2 X_INTERNATIONAL_2 +#define X_INT3 X_INTERNATIONAL_3 +#define X_INT4 X_INTERNATIONAL_4 +#define X_INT5 X_INTERNATIONAL_5 +#define X_INT6 X_INTERNATIONAL_6 +#define X_INT7 X_INTERNATIONAL_7 +#define X_INT8 X_INTERNATIONAL_8 +#define X_INT9 X_INTERNATIONAL_9 +#define X_LNG1 X_LANGUAGE_1 +#define X_LNG2 X_LANGUAGE_2 +#define X_LNG3 X_LANGUAGE_3 +#define X_LNG4 X_LANGUAGE_4 +#define X_LNG5 X_LANGUAGE_5 +#define X_LNG6 X_LANGUAGE_6 +#define X_LNG7 X_LANGUAGE_7 +#define X_LNG8 X_LANGUAGE_8 +#define X_LNG9 X_LANGUAGE_9 + +/* Modifiers */ +#define X_LCTL X_LEFT_CTRL +#define X_LSFT X_LEFT_SHIFT +#define X_LALT X_LEFT_ALT +#define X_LOPT X_LEFT_ALT +#define X_LGUI X_LEFT_GUI +#define X_LCMD X_LEFT_GUI +#define X_LWIN X_LEFT_GUI +#define X_RCTL X_RIGHT_CTRL +#define X_RSFT X_RIGHT_SHIFT +#define X_RALT X_RIGHT_ALT +#define X_ALGR X_RIGHT_ALT +#define X_ROPT X_RIGHT_ALT +#define X_RGUI X_RIGHT_GUI +#define X_RCMD X_RIGHT_GUI +#define X_RWIN X_RIGHT_GUI + +/* Generic Desktop Page (0x01) */ +#define X_PWR X_SYSTEM_POWER +#define X_SLEP X_SYSTEM_SLEEP +#define X_WAKE X_SYSTEM_WAKE + +/* Consumer Page (0x0C) */ +#define X_MUTE X_AUDIO_MUTE +#define X_VOLU X_AUDIO_VOL_UP +#define X_VOLD X_AUDIO_VOL_DOWN +#define X_MNXT X_MEDIA_NEXT_TRACK +#define X_MPRV X_MEDIA_PREV_TRACK +#define X_MSTP X_MEDIA_STOP +#define X_MPLY X_MEDIA_PLAY_PAUSE +#define X_MSEL X_MEDIA_SELECT +#define X_EJCT X_MEDIA_EJECT +#define X_CALC X_CALCULATOR +#define X_MYCM X_MY_COMPUTER +#define X_WSCH X_WWW_SEARCH +#define X_WHOM X_WWW_HOME +#define X_WBAK X_WWW_BACK +#define X_WFWD X_WWW_FORWARD +#define X_WSTP X_WWW_STOP +#define X_WREF X_WWW_REFRESH +#define X_WFAV X_WWW_FAVORITES +#define X_MFFD X_MEDIA_FAST_FORWARD +#define X_MRWD X_MEDIA_REWIND +#define X_BRIU X_BRIGHTNESS_UP +#define X_BRID X_BRIGHTNESS_DOWN +#define X_CPNL X_CONTROL_PANEL +#define X_ASST X_ASSISTANT + +/* System Specific */ +#define X_BRMU X_PAUSE +#define X_BRMD X_SCROLL_LOCK + +/* Mouse Keys */ +#define X_MS_U X_MS_UP +#define X_MS_D X_MS_DOWN +#define X_MS_L X_MS_LEFT +#define X_MS_R X_MS_RIGHT +#define X_BTN1 X_MS_BTN1 +#define X_BTN2 X_MS_BTN2 +#define X_BTN3 X_MS_BTN3 +#define X_BTN4 X_MS_BTN4 +#define X_BTN5 X_MS_BTN5 +#define X_BTN6 X_MS_BTN6 +#define X_BTN7 X_MS_BTN7 +#define X_BTN8 X_MS_BTN8 +#define X_WH_U X_MS_WH_UP +#define X_WH_D X_MS_WH_DOWN +#define X_WH_L X_MS_WH_LEFT +#define X_WH_R X_MS_WH_RIGHT +#define X_ACL0 X_MS_ACCEL0 +#define X_ACL1 X_MS_ACCEL1 +#define X_ACL2 X_MS_ACCEL2 + +/* Keyboard/Keypad Page (0x07) */ +#define X_A 04 +#define X_B 05 +#define X_C 06 +#define X_D 07 +#define X_E 08 +#define X_F 09 +#define X_G 0a +#define X_H 0b +#define X_I 0c +#define X_J 0d +#define X_K 0e +#define X_L 0f +#define X_M 10 +#define X_N 11 +#define X_O 12 +#define X_P 13 +#define X_Q 14 +#define X_R 15 +#define X_S 16 +#define X_T 17 +#define X_U 18 +#define X_V 19 +#define X_W 1a +#define X_X 1b +#define X_Y 1c +#define X_Z 1d +#define X_1 1e +#define X_2 1f +#define X_3 20 +#define X_4 21 +#define X_5 22 +#define X_6 23 +#define X_7 24 +#define X_8 25 +#define X_9 26 +#define X_0 27 +#define X_ENTER 28 +#define X_ESCAPE 29 +#define X_BACKSPACE 2a +#define X_TAB 2b +#define X_SPACE 2c +#define X_MINUS 2d +#define X_EQUAL 2e +#define X_LEFT_BRACKET 2f +#define X_RIGHT_BRACKET 30 +#define X_BACKSLASH 31 +#define X_NONUS_HASH 32 +#define X_SEMICOLON 33 +#define X_QUOTE 34 +#define X_GRAVE 35 +#define X_COMMA 36 +#define X_DOT 37 +#define X_SLASH 38 +#define X_CAPS_LOCK 39 +#define X_F1 3a +#define X_F2 3b +#define X_F3 3c +#define X_F4 3d +#define X_F5 3e +#define X_F6 3f +#define X_F7 40 +#define X_F8 41 +#define X_F9 42 +#define X_F10 43 +#define X_F11 44 +#define X_F12 45 +#define X_PRINT_SCREEN 46 +#define X_SCROLL_LOCK 47 +#define X_PAUSE 48 +#define X_INSERT 49 +#define X_HOME 4a +#define X_PAGE_UP 4b +#define X_DELETE 4c +#define X_END 4d +#define X_PAGE_DOWN 4e +#define X_RIGHT 4f +#define X_LEFT 50 +#define X_DOWN 51 +#define X_UP 52 +#define X_NUM_LOCK 53 +#define X_KP_SLASH 54 +#define X_KP_ASTERISK 55 +#define X_KP_MINUS 56 +#define X_KP_PLUS 57 +#define X_KP_ENTER 58 +#define X_KP_1 59 +#define X_KP_2 5a +#define X_KP_3 5b +#define X_KP_4 5c +#define X_KP_5 5d +#define X_KP_6 5e +#define X_KP_7 5f +#define X_KP_8 60 +#define X_KP_9 61 +#define X_KP_0 62 +#define X_KP_DOT 63 +#define X_NONUS_BACKSLASH 64 +#define X_APPLICATION 65 +#define X_KB_POWER 66 +#define X_KP_EQUAL 67 +#define X_F13 68 +#define X_F14 69 +#define X_F15 6a +#define X_F16 6b +#define X_F17 6c +#define X_F18 6d +#define X_F19 6e +#define X_F20 6f +#define X_F21 70 +#define X_F22 71 +#define X_F23 72 +#define X_F24 73 +#define X_EXECUTE 74 +#define X_HELP 75 +#define X_MENU 76 +#define X_SELECT 77 +#define X_STOP 78 +#define X_AGAIN 79 +#define X_UNDO 7a +#define X_CUT 7b +#define X_COPY 7c +#define X_PASTE 7d +#define X_FIND 7e +#define X_KB_MUTE 7f +#define X_KB_VOLUME_UP 80 +#define X_KB_VOLUME_DOWN 81 +#define X_LOCKING_CAPS_LOCK 82 +#define X_LOCKING_NUM_LOCK 83 +#define X_LOCKING_SCROLL_LOCK 84 +#define X_KP_COMMA 85 +#define X_KP_EQUAL_AS400 86 +#define X_INTERNATIONAL_1 87 +#define X_INTERNATIONAL_2 88 +#define X_INTERNATIONAL_3 89 +#define X_INTERNATIONAL_4 8a +#define X_INTERNATIONAL_5 8b +#define X_INTERNATIONAL_6 8c +#define X_INTERNATIONAL_7 8d +#define X_INTERNATIONAL_8 8e +#define X_INTERNATIONAL_9 8f +#define X_LANGUAGE_1 90 +#define X_LANGUAGE_2 91 +#define X_LANGUAGE_3 92 +#define X_LANGUAGE_4 93 +#define X_LANGUAGE_5 94 +#define X_LANGUAGE_6 95 +#define X_LANGUAGE_7 96 +#define X_LANGUAGE_8 97 +#define X_LANGUAGE_9 98 +#define X_ALTERNATE_ERASE 99 +#define X_SYSTEM_REQUEST 9a +#define X_CANCEL 9b +#define X_CLEAR 9c +#define X_PRIOR 9d +#define X_RETURN 9e +#define X_SEPARATOR 9f +#define X_OUT a0 +#define X_OPER a1 +#define X_CLEAR_AGAIN a2 +#define X_CRSEL a3 +#define X_EXSEL a4 + +/* Modifiers */ +#define X_LEFT_CTRL e0 +#define X_LEFT_SHIFT e1 +#define X_LEFT_ALT e2 +#define X_LEFT_GUI e3 +#define X_RIGHT_CTRL e4 +#define X_RIGHT_SHIFT e5 +#define X_RIGHT_ALT e6 +#define X_RIGHT_GUI e7 + +/* Media and Function keys */ +/* Generic Desktop Page (0x01) */ +#define X_SYSTEM_POWER a5 +#define X_SYSTEM_SLEEP a6 +#define X_SYSTEM_WAKE a7 + +/* Consumer Page (0x0C) */ +#define X_AUDIO_MUTE a8 +#define X_AUDIO_VOL_UP a9 +#define X_AUDIO_VOL_DOWN aa +#define X_MEDIA_NEXT_TRACK ab +#define X_MEDIA_PREV_TRACK ac +#define X_MEDIA_STOP ad +#define X_MEDIA_PLAY_PAUSE ae +#define X_MEDIA_SELECT af +#define X_MEDIA_EJECT b0 +#define X_MAIL b1 +#define X_CALCULATOR b2 +#define X_MY_COMPUTER b3 +#define X_WWW_SEARCH b4 +#define X_WWW_HOME b5 +#define X_WWW_BACK b6 +#define X_WWW_FORWARD b7 +#define X_WWW_STOP b8 +#define X_WWW_REFRESH b9 +#define X_WWW_FAVORITES ba +#define X_MEDIA_FAST_FORWARD bb +#define X_MEDIA_REWIND bc +#define X_BRIGHTNESS_UP bd +#define X_BRIGHTNESS_DOWN be +#define X_CONTROL_PANEL bf +#define X_ASSISTANT c0 + +/* Mouse Buttons (unallocated range in HID spec) */ +#define X_MS_UP cd +#define X_MS_DOWN ce +#define X_MS_LEFT cf +#define X_MS_RIGHT d0 +#define X_MS_BTN1 d1 +#define X_MS_BTN2 d2 +#define X_MS_BTN3 d3 +#define X_MS_BTN4 d4 +#define X_MS_BTN5 d5 +#define X_MS_BTN6 d6 +#define X_MS_BTN7 d7 +#define X_MS_BTN8 d8 +#define X_MS_WH_UP d9 +#define X_MS_WH_DOWN da +#define X_MS_WH_LEFT db +#define X_MS_WH_RIGHT dc +#define X_MS_ACCEL0 dd +#define X_MS_ACCEL1 de +#define X_MS_ACCEL2 df + +// Send string macros +#define STRINGIZE(z) #z +#define ADD_SLASH_X(y) STRINGIZE(\x##y) +#define SYMBOL_STR(x) ADD_SLASH_X(x) + +#define SS_QMK_PREFIX 1 + +#define SS_TAP_CODE 1 +#define SS_DOWN_CODE 2 +#define SS_UP_CODE 3 +#define SS_DELAY_CODE 4 + +#define SS_TAP(keycode) "\1\1" SYMBOL_STR(keycode) +#define SS_DOWN(keycode) "\1\2" SYMBOL_STR(keycode) +#define SS_UP(keycode) "\1\3" SYMBOL_STR(keycode) +#define SS_DELAY(msecs) "\1\4" STRINGIZE(msecs) "|" + +// `string` arguments must not be parenthesized +#define SS_LCTL(string) SS_DOWN(X_LCTL) string SS_UP(X_LCTL) +#define SS_LSFT(string) SS_DOWN(X_LSFT) string SS_UP(X_LSFT) +#define SS_LALT(string) SS_DOWN(X_LALT) string SS_UP(X_LALT) +#define SS_LGUI(string) SS_DOWN(X_LGUI) string SS_UP(X_LGUI) +#define SS_LOPT(string) SS_LALT(string) +#define SS_LCMD(string) SS_LGUI(string) +#define SS_LWIN(string) SS_LGUI(string) + +#define SS_RCTL(string) SS_DOWN(X_RCTL) string SS_UP(X_RCTL) +#define SS_RSFT(string) SS_DOWN(X_RSFT) string SS_UP(X_RSFT) +#define SS_RALT(string) SS_DOWN(X_RALT) string SS_UP(X_RALT) +#define SS_RGUI(string) SS_DOWN(X_RGUI) string SS_UP(X_RGUI) +#define SS_ALGR(string) SS_RALT(string) +#define SS_ROPT(string) SS_RALT(string) +#define SS_RCMD(string) SS_RGUI(string) +#define SS_RWIN(string) SS_RGUI(string) diff --git a/app/src/launcher/sendstring_japanese.h b/app/src/launcher/sendstring_japanese.h new file mode 100644 index 00000000000..842f3541bb3 --- /dev/null +++ b/app/src/launcher/sendstring_japanese.h @@ -0,0 +1,81 @@ +/* Copyright 2016 Jack Humbert + * + * 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 . + */ + +// Sendstring lookup tables for JIS layouts + +#pragma once + +#include "send_string.h" +#include "keymap_japanese.h" + +// clang-format off +#define PROGMEM + +const uint8_t ascii_to_shift_lut[16] PROGMEM = { + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + + KCLUT_ENTRY(0, 1, 1, 1, 1, 1, 1, 1), + KCLUT_ENTRY(1, 1, 1, 1, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 1, 1, 1, 1), + KCLUT_ENTRY(0, 1, 1, 1, 1, 1, 1, 1), + KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1), + KCLUT_ENTRY(1, 1, 1, 1, 1, 1, 1, 1), + KCLUT_ENTRY(1, 1, 1, 0, 0, 0, 0, 1), + KCLUT_ENTRY(1, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 0, 0, 0, 0, 0), + KCLUT_ENTRY(0, 0, 0, 1, 1, 1, 1, 0) +}; + +const uint8_t ascii_to_keycode_lut[128] PROGMEM = { + // NUL SOH STX ETX EOT ENQ ACK BEL + XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, + // BS TAB LF VT FF CR SO SI + KC_BSPC, KC_TAB, KC_ENT, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, + // DLE DC1 DC2 DC3 DC4 NAK SYN ETB + XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, + // CAN EM SUB ESC FS GS RS US + XXXXXXX, XXXXXXX, XXXXXXX, KC_ESC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, + + // ! " # $ % & ' + KC_SPC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, + // ( ) * + , - . / + KC_8, KC_9, JP_COLN, JP_SCLN, JP_COMM, JP_MINS, JP_DOT, JP_SLSH, + // 0 1 2 3 4 5 6 7 + KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, + // 8 9 : ; < = > ? + KC_8, KC_9, JP_COLN, JP_SCLN, JP_COMM, JP_MINS, JP_DOT, JP_SLSH, + // @ A B C D E F G + JP_AT, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G, + // H I J K L M N O + KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O, + // P Q R S T U V W + KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W, + // X Y Z [ \ ] ^ _ + KC_X, KC_Y, KC_Z, JP_LBRC, JP_BSLS, JP_RBRC, JP_CIRC, JP_BSLS, + // ` a b c d e f g + JP_AT, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G, + // h i j k l m n o + KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O, + // p q r s t u v w + KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W, + // x y z { | } ~ DEL + KC_X, KC_Y, KC_Z, JP_LBRC, JP_YEN, JP_RBRC, JP_CIRC, KC_DEL +}; diff --git a/app/src/led_effect.h b/app/src/led_effect.h new file mode 100644 index 00000000000..3c45b16a129 --- /dev/null +++ b/app/src/led_effect.h @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2019-2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef _LED_EFFECT_H_ +#define _LED_EFFECT_H_ + +/** + * @brief LED Effect + * @defgroup led_effect_CAF LED Effect + * @{ + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define _CAF_LED_COLOR_CHANNEL_COUNT 3 + +/** @brief Color of LED. + */ +struct led_color { + /** Values for color channels. */ + uint8_t c[_CAF_LED_COLOR_CHANNEL_COUNT]; +}; + +/** @brief Single step of a LED effect. + * + * During a single step, color of LED changes from the color before the step + * to the color defined in the step. The color update may be done in multiple + * substeps to achieve smooth, gradual change. + */ +struct led_effect_step { + /** LED color at the end of the step. */ + struct led_color color; + + /** Number of substeps. */ + uint16_t substep_count; + + /** Duration of a single substep. */ + uint16_t substep_time; +}; + +/** @brief Single LED effect. + */ +struct led_effect { + /** Sequence of LED color changes. It is defined by subsequent steps. */ + const struct led_effect_step *steps; + + /** Number of steps for the given effect. */ + uint16_t step_count; + + /** Flag that indicates if the sequence should start again after it finishes. */ + bool loop_forever; +}; + +/** Transform color brightness from 8-bit space to percentage representation. + * + * @param _val Color brightness in 0-255 range + * + * @return Color brightness in 0-100 range + */ +#define COLOR_BRIGHTNESS_TO_PCT(_val) ((_val * 100) / UINT8_MAX) + +/** + * @brief Pass a color value as a macro argument + * + * @ref LED_COLOR macro contains commas in its body. + * This means that after the argument is expanded, the macro is to be treated + * as multiple arguments. This also makes it impossible to pass an argument + * from macro level to another macro. + * The macro allows the usage of the color argument as an argument to + * another macro level. + * + * @param ... Any list of arguments that have to be treated as + * a single argument for the macro. + */ +#define LED_COLOR_ARG_PASS(...) __VA_ARGS__ + +/** Create LED color initializer for LED turned on. + * + * @note As arguments, pass the brightness levels for every color channel. + * + * @note The macro returns the structure initializer that once expanded + * contains commas not placed in brackets. + * This means that when passed as an argument, this argument + * cannot be passed simply to another macro. + * Use @ref LED_COLOR_ARG_PASS macro for the preprocessor + * to treat it as a single argument again. + */ +#define LED_COLOR(_r, _g, _b) { \ + .c = { \ + COLOR_BRIGHTNESS_TO_PCT(_r), \ + COLOR_BRIGHTNESS_TO_PCT(_g), \ + COLOR_BRIGHTNESS_TO_PCT(_b) \ + } \ +} + +/** Create LED color initializer for LED turned off. + */ +#define LED_NOCOLOR() { \ + .c = {0, 0, 0} \ +} + +/** Create LED turned on effect initializer. + * + * LED color remains constant. + * + * @param _color Selected LED color. + */ +#define LED_EFFECT_LED_ON(_color) \ + { \ + .steps = ((const struct led_effect_step[]) { \ + { \ + .color = _color, \ + .substep_count = 1, \ + .substep_time = 0, \ + }, \ + }), \ + .step_count = 1, \ + .loop_forever = false, \ + } + + +/** Create LED turned off effect initializer. + */ +#define LED_EFFECT_LED_OFF() LED_EFFECT_LED_ON(LED_NOCOLOR()) + +/** Create LED turned on for a brief period effect initializer. + * + * LED color remains constant for a defined time, then goes off. + * + * @param _color Selected LED color. + * @param _on_time Time LED will remain on in milliseconds. + * @param _off_delay Time in which LED will gradually switch to off + * (in milliseconds). + */ +#define LED_EFFECT_LED_ON_GO_OFF(_color, _on_time, _off_delay) \ + { \ + .steps = ((const struct led_effect_step[]) { \ + { \ + .color = _color, \ + .substep_count = 1, \ + .substep_time = 0, \ + }, \ + { \ + .color = _color, \ + .substep_count = 1, \ + .substep_time = (_on_time), \ + }, \ + { \ + .color = LED_NOCOLOR(), \ + .substep_count = (_off_delay)/10, \ + .substep_time = 10, \ + }, \ + }), \ + .step_count = 3, \ + .loop_forever = false, \ + } + +/** Create LED blinking effect initializer with two periods as arguments. + * + * LED color is periodically changed between the selected color and the LED + * turned off. + * This macro takes two periods: for on and off time. + * + * @param _period_on Period of time for which LED is on. + * @param _period_off Period of time for which LED is off. + * @param _color Selected LED color. + * + * @sa LED_EFFECT_LED_BLINK + */ +#define LED_EFFECT_LED_BLINK2(_period_on, _period_off, _color) \ + { \ + .steps = ((const struct led_effect_step[]) { \ + { \ + .color = _color, \ + .substep_count = 1, \ + .substep_time = (_period_off), \ + }, \ + { \ + .color = LED_NOCOLOR(), \ + .substep_count = 1, \ + .substep_time = (_period_on), \ + }, \ + }), \ + .step_count = 2, \ + .loop_forever = true, \ + } + + +/** Create LED blinking effect initializer with one period given + * + * LED color is periodically changed between the selected color and the LED + * turned off. + * The same time is used for both: on and off time. + * + * @param _period Period of time between LED color switches. + * @param _color Selected LED color. + * + * @sa LED_EFFECT_LED_BLINK + */ +#define LED_EFFECT_LED_BLINK(_period, _color) \ + LED_EFFECT_LED_BLINK2(_period, _period, LED_COLOR_ARG_PASS(_color)) + +/** @def _BREATH_SUBSTEPS + * + * @brief Substeps for color update for LED breathing effect. + */ +#define _BREATH_SUBSTEPS 15 + +/** Create LED breathing effect initializer. + * + * LED color is smoothly, gradually changed between the LED turned off + * and the selected color. + * + * @param _period Period of time for single substep. + * @param _color Selected LED color. + */ +#define LED_EFFECT_LED_BREATH(_period, _color) \ + { \ + .steps = ((const struct led_effect_step[]) { \ + { \ + .color = _color, \ + .substep_count = _BREATH_SUBSTEPS, \ + .substep_time = ((_period + (_BREATH_SUBSTEPS - 1)) \ + / _BREATH_SUBSTEPS), \ + }, \ + { \ + .color = _color, \ + .substep_count = 1, \ + .substep_time = _period, \ + }, \ + { \ + .color = LED_NOCOLOR(), \ + .substep_count = _BREATH_SUBSTEPS, \ + .substep_time = ((_period + (_BREATH_SUBSTEPS - 1)) \ + / _BREATH_SUBSTEPS), \ + }, \ + { \ + .color = LED_NOCOLOR(), \ + .substep_count = 1, \ + .substep_time = _period, \ + }, \ + }), \ + .step_count = 4, \ + .loop_forever = true, \ + } + +/** @def LED_CLOCK_BLINK_PERIOD + * + * @brief Period of time between color changes while the LED is blinking + * (LED clock effect). + */ +#define LED_CLOCK_BLINK_PERIOD 100 + +/** @def LED_CLOCK_SLEEP_PERIOD + * + * @brief Period of time when the LED is turned off (LED clock effect). + */ +#define LED_CLOCK_SLEEP_PERIOD 1000 + +/** Create LED steps initializer for single clock tick. + * + * A single clock tick is a single LED blink with the defined color. + * This macro is used by UTIL_LISTIFY macro. + * + * @param i Tick number (required by UTIL_LISTIFY). + * @param ... Selected LED color. + */ +#define _LED_CLOCK_TIK(i, ...) \ + { \ + .color = __VA_ARGS__, \ + .substep_count = 1, \ + .substep_time = LED_CLOCK_BLINK_PERIOD, \ + }, \ + { \ + .color = LED_NOCOLOR(), \ + .substep_count = 1, \ + .substep_time = LED_CLOCK_BLINK_PERIOD, \ + } + +/** Create LED clock effect initializer. + * + * LED blinks a defined number of times, then it is turned off for a defined + * period of time. The sequence is repeated periodically. + * + * @note You can pass only one additional argument to the UTIL_LISTIFY macro, + * which in this case is LED color. Period is defined separately. + * + * @param _ticks Number of ticks. + * @param _color Selected LED color. + */ +#define LED_EFFECT_LED_CLOCK(_ticks, _color) \ + { \ + .steps = ((const struct led_effect_step[]) { \ + { \ + .color = LED_NOCOLOR(), \ + .substep_count = 1, \ + .substep_time = LED_CLOCK_SLEEP_PERIOD, \ + }, \ + LISTIFY(_ticks, _LED_CLOCK_TIK, (,), _color) \ + }), \ + .step_count = (2 * _ticks + 1), \ + .loop_forever = true, \ + } +#define LED_EFFECT_LED_FLASH(_ticks,_period,_color) \ + { \ + .steps = ((const struct led_effect_step[]) { \ + { \ + .color = LED_NOCOLOR(), \ + .substep_count = 1, \ + .substep_time = _period, \ + }, \ + LISTIFY(_ticks, _LED_CLOCK_TIK, (,), _color) \ + }), \ + .step_count = (2 * _ticks + 1), \ + .loop_forever = false, \ + } + +#define _LED_FLASH_TIK(i, ...) \ + { \ + .color = __VA_ARGS__, \ + .substep_count = 1, \ + .substep_time = 400, \ + }, \ + { \ + .color = LED_NOCOLOR(), \ + .substep_count = 1, \ + .substep_time = 400, \ + } +#define LED_EFFECT_LED_FLASH2(_ticks,_color) \ + { \ + .steps = ((const struct led_effect_step[]) { \ + { \ + .color = LED_NOCOLOR(), \ + .substep_count = 1, \ + .substep_time = 200, \ + }, \ + LISTIFY(_ticks, _LED_FLASH_TIK, (,), _color) \ + }), \ + .step_count = (2 * _ticks + 1), \ + .loop_forever = false, \ + } + +#define _LED_FLASH_TIK1(i, ...) \ + { \ + .color = __VA_ARGS__, \ + .substep_count = 1, \ + .substep_time = 500, \ + }, \ + { \ + .color = LED_NOCOLOR(), \ + .substep_count = 1, \ + .substep_time = 500, \ + } +#define LED_EFFECT_LED_FLASH3(_ticks,_color) \ + { \ + .steps = ((const struct led_effect_step[]) { \ + { \ + .color = LED_NOCOLOR(), \ + .substep_count = 1, \ + .substep_time = 200, \ + }, \ + LISTIFY(_ticks, _LED_FLASH_TIK1, (,),_color) \ + }), \ + .step_count = (2 * _ticks + 1), \ + .loop_forever = false, \ + } +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* _LED_EFFECT_H_ */ diff --git a/app/src/leds.c b/app/src/leds.c new file mode 100644 index 00000000000..18a7d130ad8 --- /dev/null +++ b/app/src/leds.c @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2018-2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include +#include "led_effect.h" +#include +#include + + +// #include +// #include + +// #define MODULE leds +// #include + +#include +// LOG_MODULE_REGISTER(MODULE, CONFIG_CAF_LEDS_LOG_LEVEL); + +static const struct led_effect led_peer_state_effect[] = +{ + [LED_PEER_STATE_DISCONNECTED] = LED_EFFECT_LED_OFF(), + [LED_PEER_STATE_CONNECTED] = LED_EFFECT_LED_ON_GO_OFF(LED_COLOR(150, 0, 0),3000,100), + [LED_PEER_STATE_PAIR] = LED_EFFECT_LED_BLINK(1000, LED_COLOR(150, 0, 0)), + [LED_PEER_STATE_RECONN] = LED_EFFECT_LED_FLASH(3, 200,LED_COLOR(150, 0, 0)),// LED_EFFECT_LED_BLINK(200, LED_COLOR(150, 0, 0)), + [LED_PEER_STATE_FAILE] = LED_EFFECT_LED_FLASH(3, 300,LED_COLOR(150, 0, 0)), + [LED_PEER_STATE_POWER_ON] = LED_EFFECT_LED_ON_GO_OFF(LED_COLOR(150, 150, 150),2500,100), + [LED_PEER_STATE_ON_100MS] = LED_EFFECT_LED_ON_GO_OFF(LED_COLOR(100, 100,100),200,100), + [LED_PEER_STATE_BAT_LOW] = LED_EFFECT_LED_FLASH3(5, LED_COLOR(255, 0,0)), + [LED_PEER_STATE_BAT_CHARGING] = LED_EFFECT_LED_ON(LED_COLOR(255, 0,0)), + [LED_PEER_STATE_BAT_CHARGEDONE] = LED_EFFECT_LED_ON(LED_COLOR(0, 255,0)), + [LED_PEER_STATE_RECOVER] = LED_EFFECT_LED_FLASH2(3, LED_COLOR(0, 0,255)), + + +}; +LOG_MODULE_DECLARE(zmk,4); + +// K_SEM_DEFINE(power_on_sem,0,1); +void power_on_finish_cb(struct k_work * work); +K_WORK_DEFINE(power_on_finish,power_on_finish_cb); +static uint8_t led_power_on_status; + +#define LED_ID(led) ((led) - &leds[0]) + +struct led { + const struct device *dev; + uint8_t color_count; + + struct led_color color; + const struct led_effect *effect; + uint16_t effect_step; + uint16_t effect_substep; + + // struct k_work_delayable work; + struct k_timer timer; +}; + +#ifdef CONFIG_ZMK_LEDS_PWM + #define DT_DRV_COMPAT pwm_leds +#elif defined(CONFIG_ZMK_LEDS_GPIO) + #define DT_DRV_COMPAT gpio_leds +#else + #error "LED driver must be specified in configuration" +#endif + +#define _LED_COLOR_ID(_unused) 0, + +#define _LED_COLOR_COUNT(id) \ + static const uint8_t led_colors_##id[] = { \ + DT_INST_FOREACH_CHILD(id, _LED_COLOR_ID) \ + }; + +DT_INST_FOREACH_STATUS_OKAY(_LED_COLOR_COUNT) + +#define _LED_INSTANCE_DEF(id) \ + { \ + .dev = DEVICE_DT_GET(DT_DRV_INST(id)), \ + .color_count = ARRAY_SIZE(led_colors_##id), \ + }, +/**/ + +static struct led leds[] = { + DT_INST_FOREACH_STATUS_OKAY(_LED_INSTANCE_DEF) +}; +static void led_update(struct led *led); + +// void test_led_work_cb(struct k_work *work); +// K_WORK_DELAYABLE_DEFINE(test_led_work, test_led_work_cb); +// void test_led_work_cb(struct k_work *work) { +// leds[4].effect = &led_peer_state_effect[LED_PEER_STATE_ON_100MS]; +// led_update(&leds[4]); +// k_work_reschedule(&test_led_work, K_MSEC(3000)); +// } + +// uint8_t get_mode_status(void); +// static uint8_t last_mode; +// void mode_check_cb(struct k_timer *timer); +// K_TIMER_DEFINE(mode_check,mode_check_cb,NULL); +// void mode_check_cb(struct k_timer *timer) +// { +// uint8_t mode =get_mode_status(); +// if(mode!=last_mode) +// { +// k_sem_give(&power_on_sem); +// LOG_INF("mode change:%d",mode); +// for (size_t i = 0; i < ARRAY_SIZE(leds); i++) +// k_timer_stop(&leds[i].timer); +// } +// else +// k_timer_start(&mode_check,K_MSEC(100),K_FOREVER); +// } + + +static int set_color_one_channel(struct led *led, struct led_color *color) +{ + /* For a single color LED convert color to brightness. */ + unsigned int brightness = 0; + + for (size_t i = 0; i < ARRAY_SIZE(color->c); i++) { + brightness += color->c[i]; + } + brightness /= ARRAY_SIZE(color->c); + + return led_set_brightness(led->dev, 0, brightness); +} + +static int set_color_all_channels(struct led *led, struct led_color *color) +{ + int err = 0; + + for (size_t i = 0; (i < ARRAY_SIZE(color->c)) && !err; i++) { + err = led_set_brightness(led->dev, i, color->c[i]); + } + + return err; +} + +static void set_color(struct led *led, struct led_color *color) +{ + int err; + // LOG_INF("color:%d,%d,%d",color->c[0],color->c[1],color->c[1]); + if (led->color_count == ARRAY_SIZE(color->c)) { + err = set_color_all_channels(led, color); + } else { + err = set_color_one_channel(led, color); + } + + if (err) { + LOG_ERR("Cannot set LED brightness (err: %d)", err); + } +} + +static void set_off(struct led *led) +{ + struct led_color nocolor = {0}; + + set_color(led, &nocolor); +} + +// static void work_handler(struct k_work *work) +static void timer_handler(struct k_timer *timer) +{ + // struct led *led = CONTAINER_OF(work, struct led, work); + struct led *led = CONTAINER_OF(timer, struct led, timer); + // LOG_INF("led ptr:%x,time:%d,%d",led,led->effect->steps[0].substep_time,led->effect->steps[1].substep_time); + const struct led_effect_step *effect_step = + &led->effect->steps[led->effect_step]; + + __ASSERT_NO_MSG(effect_step->substep_count > 0); + int substeps_left = effect_step->substep_count - led->effect_substep; + + for (size_t i = 0; i < ARRAY_SIZE(led->color.c); i++) { + int diff = (effect_step->color.c[i] - led->color.c[i]) / + substeps_left; + led->color.c[i] += diff; + } + set_color(led, &led->color); + + led->effect_substep++; + if (led->effect_substep == effect_step->substep_count) { + led->effect_substep = 0; + led->effect_step++; + + if (led->effect_step == led->effect->step_count) { + if (led->effect->loop_forever) { + led->effect_step = 0; + } else { + LOG_INF("led:%p effect finish",led); + if((led == &leds[ARRAY_SIZE(leds)-1]) && (led->effect == &led_peer_state_effect[LED_PEER_STATE_POWER_ON])) + { + LOG_INF("power_on_finish"); + // k_sem_give(&power_on_sem); + // k_timer_stop(&mode_check); + led_power_on_status =0; + k_work_submit(&power_on_finish); + } + + } + } + } + + if (led->effect_step < led->effect->step_count) { + int32_t next_delay = + led->effect->steps[led->effect_step].substep_time; + // LOG_INF("led ptr:%x,led->effect_step:%d,next delay:%d",led,led->effect_step,next_delay); + // k_work_reschedule(&led->work, K_MSEC(next_delay)); + k_timer_start(&led->timer,K_MSEC(next_delay),K_FOREVER); + } +} + +static void led_update(struct led *led) +{ + // k_work_cancel_delayable(&led->work); + k_timer_stop(&led->timer); + + led->effect_step = 0; + led->effect_substep = 0; + + if (!led->effect) { + LOG_DBG("No effect set"); + return; + } + + __ASSERT_NO_MSG(led->effect->steps); + + if (led->effect->step_count > 0) { + int32_t next_delay = + led->effect->steps[led->effect_step].substep_time; + LOG_INF("next delay:%d",next_delay); + // k_work_reschedule(&led->work, K_MSEC(next_delay)); + k_timer_start(&led->timer,K_MSEC(next_delay),K_FOREVER); + } else { + LOG_WRN("LED effect with no effect"); + } +} +void print_led_info(const struct device *dev,uint32_t led); + int leds_init(const struct device *_arg) +{ + int err = 0; + + BUILD_ASSERT(DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) > 0, "No LEDs defined"); + + for (size_t i = 0; (i < ARRAY_SIZE(leds)) && !err; i++) { + struct led *led = &leds[i]; + LOG_INF("led :%d,color count:%d",i,led->color_count); + // print_led_info(led->dev,i); + if(led->color_count>3) continue; + __ASSERT_NO_MSG((led->color_count == 1) || (led->color_count == 3)); + + if (!device_is_ready(led->dev)) { + LOG_ERR("Device %s is not ready", led->dev->name); + err = -ENODEV; + } else { + // k_work_init_delayable(&led->work, work_handler); + k_timer_init(&led->timer,timer_handler,NULL); + + // led_set_state(i,LED_PEER_STATE_POWER_ON); + // led->effect = &led_peer_state_effect[LED_PEER_STATE_POWER_ON]; + + led_update(led); + } + } + // k_work_reschedule(&test_led_work, K_MSEC(1000)); + return err; +} + + void leds_start(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(leds); i++) { +#if defined(CONFIG_PM_DEVICE) && !defined(CONFIG_ZMK_LEDS_GPIO) + /* Zephyr power management API is not implemented for GPIO LEDs. + * LEDs are turned off by CAF LEDs module. + */ + int err = pm_device_action_run(leds[i].dev, PM_DEVICE_ACTION_RESUME); + + if (err) { + LOG_ERR("Failed to set LED driver into active state (err: %d)", err); + } +#endif + led_update(&leds[i]); + } +} + + void leds_stop(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(leds); i++) { + // k_work_cancel_delayable(&leds[i].work); + k_timer_stop(&leds[i].timer); + + set_off(&leds[i]); + +#if defined(CONFIG_PM_DEVICE) && !defined(CONFIG_ZMK_LEDS_GPIO) + /* Zephyr power management API is not implemented for GPIO LEDs. + * LEDs are turned off by CAF LEDs module. + */ + int err = pm_device_action_run(leds[i].dev, PM_DEVICE_ACTION_SUSPEND); + + if (err) { + LOG_ERR("Failed to set LED driver into suspend state (err: %d)", err); + } +#endif + } +} + + + +void led_set_state(uint8_t index,uint8_t led_state) +{ + LOG_INF("led_set_state index:%d,state:%d",index,led_state); + if(index< ARRAY_SIZE(leds)) + { + //why leds in dts is enable? + for(int i=0;i +#include + +struct led_gpio_config { + size_t num_leds; + const struct gpio_dt_spec *led; +}; +void print_led_info(const struct device *dev,uint32_t led) +{ + const struct led_gpio_config *config = dev->config; + const struct gpio_dt_spec *led_gpio; + LOG_INF("LED NUM:%d,dev name:%s",config->num_leds,dev->name); + + for(int i=0;inum_leds;i++) + { + led_gpio = &config->led[i]; + LOG_INF("LED gpio pin:%d",led_gpio->pin); + } + // keyboard_led_init(); +} +static uint8_t keyboard_led_state; +static uint8_t charge_led_state; +void keyboad_led_set_onoff(uint8_t led_state) +{ + if(led_power_on_status) + { + keyboard_led_state =led_state; + return; + } + uint8_t num =led_state &0x01; + uint8_t caps= (led_state &0x02); + struct led_color color=LED_COLOR(0xff,0xff,0xff); + LOG_DBG("led state:%d,num:%d,caps:%d",led_state,num,caps); +#if !(CONFIG_SHIELD_KEYCHRON_B1) + num ? set_color(&leds[LED_NUMLOCK],&color):set_off(&leds[LED_NUMLOCK]); +#endif + caps ? set_color(&leds[LED_CAPSLOCK],&color):set_off(&leds[LED_CAPSLOCK]); + keyboard_led_state =led_state; + +} +uint8_t keyboard_get_led_state(void) +{ + return keyboard_led_state; +} +uint8_t get_charge_led_state(void) +{ + return charge_led_state; +} +void blue_led_set_state(uint8_t led_state) +{ + if(get_current_transport()!=ZMK_TRANSPORT_BLE) return; + LOG_DBG("set:%d",led_state); + + if((leds[LED_BLUE].effect !=&led_peer_state_effect[led_state]) || k_timer_remaining_get(&leds[LED_BLUE].timer)==0)// k_work_delayable_remaining_get(&leds[LED_BLUE].work)==0) + { + leds[LED_BLUE].effect = &led_peer_state_effect[led_state]; + led_update(&leds[LED_BLUE]); + } +} +void led_24G_set_state(uint8_t led_state) +{ + if(get_current_transport()!=ZMK_TRANSPORT_24G) return; + LOG_DBG("set:%d",led_state); + if((leds[LED_24G].effect !=&led_peer_state_effect[led_state]) || k_timer_remaining_get(&leds[LED_24G].timer)==0)//k_work_delayable_remaining_get(&leds[LED_24G].work)==0) + { + LOG_DBG("."); + leds[LED_24G].effect = &led_peer_state_effect[led_state]; + led_update(&leds[LED_24G]); + } +} +void led_charge_set_state(uint8_t led_state) +{ + if(led_power_on_status) + { + charge_led_state =led_state; + return; + } + if(led_state == LED_BAT_CHARGING) + { + leds[LED_BAT].effect = &led_peer_state_effect[LED_PEER_STATE_BAT_CHARGING]; + led_update(&leds[LED_BAT]); + } + else if(led_state == LED_BAT_CHARGE_DONE) + { + leds[LED_BAT].effect = &led_peer_state_effect[LED_PEER_STATE_BAT_CHARGEDONE]; + led_update(&leds[LED_BAT]); + } + else if(led_state == LED_BAT_LOW) + { + leds[LED_BAT].effect = &led_peer_state_effect[LED_PEER_STATE_BAT_LOW]; + led_update(&leds[LED_BAT]); + } + else if(led_state == LED_BAT_NONE) + { + leds[LED_BAT].effect = &led_peer_state_effect[LED_PEER_STATE_DISCONNECTED]; + led_update(&leds[LED_BAT]); + } + charge_led_state =led_state; +} +void led_recover(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(leds);i++) + { + #if (CONFIG_SHIELD_KEYCHRON_B1) + if(i== LED_NUMLOCK) continue; + #endif + leds[i].effect = &led_peer_state_effect[LED_PEER_STATE_RECOVER]; + led_update(&leds[i]); + } +} +void power_on_finish_cb(struct k_work * work) +{ + keyboad_led_set_onoff(keyboard_led_state); + led_charge_set_state(charge_led_state); +} +bool bat_is_shutdown(void); +void led_power_on(void) +{ + if(bat_is_shutdown()) return; + // k_sem_reset(&power_on_sem); + led_power_on_status =1; + + for (size_t i = 0; i < ARRAY_SIZE(leds);i++) + { + #if (CONFIG_SHIELD_KEYCHRON_B1) + if(i== LED_NUMLOCK) continue; + #endif + if(get_current_transport()==ZMK_TRANSPORT_BLE) + { + if(i==LED_24G) continue; + } + else if(get_current_transport()==ZMK_TRANSPORT_24G) + { + if(i==LED_BLUE) continue; + } + leds[i].effect = &led_peer_state_effect[LED_PEER_STATE_POWER_ON]; + + led_update(&leds[i]); + } + // last_mode = get_mode_status(); + // k_timer_start(&mode_check,K_MSEC(100),K_FOREVER); + // k_sem_take(&power_on_sem,K_MSEC(3000)); + // LOG_INF("power on finish"); + // led_charge_set_state(charge_led_state); +} +void reset_led_power_on(void) +{ + // k_sem_give(&power_on_sem); + led_power_on_status=0; + leds_stop(); +} + +static const struct led_effect * bat_bak_effect ; +extern uint8_t bt_bas_get_battery_level(void); +void led_bat_display(void) +{ + bat_bak_effect = leds[LED_BAT].effect; + LOG_DBG("."); + // led_charge_set_state(LED_BAT_NONE); + + // k_sem_take(&led_semi,K_MSEC(1000)); + + uint8_t level =bt_bas_get_battery_level(); + + if(level >=70) + { + struct led_color color=LED_COLOR(0,0xff,0); //green; + set_color(&leds[LED_BAT],&color); + LOG_DBG("green,level:%d",level); + + } + else if(level >=30) + { + struct led_color color=LED_COLOR(0,0,0xff); //blue; + set_color(&leds[LED_BAT],&color); + LOG_DBG("blue,level:%d",level); + } + else + { + struct led_color color=LED_COLOR(0xff,0,0); //red + set_color(&leds[LED_BAT],&color); + LOG_DBG("red,level:%d",level); + } +} +void led_bat_display_off(void) +{ + LOG_DBG("."); + // if(bat_bak_effect) + // { + // leds[LED_BAT].effect = bat_bak_effect; + // led_update(&leds[LED_BAT]); + // } + // else + if(charge_led_state !=LED_BAT_LOW) + { + led_charge_set_state(charge_led_state); + } + else + { + led_charge_set_state(LED_BAT_NONE); + } +} +void leds_turnoff(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(leds);i++) + { + set_off(&leds[i]); + } + led_charge_set_state(LED_BAT_NONE); + blue_led_set_state( LED_PEER_STATE_DISCONNECTED); + led_24G_set_state(LED_PEER_STATE_DISCONNECTED); +} + +SYS_INIT(leds_init, APPLICATION, CONFIG_ZMK_LED_INIT_PRIORITY); \ No newline at end of file diff --git a/app/src/version.h b/app/src/version.h new file mode 100644 index 00000000000..2258fe0d7b4 --- /dev/null +++ b/app/src/version.h @@ -0,0 +1,37 @@ +#ifndef __VERSION_H__ +#define __VERSION_H__ + +#if CONFIG_SHIELD_KEYCHRON_B1 +#define VERSION_MAJOR 1 +#define VERSION_MINOR 0 +#define PATCHLEVEL 4 +#elif CONFIG_SHIELD_KEYCHRON_B2 +#define VERSION_MAJOR 1 +#define VERSION_MINOR 0 +#define PATCHLEVEL 2 +#else +#define VERSION_MAJOR 1 +#define VERSION_MINOR 3 +#define PATCHLEVEL 3 +#endif +#define VERSION_TWEAK 0 +#define EXTRAVERSION "ZK" + +#define ZMK_VERSION (VERSION_MAJOR<<16| VERSION_MINOR<<8 | PATCHLEVEL)//0x00010209 +#define VIA_FIRMWARE_VERSION ZMK_VERSION + +#define USB_DEC_TO_BCD(dec) ((((dec) / 10) << 4) | ((dec) % 10)) + +/** USB Device release number (bcdDevice Descriptor field) */ +#define USB_BCD_VER (USB_DEC_TO_BCD(VERSION_MAJOR) << 8 | \ + USB_DEC_TO_BCD((VERSION_MINOR*10)+PATCHLEVEL)) +#define VER_STR1(a1,a2,a3,a4) "v"#a1"."#a2"."#a3"-"a4 +#define VER_STR(a1,a2,a3,a4) VER_STR1(a1,a2,a3,a4) + +#define APP_VERSION_STRING VER_STR(VERSION_MAJOR,VERSION_MINOR,PATCHLEVEL,EXTRAVERSION) + +//upate version.h 's timestamp in ps shell +//(Get-Item ".\src\version.h").LastWriteTime=$(Get-Date -format o) +//read version.h 's timestamp + //Get-Item .\src\version.h | Format-List CreationTime, LastAccessTime, LastWriteTime +#endif \ No newline at end of file From 1a7d51818f080378b96ff5dabea784a445c3327a Mon Sep 17 00:00:00 2001 From: william <43848894@qq.com> Date: Mon, 13 Jan 2025 15:19:30 +0800 Subject: [PATCH 3/7] remove ledstrip config --- app/boards/arm/keychron/keychron.dts | 128 +-------------------------- app/module/drivers/Kconfig | 1 - 2 files changed, 2 insertions(+), 127 deletions(-) diff --git a/app/boards/arm/keychron/keychron.dts b/app/boards/arm/keychron/keychron.dts index 1c17fb5691a..3c2164a81dc 100644 --- a/app/boards/arm/keychron/keychron.dts +++ b/app/boards/arm/keychron/keychron.dts @@ -9,7 +9,7 @@ #include #include -#include + / { model = "keychron"; @@ -23,7 +23,6 @@ zmk,battery = &vbatt; zmk,kscan = &kscan_comp;//&kscan0; zmk,matrix_transform = &default_transform; - zmk,underglow = &led_strip; }; default_transform: keymap_transform_0 { @@ -120,18 +119,7 @@ }; }; - led_strip: led-strip-composite { - compatible = "zmk,led-strip-composite"; - label = "LED_STRIP"; - chain-length = <67>; - strip-0 { - led-strip = <&led_strip_0>; - }; - strip-1 { - led-strip = <&led_strip_1>; - }; - }; - + ext-power { compatible = "zmk,ext-power-generic"; @@ -261,119 +249,7 @@ -ckled:&i2c0 { - // compatible = "nordic,nrf-twi"; - pinctrl-0 = <&i2c0_default>; - pinctrl-names = "default"; - status = "disabled"; - - // pinctrl-0 = <&i2c0_default>; - // pinctrl-1 = <&i2c0_sleep>; - // pinctrl-names = "default", "sleep"; - // clock-frequency = ; - - led_strip_0: ckled2001@77 { - compatible = "zmk,ckled2001"; - //label = "LED_STRIP_0"; - /* ADDR/CS pin connected to VDDIO */ - /* Located closer to the USB daughterboard connection */ - reg = <0x77>; - chain-length = <34>; - map = < - /* ROW 0 */ - /* R G B */ - CK(2, 0) CK(0, 0) CK(1, 0) - CK(2, 1) CK(0, 1) CK(1, 1) - CK(2, 2) CK(0, 2) CK(1, 2) - CK(2, 3) CK(0, 3) CK(1, 3) - CK(2, 4) CK(0, 4) CK(1, 4) - CK(2, 5) CK(0, 5) CK(1, 5) - CK(2, 6) CK(0, 6) CK(1, 6) - CK(2, 7) CK(0, 7) CK(1, 7) - CK(2, 8) CK(0, 8) CK(1, 8) - CK(2, 9) CK(0, 9) CK(1, 9) - CK(2,10) CK(0,10) CK(1,10) - CK(2,11) CK(0,11) CK(1,11) - CK(2,12) CK(0,12) CK(1,12) - CK(2,13) CK(0,13) CK(1,13) - CK(2,15) CK(0,15) CK(1,15) - /* ROW 1 */ - /* R G B */ - CK(8, 0) CK(6, 0) CK(7, 0) - CK(8, 1) CK(6, 1) CK(7, 1) - CK(8, 2) CK(6, 2) CK(7, 2) - CK(8, 3) CK(6, 3) CK(7, 3) - /* ROW 2 */ - /* R G B */ - CK(5, 0) CK(3, 0) CK(4, 0) - CK(5, 1) CK(3, 1) CK(4, 1) - CK(5, 2) CK(3, 2) CK(4, 2) - CK(5, 3) CK(3, 3) CK(4, 3) - CK(5, 4) CK(3, 4) CK(4, 4) - CK(5, 5) CK(3, 5) CK(4, 5) - CK(5, 6) CK(3, 6) CK(4, 6) - CK(5, 7) CK(3, 7) CK(4, 7) - CK(5, 8) CK(3, 8) CK(4, 8) - CK(5, 9) CK(3, 9) CK(4, 9) - CK(5,10) CK(3,10) CK(4,10) - CK(5,11) CK(3,11) CK(4,11) - CK(5,12) CK(3,12) CK(4,12) - CK(5,13) CK(3,13) CK(4,13) - CK(5,15) CK(3,15) CK(4,15) - >; - }; - - led_strip_1: ckled2001@74 { - compatible = "zmk,ckled2001"; - //label = "LED_STRIP_1"; - /* ADDR/CS pin connected to GND */ - /* Located closer to the space bar */ - reg = <0x74>; - chain-length = <33>; - map = < - /* ROW 3 */ - /* R G B */ - CK(8, 4) CK(6, 4) CK(7, 4) - CK(8, 5) CK(6, 5) CK(7, 5) - CK(8, 6) CK(6, 6) CK(7, 6) - CK(8, 7) CK(6, 7) CK(7, 7) - CK(8, 8) CK(6, 8) CK(7, 8) - CK(8, 9) CK(6, 9) CK(7, 9) - CK(8,10) CK(6,10) CK(7,10) - CK(8,11) CK(6,11) CK(7,11) - CK(8,13) CK(6,13) CK(7,13) - CK(8,15) CK(6,15) CK(7,15) - /* ROW 4 */ - /* R G B */ - CK(5, 0) CK(3, 0) CK(4, 0) - CK(5, 1) CK(3, 1) CK(4, 1) - CK(5, 2) CK(3, 2) CK(4, 2) - CK(5, 6) CK(3, 6) CK(4, 6) - CK(5,10) CK(3,10) CK(4,10) - CK(5,11) CK(3,11) CK(4,11) - CK(5,12) CK(3,12) CK(4,12) - CK(5,13) CK(3,13) CK(4,13) - CK(5,14) CK(3,14) CK(4,14) - CK(5,15) CK(3,15) CK(4,15) - /* ROW 5 */ - /* R G B */ - CK(2, 0) CK(0, 0) CK(1, 0) - CK(2, 2) CK(0, 2) CK(1, 2) - CK(2, 3) CK(0, 3) CK(1, 3) - CK(2, 4) CK(0, 4) CK(1, 4) - CK(2, 5) CK(0, 5) CK(1, 5) - CK(2, 6) CK(0, 6) CK(1, 6) - CK(2, 7) CK(0, 7) CK(1, 7) - CK(2, 8) CK(0, 8) CK(1, 8) - CK(2, 9) CK(0, 9) CK(1, 9) - CK(2,10) CK(0,10) CK(1,10) - CK(2,11) CK(0,11) CK(1,11) - CK(2,13) CK(0,13) CK(1,13) - CK(2,14) CK(0,14) CK(1,14) - >; - }; -}; &usbd { diff --git a/app/module/drivers/Kconfig b/app/module/drivers/Kconfig index 5c0d6437e3e..c57ed3347c9 100644 --- a/app/module/drivers/Kconfig +++ b/app/module/drivers/Kconfig @@ -5,4 +5,3 @@ rsource "gpio/Kconfig" rsource "kscan/Kconfig" rsource "sensor/Kconfig" rsource "display/Kconfig" -rsource "led_strip/Kconfig" From 7df1550136f368a58fdd6915b0abf4dc81cfa4ea Mon Sep 17 00:00:00 2001 From: william <43848894@qq.com> Date: Mon, 13 Jan 2025 16:08:51 +0800 Subject: [PATCH 4/7] =?UTF-8?q?add=20zephyr=20patch=EF=BC=81=20change=20Re?= =?UTF-8?q?adme.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 0001-esb-nrf-fix.patch | 117 +++++++++++++++++++++++++++++++++++++++++ README.md | 14 +++++ 2 files changed, 131 insertions(+) create mode 100644 0001-esb-nrf-fix.patch diff --git a/0001-esb-nrf-fix.patch b/0001-esb-nrf-fix.patch new file mode 100644 index 00000000000..12d4c3bbd7b --- /dev/null +++ b/0001-esb-nrf-fix.patch @@ -0,0 +1,117 @@ +From 46e84d0dfcb21acde11d531eb40f91ee551942c6 Mon Sep 17 00:00:00 2001 +From: william <43848894@qq.com> +Date: Mon, 13 Jan 2025 12:16:43 +0800 +Subject: [PATCH] esb nrf fix + +--- + drivers/usb/device/usb_dc_nrfx.c | 4 ++- + .../controller/ll_sw/nordic/lll/lll.c | 29 ++++++++++++++++++- + subsys/bluetooth/services/bas.c | 14 +++++++++ + 3 files changed, 45 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/device/usb_dc_nrfx.c b/drivers/usb/device/usb_dc_nrfx.c +index c0b661007..c2014c3ba 100644 +--- a/drivers/usb/device/usb_dc_nrfx.c ++++ b/drivers/usb/device/usb_dc_nrfx.c +@@ -1075,7 +1075,9 @@ static void usbd_event_handler(nrfx_usbd_evt_t const *const p_event) + case NRFX_USBD_EVT_SOF: + if (IS_ENABLED(CONFIG_USB_DEVICE_SOF)) { + evt.evt_type = USBD_EVT_SOF; +- put_evt = true; ++ // put_evt = true; ++ extern uint32_t usb_sof_count; ++ usb_sof_count ++; + } + break; + +diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c +index e3ce60282..5bfe7d38d 100644 +--- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c ++++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c +@@ -84,7 +84,11 @@ static void ticker_op_job_disable(uint32_t status, void *op_context); + #endif + #endif /* CONFIG_BT_CTLR_LOW_LAT */ + ++#if defined(CONFIG_DYNAMIC_DIRECT_INTERRUPTS) ++static void radio_nrf5_isr(const void *arg) ++#else /* !CONFIG_DYNAMIC_DIRECT_INTERRUPTS */ + ISR_DIRECT_DECLARE(radio_nrf5_isr) ++#endif /* !CONFIG_DYNAMIC_DIRECT_INTERRUPTS */ + { + DEBUG_RADIO_ISR(1); + +@@ -97,7 +101,9 @@ ISR_DIRECT_DECLARE(radio_nrf5_isr) + lll_prof_exit_radio(); + + DEBUG_RADIO_ISR(0); ++#if !defined(CONFIG_DYNAMIC_DIRECT_INTERRUPTS) + return 1; ++#endif /* !CONFIG_DYNAMIC_DIRECT_INTERRUPTS */ + } + + static void rtc0_nrf5_isr(const void *arg) +@@ -183,7 +189,27 @@ int lll_init(void) + + /* Initialize SW IRQ structure */ + hal_swi_init(); ++#if defined(CONFIG_DYNAMIC_INTERRUPTS) ++#if defined(CONFIG_DYNAMIC_DIRECT_INTERRUPTS) ++ ARM_IRQ_DIRECT_DYNAMIC_CONNECT(RADIO_IRQn, CONFIG_BT_CTLR_LLL_PRIO, ++ IRQ_CONNECT_FLAGS, no_reschedule); ++ irq_connect_dynamic(RADIO_IRQn, CONFIG_BT_CTLR_LLL_PRIO, ++ radio_nrf5_isr, NULL, IRQ_CONNECT_FLAGS); ++#else /* !CONFIG_DYNAMIC_DIRECT_INTERRUPTS */ ++ IRQ_DIRECT_CONNECT(RADIO_IRQn, CONFIG_BT_CTLR_LLL_PRIO, ++ radio_nrf5_isr, IRQ_CONNECT_FLAGS); ++#endif /* !CONFIG_DYNAMIC_DIRECT_INTERRUPTS */ ++ irq_connect_dynamic(RTC0_IRQn, CONFIG_BT_CTLR_ULL_HIGH_PRIO, ++ rtc0_nrf5_isr, NULL, 0U); ++ irq_connect_dynamic(HAL_SWI_RADIO_IRQ, CONFIG_BT_CTLR_LLL_PRIO, ++ swi_lll_nrf5_isr, NULL, IRQ_CONNECT_FLAGS); ++#if defined(CONFIG_BT_CTLR_LOW_LAT) || \ ++ (CONFIG_BT_CTLR_ULL_HIGH_PRIO != CONFIG_BT_CTLR_ULL_LOW_PRIO) ++ irq_connect_dynamic(HAL_SWI_JOB_IRQ, CONFIG_BT_CTLR_ULL_LOW_PRIO, ++ swi_ull_low_nrf5_isr, NULL, 0U); ++#endif + ++#else /* !CONFIG_DYNAMIC_INTERRUPTS */ + /* Connect ISRs */ + IRQ_DIRECT_CONNECT(RADIO_IRQn, CONFIG_BT_CTLR_LLL_PRIO, + radio_nrf5_isr, IRQ_CONNECT_FLAGS); +@@ -196,7 +222,8 @@ int lll_init(void) + IRQ_CONNECT(HAL_SWI_JOB_IRQ, CONFIG_BT_CTLR_ULL_LOW_PRIO, + swi_ull_low_nrf5_isr, NULL, 0); + #endif +- ++#endif /* !CONFIG_DYNAMIC_INTERRUPTS */ ++ + /* Enable IRQs */ + irq_enable(RADIO_IRQn); + irq_enable(RTC0_IRQn); +diff --git a/subsys/bluetooth/services/bas.c b/subsys/bluetooth/services/bas.c +index cf6482d53..ead09c15a 100644 +--- a/subsys/bluetooth/services/bas.c ++++ b/subsys/bluetooth/services/bas.c +@@ -95,5 +95,19 @@ int bt_bas_set_battery_level(uint8_t level) + + return rc == -ENOTCONN ? 0 : rc; + } ++//add by cwl @2023/11/23 ++int bt_bas_set_battery_level_fix(struct bt_conn *conn,uint8_t level) ++{ ++ int rc; ++ battery_level = level; ++ if (level > 100U || conn ==NULL) { ++ if(level > 100U) battery_level =100; ++ return -EINVAL; ++ } ++ ++ rc = bt_gatt_notify(conn, &bas.attrs[1], &level, sizeof(level)); ++ ++ return rc == -ENOTCONN ? 0 : rc; ++} + + SYS_INIT(bas_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); +-- +2.42.0.windows.2 + diff --git a/README.md b/README.md index f112b0f9705..46d15ad3078 100644 --- a/README.md +++ b/README.md @@ -11,3 +11,17 @@ Check out the website to learn more: https://zmk.dev/. You can also come join our [ZMK Discord Server](https://zmk.dev/community/discord/invite). To review features, check out the [feature overview](https://zmk.dev/docs/). ZMK is under active development, and new features are listed with the [enhancement label](https://github.com/zmkfirmware/zmk/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) in GitHub. Please feel free to add 👍 to the issue description of any requests to upvote the feature. + +[Keychron](https://keychron.com/) use zmk source code for Bpro series keyboards ,have made big changes fro Bpro, also add proprietary 2.4g communication. + +To build the firmware ,for example: keychorn b1 pro +``` + mkdir keychron + cd keychron + git clone -b keychron_bpro https://github.com/keychron/zmk.git + cd zmk + west init -l app/ + west update + git am 001-esb-nrf-fix.patch + west build -b keychron -p -- -DSHIELD=keychron_b1_us +``` \ No newline at end of file From dd86028ef213db5d9d3feabe10ae6ac256040d8a Mon Sep 17 00:00:00 2001 From: william <43848894@qq.com> Date: Sat, 18 Jan 2025 10:24:20 +0800 Subject: [PATCH 5/7] reorganize keychron keyboard files --- app/boards/shields/keychron/Kconfig.shield | 51 ---- .../shields/keychron/b1/jis/Kconfig.shield | 14 + .../{ => b1/jis}/keychron_b1_jis.conf | 0 .../{ => b1/jis}/keychron_b1_jis.keymap | 0 .../{ => b1/jis}/keychron_b1_jis.overlay | 0 .../shields/keychron/b1/uk/Kconfig.shield | 14 + .../keychron/{ => b1/uk}/keychron_b1_uk.conf | 0 .../{ => b1/uk}/keychron_b1_uk.keymap | 0 .../{ => b1/uk}/keychron_b1_uk.overlay | 0 .../shields/keychron/b1/us/Kconfig.shield | 14 + .../keychron/{ => b1/us}/keychron_b1_us.conf | 0 .../{ => b1/us}/keychron_b1_us.keymap | 0 .../{ => b1/us}/keychron_b1_us.overlay | 0 .../shields/keychron/b2/jis/Kconfig.shield | 14 + .../{ => b2/jis}/keychron_b2_jis.conf | 0 .../{ => b2/jis}/keychron_b2_jis.keymap | 0 .../{ => b2/jis}/keychron_b2_jis.overlay | 0 .../shields/keychron/b2/kr/Kconfig.shield | 14 + .../keychron/{ => b2/kr}/keychron_b2_kr.conf | 0 .../{ => b2/kr}/keychron_b2_kr.keymap | 0 .../{ => b2/kr}/keychron_b2_kr.overlay | 0 .../shields/keychron/b2/uk/Kconfig.shield | 14 + .../keychron/{ => b2/uk}/keychron_b2_uk.conf | 0 .../{ => b2/uk}/keychron_b2_uk.keymap | 0 .../{ => b2/uk}/keychron_b2_uk.overlay | 0 .../shields/keychron/b2/us/Kconfig.shield | 14 + .../keychron/{ => b2/us}/keychron_b2_us.conf | 0 .../{ => b2/us}/keychron_b2_us.keymap | 0 .../{ => b2/us}/keychron_b2_us.overlay | 0 .../shields/keychron/b6/jis/Kconfig.shield | 11 + .../{ => b6/jis}/keychron_b6_jis.conf | 0 .../{ => b6/jis}/keychron_b6_jis.keymap | 0 .../{ => b6/jis}/keychron_b6_jis.overlay | 0 .../shields/keychron/b6/uk/Kconfig.shield | 11 + .../keychron/{ => b6/uk}/keychron_b6_uk.conf | 0 .../{ => b6/uk}/keychron_b6_uk.keymap | 0 .../{ => b6/uk}/keychron_b6_uk.overlay | 0 .../shields/keychron/b6/us/Kconfig.shield | 9 + .../keychron/{ => b6/us}/keychron_b6_us.conf | 0 .../{ => b6/us}/keychron_b6_us.keymap | 0 .../{ => b6/us}/keychron_b6_us.overlay | 0 app/boards/shields/keychron/keychron.zmk.yml | 4 +- .../shields/keychron/keychron_b1_us_dbg.conf | 25 -- .../keychron/keychron_b1_us_dbg.keymap | 255 ------------------ .../keychron/keychron_b1_us_dbg.overlay | 56 ---- app/boards/shields/keychron/keychron_rgb.conf | 20 -- .../shields/keychron/keychron_rgb.keymap | 59 ---- .../shields/keychron/keychron_rgb.overlay | 195 -------------- 48 files changed, 132 insertions(+), 662 deletions(-) delete mode 100644 app/boards/shields/keychron/Kconfig.shield create mode 100644 app/boards/shields/keychron/b1/jis/Kconfig.shield rename app/boards/shields/keychron/{ => b1/jis}/keychron_b1_jis.conf (100%) rename app/boards/shields/keychron/{ => b1/jis}/keychron_b1_jis.keymap (100%) rename app/boards/shields/keychron/{ => b1/jis}/keychron_b1_jis.overlay (100%) create mode 100644 app/boards/shields/keychron/b1/uk/Kconfig.shield rename app/boards/shields/keychron/{ => b1/uk}/keychron_b1_uk.conf (100%) rename app/boards/shields/keychron/{ => b1/uk}/keychron_b1_uk.keymap (100%) rename app/boards/shields/keychron/{ => b1/uk}/keychron_b1_uk.overlay (100%) create mode 100644 app/boards/shields/keychron/b1/us/Kconfig.shield rename app/boards/shields/keychron/{ => b1/us}/keychron_b1_us.conf (100%) rename app/boards/shields/keychron/{ => b1/us}/keychron_b1_us.keymap (100%) rename app/boards/shields/keychron/{ => b1/us}/keychron_b1_us.overlay (100%) create mode 100644 app/boards/shields/keychron/b2/jis/Kconfig.shield rename app/boards/shields/keychron/{ => b2/jis}/keychron_b2_jis.conf (100%) rename app/boards/shields/keychron/{ => b2/jis}/keychron_b2_jis.keymap (100%) rename app/boards/shields/keychron/{ => b2/jis}/keychron_b2_jis.overlay (100%) create mode 100644 app/boards/shields/keychron/b2/kr/Kconfig.shield rename app/boards/shields/keychron/{ => b2/kr}/keychron_b2_kr.conf (100%) rename app/boards/shields/keychron/{ => b2/kr}/keychron_b2_kr.keymap (100%) rename app/boards/shields/keychron/{ => b2/kr}/keychron_b2_kr.overlay (100%) create mode 100644 app/boards/shields/keychron/b2/uk/Kconfig.shield rename app/boards/shields/keychron/{ => b2/uk}/keychron_b2_uk.conf (100%) rename app/boards/shields/keychron/{ => b2/uk}/keychron_b2_uk.keymap (100%) rename app/boards/shields/keychron/{ => b2/uk}/keychron_b2_uk.overlay (100%) create mode 100644 app/boards/shields/keychron/b2/us/Kconfig.shield rename app/boards/shields/keychron/{ => b2/us}/keychron_b2_us.conf (100%) rename app/boards/shields/keychron/{ => b2/us}/keychron_b2_us.keymap (100%) rename app/boards/shields/keychron/{ => b2/us}/keychron_b2_us.overlay (100%) create mode 100644 app/boards/shields/keychron/b6/jis/Kconfig.shield rename app/boards/shields/keychron/{ => b6/jis}/keychron_b6_jis.conf (100%) rename app/boards/shields/keychron/{ => b6/jis}/keychron_b6_jis.keymap (100%) rename app/boards/shields/keychron/{ => b6/jis}/keychron_b6_jis.overlay (100%) create mode 100644 app/boards/shields/keychron/b6/uk/Kconfig.shield rename app/boards/shields/keychron/{ => b6/uk}/keychron_b6_uk.conf (100%) rename app/boards/shields/keychron/{ => b6/uk}/keychron_b6_uk.keymap (100%) rename app/boards/shields/keychron/{ => b6/uk}/keychron_b6_uk.overlay (100%) create mode 100644 app/boards/shields/keychron/b6/us/Kconfig.shield rename app/boards/shields/keychron/{ => b6/us}/keychron_b6_us.conf (100%) rename app/boards/shields/keychron/{ => b6/us}/keychron_b6_us.keymap (100%) rename app/boards/shields/keychron/{ => b6/us}/keychron_b6_us.overlay (100%) delete mode 100644 app/boards/shields/keychron/keychron_b1_us_dbg.conf delete mode 100644 app/boards/shields/keychron/keychron_b1_us_dbg.keymap delete mode 100644 app/boards/shields/keychron/keychron_b1_us_dbg.overlay delete mode 100644 app/boards/shields/keychron/keychron_rgb.conf delete mode 100644 app/boards/shields/keychron/keychron_rgb.keymap delete mode 100644 app/boards/shields/keychron/keychron_rgb.overlay diff --git a/app/boards/shields/keychron/Kconfig.shield b/app/boards/shields/keychron/Kconfig.shield deleted file mode 100644 index 7418aa2e9e9..00000000000 --- a/app/boards/shields/keychron/Kconfig.shield +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) 2020 Pete Johanson -# SPDX-License-Identifier: MIT - -config SHIELD_KEYCHRON_B6_UK - def_bool $(shields_list_contains,keychron_b6_uk) - -config SHIELD_KEYCHRON_B6_US - def_bool $(shields_list_contains,keychron_b6_us) - -config SHIELD_KEYCHRON_B6_JIS - def_bool $(shields_list_contains,keychron_b6_jis) - -config SHIELD_KEYCHRON_B1 - bool - -config SHIELD_KEYCHRON_B1_UK - def_bool $(shields_list_contains,keychron_b1_uk) - select SHIELD_KEYCHRON_B1 - -config SHIELD_KEYCHRON_B1_US - def_bool $(shields_list_contains,keychron_b1_us) - select SHIELD_KEYCHRON_B1 - -config SHIELD_KEYCHRON_B1_JIS - def_bool $(shields_list_contains,keychron_b1_jis) - select SHIELD_KEYCHRON_B1 - -config SHIELD_KEYCHRON_B1_US_DEBUG - def_bool $(shields_list_contains,keychron_b1_us_dbg) - select SHIELD_KEYCHRON_B1 - -config SHIELD_KEYCHRON_B2 - bool -config SHIELD_KEYCHRON_B2_UK - def_bool $(shields_list_contains,keychron_b2_uk) - select SHIELD_KEYCHRON_B2 - -config SHIELD_KEYCHRON_B2_US - def_bool $(shields_list_contains,keychron_b2_us) - select SHIELD_KEYCHRON_B2 - -config SHIELD_KEYCHRON_B2_JIS - def_bool $(shields_list_contains,keychron_b2_jis) - select SHIELD_KEYCHRON_B2 - -config SHIELD_KEYCHRON_B2_KR - def_bool $(shields_list_contains,keychron_b2_kr) - select SHIELD_KEYCHRON_B2 - -config SHIELD_KEYCHRON_RGB - def_bool $(shields_list_contains,keychron_RGB) \ No newline at end of file diff --git a/app/boards/shields/keychron/b1/jis/Kconfig.shield b/app/boards/shields/keychron/b1/jis/Kconfig.shield new file mode 100644 index 00000000000..d6eec1464e3 --- /dev/null +++ b/app/boards/shields/keychron/b1/jis/Kconfig.shield @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Keychron +# SPDX-License-Identifier: MIT + + + +config SHIELD_KEYCHRON_B1 + bool + +config SHIELD_KEYCHRON_B1_JIS + def_bool $(shields_list_contains,keychron_b1_jis) + select SHIELD_KEYCHRON_B1 + + + diff --git a/app/boards/shields/keychron/keychron_b1_jis.conf b/app/boards/shields/keychron/b1/jis/keychron_b1_jis.conf similarity index 100% rename from app/boards/shields/keychron/keychron_b1_jis.conf rename to app/boards/shields/keychron/b1/jis/keychron_b1_jis.conf diff --git a/app/boards/shields/keychron/keychron_b1_jis.keymap b/app/boards/shields/keychron/b1/jis/keychron_b1_jis.keymap similarity index 100% rename from app/boards/shields/keychron/keychron_b1_jis.keymap rename to app/boards/shields/keychron/b1/jis/keychron_b1_jis.keymap diff --git a/app/boards/shields/keychron/keychron_b1_jis.overlay b/app/boards/shields/keychron/b1/jis/keychron_b1_jis.overlay similarity index 100% rename from app/boards/shields/keychron/keychron_b1_jis.overlay rename to app/boards/shields/keychron/b1/jis/keychron_b1_jis.overlay diff --git a/app/boards/shields/keychron/b1/uk/Kconfig.shield b/app/boards/shields/keychron/b1/uk/Kconfig.shield new file mode 100644 index 00000000000..7e1ca10da6f --- /dev/null +++ b/app/boards/shields/keychron/b1/uk/Kconfig.shield @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Keychron +# SPDX-License-Identifier: MIT + + + +config SHIELD_KEYCHRON_B1 + bool + +config SHIELD_KEYCHRON_B1_UK + def_bool $(shields_list_contains,keychron_b1_uk) + select SHIELD_KEYCHRON_B1 + + + diff --git a/app/boards/shields/keychron/keychron_b1_uk.conf b/app/boards/shields/keychron/b1/uk/keychron_b1_uk.conf similarity index 100% rename from app/boards/shields/keychron/keychron_b1_uk.conf rename to app/boards/shields/keychron/b1/uk/keychron_b1_uk.conf diff --git a/app/boards/shields/keychron/keychron_b1_uk.keymap b/app/boards/shields/keychron/b1/uk/keychron_b1_uk.keymap similarity index 100% rename from app/boards/shields/keychron/keychron_b1_uk.keymap rename to app/boards/shields/keychron/b1/uk/keychron_b1_uk.keymap diff --git a/app/boards/shields/keychron/keychron_b1_uk.overlay b/app/boards/shields/keychron/b1/uk/keychron_b1_uk.overlay similarity index 100% rename from app/boards/shields/keychron/keychron_b1_uk.overlay rename to app/boards/shields/keychron/b1/uk/keychron_b1_uk.overlay diff --git a/app/boards/shields/keychron/b1/us/Kconfig.shield b/app/boards/shields/keychron/b1/us/Kconfig.shield new file mode 100644 index 00000000000..e5db86e96d3 --- /dev/null +++ b/app/boards/shields/keychron/b1/us/Kconfig.shield @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Keychron +# SPDX-License-Identifier: MIT + + + +config SHIELD_KEYCHRON_B1 + bool + +config SHIELD_KEYCHRON_B1_US + def_bool $(shields_list_contains,keychron_b1_us) + select SHIELD_KEYCHRON_B1 + + + diff --git a/app/boards/shields/keychron/keychron_b1_us.conf b/app/boards/shields/keychron/b1/us/keychron_b1_us.conf similarity index 100% rename from app/boards/shields/keychron/keychron_b1_us.conf rename to app/boards/shields/keychron/b1/us/keychron_b1_us.conf diff --git a/app/boards/shields/keychron/keychron_b1_us.keymap b/app/boards/shields/keychron/b1/us/keychron_b1_us.keymap similarity index 100% rename from app/boards/shields/keychron/keychron_b1_us.keymap rename to app/boards/shields/keychron/b1/us/keychron_b1_us.keymap diff --git a/app/boards/shields/keychron/keychron_b1_us.overlay b/app/boards/shields/keychron/b1/us/keychron_b1_us.overlay similarity index 100% rename from app/boards/shields/keychron/keychron_b1_us.overlay rename to app/boards/shields/keychron/b1/us/keychron_b1_us.overlay diff --git a/app/boards/shields/keychron/b2/jis/Kconfig.shield b/app/boards/shields/keychron/b2/jis/Kconfig.shield new file mode 100644 index 00000000000..7d4912281cd --- /dev/null +++ b/app/boards/shields/keychron/b2/jis/Kconfig.shield @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Keychron +# SPDX-License-Identifier: MIT + + + +config SHIELD_KEYCHRON_B2 + bool + +config SHIELD_KEYCHRON_B2_JIS + def_bool $(shields_list_contains,keychron_b2_jis) + select SHIELD_KEYCHRON_B2 + + + diff --git a/app/boards/shields/keychron/keychron_b2_jis.conf b/app/boards/shields/keychron/b2/jis/keychron_b2_jis.conf similarity index 100% rename from app/boards/shields/keychron/keychron_b2_jis.conf rename to app/boards/shields/keychron/b2/jis/keychron_b2_jis.conf diff --git a/app/boards/shields/keychron/keychron_b2_jis.keymap b/app/boards/shields/keychron/b2/jis/keychron_b2_jis.keymap similarity index 100% rename from app/boards/shields/keychron/keychron_b2_jis.keymap rename to app/boards/shields/keychron/b2/jis/keychron_b2_jis.keymap diff --git a/app/boards/shields/keychron/keychron_b2_jis.overlay b/app/boards/shields/keychron/b2/jis/keychron_b2_jis.overlay similarity index 100% rename from app/boards/shields/keychron/keychron_b2_jis.overlay rename to app/boards/shields/keychron/b2/jis/keychron_b2_jis.overlay diff --git a/app/boards/shields/keychron/b2/kr/Kconfig.shield b/app/boards/shields/keychron/b2/kr/Kconfig.shield new file mode 100644 index 00000000000..b59549bd5d2 --- /dev/null +++ b/app/boards/shields/keychron/b2/kr/Kconfig.shield @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Keychron +# SPDX-License-Identifier: MIT + + + +config SHIELD_KEYCHRON_B2 + bool + +config SHIELD_KEYCHRON_B2_KR + def_bool $(shields_list_contains,keychron_b2_kr) + select SHIELD_KEYCHRON_B2 + + + diff --git a/app/boards/shields/keychron/keychron_b2_kr.conf b/app/boards/shields/keychron/b2/kr/keychron_b2_kr.conf similarity index 100% rename from app/boards/shields/keychron/keychron_b2_kr.conf rename to app/boards/shields/keychron/b2/kr/keychron_b2_kr.conf diff --git a/app/boards/shields/keychron/keychron_b2_kr.keymap b/app/boards/shields/keychron/b2/kr/keychron_b2_kr.keymap similarity index 100% rename from app/boards/shields/keychron/keychron_b2_kr.keymap rename to app/boards/shields/keychron/b2/kr/keychron_b2_kr.keymap diff --git a/app/boards/shields/keychron/keychron_b2_kr.overlay b/app/boards/shields/keychron/b2/kr/keychron_b2_kr.overlay similarity index 100% rename from app/boards/shields/keychron/keychron_b2_kr.overlay rename to app/boards/shields/keychron/b2/kr/keychron_b2_kr.overlay diff --git a/app/boards/shields/keychron/b2/uk/Kconfig.shield b/app/boards/shields/keychron/b2/uk/Kconfig.shield new file mode 100644 index 00000000000..38147600b8f --- /dev/null +++ b/app/boards/shields/keychron/b2/uk/Kconfig.shield @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Keychron +# SPDX-License-Identifier: MIT + + + +config SHIELD_KEYCHRON_B2 + bool + +config SHIELD_KEYCHRON_B2_UK + def_bool $(shields_list_contains,keychron_b2_uk) + select SHIELD_KEYCHRON_B2 + + + diff --git a/app/boards/shields/keychron/keychron_b2_uk.conf b/app/boards/shields/keychron/b2/uk/keychron_b2_uk.conf similarity index 100% rename from app/boards/shields/keychron/keychron_b2_uk.conf rename to app/boards/shields/keychron/b2/uk/keychron_b2_uk.conf diff --git a/app/boards/shields/keychron/keychron_b2_uk.keymap b/app/boards/shields/keychron/b2/uk/keychron_b2_uk.keymap similarity index 100% rename from app/boards/shields/keychron/keychron_b2_uk.keymap rename to app/boards/shields/keychron/b2/uk/keychron_b2_uk.keymap diff --git a/app/boards/shields/keychron/keychron_b2_uk.overlay b/app/boards/shields/keychron/b2/uk/keychron_b2_uk.overlay similarity index 100% rename from app/boards/shields/keychron/keychron_b2_uk.overlay rename to app/boards/shields/keychron/b2/uk/keychron_b2_uk.overlay diff --git a/app/boards/shields/keychron/b2/us/Kconfig.shield b/app/boards/shields/keychron/b2/us/Kconfig.shield new file mode 100644 index 00000000000..06ecc2f9272 --- /dev/null +++ b/app/boards/shields/keychron/b2/us/Kconfig.shield @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Keychron +# SPDX-License-Identifier: MIT + + + +config SHIELD_KEYCHRON_B2 + bool + +config SHIELD_KEYCHRON_B2_US + def_bool $(shields_list_contains,keychron_b2_us) + select SHIELD_KEYCHRON_B2 + + + diff --git a/app/boards/shields/keychron/keychron_b2_us.conf b/app/boards/shields/keychron/b2/us/keychron_b2_us.conf similarity index 100% rename from app/boards/shields/keychron/keychron_b2_us.conf rename to app/boards/shields/keychron/b2/us/keychron_b2_us.conf diff --git a/app/boards/shields/keychron/keychron_b2_us.keymap b/app/boards/shields/keychron/b2/us/keychron_b2_us.keymap similarity index 100% rename from app/boards/shields/keychron/keychron_b2_us.keymap rename to app/boards/shields/keychron/b2/us/keychron_b2_us.keymap diff --git a/app/boards/shields/keychron/keychron_b2_us.overlay b/app/boards/shields/keychron/b2/us/keychron_b2_us.overlay similarity index 100% rename from app/boards/shields/keychron/keychron_b2_us.overlay rename to app/boards/shields/keychron/b2/us/keychron_b2_us.overlay diff --git a/app/boards/shields/keychron/b6/jis/Kconfig.shield b/app/boards/shields/keychron/b6/jis/Kconfig.shield new file mode 100644 index 00000000000..24175117c51 --- /dev/null +++ b/app/boards/shields/keychron/b6/jis/Kconfig.shield @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Keychron +# SPDX-License-Identifier: MIT + + + +config SHIELD_KEYCHRON_B6_JIS + def_bool $(shields_list_contains,keychron_b6_jis) + + + + diff --git a/app/boards/shields/keychron/keychron_b6_jis.conf b/app/boards/shields/keychron/b6/jis/keychron_b6_jis.conf similarity index 100% rename from app/boards/shields/keychron/keychron_b6_jis.conf rename to app/boards/shields/keychron/b6/jis/keychron_b6_jis.conf diff --git a/app/boards/shields/keychron/keychron_b6_jis.keymap b/app/boards/shields/keychron/b6/jis/keychron_b6_jis.keymap similarity index 100% rename from app/boards/shields/keychron/keychron_b6_jis.keymap rename to app/boards/shields/keychron/b6/jis/keychron_b6_jis.keymap diff --git a/app/boards/shields/keychron/keychron_b6_jis.overlay b/app/boards/shields/keychron/b6/jis/keychron_b6_jis.overlay similarity index 100% rename from app/boards/shields/keychron/keychron_b6_jis.overlay rename to app/boards/shields/keychron/b6/jis/keychron_b6_jis.overlay diff --git a/app/boards/shields/keychron/b6/uk/Kconfig.shield b/app/boards/shields/keychron/b6/uk/Kconfig.shield new file mode 100644 index 00000000000..0d437d27a35 --- /dev/null +++ b/app/boards/shields/keychron/b6/uk/Kconfig.shield @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Keychron +# SPDX-License-Identifier: MIT + + + +config SHIELD_KEYCHRON_B6_UK + def_bool $(shields_list_contains,keychron_b6_uk) + + + + diff --git a/app/boards/shields/keychron/keychron_b6_uk.conf b/app/boards/shields/keychron/b6/uk/keychron_b6_uk.conf similarity index 100% rename from app/boards/shields/keychron/keychron_b6_uk.conf rename to app/boards/shields/keychron/b6/uk/keychron_b6_uk.conf diff --git a/app/boards/shields/keychron/keychron_b6_uk.keymap b/app/boards/shields/keychron/b6/uk/keychron_b6_uk.keymap similarity index 100% rename from app/boards/shields/keychron/keychron_b6_uk.keymap rename to app/boards/shields/keychron/b6/uk/keychron_b6_uk.keymap diff --git a/app/boards/shields/keychron/keychron_b6_uk.overlay b/app/boards/shields/keychron/b6/uk/keychron_b6_uk.overlay similarity index 100% rename from app/boards/shields/keychron/keychron_b6_uk.overlay rename to app/boards/shields/keychron/b6/uk/keychron_b6_uk.overlay diff --git a/app/boards/shields/keychron/b6/us/Kconfig.shield b/app/boards/shields/keychron/b6/us/Kconfig.shield new file mode 100644 index 00000000000..6d95f78a0e9 --- /dev/null +++ b/app/boards/shields/keychron/b6/us/Kconfig.shield @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Keychron +# SPDX-License-Identifier: MIT + + +config SHIELD_KEYCHRON_B6_US + def_bool $(shields_list_contains,keychron_b6_us) + + + diff --git a/app/boards/shields/keychron/keychron_b6_us.conf b/app/boards/shields/keychron/b6/us/keychron_b6_us.conf similarity index 100% rename from app/boards/shields/keychron/keychron_b6_us.conf rename to app/boards/shields/keychron/b6/us/keychron_b6_us.conf diff --git a/app/boards/shields/keychron/keychron_b6_us.keymap b/app/boards/shields/keychron/b6/us/keychron_b6_us.keymap similarity index 100% rename from app/boards/shields/keychron/keychron_b6_us.keymap rename to app/boards/shields/keychron/b6/us/keychron_b6_us.keymap diff --git a/app/boards/shields/keychron/keychron_b6_us.overlay b/app/boards/shields/keychron/b6/us/keychron_b6_us.overlay similarity index 100% rename from app/boards/shields/keychron/keychron_b6_us.overlay rename to app/boards/shields/keychron/b6/us/keychron_b6_us.overlay diff --git a/app/boards/shields/keychron/keychron.zmk.yml b/app/boards/shields/keychron/keychron.zmk.yml index 6f648122afa..be217dd1792 100644 --- a/app/boards/shields/keychron/keychron.zmk.yml +++ b/app/boards/shields/keychron/keychron.zmk.yml @@ -5,8 +5,10 @@ type: board arch: arm features: - keys - - underglow + outputs: - usb - ble + - 24G + url: https://www.keychron.com/ diff --git a/app/boards/shields/keychron/keychron_b1_us_dbg.conf b/app/boards/shields/keychron/keychron_b1_us_dbg.conf deleted file mode 100644 index 1c25538f3e9..00000000000 --- a/app/boards/shields/keychron/keychron_b1_us_dbg.conf +++ /dev/null @@ -1,25 +0,0 @@ -CONFIG_USB_DEVICE_PRODUCT="Keychron B1 Pro" -CONFIG_BT_DIS_MODEL="Keychron B1 pro" -CONFIG_ZMK_KEYBOARD_NAME="Keychron B1 Pro" - -CONFIG_USB_DEVICE_VID=0x3434 -CONFIG_USB_DEVICE_PID=0x0711 -CONFIG_BT_DIS_PNP_VID=0x3434 -CONFIG_BT_DIS_PNP_PID=0x0711 -CONFIG_BT_DIS_FW_REV_STR="v1.0.1" -CONFIG_BT_DIS_HW_REV_STR="v1.0.0" -CONFIG_BT_DIS_SERIAL_NUMBER_STR="SN2024040814230078" - -#debug -CONFIG_ZMK_UART_LOGGING=y -CONFIG_ZMK_BLE_THREAD_PRIORITY=5 - -#CONFIG_BT_DEBUG_LOG=y -#CONFIG_BT_DEBUG_GATT=y -CONFIG_BT_CONN_TX_MAX=8 - - -#usb debug -CONFIG_ZMK_UART_LOGGING=n -CONFIG_ZMK_USB_LOGGING=y -CONFIG_USB_CDC_ACM_RINGBUF_SIZE=8192 \ No newline at end of file diff --git a/app/boards/shields/keychron/keychron_b1_us_dbg.keymap b/app/boards/shields/keychron/keychron_b1_us_dbg.keymap deleted file mode 100644 index b692ba6dc7d..00000000000 --- a/app/boards/shields/keychron/keychron_b1_us_dbg.keymap +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (c) 2023 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#include -#include -#include -#include -#include - -/ { - ZMK_MACRO(recover, bindings = <&out OUT_RECOVER>;) - ZMK_MACRO(change, bindings = <&out OUT_FN>;) - ZMK_MACRO(fn_win, bindings = <&out OUT_FN_WIN>;) - - ZMK_MACRO(en_bootloader, bindings = <&bootloader>;) - ZMK_MACRO1(MA,bindings=<&kp 0x770000>;) - - long_press_recover:l1 { - compatible = "zmk,behavior-hold-tap"; - label = "l1"; - #binding-cells = <2>; - flavor = "tap-preferred"; - tapping-term-ms = <3000>; // delay amount in ms - bindings = <&recover>, <&none>; - }; - - long_press_change:l2{ - compatible = "zmk,behavior-hold-tap"; - label = "lp_change"; - #binding-cells = <2>; - flavor = "tap-preferred"; - tapping-term-ms = <3000>; // delay amount in ms - bindings = <&change>, <&none>; - }; - long_press_bootloader:l3{ - compatible = "zmk,behavior-hold-tap"; - label = "lp_bootloader"; - #binding-cells = <2>; - flavor = "tap-preferred"; - tapping-term-ms = <3000>; // delay amount in ms - bindings = <&en_bootloader>, <&none>; - }; - long_press_fn_win:l4{ - compatible = "zmk,behavior-hold-tap"; - label = "lp_fn_win"; - #binding-cells = <2>; - flavor = "tap-preferred"; - tapping-term-ms = <3000>; - bindings = <&fn_win>, <&none>; - }; - - - combos1 { - compatible = "zmk,combos"; - combo_jz { - timeout-ms = <1000>; - layers = <1 3>; - key-positions = <49 56>; //fn+j+z - bindings = <&long_press_recover 0 0>; - }; - combo_xl { - timeout-ms = <1000>; - layers =< 1 3>; - key-positions = <57 51>; //fn+x+l - bindings = <&long_press_change 0 0>; - }; - combo_b { - timeout-ms = <1000>; - layers =< 1 3>; - //slow-release = ; - key-positions = <60>; //fn+b - bindings = <&out OUT_BAT>; - }; - - combo_win_l { - timeout-ms = <1000>; - layers =< 1 3>; - //slow-release = ; - key-positions = <68>; //fn+win - bindings = <&long_press_fn_win 0 0>; - }; - - combo_t0 { - timeout-ms = <10 >; - layers =<4>; - - key-positions = <80 90>; - bindings = <&to 3 >; - }; - combo_t1 { - timeout-ms = <10 >; - layers =<4>; - - key-positions = <80 91>; - bindings = <&tog 3 >; - }; - combo_t2 { - timeout-ms = <10 >; - layers =<4>; - - key-positions = <80 92>; - bindings = <&sl 3 >; - }; - combo_t3 { - timeout-ms = <10 >; - layers =<4>; - - key-positions = <70 93>; - bindings = << 3 SPACE>; - }; - combo_t4 { - timeout-ms = <10 >; - layers =<4>; - - key-positions = <81 94>; - bindings = <&sk LSHIFT>; - }; - combo_t5 { - timeout-ms = <10 >; - layers =<4>; - - key-positions = <81 93>; - bindings = <&mt LSHIFT SPACE>; - }; - combo_t6 { - timeout-ms = <10 >; - layers =<4>; - - key-positions = <81 93>; - bindings = <&gresc>; - }; - }; - - td0 { - compatible = "zmk,behavior-tap-dance"; - label = "TAPD_LAYER"; - #binding-cells = <1>; - tapping-term-ms = <350>; - bindings =<&mo 0>,<&mo 0>,<&mo 0>,<&mo 0>,<&to 0>; - }; - ZMK_MACRO(bt_pair0, bindings = <&bt BT_PAIR 0>;) - ZMK_MACRO(bt_pair1, bindings = <&bt BT_PAIR 1>;) - ZMK_MACRO(bt_pair2, bindings = <&bt BT_PAIR 2>;) - ZMK_MACRO(bt_pair3, bindings = <&bt BT_PAIR 3>;) - ZMK_MACRO(bt_recon_0, bindings = <&bt BT_SEL 0>;) - ZMK_MACRO(bt_recon_1, bindings = <&bt BT_SEL 1>;) - ZMK_MACRO(bt_recon_2, bindings = <&bt BT_SEL 2>;) - ZMK_MACRO(bt_recon_3, bindings = <&bt BT_SEL 3>;) - - - - bt_pair_0: bt_pair_0 { - compatible = "zmk,behavior-hold-tap"; - label = "bt_pair0"; - #binding-cells = <2>; - flavor = "tap-preferred"; - tapping-term-ms = <3000>; // delay amount in ms - bindings = <&bt_pair0>, <&bt_recon_0>; - }; - bt_pair_1: bt_pair_1 { - compatible = "zmk,behavior-hold-tap"; - label = "bt_pair1"; - #binding-cells = <2>; - flavor = "tap-preferred"; - tapping-term-ms = <3000>; // delay amount in ms - bindings = <&bt_pair1>, <&bt_recon_1>; - }; - bt_pair_2: bt_pair_2 { - compatible = "zmk,behavior-hold-tap"; - label = "bt_pair2"; - #binding-cells = <2>; - flavor = "tap-preferred"; - tapping-term-ms = <3000>; // delay amount in ms - bindings = <&bt_pair2>, <&bt_recon_2>; - }; - bt_pair_3: bt_pair_3 { - compatible = "zmk,behavior-hold-tap"; - label = "bt_pair3"; - #binding-cells = <2>; - flavor = "tap-preferred"; - tapping-term-ms = <3000>; // delay amount in ms - bindings = <&bt_pair3>, <&bt_recon_3>; - }; - uc:user_custom { - compatible = "zmk,behavior-key-press"; - label ="user_custom"; - #binding-cells =<1>; - }; - - keymap { - compatible = "zmk,keymap"; - //mac - default_layer { - bindings = < - //ESC //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //DEL - &kp ESC &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &kp C_AC_DESKTOP_SHOW_ALL_WINDOWS &kp C_AC_MAC_LAUNCH &kp C_AC_SEARCH &kp C_AL_LOCK &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &kp DEL - &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC - &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH - &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET - &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT - &kp LCTRL &uc LALT &uc LCMD &kp SPACE &uc RCMD &mo 1 &kp LEFT &kp UP &kp DOWN &kp RIGHT - &mo 2 &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD - >; - }; - //mac - layer_one { - bindings = < - &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans - &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AC_SEARCH &trans - &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &uc LG(LS(N4)) - &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans - &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LC(LG(SPACE)) - &trans &trans &trans &trans &kp RCTRL &trans &kp HOME &kp PG_UP &kp PG_DN &kp END - // - &none &none &none &none &none - >; - }; - //win - layer_two { - bindings = < - &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp DEL - &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC - &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH - &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET - &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT - &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 3 &kp LEFT &kp UP &kp DOWN &kp RIGHT - // - &none &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD - >; - }; - //win - layer_three { - bindings = < - //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 - &trans &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &uc LG(TAB) &uc LG(E) &kp C_AC_SEARCH &uc LG(L) &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &trans - &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &long_press_bootloader 0 0 &kp C_AL_CALC &trans - &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &uc LG(LS(S)) - &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans - &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LG(DOT) - &trans &trans &trans &trans &kp RCTRL &trans &kp HOME &kp PG_UP &kp PG_DN &kp END - // - &none &none &none &none &none - >; - }; - - - - - }; -}; - - diff --git a/app/boards/shields/keychron/keychron_b1_us_dbg.overlay b/app/boards/shields/keychron/keychron_b1_us_dbg.overlay deleted file mode 100644 index 0241cc2be2f..00000000000 --- a/app/boards/shields/keychron/keychron_b1_us_dbg.overlay +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2021 Nick Winans - * - * SPDX-License-Identifier: MIT - */ - - -#include - - -/ { - // add for usb debug - chosen { - zephyr,console = &cdc_acm_uart; - }; - - default_transform: keymap_transform_0 { - compatible = "zmk,matrix-transform"; - columns = <18>; - rows = <8>; - map = < - //esc //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 //del - RC(3,1) RC(6,2) RC(6,3) RC(1,3) RC(3,3) RC(7,0) RC(3,6) RC(1,7) RC(6,7) RC(6,10) RC(7,10) RC(3,10) RC(5,10) RC(6,11) - //grave //1 //2 //3 //4 //5 //6 //7 //8 //9 //0 //- //+= //back - RC(6,1) RC(7,1) RC(7,2) RC(7,3) RC(7,4) RC(6,4) RC(6,5) RC(7,5) RC(7,6) RC(7,7) RC(7,8) RC(6,8) RC(6,6) RC(1,10) - //tab //q //w //e //r // t //y //u //i //o //p //[ //] //'\' - RC(1,1) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(1,4) RC(1,5) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(1,8) RC(1,6) RC(2,10) - //cap //a //s //d //f //g //h //j //k //l // ; //' " //enter - RC(1,2) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(3,8) RC(4,10) - //lshit //z //x //c //v //b //n //m //,< //.> //?/ //rshit - RC(1,15) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(5,4) RC(5,5) RC(4,5) RC(4,6) RC(4,7) RC(5,8) RC(2,15) - //lctrl //win l //alt l //space //alt r //fn //left //up //down //right - RC(6,0) RC(1,16) RC(3,9) RC(3,11) RC(5,9) RC(2,9) RC(5,14) RC(3,14) RC(5,11) RC(5,12) - //m/w //bt //24g //ch //ch done - RC(8,0) RC(8,1) RC(8,2) RC(8,3) RC(8,4) - >; - }; - -}; -&uart0{ - status="okay"; -}; - -&kscan0{ - - debounce-scan-period-ms =<4>; - debounce-press-ms =<8>; - debounce-release-ms=<8>; -}; -// add for usb debug -&usbd { - status = "okay"; - cdc_acm_uart: cdc_acm_uart { - compatible = "zephyr,cdc-acm-uart"; - }; -}; diff --git a/app/boards/shields/keychron/keychron_rgb.conf b/app/boards/shields/keychron/keychron_rgb.conf deleted file mode 100644 index e0a71176ce7..00000000000 --- a/app/boards/shields/keychron/keychron_rgb.conf +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2022 The ZMK Contributors -# SPDX-License-Identifier: MIT - -# Uncomment to enable Encoders -CONFIG_EC11=y -CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y -#CONFIG_NEWLIB_LIBC=y -CONFIG_MINIMAL_LIBC_RAND=y -CONFIG_I2C=y -CONFIG_LED_STRIP=y -CONFIG_CKLED2001=y - -#log -CONFIG_ZMK_RTT_LOGGING=y -#CONFIG_ZMK_USB_LOGGING=y -CONFIG_GPIO_AS_PINRESET=y - -#CONFIG_USB_DEVICE_SOF=n -#CONFIG_ZMK_LOW_PRIORITY_THREAD_STACK_SIZE=1024 - diff --git a/app/boards/shields/keychron/keychron_rgb.keymap b/app/boards/shields/keychron/keychron_rgb.keymap deleted file mode 100644 index 24651b68e0d..00000000000 --- a/app/boards/shields/keychron/keychron_rgb.keymap +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2020 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#include -#include -#include -#include -#include -/ { - keymap { - compatible = "zmk,keymap"; - default_layer { - bindings = < - &kp K_MUTE &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 - &kp PG_UP &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 - &kp PG_DN &kp TAB &kp Q &kp W &kp E &kp R &kp T &none - &kp HOME &kp CLCK &kp A &kp S &kp D &kp F &kp G &none - &kp END &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &none - &kp INS &kp LCTRL &kp LALT &kp LGUI &mo 1 &kp SPACE &none &none - >; - sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; - }; - one { - bindings = < - &rgb_ug RGB_TOG &rgb_ug RGB_HUI &rgb_ug RGB_HUD &trans &trans &trans &trans &trans - &rgb_ug RGB_EFF &rgb_ug RGB_BRI &rgb_ug RGB_SPI &trans &trans &trans &trans &trans - &rgb_ug RGB_EFR &rgb_ug RGB_BRD &rgb_ug RGB_SPD &trans &trans &trans &trans &none - &rgb_ug RGB_BRD &trans &trans &trans &trans &trans &trans &none - &bootloader &trans &trans &trans &trans &trans &trans &none - &out OUT_BLE &trans &trans &trans &trans &trans &none &none - >; - }; - two { - bindings = < - &kp K_MUTE &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 - &kp PG_UP &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 - &kp PG_DN &kp TAB &kp Q &kp W &kp E &kp R &kp T - &kp HOME &kp CLCK &kp A &kp S &kp D &kp F &kp G - &kp END &kp LSHFT &kp Z &kp X &kp C &kp V &kp B - &kp INS &kp LCTRL &kp LALT &kp LGUI &mo 1 &kp SPACE - >; - }; - three { - bindings = < - &trans &trans &trans &trans &trans &trans &trans &trans - &trans &trans &trans &trans &trans &trans &trans &trans - &trans &trans &trans &trans &trans &trans &trans - &trans &trans &trans &trans &trans &trans &trans - &trans &trans &trans &trans &trans &trans &trans - &trans &trans &trans &trans &trans &trans - >; - }; - - }; -}; - diff --git a/app/boards/shields/keychron/keychron_rgb.overlay b/app/boards/shields/keychron/keychron_rgb.overlay deleted file mode 100644 index 5af9691976f..00000000000 --- a/app/boards/shields/keychron/keychron_rgb.overlay +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2020 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -/ { - chosen { - zmk,underglow = &led_strip_0; - zmk,kscan = &kscan0; - //zephyr,console =&cdc_acm_uart; - }; - left_encoder: encoder_left { - compatible = "alps,ec11"; - status = "okay"; - label = "Encoder left"; - a-gpios = <&gpio0 13 (GPIO_ACTIVE_HIGH )>; - b-gpios = <&gpio0 15 (GPIO_ACTIVE_HIGH )>; - steps = <80>; - }; - sensors: sensors { - compatible = "zmk,keymap-sensors"; - sensors = <&left_encoder>; - triggers-per-rotation = <20>; - }; -}; - -&kscan0 { - - row-gpios - = <&gpio0 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r0 - , <&gpio0 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r1 - , <&gpio0 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r2 - , <&gpio1 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r3 - , <&gpio0 12 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r4 - , <&gpio0 29 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> //r5 - ; - col-gpios - = <&gpio0 10 (GPIO_ACTIVE_HIGH )> //c0 - , <&gpio0 9 (GPIO_ACTIVE_HIGH)> //c1 - , <&gpio1 6 (GPIO_ACTIVE_HIGH)> //c2 - , <&gpio1 4 (GPIO_ACTIVE_HIGH)> //c3 - , <&gpio1 2 (GPIO_ACTIVE_HIGH)> //c4 - , <&gpio1 1 (GPIO_ACTIVE_HIGH)> //c5 - , <&gpio1 0 (GPIO_ACTIVE_HIGH)> //c6 - , <&gpio0 24 (GPIO_ACTIVE_HIGH)> //c7 - ; -}; -&kscan1 { - - input-gpios - = <&gpio0 19 GPIO_ACTIVE_LOW> //mac/win - , <&gpio0 25 (GPIO_ACTIVE_LOW|GPIO_PULL_UP)> //bt - , <&gpio0 23 (GPIO_ACTIVE_LOW|GPIO_PULL_UP)> //24g - , <&gpio0 21 GPIO_ACTIVE_LOW> //charging - , <&gpio0 22 GPIO_ACTIVE_LOW> //charge done - ; -}; -//&default_transform { -// columns = <8>; -// rows = <6>; -// map =< -// RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) -// RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) -// RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) -// RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) -// RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) -// RC(5,0) RC(5,1) RC(5,2) RC(5,3) RC(5,4) RC(5,5) -// >; - -//}; - -&i2c0 { - status = "okay"; - zephyr,concat-buf-size = <200>; -}; - -&led_strip_0 { - chain-length = <42>; - map = < - /* R G B */ - //row0 - CK(0, 13) CK(1, 13) CK(2, 13) - CK(3, 13) CK(4, 13) CK(5, 13) - CK(6, 13) CK(7, 13) CK(8, 13) - CK(9, 13) CK(10,13) CK(11,13) - CK(0, 7) CK(1, 7) CK(2, 7) - CK(3, 7) CK(4, 7) CK(5, 7) - CK(6, 7) CK(7, 7) CK(8, 7) - - //row1 - CK(0, 1) CK(1, 1) CK(2, 1) - CK(0, 12) CK(1, 12) CK(2, 12) - CK(3, 12) CK(4, 12) CK(5, 12) - CK(6, 12) CK(7, 12) CK(8, 12) - CK(9, 12) CK(10,12) CK(11,12) - CK(0, 6) CK(1, 6) CK(2, 6) - CK(3, 6) CK(4, 6) CK(5, 6) - CK(6, 6) CK(7, 6) CK(8, 6) - - //row2 - CK(3, 1) CK(4, 1) CK(5, 1) - CK(0, 11) CK(1, 11) CK(2, 11) - CK(3, 11) CK(4, 11) CK(5, 11) - CK(6, 11) CK(7, 11) CK(8, 11) - CK(9, 11) CK(10,11) CK(11,11) - CK(0, 5) CK(1, 5) CK(2, 5) - CK(3, 5) CK(4, 5) CK(5, 5) - - //row3 - CK(6, 1) CK(7, 1) CK(8, 1) - CK(0, 10) CK(1, 10) CK(2, 10) - CK(3, 10) CK(4, 10) CK(5, 10) - CK(6, 10) CK(7, 10) CK(8, 10) - CK(9, 10) CK(10,10) CK(11,10) - CK(0, 4) CK(1, 4) CK(2, 4) - CK(3, 4) CK(4, 4) CK(5, 4) - - //row4 - CK(9, 1) CK(10, 1) CK(11, 1) - CK(0, 9) CK(1, 9) CK(2, 9) - CK(3, 9) CK(4, 9) CK(5, 9) - CK(6, 9) CK(7, 9) CK(8, 9) - CK(9, 9) CK(10, 9) CK(11, 9) - CK(0, 3) CK(1, 3) CK(2, 3) - CK(3, 3) CK(4, 3) CK(5, 3) - - //row5 - CK(0, 0) CK(1, 0) CK(2, 0) - CK(0, 8) CK(1, 8) CK(2, 8) - CK(3, 8) CK(4, 8) CK(5, 8) - CK(6, 8) CK(7, 8) CK(8, 8) - CK(9, 8) CK(10, 8) CK(11, 8) - CK(0, 2) CK(1, 2) CK(2, 2) - - >; - - current_tune = - <0x60 0xC4 0xC4 0x60 0xC4 0xC4 0x60 0xC4 0xC4 0x60 0xC4 0xC4>; -}; -//&usbd { -// cdc_acm_uart: cdc_acm_uart { -// compatible = "zephyr,cdc-acm-uart"; -// label = "CDC_ACM_0"; -// }; -//}; -&vbatt { - io-channels = <&adc 0>; -}; - -&led_blue { - blue_led { - gpios = <&gpio0 7 GPIO_ACTIVE_LOW>; - - }; -}; - -&led_numlock { - numlock_led { - gpios = <&gpio0 3 GPIO_ACTIVE_LOW>; - - }; - -}; - -&led_CAPS { - caps_led { - gpios = <&gpio0 4 GPIO_ACTIVE_LOW>; - - }; -}; - -&led_24G { - led_24g { - gpios = <&gpio0 11 GPIO_ACTIVE_LOW>; - - }; -}; - -&led_rgb { - - - myled_r: led_r { - gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; - - }; - myled_g: led_g { - gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; - - }; - myled_b: led_b { - gpios = <&gpio0 30 GPIO_ACTIVE_LOW>; - - }; -}; \ No newline at end of file From f44436b31033c81df6ab07e37178e6678d5aeace Mon Sep 17 00:00:00 2001 From: william <43848894@qq.com> Date: Sat, 8 Feb 2025 16:48:30 +0800 Subject: [PATCH 6/7] change README.md --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 46d15ad3078..a3784efe8fa 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ To review features, check out the [feature overview](https://zmk.dev/docs/). ZMK [Keychron](https://keychron.com/) use zmk source code for Bpro series keyboards ,have made big changes fro Bpro, also add proprietary 2.4g communication. To build the firmware ,for example: keychorn b1 pro + +prepare: ``` mkdir keychron cd keychron @@ -22,6 +24,14 @@ To build the firmware ,for example: keychorn b1 pro cd zmk west init -l app/ west update - git am 001-esb-nrf-fix.patch +``` +patch zephyr: +``` + cd zephyr + git am ../001-esb-nrf-fix.patch +``` +build firmware: +``` + cd app west build -b keychron -p -- -DSHIELD=keychron_b1_us ``` \ No newline at end of file From 8f3a30218fc5ae5a70ac1b7526533f3f8af3e13d Mon Sep 17 00:00:00 2001 From: taki Date: Sat, 11 Jul 2026 00:01:24 +0900 Subject: [PATCH 7/7] test --- .../keychron/b1/us/keychron_b1_us.keymap | 146 +++++++++++++++++- 1 file changed, 138 insertions(+), 8 deletions(-) diff --git a/app/boards/shields/keychron/b1/us/keychron_b1_us.keymap b/app/boards/shields/keychron/b1/us/keychron_b1_us.keymap index 9714174cde3..29506472a44 100644 --- a/app/boards/shields/keychron/b1/us/keychron_b1_us.keymap +++ b/app/boards/shields/keychron/b1/us/keychron_b1_us.keymap @@ -190,6 +190,136 @@ #binding-cells =<1>; }; + //--------USキーボードの記号を日本語OSで表示通りに入力するための処理----------------------------- + //`~マーク + jis_GRAVE: jis_GRAVE { + compatible = "zmk,behavior-mod-morph"; + label = "jis_GRAVE"; + #binding-cells = <0>; + bindings = <&kp LS(LBKT)>, <&kp EQUAL>; //通常時でもレフトシフトするようにしてある。 + mods = <(MOD_LSFT|MOD_RSFT)>; + keep-mods = <(MOD_LSFT|MOD_RSFT)>; //shiftを押しっぱなしにするための記述 + }; + + + //@マーク + jis_N2: jis_N2 { + compatible = "zmk,behavior-mod-morph"; + label = "jis_N2"; + #binding-cells = <0>; + bindings = <&kp N2>, <&kp LBKT>; + mods = <(MOD_LSFT|MOD_RSFT)>; + //keep-mods = <(MOD_LSFT|MOD_RSFT)>; + }; + //^マーク + jis_N6: jis_N6 { + compatible = "zmk,behavior-mod-morph"; + label = "jis_N6"; + #binding-cells = <0>; + bindings = <&kp N6>, <&kp EQUAL>; + mods = <(MOD_LSFT|MOD_RSFT)>; + //keep-mods = <(MOD_LSFT|MOD_RSFT)>; + //&マーク + }; + jis_N7: jis_N7 { + compatible = "zmk,behavior-mod-morph"; + label = "jis_N7"; + #binding-cells = <0>; + bindings = <&kp N7>, <&kp N6>; + mods = <(MOD_LSFT|MOD_RSFT)>; + keep-mods = <(MOD_LSFT|MOD_RSFT)>; + }; + //アスタリスクマーク + jis_N8: jis_N8 { + compatible = "zmk,behavior-mod-morph"; + label = "jis_N8"; + #binding-cells = <0>; + bindings = <&kp N8>, <&kp SQT>; + mods = <(MOD_LSFT|MOD_RSFT)>; + keep-mods = <(MOD_LSFT|MOD_RSFT)>; + }; + // (マーク + jis_N9: jis_N9 { + compatible = "zmk,behavior-mod-morph"; + label = "jis_N9"; + #binding-cells = <0>; + bindings = <&kp N9>, <&kp N8>; + mods = <(MOD_LSFT|MOD_RSFT)>; + keep-mods = <(MOD_LSFT|MOD_RSFT)>; + }; + // )マーク + jis_N0: jis_N0 { + compatible = "zmk,behavior-mod-morph"; + label = "jis_N0"; + #binding-cells = <0>; + bindings = <&kp N0>, <&kp N9>; + mods = <(MOD_LSFT|MOD_RSFT)>; + keep-mods = <(MOD_LSFT|MOD_RSFT)>; + }; + //アンダーバー + jis_MINUS: jis_MINUS { + compatible = "zmk,behavior-mod-morph"; + label = "jis_MINUS"; + #binding-cells = <0>; + bindings = <&kp MINUS>, <&kp INT1>; + mods = <(MOD_LSFT|MOD_RSFT)>; + keep-mods = <(MOD_LSFT|MOD_RSFT)>; + }; + //イコールとプラス + jis_EQUAL: jis_EQUAL { + compatible = "zmk,behavior-mod-morph"; + label = "jis_EQUAL"; + #binding-cells = <0>; + bindings = <&kp LS(MINUS)>, <&kp SEMI>; + mods = <(MOD_LSFT|MOD_RSFT)>; + keep-mods = <(MOD_LSFT|MOD_RSFT)>; + }; + // [マーク + jis_LBKT: jis_LBKT { + compatible = "zmk,behavior-mod-morph"; + label = "jis_LBKT"; + #binding-cells = <0>; + bindings = <&kp RBKT>, <&kp RBKT>; + mods = <(MOD_LSFT|MOD_RSFT)>; + keep-mods = <(MOD_LSFT|MOD_RSFT)>; + }; + // ]マーク + jis_RBKT: jis_RBKT { + compatible = "zmk,behavior-mod-morph"; + label = "jis_RBKT"; + #binding-cells = <0>; + bindings = <&kp BSLH>, <&kp BSLH>; + mods = <(MOD_LSFT|MOD_RSFT)>; + keep-mods = <(MOD_LSFT|MOD_RSFT)>; + }; + // yenマーク + jis_BSLH: jis_BSLH { + compatible = "zmk,behavior-mod-morph"; + label = "jis_BSLH"; + #binding-cells = <0>; + bindings = <&kp INT3>, <&kp INT3>; //INT3ではないかも + mods = <(MOD_LSFT|MOD_RSFT)>; + keep-mods = <(MOD_LSFT|MOD_RSFT)>; + }; + //コロンセミコロン + jis_SEMI: jis_SEMI { + compatible = "zmk,behavior-mod-morph"; + label = "jis_SEMI"; + #binding-cells = <0>; + bindings = <&kp SEMI>, <&kp SQT>; + mods = <(MOD_LSFT|MOD_RSFT)>; + //keep-mods = <(MOD_LSFT|MOD_RSFT)>; + }; + //クオーテーション + jis_SQT: jis_SQT { + compatible = "zmk,behavior-mod-morph"; + label = "jis_SQT"; + #binding-cells = <0>; + bindings = <&kp LS(N7)>, <&kp N2>; + mods = <(MOD_LSFT|MOD_RSFT)>; + keep-mods = <(MOD_LSFT|MOD_RSFT)>; + }; + keymap { compatible = "zmk,keymap"; //mac @@ -219,25 +349,27 @@ >; }; //win + //レイヤー2のリマップが必要な箇所を修正してある layer_two { bindings = < &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp DEL - &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC - &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH - &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET - &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &jis_GRAVE &kp N1 &jis_N2 &kp N3 &kp N4 &kp N5 &jis_N6 &jis_N7 &jis_N8 &jis_N9 &jis_N0 &jis_MINUS &jis_EQUAL &kp BSPC + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &jis_LBKT &jis_RBKT &jis_BSLH + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &jis_SEMI &jis_SQT &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &mo 3 &kp LEFT &kp UP &kp DOWN &kp RIGHT // &none &out OUT_BLE &out OUT_24G &out OUT_CHG &out OUT_CHGD >; }; //win + //ハイフンキーにbootloaderを入れてある。 layer_three { bindings = < //f1 //f2 //f3 //f4 //f5 //f6 //f7 //f8 //f9 //f10 //f11 //f12 &trans &kp C_BRIGHTNESS_DEC &kp C_BRIGHTNESS_INC &uc LG(TAB) &uc LG(E) &kp C_AC_SEARCH &uc LG(L) &kp C_PREVIOUS &kp C_PLAY_PAUSE &kp C_NEXT &kp C_MUTE &kp C_VOLUME_DOWN &kp C_VOLUME_UP &trans - &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &trans &kp C_AL_CALC &trans - &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &uc LG(LS(S)) + &trans &bt_pair_0 0 0 &bt_pair_1 0 0 &bt_pair_2 0 0 &bt_pair_3 0 0 &trans &trans &trans &trans &trans &trans &bootloader &kp C_AL_CALC &trans //bootloaderを入れる + &trans &trans &trans &trans &trans &trans &trans &trans &kp INS &trans &trans &trans &trans &uc LG(LS(S)) &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &uc LG(DOT) &trans &trans &trans &trans &kp RCTRL &trans &kp HOME &kp PG_UP &kp PG_DN &kp END @@ -251,5 +383,3 @@ }; }; - -