Add files via upload

This commit is contained in:
Merlinov 2023-02-08 21:56:12 +03:00 committed by GitHub
parent b2fefbb89c
commit 9d704977a4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 330 additions and 0 deletions

38
app/src/mouse/Kconfig Normal file
View file

@ -0,0 +1,38 @@
# Copyright (c) 2021 The ZMK Contributors
# SPDX-License-Identifier: MIT
menuconfig ZMK_MOUSE
bool "Enable ZMK mouse emulation"
default n
if ZMK_MOUSE
config ZMK_MOUSE_TICK_DURATION
int "Mouse tick duration in ms"
default 8
choice ZMK_MOUSE_WORK_QUEUE
prompt "Work queue selection for mouse events"
default ZMK_MOUSE_WORK_QUEUE_DEDICATED
config ZMK_MOUSE_WORK_QUEUE_SYSTEM
bool "Use default system work queue for mouse events"
config ZMK_MOUSE_WORK_QUEUE_DEDICATED
bool "Use dedicated work queue for mouse events"
endchoice
if ZMK_MOUSE_WORK_QUEUE_DEDICATED
config ZMK_MOUSE_DEDICATED_THREAD_STACK_SIZE
int "Stack size for dedicated mouse thread/queue"
default 2048
config ZMK_MOUSE_DEDICATED_THREAD_PRIORITY
int "Thread priority for dedicated mouse thread/queue"
default 3
endif # ZMK_MOUSE_WORK_QUEUE_DEDICATED
endif

View file

@ -0,0 +1,159 @@
/*
* Copyright (c) 2021 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <drivers/behavior.h>
#include <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>
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 int64_t start_time = 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_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) {
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_time));
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 int mouse_timer_ref_count = 0;
void mouse_timer_ref() {
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));
}
mouse_timer_ref_count += 1;
}
void mouse_timer_unref() {
if (mouse_timer_ref_count > 0) {
mouse_timer_ref_count--;
}
if (mouse_timer_ref_count == 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();
}
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();
}
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();
}
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();
}
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);

30
app/src/mouse/main.c Normal file
View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <kernel.h>
#include <zmk/mouse.h>
#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED)
K_THREAD_STACK_DEFINE(mouse_work_stack_area, CONFIG_ZMK_MOUSE_DEDICATED_THREAD_STACK_SIZE);
static struct k_work_q mouse_work_q;
#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() {
#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED)
k_work_q_start(&mouse_work_q, mouse_work_stack_area,
K_THREAD_STACK_SIZEOF(mouse_work_stack_area),
CONFIG_ZMK_MOUSE_DEDICATED_THREAD_PRIORITY);
#endif
return 0;
}

View file

@ -0,0 +1,103 @@
/*
* 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);