在Linux系统中,如何直接处理来自字符设备/游戏手柄的input?

我正在开发一个使用USB SNES控制器进行基于RPM分发的input的C程序。 有没有一个库让任何人知道,这使得它更容易交互,或者一些工具(joydev?)允许正确读取设备的input? 我不需要整个游戏引擎。 它只是从字符设备input。

如果有一个图书馆已经为我做了这个,那将是非常好的(我可以看看图书馆自己做了什么),这可以通过一个链接来closures; 否则,如果我必须自己做这个,我有几个具体的问题:

问题:

  • 有一个已经存在的C库,可以为我处理所有与USB设备交互的游戏手柄吗? 我很乐意学习一个新的图书馆。 (我的google-fu在这里失败了,我很抱歉,如果这太明显了)
  • 什么是确保您每次打开适当的字符设备的适当方法,因为事件*名称在会话/初始化之间改变?
  • 从我的应用程序处理来自这些设备的input的适当方法是什么? 只要确定每个button按下的值是多less,并在我们轮询字符设备时根据该input执行操作?

简单的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 

如果我从设备读取,我可以看到它收到来自设备的中断和input只是使用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 

在释放button时,您会收到类似的输出:

 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 

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

这个调查:

为了确定其他库如何做到这一点,我想在Python中做一堆pygame ,看看它打开了什么设备,以及如何读取input,但我仍然在学习如何使用它。 我还看到有关joydev的一些模糊提到,但是,还没有学会如何使用它们。 我现在正在这样做,如果我学到任何有价值的东西,我会发布结果。

除此之外,看button通过ASCII和hexbutton,我注意到他们有一个类似的input基于button,但似乎有什么我是在上面的输出(0xf53a到USB总线中断的计数中断0xf53c)。 这总是看起来也增加了,而且,为了我的目的,可能会被丢弃。

也有可能我只是不正确地安装设备,因为我错过了一些模块或包(再次想到了joydev和它应该做的)。 我没有经常使用USB,所以这种types的设备处理对我来说是新的。

search一下,我没有看到任何显示我正在寻找的东西,但我很乐意接受redirect到其他问题/阅读主题。

先谢谢你!

    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_event 。 第一个是:

     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用于将单个事件的不同值组合在一起,例如水平和EV_SYN鼠标或操纵杆的垂直轴。

    您的其他转储类似,但对于AXIS_Y

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

    这是一个USB HID设备,所以它是由HID驱动程序处理 – 请参阅您的调试输出“USB HID v1.10游戏手柄”有各种教程和示例说明如何做到这一点。

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

    另外libhidapi是一个不错的选择。