Initial: modular per-key RGB layer effect for ZMK
ZMK module providing per-key per-layer RGB effects via the modular effect API (zmk_rgb_effect). Extracted from darknao's fork patches. Contents: - Layer effect: registers via ZMK_RGB_EFFECT_DEFINE, renders per-key colors based on active keymap layer - Behaviors: underglow_color, underglow_battery, underglow_indicators - DTS bindings: zmk,underglow-layer + behavior bindings - Event: underglow_color_changed for reactive refresh Requires: ZMK core with rgb-modular branch (effect registration API)
This commit is contained in:
commit
569dc85e0c
15 changed files with 557 additions and 0 deletions
9
CMakeLists.txt
Normal file
9
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
if(CONFIG_ZMK_RGB_EFFECT_LAYER)
|
||||
target_sources(app PRIVATE src/rgb_underglow_layer.c)
|
||||
target_sources(app PRIVATE src/effects/layer_effect.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_underglow_color.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_underglow_battery.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_underglow_indicators.c)
|
||||
target_sources(app PRIVATE src/events/underglow_color_changed.c)
|
||||
target_include_directories(app PRIVATE include)
|
||||
endif()
|
||||
7
Kconfig
Normal file
7
Kconfig
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
config ZMK_RGB_EFFECT_LAYER
|
||||
bool "Per-key per-layer RGB effect"
|
||||
depends on ZMK_RGB_UNDERGLOW
|
||||
default n
|
||||
help
|
||||
Enable per-key RGB colors that change based on the active keymap layer.
|
||||
Requires the modular RGB effect API in the ZMK core (rgb-modular branch).
|
||||
12
dts/bindings/behaviors/zmk,behavior-underglow-battery.yaml
Normal file
12
dts/bindings/behaviors/zmk,behavior-underglow-battery.yaml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Copyright (c) 2024, The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Set underglow color based on battery level
|
||||
|
||||
compatible: "zmk,behavior-underglow-battery"
|
||||
|
||||
include: two_param.yaml
|
||||
|
||||
properties:
|
||||
threshold:
|
||||
type: int
|
||||
8
dts/bindings/behaviors/zmk,behavior-underglow-color.yaml
Normal file
8
dts/bindings/behaviors/zmk,behavior-underglow-color.yaml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2024, The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Set underglow to specified color
|
||||
|
||||
compatible: "zmk,behavior-underglow-color"
|
||||
|
||||
include: one_param.yaml
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# Copyright (c) 2024, The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Set underglow for num lock indicator
|
||||
|
||||
compatible: "zmk,behavior-underglow-indicators"
|
||||
|
||||
include: two_param.yaml
|
||||
|
||||
properties:
|
||||
indicator:
|
||||
type: int
|
||||
default: 0
|
||||
24
dts/bindings/zmk,underglow-layer.yaml
Normal file
24
dts/bindings/zmk,underglow-layer.yaml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
description: |
|
||||
Allows defining a rgbmap composed of multiple layers
|
||||
|
||||
compatible: "zmk,underglow-layer"
|
||||
|
||||
properties:
|
||||
pixel-lookup:
|
||||
type: array
|
||||
required: true
|
||||
|
||||
child-binding:
|
||||
description: "A layer to be used in a rgbmap"
|
||||
|
||||
properties:
|
||||
bindings:
|
||||
type: phandle-array
|
||||
required: true
|
||||
layer-id:
|
||||
type: int
|
||||
required: true
|
||||
fade-delay:
|
||||
type: int
|
||||
required: false
|
||||
default: -1
|
||||
16
include/zmk/events/underglow_color_changed.h
Normal file
16
include/zmk/events/underglow_color_changed.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright (c) 2024 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <zmk/event_manager.h>
|
||||
|
||||
struct zmk_underglow_color_changed {
|
||||
uint32_t layers;
|
||||
bool wakeup;
|
||||
};
|
||||
|
||||
ZMK_EVENT_DECLARE(zmk_underglow_color_changed);
|
||||
31
include/zmk/rgb_underglow_layer.h
Normal file
31
include/zmk/rgb_underglow_layer.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <zmk/keymap.h>
|
||||
|
||||
#define ZMK_RGB_CHILD_LEN_PLUS_ONE(node) 1 +
|
||||
|
||||
#define ZMK_RGBMAP_LAYERS_LEN \
|
||||
(DT_FOREACH_CHILD(DT_INST(0, zmk_underglow_layer), ZMK_RGB_CHILD_LEN_PLUS_ONE) 0)
|
||||
|
||||
#define ZMK_RGBMAP_EXTRACT_BINDING(idx, drv_inst) \
|
||||
{ \
|
||||
.behavior_dev = DEVICE_DT_NAME(DT_PHANDLE_BY_IDX(drv_inst, bindings, idx)), \
|
||||
.param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(drv_inst, bindings, idx, param1), (0), \
|
||||
(DT_PHA_BY_IDX(drv_inst, bindings, idx, param1))), \
|
||||
.param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(drv_inst, bindings, idx, param2), (0), \
|
||||
(DT_PHA_BY_IDX(drv_inst, bindings, idx, param2))), \
|
||||
}
|
||||
|
||||
const int rgb_pixel_lookup(int idx);
|
||||
const int zmk_rgbmap_id(uint8_t layer);
|
||||
const int zmk_rgbmap_fade_delay(uint8_t layer);
|
||||
|
||||
const struct zmk_behavior_binding *rgb_underglow_get_bindings(uint8_t layer);
|
||||
|
||||
uint8_t rgb_underglow_top_layer_with_state(uint32_t state_to_test);
|
||||
uint8_t rgb_underglow_top_layer(void);
|
||||
76
src/behaviors/behavior_underglow_battery.c
Normal file
76
src/behaviors/behavior_underglow_battery.c
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2024 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_underglow_battery
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zmk/battery.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/battery_state_changed.h>
|
||||
#include <zmk/events/underglow_color_changed.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
struct underglow_battery_data {
|
||||
uint32_t layers;
|
||||
};
|
||||
|
||||
struct underglow_battery_config {
|
||||
int threshold;
|
||||
};
|
||||
|
||||
static struct underglow_battery_data underglow_battery_data = {.layers = 0};
|
||||
|
||||
static int underglow_battery_init(const struct device *dev) { return 0; };
|
||||
|
||||
static int underglow_battery_process(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
|
||||
const struct underglow_battery_config *config = dev->config;
|
||||
struct underglow_battery_data *data = dev->data;
|
||||
data->layers |= BIT(event.layer);
|
||||
int bat = zmk_battery_state_of_charge();
|
||||
|
||||
if (bat >= config->threshold)
|
||||
return binding->param2;
|
||||
else
|
||||
return binding->param1;
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api underglow_battery_driver_api = {
|
||||
.binding_pressed = underglow_battery_process,
|
||||
.locality = BEHAVIOR_LOCALITY_GLOBAL,
|
||||
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||
.get_parameter_metadata = zmk_behavior_get_empty_param_metadata,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int underglow_battery_listener(const zmk_event_t *eh);
|
||||
|
||||
ZMK_LISTENER(behavior_underglow_battery, underglow_battery_listener);
|
||||
ZMK_SUBSCRIPTION(behavior_underglow_battery, zmk_battery_state_changed);
|
||||
|
||||
static int underglow_battery_listener(const zmk_event_t *eh) {
|
||||
raise_zmk_underglow_color_changed((struct zmk_underglow_color_changed){
|
||||
.layers = underglow_battery_data.layers, .wakeup = false});
|
||||
|
||||
return ZMK_EV_EVENT_BUBBLE;
|
||||
}
|
||||
|
||||
#define KP_INST(n) \
|
||||
static struct underglow_battery_config underglow_battery_config_##n = { \
|
||||
.threshold = DT_INST_PROP(n, threshold)}; \
|
||||
BEHAVIOR_DT_INST_DEFINE(n, underglow_battery_init, NULL, &underglow_battery_data, \
|
||||
&underglow_battery_config_##n, POST_KERNEL, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &underglow_battery_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(KP_INST)
|
||||
|
||||
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
||||
35
src/behaviors/behavior_underglow_color.c
Normal file
35
src/behaviors/behavior_underglow_color.c
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2024 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_underglow_color
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
static int underglow_color_init(const struct device *dev) { return 0; };
|
||||
|
||||
static int underglow_color_process(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
return binding->param1;
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api underglow_color_driver_api = {
|
||||
.binding_pressed = underglow_color_process,
|
||||
.locality = BEHAVIOR_LOCALITY_GLOBAL,
|
||||
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||
.get_parameter_metadata = zmk_behavior_get_empty_param_metadata,
|
||||
#endif
|
||||
};
|
||||
|
||||
BEHAVIOR_DT_INST_DEFINE(0, underglow_color_init, NULL, NULL, NULL, POST_KERNEL,
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &underglow_color_driver_api);
|
||||
|
||||
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
||||
79
src/behaviors/behavior_underglow_indicators.c
Normal file
79
src/behaviors/behavior_underglow_indicators.c
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2024 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_underglow_indicators
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zmk/hid_indicators.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/hid_indicators_changed.h>
|
||||
#include <zmk/events/underglow_color_changed.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
struct underglow_indicators_data {
|
||||
zmk_hid_indicators_t indicators;
|
||||
uint32_t layers;
|
||||
};
|
||||
|
||||
struct underglow_indicators_config {
|
||||
int indicator;
|
||||
};
|
||||
|
||||
static int underglow_indicators_init(const struct device *dev) { return 0; };
|
||||
|
||||
static int underglow_indicators_process(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
|
||||
struct underglow_indicators_data *data = dev->data;
|
||||
const struct underglow_indicators_config *config = dev->config;
|
||||
data->layers |= BIT(event.layer);
|
||||
|
||||
if (data->indicators & BIT(config->indicator))
|
||||
return binding->param2;
|
||||
else
|
||||
return binding->param1;
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api underglow_indicators_driver_api = {
|
||||
.binding_pressed = underglow_indicators_process,
|
||||
.locality = BEHAVIOR_LOCALITY_GLOBAL,
|
||||
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||
.get_parameter_metadata = zmk_behavior_get_empty_param_metadata,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int underglow_indicators_listener(const zmk_event_t *eh);
|
||||
|
||||
ZMK_LISTENER(behavior_underglow_indicators, underglow_indicators_listener);
|
||||
ZMK_SUBSCRIPTION(behavior_underglow_indicators, zmk_hid_indicators_changed);
|
||||
|
||||
static struct underglow_indicators_data underglow_indicators_data = {.indicators = 0, .layers = 0};
|
||||
|
||||
static int underglow_indicators_listener(const zmk_event_t *eh) {
|
||||
const struct zmk_hid_indicators_changed *ev = as_zmk_hid_indicators_changed(eh);
|
||||
underglow_indicators_data.indicators = ev->indicators;
|
||||
raise_zmk_underglow_color_changed((struct zmk_underglow_color_changed){
|
||||
.layers = underglow_indicators_data.layers, .wakeup = true});
|
||||
|
||||
return ZMK_EV_EVENT_BUBBLE;
|
||||
}
|
||||
|
||||
#define KP_INST(n) \
|
||||
static struct underglow_indicators_config underglow_indicators_config_##n = { \
|
||||
.indicator = DT_INST_PROP(n, indicator)}; \
|
||||
BEHAVIOR_DT_INST_DEFINE(n, underglow_indicators_init, NULL, &underglow_indicators_data, \
|
||||
&underglow_indicators_config_##n, POST_KERNEL, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
||||
&underglow_indicators_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(KP_INST)
|
||||
|
||||
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
||||
149
src/effects/layer_effect.c
Normal file
149
src/effects/layer_effect.c
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* Copyright (c) 2024 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include <drivers/behavior.h>
|
||||
|
||||
#include <zmk/rgb_underglow.h>
|
||||
#include <zmk/rgb_effect.h>
|
||||
#include <zmk/rgb_underglow_layer.h>
|
||||
#include <zmk/matrix.h>
|
||||
#include <zmk/keymap.h>
|
||||
#include <zmk/behavior.h>
|
||||
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/underglow_color_changed.h>
|
||||
#include <zmk/workqueue.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
#include <zmk/events/split_peripheral_layer_changed.h>
|
||||
#endif
|
||||
|
||||
#if !IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
#include <zmk/split/bluetooth/peripheral_layers.h>
|
||||
#endif
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#define DT_DRV_COMPAT zmk_underglow_layer
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
static bool layer_effect_active = false;
|
||||
|
||||
static struct led_rgb hex_to_rgb_scaled(uint8_t r, uint8_t g, uint8_t b, uint8_t brightness) {
|
||||
return (struct led_rgb){
|
||||
r : (brightness * r) / 0xff,
|
||||
g : (brightness * g) / 0xff,
|
||||
b : (brightness * b) / 0xff
|
||||
};
|
||||
}
|
||||
|
||||
static int apply_rgbmap(struct led_rgb *pixels, uint16_t num_pixels,
|
||||
const struct zmk_behavior_binding *bindings,
|
||||
size_t rgbmap_len, uint8_t layer, uint8_t brightness) {
|
||||
int rc = 0;
|
||||
for (int i = 0; i < num_pixels; i++) {
|
||||
uint8_t midx = rgb_pixel_lookup(i);
|
||||
if (midx >= ZMK_KEYMAP_LEN) {
|
||||
LOG_DBG("out of range");
|
||||
} else {
|
||||
const struct device *dev = zmk_behavior_get_binding(bindings[midx].behavior_dev);
|
||||
|
||||
if (dev == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api;
|
||||
|
||||
if (api->binding_pressed == NULL) {
|
||||
continue;
|
||||
}
|
||||
struct zmk_behavior_binding_event event = {
|
||||
.position = midx, .layer = layer, .timestamp = k_uptime_get()};
|
||||
|
||||
int color = api->binding_pressed(
|
||||
(struct zmk_behavior_binding *)&bindings[midx], event);
|
||||
|
||||
if (color > 0) {
|
||||
pixels[i] = hex_to_rgb_scaled(
|
||||
(color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF, brightness);
|
||||
rc = 1;
|
||||
} else {
|
||||
pixels[i] = (struct led_rgb){r : 0, g : 0, b : 0};
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void layer_effect_render(struct zmk_rgb_effect_ctx *ctx) {
|
||||
if (!layer_effect_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t layer = rgb_underglow_top_layer();
|
||||
const struct zmk_behavior_binding *rgbmap = rgb_underglow_get_bindings(layer);
|
||||
if (rgbmap != NULL) {
|
||||
apply_rgbmap(ctx->pixels, ctx->num_pixels, rgbmap, ZMK_KEYMAP_LEN,
|
||||
layer, ctx->base_color.b);
|
||||
} else {
|
||||
for (int i = 0; i < ctx->num_pixels; i++) {
|
||||
ctx->pixels[i] = (struct led_rgb){r : 0, g : 0, b : 0};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void layer_effect_on_select(void) {
|
||||
layer_effect_active = true;
|
||||
}
|
||||
|
||||
static void layer_effect_on_deselect(void) {
|
||||
layer_effect_active = false;
|
||||
}
|
||||
|
||||
ZMK_RGB_EFFECT_DEFINE(effect_layer, "Layer Indicators",
|
||||
layer_effect_render, ZMK_RGB_EFFECT_STATIC,
|
||||
layer_effect_on_select, layer_effect_on_deselect);
|
||||
|
||||
/* Event listeners — refresh pixels on layer/color change */
|
||||
|
||||
static int layer_effect_event_listener(const zmk_event_t *eh) {
|
||||
if (!layer_effect_active) {
|
||||
return ZMK_EV_EVENT_BUBBLE;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
if (as_zmk_split_peripheral_layer_changed(eh)) {
|
||||
const struct zmk_split_peripheral_layer_changed *ev =
|
||||
as_zmk_split_peripheral_layer_changed(eh);
|
||||
LOG_DBG("peripheral layer changed: %08x", ev->layers);
|
||||
#if !IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
set_peripheral_layers_state(ev->layers);
|
||||
#endif
|
||||
zmk_rgb_request_refresh();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (as_zmk_underglow_color_changed(eh)) {
|
||||
zmk_rgb_request_refresh();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ZMK_EV_EVENT_BUBBLE;
|
||||
}
|
||||
|
||||
ZMK_LISTENER(layer_effect, layer_effect_event_listener);
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
ZMK_SUBSCRIPTION(layer_effect, zmk_split_peripheral_layer_changed);
|
||||
#endif
|
||||
ZMK_SUBSCRIPTION(layer_effect, zmk_underglow_color_changed);
|
||||
|
||||
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
||||
10
src/events/underglow_color_changed.c
Normal file
10
src/events/underglow_color_changed.c
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zmk/events/underglow_color_changed.h>
|
||||
|
||||
ZMK_EVENT_IMPL(zmk_underglow_color_changed);
|
||||
83
src/rgb_underglow_layer.c
Normal file
83
src/rgb_underglow_layer.c
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#include <zmk/matrix.h>
|
||||
#include <zmk/keymap.h>
|
||||
#include <zmk/rgb_underglow_layer.h>
|
||||
|
||||
#if !IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
#include <zmk/split/bluetooth/peripheral_layers.h>
|
||||
#endif
|
||||
|
||||
#define DT_DRV_COMPAT zmk_underglow_layer
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
#define UNDERGLOW_LAYER_ENABLED
|
||||
#define LAYER_ID(node) DT_PROP(node, layer_id)
|
||||
#define FADE_DELAY(node) DT_PROP(node, fade_delay)
|
||||
|
||||
#define TRANSFORMED_RGB_LAYER(node) \
|
||||
{COND_CODE_1(DT_NODE_HAS_PROP(node, bindings), \
|
||||
(LISTIFY(DT_PROP_LEN(node, bindings), ZMK_RGBMAP_EXTRACT_BINDING, (, ), node)), \
|
||||
())}
|
||||
|
||||
#define RGBMAP_VAR(_name, _opts) \
|
||||
static _opts struct zmk_behavior_binding _name[ZMK_RGBMAP_LAYERS_LEN][ZMK_KEYMAP_LEN] = { \
|
||||
DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(0, TRANSFORMED_RGB_LAYER, (, ))};
|
||||
|
||||
RGBMAP_VAR(zmk_rgbmap, COND_CODE_1(IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE), (), (const)))
|
||||
|
||||
const int pixel_lookup_table[] = DT_INST_PROP(0, pixel_lookup);
|
||||
|
||||
static int zmk_rgbmap_ids[ZMK_RGBMAP_LAYERS_LEN] = {DT_INST_FOREACH_CHILD_SEP(0, LAYER_ID, (, ))};
|
||||
static int zmk_rgbmap_fds[ZMK_RGBMAP_LAYERS_LEN] = {DT_INST_FOREACH_CHILD_SEP(0, FADE_DELAY, (, ))};
|
||||
|
||||
const int rgb_pixel_lookup(int idx) { return pixel_lookup_table[idx]; };
|
||||
|
||||
const int zmk_rgbmap_id(uint8_t layer) {
|
||||
for (uint8_t i = 0; i < ZMK_RGBMAP_LAYERS_LEN; i++) {
|
||||
if (zmk_rgbmap_ids[i] == layer) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int zmk_rgbmap_fade_delay(uint8_t layer) { return zmk_rgbmap_fds[zmk_rgbmap_id(layer)]; }
|
||||
|
||||
const struct zmk_behavior_binding *rgb_underglow_get_bindings(uint8_t layer) {
|
||||
int rgblayer = zmk_rgbmap_id(layer);
|
||||
if (rgblayer == -1) {
|
||||
return NULL;
|
||||
} else {
|
||||
return zmk_rgbmap[rgblayer];
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t rgb_underglow_top_layer_with_state(uint32_t state_to_test) {
|
||||
for (uint8_t layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer > 0; layer--) {
|
||||
if ((state_to_test & (BIT(layer))) == (BIT(layer)) || layer == 0) {
|
||||
return layer;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t rgb_underglow_top_layer(void) {
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
return zmk_keymap_highest_layer_active();
|
||||
#else
|
||||
return peripheral_highest_layer_active();
|
||||
#endif
|
||||
}
|
||||
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
||||
5
zephyr/module.yml
Normal file
5
zephyr/module.yml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
build:
|
||||
cmake: .
|
||||
kconfig: Kconfig
|
||||
settings:
|
||||
dts_root: .
|
||||
Loading…
Add table
Add a link
Reference in a new issue