summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2021-03-25 12:37:19 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2021-03-29 12:42:37 +1000
commit031ff565c8d7059f895ba6e6ff3048214dc5024a (patch)
treee96b86d47a7d1a0f8dbabc7a469c348962bb491f
parent2289d35e0428d1cf6e566102b1b86088ad3d26cb (diff)
downloadlibwacom-031ff565c8d7059f895ba6e6ff3048214dc5024a.tar.gz
Switch the buttons to a GHashTable
Slightly simpler to manage, we keep a hashtable around with the alphabetic button as key and a new struct with flags + code as value. This removes the need for all the seperate array + length tracking. Minor regression: a caller passing invalid button codes will simply return the zero values now, without a glib error message. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--libwacom/libwacom-database.c146
-rw-r--r--libwacom/libwacom.c75
-rw-r--r--libwacom/libwacomint.h11
3 files changed, 137 insertions, 95 deletions
diff --git a/libwacom/libwacom-database.c b/libwacom/libwacom-database.c
index d3c2366..569b0d5 100644
--- a/libwacom/libwacom-database.c
+++ b/libwacom/libwacom-database.c
@@ -422,6 +422,7 @@ libwacom_parse_buttons_key(WacomDevice *device,
return;
for (i = 0; vals[i] != NULL; i++) {
char val;
+ WacomButton *button;
val = *vals[i];
if (strlen (vals[i]) > 1 ||
@@ -430,85 +431,118 @@ libwacom_parse_buttons_key(WacomDevice *device,
g_warning ("Ignoring value '%s' in key '%s'", vals[i], key);
continue;
}
- val -= 'A';
- device->buttons[(int) val] |= flag;
+
+ button = g_hash_table_lookup(device->buttons, GINT_TO_POINTER(val));
+ if (!button) {
+ button = g_new0(WacomButton, 1);
+ g_hash_table_insert(device->buttons, GINT_TO_POINTER(val), button);
+ }
+
+ button->flags |= flag;
}
g_strfreev (vals);
}
+static void
+reset_code(gpointer key, gpointer value, gpointer user_data)
+{
+ WacomButton *button = value;
+ button->code = 0;
+}
+
static inline bool
set_button_codes_from_string(WacomDevice *device, char **strvals)
{
- gint i;
+ bool success = false;
assert(strvals);
- for (i = 0; i < device->num_buttons; i++) {
- gint val;
+ for (guint i = 0; i < g_hash_table_size(device->buttons); i++) {
+ char key = 'A' + i;
+ int code;
+ WacomButton *button = g_hash_table_lookup(device->buttons, GINT_TO_POINTER(key));
+
+ if (!button) {
+ g_error("%s: Button %c is not defined, ignoring all codes\n",
+ device->name, key);
+ goto out;
+ }
if (!strvals[i]) {
g_error ("%s: Missing EvdevCode for button %d, ignoring all codes\n",
device->name, i);
- return false;
+ goto out;
}
- if (!safe_atoi_base (strvals[i], &val, 16) || val < BTN_MISC || val >= BTN_DIGI) {
- g_warning ("%s: Invalid EvdevCode %s for button %d, ignoring all codes\n",
- device->name, strvals[i], i);
- return false;
+ if (!safe_atoi_base (strvals[i], &code, 16) || code < BTN_MISC || code >= BTN_DIGI) {
+ g_warning ("%s: Invalid EvdevCode %s for button %c, ignoring all codes\n",
+ device->name, strvals[i], key);
+ goto out;
}
- device->button_codes[i] = val;
+ button->code = code;
}
+ success = true;
- return true;
+out:
+ if (!success)
+ g_hash_table_foreach(device->buttons, reset_code, NULL);
+
+ return success;
}
static inline void
set_button_codes_from_heuristics(WacomDevice *device)
{
- gint i;
- for (i = 0; i < device->num_buttons; i++) {
+ for (char key = 'A'; key <= 'Z'; key++) {
+ int code = 0;
+ WacomButton *button;
+
+ button = g_hash_table_lookup(device->buttons, GINT_TO_POINTER(key));
+ if (!button)
+ continue;
+
if (device->cls == WCLASS_BAMBOO ||
device->cls == WCLASS_GRAPHIRE) {
- switch (i) {
- case 0:
- device->button_codes[i] = BTN_LEFT;
- break;
- case 1:
- device->button_codes[i] = BTN_RIGHT;
- break;
- case 2:
- device->button_codes[i] = BTN_FORWARD;
- break;
- case 3:
- device->button_codes[i] = BTN_BACK;
- break;
+ switch (key) {
+ case 'A': code = BTN_LEFT; break;
+ case 'B': code = BTN_RIGHT; break;
+ case 'C': code = BTN_FORWARD; break;
+ case 'D': code = BTN_BACK; break;
default:
- device->button_codes[i] = 0;
break;
}
} else {
/* Assume traditional ExpressKey ordering */
- switch (i) {
- case 0 ... 9:
- device->button_codes[i] = BTN_0 + i;
- break;
- case 10 ... 15:
- device->button_codes[i] = BTN_A + (i-10);
- break;
- case 16:
- case 17:
- device->button_codes[i] = BTN_BASE + (i-16);
- break;
+ switch (key) {
+ case 'A': code = BTN_0; break;
+ case 'B': code = BTN_1; break;
+ case 'C': code = BTN_2; break;
+ case 'D': code = BTN_3; break;
+ case 'E': code = BTN_4; break;
+ case 'F': code = BTN_5; break;
+ case 'G': code = BTN_6; break;
+ case 'H': code = BTN_7; break;
+ case 'I': code = BTN_8; break;
+ case 'J': code = BTN_9; break;
+ case 'K': code = BTN_A; break;
+ case 'L': code = BTN_B; break;
+ case 'M': code = BTN_C; break;
+ case 'N': code = BTN_X; break;
+ case 'O': code = BTN_Y; break;
+ case 'P': code = BTN_Z; break;
+ case 'Q': code = BTN_BASE; break;
+ case 'R': code = BTN_BASE2; break;
default:
- device->button_codes[i] = 0;
break;
}
}
- if (device->button_codes[i] == 0)
- g_warning ("Unable to determine evdev code for button %d (%s)", i, device->name);
+ if (code == 0)
+ g_warning ("Unable to determine evdev code for button %c (%s)",
+ key, device->name);
+
+ button->code = code;
}
}
@@ -519,8 +553,7 @@ libwacom_parse_button_codes(WacomDevice *device,
char **vals;
vals = g_key_file_get_string_list(keyfile, BUTTONS_GROUP, "EvdevCodes", NULL, NULL);
- if (!vals ||
- !set_button_codes_from_string(device, vals))
+ if (!vals || !set_button_codes_from_string(device, vals))
set_button_codes_from_heuristics(device);
g_strfreev (vals);
@@ -532,16 +565,21 @@ libwacom_parse_num_modes (WacomDevice *device,
const char *key,
WacomButtonFlags flag)
{
+ GHashTableIter iter;
int num;
- int i;
+ gpointer k, v;
num = g_key_file_get_integer (keyfile, BUTTONS_GROUP, key, NULL);
if (num > 0)
return num;
- for (i = 0; i < device->num_buttons; i++) {
- if (device->buttons[i] & flag)
+
+ g_hash_table_iter_init(&iter, device->buttons);
+ while (g_hash_table_iter_next(&iter, &k, &v)) {
+ WacomButton *button = v;
+ if (button->flags & flag)
num++;
}
+
return num;
}
@@ -621,6 +659,7 @@ libwacom_parse_tablet_keyfile(WacomDeviceDatabase *db,
char *paired;
char **string_list;
bool success = FALSE;
+ int num_buttons;
keyfile = g_key_file_new();
@@ -760,17 +799,18 @@ libwacom_parse_tablet_keyfile(WacomDeviceDatabase *db,
g_warning ("Tablet '%s' has touch switch but no touch tool. This is impossible", libwacom_get_match(device));
device->num_strips = g_key_file_get_integer(keyfile, FEATURES_GROUP, "NumStrips", NULL);
- device->num_buttons = g_key_file_get_integer(keyfile, FEATURES_GROUP, "Buttons", &error);
- if (device->num_buttons == 0 &&
+
+ num_buttons = g_key_file_get_integer(keyfile, FEATURES_GROUP, "Buttons", &error);
+ if (num_buttons == 0 &&
g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND)) {
g_warning ("Tablet '%s' has no buttons defined, do something!", libwacom_get_match(device));
g_clear_error (&error);
}
- if (device->num_buttons > 0) {
- device->buttons = g_new0 (WacomButtonFlags, device->num_buttons);
- device->button_codes = g_new0 (gint, device->num_buttons);
+
+ device->buttons = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, g_free);
+ if (num_buttons > 0)
libwacom_parse_buttons(device, keyfile);
- }
string_list = g_key_file_get_string_list(keyfile, FEATURES_GROUP, "StatusLEDs", NULL, NULL);
if (string_list) {
diff --git a/libwacom/libwacom.c b/libwacom/libwacom.c
index b151fb3..9f6aa0d 100644
--- a/libwacom/libwacom.c
+++ b/libwacom/libwacom.c
@@ -311,6 +311,8 @@ static WacomDevice *
libwacom_copy(const WacomDevice *device)
{
WacomDevice *d;
+ GHashTableIter iter;
+ gpointer k, v;
d = g_new0 (WacomDevice, 1);
g_atomic_int_inc(&d->refcnt);
@@ -343,10 +345,16 @@ libwacom_copy(const WacomDevice *device)
g_array_append_val(d->styli, id);
}
d->num_leds = device->num_leds;
- d->status_leds = g_memdup2 (device->status_leds, sizeof(WacomStatusLEDs) * device->num_leds);
- d->num_buttons = device->num_buttons;
- d->buttons = g_memdup2 (device->buttons, sizeof(WacomButtonFlags) * device->num_buttons);
- d->button_codes = g_memdup2 (device->button_codes, sizeof(int) * device->num_buttons);
+ d->status_leds = g_memdup2(device->status_leds, sizeof(WacomStatusLEDs) * device->num_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);
+ while (g_hash_table_iter_next(&iter, &k, &v)) {
+ WacomButton *a = v;
+ WacomButton *b = g_memdup2(a, sizeof(WacomButton));
+ g_hash_table_insert(d->buttons, k, b);
+ }
return d;
}
@@ -401,6 +409,9 @@ libwacom_same_layouts (const WacomDevice *a, const WacomDevice *b)
LIBWACOM_EXPORT int
libwacom_compare(const WacomDevice *a, const WacomDevice *b, WacomCompareFlags flags)
{
+ GHashTableIter iter;
+ gpointer k, v;
+
g_return_val_if_fail(a || b, 0);
if (!a || !b)
@@ -439,7 +450,7 @@ libwacom_compare(const WacomDevice *a, const WacomDevice *b, WacomCompareFlags f
if (a->ring2_num_modes != b->ring2_num_modes)
return 1;
- if (a->num_buttons != b->num_buttons)
+ if (g_hash_table_size(a->buttons) != g_hash_table_size(b->buttons))
return 1;
if (a->styli->len != b->styli->len)
@@ -454,11 +465,14 @@ libwacom_compare(const WacomDevice *a, const WacomDevice *b, WacomCompareFlags f
if (memcmp(a->status_leds, b->status_leds, sizeof(WacomStatusLEDs) * a->num_leds) != 0)
return 1;
- if (memcmp(a->buttons, b->buttons, sizeof(WacomButtonFlags) * a->num_buttons) != 0)
- return 1;
+ g_hash_table_iter_init(&iter, a->buttons);
+ while (g_hash_table_iter_next(&iter, &k, &v)) {
+ WacomButton *ba = v;
+ WacomButton *bb = g_hash_table_lookup(b->buttons, k);
- if (memcmp(a->button_codes, b->button_codes, sizeof(int) * a->num_buttons) != 0)
- return 1;
+ if (!bb || ba->flags != bb->flags || ba->code != bb->code)
+ return 1;
+ }
if ((a->paired == NULL && b->paired != NULL) ||
(a->paired != NULL && b->paired == NULL) ||
@@ -880,8 +894,8 @@ libwacom_unref(WacomDevice *device)
g_array_free (device->matches, TRUE);
g_array_free (device->styli, TRUE);
g_free (device->status_leds);
- g_free (device->buttons);
- g_free (device->button_codes);
+ if (device->buttons)
+ g_hash_table_destroy (device->buttons);
g_free (device);
return NULL;
@@ -1048,7 +1062,7 @@ libwacom_has_touch(const WacomDevice *device)
LIBWACOM_EXPORT int
libwacom_get_num_buttons(const WacomDevice *device)
{
- return device->num_buttons;
+ return g_hash_table_size(device->buttons);
}
LIBWACOM_EXPORT const int *
@@ -1114,24 +1128,18 @@ struct {
LIBWACOM_EXPORT int
libwacom_get_button_led_group (const WacomDevice *device, char button)
{
- int button_index, led_index;
- WacomButtonFlags button_flags;
-
- g_return_val_if_fail (device->num_buttons > 0, -1);
- g_return_val_if_fail (button >= 'A', -1);
- g_return_val_if_fail (button < 'A' + device->num_buttons, -1);
-
- button_index = button - 'A';
- button_flags = device->buttons[button_index];
+ int led_index;
+ WacomButton *b = g_hash_table_lookup(device->buttons,
+ GINT_TO_POINTER(button));
- if (!(button_flags & WACOM_BUTTON_MODESWITCH))
+ if (!(b->flags & WACOM_BUTTON_MODESWITCH))
return -1;
for (led_index = 0; led_index < device->num_leds; led_index++) {
guint n;
for (n = 0; n < G_N_ELEMENTS (button_status_leds); n++) {
- if ((button_flags & button_status_leds[n].button_flags) &&
+ if ((b->flags & button_status_leds[n].button_flags) &&
(device->status_leds[led_index] == button_status_leds[n].status_leds)) {
return led_index;
}
@@ -1179,29 +1187,20 @@ libwacom_get_bustype(const WacomDevice *device)
LIBWACOM_EXPORT WacomButtonFlags
libwacom_get_button_flag(const WacomDevice *device, char button)
{
- int index;
+ WacomButton *b = g_hash_table_lookup(device->buttons,
+ GINT_TO_POINTER(button));
- g_return_val_if_fail (device->num_buttons > 0, WACOM_BUTTON_NONE);
- g_return_val_if_fail (button >= 'A', WACOM_BUTTON_NONE);
- g_return_val_if_fail (button < 'A' + device->num_buttons, WACOM_BUTTON_NONE);
- index = button - 'A';
-
- return device->buttons[index];
+ return b ? b->flags : WACOM_BUTTON_NONE;
}
LIBWACOM_EXPORT int
libwacom_get_button_evdev_code(const WacomDevice *device, char button)
{
- int index;
-
- g_return_val_if_fail (device->num_buttons > 0, 0);
- g_return_val_if_fail (button >= 'A', 0);
- g_return_val_if_fail (button < 'A' + device->num_buttons, 0);
-
- index = button - 'A';
+ WacomButton *b = g_hash_table_lookup(device->buttons,
+ GINT_TO_POINTER(button));
- return device->button_codes[index];
+ return b ? b->code : 0;
}
LIBWACOM_EXPORT const
diff --git a/libwacom/libwacomint.h b/libwacom/libwacomint.h
index f5041a2..47574b0 100644
--- a/libwacom/libwacomint.h
+++ b/libwacom/libwacomint.h
@@ -61,6 +61,12 @@ struct _WacomMatch {
uint32_t product_id;
};
+/* Used in the device->buttons hashtable */
+typedef struct _WacomButton {
+ WacomButtonFlags flags;
+ int code;
+} WacomButton;
+
/* WARNING: When adding new members to this struct
* make sure to update libwacom_copy() and
* libwacom_print_device_description() ! */
@@ -85,10 +91,7 @@ struct _WacomDevice {
int ring2_num_modes;
GArray *styli;
-
- int num_buttons;
- WacomButtonFlags *buttons;
- int *button_codes;
+ GHashTable *buttons; /* 'A' : WacomButton */
int num_leds;
WacomStatusLEDs *status_leds;