[PATCH libinput 6/6] tablet: add touch arbitration

Jason Gerecke killertofu at gmail.com
Thu Sep 1 22:48:39 UTC 2016


The first 5 patches look fine, but I have a few questions about this
one, especially in the unit tests:

On 08/21/2016 11:14 PM, Peter Hutterer wrote:
> So far we've relied on the wacom kernel module to do touch arbitration for us
> but that won't be the case in upcoming kernels. Implement touch arbitration in
> userspace by pairing the two devices and suspending the touch device whenever
> a tool comes into proximity.
> 
> In the future more sophisticated arbitration can be done (e.g. only touches
> which are close to the pen) but let's burn that bridge when we have to cross
> it.
> 
> Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
> ---
>  doc/tablet-support.dox  |  12 ++
>  src/evdev-mt-touchpad.c |  18 +++
>  src/evdev-tablet-pad.c  |   1 +
>  src/evdev-tablet.c      |  80 ++++++++++-
>  src/evdev-tablet.h      |   3 +
>  src/evdev.c             |  15 +++
>  src/evdev.h             |   4 +
>  test/tablet.c           | 352 ++++++++++++++++++++++++++++++++++++++++++++++++
>  8 files changed, 482 insertions(+), 3 deletions(-)
> 
> diff --git a/doc/tablet-support.dox b/doc/tablet-support.dox
> index cda0d70..839924b 100644
> --- a/doc/tablet-support.dox
> +++ b/doc/tablet-support.dox
> @@ -331,4 +331,16 @@ button and ring events on the right. When one of the three mode toggle
>  buttons on the right is pressed, the right mode switches to that button's
>  mode but the left mode remains unchanged.
>  
> + at section tablet-touch-arbitration Tablet touch arbitration
> +
> +"Touch arbitration" is the terminology used when touch events are suppressed
> +while the pen is in proximity. Since it is almost impossible to use a stylus
> +or other tool without triggering touches with the hand holding the tool,
> +touch arbitration serves to reduce the number of accidental inputs.
> +The wacom kernel driver provides touch arbitration but for other devices
> +arbitration has to be done in userspace.
> +
> +libinput uses the @ref libinput_device_group to decide on touch arbitration
> +and automatically discards touch events whenever a tool is in proximity.
> +
>  */
> diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
> index 3baed09..cbcac8a 100644
> --- a/src/evdev-mt-touchpad.c
> +++ b/src/evdev-mt-touchpad.c
> @@ -1679,6 +1679,23 @@ evdev_tag_touchpad(struct evdev_device *device,
>  	}
>  }
>  
> +static void
> +tp_interface_toggle_touch(struct evdev_dispatch *dispatch,
> +			  struct evdev_device *device,
> +			  bool enable)
> +{
> +	struct tp_dispatch *tp = (struct tp_dispatch*)dispatch;
> +
> +	if (enable != tp->device->is_suspended)
> +		return;
> +
> +	if (enable)
> +		tp_resume(tp, device);
> +	else
> +		tp_suspend(tp, device);
> +
> +}
> +
>  static struct evdev_dispatch_interface tp_interface = {
>  	tp_interface_process,
>  	tp_interface_suspend,
> @@ -1689,6 +1706,7 @@ static struct evdev_dispatch_interface tp_interface = {
>  	tp_interface_device_removed, /* device_suspended, treat as remove */
>  	tp_interface_device_added,   /* device_resumed, treat as add */
>  	NULL,                        /* post_added */
> +	tp_interface_toggle_touch,
>  };
>  
>  static void
> diff --git a/src/evdev-tablet-pad.c b/src/evdev-tablet-pad.c
> index 0e95408..82542bc 100644
> --- a/src/evdev-tablet-pad.c
> +++ b/src/evdev-tablet-pad.c
> @@ -512,6 +512,7 @@ static struct evdev_dispatch_interface pad_interface = {
>  	NULL, /* device_suspended */
>  	NULL, /* device_resumed */
>  	NULL, /* post_added */
> +	NULL, /* toggle_touch */
>  };
>  
>  static void
> diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
> index 8f24555..4a2cae5 100644
> --- a/src/evdev-tablet.c
> +++ b/src/evdev-tablet.c
> @@ -1422,6 +1422,39 @@ tablet_flush(struct tablet_dispatch *tablet,
>  }
>  
>  static inline void
> +tablet_set_touch_device_enabled(struct evdev_device *touch_device,
> +				bool enable)
> +{
> +	struct evdev_dispatch *dispatch;
> +
> +	if (touch_device == NULL)
> +		return;
> +
> +	dispatch = touch_device->dispatch;
> +	if (dispatch->interface->toggle_touch)
> +		dispatch->interface->toggle_touch(dispatch,
> +						  touch_device,
> +						  enable);
> +}
> +
> +static inline void
> +tablet_toggle_touch_device(struct tablet_dispatch *tablet,
> +			   struct evdev_device *tablet_device)
> +{
> +	bool enable_events;
> +
> +	enable_events = tablet_has_status(tablet,
> +					  TABLET_TOOL_OUT_OF_RANGE) ||
> +			tablet_has_status(tablet, TABLET_NONE) ||
> +			tablet_has_status(tablet,
> +					  TABLET_TOOL_LEAVING_PROXIMITY) ||
> +			tablet_has_status(tablet,
> +					  TABLET_TOOL_OUT_OF_PROXIMITY);
> +
> +	tablet_set_touch_device_enabled(tablet->touch_device, enable_events);
> +}
> +
> +static inline void
>  tablet_reset_state(struct tablet_dispatch *tablet)
>  {
>  	/* Update state */
> @@ -1454,6 +1487,7 @@ tablet_process(struct evdev_dispatch *dispatch,
>  		break;
>  	case EV_SYN:
>  		tablet_flush(tablet, device, time);
> +		tablet_toggle_touch_device(tablet, device);
>  		tablet_reset_state(tablet);
>  		break;
>  	default:
> @@ -1466,6 +1500,16 @@ tablet_process(struct evdev_dispatch *dispatch,
>  }
>  
>  static void
> +tablet_suspend(struct evdev_dispatch *dispatch,
> +	       struct evdev_device *device)
> +{
> +	struct tablet_dispatch *tablet =
> +		(struct tablet_dispatch *)dispatch;
> +
> +	tablet_set_touch_device_enabled(tablet->touch_device, true);

If the touch device was already suspended for some reason, doesn't this
mean that suspending the pen will suddenly un-suspend it? I suppose if
the only way touch can be suspended is via arbitration then this will
work, but it could change down the road...

> +}
> +
> +static void
>  tablet_destroy(struct evdev_dispatch *dispatch)
>  {
>  	struct tablet_dispatch *tablet =
> @@ -1480,6 +1524,35 @@ tablet_destroy(struct evdev_dispatch *dispatch)
>  }
>  
>  static void
> +tablet_device_added(struct evdev_device *device,
> +		    struct evdev_device *added_device)
> +{
> +	struct tablet_dispatch *tablet =
> +		(struct tablet_dispatch*)device->dispatch;
> +
> +	if (libinput_device_get_device_group(&device->base) !=
> +	    libinput_device_get_device_group(&added_device->base))
> +		return;
> +
> +	/* Touch screens or external touchpads only */
> +	if (evdev_device_has_capability(added_device, LIBINPUT_DEVICE_CAP_TOUCH) ||
> +	    (evdev_device_has_capability(added_device, LIBINPUT_DEVICE_CAP_POINTER) &&
> +	     (added_device->tags & EVDEV_TAG_EXTERNAL_TOUCHPAD)))
> +	    tablet->touch_device = added_device;
> +}
> +
> +static void
> +tablet_device_removed(struct evdev_device *device,
> +		      struct evdev_device *removed_device)
> +{
> +	struct tablet_dispatch *tablet =
> +		(struct tablet_dispatch*)device->dispatch;
> +
> +	if (tablet->touch_device == removed_device)
> +		tablet->touch_device = NULL;
> +}
> +
> +static void
>  tablet_check_initial_proximity(struct evdev_device *device,
>  			       struct evdev_dispatch *dispatch)
>  {
> @@ -1520,14 +1593,15 @@ tablet_check_initial_proximity(struct evdev_device *device,
>  
>  static struct evdev_dispatch_interface tablet_interface = {
>  	tablet_process,
> -	NULL, /* suspend */
> +	tablet_suspend,
>  	NULL, /* remove */
>  	tablet_destroy,
> -	NULL, /* device_added */
> -	NULL, /* device_removed */
> +	tablet_device_added,
> +	tablet_device_removed,
>  	NULL, /* device_suspended */
>  	NULL, /* device_resumed */
>  	tablet_check_initial_proximity,
> +	NULL, /* toggle_touch */
>  };
>  
>  static void
> diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h
> index f66de5d..2279e03 100644
> --- a/src/evdev-tablet.h
> +++ b/src/evdev-tablet.h
> @@ -71,6 +71,9 @@ struct tablet_dispatch {
>  	uint32_t cursor_proximity_threshold;
>  
>  	struct libinput_device_config_calibration calibration;
> +
> +	/* The paired touch device on devices with both pen & touch */
> +	struct evdev_device *touch_device;
>  };
>  
>  static inline enum libinput_tablet_tool_axis
> diff --git a/src/evdev.c b/src/evdev.c
> index 0e506bc..f9697ae 100644
> --- a/src/evdev.c
> +++ b/src/evdev.c
> @@ -319,6 +319,20 @@ evdev_device_transform_y(struct evdev_device *device,
>  	return scale_axis(device->abs.absinfo_y, y, height);
>  }
>  
> +static void
> +fallback_toggle_touch(struct evdev_dispatch *evdev_dispatch,
> +		      struct evdev_device *device,
> +		      bool enable)
> +{
> +	if (enable != device->is_suspended)
> +		return;
> +
> +	if (enable)
> +		evdev_device_resume(device);
> +	else
> +		evdev_device_suspend(device);
> +}
> +
>  static inline void
>  normalize_delta(struct evdev_device *device,
>  		const struct device_coords *delta,
> @@ -1232,6 +1246,7 @@ struct evdev_dispatch_interface fallback_interface = {
>  	NULL, /* device_suspended */
>  	NULL, /* device_resumed */
>  	NULL, /* post_added */
> +	fallback_toggle_touch, /* toggle_touch */
>  };
>  
>  static uint32_t
> diff --git a/src/evdev.h b/src/evdev.h
> index 1a2f1ff..805cb6a 100644
> --- a/src/evdev.h
> +++ b/src/evdev.h
> @@ -264,6 +264,10 @@ struct evdev_dispatch_interface {
>  	 * was sent */
>  	void (*post_added)(struct evdev_device *device,
>  			   struct evdev_dispatch *dispatch);
> +
> +	void (*toggle_touch)(struct evdev_dispatch *dispatch,
> +			     struct evdev_device *device,
> +			     bool enable);
>  };
>  
>  struct evdev_dispatch {
> diff --git a/test/tablet.c b/test/tablet.c
> index c6886b0..d2f710f 100644
> --- a/test/tablet.c
> +++ b/test/tablet.c
> @@ -3670,6 +3670,348 @@ START_TEST(relative_calibration)
>  }
>  END_TEST
>  
> +START_TEST(intuos_touch_arbitration)
> +{
> +	struct litest_device *dev = litest_current_device();
> +	struct litest_device *finger;
> +	struct libinput *li = dev->libinput;
> +	struct axis_replacement axes[] = {
> +		{ ABS_DISTANCE, 10 },
> +		{ ABS_PRESSURE, 0 },
> +		{ -1, -1 }
> +	};
> +
> +	litest_tablet_proximity_in(dev, 10, 10, axes);
> +	litest_drain_events(li);
> +
> +	finger = litest_add_device(li, LITEST_WACOM_FINGER);
> +	litest_drain_events(li);
> +
> +	litest_tablet_proximity_in(dev, 10, 10, axes);

Isn't this proximity event (or the first prox/drain sequence above)
redundant? Similar "redundant" events occur multiple times below, so its
hard to tell if they are or if its just copy/paste :)

> +	litest_tablet_motion(dev, 10, 10, axes);
> +	litest_tablet_motion(dev, 20, 40, axes);
> +	litest_drain_events(li);
> +
> +	litest_touch_down(finger, 0, 30, 30);
> +	litest_touch_move_to(finger, 0, 30, 30, 80, 80, 10, 1);
> +	litest_touch_up(finger, 0);
> +	litest_assert_empty_queue(li);
> +
> +	litest_tablet_motion(dev, 10, 10, axes);
> +	litest_tablet_motion(dev, 20, 40, axes);
> +	litest_assert_only_typed_events(li,
> +					LIBINPUT_EVENT_TABLET_TOOL_AXIS);
> +
> +	litest_delete_device(finger);
> +}
> +END_TEST
> +
> +START_TEST(intuos_touch_arbitration_stop_touch)
> +{
> +	struct litest_device *dev = litest_current_device();
> +	struct litest_device *finger;
> +	struct libinput *li = dev->libinput;
> +	struct axis_replacement axes[] = {
> +		{ ABS_DISTANCE, 10 },
> +		{ ABS_PRESSURE, 0 },
> +		{ -1, -1 }
> +	};
> +
> +	finger = litest_add_device(li, LITEST_WACOM_FINGER);
> +	litest_touch_down(finger, 0, 30, 30);
> +	litest_touch_move_to(finger, 0, 30, 30, 80, 80, 10, 1);
> +
> +	litest_tablet_proximity_in(dev, 10, 10, axes);
> +	litest_drain_events(li);
> +
> +	litest_tablet_proximity_in(dev, 10, 10, axes);
> +	litest_tablet_motion(dev, 10, 10, axes);
> +	litest_tablet_motion(dev, 20, 40, axes);
> +	litest_drain_events(li);
> +
> +	litest_touch_move_to(finger, 0, 80, 80, 30, 30, 10, 1);
> +	litest_assert_empty_queue(li);

For what its worth, this might not always be the ideal form of
arbitration. It matches what the kernel does (and we haven't heard any
complaints), but another option would be to allow the currently-in-prox
device to suspend its sibling even if that happens to mean touch
suspends pen. Its may be more useful on devices which can sense the pen
at greater distances (where you don't want to stop a deliberate touch
due to a pen held in the same hand at the edge of proximity) and is the
approach taken by xf86-input-wacom.

Just something to consider if you feel like experimenting with the
arbitration's "feel".

> +
> +	litest_tablet_motion(dev, 10, 10, axes);
> +	litest_tablet_motion(dev, 20, 40, axes);
> +	litest_assert_only_typed_events(li,
> +					LIBINPUT_EVENT_TABLET_TOOL_AXIS);
> +	litest_tablet_proximity_out(dev);
> +	litest_drain_events(li);
> +
> +	/* Finger needs to be lifted for events to happen*/
> +	litest_touch_move_to(finger, 0, 30, 30, 80, 80, 10, 1);
> +	litest_assert_empty_queue(li);
> +	litest_touch_up(finger, 0);
> +
> +	litest_touch_down(finger, 0, 30, 30);
> +	litest_touch_move_to(finger, 0, 30, 30, 80, 80, 10, 1);
> +	litest_touch_up(finger, 0);
> +
> +	litest_assert_only_typed_events(li,
> +					LIBINPUT_EVENT_POINTER_MOTION);
> +
> +	litest_delete_device(finger);
> +}
> +END_TEST
> +
> +START_TEST(intuos_touch_arbitration_remove_touch)
> +{
> +	struct litest_device *dev = litest_current_device();
> +	struct litest_device *finger;
> +	struct libinput *li = dev->libinput;
> +	struct axis_replacement axes[] = {
> +		{ ABS_DISTANCE, 10 },
> +		{ ABS_PRESSURE, 0 },
> +		{ -1, -1 }
> +	};
> +
> +	finger = litest_add_device(li, LITEST_WACOM_FINGER);
> +	litest_touch_down(finger, 0, 30, 30);
> +	litest_touch_move_to(finger, 0, 30, 30, 80, 80, 10, 1);
> +
> +	litest_tablet_proximity_in(dev, 10, 10, axes);
> +	litest_drain_events(li);
> +
> +	litest_delete_device(finger);
> +
> +	litest_tablet_proximity_in(dev, 10, 10, axes);

Another possibly redundant prox-in?

> +	litest_tablet_motion(dev, 10, 10, axes);
> +	litest_tablet_motion(dev, 20, 40, axes);
> +	litest_drain_events(li);
> +

Doesn't draining the events here mean that any events which were
erroneously genererated by the (suspended) touch device after the pen
entered prox will be removed before the assert below can complain?

> +	litest_tablet_motion(dev, 10, 10, axes);
> +	litest_tablet_motion(dev, 20, 40, axes);
> +	litest_assert_only_typed_events(li,
> +					LIBINPUT_EVENT_TABLET_TOOL_AXIS);
> +}
> +END_TEST
> +
> +START_TEST(intuos_touch_arbitration_remove_tablet)
> +{
> +	struct litest_device *dev = litest_current_device();
> +	struct litest_device *tablet;
> +	struct libinput *li = dev->libinput;
> +	struct axis_replacement axes[] = {
> +		{ ABS_DISTANCE, 10 },
> +		{ ABS_PRESSURE, 0 },
> +		{ -1, -1 }
> +	};
> +
> +	tablet = litest_add_device(li, LITEST_WACOM_INTUOS);
> +	libinput_dispatch(li);
> +	litest_tablet_proximity_in(tablet, 10, 10, axes);
> +	litest_tablet_motion(tablet, 10, 10, axes);
> +	litest_tablet_motion(tablet, 20, 40, axes);
> +	litest_drain_events(li);
> +
> +	litest_touch_down(dev, 0, 30, 30);
> +	litest_touch_move_to(dev, 0, 30, 30, 80, 80, 10, 1);
> +	litest_assert_empty_queue(li);
> +
> +	litest_delete_device(tablet);
> +	litest_assert_only_typed_events(li, LIBINPUT_EVENT_DEVICE_REMOVED);
> +
> +	/* Touch is still down, don't enable */
> +	litest_touch_move_to(dev, 0, 80, 80, 30, 30, 10, 1);
> +	litest_touch_up(dev, 0);
> +	litest_assert_empty_queue(li);
> +
> +	litest_touch_down(dev, 0, 30, 30);
> +	litest_touch_move_to(dev, 0, 30, 30, 80, 80, 10, 1);
> +	litest_touch_up(dev, 0);
> +	litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
> +}
> +END_TEST
> +
> +START_TEST(cintiq_touch_arbitration)
> +{
> +	struct litest_device *dev = litest_current_device();
> +	struct litest_device *finger;
> +	struct libinput *li = dev->libinput;
> +	struct axis_replacement axes[] = {
> +		{ ABS_DISTANCE, 10 },
> +		{ ABS_PRESSURE, 0 },
> +		{ -1, -1 }
> +	};
> +
> +	litest_tablet_proximity_in(dev, 10, 10, axes);
> +	litest_drain_events(li);
> +
> +	finger = litest_add_device(li, LITEST_WACOM_CINTIQ_13HDT_FINGER);
> +	litest_drain_events(li);
> +
> +	litest_tablet_proximity_in(dev, 10, 10, axes);

Another possibly redundant prox-in?

> +	litest_tablet_motion(dev, 10, 10, axes);
> +	litest_tablet_motion(dev, 20, 40, axes);
> +	litest_drain_events(li);
> +
> +	litest_touch_down(finger, 0, 30, 30);
> +	litest_touch_move_to(finger, 0, 30, 30, 80, 80, 10, 1);
> +	litest_touch_up(finger, 0);
> +	litest_assert_empty_queue(li);
> +
> +	litest_tablet_motion(dev, 10, 10, axes);
> +	litest_tablet_motion(dev, 20, 40, axes);
> +	litest_assert_only_typed_events(li,
> +					LIBINPUT_EVENT_TABLET_TOOL_AXIS);
> +
> +	litest_delete_device(finger);
> +}
> +END_TEST
> +
> +START_TEST(cintiq_touch_arbitration_stop_touch)
> +{
> +	struct litest_device *dev = litest_current_device();
> +	struct litest_device *finger;
> +	struct libinput *li = dev->libinput;
> +	struct libinput_event *event;
> +	struct axis_replacement axes[] = {
> +		{ ABS_DISTANCE, 10 },
> +		{ ABS_PRESSURE, 0 },
> +		{ -1, -1 }
> +	};
> +
> +	finger = litest_add_device(li, LITEST_WACOM_CINTIQ_13HDT_FINGER);
> +	litest_touch_down(finger, 0, 30, 30);
> +	litest_touch_move_to(finger, 0, 30, 30, 80, 80, 10, 1);
> +
> +	litest_tablet_proximity_in(dev, 10, 10, axes);
> +	litest_drain_events(li);
> +
> +	litest_tablet_proximity_in(dev, 10, 10, axes);

Another possibly redundant prox-in?

> +	litest_tablet_motion(dev, 10, 10, axes);
> +	litest_tablet_motion(dev, 20, 40, axes);
> +	litest_drain_events(li);
> +
> +	litest_touch_move_to(finger, 0, 80, 80, 30, 30, 10, 1);
> +	litest_assert_empty_queue(li);
> +
> +	litest_tablet_motion(dev, 10, 10, axes);
> +	litest_tablet_motion(dev, 20, 40, axes);
> +	litest_assert_only_typed_events(li,
> +					LIBINPUT_EVENT_TABLET_TOOL_AXIS);
> +	litest_tablet_proximity_out(dev);
> +	litest_drain_events(li);
> +
> +	/* Finger needs to be lifted for events to happen*/
> +	litest_touch_move_to(finger, 0, 30, 30, 80, 80, 10, 1);
> +	litest_assert_empty_queue(li);
> +	litest_touch_up(finger, 0);
> +
> +	litest_touch_down(finger, 0, 30, 30);
> +	litest_touch_move_to(finger, 0, 30, 30, 80, 80, 10, 1);
> +	libinput_dispatch(li);
> +
> +	event = libinput_get_event(li);
> +	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_DOWN);
> +	libinput_event_destroy(event);
> +	event = libinput_get_event(li);
> +	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
> +	libinput_event_destroy(event);
> +
> +	while ((event = libinput_get_event(li)) != NULL) {
> +		litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_MOTION);
> +		libinput_event_destroy(event);
> +		event = libinput_get_event(li);
> +		litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
> +		libinput_event_destroy(event);
> +	}
> +
> +	litest_touch_up(finger, 0);
> +	libinput_dispatch(li);
> +	event = libinput_get_event(li);
> +	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_UP);
> +	libinput_event_destroy(event);
> +	event = libinput_get_event(li);
> +	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
> +	libinput_event_destroy(event);
> +
> +	litest_delete_device(finger);
> +}
> +END_TEST
> +
> +START_TEST(cintiq_touch_arbitration_remove_touch)
> +{
> +	struct litest_device *dev = litest_current_device();
> +	struct litest_device *finger;
> +	struct libinput *li = dev->libinput;
> +	struct axis_replacement axes[] = {
> +		{ ABS_DISTANCE, 10 },
> +		{ ABS_PRESSURE, 0 },
> +		{ -1, -1 }
> +	};
> +
> +	finger = litest_add_device(li, LITEST_WACOM_CINTIQ_13HDT_FINGER);
> +	litest_touch_down(finger, 0, 30, 30);
> +	litest_touch_move_to(finger, 0, 30, 30, 80, 80, 10, 1);
> +
> +	litest_tablet_proximity_in(dev, 10, 10, axes);
> +	litest_drain_events(li);
> +
> +	litest_delete_device(finger);
> +	litest_drain_events(li);

Another case where 'litest_drain_events' may be defeating the assert below?

Jason
---
Now instead of four in the eights place /
you’ve got three, ‘Cause you added one /
(That is to say, eight) to the two, /
But you can’t take seven from three, /
So you look at the sixty-fours....

> +
> +	litest_tablet_motion(dev, 10, 10, axes);
> +	litest_tablet_motion(dev, 20, 40, axes);
> +
> +	litest_assert_only_typed_events(li,
> +					LIBINPUT_EVENT_TABLET_TOOL_AXIS);
> +}
> +END_TEST
> +
> +START_TEST(cintiq_touch_arbitration_remove_tablet)
> +{
> +	struct litest_device *dev = litest_current_device();
> +	struct litest_device *tablet;
> +	struct libinput *li = dev->libinput;
> +	struct libinput_event *event;
> +	struct axis_replacement axes[] = {
> +		{ ABS_DISTANCE, 10 },
> +		{ ABS_PRESSURE, 0 },
> +		{ -1, -1 }
> +	};
> +
> +	tablet = litest_add_device(li, LITEST_WACOM_CINTIQ_13HDT_PEN);
> +	litest_touch_down(dev, 0, 30, 30);
> +	litest_touch_move_to(dev, 0, 30, 30, 80, 80, 10, 1);
> +
> +	litest_tablet_proximity_in(tablet, 10, 10, axes);
> +	litest_tablet_motion(tablet, 10, 10, axes);
> +	litest_drain_events(li);
> +
> +	litest_delete_device(tablet);
> +	litest_assert_only_typed_events(li, LIBINPUT_EVENT_DEVICE_REMOVED);
> +
> +	/* Touch is still down, don't enable */
> +	litest_touch_move_to(dev, 0, 80, 80, 30, 30, 10, 1);
> +	litest_touch_up(dev, 0);
> +	litest_assert_empty_queue(li);
> +
> +	litest_touch_down(dev, 0, 30, 30);
> +	libinput_dispatch(li);
> +
> +	event = libinput_get_event(li);
> +	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_DOWN);
> +	libinput_event_destroy(event);
> +
> +	event = libinput_get_event(li);
> +	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
> +	libinput_event_destroy(event);
> +
> +	litest_touch_move_to(dev, 0, 30, 30, 80, 80, 10, 1);
> +	libinput_dispatch(li);
> +
> +	event = libinput_get_event(li);
> +	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_MOTION);
> +	libinput_event_destroy(event);
> +
> +	event = libinput_get_event(li);
> +	litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME);
> +	libinput_event_destroy(event);
> +}
> +END_TEST
> +
>  void
>  litest_setup_tests_tablet(void)
>  {
> @@ -3746,4 +4088,14 @@ litest_setup_tests_tablet(void)
>  	litest_add("tablet:relative", relative_no_delta_prox_in, LITEST_TABLET, LITEST_ANY);
>  	litest_add("tablet:relative", relative_delta, LITEST_TABLET, LITEST_ANY);
>  	litest_add("tablet:relative", relative_calibration, LITEST_TABLET, LITEST_ANY);
> +
> +	litest_add_for_device("tablet:touch-arbitration", intuos_touch_arbitration, LITEST_WACOM_INTUOS);
> +	litest_add_for_device("tablet:touch-arbitration", intuos_touch_arbitration_stop_touch, LITEST_WACOM_INTUOS);
> +	litest_add_for_device("tablet:touch-arbitration", intuos_touch_arbitration_remove_touch, LITEST_WACOM_INTUOS);
> +	litest_add_for_device("tablet:touch-arbitration", intuos_touch_arbitration_remove_tablet, LITEST_WACOM_FINGER);
> +
> +	litest_add_for_device("tablet:touch-arbitration", cintiq_touch_arbitration, LITEST_WACOM_CINTIQ_13HDT_PEN);
> +	litest_add_for_device("tablet:touch-arbitration", cintiq_touch_arbitration_stop_touch, LITEST_WACOM_CINTIQ_13HDT_PEN);
> +	litest_add_for_device("tablet:touch-arbitration", cintiq_touch_arbitration_remove_touch, LITEST_WACOM_CINTIQ_13HDT_PEN);
> +	litest_add_for_device("tablet:touch-arbitration", cintiq_touch_arbitration_remove_tablet, LITEST_WACOM_CINTIQ_13HDT_FINGER);
>  }
> 


More information about the wayland-devel mailing list