[PATCH v2 libinput] pad: use libwacom to get the evdev to button number mapping

Peter Hutterer peter.hutterer at who-t.net
Wed Nov 1 03:00:46 UTC 2017


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 at who-t.net>
Acked-by: Jason Gerecke <jason.gerecke at wacom.com>
---
Changes to v1:
- note in the commit message that libwacom is the one that orders the
  buttons
- remove erroneous return in the intuos test and fix it for the EKR

 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 41e6ea4c..24f8117b 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..cfa28b17 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_JOYSTICK) ||
+		    (code >= BTN_DIGI)) {
+			ck_assert(!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);
-
-		switch (code) {
-		case BTN_STYLUS:
-			litest_assert_empty_queue(li);
-			continue;
-		default:
-			break;
 		}
 
+		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,
@@ -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);
-- 
2.13.6



More information about the wayland-devel mailing list