[PATCH libinput 2/2] pad: use libwacom to get the evdev to button number mapping
Peter Hutterer
peter.hutterer at who-t.net
Mon Oct 30 06:01:58 UTC 2017
On Fri, Oct 27, 2017 at 01:26:40PM -0700, Jason Gerecke wrote:
> On Wed, Oct 25, 2017 at 10:24 PM, Peter Hutterer
> <peter.hutterer at who-t.net> wrote:
> > Some of wacom's tablets, notably the Bamboo series, have a non-predictable
> > scheme of mapping the buttons to numeric button numbers in libwacom. Since we
> > promise sequential button numbers, we need to have those identical to
> > libwacom, otherwise it's impossible to map the two together.
> >
> > Most tablets have a predictable mapping, so this does not affect the majority
> > of devices.
> >
> > For the old-style bamboos, this swaps the buttons around with the buttons
> > being ordered in a vertical order.
>
> This language gives me pause because I know under the covers the order
> ultimately comes down to whatever the libwacom SVGs specify. Still, it
> looks like all the Bamboo SVGs do indeed use a vertical order so you
> can leave it as-is if you'd like.
I guess the alternative here is that we swap the libwacom data files and
SVGs around to have the order follow the evdev code sort order. Either way,
the end-user breakage is roughly the same. These tablets are older enough
that I don't really care either way so I'm happy to take your preference
here. I've appended 'in libwacom' to the sentence in the commit message
to be less ambiguous here.
> > Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
> > ---
> > meson.build | 9 +++
> > src/evdev-tablet-pad.c | 74 +++++++++++++++++++--
> > test/test-pad.c | 171 ++++++++++++++++++++++++++++++++++++++++++++-----
> > 3 files changed, 233 insertions(+), 21 deletions(-)
> >
> > diff --git a/meson.build b/meson.build
> > index f93cde70..72bd90b0 100644
> > --- a/meson.build
> > +++ b/meson.build
> > @@ -66,6 +66,15 @@ if have_libwacom
> > name : 'libwacom_get_paired_device check',
> > dependencies : dep_libwacom)
> > config_h.set10('HAVE_LIBWACOM_GET_PAIRED_DEVICE', result)
> > +
> > + code = '''
> > + #include <libwacom/libwacom.h>
> > + int main(void) { libwacom_get_button_evdev_code(NULL, 'A'); }
> > + '''
> > + result = cc.links(code,
> > + name : 'libwacom_get_button_evdev_code check',
> > + dependencies : dep_libwacom)
> > + config_h.set10('HAVE_LIBWACOM_GET_BUTTON_EVDEV_CODE', result)
> > else
> > dep_libwacom = declare_dependency()
> > endif
> > diff --git a/src/evdev-tablet-pad.c b/src/evdev-tablet-pad.c
> > index 82604d70..2e85f7ac 100644
> > --- a/src/evdev-tablet-pad.c
> > +++ b/src/evdev-tablet-pad.c
> > @@ -27,6 +27,10 @@
> > #include <stdbool.h>
> > #include <string.h>
> >
> > +#if HAVE_LIBWACOM
> > +#include <libwacom/libwacom.h>
> > +#endif
> > +
> > #define pad_set_status(pad_,s_) (pad_)->status |= (s_)
> > #define pad_unset_status(pad_,s_) (pad_)->status &= ~(s_)
> > #define pad_has_status(pad_,s_) (!!((pad_)->status & (s_)))
> > @@ -517,17 +521,61 @@ static struct evdev_dispatch_interface pad_interface = {
> > .get_switch_state = NULL,
> > };
> >
> > +static bool
> > +pad_init_buttons_from_libwacom(struct pad_dispatch *pad,
> > + struct evdev_device *device)
> > +{
> > + bool rc = false;
> > +#if HAVE_LIBWACOM_GET_BUTTON_EVDEV_CODE
> > + WacomDeviceDatabase *db = NULL;
> > + WacomDevice *tablet = NULL;
> > + int num_buttons;
> > + int map = 0;
> > +
> > + db = libwacom_database_new();
> > + if (!db) {
> > + evdev_log_info(device,
> > + "Failed to initialize libwacom context.\n");
> > + goto out;
> > + }
> > +
> > + tablet = libwacom_new_from_usbid(db,
> > + evdev_device_get_id_vendor(device),
> > + evdev_device_get_id_product(device),
> > + NULL);
> > + if (!tablet)
> > + goto out;
> > +
> > + num_buttons = libwacom_get_num_buttons(tablet);
> > + for (int i = 0; i < num_buttons; i++) {
> > + unsigned int code;
> > +
> > + code = libwacom_get_button_evdev_code(tablet, 'A' + i);
> > + if (code == 0)
> > + continue;
> > +
> > + pad->button_map[code] = map++;
> > + }
> > +
> > + pad->nbuttons = map;
> > +
> > + rc = true;
> > +out:
> > + if (tablet)
> > + libwacom_destroy(tablet);
> > + if (db)
> > + libwacom_database_destroy(db);
> > +#endif
> > + return rc;
> > +}
> > +
> > static void
> > -pad_init_buttons(struct pad_dispatch *pad,
> > - struct evdev_device *device)
> > +pad_init_buttons_from_kernel(struct pad_dispatch *pad,
> > + struct evdev_device *device)
> > {
> > unsigned int code;
> > - size_t i;
> > int map = 0;
> >
> > - for (i = 0; i < ARRAY_LENGTH(pad->button_map); i++)
> > - pad->button_map[i] = -1;
> > -
> > /* we match wacom_report_numbered_buttons() from the kernel */
> > for (code = BTN_0; code < BTN_0 + 10; code++) {
> > if (libevdev_has_event_code(device->evdev, EV_KEY, code))
> > @@ -553,6 +601,20 @@ pad_init_buttons(struct pad_dispatch *pad,
> > }
> >
> > static void
> > +pad_init_buttons(struct pad_dispatch *pad,
> > + struct evdev_device *device)
> > +{
> > + size_t i;
> > +
> > + for (i = 0; i < ARRAY_LENGTH(pad->button_map); i++)
> > + pad->button_map[i] = -1;
> > +
> > + if (!pad_init_buttons_from_libwacom(pad, device))
> > + pad_init_buttons_from_kernel(pad, device);
> > +
> > +}
> > +
> > +static void
> > pad_init_left_handed(struct evdev_device *device)
> > {
> > if (evdev_tablet_has_left_handed(device))
> > diff --git a/test/test-pad.c b/test/test-pad.c
> > index 085d6c58..3383c60f 100644
> > --- a/test/test-pad.c
> > +++ b/test/test-pad.c
> > @@ -29,6 +29,10 @@
> > #include <unistd.h>
> > #include <stdbool.h>
> >
> > +#if HAVE_LIBWACOM
> > +#include <libwacom/libwacom.h>
> > +#endif
> > +
> > #include "libinput-util.h"
> > #include "litest.h"
> >
> > @@ -119,6 +123,35 @@ START_TEST(pad_time)
> > }
> > END_TEST
> >
> > +START_TEST(pad_num_buttons_libwacom)
> > +{
> > +#if HAVE_LIBWACOM
> > + struct litest_device *dev = litest_current_device();
> > + struct libinput_device *device = dev->libinput_device;
> > + WacomDeviceDatabase *db = NULL;
> > + WacomDevice *wacom = NULL;
> > + unsigned int nb_lw, nb;
> > +
> > + db = libwacom_database_new();
> > + ck_assert_notnull(db);
> > +
> > + wacom = libwacom_new_from_usbid(db,
> > + libevdev_get_id_vendor(dev->evdev),
> > + libevdev_get_id_product(dev->evdev),
> > + NULL);
> > + ck_assert_notnull(wacom);
> > +
> > + nb_lw = libwacom_get_num_buttons(wacom);
> > + nb = libinput_device_tablet_pad_get_num_buttons(device);
> > +
> > + ck_assert_int_eq(nb, nb_lw);
> > +
> > + libwacom_destroy(wacom);
> > + libwacom_database_destroy(db);
> > +#endif
> > +}
> > +END_TEST
> > +
> > START_TEST(pad_num_buttons)
> > {
> > struct litest_device *dev = litest_current_device();
> > @@ -141,33 +174,42 @@ START_TEST(pad_num_buttons)
> > }
> > END_TEST
> >
> > -START_TEST(pad_button)
> > +START_TEST(pad_button_intuos)
> > {
> > +#if !HAVE_LIBWACOM_GET_BUTTON_EVDEV_CODE
> > struct litest_device *dev = litest_current_device();
> > struct libinput *li = dev->libinput;
> > unsigned int code;
> > unsigned int expected_number = 0;
> > struct libinput_event *ev;
> > struct libinput_event_tablet_pad *pev;
> > + unsigned int count;
> > +
> > + /* Intuos button mapping is sequential up from BTN_0 and continues
> > + * with BTN_A */
> > +
> > + if (!libevdev_has_event_code(dev->evdev, EV_KEY, BTN_0))
> > + return;
> >
> > litest_drain_events(li);
> >
> > - for (code = BTN_0; code < KEY_MAX; code++) {
> > - if (!libevdev_has_event_code(dev->evdev, EV_KEY, code))
> > + for (code = BTN_0; code < BTN_DIGI; code++) {
> > + /* SKip over the BTN_MOUSE and BTN_JOYSTICK range */
> > + if (code >= BTN_MOUSE && code < BTN_A) {
> > + ck_assert(!libevdev_has_event_code(dev->evdev,
> > + EV_KEY, code));
>
> Will this get tripped up by the ExpressKey remote? It uses BTN_BASE
> and BTN_BASE2 for its two highest-numbered buttons (following
> BTN_0..BTN_9, BTN_A..BTN_Z). No other device uses those codes from
> what I can tell, but a hypothetical future tablet with enough buttons
> would.
indeed it does - an excessive return (below) skipped the rest of the test,
thus never triggering the assertion. I'll fix this, thanks.
> > continue;
> > -
> > - litest_button_click(dev, code, 1);
> > - litest_button_click(dev, code, 0);
> > - libinput_dispatch(li);
> > -
> > - switch (code) {
> > - case BTN_STYLUS:
> > - litest_assert_empty_queue(li);
> > - continue;
> > - default:
> > - break;
> > }
> >
> > + if (!libevdev_has_event_code(dev->evdev, EV_KEY, code))
> > + return;
> > +
> > + litest_button_click(dev, code, 1);
> > + litest_button_click(dev, code, 0);
> > + libinput_dispatch(li);
> > +
> > + count++;
> > +
> > ev = libinput_get_event(li);
> > pev = litest_is_pad_button_event(ev,
> > expected_number,
> > @@ -186,6 +228,102 @@ START_TEST(pad_button)
> > }
> >
> > litest_assert_empty_queue(li);
> > +
> > + ck_assert_int_gt(count, 3);
> > +#endif
> > +}
> > +END_TEST
> > +
> > +START_TEST(pad_button_bamboo)
> > +{
> > +#if !HAVE_LIBWACOM_GET_BUTTON_EVDEV_CODE
> > + struct litest_device *dev = litest_current_device();
> > + struct libinput *li = dev->libinput;
> > + unsigned int code;
> > + unsigned int expected_number = 0;
> > + struct libinput_event *ev;
> > + struct libinput_event_tablet_pad *pev;
> > + unsigned int count;
> > +
> > + if (!libevdev_has_event_code(dev->evdev, EV_KEY, BTN_LEFT))
> > + return;
>
> Pre-3.17 kernels combine the pen and pad on the same device. A device
> like the Intuos4 will declare the BTN_0 range for its ExpressKeys, as
> well as the BTN_LEFT range for its puck. Not sure if that'll be
> problematic...
not for the test here, we expect something more recent. The whole libinput
tablet pad support was basically written with post 3.17 as expectation.
Speaking of which, I should set up a test device that has pre-3.17 behaviour
and see what happens :)
Cheers,
Peter
> > +
> > + litest_drain_events(li);
> > +
> > + for (code = BTN_LEFT; code < BTN_JOYSTICK; code++) {
> > + if (!libevdev_has_event_code(dev->evdev, EV_KEY, code))
> > + return;
> > +
> > + litest_button_click(dev, code, 1);
> > + litest_button_click(dev, code, 0);
> > + libinput_dispatch(li);
> > +
> > + count++;
> > +
> > + ev = libinput_get_event(li);
> > + pev = litest_is_pad_button_event(ev,
> > + expected_number,
> > + LIBINPUT_BUTTON_STATE_PRESSED);
> > + ev = libinput_event_tablet_pad_get_base_event(pev);
> > + libinput_event_destroy(ev);
> > +
> > + ev = libinput_get_event(li);
> > + pev = litest_is_pad_button_event(ev,
> > + expected_number,
> > + LIBINPUT_BUTTON_STATE_RELEASED);
> > + ev = libinput_event_tablet_pad_get_base_event(pev);
> > + libinput_event_destroy(ev);
> > +
> > + expected_number++;
> > + }
> > +
> > + litest_assert_empty_queue(li);
> > +
> > + ck_assert_int_gt(count, 3);
> > +#endif
> > +}
> > +END_TEST
> > +
> > +START_TEST(pad_button_libwacom)
> > +{
> > +#if HAVE_LIBWACOM_GET_BUTTON_EVDEV_CODE
> > + struct litest_device *dev = litest_current_device();
> > + struct libinput *li = dev->libinput;
> > + WacomDeviceDatabase *db = NULL;
> > + WacomDevice *wacom = NULL;
> > +
> > + db = libwacom_database_new();
> > + assert(db);
> > +
> > + wacom = libwacom_new_from_usbid(db,
> > + libevdev_get_id_vendor(dev->evdev),
> > + libevdev_get_id_product(dev->evdev),
> > + NULL);
> > + assert(wacom);
> > +
> > + litest_drain_events(li);
> > +
> > + for (int i = 0; i < libwacom_get_num_buttons(wacom); i++) {
> > + unsigned int code;
> > +
> > + code = libwacom_get_button_evdev_code(wacom, 'A' + i);
> > +
> > + litest_button_click(dev, code, 1);
> > + litest_button_click(dev, code, 0);
> > + libinput_dispatch(li);
> > +
> > + litest_assert_pad_button_event(li,
> > + i,
> > + LIBINPUT_BUTTON_STATE_PRESSED);
> > + litest_assert_pad_button_event(li,
> > + i,
> > + LIBINPUT_BUTTON_STATE_RELEASED);
> > + }
> > +
> > +
> > + libwacom_destroy(wacom);
> > + libwacom_database_destroy(db);
> > +#endif
> > }
> > END_TEST
> >
> > @@ -788,7 +926,10 @@ litest_setup_tests_pad(void)
> > litest_add("pad:time", pad_time, LITEST_TABLET_PAD, LITEST_ANY);
> >
> > litest_add("pad:button", pad_num_buttons, LITEST_TABLET_PAD, LITEST_ANY);
> > - litest_add("pad:button", pad_button, LITEST_TABLET_PAD, LITEST_ANY);
> > + litest_add("pad:button", pad_num_buttons_libwacom, LITEST_TABLET_PAD, LITEST_ANY);
> > + litest_add("pad:button", pad_button_intuos, LITEST_TABLET_PAD, LITEST_ANY);
> > + litest_add("pad:button", pad_button_bamboo, LITEST_TABLET_PAD, LITEST_ANY);
> > + litest_add("pad:button", pad_button_libwacom, LITEST_TABLET_PAD, LITEST_ANY);
> > litest_add("pad:button", pad_button_mode_groups, LITEST_TABLET_PAD, LITEST_ANY);
> >
> > litest_add("pad:ring", pad_has_ring, LITEST_RING, LITEST_ANY);
> > --
> > 2.13.6
> >
>
> Those concerns aside, for the set:
>
> Acked-by: Jason Gerecke <jason.gerecke at wacom.com>
>
> 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....
>
More information about the wayland-devel
mailing list