diff --git a/data/libwacom.stylus b/data/libwacom.stylus index d19ffdd8..9c90e57c 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 35bd65c9..f7c41fda 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 4366f291..e927c60c 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 c0d380c9..98710658 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 be0dd1e0..65f104f7 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 36a6bf74..7178777d 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 3963d9e2..43083f10 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 64d47a34..f33085d7 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 e17d9112..c9e7b078 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 69d34c81..f6342649 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 95c833c9..e123985b 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 2cdac201..4de74c45 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 0e2643cf..0914f790 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 ea39b257..90c12f49 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