Cleanup and acceleration fixes

This commit is contained in:
krikun98 2021-09-02 04:09:07 +03:00 committed by Alexander Krikun
parent a6d5ed15c9
commit 775117d590
12 changed files with 80 additions and 76 deletions

View file

@ -4,9 +4,9 @@
compatible = "zmk,behavior-mouse-move"; compatible = "zmk,behavior-mouse-move";
label = "MOUSE_MOVE"; label = "MOUSE_MOVE";
#binding-cells = <1>; #binding-cells = <1>;
delay-ms = <100>; delay-ms = <0>;
time-to-max-speed-ms = <1000>; time-to-max-speed-ms = <300>;
acceleration-exponent = <2000>; acceleration-exponent = <1>;
}; };
}; };
}; };

View file

@ -5,7 +5,7 @@
label = "MOUSE_SCROLL"; label = "MOUSE_SCROLL";
#binding-cells = <1>; #binding-cells = <1>;
delay-ms = <0>; delay-ms = <0>;
time-to-max-speed-ms = <1000>; time-to-max-speed-ms = <300>;
acceleration-exponent = <0>; acceleration-exponent = <0>;
}; };
}; };

View file

@ -17,6 +17,7 @@ struct zmk_mouse_tick {
struct vector2d max_scroll; struct vector2d max_scroll;
struct mouse_config move_config; struct mouse_config move_config;
struct mouse_config scroll_config; struct mouse_config scroll_config;
int64_t* start_time;
int64_t timestamp; int64_t timestamp;
}; };
@ -25,12 +26,14 @@ ZMK_EVENT_DECLARE(zmk_mouse_tick);
static inline struct zmk_mouse_tick_event *zmk_mouse_tick(struct vector2d max_move, static inline struct zmk_mouse_tick_event *zmk_mouse_tick(struct vector2d max_move,
struct vector2d max_scroll, struct vector2d max_scroll,
struct mouse_config move_config, struct mouse_config move_config,
struct mouse_config scroll_config) { struct mouse_config scroll_config,
int64_t* movement_start) {
return new_zmk_mouse_tick((struct zmk_mouse_tick){ return new_zmk_mouse_tick((struct zmk_mouse_tick){
.max_move = max_move, .max_move = max_move,
.max_scroll = max_scroll, .max_scroll = max_scroll,
.move_config = move_config, .move_config = move_config,
.scroll_config = scroll_config, .scroll_config = scroll_config,
.start_time = movement_start,
.timestamp = k_uptime_get(), .timestamp = k_uptime_get(),
}); });
} }

View file

@ -18,7 +18,7 @@ struct mouse_config {
// acceleration exponent 0: uniform speed // acceleration exponent 0: uniform speed
// acceleration exponent 1: uniform acceleration // acceleration exponent 1: uniform acceleration
// acceleration exponent 2: uniform jerk // acceleration exponent 2: uniform jerk
float acceleration_exponent; int acceleration_exponent;
}; };
struct vector2d { struct vector2d {

View file

@ -39,9 +39,9 @@ static const struct behavior_driver_api behavior_mouse_key_press_driver_api = {
.binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released};
#define KP_INST(n) \ #define KP_INST(n) \
DEVICE_AND_API_INIT( \ DEVICE_DT_INST_DEFINE(n, behavior_mouse_key_press_init, device_pm_control_nop, NULL, NULL, \
behavior_mouse_key_press_##n, DT_INST_LABEL(n), behavior_mouse_key_press_init, NULL, NULL, \ APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_key_press_driver_api); &behavior_mouse_key_press_driver_api);
DT_INST_FOREACH_STATUS_OKAY(KP_INST) DT_INST_FOREACH_STATUS_OKAY(KP_INST)

View file

@ -46,11 +46,11 @@ static const struct behavior_driver_api behavior_mouse_move_driver_api = {
static struct mouse_config behavior_mouse_move_config_##n = { \ static struct mouse_config behavior_mouse_move_config_##n = { \
.delay_ms = DT_INST_PROP(n, delay_ms), \ .delay_ms = DT_INST_PROP(n, delay_ms), \
.time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \ .time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \
.acceleration_exponent = (float)DT_INST_PROP(n, acceleration_exponent) / 1000.0f, \ .acceleration_exponent = DT_INST_PROP(n, acceleration_exponent), \
}; \ }; \
DEVICE_AND_API_INIT(behavior_mouse_move_##n, DT_INST_LABEL(n), behavior_mouse_move_init, NULL, \ DEVICE_DT_INST_DEFINE(n, behavior_mouse_move_init, device_pm_control_nop, NULL, \
&behavior_mouse_move_config_##n, APPLICATION, \ &behavior_mouse_move_config_##n, APPLICATION, \
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_move_driver_api); CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_move_driver_api);
DT_INST_FOREACH_STATUS_OKAY(KP_INST) DT_INST_FOREACH_STATUS_OKAY(KP_INST)

View file

@ -47,11 +47,11 @@ static const struct behavior_driver_api behavior_mouse_scroll_driver_api = {
static struct mouse_config behavior_mouse_scroll_config_##n = { \ static struct mouse_config behavior_mouse_scroll_config_##n = { \
.delay_ms = DT_INST_PROP(n, delay_ms), \ .delay_ms = DT_INST_PROP(n, delay_ms), \
.time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \ .time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \
.acceleration_exponent = (float)DT_INST_PROP(n, acceleration_exponent) / 1000.0f, \ .acceleration_exponent = DT_INST_PROP(n, acceleration_exponent), \
}; \ }; \
DEVICE_AND_API_INIT(behavior_mouse_scroll_##n, DT_INST_LABEL(n), behavior_mouse_scroll_init, \ DEVICE_DT_INST_DEFINE(n, behavior_mouse_scroll_init, device_pm_control_nop, NULL, \
NULL, &behavior_mouse_scroll_config_##n, APPLICATION, \ &behavior_mouse_scroll_config_##n, APPLICATION, \
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_scroll_driver_api); CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_scroll_driver_api);
DT_INST_FOREACH_STATUS_OKAY(KP_INST) DT_INST_FOREACH_STATUS_OKAY(KP_INST)

View file

@ -146,7 +146,6 @@ int zmk_endpoints_send_report(uint16_t usage_page) {
} }
int zmk_endpoints_send_mouse_report() { int zmk_endpoints_send_mouse_report() {
LOG_DBG("SENDING MOUSE REPORT");
struct zmk_hid_mouse_report *mouse_report = zmk_hid_get_mouse_report(); struct zmk_hid_mouse_report *mouse_report = zmk_hid_get_mouse_report();
switch (current_endpoint) { switch (current_endpoint) {

View file

@ -17,6 +17,10 @@ LOG_MODULE_REGISTER(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/display.h> #include <zmk/display.h>
#include <drivers/ext_power.h> #include <drivers/ext_power.h>
#ifdef CONFIG_ZMK_MOUSE
#include <zmk/mouse.h>
#endif /* CONFIG_ZMK_MOUSE */
#define ZMK_KSCAN_DEV DT_LABEL(ZMK_MATRIX_NODE_ID) #define ZMK_KSCAN_DEV DT_LABEL(ZMK_MATRIX_NODE_ID)
void main(void) { void main(void) {

View file

@ -20,18 +20,36 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
static struct vector2d move_speed = {0}; static struct vector2d move_speed = {0};
static struct vector2d scroll_speed = {0}; static struct vector2d scroll_speed = {0};
static struct mouse_config move_config = {0}; static struct mouse_config move_config = (struct mouse_config){0};
static struct mouse_config scroll_config = {0}; static struct mouse_config scroll_config = (struct mouse_config){0};
static int64_t start_time = 0;
static void clear_mouse_state() { 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}; move_speed = (struct vector2d){0};
scroll_speed = (struct vector2d){0}; scroll_speed = (struct vector2d){0};
start_time = 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) { static void mouse_tick_timer_handler(struct k_work *work) {
zmk_hid_mouse_movement_set(0, 0); zmk_hid_mouse_movement_set(0, 0);
zmk_hid_mouse_scroll_set(0, 0); zmk_hid_mouse_scroll_set(0, 0);
ZMK_EVENT_RAISE(zmk_mouse_tick(move_speed, scroll_speed, move_config, scroll_config)); LOG_DBG("Raising mouse tick event");
ZMK_EVENT_RAISE(zmk_mouse_tick(move_speed, scroll_speed, move_config, scroll_config, &start_time));
zmk_endpoints_send_mouse_report(); zmk_endpoints_send_mouse_report();
} }
@ -41,12 +59,13 @@ void mouse_timer_cb(struct k_timer *dummy) {
k_work_submit_to_queue(zmk_mouse_work_q(), &mouse_tick); k_work_submit_to_queue(zmk_mouse_work_q(), &mouse_tick);
} }
K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, NULL); K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, mouse_clear_cb);
static int mouse_timer_ref_count = 0; static int mouse_timer_ref_count = 0;
void mouse_timer_ref() { void mouse_timer_ref() {
if (mouse_timer_ref_count == 0) { if (mouse_timer_ref_count == 0) {
start_time = k_uptime_get();
k_timer_start(&mouse_timer, K_NO_WAIT, K_MSEC(CONFIG_ZMK_MOUSE_TICK_DURATION)); k_timer_start(&mouse_timer, K_NO_WAIT, K_MSEC(CONFIG_ZMK_MOUSE_TICK_DURATION));
} }
mouse_timer_ref_count += 1; mouse_timer_ref_count += 1;
@ -58,7 +77,6 @@ void mouse_timer_unref() {
} }
if (mouse_timer_ref_count == 0) { if (mouse_timer_ref_count == 0) {
k_timer_stop(&mouse_timer); k_timer_stop(&mouse_timer);
clear_mouse_state();
} }
} }
@ -101,6 +119,9 @@ static void listener_mouse_button_released(const struct zmk_mouse_button_state_c
int mouse_listener(const zmk_event_t *eh) { int mouse_listener(const zmk_event_t *eh) {
const struct zmk_mouse_move_state_changed *mmv_ev = as_zmk_mouse_move_state_changed(eh); const struct zmk_mouse_move_state_changed *mmv_ev = as_zmk_mouse_move_state_changed(eh);
if (mmv_ev) { if (mmv_ev) {
if (!equals(&move_config, &(mmv_ev->config)))
move_config = mmv_ev->config;
if (mmv_ev->state) { if (mmv_ev->state) {
listener_mouse_move_pressed(mmv_ev); listener_mouse_move_pressed(mmv_ev);
} else { } else {
@ -110,6 +131,8 @@ int mouse_listener(const zmk_event_t *eh) {
} }
const struct zmk_mouse_scroll_state_changed *msc_ev = as_zmk_mouse_scroll_state_changed(eh); const struct zmk_mouse_scroll_state_changed *msc_ev = as_zmk_mouse_scroll_state_changed(eh);
if (msc_ev) { if (msc_ev) {
if (!equals(&scroll_config, &(msc_ev->config)))
scroll_config = msc_ev->config;
if (msc_ev->state) { if (msc_ev->state) {
listener_mouse_scroll_pressed(msc_ev); listener_mouse_scroll_pressed(msc_ev);
} else { } else {

View file

@ -8,23 +8,18 @@
#include <zmk/mouse.h> #include <zmk/mouse.h>
#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) #if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED)
K_THREAD_STACK_DEFINE(mouse_work_stack_area, CONFIG_ZMK_MOUSE_DEDICATED_THREAD_STACK_SIZE); K_THREAD_STACK_DEFINE(mouse_work_stack_area, CONFIG_ZMK_MOUSE_DEDICATED_THREAD_STACK_SIZE);
static struct k_work_q mouse_work_q; static struct k_work_q mouse_work_q;
struct k_work_q *zmk_mouse_work_q() {
return &mouse_work_q;
}
#else
struct k_work_q *zmk_mouse_work_q() {
return &k_sys_work_q;
}
#endif #endif
struct k_work_q *zmk_mouse_work_q() {
#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED)
return &mouse_work_q;
#else
return &k_sys_work_q;
#endif
}
int zmk_mouse_init() { int zmk_mouse_init() {
#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) #if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED)
k_work_q_start(&mouse_work_q, mouse_work_stack_area, k_work_q_start(&mouse_work_q, mouse_work_stack_area,

View file

@ -13,17 +13,13 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/endpoints.h> #include <zmk/endpoints.h>
#include <zmk/mouse.h> #include <zmk/mouse.h>
#include <sys/util.h> #include <sys/util.h> // CLAMP
// CLAMP will be provided by sys/util.h from zephyr 2.6 onward
#define CLAMP(x, min, max) MIN(MAX(x, min), max)
#if CONFIG_MINIMAL_LIBC #if CONFIG_MINIMAL_LIBC
static float powf(float base, float exponent) { static float powf(float base, float exponent) {
// poor man's power implementation rounds the exponent down to the nearest integer. // poor man's power implementation rounds the exponent down to the nearest integer.
LOG_DBG("falling back to integer exponent %d instead of %f", (int)exponent, exponent);
float power = 1.0f; float power = 1.0f;
for (; exponent < 1.0f; exponent--) { for (; exponent >= 1.0f; exponent--) {
power = power * base; power = power * base;
} }
return power; return power;
@ -32,27 +28,11 @@ static float powf(float base, float exponent) {
#include <math.h> #include <math.h>
#endif #endif
struct movement_state { struct vector2d move_remainder = {0};
int64_t start; struct vector2d scroll_remainder = {0};
struct vector2d fractional_remainder;
};
struct movement_state move_state = {0}; static int64_t ms_since_start(int64_t start, int64_t now, int64_t delay) {
static struct mouse_config move_config = (struct mouse_config){ int64_t move_duration = now - (start + delay);
.delay_ms = 0,
.time_to_max_speed_ms = 300,
.acceleration_exponent = 2.0,
};
struct movement_state scroll_state = {0};
static struct mouse_config scroll_config = (struct mouse_config){
.delay_ms = 0,
.time_to_max_speed_ms = 300,
.acceleration_exponent = 2.0,
};
static int64_t ms_since_start(int64_t start, int64_t now) {
int64_t move_duration = now - start;
// start can be in the future if there's a delay // start can be in the future if there's a delay
if (move_duration < 0) { if (move_duration < 0) {
move_duration = 0; move_duration = 0;
@ -60,10 +40,12 @@ static int64_t ms_since_start(int64_t start, int64_t now) {
return move_duration; return move_duration;
} }
static float speed(struct mouse_config *config, float max_speed, int64_t duration_ms) { static float speed(const struct mouse_config *config, float max_speed, int64_t duration_ms) {
// Calculate the speed based on MouseKeysAccel // Calculate the speed based on MouseKeysAccel
// See https://en.wikipedia.org/wiki/Mouse_keys // See https://en.wikipedia.org/wiki/Mouse_keys
if (duration_ms > config->time_to_max_speed_ms) { if (duration_ms > config->time_to_max_speed_ms
|| config->time_to_max_speed_ms == 0
|| config->acceleration_exponent == 0) {
return max_speed; return max_speed;
} }
float time_fraction = (float)duration_ms / config->time_to_max_speed_ms; float time_fraction = (float)duration_ms / config->time_to_max_speed_ms;
@ -76,36 +58,34 @@ static void track_remainder(float *move, float *remainder) {
*move = (int)new_move; *move = (int)new_move;
} }
static struct vector2d update_movement(struct movement_state *state, struct mouse_config *config, static struct vector2d update_movement(struct vector2d *remainder,
struct vector2d max_speed, int64_t now) { const struct mouse_config *config, struct vector2d max_speed,
int64_t now, int64_t *start_time) {
struct vector2d move = {0}; struct vector2d move = {0};
if (max_speed.x == 0 && max_speed.y == 0) { if (max_speed.x == 0 && max_speed.y == 0) {
*state = (struct movement_state){0}; *remainder = (struct vector2d){0};
return move; return move;
} }
if (state->start == 0) {
state->start = now + config->delay_ms;
}
int64_t move_duration = ms_since_start(state->start, now); int64_t move_duration = ms_since_start(*start_time, now, config->delay_ms);
move = (struct vector2d){ move = (struct vector2d){
.x = speed(config, max_speed.x, move_duration) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000, .x = speed(config, max_speed.x, move_duration) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000,
.y = speed(config, max_speed.y, move_duration) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000, .y = speed(config, max_speed.y, move_duration) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000,
}; };
track_remainder(&(move.x), &state->fractional_remainder.x); track_remainder(&(move.x), &(remainder->x));
track_remainder(&(move.y), &state->fractional_remainder.y); track_remainder(&(move.y), &(remainder->y));
return move; return move;
} }
static void mouse_tick_handler(const struct zmk_mouse_tick *tick) { static void mouse_tick_handler(const struct zmk_mouse_tick *tick) {
struct vector2d move = struct vector2d move =
update_movement(&move_state, &move_config, tick->max_move, tick->timestamp); update_movement(&move_remainder, &(tick->move_config), tick->max_move, tick->timestamp, tick->start_time);
zmk_hid_mouse_movement_update((int16_t)CLAMP(move.x, INT16_MIN, INT16_MAX), zmk_hid_mouse_movement_update((int16_t)CLAMP(move.x, INT16_MIN, INT16_MAX),
(int16_t)CLAMP(move.y, INT16_MIN, INT16_MAX)); (int16_t)CLAMP(move.y, INT16_MIN, INT16_MAX));
struct vector2d scroll = struct vector2d scroll =
update_movement(&scroll_state, &scroll_config, tick->max_scroll, tick->timestamp); update_movement(&scroll_remainder, &(tick->scroll_config), tick->max_scroll, tick->timestamp, tick->start_time);
zmk_hid_mouse_scroll_update((int8_t)CLAMP(scroll.x, INT8_MIN, INT8_MAX), zmk_hid_mouse_scroll_update((int8_t)CLAMP(scroll.x, INT8_MIN, INT8_MAX),
(int8_t)CLAMP(scroll.y, INT8_MIN, INT8_MAX)); (int8_t)CLAMP(scroll.y, INT8_MIN, INT8_MAX));
} }