USB Clickity Clack

If you read this space regularly, you know I’ve been on a mission lately to build up some simple tools to work with USB on embedded systems. This week, I got some motivation from an unexpected source: a keyboard made for gaming enthusiasts.

I don’t think of myself as especially old fashioned. However, I do have affection for several old technologies (after all, I do collect slide rules). One of the things I really love is the old-style “clickity clack” mechanical computer keyboards. I don’t know if it is the placebo effect or not, but my typing speed goes up by about 20% when I have a mechanical keyboard.

The problem is, the world has changed since these keyboards had their hay day. The two mechanical keyboards I own are getting pretty shabby. Even when you clean them up, they need an adapter to hook into a PS/2 port (they use the big old-style keyboard connectors) and they don’t have things like Windows keys and media control keys.

I wind up swapping every few months. I get frustrated with the big heavy old keyboard, switch it for something new, and then get sick of that in (usually) a few weeks and switch back. You can buy mechanical keyboards still, but they are typically expensive and I haven’t really found one I liked well enough to make me blow that much money.

The other day, however, I was in the local computer store and saw a RAZER Blackwidow keyboard. It had a great mechanical feel to it and was about US$80. The only downside is it was billed as a “gamer keyboard” so the style of it isn’t going to fit into a Wall Street office. Still, for a gamer keyboard it isn’t too loud and I thought it would work fine in my office at home.

When I got it home I still appreciated the feel, but I had forgot one little detail. All the keyboard’s special keys relied on the Windows software supplied with the keyboard. I don’t use Windows, so naturally I was a little miffed, if not surprised.

On the other hand, a keyboard is just a USB human interface device (HID) and I have been worrying with USB interfaces lately. So it turned into a project. Naturally, there aren’t any specs for the keyboard that I could find at that level of detail. However, a quick search turned up someone who had reverse engineered what the Windows software sends to the keyboard to enable the keys and wrote a program to turn it on.

Problem solved, right? Well, sort of. First, the program was in Haskell. I write in a lot of different languages, but Haskell isn’t one of them. Second, I really wanted to look at the host side of USB programming and this was as good of an excuse as any.

When you build up a USB device, you need to have some software on the host computer to interact with it. In the last few weeks, I’ve talked about using USB to RS232 chips, in which case you just treat the thing like a plain old serial port. At the other extreme would be a completely custom USB device with your own drivers for whatever operating systems you wanted to support.

There is, however, a middle ground. The USB standard defines several types of devices with preset behaviors. This is why you can plug in a USB mouse or keyboard or camera or disk drive and expect it to work with no real effort. While any of these could be useful, many embedded systems (at least the ones where you might have used a serial port in the past) can use the USB HID (Human Interface Device) drivers. Normally, a HID is a mouse or a keyboard (or a VR glove, or a graphics tablet, or something similar). However, there’s no reason you can’t define a HID device that accepts and produces data – not all HID devices really talk to a human. Your program can use the HID drivers to query and command the remote system.

In this case, the embedded system of interest isn’t one I designed, it is the microcontroller inside the Blackwidow keyboard. All USB devices have a vendor ID and a product ID. They can also have a serial number. These three things uniquely identify a device on the bus. On Linux, the lsusb command will show you data about all connected devices. Here’s the output from my keyboard:

Bus 001 Device 032: ID 1532:010e Razer USA, Ltd