On 09/05/2016 06:04 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.
> 
> Note that touch arbitration is "device suspend light", i.e. we leave the
> device enabled and the fd is active. Tablet interactions are comparatively
> short-lived, so closing the fd and asking logind for a new one every time the
> pen changes proximity is suboptimal. Instead, we just keep a boolean around
> and discard all events while it is set.
> 
> Signed-off-by: Peter Hutterer <[email protected]>

The revised series looks good to me -- thanks again :)

Reviewed-by: Jason Gerecke <[email protected]>

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....

> ---
> Changes to v1:
> - drop the previous evdev_device_suspend() approach and use a ignore_events
>   boolean in the dispatch instead.
> - add test for suspending/resuming the touch device during arbitration
> - use a common helper for each arbitration test. the tests only differ in
>   the second device created and what events we expect so let's re-use
>   everything else
> 
>  doc/tablet-support.dox  |  13 ++
>  src/evdev-mt-touchpad.c |  21 +++
>  src/evdev-mt-touchpad.h |   4 +
>  src/evdev-tablet-pad.c  |   1 +
>  src/evdev-tablet.c      |  80 ++++++++++-
>  src/evdev-tablet.h      |   3 +
>  src/evdev.c             |  21 +++
>  src/evdev.h             |   8 ++
>  test/tablet.c           | 344 
> ++++++++++++++++++++++++++++++++++++++++++++++++
>  9 files changed, 492 insertions(+), 3 deletions(-)
> 
> diff --git a/doc/tablet-support.dox b/doc/tablet-support.dox
> index cda0d70..19c5d8f 100644
> --- a/doc/tablet-support.dox
> +++ b/doc/tablet-support.dox
> @@ -331,4 +331,17 @@ 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.
>  
> +@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 currently 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.
> +The exact behavior is device-dependent.
> +
>  */
> diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
> index 65b0abf..2354061 100644
> --- a/src/evdev-mt-touchpad.c
> +++ b/src/evdev-mt-touchpad.c
> @@ -1165,6 +1165,9 @@ tp_interface_process(struct evdev_dispatch *dispatch,
>       struct tp_dispatch *tp =
>               (struct tp_dispatch *)dispatch;
>  
> +     if (tp->ignore_events)
> +             return;
> +
>       switch (e->type) {
>       case EV_ABS:
>               if (tp->has_mt)
> @@ -1679,6 +1682,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;
> +     bool ignore_events = !enable;
> +
> +     if (ignore_events == tp->ignore_events)
> +             return;
> +
> +     if (ignore_events)
> +             tp_clear_state(tp);
> +
> +     tp->ignore_events = ignore_events;
> +}
> +
>  static struct evdev_dispatch_interface tp_interface = {
>       tp_interface_process,
>       tp_interface_suspend,
> @@ -1689,6 +1709,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-mt-touchpad.h b/src/evdev-mt-touchpad.h
> index 8a8d2db..de9bdb5 100644
> --- a/src/evdev-mt-touchpad.h
> +++ b/src/evdev-mt-touchpad.h
> @@ -231,6 +231,10 @@ struct tp_dispatch {
>       bool semi_mt;
>       bool reports_distance;                  /* does the device support true 
> hovering */
>  
> +     /* true if we're reading events (i.e. not suspended) but we're
> +      * ignoring them */
> +     bool ignore_events;
> +
>       unsigned int num_slots;                 /* number of slots */
>       unsigned int ntouches;                  /* no slots inc. fakes */
>       struct tp_touch *touches;               /* len == ntouches */
> 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 254d669..14023b6 100644
> --- a/src/evdev-tablet.c
> +++ b/src/evdev-tablet.c
> @@ -1434,6 +1434,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 */
> @@ -1466,6 +1499,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:
> @@ -1478,6 +1512,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);
> +}
> +
> +static void
>  tablet_destroy(struct evdev_dispatch *dispatch)
>  {
>       struct tablet_dispatch *tablet =
> @@ -1492,6 +1536,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)
>  {
> @@ -1532,14 +1605,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 3b48c3e..03384c8 100644
> --- a/src/evdev.c
> +++ b/src/evdev.c
> @@ -1055,6 +1055,9 @@ fallback_process(struct evdev_dispatch *evdev_dispatch,
>       struct fallback_dispatch *dispatch = (struct 
> fallback_dispatch*)evdev_dispatch;
>       enum evdev_event_type sent;
>  
> +     if (dispatch->ignore_events)
> +             return;
> +
>       switch (event->type) {
>       case EV_REL:
>               fallback_process_relative(dispatch, device, event, time);
> @@ -1184,6 +1187,23 @@ fallback_suspend(struct evdev_dispatch *evdev_dispatch,
>  }
>  
>  static void
> +fallback_toggle_touch(struct evdev_dispatch *evdev_dispatch,
> +                   struct evdev_device *device,
> +                   bool enable)
> +{
> +     struct fallback_dispatch *dispatch = (struct 
> fallback_dispatch*)evdev_dispatch;
> +     bool ignore_events = !enable;
> +
> +     if (ignore_events == dispatch->ignore_events)
> +             return;
> +
> +     if (ignore_events)
> +             fallback_return_to_neutral_state(dispatch, device);
> +
> +     dispatch->ignore_events = ignore_events;
> +}
> +
> +static void
>  fallback_destroy(struct evdev_dispatch *evdev_dispatch)
>  {
>       struct fallback_dispatch *dispatch = (struct 
> fallback_dispatch*)evdev_dispatch;
> @@ -1243,6 +1263,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 10b0e58..b240615 100644
> --- a/src/evdev.h
> +++ b/src/evdev.h
> @@ -265,6 +265,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 {
> @@ -308,6 +312,10 @@ struct fallback_dispatch {
>       unsigned long hw_key_mask[NLONGS(KEY_CNT)];
>  
>       enum evdev_event_type pending_event;
> +
> +     /* true if we're reading events (i.e. not suspended) but we're
> +        ignoring them */
> +     bool ignore_events;
>  };
>  
>  struct evdev_device *
> diff --git a/test/tablet.c b/test/tablet.c
> index 30588a4..212ef0c 100644
> --- a/test/tablet.c
> +++ b/test/tablet.c
> @@ -3767,6 +3767,338 @@ START_TEST(relative_calibration)
>  }
>  END_TEST
>  
> +static void
> +touch_arbitration(struct litest_device *dev,
> +               enum litest_device_type other,
> +               bool is_touchpad)
> +{
> +     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, other);
> +     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_down(finger, 0, 30, 30);
> +     litest_touch_move_to(finger, 0, 30, 30, 80, 80, 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_assert_only_typed_events(li,
> +                                     LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
> +
> +     /* finger still down */
> +     litest_touch_move_to(finger, 0, 80, 80, 30, 30, 10, 1);
> +     litest_touch_up(finger, 0);
> +     litest_assert_empty_queue(li);
> +
> +     /* lift finger, expect expect events */
> +     litest_touch_down(finger, 0, 30, 30);
> +     litest_touch_move_to(finger, 0, 30, 30, 80, 80, 10, 1);
> +     litest_touch_up(finger, 0);
> +     libinput_dispatch(li);
> +
> +     if (is_touchpad)
> +             litest_assert_only_typed_events(li,
> +                                             LIBINPUT_EVENT_POINTER_MOTION);
> +     else
> +             litest_assert_touch_sequence(li);
> +
> +     litest_delete_device(finger);
> +}
> +
> +START_TEST(intuos_touch_arbitration)
> +{
> +     touch_arbitration(litest_current_device(), LITEST_WACOM_FINGER, true);
> +}
> +END_TEST
> +
> +START_TEST(cintiq_touch_arbitration)
> +{
> +     touch_arbitration(litest_current_device(),
> +                       LITEST_WACOM_CINTIQ_13HDT_FINGER,
> +                       false);
> +}
> +END_TEST
> +
> +static void
> +touch_arbitration_stop_touch(struct litest_device *dev,
> +                          enum litest_device_type other,
> +                          bool is_touchpad)
> +{
> +     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, other);
> +     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_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);
> +     /* start another finger to make sure that one doesn't send events
> +        either */
> +     litest_touch_down(finger, 1, 30, 30);
> +     litest_touch_move_to(finger, 1, 30, 30, 80, 80, 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_move_to(finger, 1, 80, 80, 30, 30, 10, 1);
> +     litest_assert_empty_queue(li);
> +     litest_touch_up(finger, 0);
> +     litest_touch_move_to(finger, 1, 30, 30, 80, 80, 10, 1);
> +     litest_assert_empty_queue(li);
> +     litest_touch_up(finger, 1);
> +     litest_touch_down(finger, 0, 30, 30);
> +     litest_touch_move_to(finger, 0, 30, 30, 80, 80, 10, 1);
> +     litest_touch_up(finger, 0);
> +     libinput_dispatch(li);
> +
> +     if (is_touchpad)
> +             litest_assert_only_typed_events(li,
> +                                             LIBINPUT_EVENT_POINTER_MOTION);
> +     else
> +             litest_assert_touch_sequence(li);
> +
> +     litest_delete_device(finger);
> +     litest_assert_only_typed_events(li, LIBINPUT_EVENT_DEVICE_REMOVED);
> +}
> +
> +START_TEST(intuos_touch_arbitration_stop_touch)
> +{
> +     touch_arbitration_stop_touch(litest_current_device(),
> +                                  LITEST_WACOM_FINGER,
> +                                  true);
> +}
> +END_TEST
> +
> +START_TEST(cintiq_touch_arbitration_stop_touch)
> +{
> +     touch_arbitration_stop_touch(litest_current_device(),
> +                                  LITEST_WACOM_CINTIQ_13HDT_FINGER,
> +                                  false);
> +}
> +END_TEST
> +
> +static void
> +touch_arbitration_suspend_touch(struct litest_device *dev,
> +                             enum litest_device_type other,
> +                             bool is_touchpad)
> +{
> +     struct litest_device *tablet;
> +     struct libinput *li = dev->libinput;
> +     enum libinput_config_status status;
> +     struct axis_replacement axes[] = {
> +             { ABS_DISTANCE, 10 },
> +             { ABS_PRESSURE, 0 },
> +             { -1, -1 }
> +     };
> +
> +     tablet = litest_add_device(li, other);
> +
> +     /* we can't force a device suspend, but we can at least make sure
> +        the device doesn't send events */
> +     status = libinput_device_config_send_events_set_mode(
> +                          dev->libinput_device,
> +                          LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
> +     ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
> +
> +     litest_drain_events(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_touch_up(dev, 0);
> +     litest_assert_empty_queue(li);
> +
> +     /* Remove tablet device to unpair, still disabled though */
> +     litest_delete_device(tablet);
> +     litest_assert_only_typed_events(li, LIBINPUT_EVENT_DEVICE_REMOVED);
> +
> +     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_empty_queue(li);
> +
> +     /* Touch device is still disabled */
> +     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_empty_queue(li);
> +
> +     status = libinput_device_config_send_events_set_mode(
> +                          dev->libinput_device,
> +                          LIBINPUT_CONFIG_SEND_EVENTS_ENABLED);
> +     ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
> +
> +     litest_touch_down(dev, 0, 30, 30);
> +     litest_touch_move_to(dev, 0, 30, 30, 80, 80, 10, 1);
> +     litest_touch_up(dev, 0);
> +     libinput_dispatch(li);
> +
> +     if (is_touchpad)
> +             litest_assert_only_typed_events(li,
> +                                             LIBINPUT_EVENT_POINTER_MOTION);
> +     else
> +             litest_assert_touch_sequence(li);
> +}
> +
> +START_TEST(intuos_touch_arbitration_suspend_touch_device)
> +{
> +     touch_arbitration_suspend_touch(litest_current_device(),
> +                                     LITEST_WACOM_INTUOS,
> +                                     true);
> +}
> +END_TEST
> +
> +START_TEST(cintiq_touch_arbitration_suspend_touch_device)
> +{
> +     touch_arbitration_suspend_touch(litest_current_device(),
> +                                     LITEST_WACOM_CINTIQ_13HDT_PEN,
> +                                     false);
> +}
> +END_TEST
> +
> +static void
> +touch_arbitration_remove_touch(struct litest_device *dev,
> +                            enum litest_device_type other,
> +                            bool is_touchpad)
> +{
> +     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, other);
> +     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);
> +     libinput_dispatch(li);
> +     litest_assert_only_typed_events(li, LIBINPUT_EVENT_DEVICE_REMOVED);
> +     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);
> +}
> +
> +START_TEST(intuos_touch_arbitration_remove_touch)
> +{
> +     touch_arbitration_remove_touch(litest_current_device(),
> +                                    LITEST_WACOM_INTUOS,
> +                                    true);
> +}
> +END_TEST
> +
> +START_TEST(cintiq_touch_arbitration_remove_touch)
> +{
> +     touch_arbitration_remove_touch(litest_current_device(),
> +                                    LITEST_WACOM_CINTIQ_13HDT_FINGER,
> +                                    false);
> +}
> +END_TEST
> +
> +static void
> +touch_arbitration_remove_tablet(struct litest_device *dev,
> +                             enum litest_device_type other,
> +                             bool is_touchpad)
> +{
> +     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, other);
> +     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);
> +     libinput_dispatch(li);
> +
> +     if (is_touchpad)
> +             litest_assert_only_typed_events(li, 
> LIBINPUT_EVENT_POINTER_MOTION);
> +     else
> +             litest_assert_touch_sequence(li);
> +}
> +
> +START_TEST(intuos_touch_arbitration_remove_tablet)
> +{
> +     touch_arbitration_remove_tablet(litest_current_device(),
> +                                     LITEST_WACOM_INTUOS,
> +                                     true);
> +}
> +END_TEST
> +
> +START_TEST(cintiq_touch_arbitration_remove_tablet)
> +{
> +     touch_arbitration_remove_tablet(litest_current_device(),
> +                                     LITEST_WACOM_CINTIQ_13HDT_PEN,
> +                                     false);
> +}
> +END_TEST
> +
>  void
>  litest_setup_tests_tablet(void)
>  {
> @@ -3844,4 +4176,16 @@ 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_suspend_touch_device, LITEST_WACOM_FINGER);
> +     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_suspend_touch_device, 
> LITEST_WACOM_CINTIQ_13HDT_FINGER);
> +     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);
>  }
> 
_______________________________________________
wayland-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to