Is there any way to get evdev keycode from a string?

I would like to read button mappings from a text file that contains such data:

DPAD_LEFT = 105 DPAD_RIGHT = 106 DPAD_UP = 103 DPAD_DOWN = 108 

The right side is actually the evdev code number (as defined in <linux/input.h> ).

This is pretty hard to read, so I would like to have these files:

 DPAD_LEFT = KEY_LEFT DPAD_RIGHT = KEY_RIGHT DPAD_UP = KEY_UP DPAD_DOWN = KEY_DOWN 

But I currently cannot return them:

 char[256] keyname; some_method_to_read(&keyname, "DPAD_LEFT"); //keyname now contains "KEY_LEFT" 

How to get the corresponding key code (for example, 105 )? Is there a standard way to do this?

EDIT: The only way I can think of now is to duplicate all key codes in my source and put them in an array or map, for example evtest utility . But there are many key codes, and to me it seems a bit redundant. In addition, at some point this may go out of sync with the key codes defined in <input/linux.h> .

 std::map<string, int> keynames; #define MAP_KEYCODE(keycode) keynames[#keycode] = keycode MAP_KEYCODE(KEY_LEFT); MAP_KEYCODE(KEY_RIGHT); MAP_KEYCODE(KEY_UP); MAP_KEYCODE(KEY_DOWN); // [...] 
+4
source share
2 answers

I found a way to do it right: using libevdev libevdev_event_code_from_name .

 unsigned int event_type = EV_KEY; const char* name = "BTN_A"; int code = libevdev_event_code_from_name(event_type, name); if(code < 0) { puts("There was an error!"); } 
0
source

Ask your program to read the name-code mapping from the configuration file (s), for example /usr/share/yourprogram/keycodes and / or $HOME/.yourprogram/keycodes .

The document that anyone can restore this file from their /usr/include/linux/input.h - and restore the original file themselves, 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 may need to add KEY_CNT youself (this value is greater than KEY_MAX ), since the above script does not perform math, but only direct aliases.

To describe comparisons between names, I would use

 struct keycode { struct keycode *next; unsigned int code; unsigned int hash; unsigned char namelen; char name[]; }; 

where the hash is a simple hash of, 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; } 

Currently certain key codes, only KEY_CUT and KEY_F15 mapped to the same djb2 hash, 1857856141. (If you used 31U instead of 33U , the current set will not have collisions, but it will not be proof against future collisions. It is better to have one collision so that you can verify that it is being processed correctly.)

A function that reads the configuration file may simply return codes by adding new ones to the list with one link, perhaps

 int read_keycodes(const char *const filename, struct keycode **list); 

If you added to the list, you should later ignore the override with the same name. Thus, if you first read the system-wide configuration, then the user-specific, depending on the user, can override the system-wide.

After all the code key mappings have been read, you will create a hash table, something like

 struct keytab { unsigned int size; /* index = hash % size */ struct keycode **slot; }; 

(When constructing a hash table, discard the key codes whose exact names are already in keytab. Thus, later definitions override the earlier ones.)

Thus, you only need to calculate the hash of the name you want to find, and then check the linked list in your keytab structure. Compare hashes first, then lengths; if both matches finally execute strcmp() . Thus, the search will be very fast and relatively easy to implement. When using current key codes, you will execute slow strcmp() twice for KEY_F15 and KEY_CUT ; for all the rest, one strcmp() enough.

Questions?

0
source

All Articles