4

我有一个在树莓派上运行的节点应用程序,它跟踪一堆 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 脚本或一些本机守护程序。但是,我查看了一些热键守护程序,但没有一个起作用。

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

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

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

4

2 回答 2

2

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

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

Astruct timeval有这样的结构:

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

这些时间类型的定义是

typedef signed long time_t;
typedef signed long suseconds_t;

Asigned 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。唔。

于 2013-04-02T20:57:18.453 回答
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;
  }
于 2014-06-13T20:07:33.840 回答