From dee2d3847669cfad7398b4302789e018564c5c16 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 8 Jan 2026 16:57:59 +1000 Subject: [PATCH] Add libinput_tablet_tool_get_name() for the tool's specific name If the tool has a name let's provide that to the caller. We have it easily accessible so let's export it to make everyone's life easier. The name is provided by libwacom, there is no need for us to even copy that value since we don't need it ourselves. Note that at this point effectively only (some) Wacom devices have meaningful names. Virtually all non-wacom devices will use a generic tool and even the built-in Wacoms will largely just say "AES Pen". Part-of: --- src/libinput.c | 25 +++++++++++ src/libinput.h | 28 +++++++++++++ src/libinput.sym | 1 + src/util-libinput.c | 7 +++- test/test-tablet.c | 78 +++++++++++++++++++++++++++++++++++ tools/libinput-debug-tablet.c | 7 +++- 6 files changed, 144 insertions(+), 2 deletions(-) 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));