fix: Optimize layout changes by doing runtime mapping

* To avoid tons of migration, extra flash writes, etc, we keep
  the keymaps and settings using a key position index that's tied
  to the stock layout, and at runtime mapping key positions as
  needed.
This commit is contained in:
Peter Johanson
2024-10-17 12:24:43 -06:00
committed by Pete Johanson
parent a6d09f8c00
commit ea1a09bf99
4 changed files with 115 additions and 57 deletions

View File

@@ -18,6 +18,7 @@
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/matrix.h>
#include <zmk/physical_layouts.h>
#include <zmk/event_manager.h>
#include <zmk/events/position_state_changed.h>
@@ -213,6 +214,35 @@ static void zmk_physical_layouts_kscan_process_msgq(struct k_work *item) {
}
}
static const struct zmk_physical_layout *get_default_layout(void) {
const struct zmk_physical_layout *initial;
#if USE_PHY_LAYOUTS && DT_HAS_CHOSEN(zmk_physical_layout)
initial = &_CONCAT(_zmk_physical_layout_, DT_CHOSEN(zmk_physical_layout));
#else
initial = layouts[0];
#endif
return initial;
}
static int get_index_of_layout(const struct zmk_physical_layout *layout) {
for (int i = 0; i < ARRAY_SIZE(layouts); i++) {
if (layouts[i] == layout) {
return i;
}
}
return -ENODEV;
}
static uint32_t selected_to_stock_map[ZMK_KEYMAP_LEN];
int zmk_physical_layouts_get_selected_to_stock_position_map(uint32_t const **map) {
*map = selected_to_stock_map;
return ZMK_KEYMAP_LEN;
}
int zmk_physical_layouts_select_layout(const struct zmk_physical_layout *dest_layout) {
if (!dest_layout) {
return -ENODEV;
@@ -233,6 +263,15 @@ int zmk_physical_layouts_select_layout(const struct zmk_physical_layout *dest_la
}
}
int new_idx = get_index_of_layout(dest_layout);
int stock_idx = get_index_of_layout(get_default_layout());
int ret = zmk_physical_layouts_get_position_map(stock_idx, new_idx, ZMK_KEYMAP_LEN,
selected_to_stock_map);
if (ret < 0) {
LOG_ERR("Failed to refresh the selected to stock mapping (%d)", ret);
return ret;
}
active = dest_layout;
if (active->kscan) {
@@ -284,15 +323,7 @@ static int8_t saved_selected_index = -1;
#endif
int zmk_physical_layouts_select_initial(void) {
const struct zmk_physical_layout *initial;
#if USE_PHY_LAYOUTS && DT_HAS_CHOSEN(zmk_physical_layout)
initial = &_CONCAT(_zmk_physical_layout_, DT_CHOSEN(zmk_physical_layout));
#else
initial = layouts[0];
#endif
int ret = zmk_physical_layouts_select_layout(initial);
int ret = zmk_physical_layouts_select_layout(get_default_layout());
return ret;
}
@@ -326,6 +357,14 @@ int zmk_physical_layouts_get_position_map(uint8_t source, uint8_t dest, size_t m
return -EINVAL;
}
if (source == dest) {
for (int i = 0; i < map_size; i++) {
map[i] = i;
}
return 0;
}
const struct zmk_physical_layout *src_layout = layouts[source];
const struct zmk_physical_layout *dest_layout = layouts[dest];
int max_kp = dest_layout->keys_len;
@@ -435,6 +474,11 @@ static int zmk_physical_layouts_init(void) {
}
#endif // IS_ENABLED(CONFIG_PM_DEVICE)
// Initialize a sane mapping
for (int i = 0; i < ZMK_KEYMAP_LEN; i++) {
selected_to_stock_map[i] = i;
}
return zmk_physical_layouts_select_initial();
}