[PATCH weston] evdev: Mouse speed and acceleration
Martin Minarik
minarik11 at student.fiit.stuba.sk
Fri Mar 29 13:47:55 PDT 2013
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
More information about the wayland-devel
mailing list