Linux 上的 C++ : Listening to keyboard input while running as systemd service

标签 c++ input raspberry-pi embedded-linux systemd

因此,关于这个主题存在一些问题,但没有真正高质量的答案。

我的问题如下:我有一个在 Raspberry Pi 上运行的嵌入式应用程序,它是通过 init.d 启动的。整个设置没有屏幕,通常应该在生产使用中禁用网络的情况下工作(因为它将进入一个可能会出现 WiFi/蓝牙干扰问题的环境)。

我想使用通用 USB 键盘/数字键盘作为输入设备来进行配置和故障排除。当然,我不能只从 cin 读取,因为我的程序不是在终端上运行(事实上,没有终端)。

我该如何做到这一点,最好是在我不必担心键盘布局和/或插入的输入设备数量的细节的级别?

编辑 我可能的解决方法是涉及自动登录和 .profile 脚本。不过,如果有人能解决这个问题,我们将不胜感激。

最佳答案

@meuh 似乎赢得了最佳建议的 cookie:libevdev 说得正是时候。

我找到了this answer解决了绑定(bind)按键(ALT-X)自动启动程序的相关问题,整体结构非常容易适应(我修改的代码如下)。

在您获得的每个struct input_event中,您都会查找ev.type == EV_KEY来挑选键盘事件(而不是鼠标或其他事件),ev.code 包含按键的代码(KEY_UPKEY_0KEY_KP5KEY_BACKSPACE , ETC。)。我只用数字键盘进行测试,所以我没有得到 Shift 或 Alt 等类似信息,但我怀疑这很简单。

您还可以查看ev.value,它可以是:

  • EV_KEY - 按键按下
  • EV_REL - 键重复值(可选,可以多个)
  • EV_SYN - 按键

我想对于某些应用程序,您可以忽略除 EV_SYN 之外的所有内容来捕获按键事件;这就是我要做的。

$ sudo ./evtest
Device /dev/input/event1 is open and associated w/ libevent
KEY: Value=EV_KEY; Code=KEY_KP7    <-- KP = keypad
KEY: Value=EV_SYN; Code=KEY_KP7
KEY: Value=EV_KEY; Code=KEY_KP8
KEY: Value=EV_SYN; Code=KEY_KP8
KEY: Value=EV_KEY; Code=KEY_KP9
KEY: Value=EV_SYN; Code=KEY_KP9

请注意,键值不是 ASCII,也不是传统的键盘扫描代码 - 这些是一个全新的命名空间,并且可能有一些其他抽象层可以转换为常规 ASCII,但我还没有将其视为KEY_* 代码适合我的应用程序。但这比我之前使用的糟糕的 /dev/hidraw0 机制要好得多。

它确实需要 root 权限,这是有道理的,因为否则您的用户模式程序可能会等待 super 用户登录控制台,从而获取他们的密码。对于嵌入式应用程序,我确信这不会成为问题。

谢谢你,@meuh,给了我很好的建议。我什至不需要编写设备驱动程序!

下面的代码在运行 Debian Buster 的 BeagleBone 上运行。

// hack test for working with events
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <err.h>
#include <libevdev-1.0/libevdev/libevdev.h>

#define COUNTOF(x)  (int) ( ( sizeof(x) / sizeof((x)[0]) ) )

static void setupKeyCodes(void);
static const char *printableEventType(int t);
static const char *keycodes[64 * 1024] = { 0 }; // hack

int main(void) {

    setupKeyCodes();

    const char *eventDevice = "/dev/input/event1";

    const int fd = open(eventDevice, O_RDONLY | O_NONBLOCK);

    if (fd < 0) errx(EXIT_FAILURE, "ERROR: cannot open device %s [%s]", eventDevice, strerror(errno));

    struct libevdev *dev;

    int err = libevdev_new_from_fd(fd, &dev);

    if (err < 0) errx(EXIT_FAILURE, "ERROR: cannot associate event device [%s]", strerror(-err));

    printf("Device %s is open and associated w/ libevent\n", eventDevice);
    do {
        struct input_event ev;

        err = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);

        if (err == 0 && ev.type == EV_KEY)
        {
            printf("KEY: Value=%s; Code=%s\n",
                printableEventType(ev.value),
                keycodes[ev.code]);
        }
    } while (err == 1 || err == 0 || err == -EAGAIN);

    return 0;
}

// HACK: populate the whole array of possible keycodes with their strings
// so we can see what we're reading.

static void setupKeyCodes(void)
{
    for (int i = 0; i < COUNTOF(keycodes); i++)
        keycodes[i] = "-unknown-";

    // these from /usr/include/linux/input-event-codes.h

    keycodes[KEY_RESERVED] = "KEY_RESERVED";
    keycodes[KEY_ESC] = "KEY_ESC";
    keycodes[KEY_1] = "KEY_1";
    keycodes[KEY_2] = "KEY_2";
    keycodes[KEY_3] = "KEY_3";
    keycodes[KEY_4] = "KEY_4";
    keycodes[KEY_5] = "KEY_5";
    keycodes[KEY_6] = "KEY_6";
    keycodes[KEY_7] = "KEY_7";
    keycodes[KEY_8] = "KEY_8";
    keycodes[KEY_9] = "KEY_9";
    keycodes[KEY_0] = "KEY_0";
    // ... many many more
    keycodes[KEY_STOP_RECORD] = "KEY_STOP_RECORD";
    keycodes[KEY_PAUSE_RECORD] = "KEY_PAUSE_RECORD";
    keycodes[KEY_VOD] = "KEY_VOD";
    keycodes[KEY_UNMUTE] = "KEY_UNMUTE";
    keycodes[KEY_FASTREVERSE] = "KEY_FASTREVERSE";
    keycodes[KEY_SLOWREVERSE] = "KEY_SLOWREVERSE";
}

#define STRCASE(x)  case x: return #x

static const char *printableEventType(int t)
{
    switch (t)
    {
    STRCASE(EV_SYN);
    STRCASE(EV_KEY);
    STRCASE(EV_REL);
    STRCASE(EV_ABS);
    STRCASE(EV_MSC);
    STRCASE(EV_SW);
    STRCASE(EV_LED);
    STRCASE(EV_SND);
    STRCASE(EV_REP);
    STRCASE(EV_FF);
    STRCASE(EV_PWR);
    STRCASE(EV_FF_STATUS);
    default: return "-?-";
    }
}

关于Linux 上的 C++ : Listening to keyboard input while running as systemd service,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62045724/

相关文章:

c++ - 如何在不复制此代码的情况下将多个函数放入多个 namespace ?

c++ - "else"DevC++ 之前的预期主表达式

python - 使用 BeautifulSoup 提取复选框输入对象的标签值,而不是Python中的 Mechanize

Javascript/Jquery - 在选项卡后重置文本框 View 区域

C - 在 1021 次迭代时出现段错误,并且在 1020 次迭代时无法打开 i2c

c++ - 用于编辑文本框的 SDL

c++ - C++ 的 XML 数据绑定(bind)类似于 Java 的 JAXB

python - 在 pygame 中,新文本在旧文本上呈现

css - 输入内的填充打破宽度 100%

android - RTSP 实时视频流