Books, Emacs, and ISBN APIs

I have the worst memory.

But even so, I pretty much manage to remember what books I’ve read.  If I’ve read Anagrams by Lorrie Moore, I remember that.

The problem is with the less (how to put it?) good books.

I read a lot of crap.  Crap that I like, but it’s crap.  Book after book of entertaining, but not really essential books.

For instance, I’m now reading No Cooperation from the Cat by Marian Babson.  It’s amusing, quite decently written and is a pleasant read.  It’s ostensibly a mystery novel, but people mainly stand around talking wittily to each other while they cuddle cats.  And then somebody’s going to die or something, I’m guessing.  The suspense!
She has previously written books like The Company of Cats, To Catch a Cat, The Cat Next Door and Even Yuppies Die.

I have absolutely no idea whether I’ve read those books or not, but if I haven’t, I want to.  And there’s the problem.

My books are kinda organised on the shelves, so I can pretty much find any book if I look at four separate locations where a book is likely to be.  Unless I’ve recently read it.  Then there’s no hope, because it’ll be in the “just-read” stacks.

So I thought: Perhaps I should just enter all the Marian Babson books into a database of sorts, and then just buy all the ones I haven’t read in one fell swoop.  I like fell swoops.

And then I thought that that sounded kinda boring, so perhaps it would be an idea to have a bar-code scanner, and enter the ISBNs that way.

But then I needed to look up the ISBNs via some API, so that I could see that the book is look-up-able.

Strapped-on Keypad

And then I thought that I might as well just scan all the books.  But then I needed to have a routine going where I would scan newly bought books to.

You can see where this is going.

I wrote an Emacs ISBN interface and book database thingie: Bookiez, and a bought a wireless barcode scanner, so that I don’t have to bring the books to the computer to enter them into the database.

I also set up the computer so that the data from the scanner goes directly to Emacs so that I don’t have to futz around.  I can just grab the scanner, point it at a book, and then it’s registered, without me having to start the right program or put focus into the correct window.

The Cyborg

Bookiez looks up the ISBNs via the APIs from Google Books, OpenLibrary, ISBNDB and LibraryThing.  (Phew.)  They all seem to have vaguely differing ISBN coverage, and the data quality is also…  varying.

Anyway, after scanning about a K of books, I’m really impressed with the Datalogic Gryphon D120 Barcode Scanner (aka. Datalogic Quickscan M2130).

The wireless range is fantastic (more than 20 meters), and the user interface is perfect.  When I scan something successfully, it beeps immediately, and when it transmits to the base station, it beeps, too.  So there’s never any doubt whether the scan was successful or not.  It does require you to hold it in a certain angle when scanning, but overall I think it’s a great device.  Nine thumbs up!

Not all books have ISBN barcodes, so I have to enter those by hand.  So I gaffa-taped a wireless keypad to my right thigh.  I can enter numpad stuff by touch-typing, and it makes a fashion-forward statement, as you can see.

The main annoyance when scanning is really the network latency when looking up the ISBN codes.  I’m looking at you, OpenLibrary.  But I’ve scanned half my books in a handful of hours, so it’s not too bad.

So now I can order some more Marion Babson books.  I don’t think I over-engineered this one at all.

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?

Slightly More Useful Fluttering

Some weeks back I wondered whether I could use Youtube as a screen saver.  It turned out that I could.

That wasn’t, strictly speaking, very useful, but now I had a small USB monitor sitting in the hall, so I might as well make it display something practical in addition to the music videos.

Hence: flit.

Currently it checks what temperature it’s outside my bedroom window and displays that at the top right there.  (Yes!  It’s that warm here in Oslo now!)

And then it downloads the weather forecast from, picks out the precipitation data for the next 24 hours, and plots that as a line at the bottom.

Somewhat cryptic, but that’s part of the fun.

Technologies used: LaTeX to render the temperature data, gnuplot to render the precipitation line, and qiv to display the image with a transparent background on top of the mplayer window.  As one does.

Conspicuous Youtube Consumption

Stina Nordenstam rockin’ in the USB

I’ve been sleeping in even odder patterns than usual lately (I suspect that I’m coming down with microencephaly, SAD and “the hypo”), so I found myself staring at the stereo computer thinking that there should be movement.

I normally hate computer screens that have pulsing lights and stuff, but I wondered how much work it would be to automatically download music videos from Youtube for whatever was playing, and then just show the video.  The sound wouldn’t be synced up, of course, but it’d be a kinda… like…  spastic screen saver.

A screen saver that doesn’t save the screen or the CPU or the network or on electricity, and would probably get me banned from Youtube.

So I started typing, and here it is.

I had a spare USB-powered little screen, so I put the stuff on a small screen instead of using a big one.  I mean, that would be too fluttery.

It’s been in production for all of fifteen minutes now, so I have no idea whether I’m going to pull the plug on the “project” (and the USB monitor) or not.  I’m guessing I probably will.