[PATCH libinput] touchpad: fix clickfinger behavior with a thumb being present

Peter Hutterer peter.hutterer at who-t.net
Mon May 22 02:58:06 UTC 2017


On Fri, May 19, 2017 at 07:32:28PM +0200, Friedrich Schöller wrote:
> With a thumb on the touchpad, a two-finger click was always treated as
> a middle-click. This patch takes the thumb into account and treats the
> click as a right-click, if the touchpad supports tracking of at least
> three fingers.

Looks good, I just have a few nitpicks, because why not ;)

also, please make sure the test-suite succeeds (I haven't checked yet) and
I'd love to have tests to specifically test this new behaviour to make sure
we don't accidentally break it in the future.

> ---
>  src/evdev-mt-touchpad-buttons.c | 90 +++++++++++++++++++++++++++++------------
>  1 file changed, 65 insertions(+), 25 deletions(-)
> 
> diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c
> index 895cf0e..30c2948 100644
> --- a/src/evdev-mt-touchpad-buttons.c
> +++ b/src/evdev-mt-touchpad-buttons.c
> @@ -978,54 +978,94 @@ out:
>  	return within_distance;
>  }
>  
> +static inline bool
> +tp_clickfinger_within_distance_3(struct tp_dispatch *tp,
> +				 struct tp_touch *t1,
> +				 struct tp_touch *t2,
> +				 struct tp_touch *t3)
> +{
> +	if (!t1 || !t2 || !t3)
> +		return false;
> +
> +	double d12 =
> +		(t1->point.x - t2->point.x) * (t1->point.x - t2->point.x) +
> +		(t1->point.y - t2->point.y) * (t1->point.y - t2->point.y);
> +	double d23 =
> +		(t2->point.x - t3->point.x) * (t2->point.x - t3->point.x) +
> +		(t2->point.y - t3->point.y) * (t2->point.y - t3->point.y);
> +	double d31 =
> +		(t3->point.x - t1->point.x) * (t3->point.x - t1->point.x) +
> +		(t3->point.y - t1->point.y) * (t3->point.y - t1->point.y);

this is a classic source of errors for copy/paste and x/y mixups, please
#define a macro that you can call three times to avoid that (or a static
inline that takes two struct points).

> +
> +	if (d12 > d23 && d12 > d31) {
> +		return tp_clickfinger_within_distance(tp, t2, t3) &&
> +		       tp_clickfinger_within_distance(tp, t3, t1);
> +	}
> +
> +	if (d23 > d31 && d23 > d12) {
> +		return tp_clickfinger_within_distance(tp, t3, t1) &&
> +		       tp_clickfinger_within_distance(tp, t1, t2);
> +	}
> +
> +	return tp_clickfinger_within_distance(tp, t1, t2) &&
> +	       tp_clickfinger_within_distance(tp, t2, t3);

this is a bit confusing. I get that you're always measuring the distance
between the two closest two, but have a look at the close_touches bits
removed in  316f30d2f28b62f90efc2bdd9e6f3d83116070e7. It always calculates
all three, but I think it's easier to read.

Cheers,
   Peter

> +}
> +
>  static uint32_t
>  tp_clickfinger_set_button(struct tp_dispatch *tp)
>  {
> -	uint32_t button;
> +	bool thumb_detected = false;
>  	unsigned int nfingers = tp->nfingers_down;
>  	struct tp_touch *t;
>  	struct tp_touch *first = NULL,
> -			*second = NULL;
> +	                *second = NULL,
> +	                *third = NULL;
>  
> -	if (nfingers != 2)
> -		goto out;
> +	if (nfingers < 2)
> +		return BTN_LEFT;
> +	if (nfingers > 3)
> +		return BTN_MIDDLE;
> +
> +	/* Thumb detection is unreliable if the number of fingers on the
> +	 * touchpad is greater than the number of touches that can be
> +	 * tracked. */
> +	if (nfingers == 3 && tp->num_slots < 3)
> +		return BTN_MIDDLE;
>  
> -	/* two fingers down on the touchpad. Check for distance
> -	 * between the fingers. */
>  	tp_for_each_touch(tp, t) {
>  		if (t->state != TOUCH_BEGIN && t->state != TOUCH_UPDATE)
>  			continue;
>  
> -		if (t->thumb.state == THUMB_STATE_YES)
> +		if (t->thumb.state == THUMB_STATE_YES) {
> +			thumb_detected = true;
>  			continue;
> +		}
>  
>  		if (!first)
>  			first = t;
>  		else if (!second)
>  			second = t;
> +		else if (!third)
> +			third = t;
>  	}
>  
> -	if (!first || !second) {
> -		nfingers = 1;
> -		goto out;
> -	}
> +	if (nfingers == 2) {
> +		if (thumb_detected)
> +			return BTN_LEFT;
>  
> -	if (tp_clickfinger_within_distance(tp, first, second))
> -		nfingers = 2;
> -	else
> -		nfingers = 1;
> +		if (tp_clickfinger_within_distance(tp, first, second))
> +			return BTN_RIGHT;
> +		else
> +			return BTN_LEFT;
> +	} else {
> +		if (thumb_detected)
> +			return BTN_RIGHT;
>  
> -out:
> -	switch (nfingers) {
> -	case 0:
> -	case 1: button = BTN_LEFT; break;
> -	case 2: button = BTN_RIGHT; break;
> -	default:
> -		button = BTN_MIDDLE; break;
> -		break;
> +		if (tp_clickfinger_within_distance_3(tp, first, second, third))
> +			return BTN_MIDDLE;
> +		else
> +			return BTN_RIGHT;
>  	}
> -
> -	return button;
>  }
>  
>  static int
> -- 
> 2.9.4
> 


More information about the wayland-devel mailing list