Skip to content

Commit

Permalink
feat(pointing): Add out-of-band behavior input processors
Browse files Browse the repository at this point in the history
Add the ability to intercept certain input events and trigger behaviors
when they occur.
  • Loading branch information
petejohanson committed Dec 15, 2024
1 parent 4d7cad3 commit fcd6701
Show file tree
Hide file tree
Showing 11 changed files with 262 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -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
3 changes: 2 additions & 1 deletion app/dts/input/processors.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
#include <input/processors/scaler.dtsi>
#include <input/processors/code_mapper.dtsi>
#include <input/processors/transform.dtsi>
#include <input/processors/temp_layer.dtsi>
#include <input/processors/temp_layer.dtsi>
#include <input/processors/oobb.dtsi>
16 changes: 16 additions & 0 deletions app/dts/input/processors/oobb.dtsi
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright (c) 2024 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#include <zephyr/dt-bindings/input/input-event-codes.h>

/ {
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 = <INPUT_BTN_0 INPUT_BTN_1 INPUT_BTN_2>;
bindings = <&none &none &none>;
};
};
1 change: 1 addition & 0 deletions app/src/pointing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
5 changes: 5 additions & 0 deletions app/src/pointing/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
87 changes: 87 additions & 0 deletions app/src/pointing/input_processor_out_of_band_behaviors.c
Original file line number Diff line number Diff line change
@@ -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 <zephyr/dt-bindings/input/input-event-codes.h>

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <drivers/input_processor.h>

#include <zephyr/logging/log.h>

LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

#include <zmk/keymap.h>
#include <zmk/behavior.h>

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)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
s/.*hid_mouse_//p
s/.*hid_listener_keycode_//p
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@

#include <dt-bindings/zmk/input_transform.h>
#include <zephyr/dt-bindings/input/input-event-codes.h>

#include <behaviors.dtsi>
#include <input/processors.dtsi>
#include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/kscan_mock.h>
#include <dt-bindings/zmk/pointing.h>


&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)
>;
};
75 changes: 75 additions & 0 deletions docs/docs/keymaps/input-processors/out-of-band-behaviors.md
Original file line number Diff line number Diff line change
@@ -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 <zephyr/dt-bindings/input/input-event-codes.h>
/ {
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 = <INPUT_BTN_1>;
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.

0 comments on commit fcd6701

Please sign in to comment.