The Arduino Keyboard library: a board that types
Keyboard.h turns an Arduino into a USB keyboard that the computer accepts without a driver. It only works on boards whose main chip speaks USB itself: the Leonardo, Micro and Pro Micro with the ATmega32U4, plus newer boards such as the Uno R4 and the SAMD and RP2040 ones. An Uno or Nano has a separate USB-to-serial chip and cannot do it.
Built in on Mokxi: #include <Keyboard.h> and it builds, with nothing to install. Free, and no account needed.
What Keyboard does
It can type text a key at a time with print(), or hold keys down with press() and let them go with release() or releaseAll(), which is how hotkeys like Ctrl+C or Alt+Tab are sent. Up to six ordinary keys plus the modifiers can be held at once. Text is typed for a US keyboard layout, so on another layout some symbols come out as different characters.
People use it for macro pads, stream decks, foot pedals and test rigs. Because the board starts typing as soon as it is plugged in, always give a new sketch a way to stay quiet, such as a switch it checks before sending anything.
| Library Manager name | Keyboard |
|---|---|
| Author | Arduino |
| Include | #include <Keyboard.h> |
| Boards | Arduino Leonardo, SparkFun Pro Micro, Arduino Micro |
| In the simulator | Runs, with a gap the note below names. |
Install it
It builds on Arduino Leonardo, SparkFun Pro Micro, Arduino Micro.
In Mokxi it is built in: #include <Keyboard.h> and the sketch compiles, with no download, no zip and no Library Manager.
On a real board it comes with the board package (Arduino), so the Arduino IDE has it as soon as the board is installed: there is nothing to add from the Library Manager.
The calls you will use
In the order a sketch meets them.
Keyboard.begin()
Starts acting as a keyboard. Call it once in setup().
Keyboard.print("Hello")
Types the text one key at a time. println() adds an Enter at the end.
Keyboard.press(KEY_LEFT_CTRL)
Holds a key down until it is released. Combine several presses for a shortcut.
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press('c');
delay(50);
Keyboard.releaseAll();Keyboard.release(KEY_LEFT_SHIFT)
Lets go of one held key.
Keyboard.releaseAll()
Lets go of every key, the safe way to end any shortcut.
Keyboard.write(KEY_RETURN)
Presses and releases one key, such as KEY_RETURN, KEY_TAB or KEY_F5.
Keyboard.end()
Stops sending keys; the board stays connected.
Example: Stream deck on a Pro Micro
On the SparkFun Pro Micro. It runs in the browser exactly as printed.
// Stream deck on a Pro Micro: six keys, their labels on a 128x64 OLED, and a
// hotkey sent over USB for each press through Keyboard.h.
//
// The labels are the point. A plain macro pad makes you remember which key
// is which; here the screen shows a label over each key, the one you press
// lights up, and the sixth key flips to a second page of five more actions.
//
// Wiring.
//
// keys 4 5 6 7 8 9 (each to GND, pulled up inside the chip)
// OLED SSD1306 on I2C: SDA pin 2, SCL pin 3, VCC 5 V, GND
//
// In Mokxi: click the arcade buttons. The OLED shows the page and lights the
// key you hold, and the Serial Monitor shows the hotkey the board would type.
//
// Hotkeys. Each action is Ctrl + Shift + an F-key from F13 to F22. Almost no
// program uses F13 and up on its own, so streaming and recording software
// (OBS Studio's hotkey settings, for one) can take them without clashing with
// anything. Press the key in the program's hotkey box once and it learns it.
//
// Not simulated: the USB connection to a PC. Mokxi models this chip's USB as
// a serial pipe, so each press prints as a [Keyboard] line on the Serial
// Monitor. Flash the same sketch to a real Pro Micro and it types the keys.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Keyboard.h>
// ---------------------------------------------------------------------------
// Make it yours
// ---------------------------------------------------------------------------
const uint8_t KEY_PINS[6] = {4, 5, 6, 7, 8, 9};
// Two pages of five actions; key 6 always turns the page. Labels are six
// characters at most so they fit a key's box.
const char *const LABELS[2][5] = {
{"SCENE1", "SCENE2", "MUTE", "CAM", "REC"},
{"BRB", "CLIP", "MARKER", "CHAT", "LIVE"},
};
const uint8_t HOTKEYS[2][5] = {
{KEY_F13, KEY_F14, KEY_F15, KEY_F16, KEY_F17},
{KEY_F18, KEY_F19, KEY_F20, KEY_F21, KEY_F22},
};
// Held with every hotkey. Change to just KEY_LEFT_CTRL, or add KEY_LEFT_ALT.
const uint8_t MODIFIERS[2] = {KEY_LEFT_CTRL, KEY_LEFT_SHIFT};
const unsigned long LOCK_MS = 20; // debounce: ignore a key this long after a change
// ---------------------------------------------------------------------------
Adafruit_SSD1306 display(128, 64, &Wire, -1);
uint8_t page = 0;
bool held[6];
unsigned long changedAt[6];
void drawKey(uint8_t k) {
int16_t x = (k % 3) * 43;
int16_t y = 16 + (k / 3) * 24;
bool lit = held[k];
display.fillRect(x, y, 42, 22, lit ? SSD1306_WHITE : SSD1306_BLACK);
display.drawRect(x, y, 42, 22, SSD1306_WHITE);
display.setTextColor(lit ? SSD1306_BLACK : SSD1306_WHITE);
display.setCursor(x + 3, y + 7);
display.print(k == 5 ? "PAGE>" : LABELS[page][k]);
}
void draw() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 2);
display.print("STREAM DECK page ");
display.print(page + 1);
for (uint8_t k = 0; k < 6; k++) {
drawKey(k);
}
display.display();
}
void send(uint8_t k) {
for (uint8_t m = 0; m < 2; m++) Keyboard.press(MODIFIERS[m]);
Keyboard.press(HOTKEYS[page][k]);
Keyboard.releaseAll();
Serial.print("Key ");
Serial.print(k + 1);
Serial.print(": ");
Serial.println(LABELS[page][k]);
}
void setup() {
for (uint8_t k = 0; k < 6; k++) {
pinMode(KEY_PINS[k], INPUT_PULLUP);
}
Serial.begin(115200);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
Wire.setClock(400000); // fast mode: the screen redraws sooner
Keyboard.begin();
draw();
Serial.println("Stream deck ready: page 1");
}
void loop() {
unsigned long now = millis();
bool redraw = false;
for (uint8_t k = 0; k < 6; k++) {
bool down = digitalRead(KEY_PINS[k]) == LOW;
if (down == held[k] || now - changedAt[k] < LOCK_MS) {
continue;
}
held[k] = down;
changedAt[k] = now;
redraw = true;
if (!down) {
continue;
}
if (k == 5) {
page = (uint8_t)(1 - page);
Serial.print("Page ");
Serial.println(page + 1);
} else {
send(k);
}
}
if (redraw) {
draw();
}
}Open it in the editor, wired and ready to run 路 Stream deck on a Pro Micro: the project page
Common errors and how to fix them
'Keyboard' not found. Does your sketch include the line '#include <Keyboard.h>'?
Current Arduino cores no longer include the keyboard library automatically. Add #include <Keyboard.h> at the top, and make sure the board selected is a Leonardo, Micro or Pro Micro.
Keyboard.h fails to build on an Uno or Nano
Those boards cannot be USB devices: their USB is a separate serial chip. Use a board with an ATmega32U4 (Leonardo, Micro, Pro Micro) or another board with native USB.
The board types nonstop and is hard to reprogram
Double-tap reset on a Pro Micro or hold reset on a Leonardo while the upload starts, and upload a sketch that only types when a button is pressed or a switch is on.
Some symbols come out wrong, such as @ or quotes
The library types for a US layout. On another keyboard layout, set the computer to US for testing, or send the key codes your layout needs with press().
Projects that use Keyboard
Built-in projects that include it. Each page has the full sketch and opens in the editor, already wired.
Try Keyboard without installing anything
Open the example, change the sketch, and keep your version in a free account.