summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorKemoNine <mcrosson@users.noreply.github.com>2021-02-03 23:33:09 -0500
committerGitHub <noreply@github.com>2021-02-03 23:33:09 -0500
commitcd503ed17bb141bd54a777a375b5706acf884318 (patch)
tree2e9095fad05e8eb0d0545e0a662aca2d6b3084f6 /app
parent9205ea1c705504844ad3b9e31d6fbd437cb76aba (diff)
Feat combo layers (#661)
feat(combos): add layer filtering Co-authored-by: KemoNine <mcrosson@kemonine.info>
Diffstat (limited to 'app')
-rw-r--r--app/dts/bindings/zmk,combos.yaml3
-rw-r--r--app/src/combo.c31
-rw-r--r--app/tests/combo/layer-filter-0/events.patterns2
-rw-r--r--app/tests/combo/layer-filter-0/keycode_events.snapshot8
-rw-r--r--app/tests/combo/layer-filter-0/native_posix.keymap78
-rw-r--r--app/tests/combo/layer-filter-1/events.patterns2
-rw-r--r--app/tests/combo/layer-filter-1/keycode_events.snapshot4
-rw-r--r--app/tests/combo/layer-filter-1/native_posix.keymap40
8 files changed, 164 insertions, 4 deletions
diff --git a/app/dts/bindings/zmk,combos.yaml b/app/dts/bindings/zmk,combos.yaml
index 75eaa3e..1a914a7 100644
--- a/app/dts/bindings/zmk,combos.yaml
+++ b/app/dts/bindings/zmk,combos.yaml
@@ -20,3 +20,6 @@ child-binding:
default: 50
slow-release:
type: boolean
+ layers:
+ type: array
+ default: [-1] \ No newline at end of file
diff --git a/app/src/combo.c b/app/src/combo.c
index 82f6538..b50a0f6 100644
--- a/app/src/combo.c
+++ b/app/src/combo.c
@@ -17,6 +17,7 @@
#include <zmk/events/position_state_changed.h>
#include <zmk/hid.h>
#include <zmk/matrix.h>
+#include <zmk/keymap.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
@@ -33,6 +34,8 @@ struct combo_cfg {
// the virtual key position is a key position outside the range used by the keyboard.
// it is necessary so hold-taps can uniquely identify a behavior.
int32_t virtual_key_position;
+ int32_t layers_len;
+ int8_t layers[];
};
struct active_combo {
@@ -104,17 +107,35 @@ static int initialize_combo(struct combo_cfg *new_combo) {
return 0;
}
+static bool combo_active_on_layer(struct combo_cfg *combo, uint8_t layer) {
+ if (combo->layers[0] == -1) {
+ // -1 in the first layer position is global layer scope
+ return true;
+ }
+ for (int j = 0; j < combo->layers_len; j++) {
+ if (combo->layers[j] == layer) {
+ return true;
+ }
+ }
+ return false;
+}
+
static int setup_candidates_for_first_keypress(int32_t position, int64_t timestamp) {
+ int number_of_combo_candidates = 0;
+ uint8_t highest_active_layer = zmk_keymap_highest_layer_active();
for (int i = 0; i < CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY; i++) {
struct combo_cfg *combo = combo_lookup[position][i];
if (combo == NULL) {
- return i;
+ return number_of_combo_candidates;
+ }
+ if (combo_active_on_layer(combo, highest_active_layer)) {
+ candidates[number_of_combo_candidates].combo = combo;
+ candidates[number_of_combo_candidates].timeout_at = timestamp + combo->timeout_ms;
+ number_of_combo_candidates++;
}
- candidates[i].combo = combo;
- candidates[i].timeout_at = timestamp + combo->timeout_ms;
// LOG_DBG("combo timeout %d %d %d", position, i, candidates[i].timeout_at);
}
- return CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY;
+ return number_of_combo_candidates;
}
static int filter_candidates(int32_t position) {
@@ -451,6 +472,8 @@ ZMK_SUBSCRIPTION(combo, zmk_position_state_changed);
.behavior = KEY_BINDING_TO_STRUCT(0, n), \
.virtual_key_position = ZMK_KEYMAP_LEN + __COUNTER__, \
.slow_release = DT_PROP(n, slow_release), \
+ .layers = DT_PROP(n, layers), \
+ .layers_len = DT_PROP_LEN(n, layers), \
};
#define INITIALIZE_COMBO(n) initialize_combo(&combo_config_##n);
diff --git a/app/tests/combo/layer-filter-0/events.patterns b/app/tests/combo/layer-filter-0/events.patterns
new file mode 100644
index 0000000..b90d786
--- /dev/null
+++ b/app/tests/combo/layer-filter-0/events.patterns
@@ -0,0 +1,2 @@
+s/.*hid_listener_keycode_//p
+s/.*combo//p \ No newline at end of file
diff --git a/app/tests/combo/layer-filter-0/keycode_events.snapshot b/app/tests/combo/layer-filter-0/keycode_events.snapshot
new file mode 100644
index 0000000..f845fd1
--- /dev/null
+++ b/app/tests/combo/layer-filter-0/keycode_events.snapshot
@@ -0,0 +1,8 @@
+pressed: usage_page 0x07 keycode 0x1b implicit_mods 0x00 explicit_mods 0x00
+released: usage_page 0x07 keycode 0x1b implicit_mods 0x00 explicit_mods 0x00
+pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
+released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
+pressed: usage_page 0x07 keycode 0x1c implicit_mods 0x00 explicit_mods 0x00
+released: usage_page 0x07 keycode 0x1c implicit_mods 0x00 explicit_mods 0x00
+pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
+released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
diff --git a/app/tests/combo/layer-filter-0/native_posix.keymap b/app/tests/combo/layer-filter-0/native_posix.keymap
new file mode 100644
index 0000000..aac330f
--- /dev/null
+++ b/app/tests/combo/layer-filter-0/native_posix.keymap
@@ -0,0 +1,78 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+/* it is useful to set timeout to a large value when attaching a debugger. */
+#define TIMEOUT (60*60*1000)
+
+/ {
+ combos {
+ compatible = "zmk,combos";
+ combo_one {
+ timeout-ms = <TIMEOUT>;
+ key-positions = <0 1>;
+ bindings = <&kp X>;
+ layers = <0>;
+ };
+
+ combo_two {
+ timeout-ms = <TIMEOUT>;
+ key-positions = <0 1>;
+ bindings = <&kp Y>;
+ layers = <1>;
+ };
+
+ combo_three {
+ timeout-ms = <TIMEOUT>;
+ key-positions = <0 2>;
+ bindings = <&kp Z>;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &kp A &kp B
+ &kp C &tog 1
+ >;
+ };
+
+ filtered_layer {
+ bindings = <
+ &kp A &kp B
+ &kp C &tog 0
+ >;
+ };
+ };
+};
+
+&kscan {
+ events = <
+ /* Combo One */
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ /* Combo Three */
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(1,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(1,1,10)
+ /* Toggle Layer */
+ ZMK_MOCK_PRESS(1,1,10)
+ ZMK_MOCK_RELEASE(1,1,10)
+ /* Combo Two */
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ /* Combo Three */
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(1,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(1,1,10)
+ >;
+}; \ No newline at end of file
diff --git a/app/tests/combo/layer-filter-1/events.patterns b/app/tests/combo/layer-filter-1/events.patterns
new file mode 100644
index 0000000..b90d786
--- /dev/null
+++ b/app/tests/combo/layer-filter-1/events.patterns
@@ -0,0 +1,2 @@
+s/.*hid_listener_keycode_//p
+s/.*combo//p \ No newline at end of file
diff --git a/app/tests/combo/layer-filter-1/keycode_events.snapshot b/app/tests/combo/layer-filter-1/keycode_events.snapshot
new file mode 100644
index 0000000..bb47d85
--- /dev/null
+++ b/app/tests/combo/layer-filter-1/keycode_events.snapshot
@@ -0,0 +1,4 @@
+pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
+pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
+released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
+released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
diff --git a/app/tests/combo/layer-filter-1/native_posix.keymap b/app/tests/combo/layer-filter-1/native_posix.keymap
new file mode 100644
index 0000000..995f27e
--- /dev/null
+++ b/app/tests/combo/layer-filter-1/native_posix.keymap
@@ -0,0 +1,40 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+/* it is useful to set timeout to a large value when attaching a debugger. */
+#define TIMEOUT (60*60*1000)
+
+/ {
+ combos {
+ compatible = "zmk,combos";
+ combo_one {
+ timeout-ms = <TIMEOUT>;
+ key-positions = <0 1>;
+ bindings = <&kp X>;
+ layers = <1>;
+ };
+ };
+
+ keymap {
+ compatible = "zmk,keymap";
+ label ="Default keymap";
+
+ default_layer {
+ bindings = <
+ &kp A &kp B
+ &kp C &tog 1
+ >;
+ };
+ };
+};
+
+&kscan {
+ events = <
+ /* Combo One */
+ ZMK_MOCK_PRESS(0,0,10)
+ ZMK_MOCK_PRESS(0,1,10)
+ ZMK_MOCK_RELEASE(0,0,10)
+ ZMK_MOCK_RELEASE(0,1,10)
+ >;
+}; \ No newline at end of file