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;
};
/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 */
/omit-if-no-ref/ capslock_on_mac: behavior_capslock_on_mac {
@ -70,15 +60,5 @@
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
required: false
default: []
enable-while-keys:
type: array
required: false
default: []
capslock-press-keycode:
type: int
default: 0 # will default to `CAPSLOCK`

View file

@ -31,6 +31,10 @@ struct capslock_key_item {
uint32_t id;
uint8_t implicit_modifiers;
};
struct capslock_key_list {
const struct capslock_key_item *keys;
size_t len;
};
struct behavior_capslock_config {
uint8_t index;
@ -39,8 +43,8 @@ struct behavior_capslock_config {
bool enable_on_press;
bool disable_on_release;
bool disable_on_next_release;
uint8_t disable_on_keys_count;
struct capslock_key_item disable_on_keys[];
struct capslock_key_list disable_on_keys;
struct capslock_key_list enable_while_keys;
};
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;
}
static bool capslock_match_key_item(const struct capslock_key_item *key_items,
const size_t key_items_count, uint16_t usage_page,
static bool capslock_match_key_item(const struct capslock_key_list list, uint16_t usage_page,
uint8_t usage_id, uint8_t implicit_modifiers) {
for (int i = 0; i < key_items_count; ++i) {
const struct capslock_key_item *break_item = &key_items[i];
LOG_DBG("checking disable-on-keys: usage_page 0x%02X keycode 0x%02X", break_item->page,
for (int i = 0; i < list.len; ++i) {
const struct capslock_key_item *break_item = &list.keys[i];
LOG_DBG("checking key_list item: usage_page 0x%02X keycode 0x%02X", break_item->page,
break_item->id);
if (break_item->page == usage_page && break_item->id == usage_id &&
(break_item->implicit_modifiers & (implicit_modifiers | zmk_hid_get_explicit_mods())) ==
@ -180,11 +183,22 @@ static int capslock_keycode_state_changed_listener(const zmk_event_t *eh) {
ev->usage_page, ev->keycode);
data->active = false;
}
} else if (capslock_match_key_item(config->disable_on_keys, config->disable_on_keys_count,
ev->usage_page, ev->keycode, ev->implicit_modifiers)) {
LOG_DBG("deactivating capslock (disable-on-keys: usage_page 0x%02X keycode 0x%02X)",
ev->usage_page, ev->keycode);
deactivate_capslock(dev);
} else if (config->disable_on_keys.len > 0) {
LOG_DBG("checking %d disable-on-keys for usage_page 0x%02X keycode 0x%02X",
config->disable_on_keys.len, 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);
}
} 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);
}
}
}
@ -210,9 +224,19 @@ static int behavior_capslock_init(const struct device *dev) {
.id = ZMK_HID_USAGE_ID(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) \
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_config behavior_capslock_config_##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), \
.disable_on_release = DT_INST_PROP(n, disable_on_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_count = DT_INST_PROP_LEN(n, disable_on_keys), \
.disable_on_keys = KEY_LIST(capslock_disable_on_keys_list_##n), \
.enable_while_keys = KEY_LIST(capslock_enable_while_keys_list_##n), \
}; \
DEVICE_DT_INST_DEFINE(n, behavior_capslock_init, NULL, &behavior_capslock_data_##n, \
&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
Four pre-configured instances are provided:
Three pre-configured instances are provided:
- `&capslock_on` enables caps lock
- `&capslock_off` disables caps lock
- `&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
@ -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-next-release`: disable caps lock when the key is released a second time
- `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)
### 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 {
@ -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_line: capslock_line {
compatible = "zmk,behavior-capslock";
label = "CAPSLOCK_LINE";
#binding-cells = <0>;
enable-on-press;
disable-on-keys = <ENTER ESC>;
};
keymap {
...
};
capslock_word: behavior_capslock_word {
compatible = "zmk,behavior-capslock";
label = "CAPSLOCK_WORD";
#binding-cells = <0>;
capslock-press-ms = <5>;
enable-on-press;
disable-on-next-release;
enable-while-keys = <A B C ... Z ...>;
};
```
```