是否可以在node.js中读出物理键盘笔划?

时间:2013-04-01 10:59:51

标签: linux node.js usb hid

我有一个节点应用程序,它运行在覆盆子pi上,跟踪一堆UPnP播放器(Sonos),我希望能够通过物理遥控器进行控制。我有几个airmouses,它有小键盘和音量按钮,我想用。

我试图了解如何读取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;
};

但是我不确定如何从节点读取它。如果我可以运行一个外部应用程序,它将从预定义的击键触发,然后针对我的节点调用HTTP请求,那将是我的第二个选项,python脚本或一些本机守护程序。然而,我看了一些热键守护进程,但没有一个有效。

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

编辑:所以我做了一些测试,制作了一个简单的片段:

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不是我最强的语言,我无法确定他是如何处理它的(或者它是否应该被处理)。那个守护进程甚至不适合我(在树莓派上编译)。

2 个答案:

答案 0 :(得分: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_sec0x515b3ea4(因为它是小端的反转顺序),小数为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中无处可寻。 HMM。

答案 1 :(得分:0)

我认为你要找的是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;
  }