Acceleration: After examining, I don't like the X acceleration approach. X employs a so called velocity approximation (?) algorithm. It is quite a complex way to get an approximation of a simple thing, the velocity, when we can compute the velocity directly.
Configuring: Please, tune the values in mouse_init(). The tune speed coefficient is simply a multiplier of how fast the mouse moves. The 1.0 is the real (raw) device speed. These tune speed coefficients feel very natural to use: 0.03125 0.0625 0.25 0.5 0.75 1.0 1.5 2.0 2.5 3.0 3.5 The acceleration boost factor (at 1.0 speed coefficient): 0.01 - NO effect 0.02 - small effect 0.06 - medium effect 0.10 - pretty strong 0.13 - TOO strong This patch does not introduce smoothing. --- src/Makefile.am | 4 + src/evdev-mouse.c | 240 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/evdev.c | 3 + src/evdev.h | 3 + 4 files changed, 250 insertions(+) create mode 100644 src/evdev-mouse.c diff --git a/src/Makefile.am b/src/Makefile.am index d56daa0..2c8b3eb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -138,6 +138,7 @@ drm_backend_la_SOURCES = \ udev-seat.h \ evdev.c \ evdev.h \ + evdev-mouse.c \ evdev-touchpad.c \ launcher-util.c \ launcher-util.h \ @@ -177,7 +178,9 @@ rpi_backend_la_SOURCES = \ tty.c \ evdev.c \ evdev.h \ + evdev-mouse.c \ evdev-touchpad.c + endif if ENABLE_HEADLESS_COMPOSITOR @@ -211,6 +214,7 @@ fbdev_backend_la_SOURCES = \ evdev.c \ evdev.h \ evdev-touchpad.c \ + evdev-mouse.c \ launcher-util.c endif diff --git a/src/evdev-mouse.c b/src/evdev-mouse.c new file mode 100644 index 0000000..b4915cd --- /dev/null +++ b/src/evdev-mouse.c @@ -0,0 +1,240 @@ +#include <stdlib.h> +#include <stdbool.h> + +#include "compositor.h" +#include "evdev.h" + +#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int(10) +#define MOUSE_VELOCITY_SAMPLING_INTERVAL 20 + +struct mouse_motion { + int32_t dx; + int32_t dy; +}; + +struct mouse_dispatch { + struct evdev_dispatch base; + struct evdev_device *device; + + double actual_speed; + + struct mouse_motion motion_sample; + uint32_t motion_time_next_sample; + uint32_t motion_time_out; + unsigned long int last_velocity_sq; + + /* tuneable */ + bool tune_is_acceleration; + double tune_acceleration_boost; + double tune_speed_coefficient; +}; + +static inline void +mouse_process_relative(struct mouse_dispatch *mouse, + struct evdev_device *device, + struct input_event *event, uint32_t time) +{ + switch (event->code) { + case REL_X: + if (mouse->tune_is_acceleration) + mouse->motion_sample.dx += event->value; + device->rel.dx += wl_fixed_from_double( + (double) event->value * mouse->actual_speed); + + device->pending_events |= EVDEV_RELATIVE_MOTION; + break; + case REL_Y: + if (mouse->tune_is_acceleration) + mouse->motion_sample.dy += event->value; + device->rel.dy += wl_fixed_from_double( + (double) event->value * mouse->actual_speed); + + device->pending_events |= EVDEV_RELATIVE_MOTION; + break; + case REL_WHEEL: + switch (event->value) { + case -1: + /* Scroll down */ + case 1: + /* Scroll up */ + notify_axis(device->seat, + time, + WL_POINTER_AXIS_VERTICAL_SCROLL, + -1 * event->value * DEFAULT_AXIS_STEP_DISTANCE); + break; + default: + break; + } + break; + case REL_HWHEEL: + switch (event->value) { + case -1: + /* Scroll left */ + case 1: + /* Scroll right */ + notify_axis(device->seat, + time, + WL_POINTER_AXIS_HORIZONTAL_SCROLL, + event->value * DEFAULT_AXIS_STEP_DISTANCE); + break; + default: + break; + + } + } +} + +static inline void +mouse_process_key(struct mouse_dispatch *mouse, + struct evdev_device *device, + struct input_event *e, + uint32_t time) +{ + if (e->value == 2) + return; + + switch (e->code) { + case BTN_LEFT: + case BTN_RIGHT: + case BTN_MIDDLE: + case BTN_SIDE: + case BTN_EXTRA: + case BTN_FORWARD: + case BTN_BACK: + case BTN_TASK: + notify_button(device->seat, + time, e->code, + e->value ? WL_POINTER_BUTTON_STATE_PRESSED : + WL_POINTER_BUTTON_STATE_RELEASED); + break; + + default: + notify_key(device->seat, + time, e->code, + e->value ? WL_KEYBOARD_KEY_STATE_PRESSED : + WL_KEYBOARD_KEY_STATE_RELEASED, + STATE_UPDATE_AUTOMATIC); + break; + } +} + +static void +mouse_reset_acceleration(struct mouse_dispatch *mouse, uint32_t time) +{ + struct mouse_motion *m = &mouse->motion_sample; + unsigned const int interval = MOUSE_VELOCITY_SAMPLING_INTERVAL; + + mouse->last_velocity_sq = 0; + mouse->actual_speed = mouse->tune_speed_coefficient; + mouse->motion_time_out = 2 * interval + time; + mouse->motion_time_next_sample = interval + time; + + m->dx = 0; + m->dy = 0; +} + +static void +mouse_recompute_acceleration(struct mouse_dispatch *mouse, uint32_t time) +{ + struct mouse_motion *m = &mouse->motion_sample; + unsigned const int interval = MOUSE_VELOCITY_SAMPLING_INTERVAL; + + unsigned long int velocity_sq; + const double no_decceleration = 1.0; + double acceleration; + + velocity_sq = m->dx * m->dx + m->dy * m->dy; + + if (velocity_sq > mouse->last_velocity_sq) + acceleration = pow(velocity_sq - mouse->last_velocity_sq, + mouse->tune_acceleration_boost); + else + acceleration = no_decceleration; + + mouse->last_velocity_sq = velocity_sq; + mouse->actual_speed = mouse->tune_speed_coefficient * acceleration; + mouse->motion_time_out += interval; + mouse->motion_time_next_sample += interval; + + m->dx = 0; + m->dy = 0; +} + +static void +mouse_process(struct evdev_dispatch *dispatch, + struct evdev_device *device, + struct input_event *event, + uint32_t time) +{ + struct mouse_dispatch *mouse = + (struct mouse_dispatch *) dispatch; + + switch (event->type) { + case EV_REL: + mouse_process_relative(mouse, device, event, time); + break; + case EV_KEY: + mouse_process_key(mouse, device, event, time); + break; + case EV_SYN: + device->pending_events |= EVDEV_SYN; + + if ((mouse->tune_is_acceleration) && + (time > mouse->motion_time_next_sample)) { + if (time > mouse->motion_time_out) + mouse_reset_acceleration(mouse, time); + else + mouse_recompute_acceleration(mouse, time); + } + break; + } +} + +static void +mouse_destroy(struct evdev_dispatch *dispatch) +{ + struct mouse_dispatch *mouse = + (struct mouse_dispatch *) dispatch; + + free(mouse); +} + +struct evdev_dispatch_interface mouse_interface = { + mouse_process, + mouse_destroy +}; + +static int +mouse_init(struct mouse_dispatch *mouse, + struct evdev_device *device) +{ + mouse->base.interface = &mouse_interface; + mouse->device = device; + + /* Configure mouse velocity, acceleration */ + mouse->tune_is_acceleration = true; + mouse->tune_acceleration_boost = 0.03; + mouse->tune_speed_coefficient = 2.00; + + /* Prepare velocity tracking */ + mouse_reset_acceleration(mouse, 0); + + return 0; +} + +struct evdev_dispatch * +evdev_mouse_create(struct evdev_device *device) +{ + struct mouse_dispatch *mouse; + + mouse = malloc(sizeof *mouse); + if (mouse == NULL) + return NULL; + + if (mouse_init(mouse, device) != 0) { + free(mouse); + return NULL; + } + + return &mouse->base; +} diff --git a/src/evdev.c b/src/evdev.c index d2954b5..bbad5ad 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -459,6 +459,9 @@ evdev_handle_device(struct evdev_device *device) !TEST_BIT(key_bits, BTN_TOOL_PEN) && has_abs) device->dispatch = evdev_touchpad_create(device); + else if (TEST_BIT(key_bits, BTN_LEFT) && !has_abs) + device->dispatch = evdev_mouse_create(device); + for (i = KEY_ESC; i < KEY_MAX; i++) { if (i >= BTN_MISC && i < KEY_OK) continue; diff --git a/src/evdev.h b/src/evdev.h index eb5c868..f670682 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -111,6 +111,9 @@ struct evdev_dispatch { struct evdev_dispatch * evdev_touchpad_create(struct evdev_device *device); +struct evdev_dispatch * +evdev_mouse_create(struct evdev_device *device); + void evdev_led_update(struct evdev_device *device, enum weston_led leds); -- 1.7.10.4 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel