【问题标题】:How does one handle input from a character device/gamepad directly in Linux systems?如何在 Linux 系统中直接处理来自字符设备/游戏手柄的输入?
【发布时间】:2016-04-26 22:58:27
【问题描述】:

我正在用 C 语言开发一个程序,该程序使用 USB SNES controller 输入基于 RPM 的发行版。是否有任何人都知道的库可以使交互更容易,或者是否有一些工具(joydev?)可以正确读取设备的输入?我不需要整个游戏引擎;它仅用于字符设备的输入。

如果有一个图书馆已经为我做了这件事,那就太好了(我可以自己看看图书馆做了什么),并且可以通过一个链接关闭它;否则,如果我必须自己这样做,我有几个具体问题:

问题:

  • 是否有现有的 C 库可以为我处理所有 USB 设备与游戏手柄的交互?我很乐意学习一个新的图书馆。 (我的 google-fu 在这里让我失望了,如果这过于明显,我深表歉意)
  • 当事件*名称在会话/初始化之间发生变化时,确保您每次都打开正确的字符设备的适当方法是什么?
  • 在我的应用程序中处理来自这些设备的输入的适当方法是什么?当我们轮询字符设备时,只需确定每次按下按钮的价值并根据该输入执行操作?

简而言之,pseduo-C,类似这样的东西?

struct gamepad {
    int fd;
};

void get_input(struct gamepad *gamepad)
{
    char *buf;
    read(gamepad->fd, buf, 48);
    switch(buf)
    {
        /* insert cases about handling differing buttons */
    }
}

设备如何呈现自己:

我可以清楚地看到设备注册正确:

$ dmesg | tail
[198564.517068] usb 1-1: USB disconnect, device number 17
[198566.154324] usb 1-1: new low-speed USB device number 18 using xhci_hcd
[198566.323309] usb 1-1: New USB device found, idVendor=12bd, idProduct=d015
[198566.323312] usb 1-1: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[198566.323313] usb 1-1: Product: 2Axes 11Keys Game  Pad
[198566.323792] usb 1-1: ep 0x81 - rounding interval to 64 microframes, ep desc says 80 microframes
[198566.328692] input: 2Axes 11Keys Game  Pad as /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/input/input20
[198566.329036] hid-generic 0003:12BD:D015.0006: input,hidraw2: USB HID v1.10 Gamepad [2Axes 11Keys Game  Pad] on usb-0000:00:14.0-1/input0

如果我从设备读取,我可以看到它接收到来自设备的中断和输入,只是使用 hexdump:

$ ls -lattr /dev/input/by-id/usb-12bd_2Axes_11Keys_Game_Pad-event-joystick 
lrwxrwxrwx. 1 root root 10 Jan 20 15:56 /dev/input/by-id/usb-12bd_2Axes_11Keys_Game_Pad-event-joystick -> ../event17

当我按下一个键(不释放)时,它似乎按预期工作,尽管我无法在没有上下文的情况下破译从缓冲区返回的内容:

$ hexdump /dev/input/event17 
0000000 f53a 569f 0000 0000 ac6c 000c 0000 0000
0000010 0003 0000 007f 0000 f53a 569f 0000 0000
0000020 ac6c 000c 0000 0000 0000 0000 0000 0000

释放按钮时,您会收到类似的输出:

0000030 f53c 569f 0000 0000 8be3 0007 0000 0000
0000040 0003 0001 007f 0000 f53c 569f 0000 0000
0000050 8be3 0007 0000 0000 0000 0000 0000 0000

这是上面按下并释放的“向上”按钮。

研究:

为了确定其他库是如何做到这一点的,我考虑在 python 中对pygame 进行 strace 并查看它打开了哪些设备以及它如何读取输入,但我仍在学习如何使用它。我还看到一些关于joydev 的模糊提及,但是,同样,还没有学会如何使用它们。我目前正在这样做,如果我学到任何有价值的东西,我会发布结果。

除此之外,通过 ASCII 和 hexdump 观看按钮按下,我注意到它们具有基于按钮的类似输入,但似乎我认为是上面输出末尾的 USB 总线中断计数(0xf53a 到 0xf53c)。这似乎总是在增加,并且,就我的目的而言,可能会被丢弃。

还有一种可能是我没有正确安装设备,因为我缺少一些模块或包(再次思考joydev 以及它应该做什么)。我根本不经常使用 USB,所以这种类型的设备处理对我来说是新的。

搜索了一段时间,我没有看到任何能准确显示我正在寻找的东西的东西,但我很乐意接受重定向到其他问题/主题以供阅读。

提前谢谢你!

【问题讨论】:

  • 大多数游戏/框架(包括pygame)最终都会使用libsdl
  • 从前,大约 15 年前,我编写了一个快速的 Python 小库,用于解释原始 evdev 事件。不知道它发生了什么,或者它是否曾经公开(在与工作相关的 QA 自动化的背景下完成),但是……这真的一点也不难;一旦你有了格式,struct 模块就可以很好地解码它们。

标签: c linux input gamepad


【解决方案1】:

Linux 中的 USB 输入设备通常由 HID 驱动程序(人机接口设备)处理,然后将其转换为输入设备。

您可以将它们作为原始 USB 设备读取,但这通常不是一个好主意,因为它是一个非常低级的协议。

如果您有适当的权限,您可以读取/dev/input/* 设备。通常它们只能由 root 读取。如果您不想读取原始字节,有一些库,例如 libinput,可以为您完成这项工作。

但如果您的游戏在 XWindows 中运行(很可能),那么您应该管理 XInput 设备。您可以使用原始 X 调用来做到这一点,但您可能最好使用一些库,例如 SDL。实际上,SDL 是 pygame 在后台使用的,所以我先尝试一下。

关于如何识别正确的设备,每个输入设备都有一个名称,有些甚至还有一个序列号(您可以在/dev/input/by-id 下看到这些符号链接,这些通常足以识别设备,而不是输入编号。

如果您想阅读原始输入设备,让我解释一下您的 hexdumps。您正在阅读input* 设备,因此您将获得struct input_event 类型的值(请参阅/usr/include/linux/input.h):

struct input_event {
    struct timeval time;
    __u16 type;
    __u16 code;
    __s32 value;
};

在您的第一个转储中,例如:

0000000 f53a 569f 0000 0000 ac6c 000c 0000 0000
0000010 0003 0000 007f 0000 f53a 569f 0000 0000
0000020 ac6c 000c 0000 0000 0000 0000 0000 0000

实际上有两个input_events。第一个是:

f53a 569f 0000 0000 ac6c 000c 0000 0000 0003 0000 007f 0000

前 64 个字节是时间戳。那么,0003 (EV_ABS) 表示绝对轴的运动,0000 (ABS_X) 是轴索引,0000007f 是该轴的位置。绝对轴有时用于表示油门、操纵杆等(有时键盘作为操纵杆而不是 4 个按钮发送),即使您不移动它,您也可以在第一次读取时获得位置以了解控件的位置。

第二个事件是:

f53a 569f 0000 0000 ac6c 000c 0000 0000 0000 0000 0000 0000

前 64 字节是时间戳(同上。然后0000 (EV_SYN) 表示同步事件。EV_SYN,其他字段未使用。EV_SYN 用于将单个事件的不同值组合在一起,例如鼠标或操纵杆的水平轴和垂直轴。

您的其他转储与AXIS_Y 类似。

我的猜测是键盘被视为数字操纵杆,两个轴ABS_XABS_Y,是0x7F 的中间点(范围从0x000xFF)。您收到的消息只是中间点,即没有按下键盘按钮。也许您的hexdump 输出正在被缓冲?

【讨论】:

    【解决方案2】:

    它是一个 USB Hid 设备,因此由 hid 驱动程序处理 - 请参阅调试输出“USB HID v1.10 Gamepad” 有各种教程和示例说明如何做到这一点。

    作为起点,您可以通过“apt-get install joystick”安装游戏杆并查看源代码。

    libhidapi 也是一个不错的选择。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-11
      • 1970-01-01
      • 1970-01-01
      • 2021-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多