Thursday, July 27, 2017

libinput and button debouncing

A few days ago, I pushed code for button debouncing into libinput, scheduled for libinput 1.9. What is button debouncing you ask? Well, I'm glad you asked, because otherwise typing this blog post would've been a waste of time :)

Over in Utopia, when you press the button on a device, you get a press event from the hardware. When you release said button, you get a release event from the hardware. Together, they form the button click interaction we have come to learn and love over the last couple of decades. Life is generally merry and the sunshine to rainbow to lollipop ratio is good. Meanwhile, over here in the real world, buttons can be quite dodgy, don't always work like they're supposed to, lollipops are unhealthy and boy, have you seen that sunburn the sunshine gave me? One way how buttons may not work is that they can lose contact for a fraction of a second and send release events even though the button is being held down. The device usually detects that the button is still being down in the next hardware cycle (~8ms on most devices) and thus sends another button press.

For us, there are not a lot of hints that this is bad hardware besides the timestamps. It's not possible for a user to really release and press a button within 8ms, so we can take this as a signal for dodgy hardware. But at least that's someting. All we need to do is ignore the release event (and subsequent button event) and only release when the button is released properly. This requires timeouts and delays of the event, something we generally want to avoid unless absolutely necessary. So the behaviour libinput has now is enabled but inactive button debouncing on all devices. We monitor button release and button press timestamps, but otherwise leave the events as-is, so no delays are introduced. Only if a device sends release/press combos with unfeasably short timeouts, activate button debouncing. Once active, we filter all button release events and instead set a timer. Once the timer expires, we send the button release event. But if at any time before then another button press is detected, the scheduled release is discarded, the button press is filtered and no event is sent. Thus, we paper over the release/press combo the hardware gives us and to anyone using libinput, it will look like the button was held down for the whole time.

There's one downside with this approach - the very first button debounce to happen on a device will still trigger an erroneous button release event. It remains to be seen whether this is a problem in real-world scenarios. That's the cost of having it as an auto-enabling feature rather than an explicit configuration option.

If you do have a mouse that suffers from button bouncing, I recommend you try libinput's master branch and file any issues if the debouncing doesn't work as it should. Might as well get any issues fixed before we have a release.

9 comments:

Leslie Satenstein said...

Your article is a reminder of what we had to do to debounce contacts

Consider a contact made with a drop of mercury. Mercury conducts.
When mercury joins a metal with a second metal having a microdot or mercury between, the elasticity of mercury does not allow a bounced contact. The contact metal has to retract to at least 1.1 times the diameter of the mercury drop to force the mercury drop to let-go.

A sustained contact was timed for auto-repeat.

Imagine if we could use some conducting non-polluting-non-toxic liquid to make electrical contacts, for example.

Bastian said...

ouuh, perfect timing, my mouse happens to do this sometimes because the button gets somehow stuck occassionally. :-)

Pat said...

Thank you

Lik Doyaya said...

To start testing and using this, is it enough to just install the libinput from the master branch or do I also need to update the Xorg libinput driver and enable this option?

Peter Hutterer said...

@Lik: just updating libinput is enough (provided you're using the xorg libinput driver of course)

Lik Doyaya said...

Thank you for the clarification, it's working now.

Yagamy Light said...

Just curious, did you happen to test an actual hw with alike problem, where debouncing helped? Or is it a hypothetical problem? I'm asking out of pure curiosity about a possibility to stumble upon such issue.

Yagamy Light said...

By the way, one more thought: I know some mice have a "double click" button, I've had one 1.5 year ago. E.g. here's an example of one https://images-na.ssl-images-amazon.com/images/I/41suGcP%2BinL._SX355_.jpg the orange square you see is the button. Will debouncing be okay with them?

Peter Hutterer said...

Yagamy: I don't have hw that reproduces the issue but it was (like most developments in libinput) driven by bug reports of users affected by bad hardware. Fixing hypothetical problems usually causes more headaches than anything and in most cases we need some access to the hw or a reproducer to really fix the problem at the root rather than just papering over it. For the doubleclick buttons: if it breaks please file a bug.