我有一个节点应用程序,它运行在覆盆子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不是我最强的语言,我无法确定他是如何处理它的(或者它是否应该被处理)。那个守护进程甚至不适合我(在树莓派上编译)。
答案 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_sec
为0x515b3ea4
(因为它是小端的反转顺序),小数为1364934308
。一个简单的unix时间转换器报告这意味着02.04.2013 - 22:25:08
。看起来不错!
tv_usec
是0x0003cfab=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;
}