Re: [PATCH libinput 01/10] Replace pointer acceleration with a much simpler linear one
On Fri, Sep 19, 2014 at 10:09:58AM +0100, Steven Newbury wrote: On Fri, 2014-09-19 at 15:44 +1000, Peter Hutterer wrote: We ran a userstudy, evaluating three different accel methods. Detailed results are available at: http://www.who-t.net/publications/hutterer2014_libinput_ptraccel_study.pdf We found that there was little difference between the method we had in libinput 0.6 and this three-line function. Users didn't really notice a difference, but measured data suggests that it has slight advantages in some use-cases. The method proposed here is the one labeled linear in the paper, its profile looks roughly like this: _ / / / / where the x axis is the speed, y is the acceleration factor. The first plateau is at the acceleration factor 1 (i.e. unaccelerated movement), the second plateau is at the max acceleration factor. The threshold in the code defines where and how long the plateau is. Differences to the previous accel function: - both inclines are linear rather than curved - the second incline is less steep than the current method From a maintainer's point-of-view, this function is significantly easier to understand and manipulate than the previous one. Hi Peter, I'm going to read the report, but I would like to just state my initial feeling on this. Right now, in my experience*, the pointer acceleration in libinput/weston is inferior** to that currently in Xorg. I find it relatively difficult to accurately position the pointer in Weston while at the same time being able to comfortably move the pointer over larger distances in a predictable manner. The Xorg code has been very well tuned over the last few years and IMHO is at least as good as the Windows implementation (from a user point of view). The X server code has a bug where the size of the output screen influences the acceleration on certain devices, touchpad devices included. Plug a second monitor in and you'll see the touchpad speed go up. I've tried to fix this a number of times, but stuff is so convoluted that I need to find a spare week or two to fix this across synaptics and the server and update both in lockstep. I'd have to check the git logs too, but afaict the pointer accel code hasn't seen any real updates since when it was introduced, with the exception of some general cleanups and dropping of configurable schemes. So well tuned is stretching the term, it just happens to work and you've had up to ~6 years of exposure to it. This is of course not discrediting your experience, just remember that there is a learning curve associate with pointer acceleration and you need some time to get used to how things work before they become muscle memory. Any comparison between the libinput/weston implementations needs to be base-lined against current Xorg and Windows/OSX! I'm certainly not opposed to improvements! how? That's the main problem I had trying to analyse. the study I ran has a couple of flaws in its design and mostly the small data set but one of the abilities libinput provides us is comparable data from multiple runs. That is almost impossible with X (see the screen size issue for example), on top of the difficulty of getting this data out of X in the first place. Comparing to Windows/OS X is even more difficult since we can't even assume the same events as baseline. I've looked at the windows and OS X acceleration curves (see the Casiez et al. paper I referenced in the study writeup for graphs of how they work) and tested them locally but did not see a significant improvement. If anything an OS X-like curve made it even harder to use for some reason (note: subjective!). Note that I'm not against further improvements down the road. I still think that touchpads and mice need different accel curves (the linear one here is not as easy to use on a touchpad as on my mouse here) but I don't have the data to be sure. I could run the study again, modified a bit but right now there are more pressing issues. The code is online however so if you want to take it and continue with it I'm happy to help (or if you just find general bugs that invalidate some of the results, though I guess my help won't be as happy then ;) There's also an argument that the delta smoothening that we do before applying the accel curve may not be necessary. That needs separate evaluation though and the day has only so many hours. Maybe my concerns are unfounded, I'll have a read of the report now... :-) * Using a Synaptics touchpad ** For all I know it's the same code (haven't checked) but the parameters must be different or there's a bug somewhere. It should be mostly the same code (for relative devices anyway), but I'd need to do a full audit to verify. Cheers, Peter ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org
[PATCH v2 libinput 05.5/10] touchpad: use the evdev device's filter struct
We don't need a separate filter struct, we can use the parent evdev device. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- Changes to v1: - didn't exist in the first set of patches, slots in after 05/10 - prep work for having the same code for pointer accel functions src/evdev-mt-touchpad.c | 5 ++--- src/evdev-mt-touchpad.h | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 0b51809..79f5357 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -65,7 +65,7 @@ tp_filter_motion(struct tp_dispatch *tp, motion.dy = *dy * tp-accel.y_scale_coeff; if (motion.dx != 0.0 || motion.dy != 0.0) - filter_dispatch(tp-filter, motion, tp, time); + filter_dispatch(tp-device-pointer.filter, motion, tp, time); *dx = motion.dx; *dy = motion.dy; @@ -602,7 +602,6 @@ tp_destroy(struct evdev_dispatch *dispatch) tp_destroy_tap(tp); tp_destroy_buttons(tp); - filter_destroy(tp-filter); free(tp-touches); free(tp); } @@ -845,7 +844,7 @@ tp_init_accel(struct tp_dispatch *tp, double diagonal) if (accel == NULL) return -1; - tp-filter = accel; + tp-device-pointer.filter = accel; return 0; } diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 3d3932b..73d0c91 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -167,8 +167,6 @@ struct tp_dispatch { int32_t margin_y; } hysteresis; - struct motion_filter *filter; - struct { double x_scale_coeff; double y_scale_coeff; -- 1.9.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH v2 libinput 08/10] touchpad: hook up pointer acceleration configuration
Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- Changes to v1: - don't duplicate the accel config code, just re-use it for touchpad src/evdev-mt-touchpad.c | 7 +-- src/evdev.c | 6 +++--- src/evdev.h | 3 +++ 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 79f5357..167cea9 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -802,7 +802,6 @@ tp_init_slots(struct tp_dispatch *tp, static int tp_init_accel(struct tp_dispatch *tp, double diagonal) { - struct motion_filter *accel; int res_x, res_y; if (tp-has_mt) { @@ -839,13 +838,9 @@ tp_init_accel(struct tp_dispatch *tp, double diagonal) tp-accel.y_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal; } - accel = create_pointer_accelator_filter( - pointer_accel_profile_linear); - if (accel == NULL) + if (evdev_device_init_pointer_acceleration(tp-device) == -1) return -1; - tp-device-pointer.filter = accel; - return 0; } diff --git a/src/evdev.c b/src/evdev.c index a5a8372..4c0669c 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -893,8 +893,8 @@ evdev_accel_config_get_default_speed(struct libinput_device *device) return 0.0; } -static int -configure_pointer_acceleration(struct evdev_device *device) +int +evdev_device_init_pointer_acceleration(struct evdev_device *device) { device-pointer.filter = create_pointer_accelator_filter( @@ -1090,7 +1090,7 @@ evdev_configure_device(struct evdev_device *device) has_keyboard = 1; if ((has_abs || has_rel) has_button) { - if (configure_pointer_acceleration(device) == -1) + if (evdev_device_init_pointer_acceleration(device) == -1) return -1; device-seat_caps |= EVDEV_DEVICE_POINTER; diff --git a/src/evdev.h b/src/evdev.h index 301903a..23615f9 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -177,6 +177,9 @@ evdev_device_create(struct libinput_seat *seat, const char *sysname, const char *syspath); +int +evdev_device_init_pointer_acceleration(struct evdev_device *device); + struct evdev_dispatch * evdev_touchpad_create(struct evdev_device *device); -- 1.9.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH v2 libinput 05/10] filter: adjust acceleration curve depending on speed
The acceleration curve consists of four parts, in ascii-art like this: _ / / / / where the x axis is the speed, y is the acceleration factor. The first plateau is at the acceleration factor 1 (i.e. unaccelerated movement), the second plateau is at the max acceleration factor. The threshold in the code defines where and how long the plateau is. This patch adjusts the curve based on a [-1, 1] range. For anything below 0, the plateau is longer (i.e. accel kicks in at a higher speed), the second incline is flatter (i.e. accel kicks in slower) and the max accel factor is lower (i.e. maximum speed is slower). For anything above 0, the inverse is true, acceleration kicks in earlier, harder and is faster in general. So the default/min/max curves overlaid look something like this: max | ___ default | / _ min _|_/_/ / / Note that there's a limit to what ascii art can do... Note that there are additional tweaks we can introduce later, such as decreaseing the unaccelerated speed of the device (i.e. lowering the first plateau). Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- Changes to v1: - change accel adjustments to use the defaults at speed 0 src/filter.c | 19 +-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/filter.c b/src/filter.c index 327dbce..defbcae 100644 --- a/src/filter.c +++ b/src/filter.c @@ -69,6 +69,7 @@ filter_get_speed(struct motion_filter *filter) #define DEFAULT_THRESHOLD 0.4 /* in units/ms */ #define DEFAULT_ACCELERATION 2.0 /* unitless factor */ +#define DEFAULT_INCLINE 1.1/* unitless factor */ /* * Pointer acceleration filter constants @@ -101,6 +102,7 @@ struct pointer_accelerator { double threshold; /* units/ms */ double accel; /* unitless factor */ + double incline; /* incline of the function */ }; static void @@ -255,10 +257,21 @@ static bool accelerator_set_speed(struct motion_filter *filter, double speed) { + struct pointer_accelerator *accel_filter = + (struct pointer_accelerator *)filter; + assert(speed = -1.0 speed = 1.0); + /* delay when accel kicks in */ + accel_filter-threshold = DEFAULT_THRESHOLD - speed/6.0; + + /* adjust max accel factor */ + accel_filter-accel = DEFAULT_ACCELERATION + speed; + + /* higher speed - faster to reach max */ + accel_filter-incline = DEFAULT_INCLINE + speed/2.0; + filter-speed = speed; - return true; } @@ -290,6 +303,7 @@ create_pointer_accelator_filter(accel_profile_func_t profile) filter-threshold = DEFAULT_THRESHOLD; filter-accel = DEFAULT_ACCELERATION; + filter-incline = DEFAULT_INCLINE; return filter-base; } @@ -314,9 +328,10 @@ pointer_accel_profile_linear(struct motion_filter *filter, double s1, s2; const double max_accel = accel_filter-accel; /* unitless factor */ const double threshold = accel_filter-threshold; /* units/ms */ + const double incline = accel_filter-incline; s1 = min(1, speed_in * 5); - s2 = 1 + (speed_in - threshold) * 1.1; + s2 = 1 + (speed_in - threshold) * incline; return min(max_accel, s2 1 ? s2 : s1); } -- 1.9.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput 1/3] core: Add internal event notification mechanism
On Thu, Sep 18, 2014 at 01:11:03PM +0200, Hans de Goede wrote: For features like e.g. disable-touchpad-while-typing, it is necessary for one device to be able to listen into another device's events. It is tempting to use the existing device_added / device_removed mechanism to give e.g. the keyboard a link to the touchpad, and make the keyboard code disable / re-enable the touchpad but this wrong. This needs to be a setting of the touchpad, and the policy for things like which events to count as activity, and what sort of timeout to use to consider the device idle, belongs in the touchpad code not in the keyboard code. Add an event listeners mechanism so that the touchpad can listen for (e.g.) keyboard events, and respond to these itself. Signed-off-by: Hans de Goede hdego...@redhat.com --- src/libinput-private.h | 18 ++ src/libinput.c | 27 +++ 2 files changed, 45 insertions(+) diff --git a/src/libinput-private.h b/src/libinput-private.h index cf03c03..94d6580 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -118,12 +118,19 @@ struct libinput_device_config { struct libinput_device { struct libinput_seat *seat; struct list link; + struct list event_listeners; void *user_data; int terminated; int refcount; struct libinput_device_config config; }; +struct libinput_event_listener { + struct list link; + void (*notify_func)(struct libinput_event *ev, void *notify_func_data); + void *notify_func_data; +}; + typedef void (*libinput_source_dispatch_t)(void *data); @@ -180,6 +187,17 @@ libinput_device_init(struct libinput_device *device, struct libinput_seat *seat); void +libinput_device_add_eventlistener(struct libinput_device *device, event_listener vs eventlistener here, please use the former. otherwise: Reviewed-by: Peter Hutterer peter.hutte...@who-t.net Cheers, Peter + struct libinput_event_listener *listener, + void (*notify_func)( + struct libinput_event *event, + void *notify_func_data), + void *notify_func_data); + +void +libinput_device_remove_eventlistener(struct libinput_event_listener *listener); + +void notify_added_device(struct libinput_device *device); void diff --git a/src/libinput.c b/src/libinput.c index 14f0257..79ae90a 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -674,6 +674,7 @@ libinput_device_init(struct libinput_device *device, { device-seat = seat; device-refcount = 1; + list_init(device-event_listeners); } LIBINPUT_EXPORT struct libinput_device * @@ -686,6 +687,7 @@ libinput_device_ref(struct libinput_device *device) static void libinput_device_destroy(struct libinput_device *device) { + assert(list_empty(device-event_listeners)); evdev_device_destroy((struct evdev_device *) device); } @@ -732,6 +734,25 @@ libinput_dispatch(struct libinput *libinput) return 0; } +void +libinput_device_add_eventlistener(struct libinput_device *device, + struct libinput_event_listener *listener, + void (*notify_func)( + struct libinput_event *event, + void *notify_func_data), + void *notify_func_data) +{ + listener-notify_func = notify_func; + listener-notify_func_data = notify_func_data; + list_insert(device-event_listeners, listener-link); +} + +void +libinput_device_remove_eventlistener(struct libinput_event_listener *listener) +{ + list_remove(listener-link); +} + static uint32_t update_seat_key_count(struct libinput_seat *seat, int32_t key, @@ -798,7 +819,13 @@ post_device_event(struct libinput_device *device, enum libinput_event_type type, struct libinput_event *event) { + struct libinput_event_listener *listener, *tmp; + init_event_base(event, device, type); + + list_for_each_safe(listener, tmp, device-event_listeners, link) + listener-notify_func(event, listener-notify_func_data); + libinput_post_event(device-seat-libinput, event); } -- 2.1.0 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput 2/3] core: Move libinput_event definition to libinput-private.h
On Thu, Sep 18, 2014 at 01:11:04PM +0200, Hans de Goede wrote: Signed-off-by: Hans de Goede hdego...@redhat.com Reviewed-by: Peter Hutterer peter.hutte...@who-t.net --- src/libinput-private.h | 5 + src/libinput.c | 5 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libinput-private.h b/src/libinput-private.h index 94d6580..3b46c27 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -125,6 +125,11 @@ struct libinput_device { struct libinput_device_config config; }; +struct libinput_event { + enum libinput_event_type type; + struct libinput_device *device; +}; + struct libinput_event_listener { struct list link; void (*notify_func)(struct libinput_event *ev, void *notify_func_data); diff --git a/src/libinput.c b/src/libinput.c index 79ae90a..364890e 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -42,11 +42,6 @@ struct libinput_source { struct list link; }; -struct libinput_event { - enum libinput_event_type type; - struct libinput_device *device; -}; - struct libinput_event_device_notify { struct libinput_event base; }; -- 2.1.0 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH libinput 3/3] touchpad: Disable touchpads on trackpoint activity
On Thu, Sep 18, 2014 at 01:11:05PM +0200, Hans de Goede wrote: Some laptops with both a clickpad and a trackpoint have such a large touchpad, that parts of the users hands will touch the pad when using the trackpoint. Examples of this are the Lenovo T440s and the Toshiba Tecra Z40-A. This commit makes libinput automatically disable the touchpad while using the trackpoint on these devices, except for the buttons, as people may want to use the touchpad (hardware or soft) buttons while using the trackpoint. Signed-off-by: Hans de Goede hdego...@redhat.com --- src/evdev-mt-touchpad.c | 64 +++-- src/evdev-mt-touchpad.h | 3 +++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 1c32cc6..31e2e83 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -31,6 +31,7 @@ #define DEFAULT_ACCEL_NUMERATOR 1200.0 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0 +#define DEFAULT_TRACKPOINT_ACTIVITY_TIMEOUT 500 /* ms */ static inline int tp_hysteresis(int in, int center, int margin) @@ -523,8 +524,8 @@ tp_post_events(struct tp_dispatch *tp, uint64_t time) double dx, dy; int consumed = 0; - /* Only post (top) button events while suspended */ - if (tp-device-suspended) { + /* Only post (top) button events? */ + if (tp-device-suspended || tp-sendevents.trackpoint_active) { tp_post_button_events(tp, time); return; } @@ -594,6 +595,16 @@ tp_process(struct evdev_dispatch *dispatch, } static void +tp_destroy_sendevents(struct tp_dispatch *tp) +{ + libinput_timer_cancel(tp-sendevents.trackpoint_timer); + + if (tp-buttons.trackpoint) + libinput_device_remove_eventlistener( + tp-sendevents.trackpoint_listener); +} + +static void tp_destroy(struct evdev_dispatch *dispatch) { struct tp_dispatch *tp = @@ -601,6 +612,7 @@ tp_destroy(struct evdev_dispatch *dispatch) tp_destroy_tap(tp); tp_destroy_buttons(tp); + tp_destroy_sendevents(tp); filter_destroy(tp-filter); free(tp-touches); @@ -667,6 +679,36 @@ tp_resume(struct tp_dispatch *tp, struct evdev_device *device) } static void +tp_trackpoint_timeout(uint64_t now, void *data) +{ + struct tp_dispatch *tp = data; + + tp_clear_state(tp, tp-device); + tp-sendevents.trackpoint_active = false; +} + +static void +tp_trackpoint_event(struct libinput_event *event, void *data) +{ + struct tp_dispatch *tp = data; + + /* Only movement counts as trackpad activity, as people may use +the trackpoint buttons in combination with the touchpad. */ + if (event-type != LIBINPUT_EVENT_POINTER_MOTION) + return; the wheel emulation code posts axis events, you'll need to include those here as well. + + if (!tp-sendevents.trackpoint_active) { + tp_clear_state(tp, tp-device); + tp-sendevents.trackpoint_active = true; + } + + /* We don't use the event time as that may wrap */ + libinput_timer_set(tp-sendevents.trackpoint_timer, +libinput_now(tp-device-base.seat-libinput) + + DEFAULT_TRACKPOINT_ACTIVITY_TIMEOUT); Can you expand on this? it seems like an odd comment given that we use the event time elsewhere. it also provides inconsistent behaviour, if libinput is slow to read the event the timeout is set from when it gets processes as opposed to when the physical interaction happened. That's something we should avoid. other than that, Reviewed-by: Peter Hutterer peter.hutte...@who-t.net Cheers, Peter +} + +static void tp_device_added(struct evdev_device *device, struct evdev_device *added_device) { @@ -677,6 +719,9 @@ tp_device_added(struct evdev_device *device, /* Don't send any pending releases to the new trackpoint */ tp-buttons.active_is_top = 0; tp-buttons.trackpoint = added_device; + libinput_device_add_eventlistener(added_device-base, + tp-sendevents.trackpoint_listener, + tp_trackpoint_event, tp); } if (tp-sendevents.current_mode != @@ -700,6 +745,8 @@ tp_device_removed(struct evdev_device *device, tp-buttons.active = 0; tp-buttons.active_is_top = 0; } + libinput_device_remove_eventlistener( + tp-sendevents.trackpoint_listener); tp-buttons.trackpoint = NULL; } @@ -886,6 +933,16 @@ tp_init_palmdetect(struct tp_dispatch *tp, } static int +tp_init_sendevents(struct tp_dispatch *tp, +struct evdev_device *device) +{ +