refactor: Proper per-device input listeners.
* Buffer data from input devices and only surface to HID once synd'd.
This commit is contained in:
parent
77acca1981
commit
5513584a48
10 changed files with 220 additions and 201 deletions
|
@ -27,7 +27,6 @@ target_sources(app PRIVATE src/behavior.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_KSCAN_SIDEBAND_BEHAVIORS app PRIVATE src/kscan_sideband_behaviors.c)
|
target_sources_ifdef(CONFIG_ZMK_KSCAN_SIDEBAND_BEHAVIORS app PRIVATE src/kscan_sideband_behaviors.c)
|
||||||
target_sources(app PRIVATE src/matrix_transform.c)
|
target_sources(app PRIVATE src/matrix_transform.c)
|
||||||
target_sources(app PRIVATE src/physical_layouts.c)
|
target_sources(app PRIVATE src/physical_layouts.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/input_config.c)
|
|
||||||
target_sources(app PRIVATE src/sensors.c)
|
target_sources(app PRIVATE src/sensors.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/wpm.c)
|
target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/wpm.c)
|
||||||
target_sources(app PRIVATE src/event_manager.c)
|
target_sources(app PRIVATE src/event_manager.c)
|
||||||
|
@ -44,7 +43,7 @@ target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext
|
||||||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SOFT_OFF app PRIVATE src/behaviors/behavior_soft_off.c)
|
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SOFT_OFF app PRIVATE src/behaviors/behavior_soft_off.c)
|
||||||
if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||||
target_sources(app PRIVATE src/hid.c)
|
target_sources(app PRIVATE src/hid.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/hid_input_listener.c)
|
target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/input_listener.c)
|
||||||
target_sources(app PRIVATE src/behaviors/behavior_key_press.c)
|
target_sources(app PRIVATE src/behaviors/behavior_key_press.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_KEY_TOGGLE app PRIVATE src/behaviors/behavior_key_toggle.c)
|
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_KEY_TOGGLE app PRIVATE src/behaviors/behavior_key_toggle.c)
|
||||||
target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c)
|
target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c)
|
||||||
|
|
|
@ -21,6 +21,4 @@
|
||||||
#include <behaviors/macros.dtsi>
|
#include <behaviors/macros.dtsi>
|
||||||
#include <behaviors/mouse_key_press.dtsi>
|
#include <behaviors/mouse_key_press.dtsi>
|
||||||
#include <behaviors/soft_off.dtsi>
|
#include <behaviors/soft_off.dtsi>
|
||||||
#include <behaviors/mouse_move.dtsi>
|
|
||||||
#include <behaviors/mouse_scroll.dtsi>
|
|
||||||
#include <behaviors/macros.dtsi>
|
#include <behaviors/macros.dtsi>
|
||||||
|
|
|
@ -11,4 +11,9 @@
|
||||||
acceleration-exponent = <1>;
|
acceleration-exponent = <1>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mmv_input_listener {
|
||||||
|
compatible = "zmk,input-listener";
|
||||||
|
device = <&mmv>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,4 +11,9 @@
|
||||||
acceleration-exponent = <0>;
|
acceleration-exponent = <0>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
msc_input_listener {
|
||||||
|
compatible = "zmk,input-listener";
|
||||||
|
device = <&msc>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
description: |
|
|
||||||
Allows post-processing of input events based on the configuration
|
|
||||||
|
|
||||||
compatible: "zmk,input-configs"
|
|
||||||
|
|
||||||
child-binding:
|
|
||||||
description: "A configuration for a given input device"
|
|
||||||
|
|
||||||
properties:
|
|
||||||
device:
|
|
||||||
type: phandle
|
|
||||||
required: true
|
|
||||||
xy-swap:
|
|
||||||
type: boolean
|
|
||||||
x-invert:
|
|
||||||
type: boolean
|
|
||||||
y-invert:
|
|
||||||
type: boolean
|
|
||||||
scale-multiplier:
|
|
||||||
type: int
|
|
||||||
default: 1
|
|
||||||
scale-divisor:
|
|
||||||
type: int
|
|
||||||
default: 1
|
|
21
app/dts/bindings/zmk,input-listener.yaml
Normal file
21
app/dts/bindings/zmk,input-listener.yaml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
description: |
|
||||||
|
Listener to subscribe to input events and send HID updates after processing
|
||||||
|
|
||||||
|
compatible: "zmk,input-listener"
|
||||||
|
|
||||||
|
properties:
|
||||||
|
device:
|
||||||
|
type: phandle
|
||||||
|
required: true
|
||||||
|
xy-swap:
|
||||||
|
type: boolean
|
||||||
|
x-invert:
|
||||||
|
type: boolean
|
||||||
|
y-invert:
|
||||||
|
type: boolean
|
||||||
|
scale-multiplier:
|
||||||
|
type: int
|
||||||
|
default: 1
|
||||||
|
scale-divisor:
|
||||||
|
type: int
|
||||||
|
default: 1
|
|
@ -1,21 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2023 The ZMK Contributors
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <zephyr/kernel.h>
|
|
||||||
#include <zephyr/device.h>
|
|
||||||
|
|
||||||
struct zmk_input_config {
|
|
||||||
const struct device *dev;
|
|
||||||
bool xy_swap;
|
|
||||||
bool x_invert;
|
|
||||||
bool y_invert;
|
|
||||||
uint16_t scale_multiplier;
|
|
||||||
uint16_t scale_divisor;
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct zmk_input_config *zmk_input_config_get_for_device(const struct device *dev);
|
|
|
@ -1,110 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 The ZMK Contributors
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <zephyr/kernel.h>
|
|
||||||
#include <zephyr/input/input.h>
|
|
||||||
#include <zephyr/dt-bindings/input/input-event-codes.h>
|
|
||||||
|
|
||||||
#include <zmk/mouse.h>
|
|
||||||
#include <zmk/mouse/input_config.h>
|
|
||||||
#include <zmk/endpoints.h>
|
|
||||||
#include <zmk/hid.h>
|
|
||||||
|
|
||||||
void handle_rel_code(struct input_event *evt) {
|
|
||||||
switch (evt->code) {
|
|
||||||
case INPUT_REL_X:
|
|
||||||
zmk_hid_mouse_movement_update(evt->value, 0);
|
|
||||||
break;
|
|
||||||
case INPUT_REL_Y:
|
|
||||||
zmk_hid_mouse_movement_update(0, evt->value);
|
|
||||||
break;
|
|
||||||
case INPUT_REL_WHEEL:
|
|
||||||
zmk_hid_mouse_scroll_update(0, evt->value);
|
|
||||||
break;
|
|
||||||
case INPUT_REL_HWHEEL:
|
|
||||||
zmk_hid_mouse_scroll_update(evt->value, 0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_key_code(struct input_event *evt) {
|
|
||||||
int8_t btn;
|
|
||||||
|
|
||||||
switch (evt->code) {
|
|
||||||
case INPUT_BTN_0:
|
|
||||||
case INPUT_BTN_1:
|
|
||||||
case INPUT_BTN_2:
|
|
||||||
case INPUT_BTN_3:
|
|
||||||
case INPUT_BTN_4:
|
|
||||||
btn = evt->code - INPUT_BTN_0;
|
|
||||||
if (evt->value > 0) {
|
|
||||||
zmk_hid_mouse_button_press(btn);
|
|
||||||
} else {
|
|
||||||
zmk_hid_mouse_button_release(btn);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void swap_xy(struct input_event *evt) {
|
|
||||||
switch (evt->code) {
|
|
||||||
case INPUT_REL_X:
|
|
||||||
evt->code = INPUT_REL_Y;
|
|
||||||
break;
|
|
||||||
case INPUT_REL_Y:
|
|
||||||
evt->code = INPUT_REL_X;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void filter_with_input_config(struct input_event *evt) {
|
|
||||||
if (!evt->dev) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct zmk_input_config *cfg = zmk_input_config_get_for_device(evt->dev);
|
|
||||||
|
|
||||||
if (!cfg) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cfg->xy_swap) {
|
|
||||||
swap_xy(evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((cfg->x_invert && evt->code == INPUT_REL_X) ||
|
|
||||||
(cfg->y_invert && evt->code == INPUT_REL_Y)) {
|
|
||||||
evt->value = -(evt->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
evt->value = (int16_t)((evt->value * cfg->scale_multiplier) / cfg->scale_divisor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void input_handler(struct input_event *evt) {
|
|
||||||
// First, filter to update the event data as needed.
|
|
||||||
filter_with_input_config(evt);
|
|
||||||
|
|
||||||
switch (evt->type) {
|
|
||||||
case INPUT_EV_REL:
|
|
||||||
handle_rel_code(evt);
|
|
||||||
break;
|
|
||||||
case INPUT_EV_KEY:
|
|
||||||
handle_key_code(evt);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (evt->sync) {
|
|
||||||
zmk_endpoints_send_mouse_report();
|
|
||||||
zmk_hid_mouse_scroll_set(0, 0);
|
|
||||||
zmk_hid_mouse_movement_set(0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
INPUT_CALLBACK_DEFINE(NULL, input_handler);
|
|
|
@ -1,42 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2023 The ZMK Contributors
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <zmk/mouse/input_config.h>
|
|
||||||
#include <zephyr/device.h>
|
|
||||||
|
|
||||||
#define DT_DRV_COMPAT zmk_input_configs
|
|
||||||
|
|
||||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
|
||||||
|
|
||||||
#define CHILD_CONFIG(inst) \
|
|
||||||
{ \
|
|
||||||
.dev = DEVICE_DT_GET(DT_PHANDLE(inst, device)), \
|
|
||||||
.xy_swap = DT_PROP(inst, xy_swap), \
|
|
||||||
.x_invert = DT_PROP(inst, x_invert), \
|
|
||||||
.y_invert = DT_PROP(inst, y_invert), \
|
|
||||||
.scale_multiplier = DT_PROP(inst, scale_multiplier), \
|
|
||||||
.scale_divisor = DT_PROP(inst, scale_divisor), \
|
|
||||||
},
|
|
||||||
|
|
||||||
const struct zmk_input_config configs[] = {DT_INST_FOREACH_CHILD(0, CHILD_CONFIG)};
|
|
||||||
|
|
||||||
const struct zmk_input_config *zmk_input_config_get_for_device(const struct device *dev) {
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(configs); i++) {
|
|
||||||
if (configs[i].dev == dev) {
|
|
||||||
return &configs[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
const struct zmk_input_config *zmk_input_config_get_for_device(const struct device *dev) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
188
app/src/mouse/input_listener.c
Normal file
188
app/src/mouse/input_listener.c
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT zmk_input_listener
|
||||||
|
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/input/input.h>
|
||||||
|
#include <zephyr/dt-bindings/input/input-event-codes.h>
|
||||||
|
|
||||||
|
#include <zmk/mouse.h>
|
||||||
|
#include <zmk/endpoints.h>
|
||||||
|
#include <zmk/hid.h>
|
||||||
|
|
||||||
|
enum input_listener_xy_data_mode {
|
||||||
|
INPUT_LISTENER_XY_DATA_MODE_NONE,
|
||||||
|
INPUT_LISTENER_XY_DATA_MODE_REL,
|
||||||
|
INPUT_LISTENER_XY_DATA_MODE_ABS,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct input_listener_xy_data {
|
||||||
|
enum input_listener_xy_data_mode mode;
|
||||||
|
int16_t x;
|
||||||
|
int16_t y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct input_listener_data {
|
||||||
|
struct input_listener_xy_data data;
|
||||||
|
struct input_listener_xy_data wheel_data;
|
||||||
|
|
||||||
|
uint8_t button_set;
|
||||||
|
uint8_t button_clear;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct input_listener_config {
|
||||||
|
bool xy_swap;
|
||||||
|
bool x_invert;
|
||||||
|
bool y_invert;
|
||||||
|
uint16_t scale_multiplier;
|
||||||
|
uint16_t scale_divisor;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void handle_rel_code(struct input_listener_data *data, struct input_event *evt) {
|
||||||
|
switch (evt->code) {
|
||||||
|
case INPUT_REL_X:
|
||||||
|
data->data.mode = INPUT_LISTENER_XY_DATA_MODE_REL;
|
||||||
|
data->data.x += evt->value;
|
||||||
|
break;
|
||||||
|
case INPUT_REL_Y:
|
||||||
|
data->data.mode = INPUT_LISTENER_XY_DATA_MODE_REL;
|
||||||
|
data->data.y += evt->value;
|
||||||
|
break;
|
||||||
|
case INPUT_REL_WHEEL:
|
||||||
|
data->wheel_data.mode = INPUT_LISTENER_XY_DATA_MODE_REL;
|
||||||
|
data->wheel_data.y += evt->value;
|
||||||
|
break;
|
||||||
|
case INPUT_REL_HWHEEL:
|
||||||
|
data->wheel_data.mode = INPUT_LISTENER_XY_DATA_MODE_REL;
|
||||||
|
data->wheel_data.x += evt->value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_key_code(struct input_listener_data *data, struct input_event *evt) {
|
||||||
|
int8_t btn;
|
||||||
|
|
||||||
|
switch (evt->code) {
|
||||||
|
case INPUT_BTN_0:
|
||||||
|
case INPUT_BTN_1:
|
||||||
|
case INPUT_BTN_2:
|
||||||
|
case INPUT_BTN_3:
|
||||||
|
case INPUT_BTN_4:
|
||||||
|
btn = evt->code - INPUT_BTN_0;
|
||||||
|
if (evt->value > 0) {
|
||||||
|
WRITE_BIT(data->button_set, btn, 1);
|
||||||
|
} else {
|
||||||
|
WRITE_BIT(data->button_clear, btn, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void swap_xy(struct input_event *evt) {
|
||||||
|
switch (evt->code) {
|
||||||
|
case INPUT_REL_X:
|
||||||
|
evt->code = INPUT_REL_Y;
|
||||||
|
break;
|
||||||
|
case INPUT_REL_Y:
|
||||||
|
evt->code = INPUT_REL_X;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void filter_with_input_config(const struct input_listener_config *cfg,
|
||||||
|
struct input_event *evt) {
|
||||||
|
if (!evt->dev) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfg->xy_swap) {
|
||||||
|
swap_xy(evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cfg->x_invert && evt->code == INPUT_REL_X) ||
|
||||||
|
(cfg->y_invert && evt->code == INPUT_REL_Y)) {
|
||||||
|
evt->value = -(evt->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
evt->value = (int16_t)((evt->value * cfg->scale_multiplier) / cfg->scale_divisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clear_xy_data(struct input_listener_xy_data *data) {
|
||||||
|
data->x = data->y = 0;
|
||||||
|
data->mode = INPUT_LISTENER_XY_DATA_MODE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void input_handler(const struct input_listener_config *config,
|
||||||
|
struct input_listener_data *data, struct input_event *evt) {
|
||||||
|
// First, filter to update the event data as needed.
|
||||||
|
filter_with_input_config(config, evt);
|
||||||
|
|
||||||
|
switch (evt->type) {
|
||||||
|
case INPUT_EV_REL:
|
||||||
|
handle_rel_code(data, evt);
|
||||||
|
break;
|
||||||
|
case INPUT_EV_KEY:
|
||||||
|
handle_key_code(data, evt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evt->sync) {
|
||||||
|
if (data->wheel_data.mode == INPUT_LISTENER_XY_DATA_MODE_REL) {
|
||||||
|
zmk_hid_mouse_scroll_set(data->wheel_data.x, data->wheel_data.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->data.mode == INPUT_LISTENER_XY_DATA_MODE_REL) {
|
||||||
|
zmk_hid_mouse_movement_set(data->data.x, data->data.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->button_set != 0) {
|
||||||
|
for (int i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) {
|
||||||
|
if ((data->button_set & BIT(i)) != 0) {
|
||||||
|
zmk_hid_mouse_button_press(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->button_clear != 0) {
|
||||||
|
for (int i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) {
|
||||||
|
if ((data->button_set & BIT(i)) != 0) {
|
||||||
|
zmk_hid_mouse_button_release(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_endpoints_send_mouse_report();
|
||||||
|
zmk_hid_mouse_scroll_set(0, 0);
|
||||||
|
zmk_hid_mouse_movement_set(0, 0);
|
||||||
|
|
||||||
|
clear_xy_data(&data->data);
|
||||||
|
clear_xy_data(&data->wheel_data);
|
||||||
|
|
||||||
|
data->button_set = data->button_clear = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IL_INST(n) \
|
||||||
|
static const struct input_listener_config config_##n = { \
|
||||||
|
.xy_swap = DT_INST_PROP(n, xy_swap), \
|
||||||
|
.x_invert = DT_INST_PROP(n, x_invert), \
|
||||||
|
.y_invert = DT_INST_PROP(n, y_invert), \
|
||||||
|
.scale_multiplier = DT_INST_PROP(n, scale_multiplier), \
|
||||||
|
.scale_divisor = DT_INST_PROP(n, scale_divisor), \
|
||||||
|
}; \
|
||||||
|
static struct input_listener_data data_##n = {}; \
|
||||||
|
void input_handler_##n(struct input_event *evt) { \
|
||||||
|
input_handler(&config_##n, &data_##n, evt); \
|
||||||
|
} \
|
||||||
|
INPUT_CALLBACK_DEFINE(DEVICE_DT_GET(DT_INST_PHANDLE(n, device)), input_handler_##n);
|
||||||
|
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(IL_INST)
|
Loading…
Add table
Reference in a new issue