summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/CMakeLists.txt1
-rw-r--r--app/dts/behaviors.dtsi1
-rw-r--r--app/dts/behaviors/key_repeat.dtsi19
-rw-r--r--app/dts/bindings/behaviors/zmk,behavior-key-repeat.yaml13
-rw-r--r--app/src/behaviors/behavior_key_repeat.c124
-rw-r--r--app/tests/key-repeat/behavior_keymap.dtsi17
-rw-r--r--app/tests/key-repeat/ignore-other-usage-page-events/events.patterns2
-rw-r--r--app/tests/key-repeat/ignore-other-usage-page-events/keycode_events.snapshot12
-rw-r--r--app/tests/key-repeat/ignore-other-usage-page-events/native_posix.keymap15
-rw-r--r--app/tests/key-repeat/press-and-release-after-key-usage/events.patterns2
-rw-r--r--app/tests/key-repeat/press-and-release-after-key-usage/keycode_events.snapshot8
-rw-r--r--app/tests/key-repeat/press-and-release-after-key-usage/native_posix.keymap13
-rw-r--r--app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/events.patterns2
-rw-r--r--app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/keycode_events.snapshot0
-rw-r--r--app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/native_posix.keymap11
15 files changed, 240 insertions, 0 deletions
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index 970c6c2..c5b74aa 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -48,6 +48,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
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_key_repeat.c)
target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c)
target_sources(app PRIVATE src/behaviors/behavior_mod_morph.c)
target_sources(app PRIVATE src/behaviors/behavior_outputs.c)
diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi
index 5b5f72b..0648961 100644
--- a/app/dts/behaviors.dtsi
+++ b/app/dts/behaviors.dtsi
@@ -15,3 +15,4 @@
#include <behaviors/ext_power.dtsi>
#include <behaviors/outputs.dtsi>
#include <behaviors/caps_word.dtsi>
+#include <behaviors/key_repeat.dtsi>
diff --git a/app/dts/behaviors/key_repeat.dtsi b/app/dts/behaviors/key_repeat.dtsi
new file mode 100644
index 0000000..aa8ffa0
--- /dev/null
+++ b/app/dts/behaviors/key_repeat.dtsi
@@ -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>;
+ };
+ };
+};
+
diff --git a/app/dts/bindings/behaviors/zmk,behavior-key-repeat.yaml b/app/dts/bindings/behaviors/zmk,behavior-key-repeat.yaml
new file mode 100644
index 0000000..10b3aa0
--- /dev/null
+++ b/app/dts/bindings/behaviors/zmk,behavior-key-repeat.yaml
@@ -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
diff --git a/app/src/behaviors/behavior_key_repeat.c b/app/src/behaviors/behavior_key_repeat.c
new file mode 100644
index 0000000..b2e28a6
--- /dev/null
+++ b/app/src/behaviors/behavior_key_repeat.c
@@ -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
diff --git a/app/tests/key-repeat/behavior_keymap.dtsi b/app/tests/key-repeat/behavior_keymap.dtsi
new file mode 100644
index 0000000..93b6d06
--- /dev/null
+++ b/app/tests/key-repeat/behavior_keymap.dtsi
@@ -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
+ >;
+ };
+ };
+};
diff --git a/app/tests/key-repeat/ignore-other-usage-page-events/events.patterns b/app/tests/key-repeat/ignore-other-usage-page-events/events.patterns
new file mode 100644
index 0000000..7947192
--- /dev/null
+++ b/app/tests/key-repeat/ignore-other-usage-page-events/events.patterns
@@ -0,0 +1,2 @@
+s/.*hid_listener_keycode_//p
+s/.*hid_implicit_modifiers_//p \ No newline at end of file
diff --git a/app/tests/key-repeat/ignore-other-usage-page-events/keycode_events.snapshot b/app/tests/key-repeat/ignore-other-usage-page-events/keycode_events.snapshot
new file mode 100644
index 0000000..c06d94a
--- /dev/null
+++ b/app/tests/key-repeat/ignore-other-usage-page-events/keycode_events.snapshot
@@ -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
diff --git a/app/tests/key-repeat/ignore-other-usage-page-events/native_posix.keymap b/app/tests/key-repeat/ignore-other-usage-page-events/native_posix.keymap
new file mode 100644
index 0000000..b042e8e
--- /dev/null
+++ b/app/tests/key-repeat/ignore-other-usage-page-events/native_posix.keymap
@@ -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)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/key-repeat/press-and-release-after-key-usage/events.patterns b/app/tests/key-repeat/press-and-release-after-key-usage/events.patterns
new file mode 100644
index 0000000..7947192
--- /dev/null
+++ b/app/tests/key-repeat/press-and-release-after-key-usage/events.patterns
@@ -0,0 +1,2 @@
+s/.*hid_listener_keycode_//p
+s/.*hid_implicit_modifiers_//p \ No newline at end of file
diff --git a/app/tests/key-repeat/press-and-release-after-key-usage/keycode_events.snapshot b/app/tests/key-repeat/press-and-release-after-key-usage/keycode_events.snapshot
new file mode 100644
index 0000000..d568d37
--- /dev/null
+++ b/app/tests/key-repeat/press-and-release-after-key-usage/keycode_events.snapshot
@@ -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
diff --git a/app/tests/key-repeat/press-and-release-after-key-usage/native_posix.keymap b/app/tests/key-repeat/press-and-release-after-key-usage/native_posix.keymap
new file mode 100644
index 0000000..98c8f6f
--- /dev/null
+++ b/app/tests/key-repeat/press-and-release-after-key-usage/native_posix.keymap
@@ -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)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/events.patterns b/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/events.patterns
new file mode 100644
index 0000000..7947192
--- /dev/null
+++ b/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/events.patterns
@@ -0,0 +1,2 @@
+s/.*hid_listener_keycode_//p
+s/.*hid_implicit_modifiers_//p \ No newline at end of file
diff --git a/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/keycode_events.snapshot b/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/keycode_events.snapshot
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/keycode_events.snapshot
diff --git a/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/native_posix.keymap b/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/native_posix.keymap
new file mode 100644
index 0000000..9ff6446
--- /dev/null
+++ b/app/tests/key-repeat/send-nothing-if-no-keys-pressed-yet/native_posix.keymap
@@ -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)
+ >;
+}; \ No newline at end of file