Pairs nicely with a norns/Fates music device...

Text Editor

Adafruit recommends using the Mu editor for using your CircuitPython code with the Pico. You can get more info in this guide.

Alternatively, you can use any text editor that saves files.

CircuitPython Code

Copy the code below and paste it into Mu. Then, save it to your Pico as code.py.

Temporarily unable to load content:


Even before we've attached the mech keyswitches and PCB, you can test the code by shorting each of the GPIO pins used to ground. This is the same as pressing a key. Just be careful not to short power to ground!

Open the serial monitor for your board in Mu, or use a text editor to watch the keys get typed each time you short one of the GPIO pins.

USB keyboards and mice show up on your computer as 'HID' devices, which stands for 'Human Interface Device'

HID Keyboard Basics

This guide page has a great intro to CircuitPython HID Keyboard.

For even more details, check out the documentation at https://circuitpython.readthedocs.io/projects/hid/en/latest/ which includes all of the keycodes and media codes you can use.

By importing the adafruit_hid library into the program, you can make calls to send keyboard keys and media keys.

USB Keyboards versus CircuitPython HID Keyboards

Certain keys you might want to emulate from your standard existing keyboard, such as multi-media (volume, play/pause, etc.) keys, are not actually regular keyboard keys. They are consumer control keys. All keys on a standard USB keyboard are not necessarily sending regular keycode values, but instead may be sending consumer control values on a separate consumer control device. In CircuitPython this is the difference between sending Keycode values via a Keyboard, and sending ConsumerControlCode values via a ConsumerControl. Therefore, if, in CircuitPython, you intend to send, for example, a "mute" command in your HID example, you should use ConsumerControl instead of an equivalent keyboard key based on your standard existing keyboard.

Consumer control keys, such as multi-media keys, do not require "focus" to function. For example, sending a VOLUME_DECREMENT consumer control command will decrease the volume regardless of which window currently has keyboard focus.

Keyboard Press/Release

Using the HID library in CircuitPtyhon, you can send this command to "type" the letter 'a':



This would send a lowercase 'a' to the computer just as if you had typed it yourself. To send a capital 'A', we'd add the shift key to the command like this:

kbd.press(Keycode.SHIFT, Keycode.A)

kbd.release(Keycode.SHIFT, Keycode.A)

This is pretty cool, since it means we can layer on lots of keys all at the same time, just like you do on your physical keyboard when using keyboard shortcuts!

So, if there's some keyboard shortcut you want to use (or create for yourself in something like Quicksilver or AutoKeys) that is command+option+ctrl+a the CircuitPython code would look like this:

kbd.press(Keycode.GUI, Keycode.ALT, Keycode.CONTROL, Keycode.A)

kbd.release(Keycode.GUI, Keycode.ALT, Keycode.CONTROL, Keycode.A)

The adafruit_hid library allows for operating system specific names such as 'Keycode.COMMAND' on macOS which is 'Keycode.WINDOWS' on Windows. Or, you can use the generic 'Keycode.GUI' on any operating system. Same goes for 'ALT/OPTION'

Media Control

There is a second command to use to adjust volume, play/pause, skip tracks, and so on with media such as songs and videos. These are often represented on a physical keyboard as icons silkscreened onto the rightmost function keys.

In USB HID speak, these are known as "Consumer Control codes". To play or pause a track, use this command:


keymap = {
    (0): (KEY, (Keycode.GUI, Keycode.C)),
    (1): (KEY, (Keycode.GUI, Keycode.V)),
    (2): (KEY, [Keycode.THREE]),
    (3): (KEY, [Keycode.FOUR]),
    (4): (KEY, [Keycode.FIVE]),
    (5): (MEDIA, ConsumerControlCode.VOLUME_DECREMENT),
    (6): (MEDIA, ConsumerControlCode.VOLUME_INCREMENT),

    (7): (KEY, [Keycode.R]),
    (8): (KEY, [Keycode.G]),
    (9): (KEY, [Keycode.B]),
    (10): (KEY, [Keycode.UP_ARROW]),
    (11): (KEY, [Keycode.X]),  # plus key
    (12): (KEY, [Keycode.Y]),
    (13): (KEY, [Keycode.Z]),

    (14): (KEY, [Keycode.I]),
    (15): (KEY, [Keycode.O]),
    (16): (KEY, [Keycode.LEFT_ARROW]),
    (17): (KEY, [Keycode.DOWN_ARROW]),
    (18): (KEY, [Keycode.RIGHT_ARROW]),
    (19): (KEY, [Keycode.ALT]),
    (20): (KEY, [Keycode.U]),


Key Assignments

With that in mind, you can now fully customize the function of each key by editing this section of the code:

Note, in order to use a single stroke keycode, you'll surround it in [brackets], while a multi-stroke keycode will have its own (parentheses) as shown here:

(1): (KEY, (Keycode.GUI, Keycode.V)),
(2): (KEY, [Keycode.THREE]),

This guide was first published on Mar 03, 2021. It was last updated on 2021-03-03 10:15:41 -0500.

This page (Code the Pico Keyboard) was last updated on Jul 07, 2022.

Text editor powered by tinymce.