Merge pull request #1 from petejohanson/stephen/split-encoder
split encoder (1841)
This commit is contained in:
commit
fd80f40609
13 changed files with 206 additions and 46 deletions
|
@ -8,6 +8,10 @@
|
|||
|
||||
#include <zmk/events/position_state_changed.h>
|
||||
|
||||
#define ZMK_LAYER_CHILD_LEN_PLUS_ONE(node) 1 +
|
||||
#define ZMK_KEYMAP_LAYERS_LEN \
|
||||
(DT_FOREACH_CHILD(DT_INST(0, zmk_keymap), ZMK_LAYER_CHILD_LEN_PLUS_ONE) 0)
|
||||
|
||||
typedef uint32_t zmk_keymap_layers_state_t;
|
||||
|
||||
uint8_t zmk_keymap_layer_default();
|
||||
|
|
|
@ -24,7 +24,9 @@ struct zmk_sensor_config {
|
|||
uint16_t triggers_per_rotation;
|
||||
};
|
||||
|
||||
// This struct is also used for data transfer for splits, so any changes to the size, layout, etc
|
||||
// is a breaking change for the split GATT service protocol.
|
||||
struct zmk_sensor_channel_data {
|
||||
enum sensor_channel channel;
|
||||
struct sensor_value value;
|
||||
};
|
||||
enum sensor_channel channel;
|
||||
} __packed;
|
||||
|
|
|
@ -6,8 +6,18 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <zmk/events/sensor_event.h>
|
||||
#include <zmk/sensors.h>
|
||||
|
||||
#define ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN 9
|
||||
|
||||
struct sensor_event {
|
||||
uint8_t sensor_index;
|
||||
|
||||
uint8_t channel_data_size;
|
||||
struct zmk_sensor_channel_data channel_data[ZMK_SENSOR_EVENT_MAX_CHANNELS];
|
||||
} __packed;
|
||||
|
||||
struct zmk_split_run_behavior_data {
|
||||
uint8_t position;
|
||||
uint8_t state;
|
||||
|
@ -21,4 +31,7 @@ struct zmk_split_run_behavior_payload {
|
|||
} __packed;
|
||||
|
||||
int zmk_split_bt_position_pressed(uint8_t position);
|
||||
int zmk_split_bt_position_released(uint8_t position);
|
||||
int zmk_split_bt_position_released(uint8_t position);
|
||||
int zmk_split_bt_sensor_triggered(uint8_t sensor_number,
|
||||
const struct zmk_sensor_channel_data channel_data[],
|
||||
size_t channel_data_size);
|
||||
|
|
|
@ -16,3 +16,4 @@
|
|||
#define ZMK_SPLIT_BT_SERVICE_UUID ZMK_BT_SPLIT_UUID(0x00000000)
|
||||
#define ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID ZMK_BT_SPLIT_UUID(0x00000001)
|
||||
#define ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID ZMK_BT_SPLIT_UUID(0x00000002)
|
||||
#define ZMK_SPLIT_BT_CHAR_SENSOR_STATE_UUID ZMK_BT_SPLIT_UUID(0x00000003)
|
||||
|
|
|
@ -28,7 +28,7 @@ int zmk_behavior_sensor_rotate_common_accept_data(
|
|||
if (value.val1 == 0) {
|
||||
triggers = value.val2;
|
||||
} else {
|
||||
struct sensor_value remainder = data->remainder[sensor_index];
|
||||
struct sensor_value remainder = data->remainder[sensor_index][event.layer];
|
||||
|
||||
remainder.val1 += value.val1;
|
||||
remainder.val2 += value.val2;
|
||||
|
@ -42,15 +42,16 @@ int zmk_behavior_sensor_rotate_common_accept_data(
|
|||
triggers = remainder.val1 / trigger_degrees;
|
||||
remainder.val1 %= trigger_degrees;
|
||||
|
||||
data->remainder[sensor_index] = remainder;
|
||||
data->remainder[sensor_index][event.layer] = remainder;
|
||||
}
|
||||
|
||||
LOG_DBG(
|
||||
"val1: %d, val2: %d, remainder: %d/%d triggers: %d inc keycode 0x%02X dec keycode 0x%02X",
|
||||
value.val1, value.val2, data->remainder[sensor_index].val1,
|
||||
data->remainder[sensor_index].val2, triggers, binding->param1, binding->param2);
|
||||
value.val1, value.val2, data->remainder[sensor_index][event.layer].val1,
|
||||
data->remainder[sensor_index][event.layer].val2, triggers, binding->param1,
|
||||
binding->param2);
|
||||
|
||||
data->triggers[sensor_index] = triggers;
|
||||
data->triggers[sensor_index][event.layer] = triggers;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -64,11 +65,11 @@ int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *bindi
|
|||
const int sensor_index = ZMK_SENSOR_POSITION_FROM_VIRTUAL_KEY_POSITION(event.position);
|
||||
|
||||
if (mode != BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER) {
|
||||
data->triggers[sensor_index] = 0;
|
||||
data->triggers[sensor_index][event.layer] = 0;
|
||||
return ZMK_BEHAVIOR_TRANSPARENT;
|
||||
}
|
||||
|
||||
int triggers = data->triggers[sensor_index];
|
||||
int triggers = data->triggers[sensor_index][event.layer];
|
||||
|
||||
struct zmk_behavior_binding triggered_binding;
|
||||
if (triggers > 0) {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <drivers/behavior.h>
|
||||
#include <zmk/behavior.h>
|
||||
#include <zmk/keymap.h>
|
||||
#include <zmk/sensors.h>
|
||||
|
||||
struct behavior_sensor_rotate_config {
|
||||
|
@ -16,8 +17,8 @@ struct behavior_sensor_rotate_config {
|
|||
};
|
||||
|
||||
struct behavior_sensor_rotate_data {
|
||||
struct sensor_value remainder[ZMK_KEYMAP_SENSORS_LEN];
|
||||
int triggers[ZMK_KEYMAP_SENSORS_LEN];
|
||||
struct sensor_value remainder[ZMK_KEYMAP_SENSORS_LEN][ZMK_KEYMAP_LAYERS_LEN];
|
||||
int triggers[ZMK_KEYMAP_SENSORS_LEN][ZMK_KEYMAP_LAYERS_LEN];
|
||||
};
|
||||
|
||||
int zmk_behavior_sensor_rotate_common_accept_data(
|
||||
|
|
|
@ -31,10 +31,6 @@ static uint8_t _zmk_keymap_layer_default = 0;
|
|||
|
||||
#define DT_DRV_COMPAT zmk_keymap
|
||||
|
||||
#define LAYER_CHILD_LEN(node) 1 +
|
||||
#define ZMK_KEYMAP_NODE DT_DRV_INST(0)
|
||||
#define ZMK_KEYMAP_LAYERS_LEN (DT_INST_FOREACH_CHILD(0, LAYER_CHILD_LEN) 0)
|
||||
|
||||
#define BINDING_WITH_COMMA(idx, drv_inst) ZMK_KEYMAP_EXTRACT_BINDING(idx, drv_inst)
|
||||
|
||||
#define TRANSFORMED_LAYER(node) \
|
||||
|
|
|
@ -29,7 +29,7 @@ struct sensors_item_cfg {
|
|||
{ \
|
||||
.dev = DEVICE_DT_GET_OR_NULL(node), \
|
||||
.trigger = {.type = SENSOR_TRIG_DATA_READY, .chan = SENSOR_CHAN_ROTATION}, \
|
||||
.config = &configs[idx] \
|
||||
.config = &configs[idx], .sensor_index = idx \
|
||||
}
|
||||
#define SENSOR_ITEM(idx, _i) _SENSOR_ITEM(idx, ZMK_KEYMAP_SENSORS_BY_IDX(idx))
|
||||
|
||||
|
@ -112,7 +112,7 @@ static void zmk_sensors_trigger_handler(const struct device *dev,
|
|||
int sensor_index = test_item - sensors;
|
||||
|
||||
if (sensor_index < 0 || sensor_index >= ARRAY_SIZE(sensors)) {
|
||||
LOG_ERR("Invalid sensor item triggered our callback");
|
||||
LOG_ERR("Invalid sensor item triggered our callback (%d)", sensor_index);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -127,8 +127,6 @@ static void zmk_sensors_trigger_handler(const struct device *dev,
|
|||
static void zmk_sensors_init_item(uint8_t i) {
|
||||
LOG_DBG("Init sensor at index %d", i);
|
||||
|
||||
sensors[i].sensor_index = i;
|
||||
|
||||
if (!sensors[i].dev) {
|
||||
LOG_DBG("No local device for %d", i);
|
||||
return;
|
||||
|
|
|
@ -21,10 +21,12 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
#include <zmk/stdlib.h>
|
||||
#include <zmk/ble.h>
|
||||
#include <zmk/behavior.h>
|
||||
#include <zmk/sensors.h>
|
||||
#include <zmk/split/bluetooth/uuid.h>
|
||||
#include <zmk/split/bluetooth/service.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/position_state_changed.h>
|
||||
#include <zmk/events/sensor_event.h>
|
||||
|
||||
static int start_scanning(void);
|
||||
|
||||
|
@ -41,6 +43,7 @@ struct peripheral_slot {
|
|||
struct bt_conn *conn;
|
||||
struct bt_gatt_discover_params discover_params;
|
||||
struct bt_gatt_subscribe_params subscribe_params;
|
||||
struct bt_gatt_subscribe_params sensor_subscribe_params;
|
||||
struct bt_gatt_discover_params sub_discover_params;
|
||||
uint16_t run_behavior_handle;
|
||||
uint8_t position_state[POSITION_STATE_DATA_LEN];
|
||||
|
@ -165,6 +168,46 @@ int confirm_peripheral_slot_conn(struct bt_conn *conn) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
K_MSGQ_DEFINE(peripheral_sensor_event_msgq, sizeof(struct zmk_sensor_event),
|
||||
CONFIG_ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE, 4);
|
||||
|
||||
void peripheral_sensor_event_work_callback(struct k_work *work) {
|
||||
struct zmk_sensor_event ev;
|
||||
while (k_msgq_get(&peripheral_sensor_event_msgq, &ev, K_NO_WAIT) == 0) {
|
||||
LOG_DBG("Trigger sensor change for %d", ev.sensor_index);
|
||||
ZMK_EVENT_RAISE(new_zmk_sensor_event(ev));
|
||||
}
|
||||
}
|
||||
|
||||
K_WORK_DEFINE(peripheral_sensor_event_work, peripheral_sensor_event_work_callback);
|
||||
|
||||
static uint8_t split_central_sensor_notify_func(struct bt_conn *conn,
|
||||
struct bt_gatt_subscribe_params *params,
|
||||
const void *data, uint16_t length) {
|
||||
if (!data) {
|
||||
LOG_DBG("[UNSUBSCRIBED]");
|
||||
params->value_handle = 0U;
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
||||
LOG_DBG("[SENSOR NOTIFICATION] data %p length %u", data, length);
|
||||
|
||||
struct sensor_event sensor_event;
|
||||
memcpy(&sensor_event, data, MIN(length, sizeof(sensor_event)));
|
||||
struct zmk_sensor_event ev = {.sensor_index = sensor_event.sensor_index,
|
||||
.channel_data_size = sensor_event.channel_data_size,
|
||||
.timestamp = k_uptime_get()};
|
||||
|
||||
memcpy(&ev.channel_data, sensor_event.channel_data,
|
||||
sizeof(struct zmk_sensor_channel_data) * sensor_event.channel_data_size);
|
||||
k_msgq_put(&peripheral_sensor_event_msgq, &ev, K_NO_WAIT);
|
||||
k_work_submit(&peripheral_sensor_event_work);
|
||||
|
||||
return BT_GATT_ITER_CONTINUE;
|
||||
}
|
||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||
|
||||
static uint8_t split_central_notify_func(struct bt_conn *conn,
|
||||
struct bt_gatt_subscribe_params *params, const void *data,
|
||||
uint16_t length) {
|
||||
|
@ -209,14 +252,8 @@ static uint8_t split_central_notify_func(struct bt_conn *conn,
|
|||
return BT_GATT_ITER_CONTINUE;
|
||||
}
|
||||
|
||||
static void split_central_subscribe(struct bt_conn *conn) {
|
||||
struct peripheral_slot *slot = peripheral_slot_for_conn(conn);
|
||||
if (slot == NULL) {
|
||||
LOG_ERR("No peripheral state found for connection");
|
||||
return;
|
||||
}
|
||||
|
||||
int err = bt_gatt_subscribe(conn, &slot->subscribe_params);
|
||||
static int split_central_subscribe(struct bt_conn *conn, struct bt_gatt_subscribe_params *params) {
|
||||
int err = bt_gatt_subscribe(conn, params);
|
||||
switch (err) {
|
||||
case -EALREADY:
|
||||
LOG_DBG("[ALREADY SUBSCRIBED]");
|
||||
|
@ -228,6 +265,8 @@ static void split_central_subscribe(struct bt_conn *conn) {
|
|||
LOG_ERR("Subscribe failed (err %d)", err);
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn,
|
||||
|
@ -263,14 +302,34 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn,
|
|||
slot->subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
|
||||
slot->subscribe_params.notify = split_central_notify_func;
|
||||
slot->subscribe_params.value = BT_GATT_CCC_NOTIFY;
|
||||
split_central_subscribe(conn);
|
||||
split_central_subscribe(conn, &slot->subscribe_params);
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
} else if (bt_uuid_cmp(((struct bt_gatt_chrc *)attr->user_data)->uuid,
|
||||
BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_SENSOR_STATE_UUID)) == 0) {
|
||||
slot->discover_params.uuid = NULL;
|
||||
slot->discover_params.start_handle = attr->handle + 2;
|
||||
slot->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
|
||||
|
||||
slot->sensor_subscribe_params.disc_params = &slot->sub_discover_params;
|
||||
slot->sensor_subscribe_params.end_handle = slot->discover_params.end_handle;
|
||||
slot->sensor_subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
|
||||
slot->sensor_subscribe_params.notify = split_central_sensor_notify_func;
|
||||
slot->sensor_subscribe_params.value = BT_GATT_CCC_NOTIFY;
|
||||
split_central_subscribe(conn, &slot->sensor_subscribe_params);
|
||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||
} else if (bt_uuid_cmp(((struct bt_gatt_chrc *)attr->user_data)->uuid,
|
||||
BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID)) == 0) {
|
||||
LOG_DBG("Found run behavior handle");
|
||||
slot->discover_params.uuid = NULL;
|
||||
slot->discover_params.start_handle = attr->handle + 2;
|
||||
slot->run_behavior_handle = bt_gatt_attr_value_handle(attr);
|
||||
}
|
||||
|
||||
bool subscribed = (slot->run_behavior_handle && slot->subscribe_params.value_handle);
|
||||
bool subscribed = (slot->run_behavior_handle && slot->subscribe_params.value_handle
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
&& slot->sensor_subscribe_params.value_handle
|
||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||
);
|
||||
|
||||
return subscribed ? BT_GATT_ITER_STOP : BT_GATT_ITER_CONTINUE;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
#include <zephyr/types.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/init.h>
|
||||
|
@ -20,6 +21,22 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
#include <zmk/matrix.h>
|
||||
#include <zmk/split/bluetooth/uuid.h>
|
||||
#include <zmk/split/bluetooth/service.h>
|
||||
#include <zmk/events/sensor_event.h>
|
||||
#include <zmk/sensors.h>
|
||||
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
static struct sensor_event last_sensor_event;
|
||||
|
||||
static ssize_t split_svc_sensor_state(struct bt_conn *conn, const struct bt_gatt_attr *attrs,
|
||||
void *buf, uint16_t len, uint16_t offset) {
|
||||
return bt_gatt_attr_read(conn, attrs, buf, len, offset, &last_sensor_event,
|
||||
sizeof(last_sensor_event));
|
||||
}
|
||||
|
||||
static void split_svc_sensor_state_ccc(const struct bt_gatt_attr *attr, uint16_t value) {
|
||||
LOG_DBG("value %d", value);
|
||||
}
|
||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||
|
||||
#define POS_STATE_LEN 16
|
||||
|
||||
|
@ -98,7 +115,14 @@ BT_GATT_SERVICE_DEFINE(
|
|||
BT_GATT_CHRC_WRITE_WITHOUT_RESP, BT_GATT_PERM_WRITE_ENCRYPT, NULL,
|
||||
split_svc_run_behavior, &behavior_run_payload),
|
||||
BT_GATT_DESCRIPTOR(BT_UUID_NUM_OF_DIGITALS, BT_GATT_PERM_READ, split_svc_num_of_positions, NULL,
|
||||
&num_of_positions), );
|
||||
&num_of_positions),
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_SENSOR_STATE_UUID),
|
||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT,
|
||||
split_svc_sensor_state, NULL, &last_sensor_event),
|
||||
BT_GATT_CCC(split_svc_sensor_state_ccc, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT),
|
||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||
);
|
||||
|
||||
K_THREAD_STACK_DEFINE(service_q_stack, CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE);
|
||||
|
||||
|
@ -151,6 +175,58 @@ int zmk_split_bt_position_released(uint8_t position) {
|
|||
return send_position_state();
|
||||
}
|
||||
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
K_MSGQ_DEFINE(sensor_state_msgq, sizeof(struct sensor_event),
|
||||
CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE, 4);
|
||||
|
||||
void send_sensor_state_callback(struct k_work *work) {
|
||||
while (k_msgq_get(&sensor_state_msgq, &last_sensor_event, K_NO_WAIT) == 0) {
|
||||
int err = bt_gatt_notify(NULL, &split_svc.attrs[8], &last_sensor_event,
|
||||
sizeof(last_sensor_event));
|
||||
if (err) {
|
||||
LOG_DBG("Error notifying %d", err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
K_WORK_DEFINE(service_sensor_notify_work, send_sensor_state_callback);
|
||||
|
||||
int send_sensor_state(struct sensor_event ev) {
|
||||
int err = k_msgq_put(&sensor_state_msgq, &ev, K_MSEC(100));
|
||||
if (err) {
|
||||
// retry...
|
||||
switch (err) {
|
||||
case -EAGAIN: {
|
||||
LOG_WRN("Sensor state message queue full, popping first message and queueing again");
|
||||
struct sensor_event discarded_state;
|
||||
k_msgq_get(&sensor_state_msgq, &discarded_state, K_NO_WAIT);
|
||||
return send_sensor_state(ev);
|
||||
}
|
||||
default:
|
||||
LOG_WRN("Failed to queue sensor state to send (%d)", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
k_work_submit_to_queue(&service_work_q, &service_sensor_notify_work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zmk_split_bt_sensor_triggered(uint8_t sensor_index,
|
||||
const struct zmk_sensor_channel_data channel_data[],
|
||||
size_t channel_data_size) {
|
||||
if (channel_data_size > ZMK_SENSOR_EVENT_MAX_CHANNELS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct sensor_event ev =
|
||||
(struct sensor_event){.sensor_index = sensor_index, .channel_data_size = channel_data_size};
|
||||
memcpy(ev.channel_data, channel_data,
|
||||
channel_data_size * sizeof(struct zmk_sensor_channel_data));
|
||||
return send_sensor_state(ev);
|
||||
}
|
||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||
|
||||
int service_init(const struct device *_arg) {
|
||||
static const struct k_work_queue_config queue_config = {
|
||||
.name = "Split Peripheral Notification Queue"};
|
||||
|
|
|
@ -13,21 +13,35 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/position_state_changed.h>
|
||||
#include <zmk/events/sensor_event.h>
|
||||
#include <zmk/hid.h>
|
||||
#include <zmk/sensors.h>
|
||||
#include <zmk/endpoints.h>
|
||||
|
||||
int split_listener(const zmk_event_t *eh) {
|
||||
LOG_DBG("");
|
||||
const struct zmk_position_state_changed *ev = as_zmk_position_state_changed(eh);
|
||||
if (ev != NULL) {
|
||||
if (ev->state) {
|
||||
return zmk_split_bt_position_pressed(ev->position);
|
||||
const struct zmk_position_state_changed *pos_ev;
|
||||
if ((pos_ev = as_zmk_position_state_changed(eh)) != NULL) {
|
||||
if (pos_ev->state) {
|
||||
return zmk_split_bt_position_pressed(pos_ev->position);
|
||||
} else {
|
||||
return zmk_split_bt_position_released(ev->position);
|
||||
return zmk_split_bt_position_released(pos_ev->position);
|
||||
}
|
||||
}
|
||||
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
const struct zmk_sensor_event *sensor_ev;
|
||||
if ((sensor_ev = as_zmk_sensor_event(eh)) != NULL) {
|
||||
return zmk_split_bt_sensor_triggered(sensor_ev->sensor_index, sensor_ev->channel_data,
|
||||
sensor_ev->channel_data_size);
|
||||
}
|
||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||
return ZMK_EV_EVENT_BUBBLE;
|
||||
}
|
||||
|
||||
ZMK_LISTENER(split_listener, split_listener);
|
||||
ZMK_SUBSCRIPTION(split_listener, zmk_position_state_changed);
|
||||
ZMK_SUBSCRIPTION(split_listener, zmk_position_state_changed);
|
||||
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
ZMK_SUBSCRIPTION(split_listener, zmk_sensor_event);
|
||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||
|
|
|
@ -5,10 +5,6 @@ sidebar_label: Encoders
|
|||
|
||||
Existing support for encoders in ZMK is focused around the five pin EC11 rotary encoder with push button design used in the majority of current keyboard and macropad designs.
|
||||
|
||||
:::note
|
||||
Encoders are currently only support on the left/central sides of splits. For progress on this, see [#728](https://github.com/zmkfirmware/zmk/pull/728).
|
||||
:::
|
||||
|
||||
## Enabling EC11 Encoders
|
||||
|
||||
To enable encoders for boards that have existing encoder support, uncomment the `CONFIG_EC11=y` and `CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y` lines in your board's .conf file in your `zmk-config/config` folder. Save and push your changes, then download and flash the new firmware.
|
||||
|
|
|
@ -23,11 +23,11 @@ ZMK is currently missing some features found in other popular firmware. This tab
|
|||
| Split Keyboard Support | ✅ | ✅ | ✅ |
|
||||
| [Keymaps and Layers](behaviors/layers.md) | ✅ | ✅ | ✅ |
|
||||
| [Hold-Tap](behaviors/hold-tap.md) (which includes [Mod-Tap](behaviors/mod-tap.md) and [Layer-Tap](behaviors/layers.md/#layer-tap)) | ✅ | ✅ | ✅ |
|
||||
| [Tap-Dance](behaviors/tap-dance.md) | ✅ | ✅[^3] | ✅ |
|
||||
| [Tap-Dance](behaviors/tap-dance.md) | ✅ | ✅[^2] | ✅ |
|
||||
| [Keyboard Codes](codes/index.mdx#keyboard) | ✅ | ✅ | ✅ |
|
||||
| [Media](codes/index.mdx#media-controls) & [Consumer](codes/index.mdx#consumer-controls) Codes | ✅ | ✅ | ✅ |
|
||||
| [Encoders](features/encoders.md)[^1] | ✅ | ✅ | ✅ |
|
||||
| [Display Support](features/displays.md)[^2] | 🚧 | 🚧 | ✅ |
|
||||
| [Encoders](features/encoders.md) | ✅ | ✅ | ✅ |
|
||||
| [Display Support](features/displays.md)[^1] | 🚧 | 🚧 | ✅ |
|
||||
| [RGB Underglow](features/underglow.md) | ✅ | ✅ | ✅ |
|
||||
| [Backlight](features/backlight.md) | ✅ | ✅ | ✅ |
|
||||
| One Shot Keys | ✅ | ✅ | ✅ |
|
||||
|
@ -43,8 +43,7 @@ ZMK is currently missing some features found in other popular firmware. This tab
|
|||
| AVR/8 Bit | | | ✅ |
|
||||
| [Wide Range of ARM Chips Supported](https://docs.zephyrproject.org/latest/boards/index.html) | ✅ | | |
|
||||
|
||||
[^3]: Tap-Dances are limited to single and double-tap on BlueMicro
|
||||
[^2]: Encoders are not currently supported on peripheral side splits.
|
||||
[^2]: Tap-Dances are limited to single and double-tap on BlueMicro
|
||||
[^1]: OLEDs are currently proof of concept in ZMK.
|
||||
|
||||
## Code Of Conduct
|
||||
|
|
Loading…
Add table
Reference in a new issue