forked from zmkfirmware/zmk
-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(behaviors):
&key_repeat
behavior + tests.
* Add new `&key_repeat` behavior that captures and re-sends the most recently triggered keycode. Closes: zmkfirmware#583
- Loading branch information
1 parent
54dabff
commit 1af5648
Showing
16 changed files
with
278 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/* | ||
* Copyright (c) 2021 The ZMK Contributors | ||
* | ||
* SPDX-License-Identifier: MIT | ||
*/ | ||
|
||
#include <dt-bindings/zmk/keys.h> | ||
|
||
/ { | ||
behaviors { | ||
/omit-if-no-ref/ key_repeat: behavior_key_repeat { | ||
compatible = "zmk,behavior-key-repeat"; | ||
label = "KEY_REPEAT"; | ||
#binding-cells = <0>; | ||
usage-pages = <HID_USAGE_KEY>; | ||
}; | ||
}; | ||
}; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Copyright (c) 2021 The ZMK Contributors | ||
# SPDX-License-Identifier: MIT | ||
|
||
description: Key repeat behavior | ||
|
||
compatible: "zmk,behavior-key-repeat" | ||
|
||
include: zero_param.yaml | ||
|
||
properties: | ||
usage-pages: | ||
type: array | ||
required: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
/* | ||
* Copyright (c) 2021 The ZMK Contributors | ||
* | ||
* SPDX-License-Identifier: MIT | ||
*/ | ||
|
||
#define DT_DRV_COMPAT zmk_behavior_key_repeat | ||
|
||
#include <device.h> | ||
#include <drivers/behavior.h> | ||
#include <logging/log.h> | ||
#include <zmk/behavior.h> | ||
|
||
#include <zmk/event_manager.h> | ||
#include <zmk/events/keycode_state_changed.h> | ||
|
||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); | ||
|
||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) | ||
|
||
struct behavior_key_repeat_config { | ||
uint8_t index; | ||
uint8_t usage_pages_count; | ||
uint16_t usage_pages[]; | ||
}; | ||
|
||
struct behavior_key_repeat_data { | ||
struct zmk_keycode_state_changed last_keycode_pressed; | ||
struct zmk_keycode_state_changed current_keycode_pressed; | ||
}; | ||
|
||
static int on_key_repeat_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_key_repeat_data *data = dev->data; | ||
|
||
if (data->last_keycode_pressed.usage_page == 0) { | ||
return ZMK_BEHAVIOR_OPAQUE; | ||
} | ||
|
||
memcpy(&data->current_keycode_pressed, &data->last_keycode_pressed, | ||
sizeof(struct zmk_keycode_state_changed)); | ||
data->current_keycode_pressed.timestamp = k_uptime_get(); | ||
|
||
ZMK_EVENT_RAISE(new_zmk_keycode_state_changed(data->current_keycode_pressed)); | ||
|
||
return ZMK_BEHAVIOR_OPAQUE; | ||
} | ||
|
||
static int on_key_repeat_binding_released(struct zmk_behavior_binding *binding, | ||
struct zmk_behavior_binding_event event) { | ||
const struct device *dev = device_get_binding(binding->behavior_dev); | ||
struct behavior_key_repeat_data *data = dev->data; | ||
|
||
if (data->current_keycode_pressed.usage_page == 0) { | ||
return ZMK_BEHAVIOR_OPAQUE; | ||
} | ||
|
||
data->current_keycode_pressed.timestamp = k_uptime_get(); | ||
data->current_keycode_pressed.state = false; | ||
|
||
ZMK_EVENT_RAISE(new_zmk_keycode_state_changed(data->current_keycode_pressed)); | ||
return ZMK_BEHAVIOR_OPAQUE; | ||
} | ||
|
||
static const struct behavior_driver_api behavior_key_repeat_driver_api = { | ||
.binding_pressed = on_key_repeat_binding_pressed, | ||
.binding_released = on_key_repeat_binding_released, | ||
}; | ||
|
||
static int key_repeat_keycode_state_changed_listener(const zmk_event_t *eh); | ||
|
||
ZMK_LISTENER(behavior_key_repeat, key_repeat_keycode_state_changed_listener); | ||
ZMK_SUBSCRIPTION(behavior_key_repeat, zmk_keycode_state_changed); | ||
|
||
static const struct device *devs[DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT)]; | ||
|
||
static int key_repeat_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; | ||
} | ||
|
||
for (int i = 0; i < DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT); i++) { | ||
const struct device *dev = devs[i]; | ||
if (dev == NULL) { | ||
continue; | ||
} | ||
|
||
struct behavior_key_repeat_data *data = dev->data; | ||
const struct behavior_key_repeat_config *config = dev->config; | ||
|
||
for (int u = 0; u < config->usage_pages_count; u++) { | ||
if (config->usage_pages[u] == ev->usage_page) { | ||
memcpy(&data->last_keycode_pressed, ev, sizeof(struct zmk_keycode_state_changed)); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
return ZMK_EV_EVENT_BUBBLE; | ||
} | ||
|
||
static int behavior_key_repeat_init(const struct device *dev) { | ||
const struct behavior_key_repeat_config *config = dev->config; | ||
devs[config->index] = dev; | ||
return 0; | ||
} | ||
|
||
#define KR_INST(n) \ | ||
static struct behavior_key_repeat_data behavior_key_repeat_data_##n = {}; \ | ||
static struct behavior_key_repeat_config behavior_key_repeat_config_##n = { \ | ||
.index = n, \ | ||
.usage_pages = DT_INST_PROP(n, usage_pages), \ | ||
.usage_pages_count = DT_INST_PROP_LEN(n, usage_pages), \ | ||
}; \ | ||
DEVICE_DT_INST_DEFINE(n, behavior_key_repeat_init, device_pm_control_nop, \ | ||
&behavior_key_repeat_data_##n, &behavior_key_repeat_config_##n, \ | ||
APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ | ||
&behavior_key_repeat_driver_api); | ||
|
||
DT_INST_FOREACH_STATUS_OKAY(KR_INST) | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#include <dt-bindings/zmk/keys.h> | ||
#include <behaviors.dtsi> | ||
#include <dt-bindings/zmk/kscan_mock.h> | ||
|
||
/ { | ||
keymap { | ||
compatible = "zmk,keymap"; | ||
label = "Default keymap"; | ||
|
||
default_layer { | ||
bindings = < | ||
&key_repeat &kp A | ||
&kp B &kp C_VOL_UP | ||
>; | ||
}; | ||
}; | ||
}; |
2 changes: 2 additions & 0 deletions
2
app/tests/key-repeat/ignore-other-usage-page-events/events.patterns
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
s/.*hid_listener_keycode_//p | ||
s/.*hid_implicit_modifiers_//p |
12 changes: 12 additions & 0 deletions
12
app/tests/key-repeat/ignore-other-usage-page-events/keycode_events.snapshot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 | ||
press: Modifiers set to 0x00 | ||
released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 | ||
release: Modifiers set to 0x00 | ||
pressed: usage_page 0x0c keycode 0xe9 implicit_mods 0x00 explicit_mods 0x00 | ||
press: Modifiers set to 0x00 | ||
released: usage_page 0x0c keycode 0xe9 implicit_mods 0x00 explicit_mods 0x00 | ||
release: Modifiers set to 0x00 | ||
pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 | ||
press: Modifiers set to 0x00 | ||
released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 | ||
release: Modifiers set to 0x00 |
15 changes: 15 additions & 0 deletions
15
app/tests/key-repeat/ignore-other-usage-page-events/native_posix.keymap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#include <dt-bindings/zmk/keys.h> | ||
#include <behaviors.dtsi> | ||
#include <dt-bindings/zmk/kscan_mock.h> | ||
#include "../behavior_keymap.dtsi" | ||
|
||
&kscan { | ||
events = < | ||
ZMK_MOCK_PRESS(0,1,10) | ||
ZMK_MOCK_RELEASE(0,1,10) | ||
ZMK_MOCK_PRESS(1,1,10) | ||
ZMK_MOCK_RELEASE(1,1,10) | ||
ZMK_MOCK_PRESS(0,0,10) | ||
ZMK_MOCK_RELEASE(0,0,10) | ||
>; | ||
}; |
2 changes: 2 additions & 0 deletions
2
app/tests/key-repeat/press-and-release-after-key-usage/events.patterns
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
s/.*hid_listener_keycode_//p | ||
s/.*hid_implicit_modifiers_//p |
8 changes: 8 additions & 0 deletions
8
app/tests/key-repeat/press-and-release-after-key-usage/keycode_events.snapshot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 | ||
press: Modifiers set to 0x00 | ||
released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 | ||
release: Modifiers set to 0x00 | ||
pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 | ||
press: Modifiers set to 0x00 | ||
released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 | ||
release: Modifiers set to 0x00 |
13 changes: 13 additions & 0 deletions
13
app/tests/key-repeat/press-and-release-after-key-usage/native_posix.keymap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#include <dt-bindings/zmk/keys.h> | ||
#include <behaviors.dtsi> | ||
#include <dt-bindings/zmk/kscan_mock.h> | ||
#include "../behavior_keymap.dtsi" | ||
|
||
&kscan { | ||
events = < | ||
ZMK_MOCK_PRESS(0,1,10) | ||
ZMK_MOCK_RELEASE(0,1,10) | ||
ZMK_MOCK_PRESS(0,0,10) | ||
ZMK_MOCK_RELEASE(0,0,10) | ||
>; | ||
}; |
2 changes: 2 additions & 0 deletions
2
app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/events.patterns
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
s/.*hid_listener_keycode_//p | ||
s/.*hid_implicit_modifiers_//p |
Empty file.
11 changes: 11 additions & 0 deletions
11
app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/native_posix.keymap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#include <dt-bindings/zmk/keys.h> | ||
#include <behaviors.dtsi> | ||
#include <dt-bindings/zmk/kscan_mock.h> | ||
#include "../behavior_keymap.dtsi" | ||
|
||
&kscan { | ||
events = < | ||
ZMK_MOCK_PRESS(0,0,10) | ||
ZMK_MOCK_RELEASE(0,0,10) | ||
>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
--- | ||
title: Key Repeat Behavior | ||
sidebar_label: Key Repeat | ||
--- | ||
|
||
## Summary | ||
|
||
The key repeat behavior when triggered will send whatever keycode was last sent/triggered. | ||
|
||
### Behavior Binding | ||
|
||
- Reference: `&key_repeat` | ||
|
||
Example: | ||
|
||
``` | ||
&key_repeat | ||
``` | ||
|
||
### Configuration | ||
|
||
#### Usage Pages | ||
|
||
By default, the key repeat will only track the last pressed key from the HID "Key" usage page, and ignore events from other usages, e.g. Consumer page. | ||
|
||
If you'd rather have the repeat also capture and send Consumer page usages, you can update the existing behavior: | ||
|
||
``` | ||
&key_repeat { | ||
usage-pages = <HID_USAGE_KEY HID_USAGE_CONSUMER>; | ||
}; | ||
/ { | ||
keymap { | ||
... | ||
}; | ||
}; | ||
``` |