[PATCH weston] evdev: Mouse speed and acceleration
Daniel Stone
daniel at fooishbar.org
Tue Apr 2 21:17:21 PDT 2013
Hi Martin,
By and large this looks good to me, although the main comment I have
is that this should probably be using the acceleration mechanism in
src/filter.c.
Cheers,
Daniel
On 29 March 2013 20:47, Martin Minarik <minarik11 at student.fiit.stuba.sk> wrote:
> 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 at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
More information about the wayland-devel
mailing list