add enable-while-keys, remove &capslock_word

This commit is contained in:
snoyer 2023-12-02 20:14:14 +04:00
parent 8337f595b4
commit 3be50897c7
4 changed files with 57 additions and 53 deletions

View file

@ -33,16 +33,6 @@
disable-on-release; disable-on-release;
}; };
/omit-if-no-ref/ capslock_word: behavior_capslock_word {
compatible = "zmk,behavior-capslock";
label = "CAPSLOCK_WORD";
#binding-cells = <0>;
capslock-press-duration = <5>;
enable-on-press;
disable-on-next-release;
disable-on-keys = <SPACE TAB ENTER ESC>;
};
/* MacOS compatibility */ /* MacOS compatibility */
/omit-if-no-ref/ capslock_on_mac: behavior_capslock_on_mac { /omit-if-no-ref/ capslock_on_mac: behavior_capslock_on_mac {
@ -70,15 +60,5 @@
disable-on-release; disable-on-release;
}; };
/omit-if-no-ref/ capslock_word_mac: behavior_capslock_word_mac {
compatible = "zmk,behavior-capslock";
label = "CAPSLOCK_WORD_MAC";
#binding-cells = <0>;
capslock-press-duration = <95>;
enable-on-press;
disable-on-next-release;
disable-on-keys = <SPACE TAB ENTER ESC>;
};
}; };
}; };

View file

@ -18,6 +18,10 @@ properties:
type: array type: array
required: false required: false
default: [] default: []
enable-while-keys:
type: array
required: false
default: []
capslock-press-keycode: capslock-press-keycode:
type: int type: int
default: 0 # will default to `CAPSLOCK` default: 0 # will default to `CAPSLOCK`

View file

@ -31,6 +31,10 @@ struct capslock_key_item {
uint32_t id; uint32_t id;
uint8_t implicit_modifiers; uint8_t implicit_modifiers;
}; };
struct capslock_key_list {
const struct capslock_key_item *keys;
size_t len;
};
struct behavior_capslock_config { struct behavior_capslock_config {
uint8_t index; uint8_t index;
@ -39,8 +43,8 @@ struct behavior_capslock_config {
bool enable_on_press; bool enable_on_press;
bool disable_on_release; bool disable_on_release;
bool disable_on_next_release; bool disable_on_next_release;
uint8_t disable_on_keys_count; struct capslock_key_list disable_on_keys;
struct capslock_key_item disable_on_keys[]; struct capslock_key_list enable_while_keys;
}; };
uint32_t config_capslock_press_keycode(const struct behavior_capslock_config *config) { uint32_t config_capslock_press_keycode(const struct behavior_capslock_config *config) {
@ -135,12 +139,11 @@ static int on_capslock_binding_released(struct zmk_behavior_binding *binding,
return ZMK_BEHAVIOR_OPAQUE; return ZMK_BEHAVIOR_OPAQUE;
} }
static bool capslock_match_key_item(const struct capslock_key_item *key_items, static bool capslock_match_key_item(const struct capslock_key_list list, uint16_t usage_page,
const size_t key_items_count, uint16_t usage_page,
uint8_t usage_id, uint8_t implicit_modifiers) { uint8_t usage_id, uint8_t implicit_modifiers) {
for (int i = 0; i < key_items_count; ++i) { for (int i = 0; i < list.len; ++i) {
const struct capslock_key_item *break_item = &key_items[i]; const struct capslock_key_item *break_item = &list.keys[i];
LOG_DBG("checking disable-on-keys: usage_page 0x%02X keycode 0x%02X", break_item->page, LOG_DBG("checking key_list item: usage_page 0x%02X keycode 0x%02X", break_item->page,
break_item->id); break_item->id);
if (break_item->page == usage_page && break_item->id == usage_id && if (break_item->page == usage_page && break_item->id == usage_id &&
(break_item->implicit_modifiers & (implicit_modifiers | zmk_hid_get_explicit_mods())) == (break_item->implicit_modifiers & (implicit_modifiers | zmk_hid_get_explicit_mods())) ==
@ -180,12 +183,23 @@ static int capslock_keycode_state_changed_listener(const zmk_event_t *eh) {
ev->usage_page, ev->keycode); ev->usage_page, ev->keycode);
data->active = false; data->active = false;
} }
} else if (capslock_match_key_item(config->disable_on_keys, config->disable_on_keys_count, } else if (config->disable_on_keys.len > 0) {
ev->usage_page, ev->keycode, ev->implicit_modifiers)) { LOG_DBG("checking %d disable-on-keys for usage_page 0x%02X keycode 0x%02X",
LOG_DBG("deactivating capslock (disable-on-keys: usage_page 0x%02X keycode 0x%02X)", config->disable_on_keys.len, ev->usage_page, ev->keycode);
ev->usage_page, ev->keycode); if (capslock_match_key_item(config->disable_on_keys, ev->usage_page, ev->keycode,
ev->implicit_modifiers)) {
LOG_DBG("deactivating capslock (disable-on-keys)");
deactivate_capslock(dev); deactivate_capslock(dev);
} }
} else if (config->enable_while_keys.len > 0) {
LOG_DBG("checking %d enable-while-keys for usage_page 0x%02X keycode 0x%02X",
config->enable_while_keys.len, ev->usage_page, ev->keycode);
if (!capslock_match_key_item(config->enable_while_keys, ev->usage_page, ev->keycode,
ev->implicit_modifiers)) {
LOG_DBG("deactivating capslock (enable-while-keys)");
deactivate_capslock(dev);
}
}
} }
return ZMK_EV_EVENT_BUBBLE; return ZMK_EV_EVENT_BUBBLE;
@ -210,9 +224,19 @@ static int behavior_capslock_init(const struct device *dev) {
.id = ZMK_HID_USAGE_ID(i), \ .id = ZMK_HID_USAGE_ID(i), \
.implicit_modifiers = SELECT_MODS(i)}, .implicit_modifiers = SELECT_MODS(i)},
#define BREAK_ITEM(i, n) PARSE_KEY_ITEM(DT_INST_PROP_BY_IDX(n, disable_on_keys, i)) #define KEY_ARRAY_ITEM(i, n, prop) PARSE_KEY_ITEM(DT_INST_PROP_BY_IDX(n, prop, i))
#define KEY_LIST_PROP(n, prop) \
COND_CODE_1(DT_NODE_HAS_PROP(DT_DRV_INST(n), prop), \
({LISTIFY(DT_INST_PROP_LEN(n, prop), KEY_ARRAY_ITEM, (), n, prop)}), ({}))
#define KEY_LIST(array) ((struct capslock_key_list){.keys = array, .len = ARRAY_SIZE(array)})
#define CAPSLOCK_INST(n) \ #define CAPSLOCK_INST(n) \
static const struct capslock_key_item capslock_disable_on_keys_list_##n[] = \
KEY_LIST_PROP(n, disable_on_keys); \
static const struct capslock_key_item capslock_enable_while_keys_list_##n[] = \
KEY_LIST_PROP(n, enable_while_keys); \
static struct behavior_capslock_data behavior_capslock_data_##n = {.active = false}; \ static struct behavior_capslock_data behavior_capslock_data_##n = {.active = false}; \
static struct behavior_capslock_config behavior_capslock_config_##n = { \ static struct behavior_capslock_config behavior_capslock_config_##n = { \
.index = n, \ .index = n, \
@ -221,8 +245,8 @@ static int behavior_capslock_init(const struct device *dev) {
.enable_on_press = DT_INST_PROP(n, enable_on_press), \ .enable_on_press = DT_INST_PROP(n, enable_on_press), \
.disable_on_release = DT_INST_PROP(n, disable_on_release), \ .disable_on_release = DT_INST_PROP(n, disable_on_release), \
.disable_on_next_release = DT_INST_PROP(n, disable_on_next_release), \ .disable_on_next_release = DT_INST_PROP(n, disable_on_next_release), \
.disable_on_keys = {UTIL_LISTIFY(DT_INST_PROP_LEN(n, disable_on_keys), BREAK_ITEM, n)}, \ .disable_on_keys = KEY_LIST(capslock_disable_on_keys_list_##n), \
.disable_on_keys_count = DT_INST_PROP_LEN(n, disable_on_keys), \ .enable_while_keys = KEY_LIST(capslock_enable_while_keys_list_##n), \
}; \ }; \
DEVICE_DT_INST_DEFINE(n, behavior_capslock_init, NULL, &behavior_capslock_data_##n, \ DEVICE_DT_INST_DEFINE(n, behavior_capslock_init, NULL, &behavior_capslock_data_##n, \
&behavior_capslock_config_##n, APPLICATION, \ &behavior_capslock_config_##n, APPLICATION, \

View file

@ -11,14 +11,13 @@ This behavior can account for the current state to offer more control on how and
### Behavior Binding ### Behavior Binding
Four pre-configured instances are provided: Three pre-configured instances are provided:
- `&capslock_on` enables caps lock - `&capslock_on` enables caps lock
- `&capslock_off` disables caps lock - `&capslock_off` disables caps lock
- `&capslock_hold` enables caps lock while held, and disables it when released - `&capslock_hold` enables caps lock while held, and disables it when released
- `&capslock_word` enables caps lock, and disables it when a word separator is typed or the key is pressed again
In order to ensure compatibility with MacOS (which ignores short capslock presses by design), `&capslock_on_mac`, `&capslock_off_mac`, `&capslock_hold_mac`, `&capslock_word_mac` versions using a longer press duration of 95ms are also available. In order to ensure compatibility with MacOS (which ignores short capslock presses by design), `&capslock_on_mac`, `&capslock_off_mac`, `&capslock_hold_mac` versions using a longer press duration of 95ms are also available.
### Configuration ### Configuration
@ -28,11 +27,12 @@ The following options allow to customize the capslock behavior:
- `disable-on-release`: disable caps lock when the key is released - `disable-on-release`: disable caps lock when the key is released
- `disable-on-next-release`: disable caps lock when the key is released a second time - `disable-on-next-release`: disable caps lock when the key is released a second time
- `disable-on-keys`: list of keys after which to disable capslock - `disable-on-keys`: list of keys after which to disable capslock
- `enable-while-keys`: list of keys for which to keep capslock enabled
- `capslock-press-duration`: duration of the capslock key press to generate (in milliseconds) - `capslock-press-duration`: duration of the capslock key press to generate (in milliseconds)
### Examples ### Examples
The pre-configured `capslock_word` (which enables caps lock when pressed, and disables it when `SPACE`, `TAB`, `ENTER`, or `ESC` is pressed, or the key is pressed again) is defined as follow: In order to create a `capslock_word` key which enables caps lock when pressed, and disables it when `SPACE`, `TAB`, `ENTER`, or `ESC` is pressed, or the key is pressed again, a custom instance can be defined as follows:
``` ```
capslock_word: behavior_capslock_word { capslock_word: behavior_capslock_word {
@ -46,20 +46,16 @@ capslock_word: behavior_capslock_word {
}; };
``` ```
A key to activate caps lock and disable it only after typing a whole line can be defined as follow: In order to define a similar key using a list keys for which capslock should be kept enabled, akin to the `&caps_word`'s `continue-list`, the `enable-while-keys` proerty can be used instead of `disable-on-keys` (note that, unlike `&caps_word`, this behavior does not use any implicit whitelist so an exhaustive contination list must be provided):
``` ```
/ { capslock_word: behavior_capslock_word {
capslock_line: capslock_line {
compatible = "zmk,behavior-capslock"; compatible = "zmk,behavior-capslock";
label = "CAPSLOCK_LINE"; label = "CAPSLOCK_WORD";
#binding-cells = <0>; #binding-cells = <0>;
capslock-press-ms = <5>;
enable-on-press; enable-on-press;
disable-on-keys = <ENTER ESC>; disable-on-next-release;
}; enable-while-keys = <A B C ... Z ...>;
keymap {
...
};
}; };
``` ```