refactor caps_word
into capslock
This commit is contained in:
parent
54918e5c13
commit
55ee10ce1d
9 changed files with 235 additions and 134 deletions
|
@ -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)
|
||||
|
|
|
@ -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>
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
47
app/dts/behaviors/capslock.dtsi
Normal file
47
app/dts/behaviors/capslock.dtsi
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -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
|
|
@ -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)
|
||||
|
|
@ -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 {
|
||||
...
|
||||
};
|
||||
};
|
||||
```
|
104
docs/docs/behaviors/capslock.md
Normal file
104
docs/docs/behaviors/capslock.md
Normal 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 {
|
||||
...
|
||||
};
|
||||
};
|
||||
```
|
|
@ -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",
|
||||
|
|
Loading…
Add table
Reference in a new issue