Arduino UNO Keyboard HID part 2

Part 1 covered getting the avr tools setup and building the Arduino usbserial firmware. Part 2 covers flashing the firmware to the UNO's atmega8u2 and putting together firmware for a Keyboard HID driver.

Updating the UNO's atmega8u2 USB firmware

To do this the atmega8u2 needs to be put into DFU mode. There is a description of how to do this without soldering on the Arduino forums here: msg374201. Note that you can't brick your UNO doing this, it will always support DFU mode so you can recover by flashing it with a working Arduino-usbserial.hex file.
  • Put the UNO into DFU mode.
  • dfu-prgrammer at90usb82 erase
  • dfu-programmer at90usb82 flash --debug 1 Arduino-usbserial.hex
  • dfu-programmer at90usb82 reset
  • Unplug the UNO's USB cable for a few seconds and plug it back in
  • Check that you can still upload a sketch. If you can't upload the sketch (e.g. the usb device hasn't shown up), then put the UNO back into DFU mode and repeat the above procedure using the prebuilt Arduino-usbserial-uno.hex file that is in the Arduino-usbserial directory.
Note you can also flash the firmware by running "make dfu" in the arduino-usbserial directory after you put the UNO into DFU mode.

Creating Keyboard HID firmware

This has been made extremely easy by the excellent work done by Dean Camera with his AVR USB stack LUFA and the excellent demo's he provides which are full drivers for a large collection of USB devices. And, of course, the efforts of the Arduino team and contributors that have made it such an easy platform to develop on.

I put together the Keyboard HID firmware by starting with the Arduino-usbserial source code, adding in the LUFA keyboard HID demo code, and implementing a simple serial protocol to allow communication with the keyboard firmware from the UNO's main processor.

The source code is in the following locations:
  • Arduino/hardware/arduino/firmwares/arduino-usbserial
  • LUFA 100807/Demos/Device/ClassDriver/Keyboard
I've defined a very simple serial protocol between the keyboard firmware and the UNO's main processor. The keyboard firmware expects to receive 8 bytes formatted as a Keyboard HID report. The format is as follows:

Byte Contents
0 Modifier keys:
Bit 0 - Left CTRL
Bit 1 - Left SHIFT
Bit 2 - Left ALT
Bit 3 - Left GUI
Bit 4 - Right CTRL
Bit 5 - Right SHIFT
Bit 6 - Right ALT
Bit 7 - Right GUI
1 Not used
2 - 7 HID active key usage codes. This represents up to 6 keys currently being pressed.

The Key Usage codes are documented in chapter 10 of the HID Usage Tables. The letters 'a' to 'z' are codes 4 to 29, and you can indicate upper case by setting the left SHIFT or right SHIFT bit in byte 0 of the report.

The keyboard firmware sends back 1 byte every time it receives 8 bytes. This byte represents the LED status for the keyboard: Bit 0 - NUMLOCK, Bit 1 - CAPSLOCK, Bit 2 SCROLL LOCK. Note this isn't currently working and I haven't worked out why yet. I'll update the page when its fixed.

Example code to send an 'a':

uint8_t keyNone[8] = { 0, 0, 0, 0, 0, 0, 0 };
uint8_t keyA[8] = { 0, 0, 4, 0, 0, 0, 0 };

void setup()
{
Serial.begin(9600);
delay(2000);
}

void loop()
{
uint8_t ledStatus;

/* Send an 'a' every second */
Serial.write(keyA, 8);
ledStatus = Serial.read();
delay(100); // Give the host time to read the key
Serial.write(keyNone, 8);
delay(1000);
}
There is plenty of room for improvement in the keyboard firmware. I'll work on a version that doesn't need the delay(100) to give the host time to read the key. There is some difficulty because of the size of the firmware - its 4040 bytes which is almost at the 4096 byte limit which makes it challenging to add features.

You can download the Keyboard HID firmware source here: arduino-keyboard.tar.gz and the firmware here: Arduino-keyboard.hex

Download file "arduino-keyboard.tar.gz"
Download file "Arduino-keyboard.hex"

Comments

hads@nicegear.co.nz (unauthenticated)
Mar 22, 2011

Great write up Darran, thanks for sharing.

Lizardbones (lizardbones@gmail(dot)com) (unauthenticated)
Mar 26, 2011

First - good on yer, mate! I know from my own internet searches that many people have been waiting and looking for something to turn the Uno into a pseudo keyboard without having to buy a U-HID device.

Now for the superfluous question. I really can't think of a reason why you'd need more than 6 keys pressed at a time (especially since modifier keys are handled with a separate byte), but would it be possible to maintain 2 sets of Keyboard HID reports and juggle between them to have more than 6 keys pressed at the same time?

darran
Mar 26, 2011

I don't think that will work - it would appear to the host that two separate sets of 6 keys where being pressed and released in rapid succession. It might be possible to define a larger keyboard report message that could carry more keys but I'm not sure how the host driver would react to that. Something to experiment with.

Seán (unauthenticated)
Apr 4, 2011

Superb post, massively helped with problems in my project. Just curious, what would the modifier key for the mac cmd/option key be?

darran
Apr 5, 2011

Cheers Seán, good to hear. The cmd/option key is the GUI modifier key.

Advancer (unauthenticated)
Oct 15, 2011

Hi darran,

I'm a little confused. Are we supposed to be able to upload sketches after we flash the arduino keyboard hex file? I thought we were but I've been having to flash the arduino serial usb hex, then upload a sketch then reflash the keyboard hex...

Thanks

darran
Oct 23, 2011

Hi Advancer,

yes you have to flash back the serial hex whenever you want to load a new sketch. There's not enough space in the 8u2 to combine both the HID functionality and the serial functionality into a single hex file, and the Arduino needs the serial interface to load sketches.

Cheers,
Darran.

skm (unauthenticated)
Feb 28, 2012

I'm a little confused by some of the terms used.
Is this a keyboard to be attached to an arduino Uno? to add keyboard input to the Uno?
or is this using the Uno as the controller of the keys themselves, and the usb of the Uno is then attached to a computer? I didn't see anything about the keyboard matrix...

I'm wanting to build my own keyboard from scratch and looking for code to use a Mega or Mega32 as a replacement controller inside the keyboard.

Also, some early keyboards on lisp machines had 5 modifier keys: shift, alt, control, super, hyper. How hard would it be to have 5 modifier keys? If the status of modifiers must be contained in 1 byte, could you substitute a hyper key for one of the left/right alt keys for example?

Another question: some keys on a keyboard have an auto-repeat ability, such as any alpha key. Other keys do not have an auto-repeat, such as the shift key. Other keys function as a toggle and do not have an auto-repeat, such as caps-lock. If you add new keys (say > 12 function keys) how do you setup which type key they will be? Example: some extra keys could be used to implement a programmable keyboard to record and playback macros for example.

Thanks for your help!

skm

darran
Mar 11, 2012

Hi skm,

this is firmware to turn the Uno or Mega2560 into a USB HID keyboard device, so it appears to be a keyboard when its plugged into a PC. The arduino can send keys to the PC.

If you want to create a custom keyboard with more modifiers I think that should be possible, however the driver on the PC would need to support that kind of keyboard. I'm not sure that any of the modern PCs would support them.

For auto-repeat, you just keep the key held down by keeping it in the report sent to the PC. After a period of time the PC will begin repeating the key. The shift key does not repeat since its a modifier key that does not have a key code and its state is sent in the modifier field rather than the key array.

Hope that helps.
Darran.

shadeydave (unauthenticated)
May 15, 2012

Hi darran,

This is going to be a list of painfully stupid questions, as I'm a bit of a noob.

Using an UNO:
1) Following the "put the arduino into DFU mode without soldering" instructions the "L" LED flashes briefly and that's the only indicator you have for DFU mode, correct?

2)"dfu-prgrammer at90usb82 erase" command get's sent to the arduino how? Using Mac Terminal? Using Arduino? Using MacPorts (what ever that is)? I downloaded MacPorts and can't find the application, probably because it's a terminal level application? No idea...

3) Once the USB Firmware is flashed to the arduino, can I upload the keyboard sketch to it? or should I upload the keyboard sketch first then flash the firmware?

4) Let's say I have everything set up and working properly. And I want to send a "right arrow" key to my PC. How would you put that into these terms?

"Serial.write(keyA, 8);"

I'm used to dealing in javascript or flash where your keyboard event listeners are keyCodes like SPACE=32 or key1=49 etc...
Will these key codes work, or are we stuck with the semantic "keyA, keyB, keyC, keyLeftArrow" markup?

Thanks,
Dave Noel

darran
May 21, 2012

Hi dave,

yes you will need to use the terminal application to execute the commands. Since you have already installed mac ports, you should be able to execute the following command in the terminal:
sudo port install dfu-programmer

After that you can use dfu-programmer in the terminal to load the firmware to the atmega8u2 on your UNO when its in DFU mode.

To upload a sketch you will need to put the UNO back into DFU mode and use dfu-programmer to flash back the usbserial firmware. After that you can load you sketch the usual way (you may need to unplug the UNO and plug it back in).

Regarding key codes, in the post above is this paragraph:
"The Key Usage codes are documented in chapter 10 of the HID Usage Tables. The letters 'a' to 'z' are codes 4 to 29, and you can indicate upper case by setting the left SHIFT or right SHIFT bit in byte 0 of the report."

So, download the HID Usage Table from here: http://www.usb.org/developers/devclass_docs/Hut1_11.pdf. Then you can replace the 4 in the keyA array with whatever key code you want based on the table in chapter 10 (e.g. 79 for "right arrow").

Madarian (unauthenticated)
Jul 19, 2012

Hey,
It appears to me you have a one-off error in the code above:

uint8_t keyA[8] = { 0, 0, 4, 0, 0, 0, 0 };

should be

uint8_t keyA[8] = { 0, 0, 4, 0, 0, 0, 0, 0 };

as far as I can tell.
You don't seem to have that mistake in Arduino-keyboard.c (looking at line 211)

Regards,
Madarian

Aint (unauthenticated)
Sep 25, 2012


Hi there,

Great article thanks very much for all the explanations. In response to lizard bones, you said it might be possible to define a larger keyboard message, but that it would need some experimentation.

Well I think this might be extremely helpful for the project I'm working on... I don't suppose you've tried it, or have any pointers as to where I could look to find out how?

Thanks very much

@aint

Arvin (unauthenticated)
Mar 12, 2013

Hey Darran,

I am just starting to connect a SNAP 3100i barcode scanner (http://kudoztech.com/automatic-identification/barcode-scanner/3100i-linear-imager-scanner/) to the Arduino Mega 2560.

I read that integrating a barcode scanner to the Arduino is similar to integrating a keyboard and I thus read your post.

I found your post extremely helpful. However, since I am new with the Arduino, I want to re-iterate what I think are the steps in integrating a keyboard with the Arduino Mega 2560 (with the USB Host Shield already attached).

1. Flash the Mega to update the firmware (Done)
2. Install the USB Host Shield library provided by CircuitsatHome (Done)
3. Run the program titled keyboard demo that you have written.

Does this sound alright? Is there something I am missing out?

I would greatly appreciate any feedback.

Thanks :)

leocadiotine (unauthenticated)
Apr 11, 2013

Hey, great articles! They're being extremely useful. But I have a question:

Since you're using only one byte for the modifier keys, how do you process a keystroke (like ctrl-alt-del)?

Thanks!

Juan (unauthenticated)
Apr 21, 2013

I'm with the previous guy, I want to send SHIFT + CTRL + KEY but I'm unable to do it. Is it possible to send three keys at the same time?

Arif (unauthenticated)
May 16, 2013

Hi darran,,

Its works.. great project,
but I need a "Space" button, How i can use space button?

darran
May 23, 2013

Arif, take a look at http://hunt.net.nz/users/darran/weblog/b3029/Arduino_UNO_Keyboard_HID_version_03.html and the HID Usage Table link. You can find the HID code for "keyboard spacebar" there on page 54.

Corey (unauthenticated)
Aug 20, 2013

Hi Darran,

Awesome work. Both you and Dean Camera are doing great things. I've used you keyboard hex file previously for a project where I was controlling KVM switches over a network using Arduinos that send key sequences to the KVMs through a usb keyboard interface.

Now I'm trying something a bit more difficult. I'm trying to solve a problem of multiple touch screens connected to a single computer. The idea is to create a large, multiscreen touch interface. But typically, the multiple USB inputs are not dealt with correctly by the OS. One option may be to write a new multi-touch driver, but I am trying something different.

In the final configuration, I will have 4 (or more touch screens), but for now I am just trying to get one working. The USB output of the touchscreen digitizer is connected to a raspberry pi. Using libusb, I read the HID data in the data stage of the digitizer output. Then, I send this data over ethernet to an eth shield on an arduino. On the arduino, I want it to appear as a digitizer (which is just a USB HID).

Most of this is actually working, but I am currently stuck on the firmware. I also am using the LUFA Keyboard Class Device as an example, with some changes. But currently am a bit stuck. The HID report is actually 64 bytes and not 8. The 64 bytes I want to sent to the host are definitely getting to the Arduino (have verified the data is correct), but I am having a problem getting the data to the host.

I'm not so sure the data is coming in correctly over the serial line, do you know of any way of testing whether the ISR is being called? Given that this is all happening on the atmega16u2, it seems quite hard to debug.

darran
Sep 19, 2013

hi Corey, sounds like a great project.

One thing you could do is send some debug text back from the 16u2 to the 328p (i.e. via the serial line), and then have the Arduino send that to your PC via software serial. That way you can check on what the 16u2 code is doing.

You could also flash the Rx or Tx LEDs from the 16u2 to let you know that the ISR is running.

Another option might be to get a USB debug device (maybe a bus pirate or one of the low-cost USB capture boards). Then you can check the report that the Arduino is sending and any commands coming from the PC.

John (unauthenticated)
Mar 15, 2014

Hi Darran,
I've got the arduino_uno_keyboard pass through working well now but have a problem. It doesn't work with my Apple keyboard with integrated USB hub. I suspect that it's a problem of USB address/endpoint selection, but possibly also related to high speed vs full speed. Can you provide any guidance on how I might extend the capability of your prior work to cover this? I'm tempted to modify your arduino passthrough sketch and connect it up to a Processing sketch of a GUI that would allow me to specify bus speed, address and endpoint, and then pass these parameters back to the arduino sketch. Of course - I'm talking a LONG ways over my head right now so any advice would be welcome. I'm hoping you'll know an easier way...

Nathan Reeves (unauthenticated)
Sep 14, 2014

Got it working on my Arduino UNO R3. To get the UNO R3 into DFU mode just short the top two pins on the USB chip ICSP header (the two pins nearest the usb port) I used an old hard disk drive jumper to short them out. You'll know if its in DFU mode or not if you go into 'devices & printers' and it shows the usb chip as the device (not an UNO, but an atmega16u or something to that effect, it depends on which chip your board uses for the usb functions) Hoep this helps! Check out the unojoy as well. https://code.google.com/p/unojoy/
Fun stuff.