This commit is contained in:
Kim 2024-03-25 10:59:23 +05:30 committed by GitHub
commit d649504b36
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 1172 additions and 74 deletions

View file

@ -33,14 +33,13 @@ target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/ext_power_generic.c)
target_sources(app PRIVATE src/events/activity_state_changed.c) 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/position_state_changed.c)
target_sources(app PRIVATE src/events/sensor_event.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_WPM app PRIVATE src/events/wpm_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_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/events/usb_conn_state_changed.c)
target_sources(app PRIVATE src/behaviors/behavior_reset.c) target_sources(app PRIVATE src/behaviors/behavior_reset.c)
target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext_power.c) target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext_power.c)
if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
target_sources(app PRIVATE src/hid.c) target_sources(app PRIVATE src/hid.c)
target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse.c) target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/input_listener.c)
target_sources(app PRIVATE src/behaviors/behavior_key_press.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_KEY_TOGGLE app PRIVATE src/behaviors/behavior_key_toggle.c)
target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c) target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c)
@ -59,6 +58,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE_VAR app PRIVATE src/behaviors/behavior_sensor_rotate_var.c) target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE_VAR app PRIVATE src/behaviors/behavior_sensor_rotate_var.c)
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON app PRIVATE src/behaviors/behavior_sensor_rotate_common.c) target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON app PRIVATE src/behaviors/behavior_sensor_rotate_common.c)
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_MOUSE_KEY_PRESS app PRIVATE src/behaviors/behavior_mouse_key_press.c) target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_MOUSE_KEY_PRESS app PRIVATE src/behaviors/behavior_mouse_key_press.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/combo.c)
target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c) target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c)
target_sources(app PRIVATE src/behavior_queue.c) target_sources(app PRIVATE src/behavior_queue.c)

View file

@ -367,13 +367,7 @@ endif
#Display/LED Options #Display/LED Options
endmenu endmenu
menu "Mouse Options" rsource "src/mouse/Kconfig"
config ZMK_MOUSE
bool "Enable ZMK mouse emulation"
#Mouse Options
endmenu
menu "Power Management" menu "Power Management"

View file

@ -12,6 +12,12 @@ config ZMK_BEHAVIOR_MOUSE_KEY_PRESS
depends on DT_HAS_ZMK_BEHAVIOR_MOUSE_KEY_PRESS_ENABLED depends on DT_HAS_ZMK_BEHAVIOR_MOUSE_KEY_PRESS_ENABLED
imply ZMK_MOUSE imply ZMK_MOUSE
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 config ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON
bool bool
@ -30,4 +36,4 @@ config ZMK_BEHAVIOR_SENSOR_ROTATE_VAR
config ZMK_BEHAVIOR_MACRO config ZMK_BEHAVIOR_MACRO
bool bool
default y default y
depends on DT_HAS_ZMK_BEHAVIOR_MACRO_ENABLED || DT_HAS_ZMK_BEHAVIOR_MACRO_ONE_PARAM_ENABLED || DT_HAS_ZMK_BEHAVIOR_MACRO_TWO_PARAM_ENABLED depends on DT_HAS_ZMK_BEHAVIOR_MACRO_ENABLED || DT_HAS_ZMK_BEHAVIOR_MACRO_ONE_PARAM_ENABLED || DT_HAS_ZMK_BEHAVIOR_MACRO_TWO_PARAM_ENABLED

View file

@ -1,3 +1,9 @@
/*
* Copyright (c) 2024 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <behaviors/key_press.dtsi> #include <behaviors/key_press.dtsi>
#include <behaviors/key_toggle.dtsi> #include <behaviors/key_toggle.dtsi>
#include <behaviors/transparent.dtsi> #include <behaviors/transparent.dtsi>
@ -19,4 +25,3 @@
#include <behaviors/key_repeat.dtsi> #include <behaviors/key_repeat.dtsi>
#include <behaviors/backlight.dtsi> #include <behaviors/backlight.dtsi>
#include <behaviors/macros.dtsi> #include <behaviors/macros.dtsi>
#include <behaviors/mouse_key_press.dtsi>

View file

@ -5,4 +5,9 @@
#binding-cells = <1>; #binding-cells = <1>;
}; };
}; };
mkp_input_listener {
compatible = "zmk,input-listener";
device = <&mkp>;
};
}; };

View file

@ -0,0 +1,9 @@
/*
* Copyright (c) 2024 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include "mouse_key_press.dtsi"
#include "mouse_move.dtsi"
#include "mouse_scroll.dtsi"

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2024 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <zephyr/dt-bindings/input/input-event-codes.h>
/ {
behaviors {
/omit-if-no-ref/ mmv: mouse_move {
compatible = "zmk,behavior-input-two-axis";
#binding-cells = <1>;
x-input-code = <INPUT_REL_X>;
y-input-code = <INPUT_REL_Y>;
time-to-max-speed-ms = <300>;
acceleration-exponent = <1>;
};
};
mmv_input_listener {
compatible = "zmk,input-listener";
device = <&mmv>;
};
};

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2024 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <zephyr/dt-bindings/input/input-event-codes.h>
/ {
behaviors {
/omit-if-no-ref/ msc: mouse_scroll {
compatible = "zmk,behavior-input-two-axis";
#binding-cells = <1>;
x-input-code = <INPUT_REL_HWHEEL>;
y-input-code = <INPUT_REL_WHEEL>;
time-to-max-speed-ms = <300>;
acceleration-exponent = <0>;
};
};
msc_input_listener {
compatible = "zmk,input-listener";
device = <&msc>;
};
};

View file

@ -0,0 +1,25 @@
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
trigger-period-ms:
type: int
default: 16
description: The time (in ms) between generated inputs when an input has non-zero speed.
delay-ms:
type: int
time-to-max-speed-ms:
type: int
required: true
acceleration-exponent:
type: int
default: 1

View file

@ -0,0 +1,36 @@
description: |
Listener to subscribe to input events and send HID updates after processing
compatible: "zmk,input-listener"
properties:
device:
type: phandle
required: true
xy-swap:
type: boolean
x-invert:
type: boolean
y-invert:
type: boolean
scale-multiplier:
type: int
default: 1
scale-divisor:
type: int
default: 1
layer-toggle:
type: int
default: -1
required: false
description: The layer that should be toggled when the mouse is moved.
layer-toggle-delay-ms:
type: int
default: 250
required: false
description: How many miliseconds of mouse activity are required before the layer is toggled on.
layer-toggle-timeout-ms:
type: int
default: 250
required: false
description: How many miliseconds of mouse inactivity are required before the layer is toggled off again.

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020 The ZMK Contributors * Copyright (c) 2023 The ZMK Contributors
* *
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
@ -22,3 +22,29 @@
#define MB4 BIT(3) #define MB4 BIT(3)
#define MB5 BIT(4) #define MB5 BIT(4)
#ifndef ZMK_MOUSE_DEFAULT_MOVE_VAL
#define ZMK_MOUSE_DEFAULT_MOVE_VAL 600
#endif
#ifndef ZMK_MOUSE_DEFAULT_SCRL_VAL
#define ZMK_MOUSE_DEFAULT_SCRL_VAL 10
#endif
/* Mouse move behavior */
#define MOVE_Y(vert) ((vert)&0xFFFF)
#define MOVE_Y_DECODE(encoded) (int16_t)((encoded)&0x0000FFFF)
#define MOVE_X(hor) (((hor)&0xFFFF) << 16)
#define MOVE_X_DECODE(encoded) (int16_t)(((encoded)&0xFFFF0000) >> 16)
#define MOVE(hor, vert) (MOVE_X(hor) + MOVE_Y(vert))
#define MOVE_UP MOVE_Y(-ZMK_MOUSE_DEFAULT_MOVE_VAL)
#define MOVE_DOWN MOVE_Y(ZMK_MOUSE_DEFAULT_MOVE_VAL)
#define MOVE_LEFT MOVE_X(-ZMK_MOUSE_DEFAULT_MOVE_VAL)
#define MOVE_RIGHT MOVE_X(ZMK_MOUSE_DEFAULT_MOVE_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)

View file

@ -72,4 +72,4 @@ int zmk_endpoints_send_report(uint16_t usage_page);
#if IS_ENABLED(CONFIG_ZMK_MOUSE) #if IS_ENABLED(CONFIG_ZMK_MOUSE)
int zmk_endpoints_send_mouse_report(); int zmk_endpoints_send_mouse_report();
#endif // IS_ENABLE(CONFIG_ZMK_MOUSE) #endif // IS_ENABLED(CONFIG_ZMK_MOUSE)

View file

@ -59,6 +59,10 @@
#define ZMK_HID_REPORT_ID_CONSUMER 0x02 #define ZMK_HID_REPORT_ID_CONSUMER 0x02
#define ZMK_HID_REPORT_ID_MOUSE 0x03 #define ZMK_HID_REPORT_ID_MOUSE 0x03
// Needed until Zephyr offers a 2 byte usage macro
#define HID_USAGE16(idx) \
HID_ITEM(HID_ITEM_TAG_USAGE, HID_ITEM_TYPE_LOCAL, 2), (idx & 0xFF), (idx >> 8 & 0xFF)
static const uint8_t zmk_hid_report_desc[] = { static const uint8_t zmk_hid_report_desc[] = {
HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP), HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP),
HID_USAGE(HID_USAGE_GD_KEYBOARD), HID_USAGE(HID_USAGE_GD_KEYBOARD),
@ -167,11 +171,18 @@ static const uint8_t zmk_hid_report_desc[] = {
HID_USAGE(HID_USAGE_GD_X), HID_USAGE(HID_USAGE_GD_X),
HID_USAGE(HID_USAGE_GD_Y), HID_USAGE(HID_USAGE_GD_Y),
HID_USAGE(HID_USAGE_GD_WHEEL), HID_USAGE(HID_USAGE_GD_WHEEL),
HID_LOGICAL_MIN8(-0x7F), HID_LOGICAL_MIN16(0xFF, -0x7F),
HID_LOGICAL_MAX8(0x7F), HID_LOGICAL_MAX16(0xFF, 0x7F),
HID_REPORT_SIZE(0x08), HID_REPORT_SIZE(0x10),
HID_REPORT_COUNT(0x03), HID_REPORT_COUNT(0x03),
HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_REL), HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_REL),
HID_USAGE_PAGE(HID_USAGE_CONSUMER),
HID_USAGE16(HID_USAGE_CONSUMER_AC_PAN),
HID_LOGICAL_MIN16(0xFF, -0x7F),
HID_LOGICAL_MAX16(0xFF, 0x7F),
HID_REPORT_SIZE(0x08),
HID_REPORT_COUNT(0x01),
HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_REL),
HID_END_COLLECTION, HID_END_COLLECTION,
HID_END_COLLECTION, HID_END_COLLECTION,
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) #endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
@ -240,9 +251,10 @@ struct zmk_hid_consumer_report {
#if IS_ENABLED(CONFIG_ZMK_MOUSE) #if IS_ENABLED(CONFIG_ZMK_MOUSE)
struct zmk_hid_mouse_report_body { struct zmk_hid_mouse_report_body {
zmk_mouse_button_flags_t buttons; zmk_mouse_button_flags_t buttons;
int8_t d_x; int16_t d_x;
int8_t d_y; int16_t d_y;
int8_t d_wheel; int16_t d_scroll_y;
int16_t d_scroll_x;
} __packed; } __packed;
struct zmk_hid_mouse_report { struct zmk_hid_mouse_report {
@ -283,6 +295,10 @@ int zmk_hid_mouse_button_press(zmk_mouse_button_t button);
int zmk_hid_mouse_button_release(zmk_mouse_button_t button); int zmk_hid_mouse_button_release(zmk_mouse_button_t button);
int zmk_hid_mouse_buttons_press(zmk_mouse_button_flags_t buttons); int zmk_hid_mouse_buttons_press(zmk_mouse_button_flags_t buttons);
int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons); int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons);
void zmk_hid_mouse_movement_set(int16_t x, int16_t y);
void zmk_hid_mouse_scroll_set(int8_t x, int8_t y);
void zmk_hid_mouse_movement_update(int16_t x, int16_t y);
void zmk_hid_mouse_scroll_update(int8_t x, int8_t y);
void zmk_hid_mouse_clear(void); void zmk_hid_mouse_clear(void);
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) #endif // IS_ENABLED(CONFIG_ZMK_MOUSE)

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021 The ZMK Contributors * Copyright (c) 2023 The ZMK Contributors
* *
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */

View file

@ -0,0 +1,265 @@
/*
* 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;
uint16_t delay_ms;
uint16_t time_to_max_speed_ms;
uint8_t trigger_period_ms;
// acceleration exponent 0: uniform speed
// acceleration exponent 1: uniform acceleration
// acceleration exponent 2: uniform jerk
uint8_t 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->trigger_period_ms / 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;
uint64_t timestamp = k_uptime_get();
LOG_INF("x start: %llu, y start: %llu, current timestamp: %llu", 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(cfg->trigger_period_ms));
}
}
static void set_start_times_for_activity_1d(struct movement_state_1d *state) {
if (state->speed != 0 && state->start_time == 0) {
state->start_time = k_uptime_get();
} else if (state->speed == 0) {
state->start_time = 0;
}
}
static void set_start_times_for_activity(struct movement_state_2d *state) {
set_start_times_for_activity_1d(&state->x);
set_start_times_for_activity_1d(&state->y);
}
static void update_work_scheduling(const struct device *dev) {
struct behavior_input_two_axis_data *data = dev->data;
const struct behavior_input_two_axis_config *cfg = dev->config;
set_start_times_for_activity(&data->state);
if (should_be_working(data)) {
k_work_schedule(&data->tick_work, K_MSEC(cfg->trigger_period_ms));
} else {
k_work_cancel_delayable(&data->tick_work);
}
}
int behavior_input_two_axis_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 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);
behavior_input_two_axis_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);
behavior_input_two_axis_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), \
.trigger_period_ms = DT_INST_PROP(n, trigger_period_ms), \
.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)

View file

@ -11,8 +11,9 @@
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
#include <zmk/behavior.h> #include <zmk/behavior.h>
#include <zmk/event_manager.h> #include <zmk/hid.h>
#include <zmk/events/mouse_button_state_changed.h> #include <zephyr/input/input.h>
#include <zephyr/dt-bindings/input/input-event-codes.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); 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 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, static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) { struct zmk_behavior_binding_event event) {
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);
return raise_zmk_mouse_button_state_changed_from_encoded(binding->param1, true, process_key_state(zmk_behavior_get_binding(binding->behavior_dev), binding->param1, true);
event.timestamp);
return 0;
} }
static int on_keymap_binding_released(struct zmk_behavior_binding *binding, static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) { struct zmk_behavior_binding_event event) {
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); 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 = { static const struct behavior_driver_api behavior_mouse_key_press_driver_api = {

View file

@ -27,8 +27,9 @@ static uint8_t keys_held = 0;
#if IS_ENABLED(CONFIG_ZMK_MOUSE) #if IS_ENABLED(CONFIG_ZMK_MOUSE)
static struct zmk_hid_mouse_report mouse_report = {.report_id = ZMK_HID_REPORT_ID_MOUSE, static struct zmk_hid_mouse_report mouse_report = {
.body = {.buttons = 0}}; .report_id = ZMK_HID_REPORT_ID_MOUSE,
.body = {.buttons = 0, .d_x = 0, .d_y = 0, .d_scroll_y = 0}};
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) #endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
@ -430,7 +431,37 @@ int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons) {
} }
return 0; return 0;
} }
void zmk_hid_mouse_clear(void) { memset(&mouse_report.body, 0, sizeof(mouse_report.body)); }
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 %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 %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 %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: %d/%d", mouse_report.body.d_scroll_x,
mouse_report.body.d_scroll_y);
}
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) #endif // IS_ENABLED(CONFIG_ZMK_MOUSE)

View file

@ -395,7 +395,6 @@ int zmk_hog_send_mouse_report(struct zmk_hid_mouse_report_body *report) {
return 0; return 0;
}; };
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE) #endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
static int zmk_hog_init(void) { static int zmk_hog_init(void) {

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 */
int main(void) { int main(void) {
LOG_INF("Welcome to ZMK!\n"); LOG_INF("Welcome to ZMK!\n");

View file

@ -1,43 +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/events/mouse_button_state_changed.h>
#include <zmk/hid.h>
#include <zmk/endpoints.h>
#include <zmk/mouse.h>
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_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);

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

@ -0,0 +1,8 @@
# Copyright (c) 2023 The ZMK Contributors
# SPDX-License-Identifier: MIT
config ZMK_MOUSE
bool "Mouse Emulation"
select INPUT
select INPUT_THREAD_PRIORITY_OVERRIDE

View file

@ -0,0 +1,319 @@
/*
* Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#define DT_DRV_COMPAT zmk_input_listener
#include <zephyr/device.h>
#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>
#include <zmk/keymap.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
enum input_listener_xy_data_mode {
INPUT_LISTENER_XY_DATA_MODE_NONE,
INPUT_LISTENER_XY_DATA_MODE_REL,
INPUT_LISTENER_XY_DATA_MODE_ABS,
};
struct input_listener_xy_data {
enum input_listener_xy_data_mode mode;
int16_t x;
int16_t y;
};
struct input_listener_config {
bool xy_swap;
bool x_invert;
bool y_invert;
uint16_t scale_multiplier;
uint16_t scale_divisor;
int layer_toggle;
int layer_toggle_delay_ms;
int layer_toggle_timeout_ms;
};
struct input_listener_data {
const struct device *dev;
struct input_listener_xy_data data;
struct input_listener_xy_data wheel_data;
uint8_t button_set;
uint8_t button_clear;
bool layer_toggle_layer_enabled;
int64_t layer_toggle_last_mouse_package_time;
struct k_work_delayable layer_toggle_activation_delay;
struct k_work_delayable layer_toggle_deactivation_delay;
};
void zmk_input_listener_layer_toggle_input_rel_received(const struct input_listener_config *config,
struct input_listener_data *data);
static void handle_rel_code(struct input_listener_data *data, struct input_event *evt) {
switch (evt->code) {
case INPUT_REL_X:
data->data.mode = INPUT_LISTENER_XY_DATA_MODE_REL;
data->data.x += evt->value;
break;
case INPUT_REL_Y:
data->data.mode = INPUT_LISTENER_XY_DATA_MODE_REL;
data->data.y += evt->value;
break;
case INPUT_REL_WHEEL:
data->wheel_data.mode = INPUT_LISTENER_XY_DATA_MODE_REL;
data->wheel_data.y += evt->value;
break;
case INPUT_REL_HWHEEL:
data->wheel_data.mode = INPUT_LISTENER_XY_DATA_MODE_REL;
data->wheel_data.x += evt->value;
break;
default:
break;
}
}
static char *get_input_code_name(struct input_event *evt) {
switch (evt->code) {
case INPUT_REL_X:
return "INPUT_REL_X";
case INPUT_REL_Y:
return "INPUT_REL_Y";
case INPUT_REL_WHEEL:
return "INPUT_REL_WHEEL";
case INPUT_REL_HWHEEL:
return "INPUT_REL_HWHEEL";
case INPUT_BTN_0:
return "INPUT_BTN_0";
case INPUT_BTN_1:
return "INPUT_BTN_1";
case INPUT_BTN_2:
return "INPUT_BTN_2";
case INPUT_BTN_3:
return "INPUT_BTN_3";
case INPUT_BTN_4:
return "INPUT_BTN_4";
default:
return "UNKNOWN";
}
}
static void handle_key_code(struct input_listener_data *data, 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) {
WRITE_BIT(data->button_set, btn, 1);
} else {
WRITE_BIT(data->button_clear, btn, 1);
}
break;
default:
break;
}
}
static void swap_xy(struct input_event *evt) {
switch (evt->code) {
case INPUT_REL_X:
evt->code = INPUT_REL_Y;
break;
case INPUT_REL_Y:
evt->code = INPUT_REL_X;
break;
}
}
static void filter_with_input_config(const struct input_listener_config *cfg,
struct input_event *evt) {
if (!evt->dev) {
return;
}
if (cfg->xy_swap) {
swap_xy(evt);
}
if ((cfg->x_invert && evt->code == INPUT_REL_X) ||
(cfg->y_invert && evt->code == INPUT_REL_Y)) {
evt->value = -(evt->value);
}
evt->value = (int16_t)((evt->value * cfg->scale_multiplier) / cfg->scale_divisor);
}
static void clear_xy_data(struct input_listener_xy_data *data) {
data->x = data->y = 0;
data->mode = INPUT_LISTENER_XY_DATA_MODE_NONE;
}
static void input_handler(const struct input_listener_config *config,
struct input_listener_data *data, struct input_event *evt) {
// First, filter to update the event data as needed.
filter_with_input_config(config, evt);
LOG_DBG("Got input_handler event: %s with value 0x%x", get_input_code_name(evt), evt->value);
zmk_input_listener_layer_toggle_input_rel_received(config, data);
switch (evt->type) {
case INPUT_EV_REL:
handle_rel_code(data, evt);
break;
case INPUT_EV_KEY:
handle_key_code(data, evt);
break;
}
if (evt->sync) {
if (data->wheel_data.mode == INPUT_LISTENER_XY_DATA_MODE_REL) {
zmk_hid_mouse_scroll_set(data->wheel_data.x, data->wheel_data.y);
}
if (data->data.mode == INPUT_LISTENER_XY_DATA_MODE_REL) {
zmk_hid_mouse_movement_set(data->data.x, data->data.y);
}
if (data->button_set != 0) {
for (int i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) {
if ((data->button_set & BIT(i)) != 0) {
zmk_hid_mouse_button_press(i);
}
}
}
if (data->button_clear != 0) {
for (int i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) {
if ((data->button_clear & BIT(i)) != 0) {
zmk_hid_mouse_button_release(i);
}
}
}
zmk_endpoints_send_mouse_report();
zmk_hid_mouse_scroll_set(0, 0);
zmk_hid_mouse_movement_set(0, 0);
clear_xy_data(&data->data);
clear_xy_data(&data->wheel_data);
data->button_set = data->button_clear = 0;
}
}
void zmk_input_listener_layer_toggle_input_rel_received(const struct input_listener_config *config,
struct input_listener_data *data) {
if (config->layer_toggle == -1) {
return;
}
data->layer_toggle_last_mouse_package_time = k_uptime_get();
if (data->layer_toggle_layer_enabled == false) {
k_work_schedule(&data->layer_toggle_activation_delay,
K_MSEC(config->layer_toggle_delay_ms));
} else {
// Deactivate the layer if no further movement within
// layer_toggle_timeout_ms
k_work_reschedule(&data->layer_toggle_deactivation_delay,
K_MSEC(config->layer_toggle_timeout_ms));
}
}
void zmk_input_listener_layer_toggle_activate_layer(struct k_work *item) {
struct k_work_delayable *d_work = k_work_delayable_from_work(item);
struct input_listener_data *data =
CONTAINER_OF(d_work, struct input_listener_data, layer_toggle_activation_delay);
const struct input_listener_config *config = data->dev->config;
int64_t current_time = k_uptime_get();
int64_t last_mv_within_ms = current_time - data->layer_toggle_last_mouse_package_time;
if (last_mv_within_ms <= config->layer_toggle_timeout_ms * 0.1) {
LOG_INF("Activating layer %d due to mouse activity...", config->layer_toggle);
zmk_keymap_layer_activate(config->layer_toggle, false);
data->layer_toggle_layer_enabled = true;
} else {
LOG_INF("Not activating mouse layer %d, because last mouse activity was %lldms ago",
config->layer_toggle, last_mv_within_ms);
}
}
void zmk_input_listener_layer_toggle_deactivate_layer(struct k_work *item) {
struct k_work_delayable *d_work = k_work_delayable_from_work(item);
struct input_listener_data *data =
CONTAINER_OF(d_work, struct input_listener_data, layer_toggle_deactivation_delay);
const struct input_listener_config *config = data->dev->config;
LOG_INF("Deactivating layer %d due to mouse activity...", config->layer_toggle);
if (zmk_keymap_layer_active(config->layer_toggle)) {
zmk_keymap_layer_deactivate(config->layer_toggle);
}
data->layer_toggle_layer_enabled = false;
}
static int zmk_input_listener_layer_toggle_init(const struct input_listener_config *config,
struct input_listener_data *data) {
k_work_init_delayable(&data->layer_toggle_activation_delay,
zmk_input_listener_layer_toggle_activate_layer);
k_work_init_delayable(&data->layer_toggle_deactivation_delay,
zmk_input_listener_layer_toggle_deactivate_layer);
return 0;
}
#define IL_INST(n) \
static const struct input_listener_config config_##n = { \
.xy_swap = DT_INST_PROP(n, xy_swap), \
.x_invert = DT_INST_PROP(n, x_invert), \
.y_invert = DT_INST_PROP(n, y_invert), \
.scale_multiplier = DT_INST_PROP(n, scale_multiplier), \
.scale_divisor = DT_INST_PROP(n, scale_divisor), \
.layer_toggle = DT_INST_PROP(n, layer_toggle), \
.layer_toggle_delay_ms = DT_INST_PROP(n, layer_toggle_delay_ms), \
.layer_toggle_timeout_ms = DT_INST_PROP(n, layer_toggle_timeout_ms), \
}; \
static struct input_listener_data data_##n = { \
.dev = DEVICE_DT_INST_GET(n), \
.layer_toggle_layer_enabled = false, \
.layer_toggle_last_mouse_package_time = 0, \
}; \
void input_handler_##n(struct input_event *evt) { \
input_handler(&config_##n, &data_##n, evt); \
} \
INPUT_CALLBACK_DEFINE(DEVICE_DT_GET(DT_INST_PHANDLE(n, device)), input_handler_##n); \
\
static int zmk_input_listener_init_##n(const struct device *dev) { \
\
struct input_listener_data *data = dev->data; \
const struct input_listener_config *config = dev->config; \
\
zmk_input_listener_layer_toggle_init(config, data); \
\
return 0; \
} \
\
DEVICE_DT_INST_DEFINE(n, &zmk_input_listener_init_##n, NULL, &data_##n, &config_##n, \
POST_KERNEL, CONFIG_APPLICATION_INIT_PRIORITY, NULL);
DT_INST_FOREACH_STATUS_OKAY(IL_INST)

View file

@ -1,4 +1,5 @@
#include <behaviors.dtsi> #include <behaviors.dtsi>
#include <behaviors/mouse_keys.dtsi>
#include <dt-bindings/zmk/keys.h> #include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/kscan_mock.h> #include <dt-bindings/zmk/kscan_mock.h>
#include <dt-bindings/zmk/mouse.h> #include <dt-bindings/zmk/mouse.h>

View file

@ -0,0 +1 @@
s/.*hid_mouse_//p

View file

@ -0,0 +1,18 @@
movement_set: Mouse movement set to -1/0
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -2/-2
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -2/-2
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -3/-2
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -3/-3
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to 0/-3
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0

View file

@ -0,0 +1,39 @@
#include <behaviors.dtsi>
#include <behaviors/mouse_move.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
>;
};
};
input_configs {
compatible = "zmk,input-configs";
mmv {
device = <&mmv>;
scale-multiplier = <5>;
scale-divisor = <3>;
};
};
};
&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)
>;
};

View file

@ -0,0 +1 @@
s/.*hid_mouse_//p

View file

@ -0,0 +1,18 @@
movement_set: Mouse movement set to -1/0
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -2/-2
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -2/-2
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -3/-2
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -3/-3
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to 0/-3
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0

View file

@ -0,0 +1,39 @@
#include <behaviors.dtsi>
#include <behaviors/mouse_move.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
>;
};
};
input_configs {
compatible = "zmk,input-configs";
mmv {
device = <&mmv>;
x-invert;
y-invert;
};
};
};
&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)
>;
};

View file

@ -0,0 +1 @@
s/.*hid_mouse_//p

View file

@ -0,0 +1,18 @@
movement_set: Mouse movement set to -1/0
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -2/-2
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -2/-2
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -3/-2
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -3/-3
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to 0/-3
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0

View file

@ -0,0 +1,38 @@
#include <behaviors.dtsi>
#include <behaviors/mouse_move.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
>;
};
};
input_configs {
compatible = "zmk,input-configs";
mmv {
device = <&mmv>;
xy-swap;
};
};
};
&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)
>;
};

View file

@ -0,0 +1 @@
s/.*hid_mouse_//p

View file

@ -0,0 +1,18 @@
movement_set: Mouse movement set to -1/0
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -2/-2
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -2/-2
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -3/-2
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -3/-3
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to 0/-3
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0

View file

@ -0,0 +1,29 @@
#include <behaviors.dtsi>
#include <behaviors/mouse_move.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)
>;
};

View file

@ -0,0 +1 @@
s/.*hid_mouse_//p

View file

@ -0,0 +1,24 @@
movement_set: Mouse movement set to -1/0
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -2/0
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -2/0
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to -3/0
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to 1/0
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to 2/0
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to 2/0
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to 3/0
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0

View file

@ -0,0 +1,29 @@
#include <behaviors.dtsi>
#include <behaviors/mouse_move.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)
>;
};

View file

@ -0,0 +1 @@
s/.*hid_mouse_//p

View file

@ -0,0 +1,24 @@
movement_set: Mouse movement set to 0/-1
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to 0/-2
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to 0/-2
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to 0/-3
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to 0/1
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to 0/2
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to 0/2
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0
movement_set: Mouse movement set to 0/3
scroll_set: Mouse scroll set to 0/0
movement_set: Mouse movement set to 0/0

View file

@ -0,0 +1,29 @@
#include <behaviors.dtsi>
#include <behaviors/mouse_move.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_UP &mmv MOVE_DOWN
&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)
>;
};

View file

@ -33,7 +33,7 @@ ZMK is currently missing some features found in other popular firmware. This tab
| One Shot Keys | ✅ | ✅ | ✅ | | One Shot Keys | ✅ | ✅ | ✅ |
| [Combo Keys](features/combos.md) | ✅ | | ✅ | | [Combo Keys](features/combos.md) | ✅ | | ✅ |
| [Macros](behaviors/macros.md) | ✅ | ✅ | ✅ | | [Macros](behaviors/macros.md) | ✅ | ✅ | ✅ |
| Mouse Keys | 🚧 | ✅ | ✅ | | Mouse Keys | | ✅ | ✅ |
| Low Active Power Usage | ✅ | | | | Low Active Power Usage | ✅ | | |
| Low Power Sleep States | ✅ | ✅ | | | Low Power Sleep States | ✅ | ✅ | |
| [Low Power Mode (VCC Shutoff)](behaviors/power.md) | ✅ | ✅ | | | [Low Power Mode (VCC Shutoff)](behaviors/power.md) | ✅ | ✅ | |