You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
3.5 KiB
102 lines
3.5 KiB
/* |
|
* Copyright (c) 2020 The ZMK Contributors |
|
* |
|
* SPDX-License-Identifier: MIT |
|
*/ |
|
|
|
#include <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/mouse.h> |
|
|
|
#include <sys/util.h> // CLAMP |
|
|
|
#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) { |
|
struct vector2d move = {0}; |
|
if (max_speed.x == 0 && max_speed.y == 0) { |
|
*remainder = (struct vector2d){0}; |
|
return move; |
|
} |
|
|
|
int64_t move_duration = ms_since_start(*start_time, now, config->delay_ms); |
|
move = (struct vector2d){ |
|
.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, |
|
}; |
|
|
|
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) { |
|
struct vector2d move = 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), |
|
(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_time); |
|
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); |