refactor caps_word into capslock

This commit is contained in:
snoyer 2022-10-09 02:04:28 +00:00
parent 54918e5c13
commit 55ee10ce1d
9 changed files with 235 additions and 134 deletions

View file

@ -41,7 +41,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_KEY_TOGGLE app PRIVATE src/behaviors/behavior_key_toggle.c)
target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c)
target_sources(app PRIVATE src/behaviors/behavior_sticky_key.c)
target_sources(app PRIVATE src/behaviors/behavior_caps_word.c)
target_sources(app PRIVATE src/behaviors/behavior_capslock.c)
target_sources(app PRIVATE src/behaviors/behavior_key_repeat.c)
target_sources(app PRIVATE src/behaviors/behavior_macro.c)
target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c)

View file

@ -15,7 +15,7 @@
#include <behaviors/bluetooth.dtsi>
#include <behaviors/ext_power.dtsi>
#include <behaviors/outputs.dtsi>
#include <behaviors/caps_word.dtsi>
#include <behaviors/capslock.dtsi>
#include <behaviors/key_repeat.dtsi>
#include <behaviors/backlight.dtsi>
#include <behaviors/macros.dtsi>

View file

@ -1,20 +0,0 @@
/*
* Copyright (c) 2021 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <dt-bindings/zmk/keys.h>
/ {
behaviors {
/omit-if-no-ref/ caps_word: behavior_caps_word {
compatible = "zmk,behavior-caps-word";
label = "CAPS_WORD";
#binding-cells = <0>;
bindings = <&kp CAPSLOCK>;
break-list = <SPACE TAB ENTER ESCAPE>;
};
};
};

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2021 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <dt-bindings/zmk/keys.h>
/ {
behaviors {
/omit-if-no-ref/ caps_on: behavior_caps_on {
compatible = "zmk,behavior-capslock";
label = "CAPS_ON";
#binding-cells = <0>;
bindings = <&kp CAPSLOCK>;
enable-on-press;
};
/omit-if-no-ref/ caps_off: behavior_caps_off {
compatible = "zmk,behavior-capslock";
label = "CAPS_OFF";
#binding-cells = <0>;
bindings = <&kp CAPSLOCK>;
disable-on-release;
};
/omit-if-no-ref/ caps_hold: behavior_caps_hold {
compatible = "zmk,behavior-capslock";
label = "CAPS_HOLD";
#binding-cells = <0>;
bindings = <&kp CAPSLOCK>;
enable-on-press;
disable-on-release;
};
/omit-if-no-ref/ caps_word: behavior_caps_word {
compatible = "zmk,behavior-capslock";
label = "CAPS_WORD";
#binding-cells = <0>;
bindings = <&kp CAPSLOCK>;
enable-on-press;
disable-on-second-press;
disable-on-keys = <SPACE TAB ENTER ESCAPE>;
};
};
};

View file

@ -3,14 +3,21 @@
description: Caps word behavior
compatible: "zmk,behavior-caps-word"
compatible: "zmk,behavior-capslock"
include: zero_param.yaml
properties:
break-list:
enable-on-press:
type: boolean
disable-on-release:
type: boolean
disable-on-second-press:
type: boolean
disable-on-keys:
type: array
required: true
required: false
default: []
bindings:
type: phandle-array
required: true

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: MIT
*/
#define DT_DRV_COMPAT zmk_behavior_caps_word
#define DT_DRV_COMPAT zmk_behavior_capslock
#include <device.h>
#include <drivers/behavior.h>
@ -24,27 +24,31 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
struct caps_word_break_item {
struct capslock_key_item {
uint16_t page;
uint32_t id;
uint8_t implicit_modifiers;
};
struct behavior_caps_word_config {
struct behavior_capslock_config {
uint8_t index;
struct zmk_behavior_binding capslock_binding;
uint8_t break_items_count;
struct caps_word_break_item break_items[];
bool enable_on_press;
bool disable_on_release;
bool disable_on_second_press;
uint8_t disable_on_keys_count;
struct capslock_key_item disable_on_keys[];
};
struct behavior_caps_word_data {
struct behavior_capslock_data {
uint32_t position;
bool active;
bool just_activated;
};
static void toggle_capslock(const struct device *dev) {
const struct behavior_caps_word_config *config = dev->config;
const struct behavior_caps_word_data *data = dev->data;
const struct behavior_capslock_config *config = dev->config;
const struct behavior_capslock_data *data = dev->data;
zmk_behavior_queue_add(data->position, config->capslock_binding, true, 0);
zmk_behavior_queue_add(data->position, config->capslock_binding, false, 0);
@ -55,72 +59,84 @@ static void set_capslock_state(const struct device *dev, const bool target_state
zmk_led_indicators_get_current_flags() & ZMK_LED_INDICATORS_CAPSLOCK_BIT;
if (current_state != target_state) {
LOG_DBG("toggling capslock state from %d to %d", current_state, target_state);
toggle_capslock(dev);
} else {
LOG_DBG("capslock state was already %d", target_state);
LOG_DBG("capslock state is already %d", target_state);
}
}
static void activate_caps_word(const struct device *dev) {
struct behavior_caps_word_data *data = dev->data;
static void activate_capslock(const struct device *dev) {
struct behavior_capslock_data *data = dev->data;
set_capslock_state(dev, true);
if (!data->active) {
data->just_activated = true;
}
data->active = true;
}
static void deactivate_caps_word(const struct device *dev) {
struct behavior_caps_word_data *data = dev->data;
static void deactivate_capslock(const struct device *dev) {
struct behavior_capslock_data *data = dev->data;
set_capslock_state(dev, false);
data->active = false;
}
static int on_caps_word_binding_pressed(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
static int on_capslock_binding_pressed(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
const struct device *dev = device_get_binding(binding->behavior_dev);
struct behavior_caps_word_data *data = dev->data;
const struct behavior_capslock_config *config = dev->config;
struct behavior_capslock_data *data = dev->data;
data->position = event.position;
if (data->active) {
deactivate_caps_word(dev);
} else {
activate_caps_word(dev);
if (config->enable_on_press) {
activate_capslock(dev);
}
return ZMK_BEHAVIOR_OPAQUE;
}
static int on_caps_word_binding_released(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
static int on_capslock_binding_released(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
const struct device *dev = device_get_binding(binding->behavior_dev);
const struct behavior_capslock_config *config = dev->config;
struct behavior_capslock_data *data = dev->data;
if (config->disable_on_release || (config->disable_on_second_press && !data->just_activated)) {
deactivate_capslock(dev);
}
data->just_activated = false;
return ZMK_BEHAVIOR_OPAQUE;
}
static const struct behavior_driver_api behavior_caps_word_driver_api = {
.binding_pressed = on_caps_word_binding_pressed,
.binding_released = on_caps_word_binding_released,
static const struct behavior_driver_api behavior_capslock_driver_api = {
.binding_pressed = on_capslock_binding_pressed,
.binding_released = on_capslock_binding_released,
};
static int caps_word_keycode_state_changed_listener(const zmk_event_t *eh);
static int capslock_keycode_state_changed_listener(const zmk_event_t *eh);
ZMK_LISTENER(behavior_caps_word, caps_word_keycode_state_changed_listener);
ZMK_SUBSCRIPTION(behavior_caps_word, zmk_keycode_state_changed);
ZMK_LISTENER(behavior_capslock, capslock_keycode_state_changed_listener);
ZMK_SUBSCRIPTION(behavior_capslock, zmk_keycode_state_changed);
static const struct device *devs[DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT)];
static bool caps_word_is_break_item(const struct behavior_caps_word_config *config,
uint16_t usage_page, uint8_t usage_id,
uint8_t implicit_modifiers) {
for (int i = 0; i < config->break_items_count; i++) {
const struct caps_word_break_item *break_item = &config->break_items[i];
static bool capslock_find_key_item(const struct behavior_capslock_config *config,
uint16_t usage_page, uint8_t usage_id,
uint8_t implicit_modifiers) {
for (int i = 0; i < config->disable_on_keys_count; i++) {
const struct capslock_key_item *break_item = &config->disable_on_keys[i];
LOG_DBG("Comparing with 0x%02X - 0x%02X (with implicit mods: 0x%02X)", break_item->page,
break_item->id, break_item->implicit_modifiers);
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) {
LOG_DBG("Stopping capsword, found included usage: 0x%02X - 0x%02X", usage_page,
usage_id);
LOG_DBG("found included usage: 0x%02X - 0x%02X", usage_page, usage_id);
return true;
}
}
@ -128,7 +144,7 @@ static bool caps_word_is_break_item(const struct behavior_caps_word_config *conf
return false;
}
static int caps_word_keycode_state_changed_listener(const zmk_event_t *eh) {
static int capslock_keycode_state_changed_listener(const zmk_event_t *eh) {
struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh);
if (ev == NULL || !ev->state) {
return ZMK_EV_EVENT_BUBBLE;
@ -140,24 +156,24 @@ static int caps_word_keycode_state_changed_listener(const zmk_event_t *eh) {
continue;
}
struct behavior_caps_word_data *data = dev->data;
struct behavior_capslock_data *data = dev->data;
if (!data->active) {
continue;
}
const struct behavior_caps_word_config *config = dev->config;
const struct behavior_capslock_config *config = dev->config;
if (caps_word_is_break_item(config, ev->usage_page, ev->keycode, ev->implicit_modifiers)) {
LOG_DBG("Deactivating caps_word for 0x%02X - 0x%02X", ev->usage_page, ev->keycode);
deactivate_caps_word(dev);
if (capslock_find_key_item(config, ev->usage_page, ev->keycode, ev->implicit_modifiers)) {
LOG_DBG("Deactivating capslock for 0x%02X - 0x%02X", ev->usage_page, ev->keycode);
deactivate_capslock(dev);
}
}
return ZMK_EV_EVENT_BUBBLE;
}
static int behavior_caps_word_init(const struct device *dev) {
const struct behavior_caps_word_config *config = dev->config;
static int behavior_capslock_init(const struct device *dev) {
const struct behavior_capslock_config *config = dev->config;
devs[config->index] = dev;
return 0;
}
@ -167,7 +183,7 @@ static int behavior_caps_word_init(const struct device *dev) {
.id = ZMK_HID_USAGE_ID(i), \
.implicit_modifiers = SELECT_MODS(i)},
#define BREAK_ITEM(i, n) PARSE_BREAK(DT_INST_PROP_BY_IDX(n, break_list, i))
#define BREAK_ITEM(i, n) PARSE_BREAK(DT_INST_PROP_BY_IDX(n, disable_on_keys, i))
#define _TRANSFORM_ENTRY(idx, node) \
{ \
@ -179,16 +195,19 @@ static int behavior_caps_word_init(const struct device *dev) {
}
#define KP_INST(n) \
static struct behavior_caps_word_data behavior_caps_word_data_##n = {.active = false}; \
static struct behavior_caps_word_config behavior_caps_word_config_##n = { \
static struct behavior_capslock_data behavior_capslock_data_##n = {.active = false}; \
static struct behavior_capslock_config behavior_capslock_config_##n = { \
.index = n, \
.capslock_binding = _TRANSFORM_ENTRY(0, n), \
.break_items = {UTIL_LISTIFY(DT_INST_PROP_LEN(n, break_list), BREAK_ITEM, n)}, \
.break_items_count = DT_INST_PROP_LEN(n, break_list), \
.enable_on_press = DT_INST_PROP(n, enable_on_press), \
.disable_on_release = DT_INST_PROP(n, disable_on_release), \
.disable_on_second_press = DT_INST_PROP(n, disable_on_second_press), \
.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), \
}; \
DEVICE_DT_INST_DEFINE(n, behavior_caps_word_init, NULL, &behavior_caps_word_data_##n, \
&behavior_caps_word_config_##n, APPLICATION, \
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_caps_word_driver_api);
DEVICE_DT_INST_DEFINE(n, behavior_capslock_init, NULL, &behavior_capslock_data_##n, \
&behavior_capslock_config_##n, APPLICATION, \
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_capslock_driver_api);
DT_INST_FOREACH_STATUS_OKAY(KP_INST)

View file

@ -1,56 +0,0 @@
---
title: Caps Word Behavior
sidebar_label: Caps Word
---
## Summary
The caps word behavior activates caps lock when pressed, but will automatically deactivate it when any key in the break list is pressed, or if the caps word key is pressed again. For smaller keyboards using [mod-taps](/docs/behaviors/mod-tap), this can help avoid repeated alternating holds when typing words in all caps.
### Behavior Binding
- Reference: `&caps_word`
Example:
```
&caps_word
```
### Configuration
#### Break List
By default, the caps word will remain active until space (`SPACE`), tab (`TAB`), enter (`ENTER`), or escape (`ESCAPE`) is pressed. If you would like to override this, you can set a new array of keys in the `break-list` property in your keymap:
```
&caps_word {
break-list = <SPACE MINUS>;
};
/ {
keymap {
...
};
};
```
### Multiple Caps Breaks
If you want to use multiple caps breaks with different codes to break the caps, you can add additional caps words instances to use in your keymap:
```
/ {
prog_caps: behavior_prog_caps_word {
compatible = "zmk,behavior-caps-word";
label = "PROG_CAPS";
#binding-cells = <0>;
break-list = <SPACE TAB ENTER MINUS>;
};
keymap {
...
};
};
```

View file

@ -0,0 +1,104 @@
---
title: Caps Lock Behavior
sidebar_label: Caps Lock
---
## Summary
This set of behaviors offers enhahced versions of the caps lock key.
## Caps On
Enables caps lock when pressed, regarless of the current caps lock state.
### Behavior Binding
- Reference: `&caps_on`
Example:
```
&caps_on
```
## Caps Off
Disables caps lock when released, regarless of the current caps lock state.
### Behavior Binding
- Reference: `&caps_off`
Example:
```
&caps_off
```
## Caps Hold
Enables caps lock when pressed, and disables it when released.
### Behavior Binding
- Reference: `&caps_hold`
Example:
```
&caps_hold
```
## Caps Word
Enables caps lock when pressed, and deactivate it when any key in the break list is pressed, or if the caps word key is pressed again.
### Behavior Binding
- Reference: `&caps_word`
Example:
```
&caps_word
```
### Configuration
#### Word Separators
By default, the caps word will remain active until space (`SPACE`), tab (`TAB`), enter (`ENTER`), or escape (`ESCAPE`) is pressed. If you would like to override this, you can set a new array of keys in the `disable-on-keys` property in your keymap:
```
&caps_word {
disable-on-keys = <SPACE MINUS>;
};
/ {
keymap {
...
};
};
```
### Multiple Caps Words
If you want to use multiple caps words with different word separators, you can add additional caps word instances to use in your keymap:
```
/ {
prog_caps: behavior_prog_caps_word {
compatible = "zmk,behavior-capslock";
label = "CAPS_WORD";
#binding-cells = <0>;
bindings = <&kp CAPSLOCK>;
enable-on-press;
disable-on-second-press;
disable-on-keys = <SPACE TAB ENTER ESCAPE>;
};
keymap {
...
};
};
```

View file

@ -32,7 +32,7 @@ module.exports = {
"behaviors/sticky-key",
"behaviors/sticky-layer",
"behaviors/tap-dance",
"behaviors/caps-word",
"behaviors/capslock",
"behaviors/key-repeat",
"behaviors/reset",
"behaviors/bluetooth",