How cool would it be if you could turn any button, joystick, sensor or other electronic gizmo into a USB keyboard and/or mouse? You could make just about any input device you want into a controller for your computer programs or games. What if you could do it with one line of code, inside the comfy confines of Arduino? Interested? Well, say hello to my micro friend: the SparkFun Pro Micro!
The Pro Micro is a tiny, Arduino-compatible microcontroller centered around an ATmega32U4 - an 8-bit AVR very similar to the ATmega328 with one huge caveat: The 32U4 comes equipped with a full-speed USB transceiver. So now, when you connect the Arduino to your computer, they're connected directly over the USB bus (excuse my RAS). The Pro Micro can be programmed to emulate any USB device you could imagine. You can even program it to act just like a mouse, keyboard or other HID-class USB device.
What is HID you might ask? It's one of the many defined USB device classes. Every USB device is assigned a device class, which defines what exactly its general purpose is. There are loads of classes -- printers, hubs, speakers and webcams to mention a few -- but this tutorial is going to specialize in HID: Human Interface Device. You might be holding an HID device in one hand right now, while your other hand is hovering over another.
So the ATmega32U4 takes care of the USB-hardware hurdle, but we've still got to clear the firmware one. Fortunately for us, Arduino exists, and with the release of 1.0 it comes with built-in support for the ATmega32U4 and its USB core. That USB support includes HID functionality. Unfortunately, that HID stuff is somewhat tucked (or even locked) away from us. The goal of this tutorial is to explain how to use the Arduino HID library, so you can get the most out of your Pro Micro. So lets pop the hood!
I stress "simple" at the header of this section, because that's what it is. And that's a great thing! There are essentially two functions you'll need to turn your Pro Micro into a USB keyboard:
Keyboard.write(char)- This function will send a single character over USB. The character passed can be any standard, printable, ASCII-defined character: 0-9, a-z, A-Z, space, symbols, etc. Here's an example line of code:
Keyboard.write('z')- This will send a single 'z' character to your computer. Note those are single-quotes around the character. You could also replace 'z' with a pre-defined char variable.
Keyboard.print(string)- If you need to perform a series a Keyboard.write()'s, consider using just a single Keyboard.print(). This works similar to Serial.print() – give it a string of characters and it'll send that stream of characters over USB. An example of that:
Keyboard.print("Hello, world");- The "Hello, world" of the Arduino HID class. This'll send your computer an 'H,' followed by 'e,' followed by an 'l,' followed by … you get the picture. You could also replace the "Hello, world" with either a String variable, or an array of chars.
Keyboard.println(string)- Just like Keyboard.print() except this adds an [Enter] key to the end of the string.
Keyboard.release(byte). They do exactly what you'd expect. One presses a button down, the other releases a button. Make sure you release any buttons you press, otherwise you'll encounter some wiggyness on your computer.
That's it. You don't need to include any libraries or anything, just pull out any of those functions.
After a Keyboard.write() or Keyboard.print() function has been performed by the Pro Micro, your computer will have to decide what to do with it. What your computer does with that character, or string of characters, is entirely dependent on what program it's running at the time. If you have a text editor open and active, it'll print it out there.
The most straightforward example I can think of is tying a single button to a single key-press. Give this example a quick try (copy/paste from below, or download the sketch here). If you have a button handy, tie one end to pin 9, and the other to ground. Or, if you don't have a button, just use a wire to short pin 9 to ground.
When pin 9 is grounded, your computer should receive a 'z' character. When you do activate the keypress, make sure you have an application open that will be able to do something with a 'z'. If you want, just leave the Arduino sketch active, and it should type a 'z' into the sketch editor.
I'd also like to point out that the delay(1000) is an important part of that sketch. The 1000 is arbitrary, but the delay() is not. Try taking the delay out, and your computer will try to catch some z's (zzzzzzzzzzz). Needless to say, you've got to watch out what you're sending to the computer, as well as how fast and how often.
When I'm using my laptop, I often find myself lamenting the absence of a keypad. But with the Pro Micro, I could make a keypad!
If you pair the Pro Micro with our 12-Button Keypad, you're just a few wires away from your very own DIY USB keypad. Here's an example schematic for my DIY USB Keypad.
Feel free to connect any of the keypad pins to any digital pin of the Pro Micro. That was the easiest way for me to wire it all on a breadboard.
Load up this keypadHID code (copy paste from below, or click here to download it):
Now just open up your computer's calculator and start adding. The * button is configured as the '+' sign, and the # button is configured as the [Enter] key.
There are three functions at work here. The getKeypadStatus() function reads each button of the keypad and returns an int. Only 12-bits of the value returned by getKeypadStatus() are used, each representing the status of each key – 1 for pressed, 0 for not pressed.
The sendKeyPress(int) function is where the HID magic happens. It'll interpret the value returned by getKeypadStatus() and send a keystroke to the computer based upon that value.
In the loop() we continuously check for a keypress. If a keypress is detected, we send the corresponding character to the computer. There is a bit of funkiness in the loop(), as we're trying to emulate a repeat delay, and then a repeat rate. The repeat delay is that short, one-time delay where the key must be held down before it starts repeating endlessly. The repeat rate is a short delay (50ms) to slow the spamming of characters.
Want to get some use out of Keyboard.print()? Try replacing Keyboard.write('1') in the above example with Keyboard.println("Password1234"). Now, when I press 1 on the keypad, it prints out "Password1234 [ENTER]", and I can log into my computer after pressing just one button! If you're as bad at remembering passwords as me (especially when you're forced to change it every few months *eyes SparkFun IT*), perhaps you might benefit from this password-typer. It's not all that secure, but it's probably more safe than writing it down on a slip of paper that you hide under your keyboard. Don't look under my keyboard.
That covers about half of USB HID library, how about we add a mouse to the mix now? Implementing a USB HID mouse requires a few more functions, but it's still crazy simple. There are five functions provided by Arduino's HID class that can be used to implement a mouse:
Ever want to control your computer's cursor with a joystick? Well, you may not want to after this example (it's not exactly precise), but at least it'll show you how to use the Mouse class. For those playing along, I'm using our Thumb Joystick, planted into its breakout, and connected to the Pro Micro.
The joystick is powered by the Pro Micro's VCC and GND pins. The horizontal analog output is connected to A0, vertical to A1, and the select switch is connected to D9. As always, feel free to hook it up however you want, just make sure to change the pin definitions near the top of the code.
Here's the code:
The loop() of this code continuously monitors the horizontal and vertical analog values of the joystick, and sends the Mouse.move() command based on what it reads. It'll move the mouse in steps, depending on what the sensitivity variable is set to. With sensitivity set to 2, the cursor will move in either 1 or 2 pixel steps.
It's important to note that the variables used by Mouse.move() - vertValue and horzValue - can be either negative or positive; their sign determines whether the mouse moves up/down or left/right.
The select switch on the joystick is used to control the mouse left click. Notice this code is using Mouse.press() and Mouse.release(), rather than just calling a single Mouse.click(). This requires a bit more coding, but it allows you to do things like drag-and-drop, double click, etc.
Note (June 26, 2012): With the officical release of Leonardo in Arduino 1.0.1, a lot has changed for the better in the core USB and HID files. You can now send keyboard modifiers and non-ASCII characters using the Keyboard Write, Press, and Release member functions detailed in Part 1 above. The following defines were added to Arduino:
So, if you wanted to be evil and send ALT+F4, you could write something like:
Remember that write sends both a press and release. If you use just the press function, make sure you release the button shortly afterwards (unless evil really is your goal).
And it's become that easy! If you haven't upgraded to Arduino 1.0 yet, the below information will still apply. So, I'll keep it as is for now.
End Note (June 26, 2012)
So, that's the sum of what's provided for in the Arduino 1.0 HID library. Enough to emulate just about every mouse and keyboard action there is. However, if you're like me, you may be left wanting a little bit more. For instance, what if you want to send non-ASCII-standard keys to your computer, like the function keys, arrow keys, or even modifiers like CTRL, ALT and SHIFT? The HID library doesn't really support those by default, but we can fix that...
I'll preface this section by saying we're going to be doing a little code hacking within Arduino's core libraries. It's nothing that should cause any problems to your Arduino install -- really just one very minor change -- but you will need to be careful about how you use the code in this section.
Using a programming text editor, you'll need to open up USBAPI.h, in the hardware\arduino\cores\arduino directory of your Arduino install. Any text editor will do, but it's best to use a code editor (Notepad++ or Programmer's Notepad are good ones).
The Keyboard class definition starts at line 96, and should look like this:
To send special characters and modifiers, we need to use the void sendReport(KeyReport) member function. Unfortunately, that function is currently listed under the private: label, which means we can't access it in our Arduino sketch. To make it usable, though, all you need to do is move it under the public: label. So, cut the entire void sendReport(keyReport* keys) line and paste it just under the public: line. In the end your Keyboard class prototype should look something like this:
Remember to save the header file, and close it. That's all the code hacking you have to do!
To use Keyboard.sendReport() you'll need to give it a KeyReport, which is a data structure (here's a good read for those unfamiliar) defined in USBAPI.h. Here's how it's defined:
A KeyReport contains information like what keys are pressed, and if there are any keys (SHIFT, CTRL, ALT, GUI) modifying it. Each KeyReport has three member variables: keys, modifiers, and reserved. We won't make any use of reserved, but the other two are important.
The keys array can store up to six key presses at any one time. For the most part the first value of the array, keys, is all you need. The actual value assigned to this variable is not ASCII though, it's is an HID usage ID. The USB standard assigns specific IDs for each and every button on a keyboard; they're all listed in this official HID Usage Table document (the table starts on page 53). Click the image below to see a HUGE listing of all the defined HID Keyboard Usages (your browser should allow you to zoom in on the image):
Basically, what this all means is you can't set keys to the character 'A,' because the ASCII value of 'A' (0x41) is not the same as the usage value of 'A' (0x04).
The modifiers variable controls which, if any, modifiers are acting on a key press. You can set modifiers equal to any of the following macros:
You can also OR (|) any of those macros together to specify multiple modifiers at the same time.
Once we have all the values we need set up in a keyReport, we can finally send it over to the sendReport(keyReport) function, which will report all keys and modifiers to the computer.
Clear as mud? Let's just jump into the code.
This example uses the hardware setup in the very first bit of code -- a single button attached to pin 9.
This time, I've added a new function -- sendKey(byte key, byte modifiers) -- which can be passed to both a key (an HID usage ID) and modifiers. It'll take care of setting up the KeyReport variable, and sending all the necessary reports.
It shouldn't take much to guess what's being passed to the sendKey() function in that example. It's the three-finger salute, CTRL+ALT+DEL. Windows users should be familiar with CTRL+ALT+DEL; for them, grounding pin 9 should either call the task manager, or open the Windows Security dialog.
Mac/Linux people, I'm not sure if that'll do anything for you. If you'd rather not have a CTRL+ALT+DEL key, you can replace the modifier parameters with KEY_MODIFIER_LEFT_CTRL (or KEY_MODIFIER_LEFT_GUI for Macs), and the key value with 0x06 (the [C] key usage id). Now you've got a button devoted to copying, and it shouldn't take much more to add a paste key.
Look closely at the sendKey() function. Notice that we have to send two different HID reports. The first report sends our key, and any modifiers that may be included. The second report sends a completely blanked out KeyReport, which is necessary to tell the computer that the key has been released. This is probably why Arduino kept sendReport() as a private function, it's got a lot of mess-making potential if used incorrectly. Be careful!
You'll notice that KEY_DELETE is defined as 0x4C, which matches the "Usage ID (Hex)" value of "Keyboard Delete Forward" in that HID Usage Table document I linked above. Use that as an example for any other keys you'd like to use. There's some intriguing keys defined in there...F24 (0x73)? Who knew it went that high? Volume Up/Volume Down (0x80, 0x81)? Media player controller? RightArrow, LeftArrow, DownArrow, and UpArrow (0x4F-0x52) could be very useful!
If you want to spend a bit less time digging through that table, feel free to adapt this example code, which also includes a header file (HID_Keyboard_Advanced.h) with all of the usage ID's defined.
You can now create any type of USB input device you could ever dream of. Want to use an old arcade joystick as you play an online arcade game? Make one! Here's some code to get you started. You can use the joystick hardware setup from the mouse example above. That code will use the advanced keystrokes, replacing mouse control with up, down, left and right arrow keystrokes.
Well, that was a long-winded tutorial, but this subject has me really excited; I can't help but talk about it! I think the simplicity of Arduino's HID classes opens up an immense world of physical computing possibilities. I'm excited to see what kind of crazy USB devices you all come up with.
I hope this tutorial has you as excited about Arduino USB HID stuff as me. If you've got any questions, or need something clarified, please post in the comments below.
Thanks for taking the time to check this tutorial out!