mirror of https://github.com/zmkfirmware/zmk.git
feat(core): (Optionally) use Zephyr keyboard input devices
Add ability to assign a keyboard `input` device to a physical layout, or use a chosen `zmk,matrix-input`.
This commit is contained in:
parent
45aef02581
commit
b466913009
|
|
@ -21,6 +21,9 @@ properties:
|
|||
kscan:
|
||||
type: phandle
|
||||
description: The kscan to use along with this layout. The `zmk,kscan` chosen will be used as a fallback if this property is omitted.
|
||||
input:
|
||||
type: phandle
|
||||
description: The input device to use along with this layout. The `zmk,matrix-input` chosen will be used as a fallback if this property is omitted.
|
||||
keys:
|
||||
type: phandle-array
|
||||
description: Array of key physical attributes.
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ struct zmk_physical_layout {
|
|||
|
||||
zmk_matrix_transform_t matrix_transform;
|
||||
const struct device *kscan;
|
||||
#if IS_ENABLED(CONFIG_INPUT)
|
||||
const struct device *input;
|
||||
#endif
|
||||
|
||||
const struct zmk_key_physical_attrs *keys;
|
||||
size_t keys_len;
|
||||
|
|
|
|||
|
|
@ -48,10 +48,15 @@ static void input_mock_work_cb(struct k_work *work) {
|
|||
}
|
||||
}
|
||||
|
||||
bool sync = cfg->events[base_idx + 3];
|
||||
input_report(dev, cfg->events[base_idx], cfg->events[base_idx + 1], cfg->events[base_idx + 2],
|
||||
cfg->events[base_idx + 3], K_NO_WAIT);
|
||||
sync, K_NO_WAIT);
|
||||
|
||||
k_work_schedule(&data->work, K_MSEC(cfg->event_period));
|
||||
if (sync) {
|
||||
k_work_schedule(&data->work, K_MSEC(cfg->event_period));
|
||||
} else {
|
||||
k_work_schedule(&data->work, K_NO_WAIT);
|
||||
}
|
||||
}
|
||||
|
||||
int input_mock_init(const struct device *dev) {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <zephyr/pm/device.h>
|
||||
#include <zephyr/pm/device_runtime.h>
|
||||
#include <zephyr/drivers/kscan.h>
|
||||
#include <zephyr/input/input.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_SETTINGS)
|
||||
#include <zephyr/settings/settings.h>
|
||||
|
|
@ -27,6 +28,16 @@ ZMK_EVENT_IMPL(zmk_physical_layout_selection_changed);
|
|||
|
||||
#define DT_DRV_COMPAT zmk_physical_layout
|
||||
|
||||
#define MATRIX_INPUT_SUPPORT \
|
||||
UTIL_AND(IS_ENABLED(CONFIG_INPUT), \
|
||||
UTIL_OR(DT_ANY_INST_HAS_PROP_STATUS_OKAY(input), DT_HAS_CHOSEN(zmk_matrix_input)))
|
||||
|
||||
#if MATRIX_INPUT_SUPPORT
|
||||
|
||||
static void zmk_physical_layout_input_event_cb(struct input_event *evt, void *user_data);
|
||||
|
||||
#endif
|
||||
|
||||
#define USE_PHY_LAYOUTS \
|
||||
(DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) && !DT_HAS_CHOSEN(zmk_matrix_transform))
|
||||
|
||||
|
|
@ -53,6 +64,10 @@ BUILD_ASSERT(
|
|||
()) \
|
||||
}
|
||||
|
||||
#define INPUT_FOR_INST(n) \
|
||||
DEVICE_DT_GET(COND_CODE_1(DT_INST_PROP_LEN(n, input), (DT_INST_PHANDLE(n, input)), \
|
||||
(DT_CHOSEN(zmk_matrix_input))))
|
||||
|
||||
#define ZMK_LAYOUT_INST(n) \
|
||||
BUILD_ASSERT(!IS_ENABLED(CONFIG_ZMK_STUDIO) || DT_INST_NODE_HAS_PROP(n, keys), \
|
||||
"ZMK Studio requires physical layouts with key positions. See " \
|
||||
|
|
@ -67,8 +82,18 @@ BUILD_ASSERT(
|
|||
.matrix_transform = ZMK_MATRIX_TRANSFORM_T_FOR_NODE(DT_INST_PHANDLE(n, transform)), \
|
||||
.keys = _CONCAT(_zmk_physical_layout_keys_, n), \
|
||||
.keys_len = DT_INST_PROP_LEN_OR(n, keys, 0), \
|
||||
.kscan = DEVICE_DT_GET(COND_CODE_1(DT_INST_PROP_LEN(n, kscan), \
|
||||
(DT_INST_PHANDLE(n, kscan)), (DT_CHOSEN(zmk_kscan))))};
|
||||
COND_CODE_1(UTIL_AND(MATRIX_INPUT_SUPPORT, DT_INST_PROP_LEN(n, input)), \
|
||||
(.input = INPUT_FOR_INST(n)), ()) \
|
||||
COND_CODE_1(UTIL_OR(DT_HAS_CHOSEN(zmk_kscan), DT_INST_PROP_LEN(n, kscan)), \
|
||||
(.kscan = DEVICE_DT_GET(COND_CODE_1(DT_INST_PROP_LEN(n, kscan), \
|
||||
(DT_INST_PHANDLE(n, kscan)), \
|
||||
(DT_CHOSEN(zmk_kscan))))), \
|
||||
())}; \
|
||||
COND_CODE_1( \
|
||||
UTIL_AND(MATRIX_INPUT_SUPPORT, DT_INST_PROP_LEN(n, input)), \
|
||||
(INPUT_CALLBACK_DEFINE(INPUT_FOR_INST(n), zmk_physical_layout_input_event_cb, \
|
||||
(void *)&(_CONCAT(_zmk_physical_layout_, DT_DRV_INST(n))));), \
|
||||
())
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(ZMK_LAYOUT_INST)
|
||||
|
||||
|
|
@ -135,12 +160,12 @@ static const struct zmk_physical_layout _CONCAT(_zmk_physical_layout_, chosen) =
|
|||
static const struct zmk_physical_layout *const layouts[] = {
|
||||
&_CONCAT(_zmk_physical_layout_, chosen)};
|
||||
|
||||
#elif DT_HAS_CHOSEN(zmk_kscan)
|
||||
#elif UTIL_OR(DT_HAS_CHOSEN(zmk_kscan), DT_HAS_CHOSEN(zmk_matrix_input))
|
||||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
#warning \
|
||||
"Ignoring the physical layouts and using the chosen kscan with a synthetic transform. Consider setting a chosen physical layout instead."
|
||||
"Ignoring the physical layouts and using the chosen kscan/matrix-input with a synthetic transform. Consider setting a chosen physical layout instead."
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -148,9 +173,19 @@ ZMK_MATRIX_TRANSFORM_DEFAULT_EXTERN();
|
|||
static const struct zmk_physical_layout _CONCAT(_zmk_physical_layout_, chosen) = {
|
||||
.display_name = "Default",
|
||||
.matrix_transform = &zmk_matrix_transform_default,
|
||||
#if DT_HAS_CHOSEN(zmk_matrix_input)
|
||||
.input = DEVICE_DT_GET(DT_CHOSEN(zmk_matrix_input)),
|
||||
#elif DT_HAS_CHOSEN(zmk_kscan)
|
||||
.kscan = DEVICE_DT_GET(DT_CHOSEN(zmk_kscan)),
|
||||
#endif
|
||||
};
|
||||
|
||||
#if DT_HAS_CHOSEN(zmk_matrix_input)
|
||||
INPUT_CALLBACK_DEFINE(DEVICE_DT_GET(DT_CHOSEN(zmk_matrix_input)),
|
||||
zmk_physical_layout_input_event_cb,
|
||||
(void *)&(_CONCAT(_zmk_physical_layout_, chosen)));
|
||||
#endif
|
||||
|
||||
static const struct zmk_physical_layout *const layouts[] = {
|
||||
&_CONCAT(_zmk_physical_layout_, chosen)};
|
||||
|
||||
|
|
@ -180,6 +215,55 @@ static struct zmk_kscan_msg_processor {
|
|||
K_MSGQ_DEFINE(physical_layouts_kscan_msgq, sizeof(struct zmk_kscan_event),
|
||||
CONFIG_ZMK_KSCAN_EVENT_QUEUE_SIZE, 4);
|
||||
|
||||
#if MATRIX_INPUT_SUPPORT
|
||||
|
||||
static struct zmk_kscan_event pending_input_event;
|
||||
|
||||
static void zmk_physical_layout_input_event_cb(struct input_event *evt, void *user_data) {
|
||||
const struct zmk_physical_layout *layout = (const struct zmk_physical_layout *)user_data;
|
||||
if (layout != active) {
|
||||
LOG_WRN("Ignoring input event from non-active layout");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (evt->type) {
|
||||
case INPUT_EV_ABS:
|
||||
switch (evt->code) {
|
||||
case INPUT_ABS_X:
|
||||
pending_input_event.column = evt->value;
|
||||
break;
|
||||
case INPUT_ABS_Y:
|
||||
pending_input_event.row = evt->value;
|
||||
break;
|
||||
default:
|
||||
LOG_WRN("Unknown abs code");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case INPUT_EV_KEY:
|
||||
switch (evt->code) {
|
||||
case INPUT_BTN_TOUCH:
|
||||
pending_input_event.state =
|
||||
(evt->value ? ZMK_KSCAN_EVENT_STATE_PRESSED : ZMK_KSCAN_EVENT_STATE_RELEASED);
|
||||
break;
|
||||
default:
|
||||
LOG_WRN("Unknown key code");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_WRN("Unknown type");
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt->sync) {
|
||||
k_msgq_put(&physical_layouts_kscan_msgq, &pending_input_event, K_NO_WAIT);
|
||||
k_work_submit(&msg_processor.work);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void zmk_physical_layout_kscan_callback(const struct device *dev, uint32_t row,
|
||||
uint32_t column, bool pressed) {
|
||||
if (dev != active->kscan) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
s/.*hid_listener_keycode_//p
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||
released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||
|
|
@ -0,0 +1 @@
|
|||
CONFIG_INPUT=y
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include <dt-bindings/zmk/matrix_transform.h>
|
||||
|
||||
/delete-node/ &kscan;
|
||||
|
||||
/ {
|
||||
physical_layout: physical_layout {
|
||||
display-name = "Layout";
|
||||
compatible = "zmk,physical-layout";
|
||||
input = <&mock_matrix_input>;
|
||||
transform = <&matrix_transform0>;
|
||||
};
|
||||
|
||||
chosen {
|
||||
/delete-property/ zmk,kscan;
|
||||
|
||||
// zmk,matrix-input = &mock_matrix_input;
|
||||
};
|
||||
|
||||
matrix_transform0: keymap_transform_0 {
|
||||
compatible = "zmk,matrix-transform";
|
||||
columns = <20>;
|
||||
rows = <5>;
|
||||
|
||||
|
||||
map = <
|
||||
RC(0,0) RC(0,1)
|
||||
RC(1,0) RC(1,1)
|
||||
>;
|
||||
};
|
||||
|
||||
mock_matrix_input: mock_matrix_input {
|
||||
compatible = "zmk,input-mock";
|
||||
|
||||
event-startup-delay = <100>;
|
||||
event-period = <2000>;
|
||||
events
|
||||
= <INPUT_EV_ABS INPUT_ABS_X 0 0>
|
||||
, <INPUT_EV_ABS INPUT_ABS_Y 0 0>
|
||||
, <INPUT_EV_KEY INPUT_BTN_TOUCH 1 1>
|
||||
, <INPUT_EV_ABS INPUT_ABS_X 0 0>
|
||||
, <INPUT_EV_ABS INPUT_ABS_Y 0 0>
|
||||
, <INPUT_EV_KEY INPUT_BTN_TOUCH 0 1>
|
||||
;
|
||||
exit-after;
|
||||
};
|
||||
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&kp B &kp C
|
||||
&kp D &kp E
|
||||
>;
|
||||
};
|
||||
};
|
||||
};
|
||||
Loading…
Reference in New Issue