Turn Your Raspberry Pi Zero into a USB Keyboard (HID)

In this project you’ll learn how to turn a Raspberry Pi Zero board into a USB keyboard or HID (Human Interface Device). After following some simple steps, you can write a Python script to make your Pi act as a USB keyboard.

First, watch the video demonstration

Prerequisites:

If you like home automation and you want to learn more about Node-RED, Raspberry Pi, ESP8266 and Arduino. I recommend that you download my course: Build a Home Automation System for $100.

Parts Required

For this project you’ll need a Raspberry Pi Zero board. Important: this tutorial doesn’t work with a Raspberry Pi 3 board.

1. Enabling Modules and Drivers

These next steps to prepare the Pi Zero board are based on the instructions from iSticktoit. First, you need to run these three commands to enable the necessary modules and drivers:

pi@raspberrypi:~ $ echo "dtoverlay=dwc2" | sudo tee -a /boot/config.txt
pi@raspberrypi:~ $ echo "dwc2" | sudo tee -a /etc/modules
pi@raspberrypi:~ $ sudo echo "libcomposite" | sudo tee -a /etc/modules

2. Configuring the Gadget

Now, you have to define your Pi Zero (HID gadget) as a USB keyboard. The configuration is done via ConfigFS, a virtual file system located in /sys/.

Learn Raspberry Pi, ESP8266, Arduino and Node-RED. This is a a step-by-step course to get you building a real world home automation system using open-source tools DOWNLOAD »

Learn Raspberry Pi, ESP8266, Arduino and Node-RED. This is a a step-by-step course to get you building a real world home automation system using open-source tools DOWNLOAD »

Creating the config script

The configuration is volatile, so it must run on each startup. Create a new file called isticktoit_usb in /usr/bin/ and make it executable:

pi@raspberrypi:~ $ sudo touch /usr/bin/isticktoit_usb
pi@raspberrypi:~ $ sudo chmod +x /usr/bin/isticktoit_usb

Then, you need to run this script automatically at startup. Open /etc/rc.local with this command:

pi@raspberrypi:~ $ sudo nano /etc/rc.local

Add the following before the line containing exit 0:

/usr/bin/isticktoit_usb # libcomposite configuration

Here’s how your file should look like (to save the file, press Ctrl+X followed by Y and Enter):

3. Creating the gadget

For this project, we will turn the Raspberry Pi into a USB keyboard, but you could make it work as a Serial adapter, Ethernet adapter, and Mass Storage. Open the file with:

pi@raspberrypi:~ $ sudo nano /usr/bin/isticktoit_usb

Leave the default values, but you could even change the serial number, manufacturer and product name to fit your specific needs.

#!/bin/bash
cd /sys/kernel/config/usb_gadget/
mkdir -p isticktoit
cd isticktoit
echo 0x1d6b > idVendor # Linux Foundation
echo 0x0104 > idProduct # Multifunction Composite Gadget
echo 0x0100 > bcdDevice # v1.0.0
echo 0x0200 > bcdUSB # USB2
mkdir -p strings/0x409
echo "fedcba9876543210" > strings/0x409/serialnumber
echo "Tobias Girstmair" > strings/0x409/manufacturer
echo "iSticktoit.net USB Device" > strings/0x409/product
mkdir -p configs/c.1/strings/0x409
echo "Config 1: ECM network" > configs/c.1/strings/0x409/configuration
echo 250 > configs/c.1/MaxPower

# Add functions here
mkdir -p functions/hid.usb0
echo 1 > functions/hid.usb0/protocol
echo 1 > functions/hid.usb0/subclass
echo 8 > functions/hid.usb0/report_length
echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > functions/hid.usb0/report_desc
ln -s functions/hid.usb0 configs/c.1/
# End functions

ls /sys/class/udc > UDC

Here’s how your file should look like in the end (to save the file, press Ctrl+X followed by Y and Enter):

4. Python Script

After preparing your Raspberry Pi Zero, connect it to a laptop or desktop computer through the micro USB port that is used for data and peripherals. That micro USB will both power the Pi Zero and act as a keyboard to the connected computer.

Download our Free eBooks and Resources

Establish an SSH connection with your Pi and use the next command to create a new Python script:

pi@raspberrypi:~ $ nano RPi_Keyboard_Example.py

Copy and paste the next Python script to your Raspberry Pi.

#!/usr/bin/env python3
NULL_CHAR = chr(0)

def write_report(report):
    with open('/dev/hidg0', 'rb+') as fd:
        fd.write(report.encode())

# Press a
write_report(NULL_CHAR*2+chr(4)+NULL_CHAR*5)
# Release keys
write_report(NULL_CHAR*8)
# Press SHIFT + a = A
write_report(chr(32)+NULL_CHAR+chr(4)+NULL_CHAR*5)

# Press b
write_report(NULL_CHAR*2+chr(5)+NULL_CHAR*5)
# Release keys
write_report(NULL_CHAR*8)
# Press SHIFT + b = B
write_report(chr(32)+NULL_CHAR+chr(5)+NULL_CHAR*5)

# Press SPACE key
write_report(NULL_CHAR*2+chr(44)+NULL_CHAR*5)

# Press c key
write_report(NULL_CHAR*2+chr(6)+NULL_CHAR*5)
# Press d key
write_report(NULL_CHAR*2+chr(7)+NULL_CHAR*5)

# Press RETURN/ENTER key
write_report(NULL_CHAR*2+chr(40)+NULL_CHAR*5)

# Press e key
write_report(NULL_CHAR*2+chr(8)+NULL_CHAR*5)
# Press f key
write_report(NULL_CHAR*2+chr(9)+NULL_CHAR*5)

# Release all keys
write_report(NULL_CHAR*8)

View raw code

Demonstration

Let’s test it, if you plug the Pi Zero to Computer #1, after a few seconds you’ll see an alert message or sound that indicates that a keyboard was connected successfully.

Sometimes you might see this warning message saying “USB device not recognized”. Throughout my tests, I found that you can ignore this warning message and your Pi Zero works as a keyboard without any additional configuration or drivers installation. So, you can continue and it will work just fine.

Computer #1

Open any text editor program and leave your cursor in the new file:

Computer #2

Establish an SSH connection with your Pi Zero and run the Python script created earlier:

pi@raspberrypi:~ $ sudo python3 RPi_Keyboard_Example.py

Result

The script will press these keys in that order: a – A – b – B – Space key – c – D – Enter/Return key – e – f.

You can customize the Python script to act as a keyboard and press any other character sequence.

Note: the Pi Zero also acts as a keyboard when connected to a Mac or Linux machine without any additional changes.

Taking It Further

You can use Table 12: Keyboard/Keypad Page from this USB HID PDF to find the ID of each key that you would assign in the Python script.

Here’s a section of Table 12. The Usage ID (Dec) column contains the number that you need to use in your Python script to refer to a key press:

For example, if you change the number highlighted in red, you can simulate a different key press:

write_report(NULL_CHAR*2+chr(4)+NULL_CHAR*5)

The number 4 correspondes to keyboard key a. You can find in the Usage ID (Dec) column the numbers for your desired key press sequence. If you use number 5 it corresponds to b, and so on…

Wrapping Up

You can use this method to make the Raspberry Pi Zero act as password filler or use it as a keystroke injection tool. That way you can easily create programs that type hundreds of keystrokes per minute.

You may also like some of our most popular Raspberry Pi projects:

Thanks for reading.


Learn how to program and build projects with the ESP32 and ESP8266 using MicroPython firmware DOWNLOAD »

Learn how to program and build projects with the ESP32 and ESP8266 using MicroPython firmware DOWNLOAD »


Enjoyed this project? Stay updated by subscribing our weekly newsletter!

33 thoughts on “Turn Your Raspberry Pi Zero into a USB Keyboard (HID)”

  1. Maybe I’m missing something, but why would you ever want to do this? (serious question)

    I never followed the thinking with the Arduino Leonardo either…

    • You can use this method to make the Raspberry Pi Zero act as password filler or use it as a keystroke injection tool. That way you can easily create programs that type hundreds of keystrokes per minute.

      • Yes, it said that in the notes – but, to me, it seems very impractical (a button for each password you use, or remembering a number to type on another keyboard). Personally, it seems to be an example of ‘because you can, that doesn’t mean you should’, although I can see that hackers might want it.

        • Imagine a headless remote computer with boot password, OPAL hardware encrypted drive, (inclusive-)or LUKS software encryption on your root drive and a power outage or other unplanned reboot. This situation requires a keyboard entering passwords.

          I came here looking for a possible solution to this kind of problem.

          A more complicated version of this could work. Will it compromise the security more than we’re willing to risk? Depends on how we build it. I am glad that this was posted.

  2. I’ve used this type of thing to build system test rigs – for instance to send a stream of keystrokes – with relevant delays – to automate regression testing of software.

    On a more fun note I also use with my CodeClub so that they can control their scratch games with strange controllers – a bit like the MakeyMakey. https://makeymakey.com/

  3. Thanks, for the amazing tutorial, helped heaps! I’m not particularly good at Python, and I was wondering if you could tell me how to get started in creating a repeater, so that when keys on the Pi’s keyboard are pressed, it sends them to the computer it is connected to?

  4. Great post, but there is a small error in the instructions, in section 3, the line:
    echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\$

    should read:

    echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > functions/hid.usb0/report_desc

    (see the screenshot and the linked article from isticktoit).

  5. Great tutorial. Worked first time, well after I saw David’s comment re the typo, which by the way is not fixed in the instructions :). But again, great stuff and thanks so much.

    • Based on the above keyboard version, this worked for me connected as a USB mouse to Windows 7, 10 and a Raspberry Pi 3B+.
      It didn’t work as a mouse connected to a Pi Zero W.
      In all circumstances this would only work if the device was properly recognised in Control Panel or with lsusb.

      Note: I used a RPiZeroW with kernel 2017-02-16-raspbian-jessie-lite (which is version 4.4.48).
      Post 4.4.50 this doesn’t work.

      I tested this with sudo hid_gadget_test /dev/hidg0 mouse
      10, 10 eg moves the mouse right 10 and down 10
      –b1 eg simulates a left-button click

      #!/bin/bash
      cd /sys/kernel/config/usb_gadget/
      mkdir -p isticktoit
      cd isticktoit
      echo 0x1d6b > idVendor # Linux Foundation
      echo 0x1001 > idProduct # Mouse
      echo 0x0100 > bcdDevice # v1.0.0
      echo 0x0200 > bcdUSB # USB2
      mkdir -p strings/0x409
      echo “fedcba9876543210” > strings/0x409/serialnumber
      echo “Tobias Girstmair” > strings/0x409/manufacturer
      echo “iSticktoit.net USB Device” > strings/0x409/product
      mkdir -p configs/c.1/strings/0x409
      echo “Config 1: ECM network” > configs/c.1/strings/0x409/configuration
      echo 250 > configs/c.1/MaxPower

      # Add functions here
      mkdir -p functions/hid.usb0
      echo 0 > functions/hid.usb0/protocol
      echo 0 > functions/hid.usb0/subclass
      echo 8 > functions/hid.usb0/report_length
      echo -ne \\x05\\x01\\x09\\x02\\xa1\\x01\\x09\\x01\\xa1\\x00\\x05\\x09\\x19\\x01\\x29\\x03\\x15\\x00\\x25\\x01\\x95\\x03\\x75\\x01\\x81\\x02\\x95\\x01\\x75\\x05\\x81\\x03\\x05\\x01\\x09\\x30\\x09\\x31\\x15\\x81\\x25\\x7f\\x75\\x08\\x95\\x02\\x81\\x06\\xc0\\xc0 > functions/hid.usb0/report_desc
      ln -s functions/hid.usb0 configs/c.1/
      # End functions

      ls /sys/class/udc > UDC

  6. Thank you for this awesome tutorial. I followed your steps on my pi zero w … works perfectly. (I did do a “chmod +x” on the script out of habit.)

  7. I’ve followed the guide several times – and used the 2017-04-10-raspbian-jessie-lite.
    I can’t get it to work.

    Dmsg says: (during startup)

    dwc2 20980000.usb: dwc2_hsotg_enqueue_setup: failed queue (-11)

    Any clue ???

  8. Hi, This works fine on my Raspberry Pi 3 A+ (with a male to male usb cable) but I cannot get the g key to work..

    This works: (typing f)
    echo -ne “\0\0\x9\0\0\0\0\0” > “/dev/hidg0”
    echo -ne “\0\0\0\0\0\0\0\0” > “/dev/hidg0”

    And this works: (typing h)
    echo -ne “\0\0\xb\0\0\0\0\0” > “/dev/hidg0”
    echo -ne “\0\0\0\0\0\0\0\0” > “/dev/hidg0”

    But this doesn’t:
    echo -ne “\0\0\xa\0\0\0\0\0” > “/dev/hidg0”
    echo -ne “\0\0\0\0\0\0\0\0” > “/dev/hidg0”

    Would be nice if someone could help.

Leave a Comment

Download our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.