Input Device Routing

Lots of different (USB) devices come up as HID devices in Linux.  That is, they appear to the system as if they are keybords and mice.  You plug them in, and X deals with them the normal way.

When they output stuff, X will receive the events and characters will appear in whatever program has the focus.

But what if you don’t want that?  If you have a barcode scanner, you probably want the output from that device to go to one specific program, and not to whatever has the focus.  First setting focus on the barcode program and then scanning sounds just ridonculous.

Unfortunately, it seems like this isn’t trivial to do.  Unless something has changed lately, or my bing-fu is bad, there still doesn’t seem to be a simple “point-the-output-from-this-device-to-this-program”.

So here’s a long-winded detailed howto for doing this under Debian Squeeze, but I think it should work under any Linux version.

First of all, X will read all the HID devices under /dev/input/event* only.  (The details are in
/usr/share/X11/xorg.conf.d/10-evdev.conf.)  So if you make your device show up under a different name, X won’t know about it.

Doing device name trickery is what we have udev for.

In the following example, I’m using a wireless keypad device from Ortek.

Create a file called something like /etc/udev/rules.d/95-keyboard.rules with the following content:

# Ortek RF keypad
KERNEL==”event*”, ATTRS{idVendor}==”05a4″, ATTRS{idProduct}==”3270″, MODE=”0644″, NAME=”input/ortek%n”

This tells udev that if we plug in a device that would have been called “event*”, with that vendor/id pair, then call it “input/ortek*” instead.

You find the vendor/id pair by using lsusb:

stories:~# lsusb | grep -i Ortek
Bus 001 Device 051: ID 05a4:3270 Ortek Technology, Inc.

udev will complain bitterly:

Jan 12 12:58:27 stories udevd-work[16145]: kernel-provided name ‘input/event8’ and NAME= ‘input/ortek8’ disagree, please use SYMLINK+= or change the kernel to provide the proper name

Yeah, what are you gonna do about it, udev?  Start crying?  Go ahead.

stories:~# ls -l /dev/input/ortek*
crw-r–r– 1 root root 13, 71 Jan 12 12:58 /dev/input/ortek7
crw-r–r– 1 root root 13, 72 Jan 12 12:58 /dev/input/ortek8

See?  It works.

Now we have an input device that X doesn’t know about, so we can snoop its output without the data appearing spuriously in whatever window is active.

For snooping we use evrouter.  In debug mode it will tell us what the events we get are:

stories:~# /home/larsi/bin/evrouter-64 -d /dev/input/ortek*
device  0: /dev/input/ortek7:   RF USB Device
device  1: /dev/input/ortek8:   RF USB Device
”  RF USB Device” “/dev/input/ortek7” none key/55 “fill this in!”
”  RF USB Device” “/dev/input/ortek7” none key/98 “fill this in!”
”  RF USB Device” “/dev/input/ortek7” none key/28 “fill this in!”

So we need to create an evrouter.rc file that maps the events to whatever we want to have happen.

This is the file that maps all the keypad keys on the Ortek device:

“.*” “/dev/input/ortek.*” none key/15 “Shell/getchar TAB”
“.*” “/dev/input/ortek.*” none key/98 “Shell/getchar /”
“.*” “/dev/input/ortek.*” none key/55 “Shell/getchar *”
“.*” “/dev/input/ortek.*” none key/14 “Shell/getchar BACK”

“.*” “/dev/input/ortek.*” none key/71 “Shell/getchar 7”
“.*” “/dev/input/ortek.*” none key/72 “Shell/getchar 8”
“.*” “/dev/input/ortek.*” none key/73 “Shell/getchar 9”
“.*” “/dev/input/ortek.*” none key/74 “Shell/getchar -“

“.*” “/dev/input/ortek.*” none key/75 “Shell/getchar 4”
“.*” “/dev/input/ortek.*” none key/76 “Shell/getchar 5”
“.*” “/dev/input/ortek.*” none key/77 “Shell/getchar 6”
“.*” “/dev/input/ortek.*” none key/78 “Shell/getchar +”

“.*” “/dev/input/ortek.*” none key/79 “Shell/getchar 1”
“.*” “/dev/input/ortek.*” none key/80 “Shell/getchar 2”
“.*” “/dev/input/ortek.*” none key/81 “Shell/getchar 3”
“.*” “/dev/input/ortek.*” none key/28 “Shell/getchar ENTER”

“.*” “/dev/input/ortek.*” none key/82 “Shell/getchar 0”
“.*” “/dev/input/ortek.*” none key/83 “Shell/getchar .”

You can, of course, do anything with these events.  For this particular use case, though, I want to collect a single line, and then act upon it when I hit the ENTER key.  So I’ve written a tiny program called getchar that collects keys, and then acts upon the string when it gets ENTER.

So start evrouter:

evrouter -c ~/.evrouter-keypad.rc /dev/input/ortek*

And there you are.  Couldn’t be…  er…  perhaps it could be simpler.

Perhaps evrouter should be extended to allow storing longer strings, and then executing stuff based on the string contents and stuff.  That’s for another day, I guess.

Or perhaps someone should just put support for stuff like this into … something.  X?  Or the window manager(s)?  Or both?  Anyway, that would be nicer.

Has anybody made something like that?

Leave a Reply