From 53aadc4f931a27d7b1350ea99cdc79106e138ad3 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Fri, 22 May 2020 22:47:03 -0400 Subject: [PATCH 1/2] Initial exploration of mod tap action. --- Kconfig | 8 +++ .../keymaps/default/keymap.overlay | 2 +- include/dt-bindings/zmk/keys.h | 27 +++++++--- include/zmk/endpoints.h | 1 + include/zmk/hid.h | 4 +- include/zmk/keys.h | 6 ++- include/zmk/kscan-mock.h | 2 +- prj.conf | 1 + src/endpoints.c | 37 ++++++++------ src/handlers.c | 51 +++++++++++++++++++ src/hid.c | 12 +++++ src/kscan.c | 4 +- src/kscan_mock.c | 6 +-- 13 files changed, 126 insertions(+), 35 deletions(-) diff --git a/Kconfig b/Kconfig index d778b64e..264c4510 100644 --- a/Kconfig +++ b/Kconfig @@ -25,6 +25,14 @@ config ZMK_KSCAN_MOCK_DRIVER bool "Enable mock kscan driver to simulate key presses" default n +menu "ZMK Actions" + +config ZMK_ACTION_MOD_TAP + bool "Enable the Mod-Tap Action" + default true + +endmenu + module = ZMK module-str = zmk source "subsys/logging/Kconfig.template.log_config" diff --git a/boards/shields/petejohanson_handwire/keymaps/default/keymap.overlay b/boards/shields/petejohanson_handwire/keymaps/default/keymap.overlay index ccc42303..863e0341 100644 --- a/boards/shields/petejohanson_handwire/keymaps/default/keymap.overlay +++ b/boards/shields/petejohanson_handwire/keymaps/default/keymap.overlay @@ -18,7 +18,7 @@ label = "DEFAULT"; keys = < - KC_A KC_B + KC_A MT(MOD_LSFT, KC_B) CC_RAIS CC_LOWR >; }; diff --git a/include/dt-bindings/zmk/keys.h b/include/dt-bindings/zmk/keys.h index 5a2d97a2..93b5ba3a 100644 --- a/include/dt-bindings/zmk/keys.h +++ b/include/dt-bindings/zmk/keys.h @@ -74,11 +74,22 @@ #define ZC_CSTM(n) (0xFF + n) -#define MOD_LCTL 0x00 -#define MOD_LSFT 0x01 -#define MOD_LALT 0x02 -#define MOD_LGUI 0x03 -#define MOD_RCTL 0x04 -#define MOD_RSFT 0x05 -#define MOD_RALT 0x06 -#define MOD_RGUI 0x07 \ No newline at end of file +#define MOD_LCTL (1 << 0x00) +#define MOD_LSFT (1 << 0x01) +#define MOD_LALT (1 << 0x02) +#define MOD_LGUI (1 << 0x03) +#define MOD_RCTL (1 << 0x04) +#define MOD_RSFT (1 << 0x05) +#define MOD_RALT (1 << 0x06) +#define MOD_RGUI (1 << 0x07) + +#define ZK_ACTION(k) (k >> 24) +#define _ACTION(a) (a << 24) +#define _ACTION_MODS(m) (m << 16) +#define ZK_MODS(a) ((a >> 16) & 0xFF) + +#define ZMK_ACTION_KEY 0x01 +#define ZMK_ACTION_MOD_TAP 0x01 +#define ZMK_ACTION_ONE_SHOT 0x02 + +#define MT(mods, kc) (_ACTION(ZMK_ACTION_MOD_TAP) + _ACTION_MODS(mods) + kc) diff --git a/include/zmk/endpoints.h b/include/zmk/endpoints.h index 42734aac..666f00da 100644 --- a/include/zmk/endpoints.h +++ b/include/zmk/endpoints.h @@ -3,4 +3,5 @@ #include int zmk_endpoints_init(); +int zmk_endpoints_send_report(); int zmk_endpoints_send_key_event(struct zmk_key_event key_event); diff --git a/include/zmk/hid.h b/include/zmk/hid.h index 8fbcf4fd..3767b783 100644 --- a/include/zmk/hid.h +++ b/include/zmk/hid.h @@ -97,12 +97,14 @@ static const u8_t zmk_hid_report_desc[] = { struct zmk_hid_report { - u8_t modifiers; + zmk_mod_flags modifiers; u8_t keys[13]; } __packed; int zmk_hid_register_mod(zmk_mod modifier); int zmk_hid_unregister_mod(zmk_mod modifier); +int zmk_hid_register_mods(zmk_mod_flags modifiers); +int zmk_hid_unregister_mods(zmk_mod_flags modifiers); int zmk_hid_press_key(zmk_key key); int zmk_hid_release_key(zmk_key key); diff --git a/include/zmk/keys.h b/include/zmk/keys.h index be057841..6966bbac 100644 --- a/include/zmk/keys.h +++ b/include/zmk/keys.h @@ -3,11 +3,15 @@ #include #include -typedef u64_t zmk_key; +typedef u32_t zmk_key; +typedef u8_t zmk_action; typedef u8_t zmk_mod; +typedef u8_t zmk_mod_flags; struct zmk_key_event { + u32_t column; + u32_t row; zmk_key key; bool pressed; }; \ No newline at end of file diff --git a/include/zmk/kscan-mock.h b/include/zmk/kscan-mock.h index b19cafb9..d481899f 100644 --- a/include/zmk/kscan-mock.h +++ b/include/zmk/kscan-mock.h @@ -1,6 +1,6 @@ #pragma once -#define ZMK_MOCK_IS_PRESS(v) (v & (0x01 << 31)) +#define ZMK_MOCK_IS_PRESS(v) ((v & (0x01 << 31)) != 0) #define ZMK_MOCK_PRESS(row, col, msec) (row + (col << 8) + (msec << 16) + (0x01 << 31)) #define ZMK_MOCK_RELEASE(row, col, msec) (row + (col << 8) + (msec << 16)) #define ZMK_MOCK_ROW(v) (v & 0xFF) diff --git a/prj.conf b/prj.conf index 5e0c8bb9..863e5024 100644 --- a/prj.conf +++ b/prj.conf @@ -5,6 +5,7 @@ CONFIG_USB_DEVICE_STACK=y CONFIG_USB_DEVICE_HID=y CONFIG_USB_DEVICE_PRODUCT="ZMK Firmware" CONFIG_ZMK_BLE=y +CONFIG_ZMK_ACTION_MOD_TAP=y # HID GATT notifications sent this way are *not* picked up by Linux, and possibly others. CONFIG_BT_GATT_NOTIFY_MULTIPLE=n CONFIG_BT_DEVICE_NAME="ZMK Keyboard" diff --git a/src/endpoints.c b/src/endpoints.c index 5e9fcdfb..3f2d5760 100644 --- a/src/endpoints.c +++ b/src/endpoints.c @@ -33,24 +33,10 @@ int zmk_endpoints_init() return 0; } -int zmk_endpoints_send_key_event(struct zmk_key_event key_event) +int zmk_endpoints_send_report() { - struct zmk_hid_report *report; int err; - - LOG_DBG("key %lld, state %d\n", key_event.key, key_event.pressed); - - - if (key_event.pressed) - { - zmk_hid_press_key(key_event.key); - } - else - { - zmk_hid_release_key(key_event.key); - } - - report = zmk_hid_get_report(); + struct zmk_hid_report *report = zmk_hid_get_report(); // if (zmk_usb_hid_send_report(report) != 0) // { @@ -67,3 +53,22 @@ int zmk_endpoints_send_key_event(struct zmk_key_event key_event) return 0; } + +int zmk_endpoints_send_key_event(struct zmk_key_event key_event) +{ + struct zmk_hid_report *report; + int err; + + LOG_DBG("key %d, state %d\n", key_event.key, key_event.pressed); + + if (key_event.pressed) + { + zmk_hid_press_key(key_event.key); + } + else + { + zmk_hid_release_key(key_event.key); + } + + return zmk_endpoints_send_report(); +} diff --git a/src/handlers.c b/src/handlers.c index b73c92cd..8c463a95 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -2,20 +2,71 @@ #include #include #include +#include +#include + +#ifdef CONFIG_ZMK_ACTION_MOD_TAP +u16_t action_effect_pending = 0; +#endif __attribute__((weak)) bool zmk_handle_key_user(struct zmk_key_event *key_event) { return true; }; +bool zmk_handle_action(zmk_action action, struct zmk_key_event *key_event) +{ + zmk_mod mods = ZK_MODS(key_event->key); + u8_t flattened_index = (key_event->row * ZMK_MATRIX_COLS) + key_event->column; + switch (action) + { +#ifdef CONFIG_ZMK_ACTION_MOD_TAP + case ZMK_ACTION_MOD_TAP: + if (key_event->pressed) + { + WRITE_BIT(action_effect_pending, flattened_index, true); + zmk_hid_register_mods(mods); + } + else + { + zmk_hid_unregister_mods(mods); + if (action_effect_pending & BIT(flattened_index)) + { + // Allow baseline keycode to flow to the endpoints! + return true; + } + else + { + // Since not sending a keycode, at least send the report w/ the mod removed + zmk_endpoints_send_report(); + } + } + break; +#endif + } + return false; +}; + void zmk_handle_key(struct zmk_key_event key_event) { + zmk_action action = ZK_ACTION(key_event.key); + if (!zmk_handle_key_user(&key_event)) { return; } + if (action && !zmk_handle_action(action, &key_event)) + { + return; + } + +#ifdef CONFIG_ZMK_ACTION_MOD_TAP + action_effect_pending = 0; +#endif + #ifdef CONFIG_ZMK_BLE + /* Used for intercepting key presses when doing passkey verification */ if (!zmk_ble_handle_key_user(&key_event)) { return; diff --git a/src/hid.c b/src/hid.c index 51f92a71..5e87b596 100644 --- a/src/hid.c +++ b/src/hid.c @@ -21,6 +21,18 @@ int zmk_hid_unregister_mod(zmk_mod modifier) _TOGGLE_MOD(modifier, false); } +int zmk_hid_register_mods(zmk_mod_flags modifiers) +{ + report.modifiers |= modifiers; + printk("After register mods %d have %d\n", modifiers, report.modifiers); +} + +int zmk_hid_unregister_mods(zmk_mod_flags modifiers) +{ + report.modifiers &= ~modifiers; + printk("After unregister mods %d have %d\n", modifiers, report.modifiers); +} + #define KEY_OFFSET 0x02 #define MAX_KEYS 6 diff --git a/src/kscan.c b/src/kscan.c index 83e8ca66..1f54a147 100644 --- a/src/kscan.c +++ b/src/kscan.c @@ -50,9 +50,9 @@ void zmk_kscan_process_msgq(struct k_work *item) { bool pressed = (ev.state == ZMK_KSCAN_EVENT_STATE_PRESSED); zmk_key key = zmk_keymap_keycode_from_position(ev.row, ev.column); - struct zmk_key_event kev = (struct zmk_key_event){.key = key, .pressed = pressed}; + struct zmk_key_event kev = (struct zmk_key_event){.row = ev.row, .column = ev.column, .key = key, .pressed = pressed}; - LOG_DBG("Row: %d, col: %d, key: %lld, pressed: %s\n", ev.row, ev.column, key, (pressed ? "true" : "false")); + LOG_DBG("Row: %d, col: %d, key: %d, pressed: %s\n", ev.row, ev.column, key, (pressed ? "true" : "false")); zmk_handle_key(kev); } } diff --git a/src/kscan_mock.c b/src/kscan_mock.c index 09a01617..a2143352 100644 --- a/src/kscan_mock.c +++ b/src/kscan_mock.c @@ -68,7 +68,7 @@ static void kscan_mock_work_handler(struct k_work *work) struct kscan_mock_config *cfg = data->dev->config_info; u32_t ev = cfg->events[data->event_index++]; - LOG_DBG("Triggering ev %d\n", ev); + LOG_DBG("ev %u row %d column %d state %d\n", ev, ZMK_MOCK_ROW(ev), ZMK_MOCK_COL(ev), ZMK_MOCK_IS_PRESS(ev)); data->callback(data->dev, ZMK_MOCK_ROW(ev), ZMK_MOCK_COL(ev), ZMK_MOCK_IS_PRESS(ev)); kscan_mock_schedule_next_event(data->dev); } @@ -93,10 +93,6 @@ static int kscan_mock_init(struct device *dev) struct kscan_mock_data *data = dev->driver_data; const struct kscan_mock_config *cfg = dev->config_info; - printk("Init first event: %d\n", cfg->events[0]); - - int err; - data->dev = dev; k_delayed_work_init(&data->work, kscan_mock_work_handler); From 76a433fc392be31e56df256b630a21e61775d0af Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Sun, 24 May 2020 23:13:33 -0400 Subject: [PATCH 2/2] Clean up and implement MT release w/o mod press. --- boards/native_posix.overlay | 5 +++-- include/dt-bindings/zmk/keys.h | 1 + src/endpoints.c | 3 --- src/handlers.c | 12 ++++++++++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/boards/native_posix.overlay b/boards/native_posix.overlay index cd71191c..1d692d4e 100644 --- a/boards/native_posix.overlay +++ b/boards/native_posix.overlay @@ -13,7 +13,8 @@ rows = <2>; columns = <2>; - events = ; + events = ; + // events = ; }; keymap0: keymap { @@ -29,7 +30,7 @@ label = "DEFAULT"; keys = < - KC_A KC_B + KC_A MT(MOD_LSFT, KC_B) KC_C KC_D >; }; diff --git a/include/dt-bindings/zmk/keys.h b/include/dt-bindings/zmk/keys.h index 93b5ba3a..c266de00 100644 --- a/include/dt-bindings/zmk/keys.h +++ b/include/dt-bindings/zmk/keys.h @@ -86,6 +86,7 @@ #define ZK_ACTION(k) (k >> 24) #define _ACTION(a) (a << 24) #define _ACTION_MODS(m) (m << 16) +#define ZK_KEY(a) (a & 0xFFFF) #define ZK_MODS(a) ((a >> 16) & 0xFF) #define ZMK_ACTION_KEY 0x01 diff --git a/src/endpoints.c b/src/endpoints.c index 3f2d5760..668380ad 100644 --- a/src/endpoints.c +++ b/src/endpoints.c @@ -56,9 +56,6 @@ int zmk_endpoints_send_report() int zmk_endpoints_send_key_event(struct zmk_key_event key_event) { - struct zmk_hid_report *report; - int err; - LOG_DBG("key %d, state %d\n", key_event.key, key_event.pressed); if (key_event.pressed) diff --git a/src/handlers.c b/src/handlers.c index 8c463a95..ff969b18 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -32,8 +32,16 @@ bool zmk_handle_action(zmk_action action, struct zmk_key_event *key_event) zmk_hid_unregister_mods(mods); if (action_effect_pending & BIT(flattened_index)) { - // Allow baseline keycode to flow to the endpoints! - return true; + struct zmk_key_event non_mod_event = + { + .row = key_event->row, + .column = key_event->column, + .key = ZK_KEY(key_event->key), + .pressed = true}; + + zmk_handle_key(non_mod_event); + non_mod_event.pressed = false; + zmk_handle_key(non_mod_event); } else {