[PATCH v2 libinput] tablet: sync tools already in proximity at startup
Benjamin Tissoires
benjamin.tissoires at gmail.com
Tue Mar 3 09:29:28 PST 2015
On Mon, Mar 2, 2015 at 10:29 PM, Benjamin Tissoires
<benjamin.tissoires at gmail.com> wrote:
> 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.
Patch on the LKML: https://patchwork.kernel.org/patch/5924611/
>
>> * 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;
>> +}
>> +
Shouldn't this one be in evdev-tablet.h instead? (for consistency)
The rest looks good:
Acked-by: Benjamin Tissoires <benjamin.tissoires at gmail.com>
Cheers,
Benjamin
>> 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