草庐IT

c - 如何直接在 Linux 系统中处理来自字符设备/游戏 handle 的输入?

coder 2023-06-18 原文

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

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

问题:

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

简而言之,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 的模糊提及,但同样,我还没有学会如何使用它们。我目前正在这样做,如果我学到任何有值(value)的东西,我会发布结果。

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

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

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

提前致谢!

最佳答案

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

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

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

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

关于如何识别正确的设备,每个输入设备都有一个名称,有些甚至是一个序列号(你看到那些作为 /dev/input/by-id 下的符号链接(symbolic link)这些通常是足以识别设备,而不是输入数字。

如果你想阅读原始输入设备,让我解释一下你的 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 是该轴的位置轴。绝对轴有时用于表示 throttle 、操纵杆等(有时键盘作为操纵杆而不是 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_Y0x7F 中间点 (范围从 0x000xFF)。您收到的消息只是中间点,即没有按下键盘按钮。也许您的 hexdump 输出正在被缓冲?

关于c - 如何直接在 Linux 系统中处理来自字符设备/游戏 handle 的输入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34911196/

有关c - 如何直接在 Linux 系统中处理来自字符设备/游戏 handle 的输入?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. Ruby 解析字符串 - 2

    我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?

  4. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  5. ruby-on-rails - unicode 字符串的长度 - 2

    在我的Rails(2.3,Ruby1.8.7)应用程序中,我需要将字符串截断到一定长度。该字符串是unicode,在控制台中运行测试时,例如'א'.length,我意识到返回了双倍长度。我想要一个与编码无关的长度,以便对unicode字符串或latin1编码字符串进行相同的截断。我已经了解了Ruby的大部分unicode资料,但仍然有些一头雾水。应该如何解决这个问题? 最佳答案 Rails有一个返回多字节字符的mb_chars方法。试试unicode_string.mb_chars.slice(0,50)

  6. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  7. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  10. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

随机推荐