Add an API to change pointer acceleration profiles
authorPeter Hutterer <peter.hutterer@who-t.net>
Thu, 27 Aug 2015 03:13:47 +0000 (13:13 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Thu, 10 Sep 2015 14:54:01 +0000 (00:54 +1000)
The quartett of new config functions is:
libinput_device_config_accel_get_profiles
libinput_device_config_accel_get_profile
libinput_device_config_accel_set_profile
libinput_device_config_accel_get_default_profile

The profile defines how the pointer acceleration works, from a very high-level
perspective. Two profiles are on offer, "adaptive", the standard one we have
used so far and "flat" which is a simple multiplier of input deltas and
provides 1:1 mapping of device movement vs pointer movement.

The speed setting is on top of the profile, a speed of 0 (default) is the
equivalent to "no pointer acceleration". This is popular among gamers and
users of switchable-dpi mice.

The flat profile unnormalizes the deltas, i.e. you get what the device does
and any device below 800dpi will feel excruciatingly slow. The speed range
[-1, 1] maps into 0-200% of the speed. At 200%, a delta of 1 is translated
into a 2 pixel movement, anything higher makes it rather pointless.

The flat profile is currently available for all pointer devices but touchpads.

https://bugs.freedesktop.org/show_bug.cgi?id=89485

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
14 files changed:
doc/pointer-acceleration.dox
src/evdev-mt-touchpad.c
src/evdev.c
src/filter-private.h
src/filter.c
src/filter.h
src/libinput-private.h
src/libinput.c
src/libinput.h
src/libinput.sym
test/pointer.c
tools/libinput-list-devices.c
tools/shared.c
tools/shared.h

index a372e1544c359ede6debf166f62b94a329c909d5..7ec5e74ddeeaf362834d3d819713f2d930e288b5 100644 (file)
@@ -9,6 +9,16 @@ This page explains the high-level concepts used in the code. It aims to
 provide an overview for developers and is not necessarily useful for
 users.
 
+@section ptraccel-profiles Pointer acceleration profiles
+
+The profile decides the general method of pointer acceleration.
+libinput currently supports two profiles: "adaptive" and "flat". The aptive
+profile is the default profile for all devices and takes the current speed
+of the device into account when deciding on acceleration. The flat profile
+is simply a constant factor applied to all device deltas, regardless of the
+speed of motion (see @ref ptraccel-profile-flat). Most of this document
+describes the adaptive pointer acceleration.
+
 @section ptraccel-velocity Velocity calculation
 
 The device's speed of movement is measured across multiple input events
@@ -107,4 +117,11 @@ The image above shows the trackpoint acceleration profile in comparison to the
 @ref ptraccel-linear. The constant acceleration factor, usually applied by
 udev, shapes the acceleration profile.
 
+@section ptraccel-profile-flat The flat pointer acceleration profile
+
+In a flat profile, the acceleration factor is constant regardless of the
+velocity of the pointer and each delta (dx, dy) results in an accelerated delta
+(dx * factor, dy * factor). This provides 1:1 movement between the device
+and the pointer on-screen.
+
 */
index aeb6c314e9e42f9a455e0dc9bac98a4621e83781..8804658de6bb505bb729c4afc249abb47449c952 100644 (file)
@@ -1518,11 +1518,38 @@ tp_init_slots(struct tp_dispatch *tp,
        return 0;
 }
 
+static uint32_t
+tp_accel_config_get_profiles(struct libinput_device *libinput_device)
+{
+       return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
+}
+
+static enum libinput_config_status
+tp_accel_config_set_profile(struct libinput_device *libinput_device,
+                           enum libinput_config_accel_profile profile)
+{
+       return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
+}
+
+static enum libinput_config_accel_profile
+tp_accel_config_get_profile(struct libinput_device *libinput_device)
+{
+       return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
+}
+
+static enum libinput_config_accel_profile
+tp_accel_config_get_default_profile(struct libinput_device *libinput_device)
+{
+       return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
+}
+
 static int
 tp_init_accel(struct tp_dispatch *tp, double diagonal)
 {
+       struct evdev_device *device = tp->device;
        int res_x, res_y;
        struct motion_filter *filter;
+       int rc;
 
        res_x = tp->device->abs.absinfo_x->resolution;
        res_y = tp->device->abs.absinfo_y->resolution;
@@ -1545,7 +1572,18 @@ tp_init_accel(struct tp_dispatch *tp, double diagonal)
        if (!filter)
                return -1;
 
-       return evdev_device_init_pointer_acceleration(tp->device, filter);
+       rc = evdev_device_init_pointer_acceleration(tp->device, filter);
+       if (rc != 0)
+               return rc;
+
+       /* we override the profile hooks for accel configuration with hooks
+        * that don't allow selection of profiles */
+       device->pointer.config.get_profiles = tp_accel_config_get_profiles;
+       device->pointer.config.set_profile = tp_accel_config_set_profile;
+       device->pointer.config.get_profile = tp_accel_config_get_profile;
+       device->pointer.config.get_default_profile = tp_accel_config_get_default_profile;
+
+       return 0;
 }
 
 static uint32_t
index 080e0a1240358cea4b3aedfda86c3c4db5dabbfb..aef0456ba15d8b764e87aa25e853b0494e95e668 100644 (file)
@@ -1385,6 +1385,27 @@ evdev_device_dispatch(void *data)
        }
 }
 
+static inline int
+evdev_init_accel(struct evdev_device *device,
+                enum libinput_config_accel_profile which)
+{
+       struct motion_filter *filter;
+
+       if (which == LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT)
+               filter = create_pointer_accelerator_filter_flat(device->dpi);
+       else if (device->tags & EVDEV_TAG_TRACKPOINT)
+               filter = create_pointer_accelerator_filter_trackpoint(device->dpi);
+       else if (device->dpi < DEFAULT_MOUSE_DPI)
+               filter = create_pointer_accelerator_filter_linear_low_dpi(device->dpi);
+       else
+               filter = create_pointer_accelerator_filter_linear(device->dpi);
+
+       if (!filter)
+               return -1;
+
+       return evdev_device_init_pointer_acceleration(device, filter);
+}
+
 static int
 evdev_accel_config_available(struct libinput_device *device)
 {
@@ -1418,20 +1439,83 @@ evdev_accel_config_get_default_speed(struct libinput_device *device)
        return 0.0;
 }
 
+static uint32_t
+evdev_accel_config_get_profiles(struct libinput_device *libinput_device)
+{
+       struct evdev_device *device = (struct evdev_device*)libinput_device;
+
+       if (!device->pointer.filter)
+               return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
+
+       return LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE |
+               LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT;
+}
+
+static enum libinput_config_status
+evdev_accel_config_set_profile(struct libinput_device *libinput_device,
+                              enum libinput_config_accel_profile profile)
+{
+       struct evdev_device *device = (struct evdev_device*)libinput_device;
+       struct motion_filter *filter;
+       double speed;
+
+       filter = device->pointer.filter;
+       if (filter_get_type(filter) == profile)
+               return LIBINPUT_CONFIG_STATUS_SUCCESS;
+
+       speed = filter_get_speed(filter);
+       device->pointer.filter = NULL;
+
+       if (evdev_init_accel(device, profile) == 0) {
+               evdev_accel_config_set_speed(libinput_device, speed);
+               filter_destroy(filter);
+       } else {
+               device->pointer.filter = filter;
+       }
+
+       return LIBINPUT_CONFIG_STATUS_SUCCESS;
+}
+
+static enum libinput_config_accel_profile
+evdev_accel_config_get_profile(struct libinput_device *libinput_device)
+{
+       struct evdev_device *device = (struct evdev_device*)libinput_device;
+
+       return filter_get_type(device->pointer.filter);
+}
+
+static enum libinput_config_accel_profile
+evdev_accel_config_get_default_profile(struct libinput_device *libinput_device)
+{
+       struct evdev_device *device = (struct evdev_device*)libinput_device;
+
+       if (!device->pointer.filter)
+               return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
+
+       /* No device has a flat profile as default */
+       return LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
+}
+
 int
 evdev_device_init_pointer_acceleration(struct evdev_device *device,
                                       struct motion_filter *filter)
 {
        device->pointer.filter = filter;
 
-       device->pointer.config.available = evdev_accel_config_available;
-       device->pointer.config.set_speed = evdev_accel_config_set_speed;
-       device->pointer.config.get_speed = evdev_accel_config_get_speed;
-       device->pointer.config.get_default_speed = evdev_accel_config_get_default_speed;
-       device->base.config.accel = &device->pointer.config;
+       if (device->base.config.accel == NULL) {
+               device->pointer.config.available = evdev_accel_config_available;
+               device->pointer.config.set_speed = evdev_accel_config_set_speed;
+               device->pointer.config.get_speed = evdev_accel_config_get_speed;
+               device->pointer.config.get_default_speed = evdev_accel_config_get_default_speed;
+               device->pointer.config.get_profiles = evdev_accel_config_get_profiles;
+               device->pointer.config.set_profile = evdev_accel_config_set_profile;
+               device->pointer.config.get_profile = evdev_accel_config_get_profile;
+               device->pointer.config.get_default_profile = evdev_accel_config_get_default_profile;
+               device->base.config.accel = &device->pointer.config;
 
-       evdev_accel_config_set_speed(&device->base,
-                    evdev_accel_config_get_default_speed(&device->base));
+               evdev_accel_config_set_speed(&device->base,
+                            evdev_accel_config_get_default_speed(&device->base));
+       }
 
        return 0;
 }
@@ -1868,24 +1952,6 @@ evdev_configure_mt_device(struct evdev_device *device)
        return 0;
 }
 
-static inline int
-evdev_init_accel(struct evdev_device *device)
-{
-       struct motion_filter *filter;
-
-       if (device->tags & EVDEV_TAG_TRACKPOINT)
-               filter = create_pointer_accelerator_filter_trackpoint(device->dpi);
-       else if (device->dpi < DEFAULT_MOUSE_DPI)
-               filter = create_pointer_accelerator_filter_linear_low_dpi(device->dpi);
-       else
-               filter = create_pointer_accelerator_filter_linear(device->dpi);
-
-       if (!filter)
-               return -1;
-
-       return evdev_device_init_pointer_acceleration(device, filter);
-}
-
 static int
 evdev_configure_device(struct evdev_device *device)
 {
@@ -1988,7 +2054,7 @@ evdev_configure_device(struct evdev_device *device)
 
                if (libevdev_has_event_code(evdev, EV_REL, REL_X) &&
                    libevdev_has_event_code(evdev, EV_REL, REL_Y) &&
-                   evdev_init_accel(device) == -1)
+                   evdev_init_accel(device, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE) == -1)
                        return -1;
 
                device->seat_caps |= EVDEV_DEVICE_POINTER;
index eaf84edad2588511731eadee51347f9365799667..637125a0b010b2c501c2c345f8670108c65c5e40 100644 (file)
@@ -29,6 +29,7 @@
 #include "filter.h"
 
 struct motion_filter_interface {
+       enum libinput_config_accel_profile type;
        struct normalized_coords (*filter)(
                           struct motion_filter *filter,
                           const struct normalized_coords *unaccelerated,
index a6468579200d99a2ee0c02ac1afb10259ae5a5e0..0d0b95d4979bf3a72fe177090ee0f34265db069f 100644 (file)
@@ -76,13 +76,14 @@ void
 filter_restart(struct motion_filter *filter,
               void *data, uint64_t time)
 {
-       filter->interface->restart(filter, data, time);
+       if (filter->interface->restart)
+               filter->interface->restart(filter, data, time);
 }
 
 void
 filter_destroy(struct motion_filter *filter)
 {
-       if (!filter)
+       if (!filter || !filter->interface->destroy)
                return;
 
        filter->interface->destroy(filter);
@@ -101,6 +102,12 @@ filter_get_speed(struct motion_filter *filter)
        return filter->speed_adjustment;
 }
 
+enum libinput_config_accel_profile
+filter_get_type(struct motion_filter *filter)
+{
+       return filter->interface->type;
+}
+
 /*
  * Default parameters for pointer acceleration profiles.
  */
@@ -149,6 +156,13 @@ struct pointer_accelerator {
        double dpi_factor;
 };
 
+struct pointer_accelerator_flat {
+       struct motion_filter base;
+
+       double factor;
+       double dpi_factor;
+};
+
 static void
 feed_trackers(struct pointer_accelerator *accel,
              const struct normalized_coords *delta,
@@ -714,6 +728,7 @@ trackpoint_accel_profile(struct motion_filter *filter,
 }
 
 struct motion_filter_interface accelerator_interface = {
+       .type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
        .filter = accelerator_filter,
        .filter_constant = accelerator_filter_noop,
        .restart = accelerator_restart,
@@ -761,6 +776,7 @@ create_pointer_accelerator_filter_linear(int dpi)
 }
 
 struct motion_filter_interface accelerator_interface_low_dpi = {
+       .type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
        .filter = accelerator_filter_low_dpi,
        .filter_constant = accelerator_filter_noop,
        .restart = accelerator_restart,
@@ -784,6 +800,7 @@ create_pointer_accelerator_filter_linear_low_dpi(int dpi)
 }
 
 struct motion_filter_interface accelerator_interface_touchpad = {
+       .type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
        .filter = accelerator_filter,
        .filter_constant = touchpad_constant_filter,
        .restart = accelerator_restart,
@@ -807,6 +824,7 @@ create_pointer_accelerator_filter_touchpad(int dpi)
 }
 
 struct motion_filter_interface accelerator_interface_x230 = {
+       .type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
        .filter = accelerator_filter_x230,
        .filter_constant = accelerator_filter_constant_x230,
        .restart = accelerator_restart,
@@ -845,6 +863,7 @@ create_pointer_accelerator_filter_lenovo_x230(int dpi)
 }
 
 struct motion_filter_interface accelerator_interface_trackpoint = {
+       .type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
        .filter = accelerator_filter_trackpoint,
        .filter_constant = accelerator_filter_noop,
        .restart = accelerator_restart,
@@ -869,3 +888,79 @@ create_pointer_accelerator_filter_trackpoint(int dpi)
 
        return &filter->base;
 }
+
+static struct normalized_coords
+accelerator_filter_flat(struct motion_filter *filter,
+                       const struct normalized_coords *unaccelerated,
+                       void *data, uint64_t time)
+{
+       struct pointer_accelerator_flat *accel_filter =
+               (struct pointer_accelerator_flat *)filter;
+       double factor; /* unitless factor */
+       struct normalized_coords accelerated;
+       struct normalized_coords unnormalized;
+
+       /* You want flat acceleration, you get flat acceleration for the
+        * device */
+       unnormalized.x = unaccelerated->x * accel_filter->dpi_factor;
+       unnormalized.y = unaccelerated->y * accel_filter->dpi_factor;
+       factor = accel_filter->factor;
+
+       accelerated.x = factor * unnormalized.x;
+       accelerated.y = factor * unnormalized.y;
+
+       return accelerated;
+}
+
+static bool
+accelerator_set_speed_flat(struct motion_filter *filter,
+                          double speed_adjustment)
+{
+       struct pointer_accelerator_flat *accel_filter =
+               (struct pointer_accelerator_flat *)filter;
+
+       assert(speed_adjustment >= -1.0 && speed_adjustment <= 1.0);
+
+       /* Speed rage is 0-200% of the nominal speed, with 0 mapping to the
+        * nominal speed. Anything above 200 is pointless, we're already
+        * skipping over ever second pixel at 200% speed.
+        */
+
+       accel_filter->factor = 1 + speed_adjustment;
+       filter->speed_adjustment = speed_adjustment;
+
+       return true;
+}
+
+static void
+accelerator_destroy_flat(struct motion_filter *filter)
+{
+       struct pointer_accelerator_flat *accel =
+               (struct pointer_accelerator_flat *) filter;
+
+       free(accel);
+}
+
+struct motion_filter_interface accelerator_interface_flat = {
+       .type = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT,
+       .filter = accelerator_filter_flat,
+       .filter_constant = accelerator_filter_noop,
+       .restart = NULL,
+       .destroy = accelerator_destroy_flat,
+       .set_speed = accelerator_set_speed_flat,
+};
+
+struct motion_filter *
+create_pointer_accelerator_filter_flat(int dpi)
+{
+       struct pointer_accelerator_flat *filter;
+
+       filter = zalloc(sizeof *filter);
+       if (filter == NULL)
+               return NULL;
+
+       filter->base.interface = &accelerator_interface_flat;
+       filter->dpi_factor = dpi/(double)DEFAULT_MOUSE_DPI;
+
+       return &filter->base;
+}
index c8ade07d6c51aaafe350a9264a06aa24379a43ae..e156642983a8fed9d4cea147a6bf1e5c208a1286 100644 (file)
@@ -74,12 +74,17 @@ filter_set_speed(struct motion_filter *filter,
 double
 filter_get_speed(struct motion_filter *filter);
 
+enum libinput_config_accel_profile
+filter_get_type(struct motion_filter *filter);
+
 typedef double (*accel_profile_func_t)(struct motion_filter *filter,
                                       void *data,
                                       double velocity,
                                       uint64_t time);
 
 /* Pointer acceleration types */
+struct motion_filter *
+create_pointer_accelerator_filter_flat(int dpi);
 
 struct motion_filter *
 create_pointer_accelerator_filter_linear(int dpi);
index be99af5e735771a61280c9da5592ae5d6b85e12f..e146c260d9abdb6a83003006c470b94b6e4a6eb3 100644 (file)
@@ -150,6 +150,12 @@ struct libinput_device_config_accel {
                                                 double speed);
        double (*get_speed)(struct libinput_device *device);
        double (*get_default_speed)(struct libinput_device *device);
+
+       uint32_t (*get_profiles)(struct libinput_device *device);
+       enum libinput_config_status (*set_profile)(struct libinput_device *device,
+                                                  enum libinput_config_accel_profile);
+       enum libinput_config_accel_profile (*get_profile)(struct libinput_device *device);
+       enum libinput_config_accel_profile (*get_default_profile)(struct libinput_device *device);
 };
 
 struct libinput_device_config_natural_scroll {
index b88bab11f00210311d58757173785faaafe323d2..f5c75b080185cff2fba6998931b50e01aa7dec0e 100644 (file)
@@ -2245,7 +2245,6 @@ libinput_device_config_accel_set_speed(struct libinput_device *device,
 
        return device->config.accel->set_speed(device, speed);
 }
-
 LIBINPUT_EXPORT double
 libinput_device_config_accel_get_speed(struct libinput_device *device)
 {
@@ -2264,6 +2263,52 @@ libinput_device_config_accel_get_default_speed(struct libinput_device *device)
        return device->config.accel->get_default_speed(device);
 }
 
+LIBINPUT_EXPORT uint32_t
+libinput_device_config_accel_get_profiles(struct libinput_device *device)
+{
+       if (!libinput_device_config_accel_is_available(device))
+               return 0;
+
+       return device->config.accel->get_profiles(device);
+}
+
+LIBINPUT_EXPORT enum libinput_config_accel_profile
+libinput_device_config_accel_get_profile(struct libinput_device *device)
+{
+       if (!libinput_device_config_accel_is_available(device))
+               return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
+
+       return device->config.accel->get_profile(device);
+}
+
+LIBINPUT_EXPORT enum libinput_config_accel_profile
+libinput_device_config_accel_get_default_profile(struct libinput_device *device)
+{
+       if (!libinput_device_config_accel_is_available(device))
+               return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
+
+       return device->config.accel->get_profile(device);
+}
+
+LIBINPUT_EXPORT enum libinput_config_status
+libinput_device_config_accel_set_profile(struct libinput_device *device,
+                                        enum libinput_config_accel_profile profile)
+{
+       switch (profile) {
+       case LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT:
+       case LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE:
+               break;
+       default:
+               return LIBINPUT_CONFIG_STATUS_INVALID;
+       }
+
+       if (!libinput_device_config_accel_is_available(device) ||
+           (libinput_device_config_accel_get_profiles(device) & profile) == 0)
+               return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
+
+       return device->config.accel->set_profile(device, profile);
+}
+
 LIBINPUT_EXPORT int
 libinput_device_config_scroll_has_natural_scroll(struct libinput_device *device)
 {
index 898d26ef04d0ea141a64eab07f0151513e2d7744..9057446325ce40947f02dd59f8dfa27f07511f3c 100644 (file)
@@ -2549,6 +2549,80 @@ libinput_device_config_accel_get_speed(struct libinput_device *device);
 double
 libinput_device_config_accel_get_default_speed(struct libinput_device *device);
 
+enum libinput_config_accel_profile {
+       /**
+        * Placeholder for devices that don't have a configurable pointer
+        * acceleration profile.
+        */
+       LIBINPUT_CONFIG_ACCEL_PROFILE_NONE = 0,
+       /**
+        * A flat acceleration profile. Pointer motion is accelerated by a
+        * constant (device-specific) factor, depending on the current
+        * speed.
+        *
+        * @see libinput_device_config_accel_set_speed
+        */
+       LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT = (1 << 0),
+
+       /**
+        * An adaptive acceleration profile. Pointer acceleration depends
+        * on the input speed. This is the default profile for most devices.
+        */
+       LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE = (1 << 1),
+};
+
+/**
+ * @ingroup config
+ *
+ * Returns a bitmask of the configurable acceleration modes available on
+ * this device.
+ *
+ * @param device The device to configure
+ *
+ * @return A bitmask of all configurable modes availble on this device.
+ */
+uint32_t
+libinput_device_config_accel_get_profiles(struct libinput_device *device);
+
+/**
+ * @ingroup config
+ *
+ * Set the pointer acceleration profile of this pointer device to the given
+ * mode.
+ *
+ * @param device The device to configure
+ * @param mode The mode to set the device to.
+ *
+ * @return A config status code
+ */
+enum libinput_config_status
+libinput_device_config_accel_set_profile(struct libinput_device *device,
+                                        enum libinput_config_accel_profile mode);
+
+/**
+ * @ingroup config
+ *
+ * Get the current pointer acceleration profile for this pointer device.
+ *
+ * @param device The device to configure
+ *
+ * @return The currently configured pointer acceleration profile.
+ */
+enum libinput_config_accel_profile
+libinput_device_config_accel_get_profile(struct libinput_device *device);
+
+/**
+ * @ingroup config
+ *
+ * Return the default pointer acceleration profile for this pointer device.
+ *
+ * @param device The device to configure
+ *
+ * @return The default acceleration profile for this device.
+ */
+enum libinput_config_accel_profile
+libinput_device_config_accel_get_default_profile(struct libinput_device *device);
+
 /**
  * @ingroup config
  *
index 7e0ef1c58739bbcc9078279ef6182e14f51dc36a..15203c8d52a717369b71d2f14e6af596a7c9eb00 100644 (file)
@@ -172,3 +172,10 @@ LIBINPUT_0.21.0 {
        libinput_event_pointer_get_time_usec;
        libinput_event_touch_get_time_usec;
 } LIBINPUT_0.20.0;
+
+LIBINPUT_1.1 {
+       libinput_device_config_accel_get_profile;
+       libinput_device_config_accel_get_profiles;
+       libinput_device_config_accel_get_default_profile;
+       libinput_device_config_accel_set_profile;
+} LIBINPUT_0.21.0;
index f711d385662f1c25d203b192997f6822e6eee414..e12034a045b065fda74d73fb39d49b5d69791d7d 100644 (file)
@@ -1029,6 +1029,116 @@ START_TEST(pointer_accel_direction_change)
 }
 END_TEST
 
+START_TEST(pointer_accel_profile_defaults)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput_device *device = dev->libinput_device;
+       enum libinput_config_status status;
+       enum libinput_config_accel_profile profile;
+       uint32_t profiles;
+
+       ck_assert(libinput_device_config_accel_is_available(device));
+
+       profile = libinput_device_config_accel_get_default_profile(device);
+       ck_assert_int_eq(profile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE);
+
+       profile = libinput_device_config_accel_get_profile(device);
+       ck_assert_int_eq(profile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE);
+
+       profiles = libinput_device_config_accel_get_profiles(device);
+       ck_assert(profiles & LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE);
+       ck_assert(profiles & LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT);
+
+       status = libinput_device_config_accel_set_profile(device,
+                                                         LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT);
+       ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+       profile = libinput_device_config_accel_get_profile(device);
+       ck_assert_int_eq(profile, LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT);
+
+       status = libinput_device_config_accel_set_profile(device,
+                                                         LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE);
+       ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+       profile = libinput_device_config_accel_get_profile(device);
+       ck_assert_int_eq(profile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE);
+}
+END_TEST
+
+START_TEST(pointer_accel_profile_defaults_noprofile)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput_device *device = dev->libinput_device;
+       enum libinput_config_status status;
+       enum libinput_config_accel_profile profile;
+       uint32_t profiles;
+
+       ck_assert(libinput_device_config_accel_is_available(device));
+
+       profile = libinput_device_config_accel_get_default_profile(device);
+       ck_assert_int_eq(profile, LIBINPUT_CONFIG_ACCEL_PROFILE_NONE);
+
+       profile = libinput_device_config_accel_get_profile(device);
+       ck_assert_int_eq(profile, LIBINPUT_CONFIG_ACCEL_PROFILE_NONE);
+
+       profiles = libinput_device_config_accel_get_profiles(device);
+       ck_assert_int_eq(profiles, LIBINPUT_CONFIG_ACCEL_PROFILE_NONE);
+
+       status = libinput_device_config_accel_set_profile(device,
+                                                         LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT);
+       ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
+       profile = libinput_device_config_accel_get_profile(device);
+       ck_assert_int_eq(profile, LIBINPUT_CONFIG_ACCEL_PROFILE_NONE);
+
+       status = libinput_device_config_accel_set_profile(device,
+                                                         LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE);
+       ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
+       profile = libinput_device_config_accel_get_profile(device);
+       ck_assert_int_eq(profile, LIBINPUT_CONFIG_ACCEL_PROFILE_NONE);
+}
+END_TEST
+
+START_TEST(pointer_accel_profile_invalid)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput_device *device = dev->libinput_device;
+       enum libinput_config_status status;
+
+       ck_assert(libinput_device_config_accel_is_available(device));
+
+       status = libinput_device_config_accel_set_profile(device,
+                                          LIBINPUT_CONFIG_ACCEL_PROFILE_NONE);
+       ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID);
+
+       status = libinput_device_config_accel_set_profile(device,
+                                          LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE + 1);
+       ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID);
+
+       status = libinput_device_config_accel_set_profile(device,
+                          LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE |LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT);
+       ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID);
+}
+END_TEST
+
+START_TEST(pointer_accel_profile_flat_motion_relative)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput_device *device = dev->libinput_device;
+
+       libinput_device_config_accel_set_profile(device,
+                                                LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT);
+       litest_drain_events(dev->libinput);
+
+       test_relative_event(dev, 1, 0);
+       test_relative_event(dev, 1, 1);
+       test_relative_event(dev, 1, -1);
+       test_relative_event(dev, 0, 1);
+
+       test_relative_event(dev, -1, 0);
+       test_relative_event(dev, -1, 1);
+       test_relative_event(dev, -1, -1);
+       test_relative_event(dev, 0, -1);
+}
+END_TEST
+
 START_TEST(middlebutton)
 {
        struct litest_device *device = litest_current_device();
@@ -1479,6 +1589,10 @@ litest_setup_tests(void)
        litest_add("pointer:accel", pointer_accel_defaults_absolute, LITEST_ABSOLUTE, LITEST_RELATIVE);
        litest_add("pointer:accel", pointer_accel_defaults_absolute_relative, LITEST_ABSOLUTE|LITEST_RELATIVE, LITEST_ANY);
        litest_add("pointer:accel", pointer_accel_direction_change, LITEST_RELATIVE, LITEST_ANY);
+       litest_add("pointer:accel", pointer_accel_profile_defaults, LITEST_RELATIVE, LITEST_TOUCHPAD);
+       litest_add("pointer:accel", pointer_accel_profile_defaults_noprofile, LITEST_TOUCHPAD, LITEST_ANY);
+       litest_add("pointer:accel", pointer_accel_profile_invalid, LITEST_RELATIVE, LITEST_ANY);
+       litest_add("pointer:accel", pointer_accel_profile_flat_motion_relative, LITEST_RELATIVE, LITEST_TOUCHPAD);
 
        litest_add("pointer:middlebutton", middlebutton, LITEST_BUTTON, LITEST_ANY);
        litest_add("pointer:middlebutton", middlebutton_timeout, LITEST_BUTTON, LITEST_ANY);
index c156bf0babc67b9f50668280b5a496804630f5c0..21685d9bed01b1dd3f3a0b8facf693ab630ead59 100644 (file)
@@ -172,6 +172,35 @@ click_defaults(struct libinput_device *device)
        return str;
 }
 
+static char*
+accel_profiles(struct libinput_device *device)
+{
+       uint32_t profiles;
+       char *str;
+       enum libinput_config_accel_profile profile;
+
+       if (!libinput_device_config_accel_is_available(device)) {
+               xasprintf(&str, "n/a");
+               return str;
+       }
+
+       profiles = libinput_device_config_accel_get_profiles(device);
+       if (profiles == LIBINPUT_CONFIG_ACCEL_PROFILE_NONE) {
+               xasprintf(&str, "none");
+               return str;
+       }
+
+       profile = libinput_device_config_accel_get_default_profile(device);
+       xasprintf(&str,
+                 "%s%s%s%s",
+                 (profile == LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT) ? "*" : "",
+                 (profiles & LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT) ? "flat" : "",
+                 (profile == LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE) ? "*" : "",
+                 (profiles & LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE) ? "adaptive" : "");
+
+       return str;
+}
+
 static const char *
 dwt_default(struct libinput_device *device)
 {
@@ -249,6 +278,10 @@ print_device_notify(struct libinput_event *ev)
 
        printf("Disable-w-typing: %s\n", dwt_default(dev));
 
+       str = accel_profiles(dev);
+       printf("Accel profiles:   %s\n", str);
+       free(str);
+
        printf("\n");
 }
 
index 9dba955e1c31b64d00ad83a9dce6670c0808c54a..5fe5862c61a9377f99f5c4ddc841d9e9ebeb32a6 100644 (file)
@@ -59,6 +59,7 @@ enum options {
        OPT_SCROLL_METHOD,
        OPT_SCROLL_BUTTON,
        OPT_SPEED,
+       OPT_PROFILE,
 };
 
 static void
@@ -94,6 +95,7 @@ tools_usage()
               "--set-click-method=[none|clickfinger|buttonareas] .... set the desired click method\n"
               "--set-scroll-method=[none|twofinger|edge|button] ... set the desired scroll method\n"
               "--set-scroll-button=BTN_MIDDLE ... set the button to the given button code\n"
+              "--set-profile=[adaptive|flat].... set pointer acceleration profile\n"
               "--set-speed=<value>.... set pointer acceleration speed\n"
               "\n"
               "These options apply to all applicable devices, if a feature\n"
@@ -126,6 +128,7 @@ tools_init_context(struct tools_context *context)
        options->backend = BACKEND_UDEV;
        options->seat = "seat0";
        options->speed = 0.0;
+       options->profile = LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
 }
 
 int
@@ -157,6 +160,7 @@ tools_parse_args(int argc, char **argv, struct tools_context *context)
                        { "set-click-method", 1, 0, OPT_CLICK_METHOD },
                        { "set-scroll-method", 1, 0, OPT_SCROLL_METHOD },
                        { "set-scroll-button", 1, 0, OPT_SCROLL_BUTTON },
+                       { "set-profile", 1, 0, OPT_PROFILE },
                        { "speed", 1, 0, OPT_SPEED },
                        { 0, 0, 0, 0}
                };
@@ -288,6 +292,20 @@ tools_parse_args(int argc, char **argv, struct tools_context *context)
                        }
                        options->speed = atof(optarg);
                        break;
+               case OPT_PROFILE:
+                       if (!optarg) {
+                               tools_usage();
+                               return 1;
+                       }
+                       if (streq(optarg, "adaptive")) {
+                               options->profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
+                       } else if (streq(optarg, "flat")) {
+                               options->profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT;
+                       } else {
+                               tools_usage();
+                               return 1;
+                       }
+                       break;
                default:
                        tools_usage();
                        return 1;
@@ -445,7 +463,11 @@ tools_device_apply_config(struct libinput_device *device,
                libinput_device_config_scroll_set_button(device,
                                                         options->scroll_button);
 
-       if (libinput_device_config_accel_is_available(device))
+       if (libinput_device_config_accel_is_available(device)) {
                libinput_device_config_accel_set_speed(device,
                                                       options->speed);
+               if (options->profile != LIBINPUT_CONFIG_ACCEL_PROFILE_NONE)
+                       libinput_device_config_accel_set_profile(device,
+                                                                options->profile);
+       }
 }
index a9cf6d96c6ce7fe9095de9aa5f7f51f27a02d437..0065fcc033b44b55ccc9e5414b201247c197463d 100644 (file)
@@ -48,6 +48,7 @@ struct tools_options {
        int scroll_button;
        double speed;
        int dwt;
+       enum libinput_config_accel_profile profile;
 };
 
 struct tools_context {