feat(keymap): Add binding get/set, layer movement
* Add keymap API for getting/setting a bindings in keymap layers. * Add layer move support via intemediary ordering array. * Add settings storage for keymap changes.
This commit is contained in:
parent
0f972f1cc3
commit
c8c19598a7
13 changed files with 1296 additions and 64 deletions
20
app/Kconfig
20
app/Kconfig
|
@ -258,6 +258,26 @@ rsource "src/split/Kconfig"
|
||||||
#Basic Keyboard Setup
|
#Basic Keyboard Setup
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
|
menu "Keymaps"
|
||||||
|
|
||||||
|
config ZMK_KEYMAP_LAYER_REORDERING
|
||||||
|
bool "Layer Reordering Support"
|
||||||
|
|
||||||
|
config ZMK_KEYMAP_SETTINGS_STORAGE
|
||||||
|
bool "Settings Save/Load"
|
||||||
|
depends on SETTINGS
|
||||||
|
depends on ZMK_BEHAVIOR_LOCAL_IDS
|
||||||
|
|
||||||
|
if ZMK_KEYMAP_SETTINGS_STORAGE
|
||||||
|
|
||||||
|
config ZMK_KEYMAP_LAYER_NAME_MAX_LEN
|
||||||
|
int "Max Layer Name Length"
|
||||||
|
default 20
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
endmenu # Keymaps
|
||||||
|
|
||||||
rsource "src/studio/Kconfig"
|
rsource "src/studio/Kconfig"
|
||||||
|
|
||||||
menu "Display/LED Options"
|
menu "Display/LED Options"
|
||||||
|
|
9
app/include/linker/zmk-rpc-subsystem-settings-reset.ld
Normal file
9
app/include/linker/zmk-rpc-subsystem-settings-reset.ld
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/linker/linker-defs.h>
|
||||||
|
|
||||||
|
ITERABLE_SECTION_ROM(zmk_rpc_subsystem_settings_reset, 4)
|
|
@ -12,17 +12,63 @@
|
||||||
#define ZMK_KEYMAP_LAYERS_LEN \
|
#define ZMK_KEYMAP_LAYERS_LEN \
|
||||||
(DT_FOREACH_CHILD(DT_INST(0, zmk_keymap), ZMK_LAYER_CHILD_LEN_PLUS_ONE) 0)
|
(DT_FOREACH_CHILD(DT_INST(0, zmk_keymap), ZMK_LAYER_CHILD_LEN_PLUS_ONE) 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A layer ID is a stable identifier to refer to a layer, regardless of ordering.
|
||||||
|
*/
|
||||||
|
typedef uint8_t zmk_keymap_layer_id_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A way to return/reference a missing or invalid layer ID
|
||||||
|
*/
|
||||||
|
#define ZMK_KEYMAP_LAYER_ID_INVAL UINT8_MAX
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A layer index is a identifier to refer layer at a particular position in the order.
|
||||||
|
*/
|
||||||
|
typedef uint8_t zmk_keymap_layer_index_t;
|
||||||
|
|
||||||
typedef uint32_t zmk_keymap_layers_state_t;
|
typedef uint32_t zmk_keymap_layers_state_t;
|
||||||
|
|
||||||
uint8_t zmk_keymap_layer_default(void);
|
zmk_keymap_layer_id_t zmk_keymap_layer_index_to_id(zmk_keymap_layer_index_t layer_index);
|
||||||
|
|
||||||
|
zmk_keymap_layer_id_t zmk_keymap_layer_default(void);
|
||||||
zmk_keymap_layers_state_t zmk_keymap_layer_state(void);
|
zmk_keymap_layers_state_t zmk_keymap_layer_state(void);
|
||||||
bool zmk_keymap_layer_active(uint8_t layer);
|
bool zmk_keymap_layer_active(zmk_keymap_layer_id_t layer);
|
||||||
uint8_t zmk_keymap_highest_layer_active(void);
|
zmk_keymap_layer_id_t zmk_keymap_highest_layer_active(void);
|
||||||
int zmk_keymap_layer_activate(uint8_t layer);
|
int zmk_keymap_layer_activate(zmk_keymap_layer_id_t layer);
|
||||||
int zmk_keymap_layer_deactivate(uint8_t layer);
|
int zmk_keymap_layer_deactivate(zmk_keymap_layer_id_t layer);
|
||||||
int zmk_keymap_layer_toggle(uint8_t layer);
|
int zmk_keymap_layer_toggle(zmk_keymap_layer_id_t layer);
|
||||||
int zmk_keymap_layer_to(uint8_t layer);
|
int zmk_keymap_layer_to(zmk_keymap_layer_id_t layer);
|
||||||
const char *zmk_keymap_layer_name(uint8_t layer);
|
const char *zmk_keymap_layer_name(zmk_keymap_layer_id_t layer);
|
||||||
|
|
||||||
|
const struct zmk_behavior_binding *zmk_keymap_get_layer_binding_at_idx(zmk_keymap_layer_id_t layer,
|
||||||
|
uint8_t binding_idx);
|
||||||
|
int zmk_keymap_set_layer_binding_at_idx(zmk_keymap_layer_id_t layer, uint8_t binding_idx,
|
||||||
|
const struct zmk_behavior_binding binding);
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
|
||||||
|
int zmk_keymap_add_layer(void);
|
||||||
|
int zmk_keymap_remove_layer(zmk_keymap_layer_index_t index);
|
||||||
|
int zmk_keymap_restore_layer(zmk_keymap_layer_id_t id, zmk_keymap_layer_index_t at_index);
|
||||||
|
|
||||||
|
int zmk_keymap_move_layer(zmk_keymap_layer_index_t start_idx, zmk_keymap_layer_index_t dest_idx);
|
||||||
|
|
||||||
|
int zmk_keymap_set_layer_name(zmk_keymap_layer_id_t id, const char *name, size_t size);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if there are any unsaved keymap changes.
|
||||||
|
*
|
||||||
|
* @retval 0 if there are no changes.
|
||||||
|
* @retval 1 if there are changes.
|
||||||
|
*/
|
||||||
|
int zmk_keymap_check_unsaved_changes(void);
|
||||||
|
|
||||||
|
int zmk_keymap_save_changes(void);
|
||||||
|
int zmk_keymap_discard_changes(void);
|
||||||
|
int zmk_keymap_reset_settings(void);
|
||||||
|
|
||||||
int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pressed,
|
int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pressed,
|
||||||
int64_t timestamp);
|
int64_t timestamp);
|
||||||
|
|
|
@ -40,4 +40,5 @@ int zmk_physical_layouts_check_unsaved_selection(void);
|
||||||
int zmk_physical_layouts_save_selected(void);
|
int zmk_physical_layouts_save_selected(void);
|
||||||
int zmk_physical_layouts_revert_selected(void);
|
int zmk_physical_layouts_revert_selected(void);
|
||||||
|
|
||||||
int zmk_physical_layouts_get_position_map(uint8_t source, uint8_t dest, uint32_t *map);
|
int zmk_physical_layouts_get_position_map(uint8_t source, uint8_t dest, size_t map_size,
|
||||||
|
uint32_t map[map_size]);
|
||||||
|
|
|
@ -56,6 +56,12 @@ struct zmk_rpc_subsystem_handler {
|
||||||
enum zmk_studio_rpc_handler_security security;
|
enum zmk_studio_rpc_handler_security security;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef int (*zmk_rpc_subsystem_settings_reset_func)(void);
|
||||||
|
|
||||||
|
struct zmk_rpc_subsystem_settings_reset {
|
||||||
|
zmk_rpc_subsystem_settings_reset_func callback;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Generate a "meta" subsystem response indicating an "empty" response to an RPC request.
|
* @brief Generate a "meta" subsystem response indicating an "empty" response to an RPC request.
|
||||||
*/
|
*/
|
||||||
|
@ -103,6 +109,14 @@ struct zmk_rpc_subsystem_handler {
|
||||||
.security = _security, \
|
.security = _security, \
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ZMK_RPC_SUBSYSTEM_SETTINGS_RESET(prefix, _callback) \
|
||||||
|
STRUCT_SECTION_ITERABLE(zmk_rpc_subsystem_settings_reset, _##prefix##_settings_reset) = { \
|
||||||
|
.callback = _callback, \
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ZMK_RPC_SUBSYSTEM_SETTINGS_RESET_FOREACH(_var) \
|
||||||
|
STRUCT_SECTION_FOREACH(zmk_rpc_subsystem_settings_reset, _var)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a zmk_studio_Notification struct for the given subsystem and type, including
|
* @brief Create a zmk_studio_Notification struct for the given subsystem and type, including
|
||||||
initialization of the inner fields.
|
initialization of the inner fields.
|
||||||
|
|
649
app/src/keymap.c
649
app/src/keymap.c
|
@ -6,10 +6,12 @@
|
||||||
|
|
||||||
#include <drivers/behavior.h>
|
#include <drivers/behavior.h>
|
||||||
#include <zephyr/sys/util.h>
|
#include <zephyr/sys/util.h>
|
||||||
|
#include <zephyr/settings/settings.h>
|
||||||
#include <zephyr/bluetooth/bluetooth.h>
|
#include <zephyr/bluetooth/bluetooth.h>
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
|
||||||
|
#include <zmk/stdlib.h>
|
||||||
#include <zmk/behavior.h>
|
#include <zmk/behavior.h>
|
||||||
#include <zmk/keymap.h>
|
#include <zmk/keymap.h>
|
||||||
#include <zmk/matrix.h>
|
#include <zmk/matrix.h>
|
||||||
|
@ -27,7 +29,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
#include <zmk/events/sensor_event.h>
|
#include <zmk/events/sensor_event.h>
|
||||||
|
|
||||||
static zmk_keymap_layers_state_t _zmk_keymap_layer_state = 0;
|
static zmk_keymap_layers_state_t _zmk_keymap_layer_state = 0;
|
||||||
static uint8_t _zmk_keymap_layer_default = 0;
|
static zmk_keymap_layer_id_t _zmk_keymap_layer_default = 0;
|
||||||
|
|
||||||
#define DT_DRV_COMPAT zmk_keymap
|
#define DT_DRV_COMPAT zmk_keymap
|
||||||
|
|
||||||
|
@ -38,7 +40,11 @@ static uint8_t _zmk_keymap_layer_default = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TRANSFORMED_LAYER(node) \
|
#define TRANSFORMED_LAYER(node) \
|
||||||
{ LISTIFY(DT_PROP_LEN(node, bindings), ZMK_KEYMAP_EXTRACT_BINDING, (, ), node) }
|
{ \
|
||||||
|
COND_CODE_1( \
|
||||||
|
DT_NODE_HAS_PROP(node, bindings), \
|
||||||
|
(LISTIFY(DT_PROP_LEN(node, bindings), ZMK_KEYMAP_EXTRACT_BINDING, (, ), node)), ()) \
|
||||||
|
}
|
||||||
|
|
||||||
#if ZMK_KEYMAP_HAS_SENSORS
|
#if ZMK_KEYMAP_HAS_SENSORS
|
||||||
#define _TRANSFORM_SENSOR_ENTRY(idx, layer) \
|
#define _TRANSFORM_SENSOR_ENTRY(idx, layer) \
|
||||||
|
@ -58,7 +64,7 @@ static uint8_t _zmk_keymap_layer_default = 0;
|
||||||
|
|
||||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||||
|
|
||||||
#define LAYER_NAME(node) DT_PROP_OR(node, display_name, DT_PROP_OR(node, label, NULL))
|
#define LAYER_NAME(node) DT_PROP_OR(node, display_name, DT_PROP_OR(node, label, ""))
|
||||||
|
|
||||||
// State
|
// State
|
||||||
|
|
||||||
|
@ -67,12 +73,36 @@ static uint8_t _zmk_keymap_layer_default = 0;
|
||||||
// still send the release event to the behavior in that layer also.
|
// still send the release event to the behavior in that layer also.
|
||||||
static uint32_t zmk_keymap_active_behavior_layer[ZMK_KEYMAP_LEN];
|
static uint32_t zmk_keymap_active_behavior_layer[ZMK_KEYMAP_LEN];
|
||||||
|
|
||||||
static struct zmk_behavior_binding zmk_keymap[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_LEN] = {
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
DT_INST_FOREACH_CHILD_SEP(0, TRANSFORMED_LAYER, (, ))};
|
|
||||||
|
static uint8_t keymap_layer_orders[ZMK_KEYMAP_LAYERS_LEN];
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
|
||||||
|
#define KEYMAP_VAR(_name, _opts) \
|
||||||
|
static _opts struct zmk_behavior_binding _name[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_LEN] = { \
|
||||||
|
COND_CODE_1(IS_ENABLED(CONFIG_ZMK_STUDIO), \
|
||||||
|
(DT_INST_FOREACH_CHILD_SEP(0, TRANSFORMED_LAYER, (, ))), \
|
||||||
|
(DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(0, TRANSFORMED_LAYER, (, ))))};
|
||||||
|
|
||||||
|
KEYMAP_VAR(zmk_keymap, )
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE)
|
||||||
|
|
||||||
|
KEYMAP_VAR(zmk_stock_keymap, const)
|
||||||
|
|
||||||
|
static char zmk_keymap_layer_names[ZMK_KEYMAP_LAYERS_LEN][CONFIG_ZMK_KEYMAP_LAYER_NAME_MAX_LEN] = {
|
||||||
|
DT_INST_FOREACH_CHILD_SEP(0, LAYER_NAME, (, ))};
|
||||||
|
|
||||||
|
static uint32_t changed_layer_names = 0;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
static const char *zmk_keymap_layer_names[ZMK_KEYMAP_LAYERS_LEN] = {
|
static const char *zmk_keymap_layer_names[ZMK_KEYMAP_LAYERS_LEN] = {
|
||||||
DT_INST_FOREACH_CHILD_SEP(0, LAYER_NAME, (, ))};
|
DT_INST_FOREACH_CHILD_SEP(0, LAYER_NAME, (, ))};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#if ZMK_KEYMAP_HAS_SENSORS
|
#if ZMK_KEYMAP_HAS_SENSORS
|
||||||
|
|
||||||
static struct zmk_behavior_binding
|
static struct zmk_behavior_binding
|
||||||
|
@ -81,23 +111,50 @@ static struct zmk_behavior_binding
|
||||||
|
|
||||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||||
|
|
||||||
static inline int set_layer_state(uint8_t layer, bool state) {
|
#define ASSERT_LAYER_VAL(_layer, _fail_ret) \
|
||||||
|
if ((_layer) >= ZMK_KEYMAP_LAYERS_LEN) { \
|
||||||
|
return (_fail_ret); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
|
||||||
|
uint8_t map_layer_id_to_index(zmk_keymap_layer_id_t layer_id) {
|
||||||
|
for (uint8_t i = 0; i < ZMK_KEYMAP_LAYERS_LEN; i++) {
|
||||||
|
if (keymap_layer_orders[i] == layer_id) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ZMK_KEYMAP_LAYER_ID_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LAYER_INDEX_TO_ID(_layer) keymap_layer_orders[_layer]
|
||||||
|
#define LAYER_ID_TO_INDEX(_layer) map_layer_id_to_index(_layer)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define LAYER_INDEX_TO_ID(_layer) _layer
|
||||||
|
#define LAYER_ID_TO_INDEX(_layer) _layer
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
|
||||||
|
static inline int set_layer_state(zmk_keymap_layer_id_t layer_id, bool state) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
if (layer >= ZMK_KEYMAP_LAYERS_LEN) {
|
if (layer_id >= ZMK_KEYMAP_LAYERS_LEN) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default layer should *always* remain active
|
// Default layer should *always* remain active
|
||||||
if (layer == _zmk_keymap_layer_default && !state) {
|
if (layer_id == _zmk_keymap_layer_default && !state) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
zmk_keymap_layers_state_t old_state = _zmk_keymap_layer_state;
|
zmk_keymap_layers_state_t old_state = _zmk_keymap_layer_state;
|
||||||
WRITE_BIT(_zmk_keymap_layer_state, layer, state);
|
WRITE_BIT(_zmk_keymap_layer_state, layer_id, state);
|
||||||
// Don't send state changes unless there was an actual change
|
// Don't send state changes unless there was an actual change
|
||||||
if (old_state != _zmk_keymap_layer_state) {
|
if (old_state != _zmk_keymap_layer_state) {
|
||||||
LOG_DBG("layer_changed: layer %d state %d", layer, state);
|
LOG_DBG("layer_changed: layer %d state %d", layer_id, state);
|
||||||
ret = raise_layer_state_changed(layer, state);
|
ret = raise_layer_state_changed(layer_id, state);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
LOG_WRN("Failed to raise layer state changed (%d)", ret);
|
LOG_WRN("Failed to raise layer state changed (%d)", ret);
|
||||||
}
|
}
|
||||||
|
@ -106,21 +163,28 @@ static inline int set_layer_state(uint8_t layer, bool state) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t zmk_keymap_layer_default(void) { return _zmk_keymap_layer_default; }
|
zmk_keymap_layer_id_t zmk_keymap_layer_index_to_id(zmk_keymap_layer_index_t layer_index) {
|
||||||
|
ASSERT_LAYER_VAL(layer_index, UINT8_MAX);
|
||||||
|
|
||||||
|
return LAYER_INDEX_TO_ID(layer_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_keymap_layer_id_t zmk_keymap_layer_default(void) { return _zmk_keymap_layer_default; }
|
||||||
|
|
||||||
zmk_keymap_layers_state_t zmk_keymap_layer_state(void) { return _zmk_keymap_layer_state; }
|
zmk_keymap_layers_state_t zmk_keymap_layer_state(void) { return _zmk_keymap_layer_state; }
|
||||||
|
|
||||||
bool zmk_keymap_layer_active_with_state(uint8_t layer, zmk_keymap_layers_state_t state_to_test) {
|
bool zmk_keymap_layer_active_with_state(zmk_keymap_layer_id_t layer,
|
||||||
|
zmk_keymap_layers_state_t state_to_test) {
|
||||||
// The default layer is assumed to be ALWAYS ACTIVE so we include an || here to ensure nobody
|
// The default layer is assumed to be ALWAYS ACTIVE so we include an || here to ensure nobody
|
||||||
// breaks up that assumption by accident
|
// breaks up that assumption by accident
|
||||||
return (state_to_test & (BIT(layer))) == (BIT(layer)) || layer == _zmk_keymap_layer_default;
|
return (state_to_test & (BIT(layer))) == (BIT(layer)) || layer == _zmk_keymap_layer_default;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool zmk_keymap_layer_active(uint8_t layer) {
|
bool zmk_keymap_layer_active(zmk_keymap_layer_id_t layer) {
|
||||||
return zmk_keymap_layer_active_with_state(layer, _zmk_keymap_layer_state);
|
return zmk_keymap_layer_active_with_state(layer, _zmk_keymap_layer_state);
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t zmk_keymap_highest_layer_active(void) {
|
zmk_keymap_layer_id_t zmk_keymap_highest_layer_active(void) {
|
||||||
for (uint8_t layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer > 0; layer--) {
|
for (uint8_t layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer > 0; layer--) {
|
||||||
if (zmk_keymap_layer_active(layer)) {
|
if (zmk_keymap_layer_active(layer)) {
|
||||||
return layer;
|
return layer;
|
||||||
|
@ -129,11 +193,13 @@ uint8_t zmk_keymap_highest_layer_active(void) {
|
||||||
return zmk_keymap_layer_default();
|
return zmk_keymap_layer_default();
|
||||||
}
|
}
|
||||||
|
|
||||||
int zmk_keymap_layer_activate(uint8_t layer) { return set_layer_state(layer, true); };
|
int zmk_keymap_layer_activate(zmk_keymap_layer_id_t layer) { return set_layer_state(layer, true); };
|
||||||
|
|
||||||
int zmk_keymap_layer_deactivate(uint8_t layer) { return set_layer_state(layer, false); };
|
int zmk_keymap_layer_deactivate(zmk_keymap_layer_id_t layer) {
|
||||||
|
return set_layer_state(layer, false);
|
||||||
|
};
|
||||||
|
|
||||||
int zmk_keymap_layer_toggle(uint8_t layer) {
|
int zmk_keymap_layer_toggle(zmk_keymap_layer_id_t layer) {
|
||||||
if (zmk_keymap_layer_active(layer)) {
|
if (zmk_keymap_layer_active(layer)) {
|
||||||
return zmk_keymap_layer_deactivate(layer);
|
return zmk_keymap_layer_deactivate(layer);
|
||||||
}
|
}
|
||||||
|
@ -141,7 +207,7 @@ int zmk_keymap_layer_toggle(uint8_t layer) {
|
||||||
return zmk_keymap_layer_activate(layer);
|
return zmk_keymap_layer_activate(layer);
|
||||||
};
|
};
|
||||||
|
|
||||||
int zmk_keymap_layer_to(uint8_t layer) {
|
int zmk_keymap_layer_to(zmk_keymap_layer_id_t layer) {
|
||||||
for (int i = ZMK_KEYMAP_LAYERS_LEN - 1; i >= 0; i--) {
|
for (int i = ZMK_KEYMAP_LAYERS_LEN - 1; i >= 0; i--) {
|
||||||
zmk_keymap_layer_deactivate(i);
|
zmk_keymap_layer_deactivate(i);
|
||||||
}
|
}
|
||||||
|
@ -151,18 +217,365 @@ int zmk_keymap_layer_to(uint8_t layer) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_active_layer(uint8_t layer, zmk_keymap_layers_state_t layer_state) {
|
const char *zmk_keymap_layer_name(zmk_keymap_layer_id_t layer_id) {
|
||||||
return (layer_state & BIT(layer)) == BIT(layer) || layer == _zmk_keymap_layer_default;
|
ASSERT_LAYER_VAL(layer_id, NULL)
|
||||||
|
|
||||||
|
return zmk_keymap_layer_names[layer_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *zmk_keymap_layer_name(uint8_t layer) {
|
const struct zmk_behavior_binding *
|
||||||
if (layer >= ZMK_KEYMAP_LAYERS_LEN) {
|
zmk_keymap_get_layer_binding_at_idx(zmk_keymap_layer_id_t layer_id, uint8_t binding_idx) {
|
||||||
|
if (binding_idx >= ZMK_KEYMAP_LEN) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return zmk_keymap_layer_names[layer];
|
ASSERT_LAYER_VAL(layer_id, NULL)
|
||||||
|
|
||||||
|
return &zmk_keymap[layer_id][binding_idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE)
|
||||||
|
|
||||||
|
#define PENDING_ARRAY_SIZE DIV_ROUND_UP(ZMK_KEYMAP_LEN, 8)
|
||||||
|
|
||||||
|
static uint8_t zmk_keymap_layer_pending_changes[ZMK_KEYMAP_LAYERS_LEN][PENDING_ARRAY_SIZE];
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE)
|
||||||
|
|
||||||
|
int zmk_keymap_set_layer_binding_at_idx(zmk_keymap_layer_id_t layer_id, uint8_t binding_idx,
|
||||||
|
struct zmk_behavior_binding binding) {
|
||||||
|
if (binding_idx >= ZMK_KEYMAP_LEN) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_LAYER_VAL(layer_id, -EINVAL)
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE)
|
||||||
|
uint8_t *pending = zmk_keymap_layer_pending_changes[layer_id];
|
||||||
|
|
||||||
|
WRITE_BIT(pending[binding_idx / 8], binding_idx % 8, 1);
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE)
|
||||||
|
|
||||||
|
// TODO: Need a mutex to protect access to the keymap data?
|
||||||
|
memcpy(&zmk_keymap[layer_id][binding_idx], &binding, sizeof(binding));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE)
|
||||||
|
|
||||||
|
static uint8_t settings_layer_orders[ZMK_KEYMAP_LAYERS_LEN];
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int zmk_keymap_move_layer(zmk_keymap_layer_index_t start_idx, zmk_keymap_layer_index_t dest_idx) {
|
||||||
|
ASSERT_LAYER_VAL(start_idx, -EINVAL)
|
||||||
|
ASSERT_LAYER_VAL(dest_idx, -EINVAL)
|
||||||
|
|
||||||
|
if (start_idx == dest_idx) {
|
||||||
|
return 0;
|
||||||
|
} else if (dest_idx > start_idx) {
|
||||||
|
uint8_t val = keymap_layer_orders[start_idx];
|
||||||
|
|
||||||
|
for (int i = start_idx; i < dest_idx; i++) {
|
||||||
|
keymap_layer_orders[i] = keymap_layer_orders[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
keymap_layer_orders[dest_idx] = val;
|
||||||
|
} else {
|
||||||
|
uint8_t val = keymap_layer_orders[start_idx];
|
||||||
|
|
||||||
|
for (int i = start_idx; i > dest_idx; i--) {
|
||||||
|
keymap_layer_orders[i] = keymap_layer_orders[i - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
keymap_layer_orders[dest_idx] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zmk_keymap_add_layer(void) {
|
||||||
|
uint32_t seen_layer_ids = 0;
|
||||||
|
LOG_HEXDUMP_DBG(keymap_layer_orders, ZMK_KEYMAP_LAYERS_LEN, "Order");
|
||||||
|
|
||||||
|
for (int index = 0; index < ZMK_KEYMAP_LAYERS_LEN; index++) {
|
||||||
|
zmk_keymap_layer_id_t id = LAYER_INDEX_TO_ID(index);
|
||||||
|
|
||||||
|
if (id != ZMK_KEYMAP_LAYER_ID_INVAL) {
|
||||||
|
WRITE_BIT(seen_layer_ids, id, 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int candidate_id = 0; candidate_id < ZMK_KEYMAP_LAYERS_LEN; candidate_id++) {
|
||||||
|
if (!(seen_layer_ids & BIT(candidate_id))) {
|
||||||
|
keymap_layer_orders[index] = candidate_id;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zmk_keymap_remove_layer(zmk_keymap_layer_index_t index) {
|
||||||
|
ASSERT_LAYER_VAL(index, -EINVAL);
|
||||||
|
|
||||||
|
if (keymap_layer_orders[index] == ZMK_KEYMAP_LAYER_ID_INVAL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("Removing layer index %d which is ID %d", index, keymap_layer_orders[index]);
|
||||||
|
LOG_HEXDUMP_DBG(keymap_layer_orders, ZMK_KEYMAP_LAYERS_LEN, "Order");
|
||||||
|
|
||||||
|
while (index < ZMK_KEYMAP_LAYERS_LEN - 1) {
|
||||||
|
keymap_layer_orders[index] = keymap_layer_orders[index + 1];
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
keymap_layer_orders[ZMK_KEYMAP_LAYERS_LEN - 1] = ZMK_KEYMAP_LAYER_ID_INVAL;
|
||||||
|
|
||||||
|
LOG_HEXDUMP_DBG(keymap_layer_orders, ZMK_KEYMAP_LAYERS_LEN, "Order");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zmk_keymap_restore_layer(zmk_keymap_layer_id_t id, zmk_keymap_layer_index_t at_index) {
|
||||||
|
ASSERT_LAYER_VAL(at_index, -EINVAL);
|
||||||
|
ASSERT_LAYER_VAL(id, -ENODEV);
|
||||||
|
|
||||||
|
for (zmk_keymap_layer_index_t index = ZMK_KEYMAP_LAYERS_LEN - 1; index > at_index; index--) {
|
||||||
|
keymap_layer_orders[index] = keymap_layer_orders[index - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
keymap_layer_orders[at_index] = id;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zmk_keymap_set_layer_name(zmk_keymap_layer_id_t id, const char *name, size_t size) {
|
||||||
|
ASSERT_LAYER_VAL(id, -EINVAL);
|
||||||
|
|
||||||
|
if (size >= CONFIG_ZMK_KEYMAP_LAYER_NAME_MAX_LEN) {
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcpy(zmk_keymap_layer_names[id], name, CONFIG_ZMK_KEYMAP_LAYER_NAME_MAX_LEN);
|
||||||
|
|
||||||
|
// Ensure we properly null terminate our name if we previously had a longer one.
|
||||||
|
if (size < CONFIG_ZMK_KEYMAP_LAYER_NAME_MAX_LEN - 1) {
|
||||||
|
zmk_keymap_layer_names[id][size] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE_BIT(changed_layer_names, id, 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
int zmk_keymap_move_layer(zmk_keymap_layer_index_t layer, zmk_keymap_layer_index_t dest) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zmk_keymap_add_layer(void) { return -ENOTSUP; }
|
||||||
|
|
||||||
|
int zmk_keymap_remove_layer(zmk_keymap_layer_index_t index) { return -ENOTSUP; }
|
||||||
|
|
||||||
|
int zmk_keymap_restore_layer(zmk_keymap_layer_id_t id, zmk_keymap_layer_index_t at_index) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zmk_keymap_set_layer_name(zmk_keymap_layer_id_t id, const char *name, size_t size) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE)
|
||||||
|
|
||||||
|
#define PENDING_ARRAY_SIZE DIV_ROUND_UP(ZMK_KEYMAP_LEN, 8)
|
||||||
|
|
||||||
|
static uint8_t zmk_keymap_layer_pending_changes[ZMK_KEYMAP_LAYERS_LEN][PENDING_ARRAY_SIZE];
|
||||||
|
|
||||||
|
struct zmk_behavior_binding_setting {
|
||||||
|
zmk_behavior_local_id_t behavior_local_id;
|
||||||
|
uint32_t param1;
|
||||||
|
uint32_t param2;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
int zmk_keymap_check_unsaved_changes(void) {
|
||||||
|
for (int l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) {
|
||||||
|
uint8_t *pending = zmk_keymap_layer_pending_changes[l];
|
||||||
|
for (int kp = 0; kp < ZMK_KEYMAP_LEN; kp++) {
|
||||||
|
if (pending[kp / 8] & BIT(kp % 8)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
if (settings_layer_orders[l] != keymap_layer_orders[l]) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LAYER_ORDER_SETTINGS_KEY "keymap/layer_order"
|
||||||
|
#define LAYER_NAME_SETTINGS_KEY "keymap/l_n/%d"
|
||||||
|
#define LAYER_BINDING_SETTINGS_KEY "keymap/l/%d/%d"
|
||||||
|
|
||||||
|
static void save_bindings(void) {
|
||||||
|
for (int l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) {
|
||||||
|
uint8_t *pending = zmk_keymap_layer_pending_changes[l];
|
||||||
|
|
||||||
|
for (int kp = 0; kp < ZMK_KEYMAP_LEN; kp++) {
|
||||||
|
if (pending[kp / 8] & BIT(kp % 8)) {
|
||||||
|
LOG_DBG("Pending save for layer %d at key position %d", l, kp);
|
||||||
|
|
||||||
|
struct zmk_behavior_binding *binding = &zmk_keymap[l][kp];
|
||||||
|
struct zmk_behavior_binding_setting binding_setting = {
|
||||||
|
.behavior_local_id = zmk_behavior_get_local_id(binding->behavior_dev),
|
||||||
|
.param1 = binding->param1,
|
||||||
|
.param2 = binding->param2,
|
||||||
|
};
|
||||||
|
|
||||||
|
// We can skip any trailing zero params, regardless of the behavior
|
||||||
|
// and if those params are meaningful.
|
||||||
|
size_t len = sizeof(binding_setting);
|
||||||
|
if (binding_setting.param2 == 0) {
|
||||||
|
len -= 4;
|
||||||
|
|
||||||
|
if (binding_setting.param1 == 0) {
|
||||||
|
len -= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char setting_name[20];
|
||||||
|
sprintf(setting_name, LAYER_BINDING_SETTINGS_KEY, l, kp);
|
||||||
|
|
||||||
|
settings_save_one(setting_name, &binding_setting, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*pending = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
static void save_layer_orders(void) {
|
||||||
|
settings_save_one(LAYER_ORDER_SETTINGS_KEY, keymap_layer_orders,
|
||||||
|
ARRAY_SIZE(keymap_layer_orders));
|
||||||
|
memcpy(settings_layer_orders, keymap_layer_orders, ARRAY_SIZE(keymap_layer_orders));
|
||||||
|
}
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
|
||||||
|
static void save_layer_names(void) {
|
||||||
|
for (int id = 0; id < ZMK_KEYMAP_LAYERS_LEN; id++) {
|
||||||
|
if (changed_layer_names & BIT(id)) {
|
||||||
|
char setting_name[14];
|
||||||
|
sprintf(setting_name, LAYER_NAME_SETTINGS_KEY, id);
|
||||||
|
settings_save_one(setting_name, zmk_keymap_layer_names[id],
|
||||||
|
strlen(zmk_keymap_layer_names[id]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
changed_layer_names = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zmk_keymap_save_changes(void) {
|
||||||
|
save_bindings();
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
save_layer_orders();
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
|
||||||
|
save_layer_names();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
|
||||||
|
#define KEYMAP_LAYER_ORDER_INIT(n) \
|
||||||
|
keymap_layer_orders[i] = i; \
|
||||||
|
settings_layer_orders[i] = i; \
|
||||||
|
i++;
|
||||||
|
|
||||||
|
static void load_stock_keymap_layer_ordering() {
|
||||||
|
int i = 0;
|
||||||
|
DT_INST_FOREACH_CHILD_STATUS_OKAY(0, KEYMAP_LAYER_ORDER_INIT)
|
||||||
|
while (i < ZMK_KEYMAP_LAYERS_LEN) {
|
||||||
|
keymap_layer_orders[i] = ZMK_KEYMAP_LAYER_ID_INVAL;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void reload_from_stock_keymap(void) {
|
||||||
|
for (int l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) {
|
||||||
|
for (int k = 0; k < ZMK_KEYMAP_LEN; k++) {
|
||||||
|
zmk_keymap[l][k] = zmk_stock_keymap[l][k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int zmk_keymap_discard_changes(void) {
|
||||||
|
load_stock_keymap_layer_ordering();
|
||||||
|
reload_from_stock_keymap();
|
||||||
|
|
||||||
|
int ret = settings_load_subtree("keymap");
|
||||||
|
if (ret >= 0) {
|
||||||
|
changed_layer_names = 0;
|
||||||
|
|
||||||
|
for (int l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) {
|
||||||
|
memset(zmk_keymap_layer_pending_changes[l], 0, PENDING_ARRAY_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zmk_keymap_reset_settings(void) {
|
||||||
|
settings_delete(LAYER_ORDER_SETTINGS_KEY);
|
||||||
|
for (int l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) {
|
||||||
|
char layer_name_setting_name[14];
|
||||||
|
sprintf(layer_name_setting_name, LAYER_NAME_SETTINGS_KEY, l);
|
||||||
|
settings_delete(layer_name_setting_name);
|
||||||
|
|
||||||
|
for (int k = 0; k < ZMK_KEYMAP_LEN; k++) {
|
||||||
|
if (memcmp(&zmk_keymap[l][k], &zmk_stock_keymap[l][k],
|
||||||
|
sizeof(struct zmk_behavior_binding_setting)) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
char setting_name[20];
|
||||||
|
sprintf(setting_name, LAYER_BINDING_SETTINGS_KEY, l, k);
|
||||||
|
settings_delete(setting_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
load_stock_keymap_layer_ordering();
|
||||||
|
|
||||||
|
reload_from_stock_keymap();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
int zmk_keymap_save_changes(void) { return -ENOTSUP; }
|
||||||
|
|
||||||
|
int zmk_keymap_discard_changes(void) { return -ENOTSUP; }
|
||||||
|
|
||||||
|
int zmk_keymap_reset_settings(void) { return -ENOTSUP; }
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE)
|
||||||
|
|
||||||
int invoke_locally(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
|
int invoke_locally(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
|
||||||
bool pressed) {
|
bool pressed) {
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
|
@ -172,24 +585,28 @@ int invoke_locally(struct zmk_behavior_binding *binding, struct zmk_behavior_bin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int zmk_keymap_apply_position_state(uint8_t source, int layer, uint32_t position, bool pressed,
|
int zmk_keymap_apply_position_state(uint8_t source, zmk_keymap_layer_id_t layer_id,
|
||||||
int64_t timestamp) {
|
uint32_t position, bool pressed, int64_t timestamp) {
|
||||||
// We want to make a copy of this, since it may be converted from
|
// We want to make a copy of this, since it may be converted from
|
||||||
// relative to absolute before being invoked
|
// relative to absolute before being invoked
|
||||||
struct zmk_behavior_binding binding = zmk_keymap[layer][position];
|
|
||||||
|
ASSERT_LAYER_VAL(layer_id, -EINVAL);
|
||||||
|
|
||||||
|
struct zmk_behavior_binding binding = zmk_keymap[layer_id][position];
|
||||||
const struct device *behavior;
|
const struct device *behavior;
|
||||||
struct zmk_behavior_binding_event event = {
|
struct zmk_behavior_binding_event event = {
|
||||||
.layer = layer,
|
.layer = layer_id,
|
||||||
.position = position,
|
.position = position,
|
||||||
.timestamp = timestamp,
|
.timestamp = timestamp,
|
||||||
};
|
};
|
||||||
|
|
||||||
LOG_DBG("layer: %d position: %d, binding name: %s", layer, position, binding.behavior_dev);
|
LOG_DBG("layer_id: %d position: %d, binding name: %s", layer_id, position,
|
||||||
|
binding.behavior_dev);
|
||||||
|
|
||||||
behavior = zmk_behavior_get_binding(binding.behavior_dev);
|
behavior = zmk_behavior_get_binding(binding.behavior_dev);
|
||||||
|
|
||||||
if (!behavior) {
|
if (!behavior) {
|
||||||
LOG_WRN("No behavior assigned to %d on layer %d", position, layer);
|
LOG_WRN("No behavior assigned to %d on layer %d", position, layer_id);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,9 +653,19 @@ int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pr
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
zmk_keymap_active_behavior_layer[position] = _zmk_keymap_layer_state;
|
zmk_keymap_active_behavior_layer[position] = _zmk_keymap_layer_state;
|
||||||
}
|
}
|
||||||
for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= _zmk_keymap_layer_default; layer--) {
|
|
||||||
if (zmk_keymap_layer_active_with_state(layer, zmk_keymap_active_behavior_layer[position])) {
|
// We use int here to be sure we don't loop layer_idx back to UINT8_MAX
|
||||||
int ret = zmk_keymap_apply_position_state(source, layer, position, pressed, timestamp);
|
for (int layer_idx = ZMK_KEYMAP_LAYERS_LEN - 1;
|
||||||
|
layer_idx >= LAYER_ID_TO_INDEX(_zmk_keymap_layer_default); layer_idx--) {
|
||||||
|
zmk_keymap_layer_id_t layer_id = LAYER_INDEX_TO_ID(layer_idx);
|
||||||
|
|
||||||
|
if (layer_id == ZMK_KEYMAP_LAYER_ID_INVAL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (zmk_keymap_layer_active_with_state(layer_id,
|
||||||
|
zmk_keymap_active_behavior_layer[position])) {
|
||||||
|
int ret =
|
||||||
|
zmk_keymap_apply_position_state(source, layer_id, position, pressed, timestamp);
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
LOG_DBG("behavior processing to continue to next layer");
|
LOG_DBG("behavior processing to continue to next layer");
|
||||||
continue;
|
continue;
|
||||||
|
@ -260,20 +687,26 @@ int zmk_keymap_sensor_event(uint8_t sensor_index,
|
||||||
size_t channel_data_size, int64_t timestamp) {
|
size_t channel_data_size, int64_t timestamp) {
|
||||||
bool opaque_response = false;
|
bool opaque_response = false;
|
||||||
|
|
||||||
for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= 0; layer--) {
|
for (int layer_idx = ZMK_KEYMAP_LAYERS_LEN - 1; layer_idx >= 0; layer_idx--) {
|
||||||
struct zmk_behavior_binding *binding = &zmk_sensor_keymap[layer][sensor_index];
|
uint8_t layer_id = LAYER_INDEX_TO_ID(layer_idx);
|
||||||
|
|
||||||
LOG_DBG("layer: %d sensor_index: %d, binding name: %s", layer, sensor_index,
|
if (layer_id >= ZMK_KEYMAP_LAYERS_LEN) {
|
||||||
binding->behavior_dev);
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct zmk_behavior_binding *binding = &zmk_sensor_keymap[layer_id][sensor_index];
|
||||||
|
|
||||||
|
LOG_DBG("layer idx: %d, layer id: %d sensor_index: %d, binding name: %s", layer_idx,
|
||||||
|
layer_id, sensor_index, binding->behavior_dev);
|
||||||
|
|
||||||
const struct device *behavior = zmk_behavior_get_binding(binding->behavior_dev);
|
const struct device *behavior = zmk_behavior_get_binding(binding->behavior_dev);
|
||||||
if (!behavior) {
|
if (!behavior) {
|
||||||
LOG_DBG("No behavior assigned to %d on layer %d", sensor_index, layer);
|
LOG_DBG("No behavior assigned to %d on layer %d", sensor_index, layer_id);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct zmk_behavior_binding_event event = {
|
struct zmk_behavior_binding_event event = {
|
||||||
.layer = layer,
|
.layer = layer_id,
|
||||||
.position = ZMK_VIRTUAL_KEY_POSITION_SENSOR(sensor_index),
|
.position = ZMK_VIRTUAL_KEY_POSITION_SENSOR(sensor_index),
|
||||||
.timestamp = timestamp,
|
.timestamp = timestamp,
|
||||||
};
|
};
|
||||||
|
@ -290,8 +723,8 @@ int zmk_keymap_sensor_event(uint8_t sensor_index,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum behavior_sensor_binding_process_mode mode =
|
enum behavior_sensor_binding_process_mode mode =
|
||||||
(!opaque_response && layer >= _zmk_keymap_layer_default &&
|
(!opaque_response && layer_idx >= LAYER_ID_TO_INDEX(_zmk_keymap_layer_default) &&
|
||||||
zmk_keymap_layer_active(layer))
|
zmk_keymap_layer_active(layer_id))
|
||||||
? BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER
|
? BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER
|
||||||
: BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_DISCARD;
|
: BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_DISCARD;
|
||||||
|
|
||||||
|
@ -335,3 +768,137 @@ ZMK_SUBSCRIPTION(keymap, zmk_position_state_changed);
|
||||||
#if ZMK_KEYMAP_HAS_SENSORS
|
#if ZMK_KEYMAP_HAS_SENSORS
|
||||||
ZMK_SUBSCRIPTION(keymap, zmk_sensor_event);
|
ZMK_SUBSCRIPTION(keymap, zmk_sensor_event);
|
||||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE)
|
||||||
|
|
||||||
|
static int keymap_handle_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) {
|
||||||
|
const char *next;
|
||||||
|
|
||||||
|
LOG_DBG("Setting Keymap setting %s", name);
|
||||||
|
|
||||||
|
if (settings_name_steq(name, "l_n", &next) && next) {
|
||||||
|
char *endptr;
|
||||||
|
zmk_keymap_layer_id_t layer = strtoul(next, &endptr, 10);
|
||||||
|
|
||||||
|
if (*endptr != '\0') {
|
||||||
|
LOG_WRN("Invalid layer number: %s with endptr %s", next, endptr);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layer >= ZMK_KEYMAP_LAYERS_LEN) {
|
||||||
|
LOG_WRN("Found layer name for invalid layer ID %d", layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int err = read_cb(cb_arg, zmk_keymap_layer_names[layer],
|
||||||
|
MIN(len, CONFIG_ZMK_KEYMAP_LAYER_NAME_MAX_LEN - 1));
|
||||||
|
if (err <= 0) {
|
||||||
|
LOG_ERR("Failed to handle keymap layer name from settings (err %d)", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
} else if (settings_name_steq(name, "l", &next) && next) {
|
||||||
|
char *endptr;
|
||||||
|
uint8_t layer = strtoul(next, &endptr, 10);
|
||||||
|
if (*endptr != '/') {
|
||||||
|
LOG_WRN("Invalid layer number: %s with endptr %s", next, endptr);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t key_position = strtoul(endptr + 1, &endptr, 10);
|
||||||
|
|
||||||
|
if (*endptr != '\0') {
|
||||||
|
LOG_WRN("Invalid key_position number: %s with endptr %s", next, endptr);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > sizeof(struct zmk_behavior_binding_setting)) {
|
||||||
|
LOG_ERR("Too large binding setting size (got %d expected %d)", len,
|
||||||
|
sizeof(struct zmk_behavior_binding_setting));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layer >= ZMK_KEYMAP_LAYERS_LEN) {
|
||||||
|
LOG_WRN("Layer %d is larger than max of %d", layer, ZMK_KEYMAP_LAYERS_LEN);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key_position >= ZMK_KEYMAP_LEN) {
|
||||||
|
LOG_WRN("Key position %d is larger than max of %d", key_position, ZMK_KEYMAP_LEN);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct zmk_behavior_binding_setting binding_setting = {0};
|
||||||
|
int err = read_cb(cb_arg, &binding_setting, len);
|
||||||
|
if (err <= 0) {
|
||||||
|
LOG_ERR("Failed to handle keymap binding from settings (err %d)", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *name =
|
||||||
|
zmk_behavior_find_behavior_name_from_local_id(binding_setting.behavior_local_id);
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
LOG_WRN("Loaded device %d from settings but no device found by that local ID",
|
||||||
|
binding_setting.behavior_local_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_keymap[layer][key_position] = (struct zmk_behavior_binding){
|
||||||
|
.local_id = binding_setting.behavior_local_id,
|
||||||
|
.behavior_dev = name,
|
||||||
|
.param1 = binding_setting.param1,
|
||||||
|
.param2 = binding_setting.param2,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
else if (settings_name_steq(name, "layer_order", &next) && !next) {
|
||||||
|
int err =
|
||||||
|
read_cb(cb_arg, settings_layer_orders, MIN(len, ARRAY_SIZE(settings_layer_orders)));
|
||||||
|
if (err <= 0) {
|
||||||
|
LOG_ERR("Failed to handle keymap layer orders from settings (err %d)", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_HEXDUMP_DBG(settings_layer_orders, ARRAY_SIZE(settings_layer_orders),
|
||||||
|
"Settings Layer Order");
|
||||||
|
|
||||||
|
memcpy(keymap_layer_orders, settings_layer_orders,
|
||||||
|
MIN(len, ARRAY_SIZE(settings_layer_orders)));
|
||||||
|
}
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int keymap_handle_commit(void) {
|
||||||
|
for (int l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) {
|
||||||
|
for (int p = 0; p < ZMK_KEYMAP_LEN; p++) {
|
||||||
|
struct zmk_behavior_binding *binding = &zmk_keymap[l][p];
|
||||||
|
|
||||||
|
if (binding->local_id > 0 && !binding->behavior_dev) {
|
||||||
|
binding->behavior_dev =
|
||||||
|
zmk_behavior_find_behavior_name_from_local_id(binding->local_id);
|
||||||
|
|
||||||
|
if (!binding->behavior_dev) {
|
||||||
|
LOG_ERR("Failed to finding device for local ID %d after settings load",
|
||||||
|
binding->local_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SETTINGS_STATIC_HANDLER_DEFINE(keymap, "keymap", NULL, keymap_handle_set, keymap_handle_commit,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE)
|
||||||
|
|
||||||
|
int keymap_init(void) {
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
load_stock_keymap_layer_ordering();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_INIT(keymap_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
|
||||||
|
|
|
@ -72,9 +72,17 @@ struct position_map_entry {
|
||||||
const uint32_t positions[ZMK_POS_MAP_LEN];
|
const uint32_t positions[ZMK_POS_MAP_LEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ZMK_POS_MAP_LEN_CHECK(node_id) \
|
||||||
|
BUILD_ASSERT(ZMK_POS_MAP_LEN == DT_PROP_LEN(node_id, positions), \
|
||||||
|
"Position maps must all have the same number of entries")
|
||||||
|
|
||||||
|
DT_FOREACH_CHILD_SEP(DT_INST(0, POS_MAP_COMPAT), ZMK_POS_MAP_LEN_CHECK, (;));
|
||||||
|
|
||||||
#define ZMK_POS_MAP_ENTRY(node_id) \
|
#define ZMK_POS_MAP_ENTRY(node_id) \
|
||||||
{ \
|
{ \
|
||||||
.layout = &_CONCAT(_zmk_physical_layout_, DT_PHANDLE(node_id, physical_layout)), \
|
.layout = COND_CODE_1( \
|
||||||
|
DT_HAS_COMPAT_STATUS_OKAY(DT_PHANDLE(node_id, physical_layout)), \
|
||||||
|
(&_CONCAT(_zmk_physical_layout_, DT_PHANDLE(node_id, physical_layout))), (NULL)), \
|
||||||
.positions = DT_PROP(node_id, positions), \
|
.positions = DT_PROP(node_id, positions), \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,13 +283,15 @@ int zmk_physical_layouts_save_selected(void) {
|
||||||
|
|
||||||
int zmk_physical_layouts_revert_selected(void) { return zmk_physical_layouts_select_initial(); }
|
int zmk_physical_layouts_revert_selected(void) { return zmk_physical_layouts_select_initial(); }
|
||||||
|
|
||||||
int zmk_physical_layouts_get_position_map(uint8_t source, uint8_t dest, uint32_t *map) {
|
int zmk_physical_layouts_get_position_map(uint8_t source, uint8_t dest, size_t map_size,
|
||||||
|
uint32_t map[map_size]) {
|
||||||
if (source >= ARRAY_SIZE(layouts) || dest >= ARRAY_SIZE(layouts)) {
|
if (source >= ARRAY_SIZE(layouts) || dest >= ARRAY_SIZE(layouts)) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct zmk_physical_layout *src_layout = layouts[source];
|
const struct zmk_physical_layout *src_layout = layouts[source];
|
||||||
const struct zmk_physical_layout *dest_layout = layouts[dest];
|
const struct zmk_physical_layout *dest_layout = layouts[dest];
|
||||||
|
int max_kp = dest_layout->keys_len;
|
||||||
|
|
||||||
#if HAVE_POS_MAP
|
#if HAVE_POS_MAP
|
||||||
const struct position_map_entry *src_pos_map = NULL;
|
const struct position_map_entry *src_pos_map = NULL;
|
||||||
|
@ -296,11 +306,24 @@ int zmk_physical_layouts_get_position_map(uint8_t source, uint8_t dest, uint32_t
|
||||||
dest_pos_map = &positions_maps[pm];
|
dest_pos_map = &positions_maps[pm];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Maps can place items "off the end" of other layouts so they are
|
||||||
|
// preserved but not visible, so adjust our max here if that is being used.
|
||||||
|
if (src_pos_map && dest_pos_map) {
|
||||||
|
for (int mp = 0; mp < ZMK_POS_MAP_LEN; mp++) {
|
||||||
|
max_kp =
|
||||||
|
MAX(max_kp, MAX(src_pos_map->positions[mp] + 1, dest_pos_map->positions[mp] + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
memset(map, UINT32_MAX, dest_layout->keys_len);
|
if (map_size < max_kp) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
for (int b = 0; b < dest_layout->keys_len; b++) {
|
memset(map, UINT32_MAX, map_size);
|
||||||
|
|
||||||
|
for (int b = 0; b < max_kp; b++) {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
#if HAVE_POS_MAP
|
#if HAVE_POS_MAP
|
||||||
|
@ -329,13 +352,9 @@ int zmk_physical_layouts_get_position_map(uint8_t source, uint8_t dest, uint32_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!found || map[b] >= src_layout->keys_len) {
|
|
||||||
map[b] = UINT32_MAX;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dest_layout->keys_len;
|
return max_kp;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_SETTINGS)
|
#if IS_ENABLED(CONFIG_SETTINGS)
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
zephyr_linker_sources(DATA_SECTIONS ../../include/linker/zmk-rpc-subsystems.ld)
|
zephyr_linker_sources(DATA_SECTIONS ../../include/linker/zmk-rpc-subsystems.ld)
|
||||||
zephyr_linker_sources(SECTIONS ../../include/linker/zmk-rpc-subsystem-handlers.ld)
|
zephyr_linker_sources(SECTIONS ../../include/linker/zmk-rpc-subsystem-handlers.ld)
|
||||||
|
zephyr_linker_sources(SECTIONS ../../include/linker/zmk-rpc-subsystem-settings-reset.ld)
|
||||||
zephyr_linker_sources(SECTIONS ../../include/linker/zmk-rpc-event-mappers.ld)
|
zephyr_linker_sources(SECTIONS ../../include/linker/zmk-rpc-event-mappers.ld)
|
||||||
zephyr_linker_sources(SECTIONS ../../include/linker/zmk-rpc-transport.ld)
|
zephyr_linker_sources(SECTIONS ../../include/linker/zmk-rpc-transport.ld)
|
||||||
|
|
||||||
|
@ -11,5 +12,6 @@ target_sources(app PRIVATE rpc.c)
|
||||||
target_sources(app PRIVATE core.c)
|
target_sources(app PRIVATE core.c)
|
||||||
target_sources(app PRIVATE behavior_subsystem.c)
|
target_sources(app PRIVATE behavior_subsystem.c)
|
||||||
target_sources(app PRIVATE core_subsystem.c)
|
target_sources(app PRIVATE core_subsystem.c)
|
||||||
|
target_sources(app PRIVATE keymap_subsystem.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_STUDIO_TRANSPORT_UART app PRIVATE uart_rpc_transport.c)
|
target_sources_ifdef(CONFIG_ZMK_STUDIO_TRANSPORT_UART app PRIVATE uart_rpc_transport.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_STUDIO_TRANSPORT_BLE app PRIVATE gatt_rpc_transport.c)
|
target_sources_ifdef(CONFIG_ZMK_STUDIO_TRANSPORT_BLE app PRIVATE gatt_rpc_transport.c)
|
|
@ -41,6 +41,8 @@ menuconfig ZMK_STUDIO_RPC
|
||||||
select ZMK_BEHAVIOR_METADATA
|
select ZMK_BEHAVIOR_METADATA
|
||||||
select ZMK_BEHAVIOR_LOCAL_IDS
|
select ZMK_BEHAVIOR_LOCAL_IDS
|
||||||
select RING_BUFFER
|
select RING_BUFFER
|
||||||
|
select ZMK_KEYMAP_SETTINGS_STORAGE
|
||||||
|
select ZMK_KEYMAP_LAYER_REORDERING
|
||||||
help
|
help
|
||||||
Add firmware support for studio RPC protocol
|
Add firmware support for studio RPC protocol
|
||||||
|
|
||||||
|
|
|
@ -61,8 +61,21 @@ zmk_studio_Response get_lock_state(const zmk_studio_Request *req) {
|
||||||
return CORE_RESPONSE(get_lock_state, resp);
|
return CORE_RESPONSE(get_lock_state, resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zmk_studio_Response reset_settings(const zmk_studio_Request *req) {
|
||||||
|
ZMK_RPC_SUBSYSTEM_SETTINGS_RESET_FOREACH(sub) {
|
||||||
|
int ret = sub->callback();
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to reset settings: %d", ret);
|
||||||
|
return CORE_RESPONSE(reset_settings, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CORE_RESPONSE(reset_settings, true);
|
||||||
|
}
|
||||||
|
|
||||||
ZMK_RPC_SUBSYSTEM_HANDLER(core, get_device_info, ZMK_STUDIO_RPC_HANDLER_UNSECURED);
|
ZMK_RPC_SUBSYSTEM_HANDLER(core, get_device_info, ZMK_STUDIO_RPC_HANDLER_UNSECURED);
|
||||||
ZMK_RPC_SUBSYSTEM_HANDLER(core, get_lock_state, ZMK_STUDIO_RPC_HANDLER_UNSECURED);
|
ZMK_RPC_SUBSYSTEM_HANDLER(core, get_lock_state, ZMK_STUDIO_RPC_HANDLER_UNSECURED);
|
||||||
|
ZMK_RPC_SUBSYSTEM_HANDLER(core, reset_settings, ZMK_STUDIO_RPC_HANDLER_SECURED);
|
||||||
|
|
||||||
static int core_event_mapper(const zmk_event_t *eh, zmk_studio_Notification *n) {
|
static int core_event_mapper(const zmk_event_t *eh, zmk_studio_Notification *n) {
|
||||||
struct zmk_studio_core_lock_state_changed *lock_ev = as_zmk_studio_core_lock_state_changed(eh);
|
struct zmk_studio_core_lock_state_changed *lock_ev = as_zmk_studio_core_lock_state_changed(eh);
|
||||||
|
|
539
app/src/studio/keymap_subsystem.c
Normal file
539
app/src/studio/keymap_subsystem.c
Normal file
|
@ -0,0 +1,539 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
|
LOG_MODULE_DECLARE(zmk_studio, CONFIG_ZMK_STUDIO_LOG_LEVEL);
|
||||||
|
|
||||||
|
#include <drivers/behavior.h>
|
||||||
|
|
||||||
|
#include <zmk/behavior.h>
|
||||||
|
#include <zmk/matrix.h>
|
||||||
|
#include <zmk/keymap.h>
|
||||||
|
#include <zmk/studio/rpc.h>
|
||||||
|
#include <zmk/physical_layouts.h>
|
||||||
|
|
||||||
|
#include <pb_encode.h>
|
||||||
|
|
||||||
|
ZMK_RPC_SUBSYSTEM(keymap)
|
||||||
|
|
||||||
|
#define KEYMAP_RESPONSE(type, ...) ZMK_RPC_RESPONSE(keymap, type, __VA_ARGS__)
|
||||||
|
#define KEYMAP_NOTIFICATION(type, ...) ZMK_RPC_NOTIFICATION(keymap, type, __VA_ARGS__)
|
||||||
|
|
||||||
|
static bool encode_layer_bindings(pb_ostream_t *stream, const pb_field_t *field, void *const *arg) {
|
||||||
|
const zmk_keymap_layer_id_t layer_id = *(uint8_t *)*arg;
|
||||||
|
|
||||||
|
for (int b = 0; b < ZMK_KEYMAP_LEN; b++) {
|
||||||
|
const struct zmk_behavior_binding *binding =
|
||||||
|
zmk_keymap_get_layer_binding_at_idx(layer_id, b);
|
||||||
|
|
||||||
|
zmk_keymap_BehaviorBinding bb = zmk_keymap_BehaviorBinding_init_zero;
|
||||||
|
|
||||||
|
if (binding && binding->behavior_dev) {
|
||||||
|
bb.behavior_id = zmk_behavior_get_local_id(binding->behavior_dev);
|
||||||
|
bb.param1 = binding->param1;
|
||||||
|
bb.param2 = binding->param2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pb_encode_tag_for_field(stream, field)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pb_encode_submessage(stream, &zmk_keymap_BehaviorBinding_msg, &bb)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool encode_layer_name(pb_ostream_t *stream, const pb_field_t *field, void *const *arg) {
|
||||||
|
const zmk_keymap_layer_index_t layer_idx = *(uint8_t *)*arg;
|
||||||
|
|
||||||
|
const char *name = zmk_keymap_layer_name(layer_idx);
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pb_encode_tag_for_field(stream, field)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pb_encode_string(stream, name, strlen(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool encode_keymap_layers(pb_ostream_t *stream, const pb_field_t *field, void *const *arg) {
|
||||||
|
for (zmk_keymap_layer_index_t l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) {
|
||||||
|
zmk_keymap_layer_id_t layer_id = zmk_keymap_layer_index_to_id(l);
|
||||||
|
|
||||||
|
if (layer_id == UINT8_MAX) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pb_encode_tag_for_field(stream, field)) {
|
||||||
|
LOG_WRN("Failed to encode tag");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_keymap_Layer layer = zmk_keymap_Layer_init_zero;
|
||||||
|
layer.id = layer_id;
|
||||||
|
|
||||||
|
layer.name.funcs.encode = encode_layer_name;
|
||||||
|
layer.name.arg = &layer_id;
|
||||||
|
|
||||||
|
layer.bindings.funcs.encode = encode_layer_bindings;
|
||||||
|
layer.bindings.arg = &layer_id;
|
||||||
|
|
||||||
|
if (!pb_encode_submessage(stream, &zmk_keymap_Layer_msg, &layer)) {
|
||||||
|
LOG_WRN("Failed to encode layer submessage");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_studio_Response get_keymap(const zmk_studio_Request *req) {
|
||||||
|
zmk_keymap_Keymap resp = zmk_keymap_Keymap_init_zero;
|
||||||
|
|
||||||
|
resp.layers.funcs.encode = encode_keymap_layers;
|
||||||
|
|
||||||
|
resp.available_layers = 0;
|
||||||
|
|
||||||
|
for (zmk_keymap_layer_index_t index = 0; index < ZMK_KEYMAP_LAYERS_LEN; index++) {
|
||||||
|
zmk_keymap_layer_id_t id = zmk_keymap_layer_index_to_id(index);
|
||||||
|
|
||||||
|
if (id == UINT8_MAX) {
|
||||||
|
resp.available_layers = ZMK_KEYMAP_LAYERS_LEN - index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return KEYMAP_RESPONSE(get_keymap, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_studio_Response set_layer_binding(const zmk_studio_Request *req) {
|
||||||
|
const zmk_keymap_SetLayerBindingRequest *set_req =
|
||||||
|
&req->subsystem.keymap.request_type.set_layer_binding;
|
||||||
|
|
||||||
|
zmk_behavior_local_id_t bid = set_req->binding.behavior_id;
|
||||||
|
|
||||||
|
const char *behavior_name = zmk_behavior_find_behavior_name_from_local_id(bid);
|
||||||
|
|
||||||
|
if (!behavior_name) {
|
||||||
|
return KEYMAP_RESPONSE(
|
||||||
|
set_layer_binding,
|
||||||
|
zmk_keymap_SetLayerBindingResponse_SET_LAYER_BINDING_RESP_INVALID_BEHAVIOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct zmk_behavior_binding binding = (struct zmk_behavior_binding){
|
||||||
|
.behavior_dev = behavior_name,
|
||||||
|
.param1 = set_req->binding.param1,
|
||||||
|
.param2 = set_req->binding.param2,
|
||||||
|
};
|
||||||
|
|
||||||
|
int ret = zmk_behavior_validate_binding(&binding);
|
||||||
|
if (ret < 0) {
|
||||||
|
return KEYMAP_RESPONSE(
|
||||||
|
set_layer_binding,
|
||||||
|
zmk_keymap_SetLayerBindingResponse_SET_LAYER_BINDING_RESP_INVALID_PARAMETERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = zmk_keymap_set_layer_binding_at_idx(set_req->layer_id, set_req->key_position, binding);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_WRN("Setting the binding failed with %d", ret);
|
||||||
|
switch (ret) {
|
||||||
|
case -EINVAL:
|
||||||
|
return KEYMAP_RESPONSE(
|
||||||
|
set_layer_binding,
|
||||||
|
zmk_keymap_SetLayerBindingResponse_SET_LAYER_BINDING_RESP_INVALID_LOCATION);
|
||||||
|
default:
|
||||||
|
return ZMK_RPC_SIMPLE_ERR(GENERIC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){
|
||||||
|
.notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, true)});
|
||||||
|
|
||||||
|
return KEYMAP_RESPONSE(set_layer_binding,
|
||||||
|
zmk_keymap_SetLayerBindingResponse_SET_LAYER_BINDING_RESP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_studio_Response check_unsaved_changes(const zmk_studio_Request *req) {
|
||||||
|
int layout_changes = zmk_physical_layouts_check_unsaved_selection();
|
||||||
|
int keymap_changes = zmk_keymap_check_unsaved_changes();
|
||||||
|
|
||||||
|
return KEYMAP_RESPONSE(check_unsaved_changes, layout_changes > 0 || keymap_changes > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_studio_Response save_changes(const zmk_studio_Request *req) {
|
||||||
|
int ret = zmk_physical_layouts_save_selected();
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
return ZMK_RPC_SIMPLE_ERR(GENERIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = zmk_keymap_save_changes();
|
||||||
|
if (ret < 0) {
|
||||||
|
return ZMK_RPC_SIMPLE_ERR(GENERIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){
|
||||||
|
.notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, false)});
|
||||||
|
|
||||||
|
return KEYMAP_RESPONSE(save_changes, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_studio_Response discard_changes(const zmk_studio_Request *req) {
|
||||||
|
int ret = zmk_physical_layouts_revert_selected();
|
||||||
|
if (ret < 0) {
|
||||||
|
return ZMK_RPC_SIMPLE_ERR(GENERIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = zmk_keymap_discard_changes();
|
||||||
|
if (ret < 0) {
|
||||||
|
return ZMK_RPC_SIMPLE_ERR(GENERIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){
|
||||||
|
.notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, false)});
|
||||||
|
|
||||||
|
return KEYMAP_RESPONSE(discard_changes, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int keymap_settings_reset(void) { return zmk_keymap_reset_settings(); }
|
||||||
|
|
||||||
|
ZMK_RPC_SUBSYSTEM_SETTINGS_RESET(keymap, keymap_settings_reset);
|
||||||
|
|
||||||
|
static bool encode_layout_name(pb_ostream_t *stream, const pb_field_t *field, void *const *arg) {
|
||||||
|
struct zmk_physical_layout *layout = (struct zmk_physical_layout *)*arg;
|
||||||
|
|
||||||
|
if (!layout->display_name) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pb_encode_tag_for_field(stream, field)) {
|
||||||
|
LOG_WRN("Failed to encode tag");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pb_encode_string(stream, layout->display_name, strlen(layout->display_name));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool encode_layout_keys(pb_ostream_t *stream, const pb_field_t *field, void *const *arg) {
|
||||||
|
struct zmk_physical_layout *layout = (struct zmk_physical_layout *)*arg;
|
||||||
|
|
||||||
|
for (int kp = 0; kp < layout->keys_len; kp++) {
|
||||||
|
const struct zmk_key_physical_attrs *layout_kp = &layout->keys[kp];
|
||||||
|
|
||||||
|
if (!pb_encode_tag_for_field(stream, field)) {
|
||||||
|
LOG_WRN("Failed to encode tag");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_keymap_KeyPhysicalAttrs layout_kp_msg = {
|
||||||
|
.width = layout_kp->width,
|
||||||
|
.height = layout_kp->height,
|
||||||
|
.x = layout_kp->x,
|
||||||
|
.y = layout_kp->y,
|
||||||
|
.r = layout_kp->r,
|
||||||
|
.rx = layout_kp->rx,
|
||||||
|
.ry = layout_kp->ry,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!pb_encode_submessage(stream, &zmk_keymap_KeyPhysicalAttrs_msg, &layout_kp_msg)) {
|
||||||
|
LOG_WRN("Failed to encode layout key position submessage");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool encode_layouts(pb_ostream_t *stream, const pb_field_t *field, void *const *arg) {
|
||||||
|
struct zmk_physical_layout const *const *layouts;
|
||||||
|
const size_t layout_count = zmk_physical_layouts_get_list(&layouts);
|
||||||
|
|
||||||
|
for (int i = 0; i < layout_count; i++) {
|
||||||
|
const struct zmk_physical_layout *l = layouts[i];
|
||||||
|
|
||||||
|
if (!pb_encode_tag_for_field(stream, field)) {
|
||||||
|
LOG_WRN("Failed to encode tag");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_keymap_PhysicalLayout layout = zmk_keymap_PhysicalLayout_init_zero;
|
||||||
|
|
||||||
|
layout.name.funcs.encode = encode_layout_name;
|
||||||
|
layout.name.arg = l;
|
||||||
|
|
||||||
|
layout.keys.funcs.encode = encode_layout_keys;
|
||||||
|
layout.keys.arg = l;
|
||||||
|
|
||||||
|
if (!pb_encode_submessage(stream, &zmk_keymap_PhysicalLayout_msg, &layout)) {
|
||||||
|
LOG_WRN("Failed to encode layout submessage");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_studio_Response get_physical_layouts(const zmk_studio_Request *req) {
|
||||||
|
zmk_keymap_PhysicalLayouts resp = zmk_keymap_PhysicalLayouts_init_zero;
|
||||||
|
resp.active_layout_index = zmk_physical_layouts_get_selected();
|
||||||
|
resp.layouts.funcs.encode = encode_layouts;
|
||||||
|
return KEYMAP_RESPONSE(get_physical_layouts, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void migrate_keymap(const uint8_t old) {
|
||||||
|
int new = zmk_physical_layouts_get_selected();
|
||||||
|
|
||||||
|
uint32_t new_to_old_map[ZMK_KEYMAP_LEN];
|
||||||
|
int layout_size =
|
||||||
|
zmk_physical_layouts_get_position_map(old, new, ZMK_KEYMAP_LEN, new_to_old_map);
|
||||||
|
|
||||||
|
if (layout_size < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) {
|
||||||
|
struct zmk_behavior_binding new_layer[ZMK_KEYMAP_LEN];
|
||||||
|
|
||||||
|
for (int b = 0; b < layout_size; b++) {
|
||||||
|
uint32_t old_b = new_to_old_map[b];
|
||||||
|
|
||||||
|
if (old_b == UINT32_MAX) {
|
||||||
|
memset(&new_layer[b], 0, sizeof(struct zmk_behavior_binding));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct zmk_behavior_binding *binding =
|
||||||
|
zmk_keymap_get_layer_binding_at_idx(l, old_b);
|
||||||
|
|
||||||
|
if (!binding) {
|
||||||
|
memset(&new_layer[b], 0, sizeof(struct zmk_behavior_binding));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&new_layer[b], binding, sizeof(struct zmk_behavior_binding));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int b = 0; b < layout_size; b++) {
|
||||||
|
zmk_keymap_set_layer_binding_at_idx(l, b, new_layer[b]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Migrate combos?
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_studio_Response set_active_physical_layout(const zmk_studio_Request *req) {
|
||||||
|
uint8_t index = (uint8_t)req->subsystem.keymap.request_type.set_active_physical_layout;
|
||||||
|
int old = zmk_physical_layouts_get_selected();
|
||||||
|
|
||||||
|
zmk_keymap_SetActivePhysicalLayoutResponse resp =
|
||||||
|
zmk_keymap_SetActivePhysicalLayoutResponse_init_zero;
|
||||||
|
resp.which_result = zmk_keymap_SetActivePhysicalLayoutResponse_ok_tag;
|
||||||
|
resp.result.ok.layers.funcs.encode = encode_keymap_layers;
|
||||||
|
|
||||||
|
if (old == index) {
|
||||||
|
return KEYMAP_RESPONSE(set_active_physical_layout, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = zmk_physical_layouts_select(index);
|
||||||
|
if (ret >= 0) {
|
||||||
|
migrate_keymap(old);
|
||||||
|
} else {
|
||||||
|
resp.which_result = zmk_keymap_SetActivePhysicalLayoutResponse_err_tag;
|
||||||
|
resp.result.err =
|
||||||
|
zmk_keymap_SetActivePhysicalLayoutErrorCode_SET_ACTIVE_PHYSICAL_LAYOUT_ERR_GENERIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){
|
||||||
|
.notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, true)});
|
||||||
|
|
||||||
|
return KEYMAP_RESPONSE(set_active_physical_layout, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_studio_Response move_layer(const zmk_studio_Request *req) {
|
||||||
|
const zmk_keymap_MoveLayerRequest *move_req = &req->subsystem.keymap.request_type.move_layer;
|
||||||
|
|
||||||
|
zmk_keymap_MoveLayerResponse resp = zmk_keymap_MoveLayerResponse_init_zero;
|
||||||
|
|
||||||
|
int ret = zmk_keymap_move_layer(move_req->start_index, move_req->dest_index);
|
||||||
|
|
||||||
|
if (ret >= 0) {
|
||||||
|
resp.which_result = zmk_keymap_SetActivePhysicalLayoutResponse_ok_tag;
|
||||||
|
resp.result.ok.layers.funcs.encode = encode_keymap_layers;
|
||||||
|
|
||||||
|
raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){
|
||||||
|
.notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, true)});
|
||||||
|
} else {
|
||||||
|
LOG_WRN("Failed to move layer: %d", ret);
|
||||||
|
resp.which_result = zmk_keymap_MoveLayerResponse_err_tag;
|
||||||
|
resp.result.err = zmk_keymap_MoveLayerErrorCode_MOVE_LAYER_ERR_GENERIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
return KEYMAP_RESPONSE(move_layer, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_studio_Response add_layer(const zmk_studio_Request *req) {
|
||||||
|
// Use a static here to keep the value valid during serialization
|
||||||
|
static zmk_keymap_layer_id_t layer_id = 0;
|
||||||
|
|
||||||
|
zmk_keymap_AddLayerResponse resp = zmk_keymap_AddLayerResponse_init_zero;
|
||||||
|
|
||||||
|
int ret = zmk_keymap_add_layer();
|
||||||
|
|
||||||
|
if (ret >= 0) {
|
||||||
|
layer_id = zmk_keymap_layer_index_to_id(ret);
|
||||||
|
|
||||||
|
resp.which_result = zmk_keymap_AddLayerResponse_ok_tag;
|
||||||
|
|
||||||
|
resp.result.ok.index = ret;
|
||||||
|
|
||||||
|
resp.result.ok.has_layer = true;
|
||||||
|
resp.result.ok.layer.id = layer_id;
|
||||||
|
|
||||||
|
resp.result.ok.layer.name.funcs.encode = encode_layer_name;
|
||||||
|
resp.result.ok.layer.name.arg = &layer_id;
|
||||||
|
|
||||||
|
resp.result.ok.layer.bindings.funcs.encode = encode_layer_bindings;
|
||||||
|
resp.result.ok.layer.bindings.arg = &layer_id;
|
||||||
|
|
||||||
|
raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){
|
||||||
|
.notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, true)});
|
||||||
|
} else {
|
||||||
|
LOG_WRN("Failed to add layer: %d", ret);
|
||||||
|
resp.which_result = zmk_keymap_AddLayerResponse_err_tag;
|
||||||
|
switch (ret) {
|
||||||
|
case -ENOSPC:
|
||||||
|
resp.result.err = zmk_keymap_AddLayerErrorCode_ADD_LAYER_ERR_NO_SPACE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
resp.result.err = zmk_keymap_AddLayerErrorCode_ADD_LAYER_ERR_GENERIC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return KEYMAP_RESPONSE(add_layer, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_studio_Response remove_layer(const zmk_studio_Request *req) {
|
||||||
|
const zmk_keymap_RemoveLayerRequest *rm_req = &req->subsystem.keymap.request_type.remove_layer;
|
||||||
|
|
||||||
|
zmk_keymap_RemoveLayerResponse resp = zmk_keymap_RemoveLayerResponse_init_zero;
|
||||||
|
|
||||||
|
int ret = zmk_keymap_remove_layer(rm_req->layer_index);
|
||||||
|
|
||||||
|
if (ret >= 0) {
|
||||||
|
resp.which_result = zmk_keymap_RemoveLayerResponse_ok_tag;
|
||||||
|
|
||||||
|
raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){
|
||||||
|
.notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, true)});
|
||||||
|
} else {
|
||||||
|
LOG_WRN("Failed to rm layer: %d", ret);
|
||||||
|
resp.which_result = zmk_keymap_RemoveLayerResponse_err_tag;
|
||||||
|
switch (ret) {
|
||||||
|
case -EINVAL:
|
||||||
|
resp.result.err = zmk_keymap_RemoveLayerErrorCode_REMOVE_LAYER_ERR_INVALID_INDEX;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
resp.result.err = zmk_keymap_RemoveLayerErrorCode_REMOVE_LAYER_ERR_GENERIC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return KEYMAP_RESPONSE(remove_layer, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_studio_Response restore_layer(const zmk_studio_Request *req) {
|
||||||
|
const zmk_keymap_RestoreLayerRequest *restore_req =
|
||||||
|
&req->subsystem.keymap.request_type.restore_layer;
|
||||||
|
|
||||||
|
zmk_keymap_RestoreLayerResponse resp = zmk_keymap_RestoreLayerResponse_init_zero;
|
||||||
|
|
||||||
|
int ret = zmk_keymap_restore_layer(restore_req->layer_id, restore_req->at_index);
|
||||||
|
|
||||||
|
if (ret >= 0) {
|
||||||
|
resp.which_result = zmk_keymap_RemoveLayerResponse_ok_tag;
|
||||||
|
resp.result.ok.id = restore_req->layer_id;
|
||||||
|
|
||||||
|
resp.result.ok.name.funcs.encode = encode_layer_name;
|
||||||
|
resp.result.ok.name.arg = &restore_req->layer_id;
|
||||||
|
|
||||||
|
resp.result.ok.bindings.funcs.encode = encode_layer_bindings;
|
||||||
|
resp.result.ok.bindings.arg = &restore_req->layer_id;
|
||||||
|
|
||||||
|
raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){
|
||||||
|
.notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, true)});
|
||||||
|
} else {
|
||||||
|
LOG_WRN("Failed to restore layer: %d", ret);
|
||||||
|
resp.which_result = zmk_keymap_RestoreLayerResponse_err_tag;
|
||||||
|
switch (ret) {
|
||||||
|
case -EINVAL:
|
||||||
|
resp.result.err = zmk_keymap_RestoreLayerErrorCode_RESTORE_LAYER_ERR_INVALID_INDEX;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
resp.result.err = zmk_keymap_RestoreLayerErrorCode_RESTORE_LAYER_ERR_GENERIC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return KEYMAP_RESPONSE(restore_layer, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_studio_Response set_layer_props(const zmk_studio_Request *req) {
|
||||||
|
const zmk_keymap_SetLayerPropsRequest *set_req =
|
||||||
|
&req->subsystem.keymap.request_type.set_layer_props;
|
||||||
|
|
||||||
|
zmk_keymap_SetLayerPropsResponse resp =
|
||||||
|
zmk_keymap_SetLayerPropsResponse_SET_LAYER_PROPS_RESP_OK;
|
||||||
|
|
||||||
|
if (strlen(set_req->name) <= 0) {
|
||||||
|
return KEYMAP_RESPONSE(set_layer_props, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = zmk_keymap_set_layer_name(set_req->layer_id, set_req->name, strlen(set_req->name));
|
||||||
|
|
||||||
|
if (ret >= 0) {
|
||||||
|
|
||||||
|
raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){
|
||||||
|
.notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, true)});
|
||||||
|
} else {
|
||||||
|
LOG_WRN("Failed to set layer props: %d", ret);
|
||||||
|
switch (ret) {
|
||||||
|
case -EINVAL:
|
||||||
|
resp = zmk_keymap_SetLayerPropsResponse_SET_LAYER_PROPS_RESP_ERR_INVALID_ID;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
resp = zmk_keymap_SetLayerPropsResponse_SET_LAYER_PROPS_RESP_ERR_GENERIC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return KEYMAP_RESPONSE(set_layer_props, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZMK_RPC_SUBSYSTEM_HANDLER(keymap, get_keymap, ZMK_STUDIO_RPC_HANDLER_SECURED);
|
||||||
|
ZMK_RPC_SUBSYSTEM_HANDLER(keymap, set_layer_binding, ZMK_STUDIO_RPC_HANDLER_SECURED);
|
||||||
|
ZMK_RPC_SUBSYSTEM_HANDLER(keymap, check_unsaved_changes, ZMK_STUDIO_RPC_HANDLER_SECURED);
|
||||||
|
ZMK_RPC_SUBSYSTEM_HANDLER(keymap, save_changes, ZMK_STUDIO_RPC_HANDLER_SECURED);
|
||||||
|
ZMK_RPC_SUBSYSTEM_HANDLER(keymap, discard_changes, ZMK_STUDIO_RPC_HANDLER_SECURED);
|
||||||
|
ZMK_RPC_SUBSYSTEM_HANDLER(keymap, get_physical_layouts, ZMK_STUDIO_RPC_HANDLER_SECURED);
|
||||||
|
ZMK_RPC_SUBSYSTEM_HANDLER(keymap, set_active_physical_layout, ZMK_STUDIO_RPC_HANDLER_SECURED);
|
||||||
|
ZMK_RPC_SUBSYSTEM_HANDLER(keymap, move_layer, ZMK_STUDIO_RPC_HANDLER_SECURED);
|
||||||
|
ZMK_RPC_SUBSYSTEM_HANDLER(keymap, add_layer, ZMK_STUDIO_RPC_HANDLER_SECURED);
|
||||||
|
ZMK_RPC_SUBSYSTEM_HANDLER(keymap, remove_layer, ZMK_STUDIO_RPC_HANDLER_SECURED);
|
||||||
|
ZMK_RPC_SUBSYSTEM_HANDLER(keymap, restore_layer, ZMK_STUDIO_RPC_HANDLER_SECURED);
|
||||||
|
ZMK_RPC_SUBSYSTEM_HANDLER(keymap, set_layer_props, ZMK_STUDIO_RPC_HANDLER_SECURED);
|
||||||
|
|
||||||
|
static int event_mapper(const zmk_event_t *eh, zmk_studio_Notification *n) { return 0; }
|
||||||
|
|
||||||
|
ZMK_RPC_EVENT_MAPPER(keymap, event_mapper);
|
|
@ -1,8 +1,8 @@
|
||||||
pos_state: layer: 0 position: 0, binding name: abc_macro
|
pos_state: layer_id: 0 position: 0, binding name: abc_macro
|
||||||
kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||||
pos_state: layer: 0 position: 0, binding name: abc_macro
|
pos_state: layer_id: 0 position: 0, binding name: abc_macro
|
||||||
pos_state: layer: 0 position: 1, binding name: momentary_layer
|
pos_state: layer_id: 0 position: 1, binding name: momentary_layer
|
||||||
pos_state: layer: 0 position: 1, binding name: momentary_layer
|
pos_state: layer_id: 0 position: 1, binding name: momentary_layer
|
||||||
kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||||
kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||||
kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
|
|
@ -34,7 +34,7 @@ manifest:
|
||||||
path: modules/lib/nanopb
|
path: modules/lib/nanopb
|
||||||
remote: zephyrproject-rtos
|
remote: zephyrproject-rtos
|
||||||
- name: zmk-studio-messages
|
- name: zmk-studio-messages
|
||||||
revision: 42446798e357e8021c5202a01ea250a34a776e85
|
revision: a79267a9661241a6603b6da3d2b3f71e8023a9d9
|
||||||
path: modules/msgs/zmk-studio-messages
|
path: modules/msgs/zmk-studio-messages
|
||||||
remote: zmkfirmware
|
remote: zmkfirmware
|
||||||
self:
|
self:
|
||||||
|
|
Loading…
Add table
Reference in a new issue