[PATCH libevdev 3/3] Add libevdev_event_value_get_name() to resolve ABS_MT_TOOL_TYPE values

Peter Hutterer peter.hutterer at who-t.net
Mon Jun 18 05:53:11 UTC 2018


ABS_MT_TOOL_TYPE values are an enum, not a numerical value like all other
axes. So let's allow converting those values to string.

Fixes https://gitlab.freedesktop.org/libevdev/libevdev/issues/1

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 libevdev/libevdev-names.c    | 23 ++++++++++++++
 libevdev/libevdev.c          | 17 +++++++++++
 libevdev/libevdev.h          | 73 ++++++++++++++++++++++++++++++++++++++++++++
 libevdev/libevdev.sym        |  9 ++++++
 libevdev/make-event-names.py | 10 ++++--
 test/test-event-codes.c      | 27 ++++++++++++++++
 test/test-event-names.c      | 34 +++++++++++++++++++++
 7 files changed, 191 insertions(+), 2 deletions(-)

diff --git a/libevdev/libevdev-names.c b/libevdev/libevdev-names.c
index ad318de..6d06df3 100644
--- a/libevdev/libevdev-names.c
+++ b/libevdev/libevdev-names.c
@@ -142,6 +142,29 @@ libevdev_event_code_from_name_n(unsigned int type, const char *name, size_t len)
 	return entry ? (int)entry->value : -1;
 }
 
+LIBEVDEV_EXPORT int
+libevdev_event_value_from_name(unsigned int type, unsigned int code, const char *name)
+{
+	return libevdev_event_value_from_name_n(type, code, name, strlen(name));
+}
+
+LIBEVDEV_EXPORT int
+libevdev_event_value_from_name_n(unsigned int type, unsigned int code, const char *name, size_t len)
+{
+	struct name_lookup lookup;
+	const struct name_entry *entry;
+
+	if (type != EV_ABS || code != ABS_MT_TOOL_TYPE)
+		return -1;
+
+	lookup.name = name;
+	lookup.len = len;
+
+	entry = lookup_name(tool_type_names, ARRAY_LENGTH(tool_type_names), &lookup);
+
+	return entry ? (int)entry->value : -1;
+}
+
 LIBEVDEV_EXPORT int
 libevdev_property_from_name(const char *name)
 {
diff --git a/libevdev/libevdev.c b/libevdev/libevdev.c
index c6ec114..fab87cf 100644
--- a/libevdev/libevdev.c
+++ b/libevdev/libevdev.c
@@ -1613,6 +1613,23 @@ libevdev_event_code_get_name(unsigned int type, unsigned int code)
 	return event_type_map[type][code];
 }
 
+LIBEVDEV_EXPORT const char *
+libevdev_event_value_get_name(unsigned int type,
+			      unsigned int code,
+			      int value)
+{
+	/* This is a simplified version because nothing else
+	   is an enum like ABS_MT_TOOL_TYPE so we don't need
+	   a generic lookup */
+	if (type != EV_ABS || code != ABS_MT_TOOL_TYPE)
+		return NULL;
+
+	if (value > MT_TOOL_MAX)
+		return NULL;
+
+	return mt_tool_map[value];
+}
+
 LIBEVDEV_EXPORT const char*
 libevdev_property_get_name(unsigned int prop)
 {
diff --git a/libevdev/libevdev.h b/libevdev/libevdev.h
index 4c516ad..f0f34bb 100644
--- a/libevdev/libevdev.h
+++ b/libevdev/libevdev.h
@@ -2019,6 +2019,29 @@ const char * libevdev_event_type_get_name(unsigned int type);
  */
 const char * libevdev_event_code_get_name(unsigned int type, unsigned int code);
 
+/**
+ * @ingroup misc
+ *
+ * This function resolves the event value for a code.
+ *
+ * For almost all event codes this will return NULL as the value is just a
+ * numerical value. As of kernel 4.17, the only event code that will return
+ * a non-NULL value is EV_ABS/ABS_MT_TOOL_TYPE.
+ *
+ * @param type The event type for the value to query (EV_ABS, etc.)
+ * @param code The event code for the value to query (e.g. ABS_MT_TOOL_TYPE)
+ * @param value The event value to return the name for (e.g. MT_TOOL_PALM)
+ *
+ * @return The name of the given event value (e.g. MT_TOOL_PALM) or NULL for
+ * an invalid type or code or NULL for an axis that has numerical values
+ * only.
+ *
+ * @note The list of names is compiled into libevdev. If the kernel adds new
+ * defines for new event values, libevdev will not automatically pick these up.
+ */
+const char * libevdev_event_value_get_name(unsigned int type,
+					   unsigned int code,
+					   int value);
 /**
  * @ingroup misc
  *
@@ -2127,6 +2150,56 @@ int libevdev_event_code_from_name(unsigned int type, const char *name);
 int libevdev_event_code_from_name_n(unsigned int type, const char *name,
 				    size_t len);
 
+/**
+ * @ingroup misc
+ *
+ * Look up an event value by its type, code and name. Event values start
+ * with a fixed prefix followed by their name (eg., "MT_TOOL_PALM"). The
+ * prefix must be included in the name. It returns the constant assigned
+ * to the event code or -1 if not found.
+ *
+ * You have to pass the event type and code where to look for the name. For
+ * instance, to resolve "MT_TOOL_PALM" you need to pass EV_ABS as type,
+ * ABS_MT_TOOL_TYPE as code and "MT_TOOL_PALM" as string.
+ *
+ * As of kernel 4.17, only EV_ABS/ABS_MT_TOOL_TYPE support name resolution.
+ *
+ * @param type The event type (EV_* constant) where to look for the name.
+ * @param code The event code (ABS_* constant) where to look for the name.
+ * @param name A non-NULL string describing an input-event value
+ * ("MT_TOOL_TYPE", ...)
+ *
+ * @return The given value constant for the name or -1 if not found.
+ */
+int libevdev_event_value_from_name(unsigned int type, unsigned int code,
+				   const char *name);
+
+/**
+ * @ingroup misc
+ *
+ * Look up an event value by its type, code and name. Event values start
+ * with a fixed prefix followed by their name (eg., "MT_TOOL_PALM"). The
+ * prefix must be included in the name. It returns the constant assigned
+ * to the event code or -1 if not found.
+ *
+ * You have to pass the event type and code where to look for the name. For
+ * instance, to resolve "MT_TOOL_PALM" you need to pass EV_ABS as type,
+ * ABS_MT_TOOL_TYPE as code and "MT_TOOL_PALM" as string.
+ *
+ * As of kernel 4.17, only EV_ABS/ABS_MT_TOOL_TYPE support name resolution.
+ *
+ * @param type The event type (EV_* constant) where to look for the name.
+ * @param code The event code (ABS_* constant) where to look for the name.
+ * @param name A non-NULL string describing an input-event value
+ * ("MT_TOOL_TYPE", ...)
+ * @param len The length of the string in @p name excluding any terminating 0
+ * character.
+ *
+ * @return The given value constant for the name or -1 if not found.
+ */
+int libevdev_event_value_from_name_n(unsigned int type, unsigned int code,
+				     const char *name, size_t len);
+
 /**
  * @ingroup misc
  *
diff --git a/libevdev/libevdev.sym b/libevdev/libevdev.sym
index 374712f..7dd0c20 100644
--- a/libevdev/libevdev.sym
+++ b/libevdev/libevdev.sym
@@ -112,3 +112,12 @@ global:
 local:
 	*;
 } LIBEVDEV_1;
+
+LIBEVDEV_1_6 {
+global:
+	libevdev_event_value_get_name;
+	libevdev_event_value_from_name;
+	libevdev_event_value_from_name_n;
+local:
+	*;
+} LIBEVDEV_1_3;
diff --git a/libevdev/make-event-names.py b/libevdev/make-event-names.py
index 38b44cf..8d572d0 100755
--- a/libevdev/make-event-names.py
+++ b/libevdev/make-event-names.py
@@ -26,6 +26,7 @@ prefixes = [
 		"SYN_",
 		"REP_",
 		"INPUT_PROP_",
+		"MT_TOOL_",
 ]
 
 duplicates = [
@@ -39,6 +40,7 @@ duplicates = [
 		"BTN_TRIGGER_HAPPY",
 		"SW_MAX",
 		"REP_MAX",
+		"MT_TOOL_MAX",
 ]
 
 btn_additional = [
@@ -78,7 +80,7 @@ def print_map(bits):
 	print("static const char * const * const event_type_map[EV_MAX + 1] = {")
 
 	for prefix in prefixes:
-		if prefix in ["BTN_", "EV_", "INPUT_PROP_"]:
+		if prefix in ["BTN_", "EV_", "INPUT_PROP_", "MT_TOOL_"]:
 			continue
 		print("	[EV_%s] = %s_map," % (prefix[:-1], prefix[:-1].lower()))
 
@@ -95,7 +97,7 @@ def print_map(bits):
 	print("static const int ev_max[EV_MAX + 1] = {")
 	print("	[0 ... EV_MAX] = -1,")
 	for prefix in prefixes:
-		if prefix in ["BTN_", "EV_", "INPUT_PROP_"]:
+		if prefix in ["BTN_", "EV_", "INPUT_PROP_", "MT_TOOL_"]:
 			continue
 		print("	[EV_%s] = %s_MAX," % (prefix[:-1], prefix[:-1]))
 	print("};")
@@ -129,6 +131,10 @@ def print_lookup_table(bits):
 	print("	unsigned int value;")
 	print("};")
 	print("")
+	print("static const struct name_entry tool_type_names[] = {")
+	print_lookup(bits, "mt_tool")
+	print("};")
+	print("")
 	print("static const struct name_entry ev_names[] = {")
 	print_lookup(bits, "ev")
 	print("};")
diff --git a/test/test-event-codes.c b/test/test-event-codes.c
index 8b587d9..643b537 100644
--- a/test/test-event-codes.c
+++ b/test/test-event-codes.c
@@ -114,6 +114,28 @@ START_TEST(test_code_names_max)
 }
 END_TEST
 
+START_TEST(test_value_names)
+{
+	ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, "MT_TOOL_PALM"), MT_TOOL_PALM);
+	ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, "MT_TOOL_FINGER"), MT_TOOL_FINGER);
+	ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, "MT_TOOL_PEN"), MT_TOOL_PEN);
+	ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, "MT_TOOL_MAX"), MT_TOOL_MAX);
+}
+END_TEST
+
+START_TEST(test_value_names_invalid)
+{
+	ck_assert_int_eq(libevdev_event_value_from_name(EV_SYN, REL_X, "MT_TOOL_PALM"), -1);
+	ck_assert_int_eq(libevdev_event_value_from_name(EV_REL, REL_X, "MT_TOOL_PALM"), -1);
+	ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_X, "MT_TOOL_PALM"), -1);
+	ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, "MT_TOOL_"), -1);
+	ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, "MT_TOOL_PALMA"), -1);
+	ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, ""), -1);
+	ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, "EV_ABS"), -1);
+	ck_assert_int_eq(libevdev_event_value_from_name(EV_ABS, ABS_MT_TOOL_TYPE, "ABS_X"), -1);
+}
+END_TEST
+
 START_TEST(test_properties)
 {
 	struct prop {
@@ -161,6 +183,11 @@ TEST_SUITE(event_code_suite)
 	tcase_add_test(tc, test_code_names_max);
 	suite_add_tcase(s, tc);
 
+	tc = tcase_create("value tests");
+	tcase_add_test(tc, test_value_names);
+	tcase_add_test(tc, test_value_names_invalid);
+	suite_add_tcase(s, tc);
+
 	tc = tcase_create("property tests");
 	tcase_add_test(tc, test_properties);
 	tcase_add_test(tc, test_properties_invalid);
diff --git a/test/test-event-names.c b/test/test-event-names.c
index 9ed23d0..0116fab 100644
--- a/test/test-event-names.c
+++ b/test/test-event-names.c
@@ -36,6 +36,7 @@ START_TEST(test_limits)
 	ck_assert(libevdev_event_code_get_name(EV_REP, REP_MAX + 1) == NULL);
 	ck_assert(libevdev_event_code_get_name(EV_FF, FF_MAX + 1) == NULL);
 	ck_assert(libevdev_event_code_get_name(EV_MAX + 1, 0) == NULL);
+	ck_assert(libevdev_event_value_get_name(EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_MAX + 1) == NULL);
 }
 END_TEST
 
@@ -201,6 +202,35 @@ START_TEST(test_code_syn_name)
 }
 END_TEST
 
+START_TEST(test_value_name)
+{
+	unsigned int type, code;
+	int value;
+
+	for (type = 0; type < EV_MAX; type++) {
+		int max = libevdev_event_type_get_max(type);
+
+		if (max == -1)
+			continue;
+
+		for (code = 0; code < (unsigned int)max; code++) {
+			if (type == EV_ABS && code == ABS_MT_TOOL_TYPE)
+				continue;
+
+			for (value = 0; value < 0xff; value++) {
+				ck_assert(libevdev_event_value_get_name(type, code, value) == NULL);
+			}
+		}
+	}
+
+	ck_assert_str_eq(libevdev_event_value_get_name(EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER), "MT_TOOL_FINGER");
+	ck_assert_str_eq(libevdev_event_value_get_name(EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM), "MT_TOOL_PALM");
+	ck_assert_str_eq(libevdev_event_value_get_name(EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PEN), "MT_TOOL_PEN");
+	/* overlapping value */
+	ck_assert_str_eq(libevdev_event_value_get_name(EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_MAX), "MT_TOOL_PALM");
+}
+END_TEST
+
 START_TEST(test_prop_name)
 {
 	ck_assert_str_eq(libevdev_property_get_name(INPUT_PROP_POINTER), "INPUT_PROP_POINTER");
@@ -297,6 +327,10 @@ TEST_SUITE(event_name_suite)
 	tcase_add_test(tc, test_code_syn_name);
 	suite_add_tcase(s, tc);
 
+	tc = tcase_create("value names");
+	tcase_add_test(tc, test_value_name);
+	suite_add_tcase(s, tc);
+
 	tc = tcase_create("prop names");
 	tcase_add_test(tc, test_prop_name);
 	suite_add_tcase(s, tc);
-- 
2.14.4



More information about the Input-tools mailing list