Friday, March 6, 2015

Why libinput doesn't support edge scrolling

Update June 09, 2015: edge scrolling for clickpads has been merged. Will be availble in libinput 0.20. Consider the rest of this post obsolete.

libinput supports edge scrolling since version 0.7.0. Whoops, how does the post title go with this statement? Well, libinput supports edge scrolling, but only on some devices and chances are your touchpad won't be one of them. Bug 89381 is the reference bug here.

First, what is edge scrolling? As the libinput documentation illustrates, it is scrolling triggered by finger movement within specific regions of the touchpad - the left and bottom edges for vertical and horizontal scrolling, respectively. This is in contrast to two-finger scrolling, triggered by a two-finger movement, anywhere on the touchpad. synaptics had edge scrolling since at least 2002, the earliest commit in the repo. Back then we didn't have multitouch-capable touchpads, these days they're the default and you'd be struggling to find one that doesn't support at least two fingers. But back then edge-scrolling was the default, and touchpads even had the markings for those scroll edges painted on.

libinput adds a whole bunch of features to the touchpad driver, but those features make it hard to support edge scrolling. First, libinput has quite smart software button support. Those buttons are usually on the lowest ~10mm of the touchpad. Depending on finger movement and position libinput will send a right button click, movement will be ignored, etc. You can leave one finger in the button area while using another finger on the touchpad to move the pointer. You can press both left and right areas for a middle click. And so on. On many touchpads the vertical travel/physical resistance is enough to trigger a movement every time you click the button, just by your finger's logical center moving.

libinput also has multi-direction scroll support. Traditionally we only sent one scroll event for vertical/horizontal at a time, even going as far as locking the scroll direction. libinput changes this and only requires a initial threshold to start scrolling, after that the caller will get both horizontal and vertical scroll information. The reason is simple: it's context-dependent when horizontal scrolling should be used, so a global toggle to disable doesn't make sense. And libinput's scroll coordinates are much more fine-grained too, which is particularly useful for natural scrolling where you'd expect the content to move with your fingers.

Finally, libinput has smart palm detection. The large majority of palm touches are along the left and right edges of the touchpad and they're usually indistinguishable from finger presses (same pressure values for example). Without palm detection some laptops are unusable (e.g. the T440 series).

These features interfere heavily with edge scrolling. Software button areas are in the same region as the horizontal scroll area, palm presses are in the same region as the vertical edge scroll area. The lower vertical edge scroll zone overlaps with software buttons - and that's where you would put your finger if you'd want to quickly scroll up in a document (or down, for natural scrolling). To support edge scrolling on those touchpads, we'd need heuristics and timeouts to guess when something is a palm, a software button click, a scroll movement, the start of a scroll movement, etc. The heuristics are unreliable, the timeouts reduce responsiveness in the UI. So our decision was to only provide edge scrolling on touchpads where it is required, i.e. those that cannot support two-finger scrolling, those with physical buttons. All other touchpads provide only two-finger scrolling. And we are focusing on making 2 finger scrolling good enough that you don't need/want to use edge scrolling (pls file bugs for anything broken)

Now, before you get too agitated: if edge scrolling is that important to you, invest the time you would otherwise spend sharpening pitchforks, lighting torches and painting picket signs into developing a model that allows us to do reliable edge scrolling in light of all the above, without breaking software buttons, maintaining palm detection. We'd be happy to consider it.

6 comments:

Alex Besogonov said...

Is it possible to turn off palm detection (not a problem for me at all) and leave edge scrolling on?

Also, at least in my configuration software buttons are nowhere near the scroll area.

kparal said...

So much for my habit of keeping my fingers on the keyboard+trackpoint and scrolling with my right thumb (using the edge scroll)... :-/ It's super-comfortable and your hands don't have to move. But the technical difficulties seem to be convincing enough.

Kevin Kofler said...

Given that the conflict with physical buttons is mainly for the horizontal events, how about just enabling only the vertical scrolling, and just handling horizontal scrolling the same way as for one-wheel mice (Alt+scrolling)?

For the conflict between the right button and the scroll area, can't you just make the button stop where the scroll area starts if edge scrolling is enabled?

As for the palm detection thing: You say the syndaemon approach is not possible in Wayland because of the client separation. But wasn't it one of the reasons for libinput to have a single driver handle all input devices so that it sees all of them and can handle interactions between them? So it should be possible to just disable the touchpad while typing within libinput, and in fact, isn't that actually already implemented? In addition, given that not all people need palm detection, a conflict between palm detection and edge scrolling does not seem to be sufficient justification to not even optionally allow enabling edge scrolling on explicit user request. People who enable it either already know about the limitations or will notice them and deal with them.

Peter Hutterer said...

the devil is in the details, as usual. we can't always predict what the finger will do when it moves, so moving from buttons to scroll area and back requires timeouts and heuristics. this is amplified by the fact that when you start scrolling in the button area, the scroll movement is incredibly fast.

libinput already has the hooks similar to how syndaemon works (that's how palm detection works when the trackstick is in use) but disabling the whole touchpad is a bad idea, especially when you want to use modifiers.

so again, we're aware of the simple solutions, it's getting the details right where it gets complicated.

Jon Hyatt said...

I think we should stop over-thinking this and just implement one of the simple solutions. For example, let users enable edge scrolling by disabling the conflicting features. For the interim I have my own simple solution to enable edge scrolling: using the synaptics driver. It works fine for me on a T440p.

Jon Hyatt said...
This comment has been removed by the author.