From 884d4230d1b72081abb8ec905c92aade2111161e Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 7 Aug 2024 15:39:29 +1000 Subject: [PATCH] Support styli from vendors other than Wacom The current API uses tool IDs that are bound to Wacom devices (currently only wacom devices use those). If we have styli from other vendors that use the same tool ID we cannot currently express this without having duplicates. This patch introduces an internal WacomStylusId struct with vid and tool_id and switches the internal code over to use that. It deprecates the current stylus id functions and replaces them with a set that returns the WacomStylus pointer to the caller instead of just the id. Where the id is actually used, the caller can then query that struct. A special case are the @generic styli which are assigned a VID of zero. Internal behaviour treats Wacom styli still special: styli with the 0x56a vendor id will not have a vid prefix but just the default tool id. Likewise, the legacy functions libwacom_get_supported_styli() only returns Wacom and the generic styli. --- data/libwacom.stylus | 10 +-- libwacom/libwacom-database.c | 150 +++++++++++++++++++++++++--------- libwacom/libwacom.c | 116 +++++++++++++++++++++----- libwacom/libwacom.h | 51 ++++++++++++ libwacom/libwacom.sym | 6 ++ libwacom/libwacomint.h | 19 ++++- test/__init__.py | 103 ++++++++++++++++++++++- test/test-dbverify.c | 11 ++- test/test-stylus-validity.c | 82 +++++++++---------- test/test-tablet-validity.c | 50 ++++++++++-- test/test_libwacom.py | 85 ++++++++++++++++++- tools/debug-device.c | 41 +++++++++- tools/list-compatible-styli.c | 8 +- tools/list-local-devices.c | 17 ++-- 14 files changed, 607 insertions(+), 142 deletions(-) diff --git a/data/libwacom.stylus b/data/libwacom.stylus index d19ffdd85..9c90e57c3 100644 --- a/data/libwacom.stylus +++ b/data/libwacom.stylus @@ -1,22 +1,22 @@ # Some generic fallback styli -[0xfffff] +[0x0:0xfffff] Name=General Pen Group=generic-with-eraser -PairedStylusIds=0xffffe; +PairedStylusIds=0x0:0xffffe; Buttons=2 Axes=Tilt;Pressure;Distance; Type=General -[0xffffe] +[0x0:0xffffe] Name=General Pen Eraser Group=generic-with-eraser -PairedStylusIds=0xfffff; +PairedStylusIds=0x0:0xfffff; EraserType=Invert Buttons=2 Axes=Tilt;Pressure;Distance; Type=General -[0xffffd] +[0x0:0xffffd] Name=General Pen with no Eraser Group=generic-no-eraser Buttons=2 diff --git a/libwacom/libwacom-database.c b/libwacom/libwacom-database.c index 35bd65c9d..f7c41fdad 100644 --- a/libwacom/libwacom-database.c +++ b/libwacom/libwacom-database.c @@ -253,6 +253,32 @@ libwacom_matchstr_to_paired(WacomDevice *device, const char *matchstr) return TRUE; } +static bool +parse_stylus_id(const char *str, WacomStylusId *id) +{ + char **tokens = g_strsplit(str, ":", 2); + const char *vidstr, *tidstr; + int vid, tool_id; + bool ret = false; + + if (tokens[1] == NULL) { + vidstr = G_STRINGIFY(WACOM_VENDOR_ID); + tidstr = tokens[0]; + } else { + vidstr = tokens[0]; + tidstr = tokens[1]; + } + + if (safe_atoi_base (vidstr, &vid, 16) && safe_atoi_base (tidstr, &tool_id, 16)) { + id->vid = vid; + id->tool_id = tool_id; + ret = true; + } + g_clear_pointer(&tokens, g_strfreev); + + return ret; +} + static void libwacom_parse_stylus_keyfile(WacomDeviceDatabase *db, const char *path) { @@ -266,36 +292,41 @@ libwacom_parse_stylus_keyfile(WacomDeviceDatabase *db, const char *path) rc = g_key_file_load_from_file(keyfile, path, G_KEY_FILE_NONE, &error); g_assert (rc); + groups = g_key_file_get_groups (keyfile, NULL); for (i = 0; groups[i]; i++) { WacomStylus *stylus; + WacomStylusId id; GError *error = NULL; char *eraser_type, *type; - int tool_id; char **string_list; - if (!safe_atoi_base (groups[i], &tool_id, 16)) { + if (!parse_stylus_id(groups[i], &id)) { g_warning ("Failed to parse stylus ID '%s'", groups[i]); continue; } - stylus = g_new0 (WacomStylus, 1); stylus->refcnt = 1; - stylus->tool_id = tool_id; + stylus->id = id; stylus->name = g_key_file_get_string(keyfile, groups[i], "Name", NULL); stylus->group = g_key_file_get_string(keyfile, groups[i], "Group", NULL); + stylus->paired_stylus_ids = g_array_new (FALSE, FALSE, sizeof(WacomStylusId)); eraser_type = g_key_file_get_string(keyfile, groups[i], "EraserType", NULL); stylus->eraser_type = eraser_type_from_str (eraser_type); g_clear_pointer(&eraser_type, g_free); - stylus->paired_ids = g_array_new (FALSE, FALSE, sizeof(int)); + /* We have to keep the integer array for libwacom_get_supported_styli() */ + stylus->deprecated_paired_ids = g_array_new (FALSE, FALSE, sizeof(int)); + stylus->paired_styli = g_array_new (FALSE, FALSE, sizeof(WacomStylus*)); + string_list = g_key_file_get_string_list (keyfile, groups[i], "PairedStylusIds", NULL, NULL); for (guint j = 0; string_list && string_list[j]; j++) { - int val; - - if (safe_atoi_base (string_list[j], &val, 16)) { - g_array_append_val (stylus->paired_ids, val); + WacomStylusId paired_id; + if (parse_stylus_id(string_list[j], &paired_id)) { + g_array_append_val (stylus->paired_stylus_ids, paired_id); + if (paired_id.vid == WACOM_VENDOR_ID) + g_array_append_val (stylus->deprecated_paired_ids, paired_id.tool_id); } else { g_warning ("Stylus %s (%s) Ignoring invalid PairedStylusIds value\n", stylus->name, groups[i]); } @@ -346,10 +377,10 @@ libwacom_parse_stylus_keyfile(WacomDeviceDatabase *db, const char *path) stylus->type = type_from_str (type); g_clear_pointer(&type, g_free); - if (g_hash_table_lookup (db->stylus_ht, GINT_TO_POINTER (tool_id)) != NULL) - g_warning ("Duplicate definition for stylus ID '%#x'", tool_id); + if (g_hash_table_lookup (db->stylus_ht, &id) != NULL) + g_warning ("Duplicate definition for stylus ID '%s'", groups[i]); - g_hash_table_insert (db->stylus_ht, GINT_TO_POINTER (tool_id), stylus); + g_hash_table_insert (db->stylus_ht, g_memdup2(&id, sizeof(id)), stylus); } g_clear_pointer(&groups, g_strfreev); g_clear_pointer(&keyfile, g_key_file_free); @@ -364,23 +395,24 @@ libwacom_setup_paired_attributes(WacomDeviceDatabase *db) g_hash_table_iter_init(&iter, db->stylus_ht); while (g_hash_table_iter_next (&iter, &key, &value)) { WacomStylus *stylus = value; - const int* ids; - int count; - int i; + GArray *paired_ids = g_steal_pointer(&stylus->paired_stylus_ids); - ids = libwacom_stylus_get_paired_ids(stylus, &count); - for (i = 0; i < count; i++) { - const WacomStylus *pair; + for (guint i = 0; i < paired_ids->len; i++) { + WacomStylusId *id = &g_array_index(paired_ids, WacomStylusId, i); + WacomStylus *paired = g_hash_table_lookup(db->stylus_ht, id); - pair = libwacom_stylus_get_for_id(db, ids[i]); - if (pair == NULL) { - g_warning("Paired stylus '0x%x' not found, ignoring.", ids[i]); + if (paired == NULL) { + g_warning ("Invalid paired stylus %04x:%x", id->vid, id->tool_id); continue; } - if (libwacom_stylus_is_eraser(pair)) { + + g_array_append_val(stylus->paired_styli, paired); + + if (libwacom_stylus_is_eraser(paired)) { stylus->has_eraser = true; } } + g_array_unref(paired_ids); } } @@ -688,12 +720,21 @@ libwacom_parse_keys(WacomDevice *device, libwacom_parse_key_codes(device, keyfile); } +static int +wacom_stylus_id_sort(const WacomStylusId *a, const WacomStylusId *b) +{ + if (a->vid == b->vid) + return a->tool_id - b->tool_id; + + return a->vid - b->vid; +} static int styli_id_sort(gconstpointer pa, gconstpointer pb) { - const int *a = pa, *b = pb; - return *a > *b ? 1 : *a == *b ? 0 : -1; + const WacomStylus *a = *(WacomStylus**)pa, *b = *(WacomStylus**)pb; + + return wacom_stylus_id_sort(&a->id, &b->id); } static void @@ -703,17 +744,23 @@ libwacom_parse_styli_list(WacomDeviceDatabase *db, WacomDevice *device, GArray *array; guint i; - array = g_array_new (FALSE, FALSE, sizeof(int)); + array = g_array_new (FALSE, FALSE, sizeof(WacomStylus*)); for (i = 0; ids[i]; i++) { - const char *id = ids[i]; - - if (g_str_has_prefix(id, "0x")) { - int int_value; - if (safe_atoi_base (ids[i], &int_value, 16)) { - g_array_append_val (array, int_value); + const char *str = ids[i]; + + if (g_str_has_prefix(str, "0x")) { + WacomStylusId id; + if (parse_stylus_id(str, &id)) { + WacomStylus *stylus = g_hash_table_lookup(db->stylus_ht, &id); + if (stylus) + g_array_append_val (array, stylus); + else + g_warning ("Invalid stylus id for '%s'!", str); + } else { + g_warning ("Invalid stylus id format for '%s'!", str); } - } else if (g_str_has_prefix(id, "@")) { - const char *group = &id[1]; + } else if (g_str_has_prefix(str, "@")) { + const char *group = &str[1]; GHashTableIter iter; gpointer key, value; @@ -721,17 +768,27 @@ libwacom_parse_styli_list(WacomDeviceDatabase *db, WacomDevice *device, while (g_hash_table_iter_next (&iter, &key, &value)) { WacomStylus *stylus = value; if (stylus->group && g_str_equal(group, stylus->group)) { - g_array_append_val (array, stylus->tool_id); + g_array_append_val (array, stylus); } } } else { - g_warning ("Invalid prefix for '%s'!", id); + g_warning ("Invalid prefix for '%s'!", str); } } /* Using groups means we don't get the styli in ascending order. Sort it so the output is predictable */ g_array_sort(array, styli_id_sort); device->styli = array; + + /* The legacy PID-only stylus id list */ + device->deprecated_styli_ids = g_array_new(FALSE, FALSE, sizeof(int)); + for (guint i = 0; i < device->styli->len; i++) { + WacomStylus *stylus = g_array_index(device->styli, WacomStylus*, i); + /* This only ever worked for Wacom styli, so let's keep that behavior */ + if (stylus->id.vid == 0 || stylus->id.vid == WACOM_VENDOR_ID) { + g_array_append_val(device->deprecated_styli_ids, stylus->id.tool_id); + } + } } static void @@ -890,8 +947,8 @@ libwacom_parse_tablet_keyfile(WacomDeviceDatabase *db, string_list = g_key_file_get_string_list(keyfile, DEVICE_GROUP, "Styli", NULL, NULL); if (!string_list) { string_list = g_new0(char*, 3); - string_list[0] = g_strdup_printf("0x%x", WACOM_ERASER_FALLBACK_ID); - string_list[1] = g_strdup_printf("0x%x", WACOM_STYLUS_FALLBACK_ID); + string_list[0] = g_strdup_printf("0x0:0x%x", WACOM_ERASER_FALLBACK_ID); + string_list[1] = g_strdup_printf("0x0:0x%x", WACOM_STYLUS_FALLBACK_ID); } libwacom_parse_styli_list(db, device, string_list); g_strfreev (string_list); @@ -1060,6 +1117,19 @@ load_stylus_files(WacomDeviceDatabase *db, const char *datadir) return true; } +static guint +stylus_hash(WacomStylusId *id) +{ + guint64 full_id = (guint64)id->vid << 32 | id->tool_id; + return g_int64_hash(&full_id); +} + +static gboolean +stylus_compare(WacomStylusId *a, WacomStylusId *b) +{ + return wacom_stylus_id_sort(a, b) == 0; +} + static WacomDeviceDatabase * database_new_for_paths (size_t npaths, const char **datadirs) { @@ -1072,9 +1142,9 @@ database_new_for_paths (size_t npaths, const char **datadirs) g_str_equal, g_free, (GDestroyNotify) libwacom_destroy); - db->stylus_ht = g_hash_table_new_full (g_direct_hash, - g_direct_equal, - NULL, + db->stylus_ht = g_hash_table_new_full ((GHashFunc)stylus_hash, + (GEqualFunc)stylus_compare, + (GDestroyNotify) g_free, (GDestroyNotify) stylus_destroy); for (datadir = datadirs, n = npaths; n--; datadir++) { diff --git a/libwacom/libwacom.c b/libwacom/libwacom.c index 4366f2915..e927c60cd 100644 --- a/libwacom/libwacom.c +++ b/libwacom/libwacom.c @@ -419,7 +419,9 @@ libwacom_copy(const WacomDevice *device) d->ring_num_modes = device->ring_num_modes; d->ring2_num_modes = device->ring2_num_modes; d->styli = g_array_copy(device->styli); + d->deprecated_styli_ids = g_array_copy(device->deprecated_styli_ids); d->status_leds = g_array_copy(device->status_leds); + d->buttons = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); g_hash_table_iter_init(&iter, device->buttons); @@ -544,11 +546,23 @@ libwacom_compare(const WacomDevice *a, const WacomDevice *b, WacomCompareFlags f if (g_hash_table_size(a->buttons) != g_hash_table_size(b->buttons)) return 1; + /* We don't need to check deprecated_stylus_ids because if they differ + * when the real id doesn't that's a bug */ + if (a->styli->len != b->styli->len) return 1; - if (memcmp(a->styli->data, b->styli->data, sizeof(int) * a->styli->len) != 0) - return 1; + /* This needs to be a deep comparison - our styli array contains + * WacomStylus* pointers but we want libwacom_compare() to return + * true if the stylus data matches (test-dbverify compares styli + * from two different WacomDeviceDatabase). + */ + for (guint i = 0; i < a->styli->len; i++) { + WacomStylus *as = g_array_index(a->styli, WacomStylus*, i); + WacomStylus *bs = g_array_index(b->styli, WacomStylus*, i); + if (as->id.tool_id != bs->id.tool_id) + return 1; + } if (a->status_leds->len != b->status_leds->len) return 1; @@ -849,7 +863,7 @@ libwacom_new_from_name(const WacomDeviceDatabase *db, const char *name, WacomErr static void print_styli_for_device (int fd, const WacomDevice *device) { int nstyli; - const int *styli; + const WacomStylus **styli; int i; unsigned idx = 0; char buf[1024] = {0}; @@ -857,14 +871,18 @@ static void print_styli_for_device (int fd, const WacomDevice *device) if (!libwacom_has_stylus(device)) return; - styli = libwacom_get_supported_styli(device, &nstyli); - + styli = libwacom_get_styli(device, &nstyli); for (i = 0; i < nstyli; i++) { + const WacomStylus *stylus = styli[i]; /* 20 digits for a stylus are enough, right */ assert(idx < sizeof(buf) - 20); - idx += snprintf(buf + idx, 20, "%#x;", styli[i]); + if (stylus->id.vid != WACOM_VENDOR_ID) + idx += snprintf(buf + idx, 20, "0x%04x:%#x;", stylus->id.vid, stylus->id.tool_id); + else + idx += snprintf(buf + idx, 20, "%#x;", stylus->id.tool_id); } + g_free(styli); dprintf(fd, "Styli=%s\n", buf); } @@ -1112,6 +1130,7 @@ libwacom_unref(WacomDevice *device) g_clear_pointer (&device->matches, g_array_unref); libwacom_match_unref(device->match); g_clear_pointer (&device->styli, g_array_unref); + g_clear_pointer (&device->deprecated_styli_ids, g_array_unref); g_clear_pointer (&device->status_leds, g_array_unref); g_clear_pointer (&device->buttons, g_hash_table_destroy); g_free (device); @@ -1373,8 +1392,23 @@ libwacom_get_num_keys(const WacomDevice *device) LIBWACOM_EXPORT const int * libwacom_get_supported_styli(const WacomDevice *device, int *num_styli) { - *num_styli = device->styli->len; - return (const int *)device->styli->data; + *num_styli = device->deprecated_styli_ids->len; + return (const int *)device->deprecated_styli_ids->data; +} + +LIBWACOM_EXPORT const WacomStylus ** +libwacom_get_styli(const WacomDevice *device, int *num_styli) +{ + int count = device->styli->len; + const WacomStylus **styli = g_new0(const WacomStylus*, count + 1); + + if (count > 0) + memcpy(styli, device->styli->data, count * sizeof(WacomStylus*)); + + if (num_styli) + *num_styli = count; + + return styli; } LIBWACOM_EXPORT int @@ -1534,16 +1568,34 @@ libwacom_get_button_evdev_code(const WacomDevice *device, char button) return b ? b->code : 0; } +static const WacomStylus * +libwacom_stylus_get_for_stylus_id (const WacomDeviceDatabase *db, + const WacomStylusId *id) +{ + return g_hash_table_lookup (db->stylus_ht, id); +} + LIBWACOM_EXPORT const WacomStylus * -libwacom_stylus_get_for_id (const WacomDeviceDatabase *db, int id) +libwacom_stylus_get_for_id (const WacomDeviceDatabase *db, int tool_id) { - return g_hash_table_lookup (db->stylus_ht, GINT_TO_POINTER(id)); + WacomStylusId id = { + .vid = WACOM_VENDOR_ID, + .tool_id = tool_id, + }; + + return libwacom_stylus_get_for_stylus_id (db, &id); } LIBWACOM_EXPORT int libwacom_stylus_get_id (const WacomStylus *stylus) { - return stylus->tool_id; + return stylus->id.tool_id; +} + +LIBWACOM_EXPORT int +libwacom_stylus_get_vendor_id (const WacomStylus *stylus) +{ + return stylus->id.vid; } LIBWACOM_EXPORT const char * @@ -1556,15 +1608,29 @@ LIBWACOM_EXPORT const int * libwacom_stylus_get_paired_ids(const WacomStylus *stylus, int *num_paired_ids) { if (num_paired_ids) - *num_paired_ids = stylus->paired_ids->len; - return (const int*)stylus->paired_ids->data; + *num_paired_ids = stylus->deprecated_paired_ids->len; + return (const int*)stylus->deprecated_paired_ids->data; +} + +LIBWACOM_EXPORT const WacomStylus ** +libwacom_stylus_get_paired_styli(const WacomStylus *stylus, int *num_paired) +{ + int count = stylus->paired_styli->len; + const WacomStylus **styli = g_new0(const WacomStylus*, count + 1); + + if (num_paired) + *num_paired = count; + + if (count > 0) + memcpy(styli, stylus->paired_styli->data, count * sizeof(WacomStylus*)); + return styli; } LIBWACOM_EXPORT int libwacom_stylus_get_num_buttons (const WacomStylus *stylus) { if (stylus->num_buttons == -1) { - g_warning ("Stylus '0x%x' has no number of buttons defined, falling back to 2", stylus->tool_id); + g_warning ("Stylus '0x%x' has no number of buttons defined, falling back to 2", stylus->id.tool_id); return 2; } return stylus->num_buttons; @@ -1604,7 +1670,7 @@ LIBWACOM_EXPORT WacomStylusType libwacom_stylus_get_type (const WacomStylus *stylus) { if (stylus->type == WSTYLUS_UNKNOWN) { - g_warning ("Stylus '0x%x' has no type defined, falling back to 'General'", stylus->tool_id); + g_warning ("Stylus '0x%x' has no type defined, falling back to 'General'", stylus->id.tool_id); return WSTYLUS_GENERAL; } return stylus->type; @@ -1621,17 +1687,25 @@ libwacom_print_stylus_description (int fd, const WacomStylus *stylus) { const char *type; WacomAxisTypeFlags axes; - const int *paired_ids; + const WacomStylus **paired; int count; int i; - dprintf(fd, "[%#x]\n", libwacom_stylus_get_id(stylus)); + if (libwacom_stylus_get_vendor_id(stylus) != WACOM_VENDOR_ID) + dprintf(fd, "[0x%x:%#x]\n", libwacom_stylus_get_vendor_id(stylus), libwacom_stylus_get_id(stylus)); + else + dprintf(fd, "[%#x]\n", libwacom_stylus_get_id(stylus)); + dprintf(fd, "Name=%s\n", libwacom_stylus_get_name(stylus)); dprintf(fd, "PairedIds="); - paired_ids = libwacom_stylus_get_paired_ids(stylus, &count); + paired = libwacom_stylus_get_paired_styli(stylus, &count); for (i = 0; i < count; i++) { - dprintf(fd, "%#x;", paired_ids[i]); + if (paired[i]->id.vid != 0x56a) + dprintf(fd, "%#04x:%#x;", paired[i]->id.vid, paired[i]->id.tool_id); + else + dprintf(fd, "%#x;", paired[i]->id.tool_id); } + g_free(paired); dprintf(fd, "\n"); switch (libwacom_stylus_get_eraser_type(stylus)) { case WACOM_ERASER_UNKNOWN: type = "Unknown"; break; @@ -1690,7 +1764,9 @@ libwacom_stylus_unref(WacomStylus *stylus) g_free (stylus->name); g_free (stylus->group); - g_clear_pointer (&stylus->paired_ids, g_array_unref); + g_clear_pointer (&stylus->deprecated_paired_ids, g_array_unref); + g_clear_pointer (&stylus->paired_stylus_ids, g_array_unref); + g_clear_pointer (&stylus->paired_styli, g_array_unref); g_free (stylus); return NULL; diff --git a/libwacom/libwacom.h b/libwacom/libwacom.h index c0d380c9c..987106580 100644 --- a/libwacom/libwacom.h +++ b/libwacom/libwacom.h @@ -648,9 +648,26 @@ int libwacom_get_num_keys(const WacomDevice *device); * @return an array of Styli IDs supported by the device * * @ingroup styli + * @deprecated 2.14 Use libwacom_get_styli() instead. */ +LIBWACOM_DEPRECATED const int *libwacom_get_supported_styli(const WacomDevice *device, int *num_styli); +/** + * @param device The tablet to query + * @param[out] num_styli Optional return location for the number of listed styli, + * excluding the NULL terminator. + * @return A null-terminated array of WacomStylus that are supported by this + * device + * + * The content of the list is owned by the database and must not be + * modified or freed. Use free() to free the list. + * + * @since 2.14 + * @ingroup styli + */ +const WacomStylus ** libwacom_get_styli(const WacomDevice *device, int *num_styli); + /** * @param device The tablet to query * @return non-zero if the device has a touch ring or zero otherwise @@ -824,12 +841,17 @@ int libwacom_get_button_evdev_code(const WacomDevice *device, /** * Get the WacomStylus for the given tool ID. * + * The vendor ID is assumed to be the Wacom vendor id 0x56a. + * * @param db A Tablet and Stylus database. * @param id The Tool ID for this stylus * @return A WacomStylus representing the stylus. Do not free. * * @ingroup styli + * @deprecated 2.14 Use libwacom_get_styli() and + * libwacom_stylus_get_paired_styli() to obtain the WacomStylus directly */ +LIBWACOM_DEPRECATED const WacomStylus *libwacom_stylus_get_for_id (const WacomDeviceDatabase *db, int id); /** @@ -840,6 +862,15 @@ const WacomStylus *libwacom_stylus_get_for_id (const WacomDeviceDatabase *db, in */ int libwacom_stylus_get_id (const WacomStylus *stylus); +/** + * @param stylus The stylus to query + * @return the vendor ID of the tool + * + * @ingroup styli + * @since 2.14 + */ +int libwacom_stylus_get_vendor_id (const WacomStylus *stylus); + /** * @param stylus The stylus to query * @return The name of the stylus @@ -853,10 +884,30 @@ const char *libwacom_stylus_get_name (const WacomStylus *stylus); * @param num_paired_ids The length of the returned list * @return The list of other IDs paired to this stylus * + * For historical reasons this function will only return paired ids that + * match Wacom's vendor ID 0x56a. Callers should use + * libwacom_stylus_get_paired_styli() instead. + * * @ingroup styli + * @deprecated 2.14 Use libwacom_stylus_get_paired_styli() instead */ +LIBWACOM_DEPRECATED const int *libwacom_stylus_get_paired_ids(const WacomStylus *stylus, int *num_paired_ids); +/** + * @param stylus The stylus to query + * @param[out] num_paired Optional return location for the length of the + * returned list, excluding the NULL terminator + * @return A NULL-terminated list contain the styli paired with this stylus + * + * The content of the list is owned by the database and must not be + * modified or freed. Use free() to free the list. + * + * @ingroup styli + * @since 2.14 + */ +const WacomStylus **libwacom_stylus_get_paired_styli(const WacomStylus *stylus, int *num_paired); + /** * @param stylus The stylus to query * @return The number of buttons on the stylus diff --git a/libwacom/libwacom.sym b/libwacom/libwacom.sym index be0dd1e03..65f104f73 100644 --- a/libwacom/libwacom.sym +++ b/libwacom/libwacom.sym @@ -88,3 +88,9 @@ LIBWACOM_2.12 { libwacom_builder_set_usbid; libwacom_new_from_builder; } LIBWACOM_2.9; + +LIBWACOM_2.14 { + libwacom_get_styli; + libwacom_stylus_get_paired_styli; + libwacom_stylus_get_vendor_id; +} LIBWACOM_2.12; diff --git a/libwacom/libwacomint.h b/libwacom/libwacomint.h index 36a6bf746..7178777da 100644 --- a/libwacom/libwacomint.h +++ b/libwacom/libwacomint.h @@ -40,6 +40,7 @@ #define GENERIC_DEVICE_MATCH "generic" #define WACOM_DEVICE_INTEGRATED_UNSET (WACOM_DEVICE_INTEGRATED_NONE - 1U) +#define WACOM_VENDOR_ID 0x056a enum WacomFeature { FEATURE_STYLUS = (1 << 0), @@ -107,7 +108,10 @@ struct _WacomDevice { int ring_num_modes; int ring2_num_modes; - GArray *styli; + /* for libwacom_get_supported_styli() */ + GArray *deprecated_styli_ids; /* int */ + /* for libwacom_get_styli() */ + GArray *styli; /* WacomStylus* */ GHashTable *buttons; /* 'A' : WacomButton */ WacomKeycode keycodes[32]; size_t num_keycodes; @@ -119,14 +123,21 @@ struct _WacomDevice { gint refcnt; /* for the db hashtable */ }; +typedef struct _WacomStylusId { + unsigned int vid; + unsigned int tool_id; +} WacomStylusId; + struct _WacomStylus { gint refcnt; - int tool_id; + WacomStylusId id; char *name; char *group; int num_buttons; gboolean has_eraser; - GArray *paired_ids; + GArray *paired_styli; /* [WacomStylus*, ...] */ + GArray *deprecated_paired_ids; /* [int, ...] */ + GArray *paired_stylus_ids; /* [WacomStylusId, ...], NULL once parsing is complete */ WacomEraserType eraser_type; gboolean has_lens; gboolean has_wheel; @@ -136,7 +147,7 @@ struct _WacomStylus { struct _WacomDeviceDatabase { GHashTable *device_ht; /* key = DeviceMatch (str), value = WacomDeviceData * */ - GHashTable *stylus_ht; /* key = ID (int), value = WacomStylus * */ + GHashTable *stylus_ht; /* key = WacomStylusId, value = WacomStylus * */ }; struct _WacomError { diff --git a/test/__init__.py b/test/__init__.py index 3963d9e23..43083f108 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -199,6 +199,11 @@ def instance(cls): args=(c_void_p, c_void_p), return_type=c_void_p, ), + _Api( + name="libwacom_get_styli", + args=(c_void_p, c_void_p), + return_type=ctypes.POINTER(c_void_p), + ), _Api(name="libwacom_has_ring", args=(c_void_p,), return_type=c_int), _Api(name="libwacom_has_ring2", args=(c_void_p,), return_type=c_int), _Api(name="libwacom_get_num_rings", args=(c_void_p,), return_type=c_int), @@ -240,6 +245,7 @@ def instance(cls): return_type=c_void_p, ), _Api(name="libwacom_stylus_get_id", args=(c_void_p,), return_type=c_int), + _Api(name="libwacom_stylus_get_vendor_id", args=(c_void_p,), return_type=c_int), _Api(name="libwacom_stylus_get_name", args=(c_void_p,), return_type=c_char_p), _Api( name="libwacom_stylus_get_paired_ids", @@ -258,6 +264,11 @@ def instance(cls): _Api( name="libwacom_stylus_get_eraser_type", args=(c_void_p,), return_type=c_int ), + _Api( + name="libwacom_stylus_get_paired_styli", + args=(c_void_p, c_void_p), + return_type=ctypes.POINTER(c_void_p), + ), _Api( name="libwacom_print_stylus_description", args=(c_int, c_void_p), @@ -524,6 +535,87 @@ def __del__(self): lib.builder_destroy(self.builder) +class WacomStylusType(enum.IntEnum): + UNKNOWN = 0 + GENERAL = 1 + INKING = 2 + AIRBRUSH = 3 + CLASSIC = 4 + MARKER = 5 + STROKE = 6 + PUCK = 7 + THREED = 8 + MOBILE = 9 + + +class WacomEraserType(enum.IntEnum): + UNKNOWN = 0 + NONE = 1 + INVERT = 2 + BUTTON = 3 + + +class WacomStylus: + def __init__(self, stylus): + self.stylus = stylus + lib = LibWacom.instance() + + def wrapper(func): + return lambda *args, **kwargs: func(self.stylus, *args, **kwargs) + + # Map all device-specifice accessors into respective functions + for api in lib._api_prototypes: + allowlist = ["stylus"] + if any(api.basename.startswith(n) for n in allowlist): + denylist = ["stylus_get_paired_styli", "stylus_is_eraser"] + if all(not api.basename.startswith(n) for n in denylist): + func = getattr(lib, api.basename) + setattr(self, api.basename.removeprefix("stylus_"), wrapper(func)) + + @property + def name(self): + return self.get_name().decode("utf-8") + + @property + def group(self): + return self.get_group().decode("utf-8") + + @property + def tool_id(self) -> int: + return self.get_id() + + @property + def vendor_id(self) -> int: + return self.get_vendor_id() + + @property + def num_buttons(self) -> int: + return self.get_num_buttons() + + @property + def is_eraser(self) -> bool: + lib = LibWacom.instance() + return lib.stylus_is_eraser(self.stylus) != 0 + + @property + def stylus_type(self) -> WacomEraserType: + return WacomEraserType(self.get_eraser_type()) + + @property + def eraser_type(self) -> WacomEraserType: + return WacomEraserType(self.get_eraser_type()) + + def get_paired_styli(self) -> List["WacomStylus"]: + lib = LibWacom.instance() + paired = lib.stylus_get_paired_styli(self.stylus, None) + styli = [ + WacomStylus(p) + for p in itertools.takewhile(lambda ptr: ptr is not None, paired) + ] + GlibC.instance().free(paired) + return styli + + class WacomDevice: """ Convenience wrapper to make using libwacom a bit more pythonic. @@ -571,7 +663,7 @@ def wrapper(func): for api in lib._api_prototypes: allowlist = ["get_", "is_", "has_"] if any(api.basename.startswith(n) for n in allowlist): - denylist = ["get_paired_device", "get_matches"] + denylist = ["get_paired_device", "get_matches", "get_styli"] if all(not api.basename.startswith(n) for n in denylist): func = getattr(lib, api.basename) setattr(self, api.basename, wrapper(func)) @@ -595,6 +687,15 @@ def get_matches(self) -> List[WacomMatch]: for m in itertools.takewhile(lambda ptr: ptr is not None, matches) ] + def get_styli(self) -> List[WacomStylus]: + lib = LibWacom.instance() + styli = lib.get_styli(self.device, None) + + return [ + WacomStylus(m) + for m in itertools.takewhile(lambda ptr: ptr is not None, styli) + ] + def __del__(self): if self._destroy_on_del: lib = LibWacom.instance() diff --git a/test/test-dbverify.c b/test/test-dbverify.c index 64d47a34e..f33085d7d 100644 --- a/test/test-dbverify.c +++ b/test/test-dbverify.c @@ -179,7 +179,7 @@ duplicate_database(WacomDeviceDatabase *db, const char *dirname) int fd; char *path = NULL; int nstyli; - const int *styli; + const WacomStylus **styli; g_assert(asprintf(&path, "%s/%s.tablet", dirname, libwacom_get_match(*device)) != -1); @@ -193,20 +193,19 @@ duplicate_database(WacomDeviceDatabase *db, const char *dirname) if (!libwacom_has_stylus(*device)) continue; - styli = libwacom_get_supported_styli(*device, &nstyli); + styli = libwacom_get_styli(*device, &nstyli); for (i = 0; i < nstyli; i++) { int fd_stylus; - const WacomStylus *stylus; + const WacomStylus *stylus = styli[i]; - g_assert(asprintf(&path, "%s/%#x.stylus", dirname, styli[i]) != -1); - stylus = libwacom_stylus_get_for_id(db, styli[i]); - g_assert(stylus); + g_assert(asprintf(&path, "%s/%#x.stylus", dirname, libwacom_stylus_get_id(stylus)) != -1); fd_stylus = open(path, O_WRONLY|O_CREAT, S_IRWXU); g_assert(fd_stylus >= 0); libwacom_print_stylus_description(fd_stylus, stylus); close(fd_stylus); free(path); } + free(styli); } free(devices); diff --git a/test/test-stylus-validity.c b/test/test-stylus-validity.c index e17d91120..c9e7b078c 100644 --- a/test/test-stylus-validity.c +++ b/test/test-stylus-validity.c @@ -88,7 +88,7 @@ test_has_eraser(gconstpointer data) { const WacomStylus *stylus = data; gboolean matching_eraser_found = FALSE; - const int *ids; + const WacomStylus **paired; int count; int i; @@ -97,18 +97,17 @@ test_has_eraser(gconstpointer data) g_assert_false(libwacom_stylus_is_eraser(stylus)); /* Search for the linked eraser */ - ids = libwacom_stylus_get_paired_ids(stylus, &count); + paired = libwacom_stylus_get_paired_styli(stylus, &count); g_assert_cmpint(count, >, 0); for (i = 0; i < count; i++) { - for (const WacomStylus **s = all_styli; *s; s++) { - if (libwacom_stylus_get_id(*s) == ids[i] && - libwacom_stylus_is_eraser(*s)) { - matching_eraser_found = TRUE; - break; - } + const WacomStylus *s = paired[i]; + if (libwacom_stylus_is_eraser(s)) { + matching_eraser_found = TRUE; + break; } } + g_free(paired); g_assert_true(matching_eraser_found); } @@ -117,7 +116,7 @@ static void test_eraser_link(const WacomStylus *stylus, gboolean linked) { gboolean matching_stylus_found = FALSE; - const int *ids; + const WacomStylus **paired; int count; int i; @@ -126,23 +125,23 @@ test_eraser_link(const WacomStylus *stylus, gboolean linked) g_assert_true(libwacom_stylus_is_eraser(stylus)); /* Verify the link count */ - ids = libwacom_stylus_get_paired_ids(stylus, &count); + paired = libwacom_stylus_get_paired_styli(stylus, &count); if (!linked) { g_assert_cmpint(count, ==, 0); + g_free(paired); return; } /* If we're supposed to be linked, ensure its to a non-eraser */ g_assert_cmpint(count, >, 0); for (i = 0; i < count; i++) { - for (const WacomStylus **s = all_styli; *s; s++) { - if (libwacom_stylus_get_id(*s) == ids[i] && - libwacom_stylus_has_eraser(*s)) { - matching_stylus_found = TRUE; - break; - } + const WacomStylus *s = paired[i]; + if (libwacom_stylus_has_eraser(s)) { + matching_stylus_found = TRUE; + break; } } + g_free(paired); g_assert_true(matching_stylus_found); } @@ -274,35 +273,32 @@ static void test_mutually_paired(gconstpointer data) { const WacomStylus *stylus = data; - int stylus_id; - const int *stylus_pairings; + const WacomStylus **stylus_pairings; int count; - int i; - stylus_id = libwacom_stylus_get_id(stylus); - stylus_pairings = libwacom_stylus_get_paired_ids(stylus, &count); + stylus_pairings = libwacom_stylus_get_paired_styli(stylus, &count); - for (i = 0; i < count; i++) { - for (const WacomStylus **s = all_styli; *s; s++) { - gboolean match_found = FALSE; - const int *pair_ids; - int pair_count; - int j; - - if (libwacom_stylus_get_id(*s) != stylus_pairings[i]) - continue; - - pair_ids = libwacom_stylus_get_paired_ids(*s, &pair_count); - for (j = 0; j < pair_count; j++) { - if (pair_ids[j] == stylus_id) { - match_found = TRUE; - break; - } - } + for (int i = 0; i < count; i++) { + const WacomStylus *paired = stylus_pairings[i]; + const WacomStylus **counter_paired; + gboolean match_found = FALSE; + int pair_count; + + g_assert_true(paired != stylus); /* can't be paired with itself */ - g_assert_true(match_found); + counter_paired = libwacom_stylus_get_paired_styli(paired, &pair_count); + for (int j = 0; j < pair_count; j++) { + const WacomStylus *back_paired = counter_paired[j]; + if (back_paired == stylus) { + match_found = TRUE; + break; + } } + g_free(counter_paired); + + g_assert_true(match_found); } + g_free(stylus_pairings); } /* Wrapper function to make adding tests simpler. g_test requires @@ -451,14 +447,14 @@ assemble_styli(WacomDeviceDatabase *db) g_assert(devices); for (WacomDevice **d = devices; *d; d++) { - const int *styli; + const WacomStylus **styli; int nstyli; - styli = libwacom_get_supported_styli(*d, &nstyli); + styli = libwacom_get_styli(*d, &nstyli); for (int i = 0; i < nstyli; i++) { - const WacomStylus *stylus = libwacom_stylus_get_for_id (db, styli[i]); - g_hash_table_add(all, (gpointer)stylus); + g_hash_table_add(all, (gpointer)styli[i]); } + g_free(styli); } all_styli = (const WacomStylus**)g_hash_table_get_keys_as_array(all, NULL); diff --git a/test/test-tablet-validity.c b/test/test-tablet-validity.c index 69d34c81e..f63426493 100644 --- a/test/test-tablet-validity.c +++ b/test/test-tablet-validity.c @@ -243,24 +243,62 @@ static void test_styli(gconstpointer data) { WacomDevice *device = (WacomDevice*)data; - int nstyli; - const int *styli = libwacom_get_supported_styli(device, &nstyli); + int nstylus_ids, nstyli; + const WacomStylus **styli; + const int *stylus_ids; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + stylus_ids = libwacom_get_supported_styli(device, &nstylus_ids); +#pragma GCC diagnostic pop + styli = libwacom_get_styli(device, &nstyli); g_assert_cmpint(nstyli, >, 0); + g_assert_cmpint(nstyli, ==, nstylus_ids); g_assert_nonnull(styli); + g_assert_nonnull(stylus_ids); + g_assert_null(styli[nstyli]); /* NULL-terminated list */ + + for (int i = 0; i < nstyli; i++) { + const WacomStylus *stylus = styli[i]; + gboolean found = FALSE; + for (int j = 0; !found && j < nstylus_ids; j++) { + found = stylus_ids[j] == libwacom_stylus_get_id(stylus); + } + g_assert_true(found); + } + + g_free(styli); + } static void test_realstylus(gconstpointer data) { WacomDevice *device = (WacomDevice*)data; - int nstyli; - const int *styli = libwacom_get_supported_styli(device, &nstyli); + int nstylus_ids, nstyli; + const WacomStylus **styli; + const int *stylus_ids; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + stylus_ids = libwacom_get_supported_styli(device, &nstylus_ids); +#pragma GCC diagnostic pop + styli = libwacom_get_styli(device, &nstyli); + + for (int i = 0; i < nstylus_ids; i++) { + g_assert_cmpint(stylus_ids[i], !=, WACOM_STYLUS_FALLBACK_ID); + g_assert_cmpint(stylus_ids[i], !=, WACOM_ERASER_FALLBACK_ID); + } for (int i = 0; i < nstyli; i++) { - g_assert_cmpint(styli[i], !=, WACOM_STYLUS_FALLBACK_ID); - g_assert_cmpint(styli[i], !=, WACOM_ERASER_FALLBACK_ID); + const WacomStylus *stylus = styli[i]; + g_assert_cmpint(libwacom_stylus_get_id(stylus), !=, WACOM_STYLUS_FALLBACK_ID); + g_assert_cmpint(libwacom_stylus_get_id(stylus), !=, WACOM_ERASER_FALLBACK_ID); } + + + g_free(styli); } static void diff --git a/test/test_libwacom.py b/test/test_libwacom.py index 95c833c96..e123985b0 100644 --- a/test/test_libwacom.py +++ b/test/test_libwacom.py @@ -8,7 +8,7 @@ import logging import pytest -from . import WacomBuilder, WacomBustype, WacomDatabase, WacomDevice +from . import WacomBuilder, WacomBustype, WacomDatabase, WacomDevice, WacomEraserType logger = logging.getLogger(__name__) @@ -39,14 +39,14 @@ def add_to_config(self, config: ConfigParser): @classmethod def generic_pen(cls) -> "StylusEntry": - return cls(id="0xfffff", name="General Pen", paired_stylus_ids=["0xffffe"]) + return cls(id="0x0:0xfffff", name="General Pen", paired_stylus_ids=["0x0:0xffffe"]) @classmethod def generic_eraser(cls) -> "StylusEntry": return StylusEntry( - id="0xffffe", + id="0x0:0xffffe", name="General Pen Eraser", - paired_stylus_ids=["0xfffff"], + paired_stylus_ids=["0x0:0xfffff"], eraser_type="Invert", ) @@ -86,6 +86,7 @@ class TabletFile: layout: str = "" has_stylus: bool = True is_reversible: bool = False + styli: list[str] = field(default_factory=list) def write_to(self, filename): config = ConfigParser() @@ -99,6 +100,9 @@ def write_to(self, filename): "Class": self.klass, "Layout": self.layout, } + if self.styli: + config["Device"]["Styli"] = ";".join(self.styli) + config["Features"] = { "Stylus": self.has_stylus, "Reversible": self.is_reversible, @@ -521,3 +525,76 @@ def test_new_from_path_unknown_device(db, fallback): assert dev.name == name assert dev.vendor_id == 0 assert dev.product_id == 0 + + +def test_nonwacom_stylus_ids(tmp_path): + styli = StylusFile.default() + s1 = StylusEntry( + id="0x1234:0xabcd", + name="ABC Pen", + group="notwacom", + paired_stylus_ids=["0x1234:0x9876"], + ) + s2 = StylusEntry( + id="0x1234:0x9876", + name="9876 Pen", + group="notwacom", + paired_stylus_ids=["0x1234:0xabcd"], + eraser_type="Invert", + ) + styli.entries.append(s1) + styli.entries.append(s2) + styli.write_to_dir(tmp_path) + + # matches our nonwacom group + TabletFile( + name="ABC Group Tablet", + matches=["usb|9999|abcd"], + styli=["@notwacom"], + ).write_to(tmp_path / "group.tablet") + + # matches one nonwacom styli and the default generic ones + TabletFile( + name="ABC Tablet", + matches=["usb|8888|abcd"], + styli=[s2.id, "@generic-with-eraser"], + ).write_to(tmp_path / "abc.tablet") + + db = WacomDatabase(path=tmp_path) + + builder = WacomBuilder.create(usbid=(0x9999, 0xABCD)) + device = db.new_from_builder(builder) + assert device is not None + assert device.name == "ABC Group Tablet" + styli = device.get_styli() + assert len(styli) == 2 + assert styli[0].vendor_id == 0x1234 + assert styli[1].vendor_id == 0x1234 + # Order of styli is undefined + assert styli[0].tool_id == 0xABCD or styli[1].tool_id == 0xABCD + assert styli[0].tool_id == 0x9876 or styli[1].tool_id == 0x9876 + assert sum(s.is_eraser for s in styli) == 1 + for s in filter(lambda s: s.is_eraser, styli): + assert s.eraser_type == WacomEraserType.INVERT + + assert sum(s.is_eraser is True for s in styli) == 1 + + paired0 = styli[0].get_paired_styli() + paired1 = styli[1].get_paired_styli() + assert len(paired0) == 1 + assert len(paired1) == 1 + assert paired0[0].vendor_id == styli[1].vendor_id + assert paired0[0].tool_id != styli[1].vendor_id + assert paired1[0].vendor_id == styli[0].vendor_id + assert paired1[0].tool_id != styli[0].vendor_id + + builder = WacomBuilder.create(usbid=(0x8888, 0xABCD)) + device = db.new_from_builder(builder) + assert device is not None + assert device.name == "ABC Tablet" + styli = device.get_styli() + assert len(styli) == 3 # 1 non-wacom, 2 generic ones + # Order of styli is undefined + assert sum(s.vendor_id == 0x1234 and s.tool_id == 0x9876 for s in styli) == 1 + assert sum(s.vendor_id == 0 and s.tool_id == 0xFFFFE for s in styli) == 1 + assert sum(s.vendor_id == 0 and s.tool_id == 0xFFFFF for s in styli) == 1 diff --git a/tools/debug-device.c b/tools/debug-device.c index 2cdac201d..4de74c45c 100644 --- a/tools/debug-device.c +++ b/tools/debug-device.c @@ -230,7 +230,10 @@ handle_device(WacomDeviceDatabase *db, const char *path) { int nstyli; + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" const int *styli = libwacom_get_supported_styli(device, &nstyli); + #pragma GCC diagnostic pop { char buf[1024] = {0}; @@ -239,14 +242,28 @@ handle_device(WacomDeviceDatabase *db, const char *path) func(libwacom_get_supported_styli, "[%s]", buf); } + } + + { + int nstyli; + const WacomStylus **styli = libwacom_get_styli(device, &nstyli); + { + char buf[1024] = {0}; + for (int i = 0; i < nstyli; i++) { + const WacomStylus *s = styli[i]; + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s[0x%04x, 0x%06x]", i > 0 ? ", " : "", + libwacom_stylus_get_vendor_id(s), libwacom_stylus_get_id(s)); + } + func(libwacom_get_styli, "[%s]", buf); + } if (with_styli) { printf("\n---------- Listing styli for this device ----------\n"); for (int i = 0; i < nstyli; i++) { - int id = styli[i]; - const WacomStylus *stylus = libwacom_stylus_get_for_id (db, id); + const WacomStylus *stylus = styli[i]; + int id = libwacom_stylus_get_id(stylus); ip("%s\n", "{"); push(); @@ -261,13 +278,31 @@ handle_device(WacomDeviceDatabase *db, const char *path) { char buf[1024] = {0}; int npaired; + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" const int *paired = libwacom_stylus_get_paired_ids(stylus, &npaired); + #pragma GCC diagnostic pop for (int i = 0; i < npaired; i++) snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s0x%06x", i > 0 ? ", " : "", paired[i]); func_arg(libwacom_stylus_get_paired_ids, "0x%04x", id, "[%s]", buf); } + { + char buf[1024] = {0}; + int npaired; + const WacomStylus **paired = libwacom_stylus_get_paired_styli(stylus, &npaired); + + for (int i = 0; i < npaired; i++) { + const WacomStylus *p = paired[i]; + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s[0x%04x, 0x%06x]", i > 0 ? ", " : "", + libwacom_stylus_get_vendor_id(p), libwacom_stylus_get_id(p)); + } + func_arg(libwacom_stylus_get_paired_ids, "0x%04x", id, "[%s]", buf); + + g_clear_pointer(&paired, g_free); + } + { WacomAxisTypeFlags flags = libwacom_stylus_get_axes(stylus); func_arg(libwacom_stylus_has_wheel, "0x%04x", id, "%s%s%s%s%s%s", @@ -312,6 +347,8 @@ handle_device(WacomDeviceDatabase *db, const char *path) ip("%s\n", "}"); } } + + g_clear_pointer(&styli, g_free); } libwacom_destroy(device); diff --git a/tools/list-compatible-styli.c b/tools/list-compatible-styli.c index 0e2643cfe..0914f790f 100644 --- a/tools/list-compatible-styli.c +++ b/tools/list-compatible-styli.c @@ -38,7 +38,7 @@ static void print_device_info(const WacomDeviceDatabase *db, const WacomDevice *device) { - const int *styli; + WacomStylus const **styli; int nstyli; printf("- name: '%s'\n", libwacom_get_name(device)); @@ -52,17 +52,17 @@ print_device_info(const WacomDeviceDatabase *db, const WacomDevice *device) printf(" styli:\n"); - styli = libwacom_get_supported_styli(device, &nstyli); + styli = libwacom_get_styli(device, &nstyli); for (int i = 0; i < nstyli; i++) { - const WacomStylus *s; + const WacomStylus *s = styli[i]; char id[64]; - s = libwacom_stylus_get_for_id(db, styli[i]); snprintf(id, sizeof(id), "0x%x", libwacom_stylus_get_id(s)); printf(" - { id: %*s'%s', name: '%s' }\n", (int)(7 - strlen(id)), " ", id, libwacom_stylus_get_name(s)); } + g_free(styli); } int main(int argc, char **argv) diff --git a/tools/list-local-devices.c b/tools/list-local-devices.c index ea39b2579..90c12f49b 100644 --- a/tools/list-local-devices.c +++ b/tools/list-local-devices.c @@ -116,14 +116,13 @@ print_devnode(gpointer data, gpointer user_data) static void tablet_print_yaml(gpointer data, gpointer user_data) { - WacomDeviceDatabase *db = user_data; struct tablet *d = data; const char *name = libwacom_get_name(d->dev); const char *bus = "unknown"; int vid = libwacom_get_vendor_id(d->dev); int pid = libwacom_get_product_id(d->dev); WacomBusType bustype = libwacom_get_bustype(d->dev); - const int *styli; + const WacomStylus **styli; int nstyli; switch (bustype) { @@ -142,10 +141,10 @@ tablet_print_yaml(gpointer data, gpointer user_data) printf(" nodes: \n"); g_list_foreach(d->nodes, print_devnode, NULL); - styli = libwacom_get_supported_styli(d->dev, &nstyli); + styli = libwacom_get_styli(d->dev, &nstyli); printf(" styli:%s\n", nstyli > 0 ? "" : "[]"); for (int i = 0; i < nstyli; i++) { - const WacomStylus *stylus = libwacom_stylus_get_for_id(db, styli[i]); + const WacomStylus *stylus = styli[i]; const char *type = "invalid"; WacomAxisTypeFlags axes = libwacom_stylus_get_axes(stylus); WacomEraserType eraser_type = libwacom_stylus_get_eraser_type(stylus); @@ -192,14 +191,18 @@ tablet_print_yaml(gpointer data, gpointer user_data) printf(" erasers: ["); if (libwacom_stylus_has_eraser(stylus)) { int npaired; - const int *paired = libwacom_stylus_get_paired_ids(stylus, &npaired); - for (int j = 0; j < npaired; j++) - printf("%s0x%x", j == 0 ? "" : ", ", paired[j]); + const WacomStylus **paired = libwacom_stylus_get_paired_styli(stylus, &npaired); + for (int j = 0; j < npaired; j++) { + const WacomStylus *p = paired[j]; + printf("%s0x%x", j == 0 ? "" : ", ", libwacom_stylus_get_id(p)); + } + g_free(paired); } printf("]\n"); } } + g_free(styli); } static void