c - 有没有办法从字符串中获取 evdev 键码?

标签 c linux c-preprocessor evdev

我想从包含如下数据的文本文件中读取按钮映射:

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

右边的部分实际上是 evdev 键码(在 <linux/input.h> 中定义)。

这很难读,所以我希望能够拥有这样的文件:

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

但我目前无法将它们转换回来:

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

如何获得相应的键码(例如 105 )?有没有标准的方法来做到这一点?

编辑: 我现在能想到的唯一方法是复制源代码中的所有键码并将它们放入数组或映射中,例如 evtest utility做。但是有很多键码,这对我来说似乎有点矫枉过正。此外,这可能与 <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);
// [...]

最佳答案

让您的程序从配置文件中读取名称到代码的映射,比如 /usr/share/yourprogram/keycodes 和/或 $HOME/.yourprogram/键码

任何人都可以从他们的 /usr/include/linux/input.h 重新生成该文件的文档 - 并自己重新生成初始文件 - 例如使用

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

您可能需要自己添加 KEY_CNT(它的值比 KEY_MAX 多一个),因为上面的脚本不做数学运算,只做直接别名。

为了描述名称到代码的映射,我会使用

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

这里的散列是一个简单的散列,比如 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;
}

在当前定义的键代码中,只有 KEY_CUTKEY_F15 映射到相同的 djb2 哈希 1857856141。(如果您使用 31U 而不是33U,当前集合不会发生碰撞,但这并不能证明将来会发生碰撞。最好已经有一次碰撞,这样您就可以测试它是否得到正确处理。)

读取配置文件的函数可能只是通过将新的代码添加到单链表来返回代码,也许

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

如果您添加到列表中,您稍后应该忽略同名的重新定义。这样,如果您首先读取系统范围的配置,然后是特定于用户的配置,则特定于用户的配置可以覆盖系统范围的配置。

读取所有键码映射后,您构建一个哈希表,类似于

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

(在构建哈希表时,丢弃其确切名称已经在 key 表中的键码。这样,后面的定义会覆盖前面的定义。)

这样你只需要计算你想查找的名字的散列,然后探测你的keytab结构中的链表。先比较哈希值,再比较长度;如果两者匹配,最后执行 strcmp()。这样查找会非常快,而且实现起来也相对简单。使用当前的键代码,您只需为 KEY_F15KEY_CUT 执行两次缓慢的 strcmp();对于所有其他人,单个 strcmp() 就足够了。

有问题吗?

关于c - 有没有办法从字符串中获取 evdev 键码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32059363/

相关文章:

linux - 当从 Linux 机器调用时,Excel 作为后台进程启动。我需要它作为一个应用程序

linux - 如何从USB端口连接到RJ45控制台设备?

c - 如果 X 不是子进程,我如何等待 PID X 退出?

c++ - 是否有更有效或更高效的方法来编写冗长的文本?

c++ - C++ 宏什么时候有用?

c++ - 基于图 block 的横向卷轴游戏教程?

c - 差异 : &ary1D[0] and &ary1D

c - 使用 while(str[n++]! ='\0' ) 计算字符串的长度

c - C语言中如何进行枚举

c++ - 替换循环缓冲区/fifo 队列数组元素中的 "FOR()"宏