diff --git a/src/libinput.c b/src/libinput.c index de6f97c1..6abd33d0 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -1643,6 +1643,31 @@ libinput_tablet_tool_get_tool_id(struct libinput_tablet_tool *tool) return tool->tool_id; } +LIBINPUT_EXPORT const char * +libinput_tablet_tool_get_name(struct libinput_tablet_tool *tool) +{ +#ifdef HAVE_LIBWACOM + if (!tool->last_device) + return NULL; + + auto libinput = libinput_device_get_context(tool->last_device); + auto wacom_db = libinput->libwacom.db; + if (!wacom_db) + return NULL; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + const WacomStylus *stylus = libwacom_stylus_get_for_id(wacom_db, tool->tool_id); +#pragma GCC diagnostic pop + if (!stylus) + return NULL; + + return libwacom_stylus_get_name(stylus); +#else + return NULL; +#endif +} + LIBINPUT_EXPORT int libinput_tablet_tool_is_unique(struct libinput_tablet_tool *tool) { diff --git a/src/libinput.h b/src/libinput.h index 441f6750..0085d6fa 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -2886,6 +2886,7 @@ libinput_event_tablet_tool_get_time_usec(struct libinput_event_tablet_tool *even * @return The tool type for this tool object * * @see libinput_tablet_tool_get_tool_id + * @see libinput_tablet_tool_get_name * * @since 1.2 */ @@ -2908,12 +2909,39 @@ libinput_tablet_tool_get_type(struct libinput_tablet_tool *tool); * @return The tool ID for this tool object or 0 if none is provided * * @see libinput_tablet_tool_get_type + * @see libinput_tablet_tool_get_name * * @since 1.2 */ uint64_t libinput_tablet_tool_get_tool_id(struct libinput_tablet_tool *tool); +/** + * @ingroup event_tablet + * + * Return the tool name for a tool object, if any. + * + * The tool name is a human-readable string that identifies the specific tool, + * for example "Pro Pen 2" or "Airbrush" and may be presented to the user. + * + * The lifetime of the returned string is tied to the lifetime of the + * libinput_tablet_tool. The string may be NULL. + * + * @note This function requires libwacom support. If libwacom is not available + * at compile time or the tool is not known to libwacom, this function returns + * NULL. + * + * @param tool The libinput tool + * @return The tool name for this tool object or NULL if no name is available + * + * @see libinput_tablet_tool_get_tool_id + * @see libinput_tablet_tool_get_type + * + * @since 1.31 + */ +const char * +libinput_tablet_tool_get_name(struct libinput_tablet_tool *tool); + /** * @ingroup event_tablet * diff --git a/src/libinput.sym b/src/libinput.sym index 054d66b9..0b7809ad 100644 --- a/src/libinput.sym +++ b/src/libinput.sym @@ -386,4 +386,5 @@ LIBINPUT_1.31 { libinput_device_config_dwt_set_timeout; libinput_device_config_dwtp_get_timeout; libinput_device_config_dwtp_set_timeout; + libinput_tablet_tool_get_name; } LIBINPUT_1.30; diff --git a/src/util-libinput.c b/src/util-libinput.c index 0f0a9460..e2b5bb97 100644 --- a/src/util-libinput.c +++ b/src/util-libinput.c @@ -663,6 +663,10 @@ print_proximity_event(struct libinput_event *ev, _autofree_ char *axes = NULL; _autofree_ char *proxin = NULL; + const char *tool_name = libinput_tablet_tool_get_name(tool); + if (!tool_name) + tool_name = ""; + switch (libinput_tablet_tool_get_type(tool)) { case LIBINPUT_TABLET_TOOL_TYPE_PEN: tool_str = "pen"; @@ -729,10 +733,11 @@ print_proximity_event(struct libinput_event *ev, libinput_tablet_tool_has_button(tool, BTN_0) ? "0" : ""); } - return strdup_printf("%s\t%s\t%-8s (%#" PRIx64 ", id %#" PRIx64 ") %s%s", + return strdup_printf("%s\t%s\t%-8s ('%s', %#" PRIx64 ", id %#" PRIx64 ") %s%s", time, axes ? axes : "", tool_str, + tool_name, libinput_tablet_tool_get_serial(tool), libinput_tablet_tool_get_tool_id(tool), state_str, diff --git a/test/test-tablet.c b/test/test-tablet.c index 47fb98f7..d8577f04 100644 --- a/test/test-tablet.c +++ b/test/test-tablet.c @@ -2422,6 +2422,77 @@ START_TEST(tool_id) } END_TEST +START_TEST(tool_name) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + int tool_id = litest_test_param_get_i32(test_env->params, "tool_id"); + struct axis_replacement axes[] = { + { ABS_DISTANCE, 10 }, + { ABS_PRESSURE, 0 }, + { ABS_MISC, tool_id }, + { -1, -1 }, + }; + + litest_drain_events(li); + + litest_tablet_proximity_in(dev, 10, 10, axes); + litest_dispatch(li); + + _destroy_(libinput_event) *event = libinput_get_event(li); + auto tablet_event = + litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + auto tool = libinput_event_tablet_tool_get_tool(tablet_event); + + const char *name = libinput_tablet_tool_get_name(tool); + +#ifdef HAVE_LIBWACOM + switch (tool_id) { + case 0x823: + litest_assert_str_eq(name, "Grip Pen"); + break; + case 0x4802: + litest_assert_str_eq(name, "Classic Pen"); + break; + case 0x100902: + litest_assert_str_eq(name, "Airbrush Pen"); + break; + default: + litest_assert_not_reached(); + } +#else + litest_assert_ptr_null(name); +#endif +} +END_TEST + +START_TEST(tool_no_name) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + struct axis_replacement axes[] = { + { ABS_DISTANCE, 10 }, + { ABS_PRESSURE, 0 }, + { -1, -1 }, + }; + + litest_drain_events(li); + + litest_tablet_proximity_in(dev, 10, 10, axes); + litest_dispatch(li); + + _destroy_(libinput_event) *event = libinput_get_event(li); + auto tablet_event = + litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + auto tool = libinput_event_tablet_tool_get_tool(tablet_event); + + const char *name = libinput_tablet_tool_get_name(tool); + litest_assert_ptr_null(name); +} +END_TEST + START_TEST(serial_changes_tool) { struct litest_device *dev = litest_current_device(); @@ -7875,6 +7946,13 @@ TEST_COLLECTION(tablet) litest_add(tool_unique, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY); litest_add(tool_serial, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY); litest_add(tool_id, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY); + litest_with_parameters(params, "tool_id", 'I', 3, + litest_named_i32(0x823, "GripPen"), + litest_named_i32(0x4802, "ClassicPen"), + litest_named_i32(0x100902, "AirbrushPen")) { + litest_add_parametrized_for_device(tool_name, LITEST_WACOM_CINTIQ_PRO16_PEN, params); + } + litest_add_for_device(tool_no_name, LITEST_HUION_TABLET); litest_add(serial_changes_tool, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY); litest_add(invalid_serials, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY); litest_add_no_device(tools_with_serials); diff --git a/tools/libinput-debug-tablet.c b/tools/libinput-debug-tablet.c index 08845ae1..58b4eeca 100644 --- a/tools/libinput-debug-tablet.c +++ b/tools/libinput-debug-tablet.c @@ -204,7 +204,12 @@ print_state(struct context *ctx) abort(); } - printf("\rTool: %s serial %#" PRIx64 ", id %#" PRIx64 "\n", + const char *tool_name = libinput_tablet_tool_get_name(ctx->tool); + if (!tool_name) + tool_name = ""; + + printf("\rTool: '%s' %s serial %#" PRIx64 ", id %#" PRIx64 "\n", + tool_name, tool_str, libinput_tablet_tool_get_serial(ctx->tool), libinput_tablet_tool_get_tool_id(ctx->tool));