Topic: Is it possible to read usb keyboard presses before pressing return?

If I run this:

mknod /dev/tty0 c 4 0 && cat /dev/tty0

I can see things that I type on the USB keyboard plugged into my chumby, but lines only appear after I press the return key. How can I get keypresses as they are typed?

Re: Is it possible to read usb keyboard presses before pressing return?

Hmmm, try (not tested, don't have access to a device right now...):

mknod /dev/tty0 c 4 0 && cat -u /dev/tty0

The -u switch should turn off buffering and output character-by-character - not sure if the cat in busybox supports it though.

Re: Is it possible to read usb keyboard presses before pressing return?

Using -u isn't working - nothing changes.

I found a file at /dev/input/event1 which outputs non-ascii characters every time I press a key on the keyboard. I don't know how to interpret the output, though.

Re: Is it possible to read usb keyboard presses before pressing return?

/dev/input/event1 (or, more convenient, /dev/input/by-id/*-kbd-*), might be what you're looking for.  The /by-id/ gives a friendlier name to the devices, and won't change even if you plug devices in in a different order.  The data that you're seeing is the raw input_event structure.  /dev/tty0 is line-buffered, which is why it's doing that.

The structure is defined in include/linux/input.h.  It is, I believe, a 128-bit structure.  You can ignore the first 32 bits, as it's just timestamp information.  The next 16 bits is the type, which for the keyboard will likely be EV_KEY (0x01).  The next 16 bits is the key, and will contain a VGA keycode.  The last 32-bits should be a 1 or a 0.

Though I could be wrong.  I'm not in front of a Linux device at the moment!

Re: Is it possible to read usb keyboard presses before pressing return?

ChumbyLurker wrote:

The structure is defined in include/linux/input.h.  It is, I believe, a 128-bit structure.  You can ignore the first 32 bits, as it's just timestamp information.  The next 16 bits is the type, which for the keyboard will likely be EV_KEY (0x01).  The next 16 bits is the key, and will contain a VGA keycode.  The last 32-bits should be a 1 or a 0.

What are the last 32 bits for? 32 + 16 + 16 + 32 = 96. According to the C structure that you linked to, sizeof(input_event) depends on sizeof(long) because of the timestamp. What is sizeof(long) on chumby? Assuming it is 4 bytes, that would make the timestamp 64 bits, and at least on my keyboard a 64+16+16+32=128 bit event size makes the most sense.

Here is a hexdump of me pressing one key:

chumby# hexdump /dev/input/by-id/*-kbd
hexdump 1.01
/dev/input/by-id/usb-Mitsumi_Electric_Apple_Extended_USB_Keyboard-event-kbd
00000000: 999a9a4c f52c0400 01002f00 01000000 ...L.,..../.....
00000010: 999a9a4c 132d0400 00000000 00000000 ...L.-..........
00000020: 999a9a4c 8c400600 01002f00 00000000 ...L.@..../.....
00000030: 999a9a4c 8c400600 00000000 00000000 ...L.@..........

512 bits are being recorded with each press. I think that each group of 128 bits is a separate keypress because they look so similar.

I wrote a ruby script to help figure out what is going on:

f = File.open '/dev/input/event1', 'r'

loop do
  s = f.read(16).unpack('a8SSl')
  p [s[1], s[2].to_s(16), s[3]]
end

Every time a 16 bytes is read from /dev/input/event1, this script prints out all fields but the timestamp. Here is the output from me pressing the "D" key once:

[1, "20", 1]
[0, "0", 0]
[1, "20", 0]
[0, "0", 0]

I don't know what the all-0 lines are for, but it seems that every time I press a key, two relevant events are read, one with a 1 for the last field and one with a 0. This probably means "key down" and "key up", respectively.

Am I correct? What is type 0x00? Also, it would make chumby development much easier if /dev/tty0 didn't buffer lines. smile

Re: Is it possible to read usb keyboard presses before pressing return?

Yes, you're right, the first 64 bits are the timestamp.  Sorry about that!

Your first example decodes as:

{{tv_secs, tv_nsecs}, EV_KEY, KEY_V, 1}
{{tv_secs, tv_nsecs}, EV_SYN, SYN_REPORT, 0}


{{tv_secs, tv_nsecs}, EV_KEY, KEY_V, 0}
{{tv_secs, tv_nsecs}, EV_SYN, SYN_REPORT, 0}

The EV_SYN event is a synchronization marker.  It's useful if several messages come at the same time.  For example, when you touch the screen, you'll get two EV_ABS events (one for the ABS_X and one for ABS_Y) and I think an EV_KEY event at the same time, followed by an EV_SYN event telling you to go ahead and process them.

You might be able to turn off buffering on /dev/tty0.  You could check to see how SDL does it, as I think that's the file they read.

Re: Is it possible to read usb keyboard presses before pressing return?

Isn't this just a case of linux having the tty device in "cooked" mode, and so is (by default) line buffered?  If so you need to put the device into "raw" mode.  Here's an example code that will take a single keypress

#!/bin/sh

TTY=/dev/tty0
old=`stty -g < $TTY`
stty raw min 1 -echo < $TTY
ch=`dd if=$TTY bs=1 count=1 2> /dev/null`
stty $old < $TTY
echo You pressed: $ch

This works on a normal Linux system (and if you set TTY=/dev/tty then it works on a chumby ssh session), so I'd expect it to work on /dev/tty0...