From dbd2b9c8b06a48bd5bcee864163f6bc3e02045c2 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 31 Aug 2023 12:03:07 +1000 Subject: [PATCH] data: add a new Keys/KeyCodes entry to the tablet files This is parsed but not exported by libwacom itself beyond the number of available keys. We can add other bits once we know what potential callers want. It is used however to determine if a device has a pad and thus used to set the ID_INPUT_TABLET_PAD property through the hwdb. This fixes the issue with some devices without buttons (but with keys) to not get labelled as pads, e.g. the Cintiq Pro 13. Fixes #585 --- data/cintiq-pro-13.tablet | 4 +++ data/wacom.example | 7 ++++ libwacom/libwacom-database.c | 70 ++++++++++++++++++++++++++++++++++++ libwacom/libwacom.c | 10 ++++++ libwacom/libwacom.h | 10 ++++++ libwacom/libwacom.sym | 4 +++ libwacom/libwacomint.h | 7 ++++ test/test-load.c | 13 +++++++ tools/libwacom-update-db.py | 2 +- 9 files changed, 126 insertions(+), 1 deletion(-) diff --git a/data/cintiq-pro-13.tablet b/data/cintiq-pro-13.tablet index 4b0b773ea..a98180718 100644 --- a/data/cintiq-pro-13.tablet +++ b/data/cintiq-pro-13.tablet @@ -43,3 +43,7 @@ Stylus=true Reversible=false Touch=true Ring=false + +[Keys] +# first key is in-kernel display toggle +KeyCodes=0;KEY_CONTROLPANEL;KEY_ONSCREEN_KEYBOARD;KEY_BUTTONCONFIG;SW_MUTE_DEVICE diff --git a/data/wacom.example b/data/wacom.example index d4366c3c1..7c16f01f4 100644 --- a/data/wacom.example +++ b/data/wacom.example @@ -210,3 +210,10 @@ Touchstrip2=J # We assume the same number of modes for each of the touchstrips # if there is more than one StripsNumModes=4 + + +# Metadata about the keys on the tablet +[Keys] +# The evdev codes for the keys (if any) in order from left to right. +# Keys that have a code of zero do not produce any events. +KeyCodes=0;KEY_CONTROLPANEL;KEY_ONSCREEN_KEYBOARD;KEY_BUTTONCONFIG;SW_MUTE_DEVICE diff --git a/libwacom/libwacom-database.c b/libwacom/libwacom-database.c index eec096353..2c17e0d71 100644 --- a/libwacom/libwacom-database.c +++ b/libwacom/libwacom-database.c @@ -45,6 +45,7 @@ #define FEATURES_GROUP "Features" #define DEVICE_GROUP "Device" #define BUTTONS_GROUP "Buttons" +#define KEYS_GROUP "Keys" static WacomClass libwacom_class_string_to_enum(const char *class) @@ -493,6 +494,50 @@ set_button_codes_from_string(WacomDevice *device, char **strvals) return success; } +static inline bool +set_key_codes_from_string(WacomDevice *device, char **strvals) +{ + bool success = false; + assert(strvals); + + for (unsigned int idx = 0; strvals[idx]; idx++) { + const char *str = strvals[idx]; + int code = -1; + int type = -1; + + if (!str) { + g_error("%s: Missing KeyCode for key %d, ignoring all codes\n", + device->name, idx); + goto out; + } else if (g_str_has_prefix(str, "KEY")) { + type = EV_KEY; + code = libevdev_event_code_from_code_name(str); + } else if (g_str_has_prefix(str, "SW")) { + type = EV_SW; + code = libevdev_event_code_from_code_name(str); + } else { + if (safe_atoi_base (strvals[idx], &code, 16)) + type = EV_KEY; + } + + if (code == -1 || type == -1) { + g_warning ("%s: Invalid KeyCode %s, ignoring all codes\n", device->name, str); + goto out; + } + + device->keycodes[idx].type = type; + device->keycodes[idx].code = code; + device->num_keycodes = idx + 1; + } + + success = true; +out: + if (!success) { + memset(device->keycodes, 0, sizeof(device->keycodes)); + } + return success; +} + static inline void set_button_codes_from_heuristics(WacomDevice *device) { @@ -604,6 +649,30 @@ libwacom_parse_buttons(WacomDevice *device, device->strips_num_modes = libwacom_parse_num_modes(device, keyfile, "StripsNumModes", WACOM_BUTTON_TOUCHSTRIP_MODESWITCH); } +static void +libwacom_parse_key_codes(WacomDevice *device, + GKeyFile *keyfile) +{ + char **vals; + + vals = g_key_file_get_string_list(keyfile, KEYS_GROUP, "KeyCodes", NULL, NULL); + if (vals) + set_key_codes_from_string(device, vals); + + g_strfreev (vals); +} + +static void +libwacom_parse_keys(WacomDevice *device, + GKeyFile *keyfile) +{ + if (!g_key_file_has_group(keyfile, KEYS_GROUP)) + return; + + libwacom_parse_key_codes(device, keyfile); +} + + static int styli_id_sort(gconstpointer pa, gconstpointer pb) { @@ -829,6 +898,7 @@ libwacom_parse_tablet_keyfile(WacomDeviceDatabase *db, libwacom_parse_features(device, keyfile); libwacom_parse_buttons(device, keyfile); + libwacom_parse_keys(device, keyfile); success = TRUE; diff --git a/libwacom/libwacom.c b/libwacom/libwacom.c index 27e6eadd4..92155994c 100644 --- a/libwacom/libwacom.c +++ b/libwacom/libwacom.c @@ -379,6 +379,10 @@ libwacom_copy(const WacomDevice *device) WacomButton *b = g_memdup2(a, sizeof(WacomButton)); g_hash_table_insert(d->buttons, k, b); } + + d->num_keycodes = device->num_keycodes; + memcpy(d->keycodes, device->keycodes, sizeof(device->keycodes)); + return d; } @@ -1120,6 +1124,12 @@ libwacom_get_num_buttons(const WacomDevice *device) return g_hash_table_size(device->buttons); } +LIBWACOM_EXPORT int +libwacom_get_num_keys(const WacomDevice *device) +{ + return device->num_keycodes; +} + LIBWACOM_EXPORT const int * libwacom_get_supported_styli(const WacomDevice *device, int *num_styli) { diff --git a/libwacom/libwacom.h b/libwacom/libwacom.h index cafed6402..389681d2b 100644 --- a/libwacom/libwacom.h +++ b/libwacom/libwacom.h @@ -594,6 +594,16 @@ int libwacom_has_touch(const WacomDevice *device); */ int libwacom_get_num_buttons(const WacomDevice *device); +/** + * Tablet keys indices are numbered from zero + * + * @param device The tablet to query + * @return The number of keys on the tablet + * + * @ingroup devices + */ +int libwacom_get_num_keys(const WacomDevice *device); + /** * @param device The tablet to query * @param num_styli Return location for the number of listed styli diff --git a/libwacom/libwacom.sym b/libwacom/libwacom.sym index e517f2de7..76ed06921 100644 --- a/libwacom/libwacom.sym +++ b/libwacom/libwacom.sym @@ -68,3 +68,7 @@ global: local: *; }; + +LIBWACOM_2.9 { + libwacom_get_num_keys; +} LIBWACOM_2.0; diff --git a/libwacom/libwacomint.h b/libwacom/libwacomint.h index e1af83845..537afdb48 100644 --- a/libwacom/libwacomint.h +++ b/libwacom/libwacomint.h @@ -67,6 +67,11 @@ typedef struct _WacomButton { int code; } WacomButton; +typedef struct _WacomKeycode { + unsigned int type; + unsigned int code; +} WacomKeycode; + /* WARNING: When adding new members to this struct * make sure to update libwacom_copy() and * libwacom_print_device_description() ! */ @@ -92,6 +97,8 @@ struct _WacomDevice { GArray *styli; GHashTable *buttons; /* 'A' : WacomButton */ + WacomKeycode keycodes[32]; + size_t num_keycodes; GArray *status_leds; diff --git a/test/test-load.c b/test/test-load.c index 10938b022..abb80117a 100644 --- a/test/test-load.c +++ b/test/test-load.c @@ -226,6 +226,16 @@ test_cintiq13hd(struct fixture *f, gconstpointer user_data) libwacom_destroy(device); } +static void +test_cintiqpro13(struct fixture *f, gconstpointer user_data) +{ + WacomDevice *device = libwacom_new_from_name(f->db, "Wacom Cintiq Pro 13", NULL); + g_assert_nonnull(device); + g_assert_cmpint(libwacom_get_num_keys(device), ==, 5); + + libwacom_destroy(device); +} + static void test_bamboopen(struct fixture *f, gconstpointer user_data) { @@ -294,6 +304,9 @@ int main(int argc, char **argv) g_test_add("/load/056a:0304", struct fixture, NULL, fixture_setup, test_cintiq13hd, fixture_teardown); + g_test_add("/load/056a:034f", struct fixture, NULL, + fixture_setup, test_cintiqpro13, + fixture_teardown); g_test_add("/load/056a:0065", struct fixture, NULL, fixture_setup, test_bamboopen, fixture_teardown); diff --git a/tools/libwacom-update-db.py b/tools/libwacom-update-db.py index e30c88c99..c503c3381 100755 --- a/tools/libwacom-update-db.py +++ b/tools/libwacom-update-db.py @@ -147,7 +147,7 @@ def _load(self, path): ) except KeyError: pass - t.has_pad = config.has_section("Buttons") + t.has_pad = any(config.has_section(s) for s in ["Buttons", "Keys"]) yield t