Arduino USB Keyboard Passthrough

I decided to make use of the Keyboard HID driver in a proof-of-concept project. The project: connect a USB keyboard to the Arduino and have the Arduino transparently pass the key presses to the host PC. Not all that exciting, but its the first step on my actual project which is a bit of April Fools payback for a coworker.

Some brief background; two weeks ago I was happily working on my laptop at work using the USB keyboard attached to the docking station. I pulled up a form and looked at the keyboard to find the first key I wanted to press, a "n", hit it, and in the form a "m" appeared. Hmm. I deleted it and tried again hitting the "n" key - and another "m" appeared! Confused I hit the "m" key and an "n" appeared. Arg!. I compared the keyboard's "n" and "m" keys to the laptop keyboard and discovered the cause - some prankster had switched the physical "n" and "m" keys on my keyboard. I'd been touch-typing all day without noticing the switch, it was only when I looked for the key that I discovered it. It was easy to work out who the culprit was, especially after he pulled the same stunt on a few more coworkers (let's call him Tony).

How does this relate to the Arduino? Basically I thought if I could get the Keyboard HID driver working so the Arduino looked like a keyboard to the host PC, and if I could also connect a USB keyboard to the Arduino, then I could install the Arduino between my coworkers keyboard and his PC while he was at lunch and indulge in some subtle or not so subtle payback. Hopefully on April 1st. For example, I could physically swap the "n" and "m" keys on his keyboard and have the Arduino also swap the "n" and "m" keys as he types them. Then when Tony touch-types his "n" and "m" key presses will be swapped, but when he looks at the keyboard and hits the "n" and "m" the correct key press will be sent to the host PC. Or, I could have the Arduino substitute every 50th key press with a nearby key, e.g. hitting "d" sends a "f" or an "s" instead. You get the idea.

Arduino plus USB Host ShieldI purchased a USB Host shield from Sparkfun. This will provide the interface to the USB keyboard. I downloaded the library from Circuits At Home and wrote a sketch based on the examples they provide. The sketch waits for input from the keyboard and then sends it to the host via the serial port. I loaded the sketch, flashed the Keyboard HID firmware to the atmega8u2, unplugged the USB cable, plugged a USB keyboard into the USB Host Shield, and plugged the UNO back in to my PC. It works! Its as if the Arduino is not even there, the keyboard works perfectly normally, no lag, key repeats work, numlock, capslock, scroll lock, all working really well.

I did have to cheat a little and handle the keyboard LED status in the sketch rather than taking the status from the host PC. I still need to debug that feature in the Keyboard HID driver.

Here's the keyboard pass-through sketch:
Download file "kbd_usb_passthrough.pde"

You'll need to use DFU mode to flash Arduino-keyboard-0.2.hex to the UNO's atmega8u2. See my earlier posts for the hex file and steps to follow to flash it to your board.

Comments

Jim (unauthenticated)
Apr 4, 2011

You are turning out great stuff here Darren. Thanks for sharing.

darran
Apr 4, 2011

Cheers Jim, happy to share. I'm impressed with how easy it is to develop for the Arduino.

aFirmerElfLion (unauthenticated)
Jun 21, 2011

Thank you. I took your keyboard-passthrough and used it to implement xkcd's mirrorboard (http://blog.xkcd.com/2007/08/14/mirrorboard-a-one-handed-keyboard-layout-for-the-lazy).
the pde is available here:
https://github.com/aFirmerElfLion/arduino-mirrorboard

darran
Jun 23, 2011

Hi aFirmerElfLion, nice project! I'll have to try it out at work :-).

Tony! (unauthenticated)
Jul 31, 2011

Thanks, I'll try this out at work too

Avri (unauthenticated)
Aug 10, 2011

Hi Darran,

Nice work!

Is it possible to use your code for a (GPL) project I'm making - what's the license of your sketch?

Kind Regards,
Avri

darran
Aug 11, 2011

Hi Avri,

I've updated the sketch with a BSD license, hope that will be suitable.

Cheers,
Darran.

Avri (unauthenticated)
Aug 12, 2011

Hi Darran,

Thanks for that! I have uploaded my project to Google code project hosting -

http://arduino-rfid-tag-sniffer.googlecode.com/files/rfid_reader_v1.7z

Comments are much appreciated :-)

Thanks again and Kind Regards,
Avri

Joel-E-B (unauthenticated)
Aug 16, 2011

Hi Darren,

Great work. I got the pass through code working great on my Uno. I'm even typing this comment through the Arduino. I'm attempting to get this same code to work with the new HID Bluetooth device from Roving Networks, thus creating a hacked wireless keyboard. Just like the Atmega8U2 with your firmware, the Bluetooth device supports HID and shows up as a keyboard when I search for it in My Bluetooth Places. However when I try to connect to it, it generates a random number to type on the keyboard you are trying to pair to. Because the keyboard is not initialized yet, (It doesn't seem to react until the computer sees the HID i.e. the caps lock button LED won't light up until the Uno shows up in Device manager) I can't type the number to pair the keyboard with my computer. I've tried on both OSX and XP. Same results. I thought of having the Arduino spit out the numbers itself, but they change each time. Any info you can shed on this would be greatly appreciated. Thank you.

-Joel

darran
Aug 31, 2011

Hi Joel,

sorry I'm not sure what to do with the bluetooth problem. I don't have any bluetooth hardware so I can't play around with it.

With the kbd_usb_passthrough.pde sketch the keyboard should be supported pretty much as soon as the sketch starts running. Its strange that the leds are not working (e.g. capslock) as those are handled locally in the sketch and don't rely on the connection to the PC. Perhaps the UNO is not getting powered up until the bluetooth device is paired? Can you try plugging in a DC power supply to the UNO and see if the keyboard LED responds to capslock being pressed?

Darran.

Duane (unauthenticated)
Mar 4, 2012

Darran,

Great work here. Have you ever dabbled in re-mapping the keys? I have your sketch running beautifully. Now I want to go in and work on making a custom keyboard mapping.

Thoughts on how you would go about this?

Thanks,
Duane

darran
Mar 11, 2012

Hi Duane,

sure you can remap them. You just need to do the remapping as you receive them from the USB host interface. Check which key you received, choose the new key to use instead and send it in the keyboard report to the serial interface. You could use an array to lookup the key and define the new key, or you could use a switch statement to do it.

Darran.

Thoams (unauthenticated)
May 8, 2012

Wow this is perfect!
I have been using the colemak alternative keyboard layout for some time now and had an interesting idea.
The easiest way to learn coelmak is to switch the physical keys on your keyboard however if you go to someone else's computer and use their qwerty keyboard then you feel a bit left out. This would be great for building a prototype keyboard that tricks the host computer into thinking it is qwerty when the physical layout is colemak. Then i can take my colemak keyboard anywhere without having to install any drivers.
Thumbs up to you!

(unauthenticated)
May 9, 2012

Hey Thoams, yeah you'll be able to do the mapping between your keyboard and the PC. Cool project.

Chris Young (unauthenticated)
May 9, 2012

I'm trying to build an alternative input device for handicapped person. The goal is to display characters on an LCD text display. The handicapped individual would then use a few micro switches to scroll through the display and select the characters he wanted to type. Then the Arduino would send the characters as if they were typed on the keyboard. Would want to do the same thing with mouse control.

I have an Arduino UNO revision 3. My only experience with Arduino is to use the IDE to program sketches and control gadgets. I've never done any messing with the firmware and so I am a little bit reluctant to do anything like that.

If I flash the USB controller so that it can output to the PC and look like a human interface device, can I then no longer use that USB on the Arduino to download sketches into the device? I don't want to end up turning my Arduino into an unusable brick because I "reverse the polarity" so to speak of the only input output port that I have.

In your application of the keyboard pass-through, how do you download new sketches once the USB controller has been reversed?

darran
May 15, 2012

Hi Chris,

you will need to flash back the usb serial firmware in order to load a new sketch. Its the same procedure as flashing the keyboard firmware. Another option is to use an ISP to load the sketches, or a second Arduino loaded up with an ISP sketch.

moparisthebest (unauthenticated)
May 29, 2012

This is basically exactly what I've been wanting to do, as a qwerty->dvorak layout converter for a USB keyboard, which I have working with a Teensy++ for a PS/2 keyboard:
https://github.com/moparisthebest/tmk_keyboard/tree/master/ps2_usb

I have a few questions I'm hoping someone can answer though. I'd buy an arduino UNO to do this, but it says it doesn't work on windows without a special driver (INF file), is this true? The teensy++ works as a USB keyboard on every OS I've tried it on including the BIOS before the OS is even loaded. I'd have to have this do the same.

If not, can I use that USB Host Shield with a Teensy++?

Thanks for the great writeup and code example. :)

Frank Zhao (unauthenticated)
Jul 15, 2012

Make it type "Hello Tony"

Nod (unauthenticated)
Aug 18, 2012

"Hello Tony... I know it was you!!!!"

JAYTEE (unauthenticated)
Aug 30, 2012

Hi Darran,

Great post. I was specifically searching for a keyboard passthrough using an arduino on the basis that you could also output the keyboard input on the way through to an LCD shield or similar.

I write code but I am not a touch typist and constantly need to look up at what I'm typing.

I saw this today. It's a keyboard that has a scrolling display of the input as the user types.
http://www.thesmartype.com/upload/content/images//homepage1.jpg
full site here http://www.thesmartype.com/

Unfortunately there does not seem to be any Mac support for it and I figured an arduino based version may suffice.

Your thoughts on the feasibility of this project would be appreciated

Lizino (unauthenticated)
Nov 8, 2012

Hello everybody,
This is a post of great help, however, due to my inexperience I have a few questions. I have been trying to implement the code, compile it and upload it to my arduino uno. However I keep getting these errors:

kbd_usb_passthrough:51: error: 'EP_RECORD' does not name a type
kbd_usb_passthrough:66: error: 'USB' does not name a type
kbd_usb_passthrough.cpp: In function 'void loop()':
kbd_usb_passthrough:78: error: 'Usb' was not declared in this scope
kbd_usb_passthrough:80: error: 'USB_STATE_CONFIGURING' was not declared in this scope
kbd_usb_passthrough:82: error: 'USB_STATE_RUNNING' was not declared in this scope
kbd_usb_passthrough:85: error: 'USB_STATE_RUNNING' was not declared in this scope
kbd_usb_passthrough.cpp: In function 'void kbd_init()':
kbd_usb_passthrough:96: error: 'ep_record' was not declared in this scope
kbd_usb_passthrough:96: error: 'Usb' was not declared in this scope
kbd_usb_passthrough.cpp: In function 'void kbd_poll()':
kbd_usb_passthrough:124: error: 'Usb' was not declared in this scope

This seems strange since nobody else has mentioned them and I looked in a couple of forums for this type of error
(http://www.cpp-home.com/forum/viewtopic.php?f=4&t=16517&sid=b1e5287ef4a5f792a8b32653929a185c#p126280) (http://stackoverflow.com/questions/252780/why-should-we-typedef-a-struct-so-often-in-c)
and it seems the types it says it does not name are named.

I would be really grateful for any suggestions. :)
I had a couple more errors which I eliminated by including the constant library for the max3421e

Lizino (unauthenticated)
Nov 12, 2012

Real newbie error, I was including some of the libraries but there were some missing and was an letter that was not in caps lock. I hope this helps other people..

darran
Nov 14, 2012

Hey Lizino, no worries we all do it. Great that it's working for you.

LOL (unauthenticated)
Dec 12, 2012

hahaha, nice post, I will put a LDR (light sensor) make it auto typing "hi tony".... "I love you"...."I am the ghost in your PC"..."wuuuu....wuuu....." when he turn off the light...

Arvin (unauthenticated)
Mar 12, 2013

Hey Darran,

I am referring to Lizino's comment here.

Lizino mentioned that he added more libraries to the code.

I currently have the following added but still have exactly the same errors as Lizino. Which are the other libraries I should add?

#include <Spi.h>
#include <ax3421e.h>
#include <Usb.h>

Arvin (unauthenticated)
Mar 12, 2013

Just to be clear, following are the errors that I am facing. Really noob errors but I hope someone can help me.

kbd_usb_passthrough:51: error: 'EP_RECORD' does not name a type
kbd_usb_passthrough:65: error: 'MAX3421E' does not name a type
kbd_usb_passthrough:66: error: 'USB' does not name a type
kbd_usb_passthrough.pde: In function 'void setup()':
kbd_usb_passthrough:71: error: 'Max' was not declared in this scope
kbd_usb_passthrough.pde: In function 'void loop()':
kbd_usb_passthrough:77: error: 'Max' was not declared in this scope
kbd_usb_passthrough:78: error: 'Usb' was not declared in this scope
kbd_usb_passthrough:80: error: 'USB_STATE_CONFIGURING' was not declared in this scope
kbd_usb_passthrough:82: error: 'USB_STATE_RUNNING' was not declared in this scope
kbd_usb_passthrough:85: error: 'USB_STATE_RUNNING' was not declared in this scope
kbd_usb_passthrough.pde: In function 'void kbd_init()':
kbd_usb_passthrough:96: error: 'ep_record' was not declared in this scope
kbd_usb_passthrough:96: error: 'Usb' was not declared in this scope
kbd_usb_passthrough:99: error: 'bmSNDTOG0' was not declared in this scope
kbd_usb_passthrough:100: error: 'bmRCVTOG0' was not declared in this scope
kbd_usb_passthrough.pde: In function 'void kbd_poll()':
kbd_usb_passthrough:124: error: 'Usb' was not declared in this scope

Ben (unauthenticated)
Mar 14, 2013

can you send a long key press? such as press and hold the home key will actually active google search app in android ?

Raven (unauthenticated)
Mar 30, 2013

Hey Darran,

This is awesome stuff!

I am almost done with the keyboard portion. Just stuck at one last portion.

Once I flash the keyboard hex onto my board, it is recognized on my Device Manager as a Keyboard (not an arduino).

I thus cannot use the Serial Monitor on the arduino IDE to observe the output. How do I access the serial output?

(unauthenticated)
Apr 21, 2013

Hi Raven,

to access serial output, you can use two digital pins with the softwareserial library and a serial to USB convertor.

Rafael Q. (unauthenticated)
Dec 16, 2013

Hi, Darran:
I´ve invented an stenographic/orthographic theory for the Noppoo Choc mini 84 keyboard. It´s completely an orthographic system not like the usual that´s phonetic. See my theory in Plover Google Groups and tell me if you can addapt that keyboard to my theory with the Arduino. I hope so. Your contribution in the Plover Google group (+ 275 members) can be very interesting for all of us.

https://groups.google.com/forum/#!topic/ploversteno/keA3dUOwMYQ

I introduce you my orthographic theory Mecatipia based on the Noppoo Choc keyboard. There is no briefs, neither dictionary, nor CAT program, nor learning. Just practice until the desired speed:

1.- Beginner. +/- 100 wpm for using it as a typing keyboard.
2.- Intermediate. +/- 140 for general amateur purposes.
3.- Advanced. +140 - 200 wpm for stenographic and professional uses only.

By now, it has to be adapted to the Noppoo Choc keyboard but I hope Plover gets this in a short time.

The layout of my system is optimized for Spanish but it can be adapted to other orthographic and semi-orthographic languages. A Plover group member, Steven Bhardwaj, says:

Thanks much Rafael for sharing, and Paulo for engaging as well!
I am a beginner to Plover/Steno, but have ambitions to use it for simultaneous interpretation/transcription.

I am interested in the concept of exclusively- and/or primarily-phonemic Steno theories that can be quickly applied to new languages. Rafael's system could be studied and the basic ideas extended to many more languages via a common Plover platform.

It seems that a list of phonemic language scripts may include:
Indonesian/Malay, Spanish, German, Polish, Swahili, Sanskrit, Turkish, Slovak, Finnish, Hungarian, Hawaiian, Georgian, Tagalog, Latin, Croatian, Hindi...

The threads are ambivalent on the status of Arabic, but I am studying Arabic now and I think that it would work as well, as it is many vowellings to one spelling, not many spellings to one pronunciation. If Arabic works, then Hebrew will likely work as well.

In fact, if Mecatipia-Plover were working in this manner, I might even prioritize learning that theory over learning Plover for my native English!