Merge branch 'actions/mod-tap-initial-work' into 'master'
Actions: Mod-Tap initial work See merge request zmkproject/zmk!1
This commit is contained in:
commit
96b87b2594
14 changed files with 135 additions and 37 deletions
8
Kconfig
8
Kconfig
|
@ -25,6 +25,14 @@ config ZMK_KSCAN_MOCK_DRIVER
|
||||||
bool "Enable mock kscan driver to simulate key presses"
|
bool "Enable mock kscan driver to simulate key presses"
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
menu "ZMK Actions"
|
||||||
|
|
||||||
|
config ZMK_ACTION_MOD_TAP
|
||||||
|
bool "Enable the Mod-Tap Action"
|
||||||
|
default true
|
||||||
|
|
||||||
|
endmenu
|
||||||
|
|
||||||
module = ZMK
|
module = ZMK
|
||||||
module-str = zmk
|
module-str = zmk
|
||||||
source "subsys/logging/Kconfig.template.log_config"
|
source "subsys/logging/Kconfig.template.log_config"
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
|
|
||||||
rows = <2>;
|
rows = <2>;
|
||||||
columns = <2>;
|
columns = <2>;
|
||||||
events = <ZMK_MOCK_PRESS(0,0,800) ZMK_MOCK_RELEASE(0,0,800)>;
|
events = <ZMK_MOCK_PRESS(0,1,300) ZMK_MOCK_PRESS(0,0,300) ZMK_MOCK_RELEASE(0,0,300) ZMK_MOCK_RELEASE(0,1,300)>;
|
||||||
|
// events = <ZMK_MOCK_PRESS(0,0,800) ZMK_MOCK_RELEASE(0,0,800) ZMK_MOCK_PRESS(0,1,800) ZMK_MOCK_RELEASE(0,1,800)>;
|
||||||
};
|
};
|
||||||
|
|
||||||
keymap0: keymap {
|
keymap0: keymap {
|
||||||
|
@ -29,7 +30,7 @@
|
||||||
label = "DEFAULT";
|
label = "DEFAULT";
|
||||||
keys =
|
keys =
|
||||||
<
|
<
|
||||||
KC_A KC_B
|
KC_A MT(MOD_LSFT, KC_B)
|
||||||
KC_C KC_D
|
KC_C KC_D
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
label = "DEFAULT";
|
label = "DEFAULT";
|
||||||
keys =
|
keys =
|
||||||
<
|
<
|
||||||
KC_A KC_B
|
KC_A MT(MOD_LSFT, KC_B)
|
||||||
CC_RAIS CC_LOWR
|
CC_RAIS CC_LOWR
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -74,11 +74,23 @@
|
||||||
|
|
||||||
#define ZC_CSTM(n) (0xFF + n)
|
#define ZC_CSTM(n) (0xFF + n)
|
||||||
|
|
||||||
#define MOD_LCTL 0x00
|
#define MOD_LCTL (1 << 0x00)
|
||||||
#define MOD_LSFT 0x01
|
#define MOD_LSFT (1 << 0x01)
|
||||||
#define MOD_LALT 0x02
|
#define MOD_LALT (1 << 0x02)
|
||||||
#define MOD_LGUI 0x03
|
#define MOD_LGUI (1 << 0x03)
|
||||||
#define MOD_RCTL 0x04
|
#define MOD_RCTL (1 << 0x04)
|
||||||
#define MOD_RSFT 0x05
|
#define MOD_RSFT (1 << 0x05)
|
||||||
#define MOD_RALT 0x06
|
#define MOD_RALT (1 << 0x06)
|
||||||
#define MOD_RGUI 0x07
|
#define MOD_RGUI (1 << 0x07)
|
||||||
|
|
||||||
|
#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
|
||||||
|
#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)
|
||||||
|
|
|
@ -3,4 +3,5 @@
|
||||||
#include <zmk/keys.h>
|
#include <zmk/keys.h>
|
||||||
|
|
||||||
int zmk_endpoints_init();
|
int zmk_endpoints_init();
|
||||||
|
int zmk_endpoints_send_report();
|
||||||
int zmk_endpoints_send_key_event(struct zmk_key_event key_event);
|
int zmk_endpoints_send_key_event(struct zmk_key_event key_event);
|
||||||
|
|
|
@ -97,12 +97,14 @@ static const u8_t zmk_hid_report_desc[] = {
|
||||||
|
|
||||||
struct zmk_hid_report
|
struct zmk_hid_report
|
||||||
{
|
{
|
||||||
u8_t modifiers;
|
zmk_mod_flags modifiers;
|
||||||
u8_t keys[13];
|
u8_t keys[13];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
int zmk_hid_register_mod(zmk_mod modifier);
|
int zmk_hid_register_mod(zmk_mod modifier);
|
||||||
int zmk_hid_unregister_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_press_key(zmk_key key);
|
||||||
int zmk_hid_release_key(zmk_key key);
|
int zmk_hid_release_key(zmk_key key);
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,15 @@
|
||||||
#include <zephyr.h>
|
#include <zephyr.h>
|
||||||
#include <dt-bindings/zmk/keys.h>
|
#include <dt-bindings/zmk/keys.h>
|
||||||
|
|
||||||
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;
|
||||||
|
typedef u8_t zmk_mod_flags;
|
||||||
|
|
||||||
struct zmk_key_event
|
struct zmk_key_event
|
||||||
{
|
{
|
||||||
|
u32_t column;
|
||||||
|
u32_t row;
|
||||||
zmk_key key;
|
zmk_key key;
|
||||||
bool pressed;
|
bool pressed;
|
||||||
};
|
};
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#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_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_RELEASE(row, col, msec) (row + (col << 8) + (msec << 16))
|
||||||
#define ZMK_MOCK_ROW(v) (v & 0xFF)
|
#define ZMK_MOCK_ROW(v) (v & 0xFF)
|
||||||
|
|
1
prj.conf
1
prj.conf
|
@ -5,6 +5,7 @@ CONFIG_USB_DEVICE_STACK=y
|
||||||
CONFIG_USB_DEVICE_HID=y
|
CONFIG_USB_DEVICE_HID=y
|
||||||
CONFIG_USB_DEVICE_PRODUCT="ZMK Firmware"
|
CONFIG_USB_DEVICE_PRODUCT="ZMK Firmware"
|
||||||
CONFIG_ZMK_BLE=y
|
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.
|
# HID GATT notifications sent this way are *not* picked up by Linux, and possibly others.
|
||||||
CONFIG_BT_GATT_NOTIFY_MULTIPLE=n
|
CONFIG_BT_GATT_NOTIFY_MULTIPLE=n
|
||||||
CONFIG_BT_DEVICE_NAME="ZMK Keyboard"
|
CONFIG_BT_DEVICE_NAME="ZMK Keyboard"
|
||||||
|
|
|
@ -33,24 +33,10 @@ int zmk_endpoints_init()
|
||||||
return 0;
|
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;
|
int err;
|
||||||
|
struct zmk_hid_report *report = zmk_hid_get_report();
|
||||||
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();
|
|
||||||
|
|
||||||
// if (zmk_usb_hid_send_report(report) != 0)
|
// if (zmk_usb_hid_send_report(report) != 0)
|
||||||
// {
|
// {
|
||||||
|
@ -67,3 +53,19 @@ int zmk_endpoints_send_key_event(struct zmk_key_event key_event)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int zmk_endpoints_send_key_event(struct zmk_key_event key_event)
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
|
@ -2,20 +2,79 @@
|
||||||
#include <zmk/ble.h>
|
#include <zmk/ble.h>
|
||||||
#include <zmk/handlers.h>
|
#include <zmk/handlers.h>
|
||||||
#include <zmk/endpoints.h>
|
#include <zmk/endpoints.h>
|
||||||
|
#include <zmk/hid.h>
|
||||||
|
#include <zmk/matrix.h>
|
||||||
|
|
||||||
|
#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)
|
__attribute__((weak)) bool zmk_handle_key_user(struct zmk_key_event *key_event)
|
||||||
{
|
{
|
||||||
return true;
|
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))
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
// 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)
|
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))
|
if (!zmk_handle_key_user(&key_event))
|
||||||
{
|
{
|
||||||
return;
|
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
|
#ifdef CONFIG_ZMK_BLE
|
||||||
|
/* Used for intercepting key presses when doing passkey verification */
|
||||||
if (!zmk_ble_handle_key_user(&key_event))
|
if (!zmk_ble_handle_key_user(&key_event))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
12
src/hid.c
12
src/hid.c
|
@ -21,6 +21,18 @@ int zmk_hid_unregister_mod(zmk_mod modifier)
|
||||||
_TOGGLE_MOD(modifier, false);
|
_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 KEY_OFFSET 0x02
|
||||||
#define MAX_KEYS 6
|
#define MAX_KEYS 6
|
||||||
|
|
||||||
|
|
|
@ -50,9 +50,9 @@ void zmk_kscan_process_msgq(struct k_work *item)
|
||||||
{
|
{
|
||||||
bool pressed = (ev.state == ZMK_KSCAN_EVENT_STATE_PRESSED);
|
bool pressed = (ev.state == ZMK_KSCAN_EVENT_STATE_PRESSED);
|
||||||
zmk_key key = zmk_keymap_keycode_from_position(ev.row, ev.column);
|
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);
|
zmk_handle_key(kev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ static void kscan_mock_work_handler(struct k_work *work)
|
||||||
struct kscan_mock_config *cfg = data->dev->config_info;
|
struct kscan_mock_config *cfg = data->dev->config_info;
|
||||||
|
|
||||||
u32_t ev = cfg->events[data->event_index++];
|
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));
|
data->callback(data->dev, ZMK_MOCK_ROW(ev), ZMK_MOCK_COL(ev), ZMK_MOCK_IS_PRESS(ev));
|
||||||
kscan_mock_schedule_next_event(data->dev);
|
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;
|
struct kscan_mock_data *data = dev->driver_data;
|
||||||
const struct kscan_mock_config *cfg = dev->config_info;
|
const struct kscan_mock_config *cfg = dev->config_info;
|
||||||
|
|
||||||
printk("Init first event: %d\n", cfg->events[0]);
|
|
||||||
|
|
||||||
int err;
|
|
||||||
|
|
||||||
data->dev = dev;
|
data->dev = dev;
|
||||||
k_delayed_work_init(&data->work, kscan_mock_work_handler);
|
k_delayed_work_init(&data->work, kscan_mock_work_handler);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue