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

Reply via email to