skip navigational linksPJRC
Shopping Cart Checkout Shipping Cost Download Website
Home MP3 Player 8051 Tools All Projects PJRC Store Site Map
You are here: Teensy Teensyduino USB Keyboard

PJRC Store
Teensy 3.1, $19.80
Teensy 2.0, $16.00
Teensy++ 2.0, $24.00
USB Cable, $4.00
Teensy
Main Page
Teensy 3.1
Getting Started
How-To Tips
Code Library
Projects
Teensyduino
Reference

Using USB Keyboard

CAUTION:
Save your work!
Unexpected keystrokes can quickly ruin your program.
When you select "USB Keyboard" from the Tools -> USB Type menu, the Teensy becomes a USB keyboard and mouse while running your program.

Your PC or Mac will detect a new keyboard. Then your program can send keystrokes which your computer will recognize as coming from a standard USB keyboard.

There are two ways you can make your Teensy send USB keystrokes.

The Easy Way: Keyboard.print()

Keyboard.print() works the same way as Serial.print(), except the message is typed as keystrokes. You can print strings, numbers, single characters with all the same control as Serial.print().

Here is a very simple example, using Keyboard.print().

int count = 0;
void setup() { } // no setup needed
void loop() {
  Keyboard.print("Hello World "); 
  Keyboard.println(count);
  count = count + 1;
  delay(5000);
}

When this program is run, it will type "Hello World" and the increasing count. As you can see in this screenshot, the computer sees a USB keyboard and the keystrokes directly enter the Arduino editor. If delay(5000) had not been used, the result could be very unpleasant.

You may notice "Hello World 0" does not appear. The PC takes a brief time to detect the presence of a new USB device, but this program begins running immediately. If you use Keyboard.print() before the PC finishes the detection process (called "enumeration" in USB lingo), Keyboard.print() does nothing. A delay() can be added in setup(), if necessary.

Keyboard Layouts

The Tools > Keyboard Layout menu selects the type of keyboard Teensy will emulate. This setting takes effect when you Upload to Teensy.

If you see the wrong characters from Keyboard.print(), Teensy may be emulating a US keyboard layout, but your computer expects a non-US keyboard, or vise-versa. The layout setting only affects Keyboard.print() and Keyboard.write().

Using Pushbuttons

Many applications need to send messages to a computer when pushbuttons are pressed.

The Bounce library provides the easiest way to reliably detect pushbuttons changes. This code shows the basic approach. Just update() each object, and then use the fallingEdge() to check if it has changed.

void loop() {
  // Update all the button objects.
  button1.update();
  button2.update();
  button3.update();

  // Check each button for "falling" edge.
  // falling = high (not pressed - voltage from pullup resistor)
  //           to low (pressed - button connects pin to ground)
  if (button1.fallingEdge()) {
    Keyboard.println("B1 press");
  }
  if (button2.fallingEdge()) {
    Keyboard.println("B2 press");
  }
  if (button3.fallingEdge()) {
    Keyboard.println("B3 press");
  }

For a complete example: File > Examples > Teensy > USB_Keyboard > Buttons.

Individual Key Press / Release

You can use Keyboard.press(key) and Keyboard.release(key) to send individual key press and release events. This is similar to the "Micro Manager Way" described below, except the press() and release() functions will automatically take care of the details of setting 1 of the 6 possible key slots and sending the updates.

The Micro Manager Way

Sometimes you may need precise keyboard control. For example, many Windows programs will not recognize a CTRL-C character as a copy command unless the CTRL key is pressed and remains held down while the C key is pressed. Some keys, like "Home" and "Print Screen" can not be represented in a normal string usable with Keyboard.print(). The micro manager way requires more effort but gives you complete control.

The USB keyboard can have up to 6 normal keys and 4 modifier keys pressed at the same time. To micro manage the keyboard, you use functions to set which combination of keys you want pressed (and zero for the ones you want not pressed), and then use Keyboard.send_now() to send each combination.

You can use delay() or write code to check millis() between calling Keyboard.send_now(), to create the condition of a key held down similarly to a human typing. Auto-repeat is done by the driver on your PC or Mac, so if you have a long delay between pressing and releasing a normal key, the auto-repeat feature may deliver many key events to software.

When micro managing, you need to send a zero for each key you've pressed to cause that key to be released (as if a finger were lifting off the key and its spring were returning it to the resting position).

Modifier Keys

There are 4 modifier keys: Shift, Alt, Ctrl, and GUI. GUI is either the "windows key" (PC) or the "clover key" (Macintosh), usually located to the side of the space bar. These 4 keys are special, and can only be used with Keyboard.set_modifier().

NameFunction
MODIFIERKEY_CTRLControl Key
MODIFIERKEY_SHIFTShift Key
MODIFIERKEY_ALTAlt Key
MODIFIERKEY_GUIWindows (PC) or Clover (Mac)

If you want no modifier keys pressed, use a zero.

Keyboard.set_modifier(0);

To press just one modifier is simple.

Keyboard.set_modifier(MODIFIERKEY_SHIFT);

To press more than one modifier, use the logic OR operator. For example:

Keyboard.set_modifier(MODIFIERKEY_CTRL | MODIFIERKEY_ALT);

Normal Keys

Six keys are always tranmitted by the USB keyboard. Normally, only the first key is used and the other 5 are zero. However, you can use the 6 keys in any way you like. For example, this code would send keys A, B, C, D, E and F, all pressed at once.

Keyboard.set_key1(KEY_A);
Keyboard.set_key2(KEY_B);
Keyboard.set_key3(KEY_C);
Keyboard.set_key4(KEY_D);
Keyboard.set_key5(KEY_E);
Keyboard.set_key6(KEY_F);

To release a key, you must set it to zero. For the above example, all six would need to be set back to zero if the next Keyboard.send_now() should not have any of these 6 keys pressed.

Keyboard.send_now()

After you have set the normal and modifier keys, use Keyboard.send_now() to communicate that combination to the PC or Mac.

The keys remain as you set them, so between each call to Keyboard.send_now(), you only need to make the changes you need. For example, this code would send a CTRL-ALT-DELETE sequence.

// press and hold CTRL
Keyboard.set_modifier(MODIFIERKEY_CTRL);
Keyboard.send_now();

// press ALT while still holding CTRL
Keyboard.set_modifier(MODIFIERKEY_CTRL | MODIFIERKEY_ALT);
Keyboard.send_now();

// press DELETE, while CLTR and ALT still held
Keyboard.set_key1(KEY_DELETE);
Keyboard.send_now();

// release all the keys at the same instant
Keyboard.set_modifier(0);
Keyboard.set_key1(0);
Keyboard.send_now();

It is important to set normal keys back to zero and send. If you do not, the key will remain pressed, and the PC or Mac USB driver will begin auto-repeat.

If you are familiar with the older PS/2 keyboard "scan codes", please be aware that USB keyboard codes work differently (and use different numerical values). The old scan codes sent different messages for key down and key up events, where each message represented a single key's change. With USB, each message represents the complete state of the keyboard. Up to any 6 keys may be pressed at once, plus any combination of the 8 modifier keys.

All Keys Codes

Normal Keys
KEY_AKEY_BKEY_CKEY_D
KEY_EKEY_FKEY_GKEY_H
KEY_IKEY_JKEY_KKEY_L
KEY_MKEY_NKEY_OKEY_P
KEY_QKEY_RKEY_SKEY_T
KEY_UKEY_VKEY_WKEY_X
KEY_YKEY_ZKEY_1KEY_2
KEY_3KEY_4KEY_5KEY_6
KEY_7KEY_8KEY_9KEY_0
KEY_ENTERKEY_ESCKEY_BACKSPACEKEY_TAB
KEY_SPACEKEY_MINUSKEY_EQUALKEY_LEFT_BRACE
KEY_RIGHT_BRACEKEY_BACKSLASHKEY_NUMBERKEY_SEMICOLON
KEY_QUOTEKEY_TILDEKEY_COMMAKEY_PERIOD
KEY_SLASHKEY_CAPS_LOCKKEY_F1KEY_F2
KEY_F3KEY_F4KEY_F5KEY_F6
KEY_F7KEY_F8KEY_F9KEY_F10
KEY_F11KEY_F12KEY_PRINTSCREENKEY_SCROLL_LOCK
KEY_PAUSEKEY_INSERTKEY_HOMEKEY_PAGE_UP
KEY_DELETEKEY_ENDKEY_PAGE_DOWNKEY_RIGHT
KEY_LEFTKEY_DOWNKEY_UPKEY_NUM_LOCK
KEYPAD_SLASHKEYPAD_ASTERIXKEYPAD_MINUSKEYPAD_PLUS
KEYPAD_ENTERKEYPAD_1KEYPAD_2KEYPAD_3
KEYPAD_4KEYPAD_5KEYPAD_6KEYPAD_7
KEYPAD_8KEYPAD_9KEYPAD_0KEYPAD_PERIOD

TODO: document the 8 media key codes and the special set_media() function. Currently these only work on Mac and Linux. Windows does NOT work. A future version will redesign this feature to hopefully work on Windows too. For now, the only documentation is the example, in File > Examples > Teensy > USB_Keyboard > MediaButtons.

Bandwidth - Less Than You Might Expect

USB Keyboard speed is limited to 500 keystrokes per second, and some operating systems may limit the speed to only 62.5 keystrokes per second. There is nothing you can do about these limits. Reading the rest of this section will only help you understand why they exist.

The HID protocol is used by USB keyboards, and HID uses the USB "interrupt" transfer type, which allocates 1 packet per a configurable number of USB frames. Each USB frame is 1ms, and the Teensyduino USB keyboard code requests the interval to be every frame. If the operating system honors this request, bandwidth is available for 1000 packets per second.

Each keystroke requires 2 calls to Keyboard.send_now(), the first to press the key and the second to release it. This translates to 500 keystrokes per second. Of course, you can send 10 different keys in each, but logic inside the USB device driver will analyze for changes, which imposes a practical limit, especially when sending to already-written software which expects "normal" typing.

Some operating systems might disregard the request and instead schedule 1 packet every 8 frames. At 16ms each, only 62.5 keystrokes per second are possible.

Some software, even when running on a multi-gHz, multi-core processor may perform so much work per keystroke (or be written so infficiently), that sending at such "fast" speeds could overwhelm the computer. You might need to add extra delays.

USB keyboard is slow. If you need substantial bandwidth, use USB serial.