diff --git a/app/dts/bindings/input_processors/zmk,input-processor-out-of-band-behaviors.yaml b/app/dts/bindings/input_processors/zmk,input-processor-out-of-band-behaviors.yaml new file mode 100644 index 00000000000..d3c0b3ce538 --- /dev/null +++ b/app/dts/bindings/input_processors/zmk,input-processor-out-of-band-behaviors.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2024, The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Input Processor for invoking out of band behaviors on certain events + +compatible: "zmk,input-processor-out-of-band-behaviors" + +include: ip_zero_param.yaml + +properties: + type: + type: int + codes: + type: array + required: true + bindings: + type: phandle-array + required: true diff --git a/app/dts/input/processors.dtsi b/app/dts/input/processors.dtsi index d072c0fcfcf..4b517c032c0 100644 --- a/app/dts/input/processors.dtsi +++ b/app/dts/input/processors.dtsi @@ -7,4 +7,5 @@ #include #include #include -#include \ No newline at end of file +#include +#include \ No newline at end of file diff --git a/app/dts/input/processors/oobb.dtsi b/app/dts/input/processors/oobb.dtsi new file mode 100644 index 00000000000..3047e7a0294 --- /dev/null +++ b/app/dts/input/processors/oobb.dtsi @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + zip_out_of_band_button_behaviors: zip_out_of_band_button_behaviors { + compatible = "zmk,input-processor-out-of-band-behaviors"; + #input-processor-cells = <0>; + codes = ; + bindings = <&none &none &none>; + }; +}; \ No newline at end of file diff --git a/app/src/pointing/CMakeLists.txt b/app/src/pointing/CMakeLists.txt index ad74c1ea786..8db1bf509d4 100644 --- a/app/src/pointing/CMakeLists.txt +++ b/app/src/pointing/CMakeLists.txt @@ -6,5 +6,6 @@ target_sources_ifdef(CONFIG_ZMK_INPUT_PROCESSOR_TRANSFORM app PRIVATE input_proc target_sources_ifdef(CONFIG_ZMK_INPUT_PROCESSOR_SCALER app PRIVATE input_processor_scaler.c) target_sources_ifdef(CONFIG_ZMK_INPUT_PROCESSOR_TEMP_LAYER app PRIVATE input_processor_temp_layer.c) target_sources_ifdef(CONFIG_ZMK_INPUT_PROCESSOR_CODE_MAPPER app PRIVATE input_processor_code_mapper.c) +target_sources_ifdef(CONFIG_ZMK_INPUT_PROCESSOR_OUT_OF_BAND_BEHAVIORS app PRIVATE input_processor_out_of_band_behaviors.c) target_sources_ifdef(CONFIG_ZMK_POINTING_SMOOTH_SCROLLING app PRIVATE resolution_multipliers.c) target_sources_ifdef(CONFIG_ZMK_INPUT_SPLIT app PRIVATE input_split.c) diff --git a/app/src/pointing/Kconfig b/app/src/pointing/Kconfig index 42cf8e8c072..a10168f8a62 100644 --- a/app/src/pointing/Kconfig +++ b/app/src/pointing/Kconfig @@ -57,6 +57,11 @@ config ZMK_INPUT_PROCESSOR_CODE_MAPPER default y depends on DT_HAS_ZMK_INPUT_PROCESSOR_CODE_MAPPER_ENABLED +config ZMK_INPUT_PROCESSOR_OUT_OF_BAND_BEHAVIORS + bool "Out-Of-Band Behaviors Input Processor" + default y + depends on DT_HAS_ZMK_INPUT_PROCESSOR_OUT_OF_BAND_BEHAVIORS_ENABLED + config ZMK_INPUT_SPLIT bool "Split input support" default y diff --git a/app/src/pointing/input_processor_out_of_band_behaviors.c b/app/src/pointing/input_processor_out_of_band_behaviors.c new file mode 100644 index 00000000000..8476b3a3cb1 --- /dev/null +++ b/app/src/pointing/input_processor_out_of_band_behaviors.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_input_processor_out_of_band_behaviors + +#include + +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include + +struct ip_oobb_config { + size_t size; + uint16_t type; + + const uint16_t *codes; + const struct zmk_behavior_binding *bindings; +}; + +static int ip_oobb_handle_event(const struct device *dev, struct input_event *event, + uint32_t param1, uint32_t param2, + struct zmk_input_processor_state *state) { + const struct ip_oobb_config *cfg = dev->config; + + LOG_DBG("OH"); + + if (event->type != cfg->type) { + return 0; + } + + for (size_t i = 0; i < cfg->size; i++) { + if (cfg->codes[i] == event->code) { + struct zmk_behavior_binding_event behavior_event = { + .position = INT32_MAX, + .timestamp = k_uptime_get(), +#if IS_ENABLED(CONFIG_ZMK_SPLIT) + .source = ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL, +#endif + }; + + LOG_DBG("FOUND A MATCHING CODE, invoke %s", cfg->bindings[i].behavior_dev); + int ret = zmk_behavior_invoke_binding(&cfg->bindings[i], behavior_event, event->value); + if (ret < 0) { + return ret; + } + + return ZMK_INPUT_PROC_STOP; + } + } + + return 0; +} + +static struct zmk_input_processor_driver_api ip_oobb_driver_api = { + .handle_event = ip_oobb_handle_event, +}; + +static int ip_oobb_init(const struct device *dev) { return 0; } + +#define ENTRY(i, node) ZMK_KEYMAP_EXTRACT_BINDING(i, node) + +#define IP_OOBB_INST(n) \ + static const uint16_t ip_oobb_codes_##n[] = DT_INST_PROP(n, codes); \ + static const struct zmk_behavior_binding ip_oobb_bindings_##n[] = { \ + LISTIFY(DT_INST_PROP_LEN(n, bindings), ZMK_KEYMAP_EXTRACT_BINDING, (, ), DT_DRV_INST(n))}; \ + BUILD_ASSERT(ARRAY_SIZE(ip_oobb_codes_##n) == ARRAY_SIZE(ip_oobb_bindings_##n), \ + "codes and bindings need to be the same length"); \ + static const struct ip_oobb_config ip_oobb_config_##n = { \ + .type = DT_INST_PROP_OR(n, type, INPUT_EV_KEY), \ + .size = DT_INST_PROP_LEN(n, codes), \ + .codes = ip_oobb_codes_##n, \ + .bindings = ip_oobb_bindings_##n, \ + }; \ + DEVICE_DT_INST_DEFINE(n, &ip_oobb_init, NULL, NULL, &ip_oobb_config_##n, POST_KERNEL, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &ip_oobb_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(IP_OOBB_INST) \ No newline at end of file diff --git a/app/tests/pointing/mouse-move/processors/out_of_bound_behaviors/events.patterns b/app/tests/pointing/mouse-move/processors/out_of_bound_behaviors/events.patterns new file mode 100644 index 00000000000..7374badf0f3 --- /dev/null +++ b/app/tests/pointing/mouse-move/processors/out_of_bound_behaviors/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_mouse_//p +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/pointing/mouse-move/processors/out_of_bound_behaviors/keycode_events.snapshot b/app/tests/pointing/mouse-move/processors/out_of_bound_behaviors/keycode_events.snapshot new file mode 100644 index 00000000000..7ad856db606 --- /dev/null +++ b/app/tests/pointing/mouse-move/processors/out_of_bound_behaviors/keycode_events.snapshot @@ -0,0 +1,6 @@ +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/pointing/mouse-move/processors/out_of_bound_behaviors/native_posix_64.conf b/app/tests/pointing/mouse-move/processors/out_of_bound_behaviors/native_posix_64.conf new file mode 100644 index 00000000000..fa514727ba5 --- /dev/null +++ b/app/tests/pointing/mouse-move/processors/out_of_bound_behaviors/native_posix_64.conf @@ -0,0 +1,6 @@ +CONFIG_GPIO=n +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_ZMK_POINTING=y diff --git a/app/tests/pointing/mouse-move/processors/out_of_bound_behaviors/native_posix_64.keymap b/app/tests/pointing/mouse-move/processors/out_of_bound_behaviors/native_posix_64.keymap new file mode 100644 index 00000000000..ed4f43817bb --- /dev/null +++ b/app/tests/pointing/mouse-move/processors/out_of_bound_behaviors/native_posix_64.keymap @@ -0,0 +1,44 @@ + +#include +#include + +#include +#include +#include +#include +#include + + +&zip_out_of_band_button_behaviors { + bindings = <&kp A &kp B &kp C>; +}; + +&mkp_input_listener { + input-processors = <&zip_out_of_band_button_behaviors>; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &mkp LCLK &mkp RCLK + &mkp MCLK &none + >; + }; + }; +}; + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/docs/docs/keymaps/input-processors/out-of-band-behaviors.md b/docs/docs/keymaps/input-processors/out-of-band-behaviors.md new file mode 100644 index 00000000000..71c6eb098cc --- /dev/null +++ b/docs/docs/keymaps/input-processors/out-of-band-behaviors.md @@ -0,0 +1,75 @@ +--- +title: Out-of-Band Behaviors Input Processor +sidebar_label: Out-of-Band Behaviors +--- + +## Overview + +The out-of-band behaviors input processor is used invoke standard behaviors when certain input events occur; most frequently this is used to trigger behaviors when certain mouse buttons are triggered by physical pointing devices. + +:::note + +Because the out-of-band behaviors input processor does not trigger behavior as part of a keymap, some complex behaviors like hold-taps will not work well with this input processor. + +::: + +## Usage + +When used, this input processor takes no parameters, as the event code to behavior mapping is specified in the definition of the specific processor instance, e.g.: + +```dts +&zip_out_of_band_button_behaviors +``` + +## Pre-Defined Instances + +One pre-defined instance of the out-of-band behaviors input processor is available: + +| Reference | Description | +| ----------------------------------- | -------------------------------------------------- | +| `&zip_out_of_band_button_behaviors` | Maps left/right/middle clicks to a given behavior. | + +Should you with to update the existing instance to trigger different behaviors for each mouse button, you can override the `bindings` property, e.g.: + +```dts +&zip_out_of_band_button_behaviors { + bindings = <&kp A &kp B &kp C>; +}; +``` + +## User-Defined Instances + +Users can define new instances of the out-of-band behaviors input processor if they want to target different codes or assign different behaviors. + +### Example + +Below example maps the left mouse button code to the middle mouse button. + +```dts +#include + +/ { + input_processors { + zip_right_click_trigger_paste: zip_right_click_trigger_paste { + compatible = "zmk,input-processor-out-of-band-behaviors"; + #input-processor-cells = <0>; + codes = ; + bindings = <&kp LC(V) >; + }; + }; +} +``` + +### Compatible + +The code mapper input processor uses a `compatible` property of `"zmk,input-processor-out-of-band-behaviors"`. + +### Standard Properties + +- `#input-processor-cells` - required to be constant value of `<0>`. + +### User Properties + +- `type` - The [type](https://github.com/zmkfirmware/zephyr/blob/v3.5.0%2Bzmk-fixes/include/zephyr/dt-bindings/input/input-event-codes.h#L25) of events to scale. Usually, this is `INPUT_EV_KEY` for key/button events. The default value if omitted is `INPUT_EV_KEY`. +- `codes` - The specific codes of the given type to capture, e.g. [button event codes](https://github.com/zmkfirmware/zephyr/blob/v3.5.0%2Bzmk-fixes/include/zephyr/dt-bindings/input/input-event-codes.h#L180). This list must be the same length as the `bindings` property. +- `bindings` - The bindings to trigger when an event with the corresponding code is processed.