Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Would it be possible to read out physical keyboard strokes in node.js?

Would it be possible to read out physical keyboard strokes in node.js?

Problem

I have a node application which runs on a raspberry pi that keeps track of a bunch of UPnP-players (Sonos), which I would like to be able to control through a physical remote. I have a couple of airmouses, which has small keyboards as well as volume buttons that I would like to use.

I have tried to get a grip on how to read out physical key strokes on a linux machine, and come to the conclusion that I need to read events from the input device, which in my case would be:

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

How to find the device and stuff like that is not a problem, the real issue is how to interpret the data that you read from it.

I know that you would receive a C struct, like this:

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

But I'm not sure how I would go about reading this from node. If I could run an external app that would be triggered from pre-defined keystrokes, and then invoke an HTTP-request against my node, that would be my second option, a python script or some native daemon. I have however looked at some hotkey-daemons, but none of them worked.

If would of course be nice if I could contain it within node somehow.

EDIT: So I did some testing, and made a simple snippet:

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)
    }
});

This outputs something like this (for space):

I realize that the first four bytes are some sort of timestamp, and the following 3 bytes could be something like a micro/millisecond thing.

Another odd thing is that not all keypresses produces output, but a subsequent press might sent twice as much data, and most of the time it starts blasting out data which would stop after subsequent keypresses (or after about 20 seconds or so). I'm not really sure how to interpret that. I have tried to read the source for this daemon https://github.com/baskerville/shkd/blob/master but C is not my strongest language and I can't identify how he handles it (or if it should even be handled). And that daemon didn't even work for me (compiled it on a raspberry pi).

Problem courtesy of: jishi

Solution

Well, let's have a look at that struct.

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

A struct timeval has this structure:

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

The definition of those time types are

typedef signed long time_t;
typedef signed long suseconds_t;

A signed long is 4 bytes (well, not if you just follow the spec, but in practice, it is), so the first 8 bytes are a typestamp. Next, you have a type and a code. Both are short, so in practice, they're 2 bytes each. Now there's just the value left, and that's an int again, which will be four bytes. Also, a compiler could theoretically add padding between the fields here, but I'm pretty sure he won't.

So, first chop the bytes you've read into chunks of 4+4+2+2+4=16 bytes. Each of those chunks is an event. This fits your sample data. Next, extract the values from the buffer (as little endian values because you're on an ARM system – on a normal PC, you'd need big endian) and interpret the values. For instructions on how to do that, read http://www.mjmwired.net/kernel/Documentation/input/event-codes.txt. The values of the constants aren't written down there, but you can usually find those using grep -R NAME_OF_CONSTANT /usr/include.

Let's chop up

as an example.


       |   tv_sec  |  tv_usec  |type |code |   value   |

tv_sec in hex is 0x515b3ea4 (reversed order because it's little endian), which is 1364934308 in decimal. A simple unix time converter reports that this means 02.04.2013 - 22:25:08. Looks good!

tv_usec is 0x0003cfab=249771, so actually, the event happened 249771 microseconds after that time.

Type is 0x0004=4. /usr/include/linux/input.h tells us that this is a EV_MSC.

Given the type, we can also see the the code, 0x0004=4, means MSC_SCAN.

The value is 0x0007002c. Turns up nowhere in input.h. Hmm.

Solution courtesy of: thejh

Discussion

View additional discussion.



This post first appeared on Node.js Recipes, please read the originial post: here

Share the post

Would it be possible to read out physical keyboard strokes in node.js?

×

Subscribe to Node.js Recipes

Get updates delivered right to your inbox!

Thank you for your subscription

×