summaryrefslogtreecommitdiff
path: root/app/src
diff options
context:
space:
mode:
authorPete Johanson <peter@peterjohanson.com>2020-07-31 00:07:16 -0400
committerPete Johanson <peter@peterjohanson.com>2020-07-31 00:07:16 -0400
commitf548f2a87c670a2b56507bc104e1af39fa3846e7 (patch)
treee67f674281b03ec58c9c349cd1df497395b4cead /app/src
parentf269b26ea1cdd61e39f13c6e11cbdfcdc6a0bd5c (diff)
Initial stab at mod-tap improvements.
* Not working: Roll over + mod-tap with multiple mod-tap bindings!
Diffstat (limited to 'app/src')
-rw-r--r--app/src/behaviors/behavior_key_press.c14
-rw-r--r--app/src/behaviors/behavior_mod_tap.c173
-rw-r--r--app/src/event_manager.c16
-rw-r--r--app/src/events/keycode_state_changed.c2
4 files changed, 179 insertions, 26 deletions
diff --git a/app/src/behaviors/behavior_key_press.c b/app/src/behaviors/behavior_key_press.c
index 34df1c0..7404c79 100644
--- a/app/src/behaviors/behavior_key_press.c
+++ b/app/src/behaviors/behavior_key_press.c
@@ -28,27 +28,17 @@ static int behavior_key_press_init(struct device *dev)
static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t keycode, u32_t _)
{
const struct behavior_key_press_config *cfg = dev->config_info;
- struct keycode_state_changed *ev;
LOG_DBG("position %d usage_page 0x%02X keycode 0x%02X", position, cfg->usage_page, keycode);
- ev = new_keycode_state_changed();
- ev->usage_page = cfg->usage_page;
- ev->keycode = keycode;
- ev->state = true;
- return ZMK_EVENT_RAISE(ev);
+ return ZMK_EVENT_RAISE(create_keycode_state_changed(cfg->usage_page, keycode, true));
}
static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t keycode, u32_t _)
{
const struct behavior_key_press_config *cfg = dev->config_info;
- struct keycode_state_changed *ev;
LOG_DBG("position %d usage_page 0x%02X keycode 0x%02X", position, cfg->usage_page, keycode);
- ev = new_keycode_state_changed();
- ev->usage_page = cfg->usage_page;
- ev->keycode = keycode;
- ev->state = false;
- return ZMK_EVENT_RAISE(ev);
+ return ZMK_EVENT_RAISE(create_keycode_state_changed(cfg->usage_page, keycode, false));
}
static const struct behavior_driver_api behavior_key_press_driver_api = {
diff --git a/app/src/behaviors/behavior_mod_tap.c b/app/src/behaviors/behavior_mod_tap.c
index 62604eb..df3eec2 100644
--- a/app/src/behaviors/behavior_mod_tap.c
+++ b/app/src/behaviors/behavior_mod_tap.c
@@ -10,25 +10,110 @@
#include <drivers/behavior.h>
#include <logging/log.h>
+#include <zmk/matrix.h>
+#include <zmk/endpoints.h>
#include <zmk/event-manager.h>
#include <zmk/events/keycode-state-changed.h>
#include <zmk/events/modifiers-state-changed.h>
+#include <zmk/hid.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
+#define ZMK_BHV_MOD_TAP_MAX_HELD 4
+#define ZMK_BHV_MOD_TAP_MAX_PENDING_KC 4
+
+#define TOGGLE_FIRST(arr, len, match, val) \
+ for (int idx = 0; idx < len; idx++) \
+ { \
+ if (arr[idx] != match) \
+ { \
+ continue; \
+ } \
+ arr[idx] = val; \
+ break; \
+ }
+
+struct pending_mod_tap_item {
+ u32_t keycode;
+ u8_t mods;
+};
+
struct behavior_mod_tap_config { };
struct behavior_mod_tap_data {
- u16_t pending_press_positions;
+ struct pending_mod_tap_item pending_mod_taps[ZMK_BHV_MOD_TAP_MAX_HELD];
+ struct pending_mod_tap_item triggered_mod_taps[ZMK_BHV_MOD_TAP_MAX_HELD];
+ struct keycode_state_changed* pending_key_presses[ZMK_BHV_MOD_TAP_MAX_PENDING_KC];
};
+bool have_pending_mods(char *label) {
+ struct device *dev = device_get_binding(label);
+ struct behavior_mod_tap_data *data = dev->driver_data;
+
+ for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_HELD; i++) {
+ if (data->pending_mod_taps[i].mods) {
+ LOG_DBG("Found pending mods for %d and keycode 0x%02X", data->pending_mod_taps[i].mods, data->pending_mod_taps[i].keycode);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool have_pending_keycode(struct behavior_mod_tap_data *data, u32_t keycode)
+{
+ for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_PENDING_KC; i++) {
+ if (data->pending_key_presses[i] == NULL) {
+ continue;
+ }
+
+ if (data->pending_key_presses[i]->keycode == keycode) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// How to pass context to subscription?!
int behavior_mod_tap_listener(const struct zmk_event_header *eh)
{
- if (is_keycode_state_changed(eh)) {
+ if (is_keycode_state_changed(eh) && have_pending_mods(DT_INST_LABEL(0))) {
struct device *dev = device_get_binding(DT_INST_LABEL(0));
- const struct keycode_state_changed *ev = cast_keycode_state_changed(eh);
+ struct keycode_state_changed *ev = cast_keycode_state_changed(eh);
+ struct behavior_mod_tap_data *data = dev->driver_data;
if (ev->state) {
- struct behavior_mod_tap_data *data = dev->driver_data;
- data->pending_press_positions = 0;
+ LOG_DBG("Have pending mods, capturing keycode 0x%02X event to ressend later", ev->keycode);
+ TOGGLE_FIRST(data->pending_key_presses, ZMK_BHV_MOD_TAP_MAX_PENDING_KC, NULL, ev);
+ return ZMK_EV_EVENT_CAPTURED;
+ } else if (have_pending_keycode(data, ev->keycode)) {
+ zmk_mod_flags mods = 0;
+
+ LOG_DBG("Key released, going to activate mods then send pending key presses");
+ for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_HELD; i++) {
+ memcpy(&data->triggered_mod_taps[i], &data->pending_mod_taps[i], sizeof(struct pending_mod_tap_item));
+ data->pending_mod_taps[i].mods = 0;
+ data->pending_mod_taps[i].keycode = 0;
+ }
+ LOG_DBG("After swapping, do I have pending mods? %s", (have_pending_mods(DT_INST_LABEL(0)) ? "true" : "false"));
+
+ for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_HELD; i++) {
+ mods |= data->triggered_mod_taps[i].mods;
+ }
+
+ LOG_DBG("Setting mods: %d", mods);
+
+ zmk_hid_register_mods(mods);
+
+ for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_PENDING_KC; i++) {
+ if (data->pending_key_presses[i] == NULL) {
+ continue;
+ }
+
+ struct keycode_state_changed *ev = data->pending_key_presses[i];
+ data->pending_key_presses[i] = NULL;
+ ZMK_EVENT_RAISE(ev);
+ k_msleep(10);
+ }
}
}
return 0;
@@ -46,22 +131,84 @@ static int behavior_mod_tap_init(struct device *dev)
static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t mods, u32_t keycode)
{
struct behavior_mod_tap_data *data = dev->driver_data;
- LOG_DBG("mods: %d, keycode: %d", mods, keycode);
- WRITE_BIT(data->pending_press_positions, position, true);
- return ZMK_EVENT_RAISE(create_modifiers_state_changed(mods, true));
+ LOG_DBG("mods: %d, keycode: 0x%02X", mods, keycode);
+ for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_HELD; i++) {
+ if (data->pending_mod_taps[i].mods != 0) {
+ continue;
+ }
+
+ data->pending_mod_taps[i].mods = mods;
+ data->pending_mod_taps[i].keycode = keycode;
+
+ return 0;
+ }
+
+ return -ENOMEM;
}
static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t mods, u32_t keycode)
{
struct behavior_mod_tap_data *data = dev->driver_data;
+ bool sending_keycode = false;
+ bool sent_pending_key_presses = false;
+ struct keycode_state_changed *pending_key_presses[ZMK_BHV_MOD_TAP_MAX_PENDING_KC];
LOG_DBG("mods: %d, keycode: %d", mods, keycode);
- ZMK_EVENT_RAISE(create_modifiers_state_changed(mods, false));
- k_msleep(10); // TODO: Better approach than k_msleep to avoid USB send failures? Retries in the USB endpoint layer?
- if (data->pending_press_positions & BIT(position)) {
- ZMK_EVENT_RAISE(create_keycode_state_changed(USAGE_KEYPAD, keycode, true));
+ for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_HELD; i++) {
+ if (data->triggered_mod_taps[i].mods == mods && data->triggered_mod_taps[i].keycode == keycode) {
+ LOG_DBG("Releasing triggered mods: %d", mods);
+ zmk_hid_unregister_mods(mods);
+ data->triggered_mod_taps[i].mods = 0;
+ data->triggered_mod_taps[i].keycode = 0;
+ break;
+ }
+ }
+
+ for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_HELD; i++) {
+ if (data->pending_mod_taps[i].mods == mods && data->pending_mod_taps[i].keycode == keycode) {
+ sending_keycode = true;
+ data->pending_mod_taps[i].mods = 0;
+ data->pending_mod_taps[i].keycode = 0;
+ break;
+ }
+ }
+
+ for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_PENDING_KC; i++) {
+ pending_key_presses[i] = data->pending_key_presses[i];
+ data->pending_key_presses[i] = NULL;
+ }
+
+
+ if (sending_keycode) {
+ struct keycode_state_changed *key_press = create_keycode_state_changed(USAGE_KEYPAD, keycode, true);
+ LOG_DBG("Sending un-triggered mod-tap for keycode: 0x%02X", keycode);
+ ZMK_EVENT_RAISE(key_press);
+ k_msleep(10);
+ }
+
+
+ for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_PENDING_KC; i++) {
+ if (pending_key_presses[i] == NULL) {
+ continue;
+ }
+
+ struct keycode_state_changed *ev = pending_key_presses[i];
+ sent_pending_key_presses = true;
+ LOG_DBG("Re-sending latched key press for usage page 0x%02X keycode 0x%02X state %s", ev->usage_page, ev->keycode, (ev->state ? "pressed" : "released"));
+ ZMK_EVENT_RELEASE(ev);
k_msleep(10);
- ZMK_EVENT_RAISE(create_keycode_state_changed(USAGE_KEYPAD, keycode, false));
+ }
+
+ if (sending_keycode) {
+ struct keycode_state_changed *key_release = create_keycode_state_changed(USAGE_KEYPAD, keycode, false);
+ LOG_DBG("Sending un-triggered mod-tap release for keycode: 0x%02X", keycode);
+ ZMK_EVENT_RAISE(key_release);
+ }
+
+ if (!sending_keycode && !sent_pending_key_presses) {
+ // Need to ensure the mod release is propagated.
+ zmk_endpoints_send_report(USAGE_KEYPAD);
+
}
return 0;
diff --git a/app/src/event_manager.c b/app/src/event_manager.c
index 3edba10..5d2e9ed 100644
--- a/app/src/event_manager.c
+++ b/app/src/event_manager.c
@@ -55,6 +55,22 @@ int zmk_event_manager_raise(struct zmk_event_header *event)
return zmk_event_manager_handle_from(event, 0);
}
+int zmk_event_manager_raise_after(struct zmk_event_header *event, const struct zmk_listener *listener)
+{
+ u8_t len = __event_subscriptions_end - __event_subscriptions_start;
+ for (int i = 0; i < len; i++) {
+ struct zmk_event_subscription *ev_sub = __event_subscriptions_start + i;
+
+ if (ev_sub->event_type == event->event && ev_sub->listener == listener) {
+ return zmk_event_manager_handle_from(event, i+1);
+ }
+ }
+
+ LOG_WRN("Unable to find where to raise this after event");
+
+ return -EINVAL;
+}
+
int zmk_event_manager_release(struct zmk_event_header *event)
{
return zmk_event_manager_handle_from(event, event->last_listener_index + 1);
diff --git a/app/src/events/keycode_state_changed.c b/app/src/events/keycode_state_changed.c
index 964b24a..73508e1 100644
--- a/app/src/events/keycode_state_changed.c
+++ b/app/src/events/keycode_state_changed.c
@@ -7,4 +7,4 @@
#include <kernel.h>
#include <zmk/events/keycode-state-changed.h>
-ZMK_EVENT_IMPL(keycode_state_changed); \ No newline at end of file
+ZMK_EVENT_IMPL(keycode_state_changed);