refactor: Use input system for pointer events.
This commit is contained in:
parent
79991d76f5
commit
2b6cdfa593
36 changed files with 556 additions and 655 deletions
|
@ -27,9 +27,7 @@ target_sources(app PRIVATE src/behavior.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/physical_layouts.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/key_listener.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/main.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/tick_listener.c)
|
||||
target_sources(app PRIVATE src/sensors.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/wpm.c)
|
||||
target_sources(app PRIVATE src/event_manager.c)
|
||||
|
@ -39,10 +37,6 @@ target_sources_ifdef(CONFIG_ZMK_GPIO_KEY_WAKEUP_TRIGGER app PRIVATE src/gpio_key
|
|||
target_sources(app PRIVATE src/events/activity_state_changed.c)
|
||||
target_sources(app PRIVATE src/events/position_state_changed.c)
|
||||
target_sources(app PRIVATE src/events/sensor_event.c)
|
||||
target_sources(app PRIVATE src/events/mouse_button_state_changed.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/events/mouse_move_state_changed.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/events/mouse_tick.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/events/mouse_scroll_state_changed.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/events/wpm_state_changed.c)
|
||||
target_sources_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/events/usb_conn_state_changed.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_reset.c)
|
||||
|
@ -51,6 +45,7 @@ target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SOFT_OFF app PRIVATE src/behaviors/beha
|
|||
if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
target_sources(app PRIVATE src/hid.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/main.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/hid_input_listener.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_HOLD_TAP app PRIVATE src/behaviors/behavior_hold_tap.c)
|
||||
|
@ -72,6 +67,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
|||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_STUDIO_UNLOCK app PRIVATE src/behaviors/behavior_studio_unlock.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/behaviors/behavior_mouse_move.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/behaviors/behavior_mouse_scroll.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_INPUT_TWO_AXIS app PRIVATE src/behaviors/behavior_input_two_axis.c)
|
||||
target_sources(app PRIVATE src/combo.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c)
|
||||
target_sources(app PRIVATE src/behavior_queue.c)
|
||||
|
|
|
@ -94,6 +94,12 @@ config ZMK_BEHAVIOR_SOFT_OFF
|
|||
default y
|
||||
depends on DT_HAS_ZMK_BEHAVIOR_SOFT_OFF_ENABLED && ZMK_PM_SOFT_OFF
|
||||
|
||||
config ZMK_BEHAVIOR_INPUT_TWO_AXIS
|
||||
bool
|
||||
default y
|
||||
depends on DT_HAS_ZMK_BEHAVIOR_INPUT_TWO_AXIS_ENABLED
|
||||
imply ZMK_MOUSE
|
||||
|
||||
config ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON
|
||||
bool
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#include <zephyr/dt-bindings/input/input-event-codes.h>
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
/omit-if-no-ref/ mmv: behavior_mouse_move {
|
||||
compatible = "zmk,behavior-mouse-move";
|
||||
label = "MOUSE_MOVE";
|
||||
/omit-if-no-ref/ mmv: mouse_move {
|
||||
compatible = "zmk,behavior-input-two-axis";
|
||||
#binding-cells = <1>;
|
||||
delay-ms = <0>;
|
||||
x-input-code = <INPUT_REL_X>;
|
||||
y-input-code = <INPUT_REL_Y>;
|
||||
time-to-max-speed-ms = <300>;
|
||||
acceleration-exponent = <1>;
|
||||
};
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#include <zephyr/dt-bindings/input/input-event-codes.h>
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
/omit-if-no-ref/ msc: behavior_mouse_scroll {
|
||||
compatible = "zmk,behavior-mouse-scroll";
|
||||
label = "MOUSE_SCROLL";
|
||||
/omit-if-no-ref/ msc: mouse_scroll {
|
||||
compatible = "zmk,behavior-input-two-axis";
|
||||
#binding-cells = <1>;
|
||||
delay-ms = <0>;
|
||||
x-input-code = <INPUT_REL_HWHEEL>;
|
||||
y-input-code = <INPUT_REL_WHEEL>;
|
||||
time-to-max-speed-ms = <300>;
|
||||
acceleration-exponent = <0>;
|
||||
};
|
||||
|
|
21
app/dts/bindings/behaviors/zmk,behavior-input-two-axis.yaml
Normal file
21
app/dts/bindings/behaviors/zmk,behavior-input-two-axis.yaml
Normal file
|
@ -0,0 +1,21 @@
|
|||
description: Two axis input behavior
|
||||
|
||||
compatible: "zmk,behavior-input-two-axis"
|
||||
|
||||
include: one_param.yaml
|
||||
|
||||
properties:
|
||||
x-input-code:
|
||||
type: int
|
||||
required: true
|
||||
y-input-code:
|
||||
type: int
|
||||
required: true
|
||||
delay-ms:
|
||||
type: int
|
||||
time-to-max-speed-ms:
|
||||
type: int
|
||||
required: true
|
||||
acceleration-exponent:
|
||||
type: int
|
||||
default: 1
|
|
@ -1,13 +0,0 @@
|
|||
description: Mouse move
|
||||
|
||||
compatible: "zmk,behavior-mouse-move"
|
||||
|
||||
include: one_param.yaml
|
||||
|
||||
properties:
|
||||
delay-ms:
|
||||
type: int
|
||||
time-to-max-speed-ms:
|
||||
type: int
|
||||
acceleration-exponent:
|
||||
type: int
|
|
@ -1,13 +0,0 @@
|
|||
description: Mouse scroll
|
||||
|
||||
compatible: "zmk,behavior-mouse-scroll"
|
||||
|
||||
include: one_param.yaml
|
||||
|
||||
properties:
|
||||
delay-ms:
|
||||
type: int
|
||||
time-to-max-speed-ms:
|
||||
type: int
|
||||
acceleration-exponent:
|
||||
type: int
|
|
@ -44,15 +44,7 @@
|
|||
#define MOVE_LEFT MOVE_X(-ZMK_MOUSE_DEFAULT_MOVE_VAL)
|
||||
#define MOVE_RIGHT MOVE_X(ZMK_MOUSE_DEFAULT_MOVE_VAL)
|
||||
|
||||
/* Mouse scroll behavior */
|
||||
#define SCRL_Y(vert) ((vert)&0xFFFF)
|
||||
#define SCRL_Y_DECODE(encoded) (int16_t)((encoded)&0x0000FFFF)
|
||||
#define SCRL_X(hor) (((hor)&0xFFFF) << 16)
|
||||
#define SCRL_X_DECODE(encoded) (int16_t)(((encoded)&0xFFFF0000) >> 16)
|
||||
|
||||
#define SCROLL(hor, vert) (SCRL_X(hor) + SCRL_Y(vert))
|
||||
|
||||
#define SCRL_UP SCRL_Y(ZMK_MOUSE_DEFAULT_SCRL_VAL)
|
||||
#define SCRL_DOWN SCRL_Y(-ZMK_MOUSE_DEFAULT_SCRL_VAL)
|
||||
#define SCRL_LEFT SCRL_X(-ZMK_MOUSE_DEFAULT_SCRL_VAL)
|
||||
#define SCRL_RIGHT SCRL_X(ZMK_MOUSE_DEFAULT_SCRL_VAL)
|
||||
#define SCRL_UP MOVE_Y(ZMK_MOUSE_DEFAULT_SCRL_VAL)
|
||||
#define SCRL_DOWN MOVE_Y(-ZMK_MOUSE_DEFAULT_SCRL_VAL)
|
||||
#define SCRL_LEFT MOVE_X(-ZMK_MOUSE_DEFAULT_SCRL_VAL)
|
||||
#define SCRL_RIGHT MOVE_X(ZMK_MOUSE_DEFAULT_SCRL_VAL)
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/mouse.h>
|
||||
|
||||
struct zmk_mouse_move_state_changed {
|
||||
struct vector2d max_speed;
|
||||
struct mouse_config config;
|
||||
bool state;
|
||||
int64_t timestamp;
|
||||
};
|
||||
|
||||
ZMK_EVENT_DECLARE(zmk_mouse_move_state_changed);
|
||||
|
||||
static inline struct zmk_mouse_move_state_changed_event *
|
||||
zmk_mouse_move_state_changed_from_encoded(uint32_t encoded, struct mouse_config config,
|
||||
bool pressed, int64_t timestamp) {
|
||||
struct vector2d max_speed = (struct vector2d){
|
||||
.x = MOVE_X_DECODE(encoded),
|
||||
.y = MOVE_Y_DECODE(encoded),
|
||||
};
|
||||
|
||||
return new_zmk_mouse_move_state_changed((struct zmk_mouse_move_state_changed){
|
||||
.max_speed = max_speed, .config = config, .state = pressed, .timestamp = timestamp});
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/mouse.h>
|
||||
#include <dt-bindings/zmk/mouse.h>
|
||||
|
||||
struct zmk_mouse_scroll_state_changed {
|
||||
struct vector2d max_speed;
|
||||
struct mouse_config config;
|
||||
bool state;
|
||||
int64_t timestamp;
|
||||
};
|
||||
|
||||
ZMK_EVENT_DECLARE(zmk_mouse_scroll_state_changed);
|
||||
|
||||
static inline struct zmk_mouse_scroll_state_changed_event *
|
||||
zmk_mouse_scroll_state_changed_from_encoded(uint32_t encoded, struct mouse_config config,
|
||||
bool pressed, int64_t timestamp) {
|
||||
struct vector2d max_speed = (struct vector2d){
|
||||
.x = SCRL_X_DECODE(encoded),
|
||||
.y = SCRL_Y_DECODE(encoded),
|
||||
};
|
||||
|
||||
return new_zmk_mouse_scroll_state_changed((struct zmk_mouse_scroll_state_changed){
|
||||
.max_speed = max_speed, .config = config, .state = pressed, .timestamp = timestamp});
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <dt-bindings/zmk/mouse.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/mouse.h>
|
||||
|
||||
struct zmk_mouse_tick {
|
||||
struct vector2d max_move;
|
||||
struct vector2d max_scroll;
|
||||
struct mouse_config move_config;
|
||||
struct mouse_config scroll_config;
|
||||
struct mouse_times start_times;
|
||||
int64_t timestamp;
|
||||
};
|
||||
|
||||
ZMK_EVENT_DECLARE(zmk_mouse_tick);
|
||||
|
||||
static inline struct zmk_mouse_tick_event *zmk_mouse_tick(struct vector2d max_move,
|
||||
struct vector2d max_scroll,
|
||||
struct mouse_config move_config,
|
||||
struct mouse_config scroll_config,
|
||||
struct mouse_times movement_start) {
|
||||
return new_zmk_mouse_tick((struct zmk_mouse_tick){
|
||||
.max_move = max_move,
|
||||
.max_scroll = max_scroll,
|
||||
.move_config = move_config,
|
||||
.scroll_config = scroll_config,
|
||||
.start_times = movement_start,
|
||||
.timestamp = k_uptime_get(),
|
||||
});
|
||||
}
|
|
@ -11,26 +11,4 @@
|
|||
typedef uint8_t zmk_mouse_button_flags_t;
|
||||
typedef uint16_t zmk_mouse_button_t;
|
||||
|
||||
struct mouse_config {
|
||||
int delay_ms;
|
||||
int time_to_max_speed_ms;
|
||||
// acceleration exponent 0: uniform speed
|
||||
// acceleration exponent 1: uniform acceleration
|
||||
// acceleration exponent 2: uniform jerk
|
||||
int acceleration_exponent;
|
||||
};
|
||||
|
||||
struct vector2d {
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
struct mouse_times {
|
||||
uint64_t m_x;
|
||||
uint64_t m_y;
|
||||
uint64_t s_x;
|
||||
uint64_t s_y;
|
||||
};
|
||||
|
||||
struct k_work_q *zmk_mouse_work_q();
|
||||
int zmk_mouse_init();
|
||||
int zmk_mouse_init(void);
|
||||
|
|
270
app/src/behaviors/behavior_input_two_axis.c
Normal file
270
app/src/behaviors/behavior_input_two_axis.c
Normal file
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
* Copyright (c) 2021 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_input_two_axis
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/input/input.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys/util.h> // CLAMP
|
||||
|
||||
#include <zmk/behavior.h>
|
||||
#include <dt-bindings/zmk/mouse.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
struct vector2d {
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
struct movement_state_1d {
|
||||
float remainder;
|
||||
int16_t speed;
|
||||
uint64_t start_time;
|
||||
};
|
||||
|
||||
struct movement_state_2d {
|
||||
struct movement_state_1d x;
|
||||
struct movement_state_1d y;
|
||||
};
|
||||
|
||||
struct behavior_input_two_axis_data {
|
||||
struct k_work_delayable tick_work;
|
||||
const struct device *dev;
|
||||
|
||||
struct movement_state_2d state;
|
||||
};
|
||||
|
||||
struct behavior_input_two_axis_config {
|
||||
int16_t x_code;
|
||||
int16_t y_code;
|
||||
int delay_ms;
|
||||
int time_to_max_speed_ms;
|
||||
// acceleration exponent 0: uniform speed
|
||||
// acceleration exponent 1: uniform acceleration
|
||||
// acceleration exponent 2: uniform jerk
|
||||
int acceleration_exponent;
|
||||
};
|
||||
|
||||
#if CONFIG_MINIMAL_LIBC
|
||||
static float powf(float base, float exponent) {
|
||||
// poor man's power implementation rounds the exponent down to the nearest integer.
|
||||
float power = 1.0f;
|
||||
for (; exponent >= 1.0f; exponent--) {
|
||||
power = power * base;
|
||||
}
|
||||
return power;
|
||||
}
|
||||
#else
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
static int64_t ms_since_start(int64_t start, int64_t now, int64_t delay) {
|
||||
if (start == 0) {
|
||||
return 0;
|
||||
}
|
||||
int64_t move_duration = now - (start + delay);
|
||||
// start can be in the future if there's a delay
|
||||
if (move_duration < 0) {
|
||||
move_duration = 0;
|
||||
}
|
||||
return move_duration;
|
||||
}
|
||||
|
||||
static float speed(const struct behavior_input_two_axis_config *config, float max_speed,
|
||||
int64_t duration_ms) {
|
||||
// Calculate the speed based on MouseKeysAccel
|
||||
// See https://en.wikipedia.org/wiki/Mouse_keys
|
||||
if (duration_ms == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (duration_ms > config->time_to_max_speed_ms || config->time_to_max_speed_ms == 0 ||
|
||||
config->acceleration_exponent == 0) {
|
||||
return max_speed;
|
||||
}
|
||||
float time_fraction = (float)duration_ms / config->time_to_max_speed_ms;
|
||||
return max_speed * powf(time_fraction, config->acceleration_exponent);
|
||||
}
|
||||
|
||||
static void track_remainder(float *move, float *remainder) {
|
||||
float new_move = *move + *remainder;
|
||||
*remainder = new_move - (int)new_move;
|
||||
*move = (int)new_move;
|
||||
}
|
||||
|
||||
static float update_movement_1d(const struct behavior_input_two_axis_config *config,
|
||||
struct movement_state_1d *state, int64_t now) {
|
||||
float move = 0;
|
||||
if (state->speed == 0) {
|
||||
state->remainder = 0;
|
||||
return move;
|
||||
}
|
||||
|
||||
int64_t move_duration = ms_since_start(state->start_time, now, config->delay_ms);
|
||||
move =
|
||||
(move_duration > 0)
|
||||
? (speed(config, state->speed, move_duration) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000)
|
||||
: 0;
|
||||
|
||||
track_remainder(&(move), &(state->remainder));
|
||||
|
||||
return move;
|
||||
}
|
||||
static struct vector2d update_movement_2d(const struct behavior_input_two_axis_config *config,
|
||||
struct movement_state_2d *state, int64_t now) {
|
||||
struct vector2d move = {0};
|
||||
|
||||
move = (struct vector2d){
|
||||
.x = update_movement_1d(config, &state->x, now),
|
||||
.y = update_movement_1d(config, &state->y, now),
|
||||
};
|
||||
|
||||
return move;
|
||||
}
|
||||
|
||||
static bool is_non_zero_1d_movement(int16_t speed) { return speed != 0; }
|
||||
|
||||
static bool is_non_zero_2d_movement(struct movement_state_2d *state) {
|
||||
return is_non_zero_1d_movement(state->x.speed) || is_non_zero_1d_movement(state->y.speed);
|
||||
}
|
||||
|
||||
static bool should_be_working(struct behavior_input_two_axis_data *data) {
|
||||
return is_non_zero_2d_movement(&data->state);
|
||||
}
|
||||
|
||||
static void tick_work_cb(struct k_work *work) {
|
||||
struct k_work_delayable *d_work = k_work_delayable_from_work(work);
|
||||
struct behavior_input_two_axis_data *data =
|
||||
CONTAINER_OF(d_work, struct behavior_input_two_axis_data, tick_work);
|
||||
const struct device *dev = data->dev;
|
||||
const struct behavior_input_two_axis_config *cfg = dev->config;
|
||||
|
||||
uint32_t timestamp = k_uptime_get();
|
||||
|
||||
LOG_INF("tick start times: %lld %lld %lld", data->state.x.start_time, data->state.y.start_time,
|
||||
timestamp);
|
||||
|
||||
struct vector2d move = update_movement_2d(cfg, &data->state, timestamp);
|
||||
|
||||
int ret = 0;
|
||||
bool have_x = is_non_zero_1d_movement(move.x);
|
||||
bool have_y = is_non_zero_1d_movement(move.y);
|
||||
if (have_x) {
|
||||
ret = input_report_rel(dev, cfg->x_code, (int16_t)CLAMP(move.x, INT16_MIN, INT16_MAX),
|
||||
!have_y, K_NO_WAIT);
|
||||
}
|
||||
if (have_y) {
|
||||
ret = input_report_rel(dev, cfg->y_code, (int16_t)CLAMP(move.y, INT16_MIN, INT16_MAX), true,
|
||||
K_NO_WAIT);
|
||||
}
|
||||
|
||||
if (should_be_working(data)) {
|
||||
k_work_schedule(&data->tick_work, K_MSEC(CONFIG_ZMK_MOUSE_TICK_DURATION));
|
||||
}
|
||||
}
|
||||
|
||||
static void set_start_times_for_activity(struct movement_state_2d *state) {
|
||||
if (state->x.speed != 0 && state->x.start_time == 0) {
|
||||
state->x.start_time = k_uptime_get();
|
||||
}
|
||||
|
||||
if (state->y.speed != 0 && state->y.start_time == 0) {
|
||||
state->y.start_time = k_uptime_get();
|
||||
}
|
||||
}
|
||||
|
||||
static void update_work_scheduling(const struct device *dev) {
|
||||
struct behavior_input_two_axis_data *data = dev->data;
|
||||
|
||||
set_start_times_for_activity(&data->state);
|
||||
|
||||
if (should_be_working(data)) {
|
||||
k_work_schedule(&data->tick_work, K_MSEC(CONFIG_ZMK_MOUSE_TICK_DURATION));
|
||||
} else {
|
||||
k_work_cancel_delayable(&data->tick_work);
|
||||
}
|
||||
}
|
||||
|
||||
int zmk_input_synth_pointer_adjust_speed(const struct device *dev, int16_t dx, int16_t dy) {
|
||||
struct behavior_input_two_axis_data *data = dev->data;
|
||||
|
||||
LOG_DBG("Adjusting: %d %d", dx, dy);
|
||||
data->state.x.speed += dx;
|
||||
data->state.y.speed += dy;
|
||||
|
||||
LOG_DBG("After: %d %d", data->state.x.speed, data->state.y.speed);
|
||||
|
||||
update_work_scheduling(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// static void process_key_state(const struct device *dev, int32_t val, bool pressed) {
|
||||
// for (int i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) {
|
||||
// if (val & BIT(i)) {
|
||||
// WRITE_BIT(val, i, 0);
|
||||
// input_report_key(dev, INPUT_BTN_0 + i, pressed ? 1 : 0, val == 0, K_FOREVER);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
static int behavior_input_two_axis_init(const struct device *dev) {
|
||||
struct behavior_input_two_axis_data *data = dev->data;
|
||||
|
||||
data->dev = dev;
|
||||
k_work_init_delayable(&data->tick_work, tick_work_cb);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
|
||||
const struct device *behavior_dev = zmk_behavior_get_binding(binding->behavior_dev);
|
||||
|
||||
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);
|
||||
|
||||
int16_t x = MOVE_X_DECODE(binding->param1);
|
||||
int16_t y = MOVE_Y_DECODE(binding->param1);
|
||||
|
||||
zmk_input_synth_pointer_adjust_speed(behavior_dev, x, y);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
const struct device *behavior_dev = zmk_behavior_get_binding(binding->behavior_dev);
|
||||
|
||||
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);
|
||||
|
||||
int16_t x = MOVE_X_DECODE(binding->param1);
|
||||
int16_t y = MOVE_Y_DECODE(binding->param1);
|
||||
|
||||
zmk_input_synth_pointer_adjust_speed(behavior_dev, -x, -y);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api behavior_input_two_axis_driver_api = {
|
||||
.binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released};
|
||||
|
||||
#define ITA_INST(n) \
|
||||
static struct behavior_input_two_axis_data behavior_input_two_axis_data_##n = {}; \
|
||||
static struct behavior_input_two_axis_config behavior_input_two_axis_config_##n = { \
|
||||
.x_code = DT_INST_PROP(n, x_input_code), \
|
||||
.y_code = DT_INST_PROP(n, y_input_code), \
|
||||
.delay_ms = DT_INST_PROP_OR(n, delay_ms, 0), \
|
||||
.time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \
|
||||
.acceleration_exponent = DT_INST_PROP_OR(n, acceleration_exponent, 1), \
|
||||
}; \
|
||||
BEHAVIOR_DT_INST_DEFINE( \
|
||||
n, behavior_input_two_axis_init, NULL, &behavior_input_two_axis_data_##n, \
|
||||
&behavior_input_two_axis_config_##n, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
||||
&behavior_input_two_axis_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(ITA_INST)
|
|
@ -11,8 +11,9 @@
|
|||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include <zmk/behavior.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/mouse_button_state_changed.h>
|
||||
#include <zmk/hid.h>
|
||||
#include <zephyr/input/input.h>
|
||||
#include <zephyr/dt-bindings/input/input-event-codes.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
|
@ -20,19 +21,31 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
|
||||
static int behavior_mouse_key_press_init(const struct device *dev) { return 0; };
|
||||
|
||||
static void process_key_state(const struct device *dev, int32_t val, bool pressed) {
|
||||
for (int i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) {
|
||||
if (val & BIT(i)) {
|
||||
WRITE_BIT(val, i, 0);
|
||||
input_report_key(dev, INPUT_BTN_0 + i, pressed ? 1 : 0, val == 0, K_FOREVER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);
|
||||
|
||||
return raise_zmk_mouse_button_state_changed_from_encoded(binding->param1, true,
|
||||
event.timestamp);
|
||||
process_key_state(zmk_behavior_get_binding(binding->behavior_dev), binding->param1, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);
|
||||
return raise_zmk_mouse_button_state_changed_from_encoded(binding->param1, false,
|
||||
event.timestamp);
|
||||
|
||||
process_key_state(zmk_behavior_get_binding(binding->behavior_dev), binding->param1, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api behavior_mouse_key_press_driver_api = {
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_mouse_move
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include <zmk/behavior.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/mouse_move_state_changed.h>
|
||||
#include <zmk/mouse.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
static int behavior_mouse_move_init(const struct device *dev) { return 0; };
|
||||
|
||||
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);
|
||||
const struct device *dev = device_get_binding(binding->behavior_dev);
|
||||
const struct mouse_config *config = dev->config;
|
||||
return ZMK_EVENT_RAISE(
|
||||
zmk_mouse_move_state_changed_from_encoded(binding->param1, *config, true, event.timestamp));
|
||||
}
|
||||
|
||||
static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);
|
||||
const struct device *dev = device_get_binding(binding->behavior_dev);
|
||||
const struct mouse_config *config = dev->config;
|
||||
return ZMK_EVENT_RAISE(zmk_mouse_move_state_changed_from_encoded(binding->param1, *config,
|
||||
false, event.timestamp));
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api behavior_mouse_move_driver_api = {
|
||||
.binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released};
|
||||
|
||||
#define KP_INST(n) \
|
||||
static struct mouse_config behavior_mouse_move_config_##n = { \
|
||||
.delay_ms = DT_INST_PROP(n, delay_ms), \
|
||||
.time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \
|
||||
.acceleration_exponent = DT_INST_PROP(n, acceleration_exponent), \
|
||||
}; \
|
||||
DEVICE_DT_INST_DEFINE(n, behavior_mouse_move_init, NULL, NULL, \
|
||||
&behavior_mouse_move_config_##n, APPLICATION, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_move_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(KP_INST)
|
||||
|
||||
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_mouse_scroll
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/mouse_scroll_state_changed.h>
|
||||
#include <zmk/behavior.h>
|
||||
#include <zmk/hid.h>
|
||||
#include <zmk/endpoints.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
static int behavior_mouse_scroll_init(const struct device *dev) { return 0; };
|
||||
|
||||
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);
|
||||
const struct device *dev = device_get_binding(binding->behavior_dev);
|
||||
const struct mouse_config *config = dev->config;
|
||||
return ZMK_EVENT_RAISE(zmk_mouse_scroll_state_changed_from_encoded(binding->param1, *config,
|
||||
true, event.timestamp));
|
||||
}
|
||||
|
||||
static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);
|
||||
const struct device *dev = device_get_binding(binding->behavior_dev);
|
||||
const struct mouse_config *config = dev->config;
|
||||
return ZMK_EVENT_RAISE(zmk_mouse_scroll_state_changed_from_encoded(binding->param1, *config,
|
||||
false, event.timestamp));
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api behavior_mouse_scroll_driver_api = {
|
||||
.binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released};
|
||||
|
||||
#define KP_INST(n) \
|
||||
static struct mouse_config behavior_mouse_scroll_config_##n = { \
|
||||
.delay_ms = DT_INST_PROP(n, delay_ms), \
|
||||
.time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \
|
||||
.acceleration_exponent = DT_INST_PROP(n, acceleration_exponent), \
|
||||
}; \
|
||||
DEVICE_DT_INST_DEFINE(n, behavior_mouse_scroll_init, NULL, NULL, \
|
||||
&behavior_mouse_scroll_config_##n, APPLICATION, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_scroll_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(KP_INST)
|
||||
|
||||
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
|
@ -1,10 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zmk/events/mouse_move_state_changed.h>
|
||||
|
||||
ZMK_EVENT_IMPL(zmk_mouse_move_state_changed);
|
|
@ -1,10 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zmk/events/mouse_scroll_state_changed.h>
|
||||
|
||||
ZMK_EVENT_IMPL(zmk_mouse_scroll_state_changed);
|
|
@ -1,10 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zmk/events/mouse_tick.h>
|
||||
|
||||
ZMK_EVENT_IMPL(zmk_mouse_tick);
|
|
@ -436,31 +436,33 @@ int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons) {
|
|||
void zmk_hid_mouse_movement_set(int16_t x, int16_t y) {
|
||||
mouse_report.body.d_x = x;
|
||||
mouse_report.body.d_y = y;
|
||||
LOG_DBG("Mouse movement set to 0x%02X 0x%02X ", mouse_report.body.d_x, mouse_report.body.d_y);
|
||||
LOG_DBG("Mouse movement set to %d/%d", mouse_report.body.d_x, mouse_report.body.d_y);
|
||||
}
|
||||
|
||||
void zmk_hid_mouse_movement_update(int16_t x, int16_t y) {
|
||||
mouse_report.body.d_x += x;
|
||||
mouse_report.body.d_y += y;
|
||||
LOG_DBG("Mouse movement updated to 0x%02X 0x%02X ", mouse_report.body.d_x,
|
||||
mouse_report.body.d_y);
|
||||
LOG_DBG("Mouse movement updated to %d/%d", mouse_report.body.d_x, mouse_report.body.d_y);
|
||||
}
|
||||
|
||||
void zmk_hid_mouse_scroll_set(int8_t x, int8_t y) {
|
||||
mouse_report.body.d_scroll_x = x;
|
||||
mouse_report.body.d_scroll_y = y;
|
||||
LOG_DBG("Mouse scroll set to X: 0x%02X Y: 0x%02X", mouse_report.body.d_scroll_x,
|
||||
LOG_DBG("Mouse scroll set to %d/%d", mouse_report.body.d_scroll_x,
|
||||
mouse_report.body.d_scroll_y);
|
||||
}
|
||||
|
||||
void zmk_hid_mouse_scroll_update(int8_t x, int8_t y) {
|
||||
mouse_report.body.d_scroll_x += x;
|
||||
mouse_report.body.d_scroll_y += y;
|
||||
LOG_DBG("Mouse scroll updated to X: 0x%02X Y: 0x%02X", mouse_report.body.d_scroll_x,
|
||||
LOG_DBG("Mouse scroll updated to X: %d/%d", mouse_report.body.d_scroll_x,
|
||||
mouse_report.body.d_scroll_y);
|
||||
}
|
||||
|
||||
void zmk_hid_mouse_clear(void) { memset(&mouse_report.body, 0, sizeof(mouse_report.body)); }
|
||||
void zmk_hid_mouse_clear(void) {
|
||||
LOG_DBG("Mouse report cleared");
|
||||
memset(&mouse_report.body, 0, sizeof(mouse_report.body));
|
||||
}
|
||||
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
menuconfig ZMK_MOUSE
|
||||
bool "Mouse Emulation"
|
||||
select INPUT
|
||||
select INPUT_THREAD_PRIORITY_OVERRIDE
|
||||
|
||||
if ZMK_MOUSE
|
||||
|
||||
|
|
72
app/src/mouse/hid_input_listener.c
Normal file
72
app/src/mouse/hid_input_listener.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* 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/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;
|
||||
}
|
||||
}
|
||||
|
||||
void input_handler(struct input_event *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,201 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/mouse_button_state_changed.h>
|
||||
#include <zmk/events/mouse_move_state_changed.h>
|
||||
#include <zmk/events/mouse_scroll_state_changed.h>
|
||||
#include <zmk/events/mouse_tick.h>
|
||||
#include <zmk/hid.h>
|
||||
#include <zmk/endpoints.h>
|
||||
#include <zmk/mouse.h>
|
||||
|
||||
#if !defined(CONFIG_ZMK_SPLIT) || defined(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
static struct vector2d move_speed = {0};
|
||||
static struct vector2d scroll_speed = {0};
|
||||
static struct mouse_config move_config = (struct mouse_config){0};
|
||||
static struct mouse_config scroll_config = (struct mouse_config){0};
|
||||
static struct mouse_times start_times = (struct mouse_times){0};
|
||||
|
||||
bool equals(const struct mouse_config *one, const struct mouse_config *other) {
|
||||
return one->delay_ms == other->delay_ms &&
|
||||
one->time_to_max_speed_ms == other->time_to_max_speed_ms &&
|
||||
one->acceleration_exponent == other->acceleration_exponent;
|
||||
}
|
||||
|
||||
static void clear_mouse_state(struct k_work *work) {
|
||||
move_speed = (struct vector2d){0};
|
||||
scroll_speed = (struct vector2d){0};
|
||||
start_times = (struct mouse_times){0};
|
||||
zmk_hid_mouse_movement_set(0, 0);
|
||||
zmk_hid_mouse_scroll_set(0, 0);
|
||||
LOG_DBG("Clearing state");
|
||||
}
|
||||
|
||||
K_WORK_DEFINE(mouse_clear, &clear_mouse_state);
|
||||
|
||||
void mouse_clear_cb(struct k_timer *dummy) {
|
||||
k_work_submit_to_queue(zmk_mouse_work_q(), &mouse_clear);
|
||||
}
|
||||
|
||||
static void mouse_tick_timer_handler(struct k_work *work) {
|
||||
zmk_hid_mouse_movement_set(0, 0);
|
||||
zmk_hid_mouse_scroll_set(0, 0);
|
||||
LOG_DBG("Raising mouse tick event");
|
||||
ZMK_EVENT_RAISE(
|
||||
zmk_mouse_tick(move_speed, scroll_speed, move_config, scroll_config, start_times));
|
||||
zmk_endpoints_send_mouse_report();
|
||||
}
|
||||
|
||||
K_WORK_DEFINE(mouse_tick, &mouse_tick_timer_handler);
|
||||
|
||||
void mouse_timer_cb(struct k_timer *dummy) {
|
||||
LOG_DBG("Submitting mouse work to queue");
|
||||
k_work_submit_to_queue(zmk_mouse_work_q(), &mouse_tick);
|
||||
}
|
||||
|
||||
K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, mouse_clear_cb);
|
||||
|
||||
static struct {
|
||||
int m_x;
|
||||
int m_y;
|
||||
int s_x;
|
||||
int s_y;
|
||||
} mouse_timer_ref_counts = {0, 0, 0, 0};
|
||||
|
||||
void mouse_timer_ref(bool m_x, bool m_y, bool s_x, bool s_y) {
|
||||
if (m_x && mouse_timer_ref_counts.m_x == 0) {
|
||||
start_times.m_x = k_uptime_get();
|
||||
}
|
||||
if (m_y && mouse_timer_ref_counts.m_y == 0) {
|
||||
start_times.m_y = k_uptime_get();
|
||||
}
|
||||
if (s_x && mouse_timer_ref_counts.s_x == 0) {
|
||||
start_times.s_x = k_uptime_get();
|
||||
}
|
||||
if (s_y && mouse_timer_ref_counts.s_y == 0) {
|
||||
start_times.s_y = k_uptime_get();
|
||||
}
|
||||
if (mouse_timer_ref_counts.m_x == 0 && mouse_timer_ref_counts.m_y == 0 &&
|
||||
mouse_timer_ref_counts.s_x == 0 && mouse_timer_ref_counts.s_y == 0) {
|
||||
k_timer_start(&mouse_timer, K_NO_WAIT, K_MSEC(CONFIG_ZMK_MOUSE_TICK_DURATION));
|
||||
}
|
||||
if (m_x) {
|
||||
mouse_timer_ref_counts.m_x++;
|
||||
}
|
||||
if (m_y) {
|
||||
mouse_timer_ref_counts.m_y++;
|
||||
}
|
||||
if (s_x) {
|
||||
mouse_timer_ref_counts.s_x++;
|
||||
}
|
||||
if (s_y) {
|
||||
mouse_timer_ref_counts.s_y++;
|
||||
}
|
||||
}
|
||||
|
||||
void mouse_timer_unref(bool m_x, bool m_y, bool s_x, bool s_y) {
|
||||
if (m_x && mouse_timer_ref_counts.m_x > 0) {
|
||||
mouse_timer_ref_counts.m_x--;
|
||||
}
|
||||
if (m_y && mouse_timer_ref_counts.m_y > 0) {
|
||||
mouse_timer_ref_counts.m_y--;
|
||||
}
|
||||
if (s_x && mouse_timer_ref_counts.s_x > 0) {
|
||||
mouse_timer_ref_counts.s_x--;
|
||||
}
|
||||
if (s_y && mouse_timer_ref_counts.s_y > 0) {
|
||||
mouse_timer_ref_counts.s_y--;
|
||||
}
|
||||
if (mouse_timer_ref_counts.m_x == 0 && mouse_timer_ref_counts.m_y == 0 &&
|
||||
mouse_timer_ref_counts.s_x == 0 && mouse_timer_ref_counts.s_y == 0) {
|
||||
k_timer_stop(&mouse_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void listener_mouse_move_pressed(const struct zmk_mouse_move_state_changed *ev) {
|
||||
move_speed.x += ev->max_speed.x;
|
||||
move_speed.y += ev->max_speed.y;
|
||||
mouse_timer_ref(ev->max_speed.x != 0, ev->max_speed.y != 0, false, false);
|
||||
}
|
||||
|
||||
static void listener_mouse_move_released(const struct zmk_mouse_move_state_changed *ev) {
|
||||
move_speed.x -= ev->max_speed.x;
|
||||
move_speed.y -= ev->max_speed.y;
|
||||
mouse_timer_unref(ev->max_speed.x != 0, ev->max_speed.y != 0, false, false);
|
||||
}
|
||||
|
||||
static void listener_mouse_scroll_pressed(const struct zmk_mouse_scroll_state_changed *ev) {
|
||||
scroll_speed.x += ev->max_speed.x;
|
||||
scroll_speed.y += ev->max_speed.y;
|
||||
mouse_timer_ref(false, false, ev->max_speed.x != 0, ev->max_speed.y != 0);
|
||||
}
|
||||
|
||||
static void listener_mouse_scroll_released(const struct zmk_mouse_scroll_state_changed *ev) {
|
||||
scroll_speed.x -= ev->max_speed.x;
|
||||
scroll_speed.y -= ev->max_speed.y;
|
||||
mouse_timer_unref(false, false, ev->max_speed.x != 0, ev->max_speed.y != 0);
|
||||
}
|
||||
|
||||
static void listener_mouse_button_pressed(const struct zmk_mouse_button_state_changed *ev) {
|
||||
LOG_DBG("buttons: 0x%02X", ev->buttons);
|
||||
zmk_hid_mouse_buttons_press(ev->buttons);
|
||||
zmk_endpoints_send_mouse_report();
|
||||
}
|
||||
|
||||
static void listener_mouse_button_released(const struct zmk_mouse_button_state_changed *ev) {
|
||||
LOG_DBG("buttons: 0x%02X", ev->buttons);
|
||||
zmk_hid_mouse_buttons_release(ev->buttons);
|
||||
zmk_endpoints_send_mouse_report();
|
||||
}
|
||||
|
||||
int mouse_listener(const zmk_event_t *eh) {
|
||||
const struct zmk_mouse_move_state_changed *mmv_ev = as_zmk_mouse_move_state_changed(eh);
|
||||
if (mmv_ev) {
|
||||
if (!equals(&move_config, &(mmv_ev->config)))
|
||||
move_config = mmv_ev->config;
|
||||
|
||||
if (mmv_ev->state) {
|
||||
listener_mouse_move_pressed(mmv_ev);
|
||||
} else {
|
||||
listener_mouse_move_released(mmv_ev);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
const struct zmk_mouse_scroll_state_changed *msc_ev = as_zmk_mouse_scroll_state_changed(eh);
|
||||
if (msc_ev) {
|
||||
if (!equals(&scroll_config, &(msc_ev->config)))
|
||||
scroll_config = msc_ev->config;
|
||||
if (msc_ev->state) {
|
||||
listener_mouse_scroll_pressed(msc_ev);
|
||||
} else {
|
||||
listener_mouse_scroll_released(msc_ev);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
const struct zmk_mouse_button_state_changed *mbt_ev = as_zmk_mouse_button_state_changed(eh);
|
||||
if (mbt_ev) {
|
||||
if (mbt_ev->state) {
|
||||
listener_mouse_button_pressed(mbt_ev);
|
||||
} else {
|
||||
listener_mouse_button_released(mbt_ev);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZMK_LISTENER(mouse_listener, mouse_listener);
|
||||
ZMK_SUBSCRIPTION(mouse_listener, zmk_mouse_button_state_changed);
|
||||
ZMK_SUBSCRIPTION(mouse_listener, zmk_mouse_move_state_changed);
|
||||
ZMK_SUBSCRIPTION(mouse_listener, zmk_mouse_scroll_state_changed);
|
||||
|
||||
#endif /*!defined(CONFIG_ZMK_SPLIT) || defined(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */
|
|
@ -20,7 +20,7 @@ struct k_work_q *zmk_mouse_work_q() {
|
|||
#endif
|
||||
}
|
||||
|
||||
int zmk_mouse_init() {
|
||||
int zmk_mouse_init(void) {
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED)
|
||||
k_work_queue_start(&mouse_work_q, mouse_work_stack_area,
|
||||
K_THREAD_STACK_SIZEOF(mouse_work_stack_area),
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/mouse_tick.h>
|
||||
#include <zmk/endpoints.h>
|
||||
#include <zmk/hid.h>
|
||||
#include <zmk/mouse.h>
|
||||
|
||||
#include <zephyr/sys/util.h> // CLAMP
|
||||
|
||||
#if !defined(CONFIG_ZMK_SPLIT) || defined(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
#if CONFIG_MINIMAL_LIBC
|
||||
static float powf(float base, float exponent) {
|
||||
// poor man's power implementation rounds the exponent down to the nearest integer.
|
||||
float power = 1.0f;
|
||||
for (; exponent >= 1.0f; exponent--) {
|
||||
power = power * base;
|
||||
}
|
||||
return power;
|
||||
}
|
||||
#else
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
struct vector2d move_remainder = {0};
|
||||
struct vector2d scroll_remainder = {0};
|
||||
|
||||
static int64_t ms_since_start(int64_t start, int64_t now, int64_t delay) {
|
||||
int64_t move_duration = now - (start + delay);
|
||||
// start can be in the future if there's a delay
|
||||
if (move_duration < 0) {
|
||||
move_duration = 0;
|
||||
}
|
||||
return move_duration;
|
||||
}
|
||||
|
||||
static float speed(const struct mouse_config *config, float max_speed, int64_t duration_ms) {
|
||||
// Calculate the speed based on MouseKeysAccel
|
||||
// See https://en.wikipedia.org/wiki/Mouse_keys
|
||||
if (duration_ms > config->time_to_max_speed_ms || config->time_to_max_speed_ms == 0 ||
|
||||
config->acceleration_exponent == 0) {
|
||||
return max_speed;
|
||||
}
|
||||
float time_fraction = (float)duration_ms / config->time_to_max_speed_ms;
|
||||
return max_speed * powf(time_fraction, config->acceleration_exponent);
|
||||
}
|
||||
|
||||
static void track_remainder(float *move, float *remainder) {
|
||||
float new_move = *move + *remainder;
|
||||
*remainder = new_move - (int)new_move;
|
||||
*move = (int)new_move;
|
||||
}
|
||||
|
||||
static struct vector2d update_movement(struct vector2d *remainder,
|
||||
const struct mouse_config *config, struct vector2d max_speed,
|
||||
int64_t now, int64_t start_time_x, int64_t start_time_y) {
|
||||
struct vector2d move = {0};
|
||||
if (max_speed.x == 0 && max_speed.y == 0) {
|
||||
*remainder = (struct vector2d){0};
|
||||
return move;
|
||||
}
|
||||
|
||||
int64_t move_duration_x = ms_since_start(start_time_x, now, config->delay_ms);
|
||||
int64_t move_duration_y = ms_since_start(start_time_y, now, config->delay_ms);
|
||||
move = (struct vector2d){
|
||||
.x = speed(config, max_speed.x, move_duration_x) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000,
|
||||
.y = speed(config, max_speed.y, move_duration_y) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000,
|
||||
};
|
||||
|
||||
track_remainder(&(move.x), &(remainder->x));
|
||||
track_remainder(&(move.y), &(remainder->y));
|
||||
|
||||
return move;
|
||||
}
|
||||
|
||||
static void mouse_tick_handler(const struct zmk_mouse_tick *tick) {
|
||||
LOG_INF("tick start times: %lld %lld %lld %lld", tick->start_times.m_x, tick->start_times.m_y,
|
||||
tick->start_times.s_x, tick->start_times.s_y);
|
||||
struct vector2d move =
|
||||
update_movement(&move_remainder, &(tick->move_config), tick->max_move, tick->timestamp,
|
||||
tick->start_times.m_x, tick->start_times.m_y);
|
||||
zmk_hid_mouse_movement_update((int16_t)CLAMP(move.x, INT16_MIN, INT16_MAX),
|
||||
(int16_t)CLAMP(move.y, INT16_MIN, INT16_MAX));
|
||||
struct vector2d scroll =
|
||||
update_movement(&scroll_remainder, &(tick->scroll_config), tick->max_scroll,
|
||||
tick->timestamp, tick->start_times.s_x, tick->start_times.s_y);
|
||||
zmk_hid_mouse_scroll_update((int8_t)CLAMP(scroll.x, INT8_MIN, INT8_MAX),
|
||||
(int8_t)CLAMP(scroll.y, INT8_MIN, INT8_MAX));
|
||||
}
|
||||
|
||||
int zmk_mouse_tick_listener(const zmk_event_t *eh) {
|
||||
const struct zmk_mouse_tick *tick = as_zmk_mouse_tick(eh);
|
||||
if (tick) {
|
||||
mouse_tick_handler(tick);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZMK_LISTENER(zmk_mouse_tick_listener, zmk_mouse_tick_listener);
|
||||
ZMK_SUBSCRIPTION(zmk_mouse_tick_listener, zmk_mouse_tick);
|
||||
|
||||
#endif /* !defined(CONFIG_ZMK_SPLIT) || defined(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */
|
|
@ -1 +0,0 @@
|
|||
s/.*hid_listener_keycode_//p
|
|
@ -1,2 +0,0 @@
|
|||
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 @@
|
|||
s/.*hid_mouse_//p
|
|
@ -0,0 +1,22 @@
|
|||
movement_update: Mouse movement updated to -1/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to -2/0
|
||||
movement_update: Mouse movement updated to -2/-2
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to -2/0
|
||||
movement_update: Mouse movement updated to -2/-2
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to -3/0
|
||||
movement_update: Mouse movement updated to -3/-2
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to -3/0
|
||||
movement_update: Mouse movement updated to -3/-3
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to 0/-3
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
|
@ -0,0 +1,28 @@
|
|||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include <dt-bindings/zmk/mouse.h>
|
||||
|
||||
/ {
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
label ="Default keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&mmv MOVE_LEFT &mmv MOVE_UP
|
||||
&none &none
|
||||
>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_PRESS(0,1,100)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
>;
|
||||
};
|
1
app/tests/mouse-keys/mouse-move/move_x/events.patterns
Normal file
1
app/tests/mouse-keys/mouse-move/move_x/events.patterns
Normal file
|
@ -0,0 +1 @@
|
|||
s/.*hid_mouse_//p
|
|
@ -0,0 +1,27 @@
|
|||
movement_update: Mouse movement updated to -1/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to -2/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to -2/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to -3/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to 3/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to 5/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to 5/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to 6/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to 6/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
|
@ -0,0 +1,28 @@
|
|||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include <dt-bindings/zmk/mouse.h>
|
||||
|
||||
/ {
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
label ="Default keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&mmv MOVE_LEFT &mmv MOVE_RIGHT
|
||||
&none &none
|
||||
>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,100)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
ZMK_MOCK_PRESS(0,1,100)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
>;
|
||||
};
|
1
app/tests/mouse-keys/mouse-move/move_y/events.patterns
Normal file
1
app/tests/mouse-keys/mouse-move/move_y/events.patterns
Normal file
|
@ -0,0 +1 @@
|
|||
s/.*hid_mouse_//p
|
|
@ -0,0 +1,27 @@
|
|||
movement_update: Mouse movement updated to 0/-1
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to 0/-2
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to 0/-2
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to 0/-3
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to 0/3
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to 0/5
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to 0/5
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to 0/6
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_update: Mouse movement updated to 0/6
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&mmv MOVE_LEFT &none
|
||||
&mmv MOVE_UP &mmv MOVE_DOWN
|
||||
&none &none
|
||||
>;
|
||||
};
|
||||
|
@ -22,5 +22,7 @@
|
|||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,100)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
ZMK_MOCK_PRESS(0,1,100)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
>;
|
||||
};
|
Loading…
Add table
Reference in a new issue