[PATCH v2 libinput] tablet: sync tools already in proximity at startup

Benjamin Tissoires benjamin.tissoires at gmail.com
Mon Mar 2 19:29:47 PST 2015


On Mon, Mar 2, 2015 at 7:59 PM, Peter Hutterer <peter.hutterer at who-t.net> wrote:
> If a tool is in proximity when we init, send a proximity event immediately.
>
> This is only partially reliable due to the current kernel behavior:
> * if the tool comes into proximity when there is no evdev client, the device
>   won't send any events and must be lifted out-of-proximity first.

This only affect the pro line (Intuos 1-5/pro + Cintiq), and is rather
easy to fix. I'll send a patch for it.

> * if the tool was in proximity (with an evdev client attached), but goes out
>   of proximity and back in with no client connected, we get an immediate
>   proximity out event from the kernel once we connect to the device and no
>   further events after that.

This has been fixed in b905811a49bcd6e6726ce5bbb591f57aaddfd3be in
Linus' tree, so this is in v3.19 and above.
I guess the fact that no events are sent after the prox in event means
that this one does not affect the Bamboos either.

Cheers,
Benjamin

PS: tomorrow for the review, not tonight :)

>
> Otherwise, things work as expected. The above should be fixed in the kernel
> anyway.
>
> Note that this changes the order of events during a udev seat init, before we
> had all DEVICE_ADDED events in a row, now the proximity event may be
> interspersed.
>
> Reported-by: Jason Gerecke <killertofu at gmail.com>
> Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
> ---
>  src/evdev-mt-touchpad.c |  1 +
>  src/evdev-tablet.c      | 78 ++++++++++++++++++++++++++++++++++++++++++++++---
>  src/evdev-tablet.h      |  1 +
>  src/evdev.c             |  5 ++++
>  src/evdev.h             |  5 ++++
>  test/tablet.c           | 53 +++++++++++++++++++++++++++++++++
>  6 files changed, 139 insertions(+), 4 deletions(-)
>
> diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
> index b90d84c..b3a8b08 100644
> --- a/src/evdev-mt-touchpad.c
> +++ b/src/evdev-mt-touchpad.c
> @@ -897,6 +897,7 @@ static struct evdev_dispatch_interface tp_interface = {
>         tp_device_removed, /* device_suspended, treat as remove */
>         tp_device_added,   /* device_resumed, treat as add */
>         tp_tag_device,
> +       NULL,              /* post_added */
>  };
>
>  static void
> diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
> index 6d3b9b7..12cca79 100644
> --- a/src/evdev-tablet.c
> +++ b/src/evdev-tablet.c
> @@ -190,7 +190,7 @@ tablet_update_tool(struct tablet_dispatch *tablet,
>                 tablet_set_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY);
>                 tablet_unset_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY);
>         }
> -       else
> +       else if (!tablet_has_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY))
>                 tablet_set_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY);
>  }
>
> @@ -467,6 +467,27 @@ tablet_evcode_to_tool(int code)
>         return type;
>  }
>
> +static inline int
> +tablet_tool_to_evcode(enum libinput_tool_type type)
> +{
> +       int code;
> +
> +       switch (type) {
> +       case LIBINPUT_TOOL_PEN:         code = BTN_TOOL_PEN;            break;
> +       case LIBINPUT_TOOL_ERASER:      code = BTN_TOOL_RUBBER;         break;
> +       case LIBINPUT_TOOL_BRUSH:       code = BTN_TOOL_BRUSH;          break;
> +       case LIBINPUT_TOOL_PENCIL:      code = BTN_TOOL_PENCIL;         break;
> +       case LIBINPUT_TOOL_AIRBRUSH:    code = BTN_TOOL_AIRBRUSH;       break;
> +       case LIBINPUT_TOOL_FINGER:      code = BTN_TOOL_FINGER;         break;
> +       case LIBINPUT_TOOL_MOUSE:       code = BTN_TOOL_MOUSE;          break;
> +       case LIBINPUT_TOOL_LENS:        code = BTN_TOOL_LENS;           break;
> +       default:
> +               abort();
> +       }
> +
> +       return code;
> +}
> +
>  static void
>  tablet_process_key(struct tablet_dispatch *tablet,
>                    struct evdev_device *device,
> @@ -869,6 +890,9 @@ tablet_flush(struct tablet_dispatch *tablet,
>                                 tablet->current_tool_id,
>                                 tablet->current_tool_serial);
>
> +       if (tablet_has_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY))
> +               return;
> +
>         if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY)) {
>                 /* Release all stylus buttons */
>                 memset(tablet->button_state.stylus_buttons,
> @@ -916,7 +940,11 @@ tablet_flush(struct tablet_dispatch *tablet,
>
>                 tablet_change_to_left_handed(device);
>         }
> +}
>
> +static inline void
> +tablet_reset_state(struct tablet_dispatch *tablet)
> +{
>         /* Update state */
>         memcpy(&tablet->prev_button_state,
>                &tablet->button_state,
> @@ -947,6 +975,7 @@ tablet_process(struct evdev_dispatch *dispatch,
>                 break;
>         case EV_SYN:
>                 tablet_flush(tablet, device, time);
> +               tablet_reset_state(tablet);
>                 break;
>         default:
>                 log_error(device->base.seat->libinput,
> @@ -971,6 +1000,49 @@ tablet_destroy(struct evdev_dispatch *dispatch)
>         free(tablet);
>  }
>
> +static void
> +tablet_check_initial_proximity(struct evdev_device *device,
> +                              struct evdev_dispatch *dispatch)
> +{
> +       bool tool_in_prox = false;
> +       int code, state;
> +       enum libinput_tool_type tool;
> +       struct tablet_dispatch *tablet = (struct tablet_dispatch*)dispatch;
> +
> +       for (tool = LIBINPUT_TOOL_PEN; tool <= LIBINPUT_TOOL_MAX; tool++) {
> +               code = tablet_tool_to_evcode(tool);
> +
> +               /* we only expect one tool to be in proximity at a time */
> +               if (libevdev_fetch_event_value(device->evdev,
> +                                               EV_KEY,
> +                                               code,
> +                                               &state) && state) {
> +                       tool_in_prox = true;
> +                       break;
> +               }
> +       }
> +
> +       if (!tool_in_prox) {
> +               tablet_set_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY);
> +               return;
> +       }
> +
> +       tablet_update_tool(tablet, device, tool, state);
> +
> +       tablet->current_tool_id =
> +               libevdev_get_event_value(device->evdev,
> +                                        EV_ABS,
> +                                        ABS_MISC);
> +       tablet->current_tool_serial =
> +               libevdev_get_event_value(device->evdev,
> +                                        EV_MSC,
> +                                        MSC_SERIAL);
> +
> +       tablet_flush(tablet,
> +                    device,
> +                    libinput_now(device->base.seat->libinput));
> +}
> +
>  static struct evdev_dispatch_interface tablet_interface = {
>         tablet_process,
>         NULL, /* remove */
> @@ -980,6 +1052,7 @@ static struct evdev_dispatch_interface tablet_interface = {
>         NULL, /* device_suspended */
>         NULL, /* device_resumed */
>         NULL, /* tag_device */
> +       tablet_check_initial_proximity,
>  };
>
>  static int
> @@ -1002,9 +1075,6 @@ tablet_init(struct tablet_dispatch *tablet,
>         }
>
>         tablet_mark_all_axes_changed(tablet, device);
> -
> -       tablet_set_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY);
> -
>         return 0;
>  }
>
> diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h
> index ea103b0..76a9677 100644
> --- a/src/evdev-tablet.h
> +++ b/src/evdev-tablet.h
> @@ -28,6 +28,7 @@
>
>  #define LIBINPUT_TABLET_AXIS_NONE 0
>  #define LIBINPUT_TOOL_NONE 0
> +#define LIBINPUT_TOOL_MAX LIBINPUT_TOOL_LENS
>
>  enum tablet_status {
>         TABLET_NONE = 0,
> diff --git a/src/evdev.c b/src/evdev.c
> index b90ea7c..2c4d1f1 100644
> --- a/src/evdev.c
> +++ b/src/evdev.c
> @@ -803,6 +803,7 @@ struct evdev_dispatch_interface fallback_interface = {
>         NULL, /* device_suspended */
>         NULL, /* device_resumed */
>         fallback_tag_device,
> +       NULL, /* post_added */
>  };
>
>  static uint32_t
> @@ -1592,6 +1593,10 @@ evdev_notify_added_device(struct evdev_device *device)
>         }
>
>         notify_added_device(&device->base);
> +
> +       if (device->dispatch->interface->post_added)
> +               device->dispatch->interface->post_added(device,
> +                                                       device->dispatch);
>  }
>
>  static int
> diff --git a/src/evdev.h b/src/evdev.h
> index 7469675..26f321e 100644
> --- a/src/evdev.h
> +++ b/src/evdev.h
> @@ -196,6 +196,11 @@ struct evdev_dispatch_interface {
>         /* Tag device with one of EVDEV_TAG */
>         void (*tag_device)(struct evdev_device *device,
>                            struct udev_device *udev_device);
> +
> +       /* Called immediately after the LIBINPUT_EVENT_DEVICE_ADDED event
> +        * was sent */
> +       void (*post_added)(struct evdev_device *device,
> +                          struct evdev_dispatch *dispatch);
>  };
>
>  struct evdev_dispatch {
> diff --git a/test/tablet.c b/test/tablet.c
> index d7486cb..ba61e0e 100644
> --- a/test/tablet.c
> +++ b/test/tablet.c
> @@ -1157,6 +1157,58 @@ START_TEST(tool_capabilities)
>  }
>  END_TEST
>
> +START_TEST(tool_in_prox_before_start)
> +{
> +       struct libinput *li;
> +       struct litest_device *dev = litest_current_device();
> +       struct libinput_event *event;
> +       struct axis_replacement axes[] = {
> +               { ABS_DISTANCE, 10 },
> +               { ABS_TILT_X, 0 },
> +               { ABS_TILT_Y, 0 },
> +               { -1, -1 }
> +       };
> +       const char *devnode;
> +
> +       litest_tablet_proximity_in(dev, 10, 10, axes);
> +
> +       /* for simplicity, we create a new litest context */
> +       devnode = libevdev_uinput_get_devnode(dev->uinput);
> +       li = litest_create_context();
> +       libinput_path_add_device(li, devnode);
> +
> +       litest_wait_for_event_of_type(li,
> +                                     LIBINPUT_EVENT_DEVICE_ADDED,
> +                                     -1);
> +       event = libinput_get_event(li);
> +       libinput_event_destroy(event);
> +
> +       litest_wait_for_event_of_type(li,
> +                                     LIBINPUT_EVENT_TABLET_PROXIMITY,
> +                                     -1);
> +       event = libinput_get_event(li);
> +       libinput_event_destroy(event);
> +       litest_assert_empty_queue(li);
> +
> +       litest_tablet_motion(dev, 10, 20, axes);
> +       litest_tablet_motion(dev, 30, 40, axes);
> +
> +       litest_assert_only_typed_events(li, LIBINPUT_EVENT_TABLET_AXIS);
> +       litest_assert_empty_queue(li);
> +       litest_event(dev, EV_KEY, BTN_STYLUS, 1);
> +       litest_event(dev, EV_SYN, SYN_REPORT, 0);
> +       litest_event(dev, EV_KEY, BTN_STYLUS, 1);
> +       litest_event(dev, EV_SYN, SYN_REPORT, 0);
> +       litest_assert_only_typed_events(li, LIBINPUT_EVENT_TABLET_BUTTON);
> +       litest_tablet_proximity_out(dev);
> +
> +       litest_wait_for_event_of_type(li,
> +                                     LIBINPUT_EVENT_TABLET_PROXIMITY,
> +                                     -1);
> +       libinput_unref(li);
> +}
> +END_TEST
> +
>  START_TEST(mouse_tool)
>  {
>         struct litest_device *dev = litest_current_device();
> @@ -1615,6 +1667,7 @@ main(int argc, char **argv)
>  {
>         litest_add("tablet:tool", tool_ref, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
>         litest_add_no_device("tablet:tool", tool_capabilities);
> +       litest_add("tablet:tool", tool_in_prox_before_start, LITEST_TABLET, LITEST_ANY);
>         litest_add("tablet:tool_serial", tool_serial, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
>         litest_add("tablet:tool_serial", serial_changes_tool, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
>         litest_add("tablet:tool_serial", invalid_serials, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
> --
> 2.1.0
>


More information about the wayland-devel mailing list