From b6b82e4afa6a2114afc819cddf6b3ee65dff2e15 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 2 May 2024 15:35:02 +1000 Subject: [PATCH] Add support for relative dials (#665) We already have a number of tablets with a relative dial that sends mouse wheel events (UCLOGIC/Huion/XP Pen devices, primarily) so let's add support for these in our description files. This is copy/paste from the touch strip and ring support. --- data/wacom.example | 15 +++++++- libwacom/libwacom-database.c | 8 ++++- libwacom/libwacom.c | 38 ++++++++++++++++++++ libwacom/libwacom.h | 30 +++++++++++++++- libwacom/libwacom.sym | 5 ++- libwacom/libwacomint.h | 3 ++ test/test-load.c | 2 ++ test/test-tablet-svg-validity.c | 63 +++++++++++++++++++++++++++++++++ test/test-tablet-validity.c | 20 +++++++++++ tools/debug-device.c | 8 +++-- 10 files changed, 186 insertions(+), 6 deletions(-) diff --git a/data/wacom.example b/data/wacom.example index d7424ace..70cc076e 100644 --- a/data/wacom.example +++ b/data/wacom.example @@ -167,10 +167,14 @@ TouchSwitch=false # This tablet has one or more touch rings (Intuos4 and Cintiq 24HD) # A touch ring is a circular button that responds to touch -# (rather than clicks): +# (rather than clicks) and sends absolute events: # http://intuos.wacom.com/americas/touch-ring.php NumRings=1 +# This tablet's number of dials/rotary toggles that send relative events +# similar to a mouse wheel. +NumDials=1 + # This tablet's number of touch strips (e.g. Cintiq 22HD), default is zero NumStrips=1 @@ -220,6 +224,15 @@ Touchstrip2=J # if there is more than one StripsNumModes=4 +# If the dials have mode toggling through a button +Dial=A +# The number of modes we can toggle through. +DialNumModes=4 +# Buttons associated with the second dial, if any. +Dial2=B +# Number of modes on the second dial, if any +Dial2NumModes=4 + # Metadata about the keys on the tablet [Keys] diff --git a/libwacom/libwacom-database.c b/libwacom/libwacom-database.c index d4b48d42..43bbc096 100644 --- a/libwacom/libwacom-database.c +++ b/libwacom/libwacom-database.c @@ -408,7 +408,9 @@ static const struct { { "Ring2", WACOM_BUTTON_RING2_MODESWITCH }, { "Touchstrip", WACOM_BUTTON_TOUCHSTRIP_MODESWITCH }, { "Touchstrip2", WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH }, - { "OLEDs", WACOM_BUTTON_OLED } + { "OLEDs", WACOM_BUTTON_OLED }, + { "Dial", WACOM_BUTTON_DIAL_MODESWITCH }, + { "Dial2", WACOM_BUTTON_DIAL2_MODESWITCH }, }; static const struct { @@ -671,6 +673,8 @@ libwacom_parse_buttons(WacomDevice *device, device->ring_num_modes = libwacom_parse_num_modes(device, keyfile, "RingNumModes", WACOM_BUTTON_RING_MODESWITCH); device->ring2_num_modes = libwacom_parse_num_modes(device, keyfile, "Ring2NumModes", WACOM_BUTTON_RING2_MODESWITCH); device->strips_num_modes = libwacom_parse_num_modes(device, keyfile, "StripsNumModes", WACOM_BUTTON_TOUCHSTRIP_MODESWITCH); + device->dial_num_modes = libwacom_parse_num_modes(device, keyfile, "DialNumModes", WACOM_BUTTON_DIAL_MODESWITCH); + device->dial2_num_modes = libwacom_parse_num_modes(device, keyfile, "Dial2NumModes", WACOM_BUTTON_DIAL2_MODESWITCH); } static void @@ -771,6 +775,7 @@ libwacom_parse_features(WacomDevice *device, GKeyFile *keyfile) device->num_rings = g_key_file_get_integer(keyfile, FEATURES_GROUP, "NumRings", NULL); device->num_strips = g_key_file_get_integer(keyfile, FEATURES_GROUP, "NumStrips", NULL); + device->num_dials = g_key_file_get_integer(keyfile, FEATURES_GROUP, "NumDials", NULL); string_list = g_key_file_get_string_list(keyfile, FEATURES_GROUP, "StatusLEDs", NULL, NULL); if (string_list) { @@ -907,6 +912,7 @@ libwacom_parse_tablet_keyfile(WacomDeviceDatabase *db, } device->num_strips = g_key_file_get_integer(keyfile, FEATURES_GROUP, "NumStrips", NULL); + device->num_dials = g_key_file_get_integer(keyfile, FEATURES_GROUP, "NumDials", NULL); device->buttons = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); device->status_leds = g_array_new (FALSE, FALSE, sizeof(WacomStatusLEDs)); diff --git a/libwacom/libwacom.c b/libwacom/libwacom.c index 3626bac8..5e18353b 100644 --- a/libwacom/libwacom.c +++ b/libwacom/libwacom.c @@ -404,8 +404,11 @@ libwacom_copy(const WacomDevice *device) d->cls = device->cls; d->num_strips = device->num_strips; d->num_rings = device->num_rings; + d->num_dials = device->num_dials; d->features = device->features; d->strips_num_modes = device->strips_num_modes; + d->dial_num_modes = device->dial_num_modes; + d->dial2_num_modes = device->dial2_num_modes; d->ring_num_modes = device->ring_num_modes; d->ring2_num_modes = device->ring2_num_modes; d->styli = g_array_sized_new(FALSE, FALSE, sizeof(int), @@ -522,12 +525,21 @@ libwacom_compare(const WacomDevice *a, const WacomDevice *b, WacomCompareFlags f if (a->num_strips != b->num_strips) return 1; + if (a->num_dials != b->num_dials) + return 1; + if (a->features != b->features) return 1; if (a->strips_num_modes != b->strips_num_modes) return 1; + if (a->dial_num_modes != b->dial_num_modes) + return 1; + + if (a->dial2_num_modes != b->dial2_num_modes) + return 1; + if (a->ring_num_modes != b->ring_num_modes) return 1; @@ -843,13 +855,18 @@ static void print_buttons_for_device (int fd, const WacomDevice *device) print_button_flag_if(fd, device, "Bottom", WACOM_BUTTON_POSITION_BOTTOM); print_button_flag_if(fd, device, "Touchstrip", WACOM_BUTTON_TOUCHSTRIP_MODESWITCH); print_button_flag_if(fd, device, "Touchstrip2", WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH); + print_button_flag_if(fd, device, "Dial", WACOM_BUTTON_DIAL_MODESWITCH); print_button_flag_if(fd, device, "OLEDs", WACOM_BUTTON_OLED); print_button_flag_if(fd, device, "Ring", WACOM_BUTTON_RING_MODESWITCH); print_button_flag_if(fd, device, "Ring2", WACOM_BUTTON_RING2_MODESWITCH); + print_button_flag_if(fd, device, "Dial", WACOM_BUTTON_DIAL_MODESWITCH); + print_button_flag_if(fd, device, "Dial2", WACOM_BUTTON_DIAL2_MODESWITCH); print_button_evdev_codes(fd, device); dprintf(fd, "RingNumModes=%d\n", libwacom_get_ring_num_modes(device)); dprintf(fd, "Ring2NumModes=%d\n", libwacom_get_ring2_num_modes(device)); dprintf(fd, "StripsNumModes=%d\n", libwacom_get_strips_num_modes(device)); + dprintf(fd, "DialNumModes=%d\n", libwacom_get_dial_num_modes(device)); + dprintf(fd, "Dial2NumModes=%d\n", libwacom_get_dial2_num_modes(device)); dprintf(fd, "\n"); } @@ -953,6 +970,9 @@ libwacom_print_device_description(int fd, const WacomDevice *device) dprintf(fd, "NumStrips=%d\n", libwacom_get_num_strips(device)); dprintf(fd, "\n"); + dprintf(fd, "NumDials=%d\n", libwacom_get_num_dials(device)); + dprintf(fd, "\n"); + print_buttons_for_device(fd, device); } @@ -1244,6 +1264,24 @@ libwacom_get_strips_num_modes(const WacomDevice *device) return device->strips_num_modes; } +LIBWACOM_EXPORT int +libwacom_get_num_dials(const WacomDevice *device) +{ + return device->num_dials; +} + +LIBWACOM_EXPORT int +libwacom_get_dial_num_modes(const WacomDevice *device) +{ + return device->dial_num_modes; +} + +LIBWACOM_EXPORT int +libwacom_get_dial2_num_modes(const WacomDevice *device) +{ + return device->dial2_num_modes; +} + LIBWACOM_EXPORT const WacomStatusLEDs * libwacom_get_status_leds(const WacomDevice *device, int *num_leds) { diff --git a/libwacom/libwacom.h b/libwacom/libwacom.h index 2a8b3990..5c0d1f9b 100644 --- a/libwacom/libwacom.h +++ b/libwacom/libwacom.h @@ -231,10 +231,13 @@ typedef enum { WACOM_BUTTON_TOUCHSTRIP_MODESWITCH = (1 << 7), WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH = (1 << 8), WACOM_BUTTON_OLED = (1 << 9), - WACOM_BUTTON_MODESWITCH = (WACOM_BUTTON_RING_MODESWITCH | WACOM_BUTTON_RING2_MODESWITCH | WACOM_BUTTON_TOUCHSTRIP_MODESWITCH | WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH), + WACOM_BUTTON_DIAL_MODESWITCH = (1 << 10), + WACOM_BUTTON_DIAL2_MODESWITCH = (1 << 11), + WACOM_BUTTON_MODESWITCH = (WACOM_BUTTON_RING_MODESWITCH | WACOM_BUTTON_RING2_MODESWITCH | WACOM_BUTTON_TOUCHSTRIP_MODESWITCH | WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH | WACOM_BUTTON_DIAL_MODESWITCH | WACOM_BUTTON_DIAL2_MODESWITCH), WACOM_BUTTON_DIRECTION = (WACOM_BUTTON_POSITION_LEFT | WACOM_BUTTON_POSITION_RIGHT | WACOM_BUTTON_POSITION_TOP | WACOM_BUTTON_POSITION_BOTTOM), WACOM_BUTTON_RINGS_MODESWITCH = (WACOM_BUTTON_RING_MODESWITCH | WACOM_BUTTON_RING2_MODESWITCH), WACOM_BUTTON_TOUCHSTRIPS_MODESWITCH = (WACOM_BUTTON_TOUCHSTRIP_MODESWITCH | WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH), + WACOM_BUTTON_DIALS_MODESWITCH = (WACOM_BUTTON_DIAL_MODESWITCH | WACOM_BUTTON_DIAL2_MODESWITCH), } WacomButtonFlags; /** @@ -682,6 +685,31 @@ int libwacom_get_num_strips(const WacomDevice *device); */ int libwacom_get_strips_num_modes(const WacomDevice *device); +/** + * @param device The tablet to query + * @return the number of rotary dials on the tablet + * otherwise + * + * @ingroup devices + */ +int libwacom_get_num_dials(const WacomDevice *device); + +/** + * @param device The tablet to query + * @return the number of modes for the dial, if any + * + * @ingroup devices + */ +int libwacom_get_dial_num_modes(const WacomDevice *device); + +/** + * @param device The tablet to query + * @return the number of modes for the second dial, if any + * + * @ingroup devices + */ +int libwacom_get_dial2_num_modes(const WacomDevice *device); + /** * @param device The tablet to query * @param num_leds Return location for the number of supported status LEDs diff --git a/libwacom/libwacom.sym b/libwacom/libwacom.sym index b34848e6..7238d63d 100644 --- a/libwacom/libwacom.sym +++ b/libwacom/libwacom.sym @@ -74,6 +74,9 @@ LIBWACOM_2.9 { } LIBWACOM_2.0; LIBWACOM_2.12 { - libwacom_match_get_uniq; + libwacom_get_dial_num_modes; + libwacom_get_dial2_num_modes; + libwacom_get_num_dials; libwacom_get_num_rings; + libwacom_match_get_uniq; } LIBWACOM_2.9; diff --git a/libwacom/libwacomint.h b/libwacom/libwacomint.h index 14d4f5d0..265998ee 100644 --- a/libwacom/libwacomint.h +++ b/libwacom/libwacomint.h @@ -88,10 +88,13 @@ struct _WacomDevice { WacomClass cls; int num_strips; int num_rings; + int num_dials; uint32_t features; uint32_t integration_flags; int strips_num_modes; + int dial_num_modes; + int dial2_num_modes; int ring_num_modes; int ring2_num_modes; diff --git a/test/test-load.c b/test/test-load.c index 361b8c73..08aa8070 100644 --- a/test/test-load.c +++ b/test/test-load.c @@ -126,6 +126,7 @@ test_intuos4(struct fixture *f, gconstpointer user_data) g_assert_cmpint(libwacom_get_num_rings(device), ==, 1); g_assert_false(libwacom_has_touchswitch(device)); g_assert_cmpint(libwacom_get_num_strips(device), ==, 0); + g_assert_cmpint(libwacom_get_num_dials(device), ==, 0); g_assert_cmpint(libwacom_get_integration_flags (device), ==, WACOM_DEVICE_INTEGRATED_NONE); g_assert_cmpint(libwacom_get_width(device), ==, 8); g_assert_cmpint(libwacom_get_height(device), ==, 5); @@ -177,6 +178,7 @@ test_cintiq21ux(struct fixture *f, gconstpointer user_data) g_assert_nonnull(device); g_assert_cmpint(libwacom_get_num_strips(device), ==, 2); + g_assert_cmpint(libwacom_get_num_dials(device), ==, 0); libwacom_destroy(device); } diff --git a/test/test-tablet-svg-validity.c b/test/test-tablet-svg-validity.c index 2084d282..e42b7f98 100644 --- a/test/test-tablet-svg-validity.c +++ b/test/test-tablet-svg-validity.c @@ -176,6 +176,56 @@ check_touchstrip (xmlNodePtr cur, gchar *id) g_free (class); } +static void +check_dial (xmlNodePtr cur, gchar *id) +{ + char *sub; + char *class; + xmlNodePtr node; + + node = verify_has_sub (cur, id); + g_assert (node != NULL); + + class = g_strdup_printf ("%s %s", id, "Dial"); + verify_has_class (node, class); + g_free (class); + + sub = g_strdup_printf ("Label%sUp", id); + node = verify_has_sub (cur, sub); + g_assert (node != NULL); + g_free (sub); + + class = g_strdup_printf ("%sUp %s Label", id, id); + verify_has_class (node, class); + g_free (class); + + sub = g_strdup_printf ("Label%sDown", id); + node = verify_has_sub (cur, sub); + g_assert (node != NULL); + g_free (sub); + + class = g_strdup_printf ("%sDown %s Label", id, id); + verify_has_class (node, class); + g_free (class); + + sub = g_strdup_printf ("Leader%sUp", id); + node = verify_has_sub (cur, sub); + g_assert (node != NULL); + g_free (sub); + + class = g_strdup_printf ("%sUp %s Leader", id, id); + verify_has_class (node, class); + g_free (class); + + sub = g_strdup_printf ("Leader%sDown", id); + node = verify_has_sub (cur, sub); + g_assert (node != NULL); + g_free (sub); + + class = g_strdup_printf ("%sDown %s Leader", id, id); + verify_has_class (node, class); + g_free (class); +} static void check_touchring (xmlNodePtr cur, gchar *id) @@ -279,6 +329,17 @@ test_strips(struct fixture *f, gconstpointer data) check_touchstrip(f->root, "Strip2"); } +static void +test_dials(struct fixture *f, gconstpointer data) +{ + const WacomDevice *device = data; + + if (libwacom_get_num_dials(device) > 0) + check_dial(f->root, "Dial"); + if (libwacom_get_num_dials(device) > 1) + check_dial(f->root, "Dial"); +} + static void test_buttons(struct fixture *f, gconstpointer data) { @@ -366,6 +427,8 @@ static void setup_tests(WacomDevice *device) add_test(device, test_rings); if (libwacom_get_num_strips(device) > 0) add_test(device, test_strips); + if (libwacom_get_num_dials(device) > 0) + add_test(device, test_dials); } static WacomDeviceDatabase * diff --git a/test/test-tablet-validity.c b/test/test-tablet-validity.c index b55dd8b3..69d34c81 100644 --- a/test/test-tablet-validity.c +++ b/test/test-tablet-validity.c @@ -295,6 +295,25 @@ test_strips(gconstpointer data) WACOM_BUTTON_TOUCHSTRIP_MODESWITCH)); } +static void +test_dials(gconstpointer data) +{ + WacomDevice *device = (WacomDevice*)data; + + g_assert_cmpint(libwacom_get_num_dials(device), >=, 0); + g_assert_cmpint(libwacom_get_dial_num_modes(device), >=, 0); + + if (libwacom_get_num_dials(device) > 0) + g_assert_true(match_mode_switch(device, + libwacom_get_dial_num_modes, + WACOM_BUTTON_DIAL_MODESWITCH)); + + if (libwacom_get_num_dials(device) > 1) + g_assert_true(match_mode_switch(device, + libwacom_get_dial2_num_modes, + WACOM_BUTTON_DIAL2_MODESWITCH)); +} + /* Wrapper function to make adding tests simpler. g_test requires * a unique test case name so we assemble that from the test function and * the tablet data. @@ -339,6 +358,7 @@ static void setup_tests(WacomDevice *device) add_test(device, test_styli); add_test(device, test_rings); add_test(device, test_strips); + add_test(device, test_dials); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" diff --git a/tools/debug-device.c b/tools/debug-device.c index 5d125b96..2cdac201 100644 --- a/tools/debug-device.c +++ b/tools/debug-device.c @@ -162,6 +162,9 @@ handle_device(WacomDeviceDatabase *db, const char *path) intfunc(libwacom_get_ring2_num_modes, device); intfunc(libwacom_get_num_strips, device); intfunc(libwacom_get_strips_num_modes, device); + intfunc(libwacom_get_num_dials, device); + intfunc(libwacom_get_dial_num_modes, device); + intfunc(libwacom_get_dial2_num_modes, device); { WacomIntegrationFlags flags = libwacom_get_integration_flags(device); @@ -190,7 +193,7 @@ handle_device(WacomDeviceDatabase *db, const char *path) WacomButtonFlags flags; flags = libwacom_get_button_flag(device, b); - func_arg(libwacom_get_button_flag, "%c", b, "%s%s%s%s%s%s%s%s%s%s", + func_arg(libwacom_get_button_flag, "%c", b, "%s%s%s%s%s%s%s%s%s%s%s%s", flags == WACOM_BUTTON_NONE ? "NONE" : "", flags & WACOM_BUTTON_POSITION_LEFT ? "POSITION_LEFT|" : "", flags & WACOM_BUTTON_POSITION_RIGHT ? "POSITION_RIGHT|" : "", @@ -200,8 +203,9 @@ handle_device(WacomDeviceDatabase *db, const char *path) flags & WACOM_BUTTON_RING2_MODESWITCH ? "RING2_MODESWITCH|" : "", flags & WACOM_BUTTON_TOUCHSTRIP_MODESWITCH ? "TOUCHSTRIP_MODESWITCH|" : "", flags & WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH ? "TOUCHSTRIP2_MODESWITCH|" : "", + flags & WACOM_BUTTON_DIAL_MODESWITCH ? "DIAL_MODESWITCH|" : "", + flags & WACOM_BUTTON_DIAL2_MODESWITCH ? "DIAL2_MODESWITCH|" : "", flags & WACOM_BUTTON_OLED ? "OLED " : ""); - } }