Have your program read the name-to-code mapping from a configuration file(s), say /usr/share/yourprogram/keycodes
and/or $HOME/.yourprogram/keycodes
.
Document that anyone can regenerate that file from their /usr/include/linux/input.h
-- and regenerate the initial file yourself -- using for example
awk '$2 ~ /^KEY_/ { code[$2] = $3 }
END {
for (name in code)
if (code[name] ~ /^KEY_/)
code[name] = code[code[name]];
for (name in code)
if (code[name] !~ /KEY_/)
printf "%-24s %s\n", name, code[name]
}' /usr/include/linux/input.h | sort
You might have to add KEY_CNT
youself (it's value is one more than KEY_MAX
), as the above script does not do math, only direct aliases.
To describing the name-to-code mappings, I'd use
struct keycode {
struct keycode *next;
unsigned int code;
unsigned int hash;
unsigned char namelen;
char name[];
};
where the hash is a simple hash, say djb2,
unsigned int djb2(const char *const str, const size_t len)
{
unsigned int result = 5831U;
size_t i;
for (i = 0; i < len; i++)
result = result * 33U ^ (unsigned int)str[i];
return result;
}
Of currently defined key codes, only KEY_CUT
and KEY_F15
map to the same djb2 hash, 1857856141. (If you used 31U
instead of 33U
, the current set would have no collisions, but that's no proof against future collisions. Better have one collision already, so you can test it is handled correctly.)
The function that reads the configuration file could just return the codes by prepending new ones to a singly-linked list, perhaps
int read_keycodes(const char *const filename,
struct keycode **list);
If you prepend to the list, you should later on ignore redefinitions of the same name. This way, if you read the system-wide configuration first, then the user-specific one, the user-specific one can override the system-wide ones.
After all keycode mappings are read, you construct a hash table, something like
struct keytab {
unsigned int size; /* index = hash % size */
struct keycode **slot;
};
(When building the hash table, discard keycodes whose exact names are already in the keytab. This way later definitions override earlier ones.)
This way you only need to calculate the hash of the name you want to look up, then probe the linked list in your keytab structure. Compare hashes first, then lengths; if both match, finally do a strcmp()
. This way the lookup will be very fast, and relatively simple to implement, too. With current key codes, you'll only do the slow strcmp()
twice for KEY_F15
and KEY_CUT
; for all others, a single strcmp()
will suffice.
Questions?