Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_MOUSE_KEY_PRESS app PRIVATE src/behaviors/behavior_mouse_key_press.c)
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_STUDIO_UNLOCK app PRIVATE src/behaviors/behavior_studio_unlock.c)
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_INPUT_TWO_AXIS app PRIVATE src/behaviors/behavior_input_two_axis.c)
target_sources(app PRIVATE src/combo.c)
target_sources_ifdef(CONFIG_ZMK_COMBOS app PRIVATE src/combo.c)
target_sources_ifdef(CONFIG_ZMK_COMBOS_RUNTIME_SHELL_CMD app PRIVATE src/combos_cmd.c)
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_TAP_DANCE app PRIVATE src/behaviors/behavior_tap_dance.c)
target_sources(app PRIVATE src/behavior_queue.c)
target_sources(app PRIVATE src/conditional_layer.c)
Expand Down Expand Up @@ -107,6 +108,8 @@ target_sources_ifdef(CONFIG_ZMK_LOW_PRIORITY_WORK_QUEUE app PRIVATE src/workqueu
target_sources(app PRIVATE src/main.c)

add_subdirectory(src/display/)
add_subdirectory(src/shell/)

add_subdirectory_ifdef(CONFIG_SETTINGS src/settings/)

if (CONFIG_ZMK_STUDIO_RPC)
Expand All @@ -124,6 +127,7 @@ if (CONFIG_ZMK_STUDIO_RPC)
${ZEPHYR_ZMK_STUDIO_MESSAGES_MODULE_DIR}/proto/zmk/core.proto
${ZEPHYR_ZMK_STUDIO_MESSAGES_MODULE_DIR}/proto/zmk/behaviors.proto
${ZEPHYR_ZMK_STUDIO_MESSAGES_MODULE_DIR}/proto/zmk/keymap.proto
${ZEPHYR_ZMK_STUDIO_MESSAGES_MODULE_DIR}/proto/zmk/combos.proto
)

target_include_directories(app PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
Expand Down
17 changes: 2 additions & 15 deletions app/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -434,21 +434,7 @@ endmenu

menu "Combo options"

config ZMK_COMBO_MAX_PRESSED_COMBOS
int "Maximum number of currently pressed combos"
default 4

config ZMK_COMBO_MAX_COMBOS_PER_KEY
int "Deprecated: Max combos per key"
default 0
help
Deprecated: Storage for combos is now determined automatically

config ZMK_COMBO_MAX_KEYS_PER_COMBO
int "Deprecated: Max keys per combo"
default 0
help
Deprecated: This is now auto-calculated based on `key-positions` in devicetree
rsource "Kconfig.combos"

# Combo options
endmenu
Expand All @@ -474,6 +460,7 @@ endmenu
menu "Advanced"

rsource "src/boot/Kconfig"
rsource "src/shell/Kconfig"

menu "Initialization Priorities"

Expand Down
44 changes: 44 additions & 0 deletions app/Kconfig.combos
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright (c) 2020 The ZMK Contributors
# SPDX-License-Identifier: MIT

menuconfig ZMK_COMBOS
bool "Combos"
default y
depends on DT_HAS_ZMK_COMBOS_ENABLED

if ZMK_COMBOS

config ZMK_COMBO_MAX_PRESSED_COMBOS
int "Maximum number of currently pressed combos"
default 4

config ZMK_COMBO_MAX_COMBOS_PER_KEY
int "Deprecated: Max combos per key"
default 0
help
Deprecated: Storage for combos is now determined automatically

config ZMK_COMBO_MAX_KEYS_PER_COMBO
int "Deprecated: Max keys per combo"
default 0
help
Deprecated: This is now auto-calculated based on `key-positions` in devicetree

config ZMK_COMBOS_RUNTIME
bool "Runtime combo updates"

if ZMK_COMBOS_RUNTIME

config ZMK_COMBOS_RUNTIME_SETTINGS_STORAGE
bool "Save/restore runtime combos using settings"
default y
depends on SETTINGS

config ZMK_COMBOS_RUNTIME_SHELL_CMD
bool "Combos shell command"
default y
depends on SHELL

endif

endif
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@

#include <zephyr/linker/linker-defs.h>

ITERABLE_SECTION_ROM(zmk_rpc_subsystem_settings_reset, 4)
ITERABLE_SECTION_ROM(zmk_rpc_subsystem_persistence, 4)
6 changes: 6 additions & 0 deletions app/include/zmk/behavior.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ struct zmk_behavior_binding_event {
#endif
};

struct zmk_behavior_binding_setting {
zmk_behavior_local_id_t behavior_local_id;
uint32_t param1;
uint32_t param2;
} __packed;

/**
* @brief Get a const struct device* for a behavior from its @p name field.
*
Expand Down
74 changes: 73 additions & 1 deletion app/include/zmk/combos.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,82 @@
#pragma once

#include <zephyr/devicetree.h>
#include <zmk/behavior.h>

#define ZMK_COMBOS_UTIL_ONE(n) +1

#define ZMK_COMBOS_LEN \
#define ZMK_COMBOS_FOREACH(_fn) \
COND_CODE_1(IS_ENABLED(CONFIG_ZMK_COMBOS_RUNTIME), \
(DT_FOREACH_CHILD(DT_INST(0, zmk_combos), _fn)), \
(DT_FOREACH_CHILD_STATUS_OKAY(DT_INST(0, zmk_combos), _fn)))

#define ZMK_COMBOS_FOREACH_SEP(_fn, _sep) \
COND_CODE_1(IS_ENABLED(CONFIG_ZMK_COMBOS_RUNTIME), \
(DT_FOREACH_CHILD_SEP(DT_INST(0, zmk_combos), _fn, _sep)), \
(DT_FOREACH_CHILD_STATUS_OKAY_SEP(DT_INST(0, zmk_combos), _fn, _sep)))

#define ZMK_STATIC_COMBOS_LEN \
COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(zmk_combos), \
(0 DT_FOREACH_CHILD_STATUS_OKAY(DT_INST(0, zmk_combos), ZMK_COMBOS_UTIL_ONE)), \
(0))

#define ZMK_COMBOS_LEN \
COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(zmk_combos), \
(0 ZMK_COMBOS_FOREACH(ZMK_COMBOS_UTIL_ONE)), (0))

#define COMBOS_KEYS_BYTE_ARRAY(node_id) \
uint8_t _CONCAT(combo_prop_, node_id)[DT_PROP_LEN_OR(node_id, key_positions, 0)];

#define MAX_COMBO_KEYS \
COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(zmk_combos), \
(sizeof(union {ZMK_COMBOS_FOREACH(COMBOS_KEYS_BYTE_ARRAY)})), (0))

struct combo_cfg {
uint16_t key_positions[MAX_COMBO_KEYS];
int16_t key_position_len;
int16_t require_prior_idle_ms;
int32_t timeout_ms;
uint32_t layer_mask;
struct zmk_behavior_binding behavior;
// if slow release is set, the combo releases when the last key is released.
// otherwise, the combo releases when the first key is released.
bool slow_release;
};

#if IS_ENABLED(CONFIG_ZMK_COMBOS_RUNTIME)

typedef int zmk_combo_runtime_id_t;

struct zmk_combo_runtime {
zmk_combo_runtime_id_t id;
struct combo_cfg combo;
};

bool zmk_combos_check_unsaved_changes(void);
int zmk_combos_reset_settings(void);
int zmk_combos_save_changes(void);
int zmk_combos_discard_changes(void);
// TODO: Document
// Returns non-negative combo ID value on success
// Returns negative errno on error
int zmk_combo_runtime_add_combo(const struct combo_cfg *cfg);
int zmk_combo_runtime_remove_combo(zmk_combo_runtime_id_t combo_id);

int zmk_combo_runtime_set_combo_binding(zmk_combo_runtime_id_t combo_id,
const struct zmk_behavior_binding *binding);
int zmk_combo_runtime_add_combo_position(zmk_combo_runtime_id_t combo_id, uint16_t position);
int zmk_combo_runtime_remove_combo_position(zmk_combo_runtime_id_t combo_id, uint16_t position);

int zmk_combo_runtime_clear_combo_layers(zmk_combo_runtime_id_t combo_id);
int zmk_combo_runtime_set_combo_layer(zmk_combo_runtime_id_t combo_id, uint8_t layer, bool enabled);

int zmk_combo_runtime_set_combo_timeout(zmk_combo_runtime_id_t combo_id, uint16_t timeout);
int zmk_combo_runtime_set_combo_prior_idle(zmk_combo_runtime_id_t combo_id, uint16_t prior_idle);
int zmk_combo_runtime_set_combo_slow_release(zmk_combo_runtime_id_t combo_id, bool enabled);

int zmk_combo_runtime_get_combos(const struct zmk_combo_runtime **list);
const struct zmk_combo_runtime *zmk_combo_runtime_get_combo(zmk_combo_runtime_id_t combo_id);

int zmk_combo_runtime_get_free_combos(void);

#endif
6 changes: 3 additions & 3 deletions app/include/zmk/keymap.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ int zmk_keymap_set_layer_name(zmk_keymap_layer_id_t id, const char *name, size_t
/**
* @brief Check if there are any unsaved keymap changes.
*
* @retval 0 if there are no changes.
* @retval 1 if there are changes.
* @retval true if there are no changes.
* @retval false if there are changes.
*/
int zmk_keymap_check_unsaved_changes(void);
bool zmk_keymap_check_unsaved_changes(void);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

has_unsaved_changes seems like a better naming convention, with the boolean returns inverted.


int zmk_keymap_save_changes(void);
int zmk_keymap_discard_changes(void);
Expand Down
2 changes: 1 addition & 1 deletion app/include/zmk/physical_layouts.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ size_t zmk_physical_layouts_get_list(struct zmk_physical_layout const *const **p
int zmk_physical_layouts_select(uint8_t index);
int zmk_physical_layouts_get_selected(void);

int zmk_physical_layouts_check_unsaved_selection(void);
bool zmk_physical_layouts_check_unsaved_selection(void);
int zmk_physical_layouts_save_selected(void);
int zmk_physical_layouts_revert_selected(void);

Expand Down
25 changes: 15 additions & 10 deletions app/include/zmk/studio/rpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,16 @@ struct zmk_rpc_subsystem_handler {
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;
typedef int (*zmk_rpc_subsystem_reset_settings_func_t)(void);
typedef int (*zmk_rpc_subsystem_discard_changes_func_t)(void);
typedef bool (*zmk_rpc_subsystem_check_unsaved_changes_func_t)(void);
typedef int (*zmk_rpc_subsystem_save_changes_func_t)(void);

struct zmk_rpc_subsystem_persistence {
zmk_rpc_subsystem_reset_settings_func_t reset_settings;
zmk_rpc_subsystem_check_unsaved_changes_func_t check_unsaved_changes;
zmk_rpc_subsystem_save_changes_func_t save_changes;
zmk_rpc_subsystem_discard_changes_func_t discard_changes;
};

/**
Expand Down Expand Up @@ -109,13 +115,12 @@ struct zmk_rpc_subsystem_settings_reset {
.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_PERSISTENCE(prefix, ...) \
STRUCT_SECTION_ITERABLE(zmk_rpc_subsystem_persistence, \
_##prefix##_settings_reset) = {__VA_ARGS__};

#define ZMK_RPC_SUBSYSTEM_SETTINGS_RESET_FOREACH(_var) \
STRUCT_SECTION_FOREACH(zmk_rpc_subsystem_settings_reset, _var)
#define ZMK_RPC_SUBSYSTEM_PERSISTENCE_FOREACH(_var) \
STRUCT_SECTION_FOREACH(zmk_rpc_subsystem_persistence, _var)

/**
* @brief Create a zmk_studio_Notification struct for the given subsystem and type, including
Expand Down
Loading