Hardware Keyboard Remapping
Ever since using vim and vimperator, I've gotten used to mapping the Caps Lock key to act like another Left Control key. In windows I did this by setting the registry key
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout\Scancode MapTo the following binary value
00 00 00 00 00 00 00 00 02 00 00 00 1D 00 3A 00 00 00 00 00. In Arch Linux I would use this .Xmodmap file:
clear lock clear control keycode 66 = Control_L add control = Control_L Control_R.
When I switched between computers often, these configuration changes became impossible, the windows change even required me to have administrator access. This is when I had the idea for a hardware-based key remapper. A device that sits between a USB keyboard and a computer, intercepts the keystrokes, and remaps them before they even hit the computer, no more configuring every computer I work at, and I could take this device with me everywhere I go.
Well I finally got around to making it. Here are the components I used:
- Teensy 3.6
- DuinoFun mini USB Host Shield
The USB Host Shield allows the device to act as a "USB Host" just like
your computer acts as a USB host to your mouse, keyboard, and whatever other
"USB Device"s you may have.
When I started the project, I intended to use a circuits@home version of
the mini USB Host Shield, but I couldn't find a place to buy them ANYWHERE
and the original shop's site was broken.
So I had to settle with the DuinoFun version,
which I could find zero documentation for, except for a
single project
where someone else had used it.
So a week later and my chip came in from China.
I had bought a Teensy 2.0 to go along with it (Because of
PJRC's USBHS article
) Unfortunately I had completely missed the part about needing a MCP1825S-3302E/DB
to convert the Teensy 2.0 to run at 3.3V. And without quick access to one
of those, I decided to test the USBHS with an Arduino Uno I had won a few years
back.
So I wired it up to the Uno according to
Arduino's USBHS page
and the USBHS pins shown on
PJRC's USBHS article
and hoped that everything would just work.
Fired up Arduino IDE and installed the USBHostShield 2.0 library
and tried to run the included board_qc sketch meant to test
the USBHS.
Unfortunately this failed many times, it wasn't until hours later
of replugging everything in and browsing forums that it just magically
worked out of the blue. Nevertheless it is was not reproducable,
and I figured the Uno was just too old to work well with the newer hardware.
I needed a board capable of acting as a USB Device (Specifically a keyboard) to the computer. I whent back to the store and bought a Teensy 3.6 which already runs at 3.3V (as opposed to the Teensy 2.0 and Uno). Connecting the Teensy 3.6 to the USBHS according to this article worked perfectly, except that the USHS could only handle low-power USB devices, like old flash drives, but not a backlit USB keyboard. I knew that in the current configuration, the USBS could only provide 3.3V to the USB device, however, most USB devices expect 5V, therefore I needed to route the 5V from the computer going into the Teensy to the USBHS and then to the USB Device. To do this, I connected the VIN of the Teensy 3.6 to the VBUS pad on the USBHS and cut the jumper running from the VBUS pad to the USBHS as shown below.
Now, the board worked perfectly, all that was left was to code up the sketch to grab the keystrokes coming from the keyboard, possibly modify them, and send them onto the computer.
The USB Host Shield library v2.0 did not work out of the box with the Teensy 3.6, I had to modify the config files to get them to recognize it's id (and treat it therefore like a Teensy 3.0).
TODO TODO TODO TODOUSB Keyboard send their state to the USB Host as a wrapped packet containing 2 to 8 bytes.
struct MODIFIERKEYS { uint8_t bmLeftCtrl : 1; uint8_t bmLeftShift : 1; uint8_t bmLeftAlt : 1; uint8_t bmLeftGUI : 1; uint8_t bmRightCtrl : 1; uint8_t bmRightShift : 1; uint8_t bmRightAlt : 1; uint8_t bmRightGUI : 1; };The next byte is a reserved field, usually zero. The following 0 to 6 bytes (integers in 0-255) indicate which keys are being held down. Therefore all I have to do is intercept calls with a 0x14 key (Caps Lock), set bit 0 of the first byte, and remove the 0x14 key from being sent to the host. and then do similar when the key is released.
I can think of many other interesting uses for this USB keyboard passthrough device. For example:
- Switch keyboard layouts (DVORAK to QWERTY) by pressing some key combination.
- Keyboard macros which are undetectable from software. (Cheat detection systems could not detect it by scanning the system)
- Changing your typing rhythm to avoid biometric detection (see https://github.com/leoneckert/deceit-board)
- Keylogger (Add a micro SD to the Teensy 3.6
To make your own, the two boards will cost you $30 for the Teensy 3.6 and around $10 for the USBHS. However, it looks as though this could be done with a Teensy LC board (only $10) instead of the 3.6. Granted, the entire project may cost you alot more in tools (Soldering iron) and wires if you don't already have them.