【问题标题】:Would it be possible to read out physical keyboard strokes in node.js?是否可以在 node.js 中读出物理键盘击键?
【发布时间】:2013-03-22 10:51:25
【问题描述】:

我有一个运行在树莓派上的节点应用程序,它跟踪一堆 UPnP 播放器 (Sonos),我希望能够通过物理遥控器对其进行控制。我有几个空中鼠标,它们有小键盘以及我想使用的音量按钮。

我试图掌握如何在 linux 机器上读取物理按键,并得出结论,我需要从输入设备读取事件,在我的情况下是:

/dev/input/by-id/usb-Dell_Dell_QuietKey_Keyboard-event-kbd

如何找到设备和类似的东西不是问题,真正的问题是如何解释您从中读取的数据。

我知道你会收到一个 C 结构体,像这样:

struct input_event {
    struct timeval time;
    unsigned short type;
    unsigned short code;
    unsigned int value;
};

但我不确定如何从 node.js 读取这个。如果我可以运行一个外部应用程序,该应用程序将由预定义的击键触发,然后针对我的节点调用 HTTP 请求,那将是我的第二个选择,python 脚本或一些本机守护程序。但是,我查看了一些热键守护程序,但它们都不起作用。

如果我能以某种方式将它包含在节点中当然会很好。

编辑:所以我做了一些测试,并做了一个简单的 sn-p:

var fs = require('fs');

var buffer = new Buffer(16);

fs.open('/dev/input/by-id/usb-HJT_Air_Mouse-event-kbd', 'r', function (err, fd) {
    while (true) {
        fs.readSync(fd, buffer, 0, 16, null);
        console.log(buffer)
    }
});

这会输出类似这样的内容(用于空格):

<Buffer a4 3e 5b 51 ab cf 03 00 04 00 04 00 2c 00 07 00>
<Buffer a4 3e 5b 51 c3 cf 03 00 01 00 39 00 01 00 00 00>
<Buffer a4 3e 5b 51 cb cf 03 00 00 00 00 00 00 00 00 00>
<Buffer a4 3e 5b 51 ba 40 06 00 04 00 04 00 2c 00 07 00>
<Buffer a4 3e 5b 51 cd 40 06 00 01 00 39 00 00 00 00 00>
<Buffer a4 3e 5b 51 d2 40 06 00 00 00 00 00 00 00 00 00>

我意识到前四个字节是某种时间戳,接下来的 3 个字节可能是微/毫秒的东西。

另一个奇怪的事情是,并非所有按键都会产生输出,但随后的按键可能会发送两倍的数据,并且大多数情况下它会开始爆出数据,这些数据会在后续按键(或大约 20 秒左右)后停止.我不确定如何解释。我试图阅读这个守护进程https://github.com/baskerville/shkd/blob/master 的源代码,但 C 不是我最强的语言,我无法确定他如何处理它(或者是否应该处理它)。而且那个守护进程甚至对我都不起作用(在树莓派上编译)。

【问题讨论】:

    标签: linux node.js usb hid


    【解决方案1】:

    我认为您正在寻找的是 fs.createReadStream,因此您可以安装一些事件处理程序。

    您可以使用 Buffer.readX 例程将输入事件解析为结构:

      var i = 0;
      while((buf.length-i) >= 16) {
         var event = {
            tssec:   buf.readUInt32LE(i+0),
            tsusec:  buf.readUInt32LE(i+4),
            type:    buf.readUInt16LE(i+8),
            code:    buf.readUInt16LE(i+10),
            value:   buf.readUInt32LE(i+12)
         };
         i += 16;
      }
    

    【讨论】:

      【解决方案2】:

      好吧,让我们看看那个结构。

      struct input_event {
          struct timeval time;
          unsigned short type;
          unsigned short code;
          unsigned int value;
      };
      

      struct timeval 具有这样的结构:

      struct timeval
        {
          __time_t tv_sec;            /* Seconds.  */
          __suseconds_t tv_usec;      /* Microseconds.  */
        };
      

      这些时间类型的定义是

      typedef signed long time_t;
      typedef signed long suseconds_t;
      

      signed long 是 4 个字节(好吧,如果你只是遵循规范,但实际上是这样),所以前 8 个字节是一个类型戳。接下来,您有一个类型和一个代码。两者都是short,所以在实践中,它们每个都是 2 个字节。现在只剩下值了,这又是一个 int,它将是四个字节。此外,编译器理论上可以在此处的字段之间添加填充,但我很确定他不会。

      所以,首先将您读取的字节切成4+4+2+2+4=16 字节的块。这些块中的每一个都是一个事件。这适合您的样本数据。接下来,从缓冲区中提取值(作为小端值,因为您在 ARM 系统上 - 在普通 PC 上,您需要大端)并解释这些值。有关如何执行此操作的说明,请阅读 http://www.mjmwired.net/kernel/Documentation/input/event-codes.txt。常量的值没有写在那里,但您通常可以使用grep -R NAME_OF_CONSTANT /usr/include 找到这些值。

      让我们切碎

      <Buffer a4 3e 5b 51 ab cf 03 00 04 00 04 00 2c 00 07 00>
      

      举个例子。

      <Buffer a4 3e 5b 51 ab cf 03 00 04 00 04 00 2c 00 07 00>
             |   tv_sec  |  tv_usec  |type |code |   value   |
      

      tv_sec 十六进制是 0x515b3ea4 (颠倒顺序,因为它是小端序),这是 1364934308 十进制。一个简单的 unix 时间转换器报告这意味着 02.04.2013 - 22:25:08。看起来不错!

      tv_usec0x0003cfab=249771,所以实际上,事件发生在249771 微秒之后。

      类型是0x0004=4/usr/include/linux/input.h 告诉我们这是EV_MSC

      给定类型,我们还可以看到代码,0x0004=4,意思是MSC_SCAN

      值为0x0007002c。在input.h 中无处出现。嗯。

      【讨论】:

      • 谢谢,我在这里找到了常量:tomoyo.sourceforge.jp/cgi-bin/lxr/source/include/uapi/linux/…,关于尺寸,我得出了与您类似的结论。但是,重复的事件对我来说是个谜,如果我过滤掉所有不是 type = 1 和 value = 0 的东西,我通常会得到相应的键码,但它会漏掉很多笔画。有什么想法吗?
      • @jishi: 按键是否出现在普通控制台中?可能是您的键盘只是电池没电了。 :D
      • 感谢您的澄清。我想我可以放心地忽略 MSC_SCAN 条目。关于重复的代码,似乎是空中鼠标在起作用,我无法复制有线戴尔键盘上的行为。感谢您的反馈!
      猜你喜欢
      • 1970-01-01
      • 2012-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-28
      • 2020-11-04
      • 2021-09-05
      • 2021-10-25
      相关资源
      最近更新 更多