pad: use libwacom to get the evdev to button number mapping

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 vertically top-to-bottom in libwacom.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Jason Gerecke <jason.gerecke@wacom.com>
This commit is contained in:
Peter Hutterer 2017-10-18 13:00:16 +10:00
parent 8f688be749
commit 96fd84ebc9
3 changed files with 229 additions and 17 deletions

View file

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

View file

@ -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,16 +521,60 @@ static struct evdev_dispatch_interface pad_interface = {
.get_switch_state = NULL,
};
static void
pad_init_buttons(struct pad_dispatch *pad,
struct evdev_device *device)
static bool
pad_init_buttons_from_libwacom(struct pad_dispatch *pad,
struct evdev_device *device)
{
unsigned int code;
size_t i;
bool rc = false;
#if HAVE_LIBWACOM_GET_BUTTON_EVDEV_CODE
WacomDeviceDatabase *db = NULL;
WacomDevice *tablet = NULL;
int num_buttons;
int map = 0;
for (i = 0; i < ARRAY_LENGTH(pad->button_map); i++)
pad->button_map[i] = -1;
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_from_kernel(struct pad_dispatch *pad,
struct evdev_device *device)
{
unsigned int code;
int map = 0;
/* we match wacom_report_numbered_buttons() from the kernel */
for (code = BTN_0; code < BTN_0 + 10; code++) {
@ -552,6 +600,20 @@ pad_init_buttons(struct pad_dispatch *pad,
pad->nbuttons = map;
}
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)
{

View file

@ -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,18 +174,33 @@ 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++) {
for (code = BTN_0; code < BTN_DIGI; code++) {
/* Skip over the BTN_MOUSE and BTN_JOYSTICK range */
if ((code >= BTN_MOUSE && code < BTN_JOYSTICK) ||
(code >= BTN_DIGI)) {
ck_assert(!libevdev_has_event_code(dev->evdev,
EV_KEY, code));
continue;
}
if (!libevdev_has_event_code(dev->evdev, EV_KEY, code))
continue;
@ -160,13 +208,7 @@ START_TEST(pad_button)
litest_button_click(dev, code, 0);
libinput_dispatch(li);
switch (code) {
case BTN_STYLUS:
litest_assert_empty_queue(li);
continue;
default:
break;
}
count++;
ev = libinput_get_event(li);
pev = litest_is_pad_button_event(ev,
@ -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;
litest_drain_events(li);
for (code = BTN_LEFT; code < BTN_JOYSTICK; code++) {
if (!libevdev_has_event_code(dev->evdev, EV_KEY, code))
continue;
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);