Bug 101139

Summary: Acceleration still too fast with slow and slow-medium finger movements
Product: Wayland Reporter: Nate Graham <nate>
Component: libinputAssignee: Wayland bug list <wayland-bugs>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: medium CC: bugseforuns, gdr3941, nate, peter.hutterer, samuel
Version: unspecified   
Hardware: x86-64 (AMD64)   
OS: Linux (All)   
Whiteboard:
i915 platform: i915 features:
Bug Depends on:    
Bug Blocks: 98535    
Attachments: Patch for Macbook Pro 8,2 testing
MacOS inspired touchpad acceleration patch
Accel Profile Comparison at Zero Speed
Accel profile comparison patch at -0.75 vs nominal
Accel profiles from lowclip.patch
Lowclip patch
0001-filter-match-accel-roughly-with-macos.patch
synaptics-libinput-comparison.svg

Description Nate Graham 2017-05-21 15:32:43 UTC
Linux distro: openSUSE Tumbleweed
libinput version: 1.7.0-2.1

This is a subtask/blocker of https://bugs.freedesktop.org/show_bug.cgi?id=98535

I thought I was happy enough with Libinput's touchpad behavior, but then I got to use a 5 year-old Mac laptop and was reminded of the much nicer feel of its trackpad software. One of the major differences was how naturally the cursor accelerated in response to medium-ish finger movements: much faster than current libinput does. I'd like to track that in this issue.
Comment 1 Greg Reichow 2017-11-14 05:54:51 UTC
Peter-
First off thanks for all your work with libinput.  Really appreciate your contribution to the community.  

I also had a pretty bad experience with libinput on a Macbook Pro 8,2 using 1.8.4 and also in 1.9.  Pointer acceleration felt really different from what I was used to on the machine under MacOS.  Slow movements were two "jerky", medium were not fast enough, etc.  (I had previously been using mtrack under xorg with mediocre results)

I spent some time and created a mac app to profile the touchpad acceleration profiles used in MacOS. It was a course view, but provided some insight into what felt right for this machine.  I then took a crack at modifying the acceleration code in libinput to best match this profile curve.  After some tuning, it seems to be working really great for me on this machine.  The basic acceleration is a power function.  Copied below is the new touchpad_accel_profile function I am using.  It is pretty sensitive (my desired speed setting is right in the middle), yet gives me a lot of room to adjust from slow to really fast using the normal speed slider.

My apologies if this is not the right way to help share this information. This below plus a couple other small improvements has made libinput (and therefore Wayland) very enjoyable for me with an old macbook pro touchpad. The pointer acceleration has a really nice balance of slow speed accuracy and high speed capability.  FWIW.

Code below
----------

double
touchpad_apple_accel_profile(struct motion_filter *filter,
			      void *data,
			      double speed_in, /* in device units/µs */
			      uint64_t time)
{
	struct pointer_accelerator *accel_filter =
		(struct pointer_accelerator *)filter;
	const double max_accel = accel_filter->accel; /* unitless factor */
	double factor; /* unitless */

	/* Convert to mm/s because that's something one can understand */

	speed_in = v_us2s(speed_in) * 25.4/accel_filter->dpi;

	// Convert into speed that my formula used which assumed 1 = distance of trackpad in X (103mm for my pad); should fix the formulas below to make this a function of the trackpad distance in mm instead.

	double norm_in = speed_in / 103.0;

	// X adjustment; range on Apple was .07 to .7 (fastest)

	double x_factor = 0.385 + 0.315 * filter->speed_adjustment;

	// Power adjustment; range on Apple was 1.1 to 1.5 (fastest)

	double power = 1.3 + 0.2 * filter->speed_adjustment;

	// first number is a magic number to get into the scale that is appropriate

	factor = 3.5 * pow(norm_in * x_factor, power);

	// Minimum factor for slow speeds

	if (factor < 0.20) {
		factor = 0.20;
	}
	
	/* Cap at the maximum acceleration factor */
	factor = min(max_accel, factor);

	return factor;
}
Comment 2 Greg Reichow 2017-11-14 06:20:02 UTC
Correction above:  that is too, not two.  And coarse, not course.  Yikes.

To clarify above, the profiling and curve fitting I did on MacOS assumed input velocities with distance represented by 0-1 (1 = full width of trackpad) and time in seconds.  Obviously, the formulas could be modified to eliminate this extra conversion.  I left as shown to make adjustments easier vs the measured acceleration curves.
Comment 3 Nate Graham 2017-11-16 01:08:45 UTC
Greg, if you put that in patch form, I'd love to test it out.
Comment 4 Greg Reichow 2017-11-16 05:38:01 UTC
Created attachment 135510 [details] [review]
Patch for Macbook Pro 8,2 testing

Patch from libinput 1.9.1 attached

Changes:
1. Added thumb detection based on size, improves detection on MacbookPro
2. Raised height at which thumb detection is triggered (was 15%, now is 40% up from bottom).  This better matches Apple and the mtrack driver.
3. Lower scroll lock distance threshold
4. New Apple MacbookPro acceleration profile based on MacOS profiling
5. Fixed two finger click to activate right mouse button instead of middle
6. Disabled some gestures that were causing problems
7. Slowed down scrolling speed slightly (may not be working)

NOTE:  The new acceleration profile is only triggered if the touch device registers as EVDEV_MODEL_APPLE_TOUCHPAD.  This worked for my Macbook Pro 8,2.

The new acceleration profile is pretty fast relative to the standard libinput settings.  The normal mouse speed setting (for example in Gnome settings) can be used to adjust the speed.  It adjusts both the speed and acceleration ramp up.  

All of the other changes are general and may cause problems for non-Apple products.  I have only tested this on my MacbookPro 8,2.
Comment 5 Nate Graham 2017-11-16 15:03:47 UTC
Thank you so much for that patch, Greg. I'm not using an Apple touchpad, but with accel speed -0.85, your patch RADICALLY improves the feel anyway, both for cursor movement and scroll speed. It's a vast improvement over the Flat or Adaptive profiles. I would strongly support using the acceleration curve as the default, or adding it as an additional profile beyond Flat and Adaptive.

If this ever gets made the default or incorporated somehow, the scaling of the accel speed setting would need to be tweaked, because anything higher than about -0.5 is unusably fast for me.
Comment 6 Nate Graham 2017-11-16 15:09:24 UTC
Your patch also implements/fixes the following issues that previously made libinput less than pleasant:

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

Congrats, you just made libinput usable full-time for me.
Comment 7 Greg Reichow 2017-11-18 19:33:10 UTC
Created attachment 135579 [details] [review]
MacOS inspired touchpad acceleration patch

Nate-  Thanks for the testing and feedback.  This new patch against 1.9.2 is slowed down slightly.  This patch only includes the touchpad acceleration profile change.  (Previous patch had several other smaller fixes for MacbookPro). 
It replaces the existing linear profile in libinput and therefore can be tested by people using various different laptops.
Comment 8 Nate Graham 2017-12-16 19:34:18 UTC
Greg, that's a pretty great patch. I've been using it for the past month. The default speed still feels too fast, though. I still need to set "libinput Accel Speed" to -0.75 to make it feel reasonable.

Peter, minus the speed issues, this patch makes libinput's touchpad cursor movement profile feel *perfect* to me.
Comment 9 Peter Hutterer 2018-01-05 05:30:49 UTC
Thanks for the patch greg, sorry about the delay. I tried this on top of 43de03a08c7cdbe on the t440s that I have here and, well, it's almost unusable, sorry. On the default 0 setting it's way too fast, reducing it to -0.75 like Nate makes very slow to slow movements almost match the finger movements. but as soon as I go past that basic speed, the cursor is unpredictable and lands in the screen edges almost immediately. 

I printed the curve (./build/ptraccel-debug --filter=touchpad --mode=accel, then use the gnuplot commands at the top of the output) and it's no surprise that it feels fast. The max accel factor is 9 (vs ~3 in the current code) and the increase is sooner and much steeper than the current code. So at least the fast movement isn't some weird side-effect but the intention.

So we definitely need some tuning here. Or am I missing something? I only applied the patch from comment 7 locally.

And if that's it, I *really* wonder where the bug is because it's one thing to argue about a personal preference for pointer feel but another to see that code that *should* be device-independent behaves so different on different devices. There's a bug in the accel code somewhere but I don't know where.
Comment 10 Greg Reichow 2018-01-06 04:59:31 UTC
Peter- Thanks for checking it out.  I agree something strange is happening.  The patch you mention is the same I am using on my Macbook Pro with very different results.  Agree that this is not a preference / slight difference.  (For reference, I am running with a setting of -0.3 and even relatively quick movements only get me about 1/2 way across the screen.)

It sounds like something is very different in the end result between our two different pieces of hardware.  I will dig in further and see what I can find.
Comment 11 Greg Reichow 2018-01-06 19:14:20 UTC
Created attachment 136584 [details]
Accel Profile Comparison at Zero Speed

See next comment
Comment 12 Greg Reichow 2018-01-06 19:16:03 UTC
Created attachment 136585 [details]
Accel profile comparison patch at -0.75 vs nominal

Hi Peter,

After some further investigation, I think I have a better idea what is happening.  The good news is that I don't think there is some bug causing a difference in performance between our machines.  

To start, I confirmed that my touchpad was not doing something odd like reporting a bad DPI or size.  Everything looked good.  (DPI is 92 device units/mm or about 2300 per inch).  Did a bunch of verification and everything seemed to make sense.

I then used your speed measuring tool and found something interesting to me.  It turns out that my typical speeds for normal operation of the touchpad range from 0 to 200 (99th percentile).  I then compared this to the nominal accel profiles (set at speed 0) and noticed that 99% of my operational speeds never even get to the part of the curve where accel ramps up in the libinput profile.  This created what I felt was no acceleration and a "dead middle" to high end.  I also felt that at very slow speeds, it did not have the accuracy I needed.  If I cranked up the speed setting to pull in the threshold of the acceleration ramp, it made the low end speed even worse (meaning even harder to control).  I then looked at the curve from the patch and noticed that within my operational range, it addressed both of these problems for me.  The low end is slower and more accurate, and the acceleration starts at about the midpoint and ramps up.  (Completely agree that at much higher speeds the raw accel factor gets crazy high in my patch, but it would seem I never get there with my touchpad speed.)  I have attached plots that show both the nominal and the patched accel profile plots at a speed setting of zero.

I also then did a comparision on the patch at the setting that Nate mentioned feeling good (-0.75).  See attached graph that compares it to the zero speed setting of the nominal accel profile.  It actually seems very close yet addresses the slow speed problem and also has a bit more acceleration early and smoothly from the middle to the high end.  

I will take another swing at a new profile / patch that moves the current patch's -0.75 setting and moves this up to 0 to slow things down overall.

Thanks,
Greg
Comment 13 Nate Graham 2018-01-07 05:34:55 UTC
Thanks for the investigation, Greg. That matches both my experience, and also libinput's as-designed acceleration curve (I know I've seen that curve displayed elsewhere, maybe even in the docs somewhere).

The curve in your patch makes vastly more sense to me, both after experiencing it for real-world use, but also on a theoretical, conceptual basis: slow finger movements *should* trigger a usable slow speed, not the immediate jump to much higher speed that libinput currently has.
Comment 14 Peter Hutterer 2018-01-08 04:58:32 UTC
That 'dead' zone is intentional, see https://who-t.blogspot.com.au/2016/12/libinput-touchpad-pointer-acceleration.html for a few graphs. And the main motivation there was that for most slower-medium motions, the cursor should basically match the finger movement, so the acceleration should be flat. Cursor movement is actually slightly faster than finger movement but that's the reference point anyway. A 1cm circle with the finger on the touchpad gives me a ~3cm circle on the screen. Can you confirm this?
Comment 15 Peter Hutterer 2018-01-09 05:34:14 UTC
fwiw, I went through the touchpad acceleration code again and could not find anything obviously wrong. An important definition: a 'normalized' coordinate is one that's converted from device units to units equivalent to a 1000dpi standard mouse.

* starting point: tp_gesture_post_pointer_motion()
* tp_get_delta() returns a normalised delta
* this delta is passed to tp_filter_motion(), where it is converted back to device units [the double-conversion is a leftover]. Only difference: the y axis is pushed to the same resolution as the x axis so we can assume a delta in a single coordinate system. That's the 'raw' variable.
* 'raw', in units/mm, is passed to filter_dispatch() which calls accelerator_filter_post_normalized (see accelerator_interface_touchpad)
* 'raw' is passed further to accelerator_filter_generic() and calculate_acceleration_factor().
* that calculates the velocity (in units/us) and passes it to calculate_acceleration()
* that then calls the profile: touchpad_accel_profile_linear()
* the profile converts the speed (in units/us) to mm/s for easier understanding and then applies the linear-ish accel function that calculates the accel factor.
* that factor is passed back up and applied to the raw input delta (accelerator_filter_post_normalized)
* the input delta is converted to 1000dpi normalized units and we finish filter_dispatch() and send the accelerated delta to the caller

So aside from the slightly confusing conversions between systems, there is nothing bleedingly obviously wrong.
Comment 16 Greg Reichow 2018-01-09 07:07:04 UTC
Peter-

Thanks for your response.  Agree that it does not look like there are any bugs that are causing this behavior.  It may just come down to preference.  On your earlier response, I understand the intention behind the flat zone.  Yet, I think part of what I am experiencing is that this flat zone is not fixed at the 1:1 rate.  It scales with the overall speed setting.  Therefore, when I set the speed high enough to pull forward the threshold to get the acceleration profile I like in the middle, it is also bringing up the low speed floor to a too high level for me to accurately control the pointer.  For reference, to make the middle and high end feel right, my speed setting is ~0.95.  Yet, this has the low speed range too high.  To get the low speed range to a level that enables precision, I need to have the overall speed setting down at about -0.8.  (Might be that I have some poor fine muscle control..)  

On your question on the circle, at a speed setting of 0, a 1cm circle on my touchpad = about 3.5cm circle on screen.  (My best attempt to measure, don't read too much into the accuracy of this.)

I did try another approach.  Instead of trying to emulate a power profile like in my earlier patch, I tried making the minimal amount of changes to the existing profiles to make it feel right at both low speed and high speed.  I first eliminated the scaling on the flat portion and fixed it at a lower level.  This really improved the low end accuracy for me.  Yet, the middle was still flat and not accelerating enough.  I then pulled forward the threshold for the acceleration ramp by 50%.  (Effectively starting the acceleration ramp up earlier).  With both of these and a speed setting of about +0.75, things feel really good to me.  I have the mid and high speed acceleration that feels right and also the low speed precision.  

I have attached a patch for reference and also a graph of the resulting profiles. FWIW, I will probably stick with using this patch as it feels pretty good.  I get for others, it may not make sense.  I guess this is the beauty of open source software! 

Thanks for taking the time to look at this.  (And thanks for all your work on libinput!)

Greg
Comment 17 Greg Reichow 2018-01-09 07:08:24 UTC
Created attachment 136627 [details]
Accel profiles from lowclip.patch

Per comment above
Comment 18 Greg Reichow 2018-01-09 07:10:21 UTC
Created attachment 136628 [details] [review]
Lowclip patch

This is the patch mentioned above that attempts to minimally modify existing accel profile.  Pulls forward beginning of acceleration ramp and also fixes slow speed at a lower acceleration for accuracy.  End result for me is good low speed precision and improved mid range acceleration.
Comment 19 Peter Hutterer 2018-01-10 05:46:15 UTC
(In reply to Greg Reichow from comment #16)
> On your question on the circle, at a speed setting of 0, a 1cm circle on my
> touchpad = about 3.5cm circle on screen.  (My best attempt to measure, don't
> read too much into the accuracy of this.)

close enough, thanks. This indicates at least that we're not talking about two completely reactions but rather preferences. fwiw, at the -0.8 setting with current master, 1cm on the touchpad maps to ~1cm on the screen and the screen cursor feels like it's just a tad slower than the finger, a movement not triggering any acceleration eventually has the finger overtake the cursor.

While that's acceptable for something that close to the lower range limit of -1, it would be way too slow for anything above.

At a speed setting of 0.9 the cursor is effectively uncontrollable. Any faster movement hits the edge, a fast ~2cm movement crosses the whole screen. Again, for 0.9 that's acceptable because it's the upper range. But I'm really curious that you want such a slow default speed and such a fast acceleration. I tried your curve and the pointer is almost uncontrollable for me. When acceleration kicks in it shoots to an edge way too quickly, I end up overshooting by 5-10cm on anything but fast movements. So what's going on here?
Comment 20 Greg Reichow 2018-01-12 04:06:13 UTC
Given your description, there must be something wrong still.  I really need to crank up the speed setting to make it feel like it is accelerating at all.  I am wondering if there is not something weird happening on inbound events that are being used to calculate the initial (pre-acceleration) velocities.  I measured a sample of my usage doing normal navigation around the screen.  Attached below is the profile.  It really seems to me this is likely skewed very low.  Does this match your normal velocity profile?  I am going to do more digging to see if I can figure out why I am getting such low initial velocities (if indeed these are truly low).  It makes sense that I am having a problem with these velocities as even with the speed set to 0.5, 92% of my movements never even hit the beginning of the acceleration curve.

# Number of data points: 4284
# Highest velocity: 315.338257387 mm/s
# Starting with 32 buckets
# Reducing to 24 buckets (5 required per bucket)
# Left with 4273 data points (99.7% of data)
  percent    nevents    total-percent    speed
---------  ---------  ---------------  -------
12.0056          513          12.0056       10
11.8184          505          23.824        20
11.1631          477          34.9871       30
14.3459          613          49.333        40
13.3864          572          62.7194       50
 5.055           216          67.7744       60
 0.234028         10          68.0084       70
 2.01264          86          70.0211       80
 2.5041          107          72.5252       90
 3.01896         129          75.5441      100
 4.68055         200          80.2247      110
 4.16569         178          84.3904      120
 3.15937         135          87.5497      130
 3.01896         129          90.5687      140
 2.34028         100          92.909       150
 2.41048         103          95.3194      160
 1.42757          61          96.747       170
 0.93611          40          97.6831      180
 0.819097         35          98.5022      190
 0.655277         28          99.1575      200
 0.25743          11          99.4149      210
 0.280833         12          99.6958      220
 0.140417          6          99.8362      230
 0.163819          7         100           240
Comment 21 Peter Hutterer 2018-03-06 07:19:51 UTC
sigh, this is how quickly two months disappear. sorry about this, busy with a million other things but this is on my radar again now. So: a 5 min browsing session shows this:

# Number of data points: 12378
# Highest velocity: 5692.05937231 mm/s
# Starting with 570 buckets
# Reducing to 31 buckets (5 required per bucket)
# Left with 12359 data points (99.8% of data)
   percent    nevents    total-percent    speed
----------  ---------  ---------------  -------
43.2964          5351          43.2964       10
13.65            1687          56.9464       20
 7.60579          940          64.5521       30
 5.34833          661          69.9005       40
 4.70912          582          74.6096       50
 4.34501          537          78.9546       60
 3.50352          433          82.4581       70
 2.83194          350          85.2901       80
 2.20892          273          87.499        90
 2.00663          248          89.5056      100
 1.87717          232          91.3828      110
 1.59398          197          92.9768      120
 1.27033          157          94.2471      130
 1.13278          140          95.3799      140
 0.962861         119          96.3427      150
 0.736306          91          97.0791      160
 0.687758          85          97.7668      170
 0.453111          56          98.2199      180
 0.38029           47          98.6002      190
 0.347925          43          98.9481      200
 0.226556          28          99.1747      210
 0.226556          28          99.4012      220
 0.250829          31          99.6521      230
 0.0728214          9          99.7249      240
 0.0323651          4          99.7573      250
 0.0404563          5          99.7977      260
 0.0323651          4          99.8301      270
 0.0485476          6          99.8786      280
 0.0566389          7          99.9353      290
 0.0242738          3          99.9595      300
 0.0404563          5         100           310

note how almost half the events are in the 10-20mm/s bucket. So I don't think your measurement is out of the ordinary.

I realised after recording that this was with the synaptics driver. Since there is a positive feedback loop, here's another session with libinput. I think any differences are more due to different interactions than the two drivers.

# Number of data points: 7033
# Highest velocity: 1669.01036276 mm/s
# Starting with 167 buckets
# Reducing to 37 buckets (5 required per bucket)
# Left with 7005 data points (99.6% of data)
   percent    nevents    total-percent    speed
----------  ---------  ---------------  -------
37.8016          2648          37.8016       10
16.8879          1183          54.6895       20
 3.88294          272          58.5724       30
 2.55532          179          61.1278       40
 6.8808           482          68.0086       50
 4.75375          333          72.7623       60
 4.0828           286          76.8451       70
 2.75517          193          79.6003       80
 2.18415          153          81.7844       90
 2.14133          150          83.9258      100
 1.68451          118          85.6103      110
 1.54176          108          87.152       120
 1.3419            94          88.4939      130
 1.22769           86          89.7216      140
 1.18487           83          90.9065      150
 1.01356           71          91.9201      160
 1.02784           72          92.9479      170
 0.913633          64          93.8615      180
 0.842256          59          94.7038      190
 0.813704          57          95.5175      200
 0.770878          54          96.2884      210
 0.6995            49          96.9879      220
 0.613847          43          97.6017      230
 0.342612          24          97.9443      240
 0.399714          28          98.344       250
 0.28551           20          98.6296      260
 0.271235          19          98.9008      270
 0.256959          18          99.1577      280
 0.171306          12          99.3291      290
 0.157031          11          99.4861      300
 0.157031          11          99.6431      310
 0.0856531          6          99.7288      320
 0.0713776          5          99.8001      330
 0.028551           2          99.8287      340
 0.028551           2          99.8572      350
 0.0713776          5          99.9286      360
 0.0713776          5         100           370
Comment 22 Peter Hutterer 2018-03-07 06:25:14 UTC
Some notes after another afternoon of playing around with this:

The script that produces the output above measures *physical* movements on the touchpad, thus the 'speed' on the right column represent 10mm/s physical movement, not pointer movement. IMO it makes sense that the majority comes in at below 20mm/s. Slow movements generate more events, fast movements are *short* movements with few events.

I played around with a bunch of acceleration curves similar to attachment 136584 [details]. I used a linear curve instead for simplicity with varying inclines, starting acceleration at 40mm/s, inclines from 'roughly parallel to current' to 'roughly like attachment 136584 [details]'. They showed the same thing every time: the pointer is uncontrollable once we hit accel factor 3 [1] at anything but very low speeds. The fast pointer movement is multiplied by a high factor, resulting in ridiculous deltas and unpredictable pointers.

A fixed factor 3 is just about controllable but would cause RSI after 5 min.

I have in front of me: Lenovo T440s, Lenovo T450s, Dell XPS 13 9365, Asus E402S. All with Fedora 27, up-to-date (libinput 1.10.1). The touchpad behaviour is effectively identical [2] on all four machines.

Bug 105375 is the next step here, once that's implemented we can at least compare full output. But right now, I know just as much as before :(


All that aside, please confirm that you do *not* have a hidpi screen though.


[1] factor 3 not accounting for the TP_MAGIC_SLOWDOWN, so effective factor 3 * 0.37
[2] The XPS has a hidpi screen and is slow under X, GNOME on wayland makes up for this but that's not a libinput issue.
Comment 23 Nate Graham 2018-03-08 22:02:08 UTC
Peter, do you happen to have access to a Mac running macOS? IMHO that's the benchmark of A+ touchpad experience. Yes, a lot of this is the good hardware, but a lot of it is also the acceleration curve; I continue to find libinput unusable with the default curve, but a joy using  Greg's that patch mimics the macOS acceleration curve. With this, I have been able to finally switch from synaptics and use libinput full-time.
Comment 24 Peter Hutterer 2018-03-08 22:38:04 UTC
I do, a 2015 macbook air. And while I admit there are differences, I don't think they're that big. And that's the biggest puzzle, I can switch between the air and the t440 and notice a bit of a difference but it's not massive. Whereas the patch above that makes things useful for you makes the cursor absolutely uncontrollable - and with that I don't mean "i don't like it" but "i cannot hit a 200x200 size target with it" as soon as I'm going beyond crawling speed. So, *something* is off and I still have not yet identified what it is.

Again: "please confirm that you do *not* have a hidpi screen"
Comment 25 Nate Graham 2018-03-08 22:46:26 UTC
Funny, I notice a MASSIVE difference (all Mac touchpads feel the same; there's no moderl/year difference in touchpad feel). I'm the kind of person who wants a touchpad so good that I don't feel the urge to use a mouse, so maybe I'm just picky. But I really really really do notice the difference.

With Greg's patch, I have to use a -0.75 accel value, and it feels perfect. But there may be hardware-specific factors at play. My touchpad hardware is definitely not the highest quality in the world.

I'm not married to Greg's patch per se; my issue with libinput's default acceleration curve is pretty simple to articulate: it accelerates too much at slow and slow-medium speeds. Check out the graph attached at https://bugs.freedesktop.org/attachment.cgi?id=136584: Up to 50 mm/s, the default acceleration is faster than with Greg's patch, and there's a very abrupt cliff where the acceleration increases. Aside from technical matters, I'm just not sure what the justification is for accelerating small movements that much. It makes precise control very difficult.

I do not have a HiDPI screen (didn't know it was directed at me, sorry). Regular old 1920x1080 @ 13". Not sure it's relevant now since I'm using KDE Plasma with KWin, not GNOME with Mutter.
Comment 26 Peter Hutterer 2018-03-09 00:38:33 UTC
And here's the thing - libinput's acceleration works in physical distances. So the hw shouldn't really matter because a speed of 10mm/s is always that, regardless of the hardware. As long as touchpad-edge-detector and you agree on the ranges/dimensions on the hardware, there shouldn't be much difference.

That acceleration in the attachment is actually a slowdown, we multiply the calculated input speed by a magic constant (0.37) so that a physical delta of 10mm should end up in a delta of 3.7mm [1], give or take with the changing screen resolution. Greg's patch just slows things down even further and a -0.75 should then make this even slower.

The question was directed at anyone btw, sorry, should've made that clear.
If you have a compositor that doesn't support hidpi, you'd see a slowdown because with twice the pixel density (which libinput knows nothing about) your delta is half as fast - but that's something the compositor has to take care of (mutter already does).

It would be good if you could attach an evemu recording from a finger movement. Close your eyes, put your finger down and move from left to right at about 20mm/s - hard to guess I know but it's basically a medium movement. Then I can try to reproduce this here, maybe, hopefully.

For reference: here's a video of me moving the finger and the corresponding cursor movement in the libinput debug-gui: https://photos.app.goo.gl/BTED3UdQwYqw5iW22

[1] having said that, I'm now wondering what's going on there, because if I move 10mm, it moves by ~10mm on the screen, not 3.7
Comment 27 Nate Graham 2018-03-09 01:09:43 UTC
> [1] having said that, I'm now wondering what's going on there, because if I
move 10mm, it moves by ~10mm on the screen, not 3.7

And that, I think, is exactly the bug we're trying to get to the bottom of.
Comment 28 Greg Reichow 2018-03-09 03:18:21 UTC
Couple comments to answer above:

1. Not using a Hi-dpi display. Reported resolution is 1680 x 1050.

2. Exact machine is a 2011 MacBook Pro 8,2 

3. Agree the earlier patch was too fast.  I also found I did not like the exponential acceleration from my first patch and have since switched full time to the last patch I submitted (lowclip_patch) which has a simple linear accel curve yet starts slower to enable precision at low speeds.  For reference, my comfortable setting is 0.

4. I will try to get some similar video with the slow finger movement and share back with you.

Is there a utility you have that records both physical input speed and also resulting cursor speed on screen? I wonder if something is not happening further up the stack from libinput and causing the differences in resulting pointer movement?  (As I keep going through the libinput code and do not understand why we are seeing such different results from similar input speeds as you have shown above.)
Comment 29 Peter Hutterer 2018-03-09 05:39:24 UTC
https://github.com/whot/libinput/tree/wip/evemu-v3 is the closest I have so far. It's still WIP so the output format isn't stable. Run with:

sudo ./build/libinput-record --with-libinput /dev/input/eventX (for the touchpad device). That will print the evdev events along with the libinput events. It's not evemu in that I don't have the python wrappers to process the data but that'll come eventually.

I tested the lowclip patch - the base speed is too slow for my liking but I can accept how this could be a preference. The acceleration is still too fast with the pointer shooting off as soon as I move a bit faster than the speed in the video from comment #26
Comment 30 Greg Reichow 2018-03-09 06:44:41 UTC
See video attached.  This was using the lowclip patch I mentioned with accel @ 0.  For reference, the physical trackpad distance covered in the video is about 90mm in 3 seconds.  So roughly 30mm/sec.  

I roughly measured the distance covered on the screen, it is about 110mm-120mm.   

https://www.dropbox.com/s/g32jmah45so38ck/IMG_6781.MOV?dl=0

I then did another video with far faster movements, see below:

https://www.dropbox.com/s/9yytyaydw26u5xt/IMG_6782.MOV?dl=0

Even with these movements at a significantly higher speed, I am still only covering about 50-75% of the screen width.

Greg
Comment 31 Peter Hutterer 2018-03-09 11:15:39 UTC
Hooray. The good news: based on these videos, I don't think we have a libinput *bug*, this does appear to be just a different preference. AFAICT, the movement matches what I got with the lowclip patch, at least considering the finger motion speed etc.

The bad news: to accommodate for this, we'd need some new pointer acceleration profile because if *that* is your preferred behaviour, it's going to be difficult to find a middle ground between the current and your patch. Because I consider the fast pointer motion (like in your second video) to be uncontrollable, I don't even get near any target when moving fast.

Adding a new profile is relatively trivial, but it opens us up to a few things: once you have two profiles, the floodgates are open for N profiles. Anyone not happy with the current profile will be pushing for another profile slightly different and that's a situation I really want to avoid.

fwiw, my macos at default speed is a lot faster than the lowclip patch. And given that we have the accel range, I think the first thing to look at is moving that baseline. From what I can tell, the macos accel doesn't have that same unaccelerated plateau that we have, it seems to almost contineously linear.
Comment 32 Peter Hutterer 2018-03-09 11:22:24 UTC
doh, sorry, hit the wrong button. Continued:

More experimenting with the lowclip patch is needed, and it needs to be compared to the original touchpad pointer accel (for which I got a lot of complaints for, so let's not go back to that).

I think macos may also use pressure values (well, touch sizes) for acceleration, but I'm not 100% of that. What it definitely has is deceleration at low speeds, that bit is missing from the lowclip patch. So the things to do to get closer to macos (from git master):
* keep deceleration at super-low speed
* shorten the plateau
* experiment with the incline a bit more
* verify max accel is still useful once the above is there
* slightly reduce the baseline

lowclip does 2 and 5 of these already, but the baseline is too low for a default setting. If you want it that low, you can reduce your speed in the config. The rest, well, we'll have to experiment to see if we come to some agreement :)
Comment 33 Peter Hutterer 2018-03-12 05:58:03 UTC
Created attachment 138012 [details] [review]
0001-filter-match-accel-roughly-with-macos.patch

This patch matches the macos pointer acceleration, afaict, at least at speed 0 and the min/max ranges sort-of match as well. +1.0 is more controllable than macos IMO. The negative ranges close to -1.0 have a tendency to shoot off too much, I think we need some lower max-accel caps here. Anyway, give this one a try please and let me know what you think.
Comment 34 Nate Graham 2018-03-12 16:58:41 UTC
Thanks, I'll give that a whirl later today!
Comment 35 Nate Graham 2018-03-13 03:14:29 UTC
Preliminary impressions: Feels quite nice at 0.0 "libinput accel speed" (i.e with no configuration). Definitely an improvement over the current profile. It does still feel like there's an abrupt jump in acceleration between medium and fast movements, but I think I could live with it.
Comment 36 Peter Hutterer 2018-03-13 06:26:42 UTC
The jump is probably caused by the angle between flat and actual acceleration which still looks like this: _/ (ascii-art! :) 
Smoothing this out to be more of a curve may or may not help.

Or the jump is caused by the incline being too steep and acceleration kicking in too quickly, if you could play around with that that'd be much appreciated.
Comment 37 Nate Graham 2018-04-05 21:28:21 UTC
I think it's both. If you think about it; they're two sides of the same coin: a shallower initial acceleration starts to look like a smooth curve the more segments are added.

Since it's a definite improvement in my book, it might be worth committing and then we can continue to tweak it later. Or should we shoot for fully resolving the issue in one fell swoop?
Comment 38 Peter Hutterer 2018-04-06 05:29:10 UTC
For the archives, I've done a visual comparison to the synaptics driver, basically by running Xorg with synaptics and libinput debug-gui with libinput (without the patch above, just git master at a59ce1c) and looking at the two cursors. Tests done with libinput acceleration 0 and synaptics' default acceleration without any changed settings.

1) at really slow motion libinput applies deceleration, cursor speed is approx the same for both. That's for things like slowly rolling the finger.
2) at slow motion libinput has a much higher acceleration factor than synaptics, possibly twice as high. Thats for slowly moving the finger across the touchpad.
3) at some medium speeds, libinput acceleration is still the same baseline but synaptics starts to accelerate already. This is where synaptics gets faster than libinput.
4) at high speeds, the acceleration rate is roughly the same but the maximum acceleration differs. When jerking the finger between two positions, sometimes the cursors move in parallel, sometimes the libinput cursor moves further than the synaptics one.

Despite my best efforts so far, I have yet to figure out how to print the synaptics acceleration curves for analysis. I've tried a few things but none of them match the perceived movements. There are too many factors and they are hard to calculate (e.g. screen resolution plays a part). Specifically, once the cursor is at the edges the behaviour changes and separating that is difficult.
Comment 39 Peter Hutterer 2018-04-06 05:30:39 UTC
I forgot: to do the above test, #if 0 around gdk_window_set_cursor() in tools/libinput-debug-gui.c, otherwise the system cursor is not visible.
Comment 40 Peter Hutterer 2018-04-06 06:29:43 UTC
Can I get you to try a84e79b4aee3563a37485de13c9448981afa4f7c on https://github.com/whot/libinput/tree/wip/touchpad-pointer-accel-v5

This one has a more adjusted curve, close to the macos one but with less harsh kick-in. That happens earlier too, combined with a lower baseline.
Comment 41 Greg Reichow 2018-04-08 16:29:31 UTC
(In reply to Peter Hutterer from comment #40)
> Can I get you to try a84e79b4aee3563a37485de13c9448981afa4f7c on
> https://github.com/whot/libinput/tree/wip/touchpad-pointer-accel-v5
> 
> This one has a more adjusted curve, close to the macos one but with less
> harsh kick-in. That happens earlier too, combined with a lower baseline.

I tested it some this morning and find it to be a good improvement.  I am still having a small amount of lack of precision with small movements and a little too slow when trying to move quickly.  That said, it is far better than the baseline I was testing and commenting on earlier.  Thanks for your work on this.  This would definitely be usable for me.

As another reference for profiling, I have been back in the land of Xorg lately as I am using i3.  The mtrack driver performs very nicely with my hardware and might be another baseline for comparison.  Yet I assume it suffers from the same complexity that you described with the Synaptics driver.
Comment 42 Peter Hutterer 2018-04-09 00:37:47 UTC
Awesome, thanks. I hope Nathan can chime in too with some testing comments, I'll work on getting the range of the acceleration right (or at least big enough that it should cover most cases). that should, hopefully, improve the remaining issues.

mtrack is a tricky beast. It's GPL which means I can't look at it for ideas for libinput without it getting problematic (libinput is MIT). So I don't know if it has a custom acceleration function but if it does similar initialization to the synaptics driver than most is handled in the server. but yeah, for testing and comparison I should probably start using it...
Comment 43 Nate Graham 2018-04-09 02:39:59 UTC
Still not quite perfect, but definitely better than the status quo! Feels best for me at around accel value -0.1. I can still feel that jarring hard "jump" when the acceleration curve changes. And it is still a bit (but now only a bit, not a lot) too fast for slow movements. I'll try to keep using it for a few days.

Also hysteresis turned itself back on... :/ I really, really dislike how it keeps turning itself back on every time I re-compile and deploy libinput. It's incredibly frustrating.
Comment 44 Peter Hutterer 2018-04-10 00:19:30 UTC
Created attachment 138716 [details]
synaptics-libinput-comparison.svg

Please keep this bug on-topic, the hysteresis issues are not for this bug.

Attaching my best efforts to compare synaptics and libinput for archival purposes. The libinput curve is printed directly with the ptraccel-debug tool (this is git master without the patches above). For the synaptics curve, I created a uinput device that moves a touch from left to right at decreasing time intervals and eventually gets to the maximum speeds shown. The various values were printed as YAML to the xorg.log and extracted from there with custom python scripts.

Since the server uses device coordinates everywhere, I divided the velocity for synaptics values by the resolution I used in the uinput device. This should give us mm.

The curves shown in the diagram are:
"synaptics" - the accelfct as returned from SynapticsAccelerationProfile for a given speed. Notice how the curve isn't too dissimilar to the libinput curve in shape, albeit the libinput curve includes the final accel factor.
"mult" - the multiplier used in the server's acceleratePointerPredictable(), after taking constant deceleration and the synaptics acceleration factor into account. This mult factor is then applied to the input deltas (these are in device coordinates) and the closest match to the 'accel factor' that libinput uses (but see below).
"libinput" - libinput accel factor applied to a delta at any given speed.

Constant deceleration in synaptics is 1/2.5 (0.4), and quite similar to the MAGIC we use in libinput (0.37). That latter one was found by trial and error but having those two similar indicates this is a good value.

I haven't even tried to change synaptics acceleration options, this makes it even harder...

To the best of my knowledge, the curves are correct. But honestly, this is all so convoluted that it's hard to be sure. And note that after applying the acceleration factor, the device coordinates are scaled into screen coordinates which depends on the screen resolution. IOW, different results for larger screens (or screens with different aspect ratios). And for all I know, this may change the curve significantly but this is even harder to test because the rescaling will clip at screen edges and my testing approach hit those very quickly.

Also, neither libinput nor synaptics are that simple, there is some analysis of previous events to adjust the acceleration curve (e.g. on directional changes).
Comment 45 Tim Richardson 2018-04-11 10:37:13 UTC
In 90-libinput-model-quirks.hwdb
the two current rules end with a colon
I don't know the syntax of this file, but there is no other example of this pattern in the file

when I made a separate P50 rule, I did not use a colon at the end, and it worked.

we do see :* at the end of a few rules. 



 libinput:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*:pvrThinkPad??50*:
 libinput:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*:pvrThinkPad??60*:
Comment 46 Tim Richardson 2018-04-11 10:41:11 UTC
sorry wrong bug report
Comment 47 Peter Hutterer 2018-04-24 05:20:02 UTC
Ok, another version to test please:
https://github.com/whot/libinput/tree/wip/touchpad-pointer-accel-v6

Still feels roughly like the macOS one though there are some differences that tbh I can't quite put my finger on. Either way, it feels precise enough, especially at -0.1 (for me).
Comment 48 Nate Graham 2018-04-25 04:12:22 UTC
That feels *fantastic* to me. I'd be very happy to see that in a real release. I've been living with v5 and it was already pretty good. I got used to it fairly quickly. This one is even better.
Comment 49 Peter Hutterer 2018-05-14 07:51:41 UTC
Patch (squashed and polished) is on the list now: https://lists.freedesktop.org/archives/wayland-devel/2018-May/038172.html

The speed range has significantly increased, so this should cover more use-cases.
Comment 50 Nate Graham 2018-05-14 23:12:09 UTC
Being someone who prefers the macOS touchpad acceleration curve, that patch radically improves things for my hardware and motion preferences. Bug thumbs up from me!
Comment 51 Peter Hutterer 2018-05-21 23:09:45 UTC
patch is on master now, thanks for testing!

commit d6e531349745ff38ae457169d5089ea61297accf
Author: Peter Hutterer <>
Date:   Mon Mar 12 15:24:07 2018 +1000

     filter: improve touchpad acceleration
Comment 52 Nate Graham 2018-05-22 03:46:33 UTC
Yep, this is fixed for me. Many thanks for all your hard work, Peter!

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.