diff --git a/meson.build b/meson.build index 60caf997..c80f4b79 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 + 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 #include +#if HAVE_LIBWACOM +#include +#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) { 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 #include +#if HAVE_LIBWACOM +#include +#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);