USB: Keyboard

This code implements a USB keyboard, which you can use to control almost any PC or Mac software.

Download Source Files

Example Application

The example program configures all Port B and Port D pins as inputs with pullup resistors. When any of these 16 pins is shorted to ground, 2 keystrokes are sent to the PC naming that pin.

An idle timeout is also implemented which send a spacebar keystroke after 8 seconds of inactivity.


USB Keyboard Example, 16 keys on Port B and Port D

Operating System Setup

All modern operating systems support USB keyboards. No special drivers need to be loaded.

This code also supports the keyboard "boot protocol" for compatability with the BIOS before an operating system has loaded.

Simple Keypress Function

#include <usb_keyboard.h>

usb_keyboard_press(key, modifier)

This simple function sends a single keypress. The following table lists definitions for the standard keys and modifiers. If no modifier is needed, use 0.

keymodifier
KEY_AKEY_BKEY_CKEY_DKEY_CTRL
KEY_EKEY_FKEY_GKEY_HKEY_SHIFT
KEY_IKEY_JKEY_KKEY_LKEY_ALT
KEY_MKEY_NKEY_OKEY_PKEY_GUI
KEY_QKEY_RKEY_SKEY_TKEY_LEFT_CTRL
KEY_UKEY_VKEY_WKEY_XKEY_LEFT_SHIFT
KEY_YKEY_ZKEY_1KEY_2KEY_LEFT_ALT
KEY_3KEY_4KEY_5KEY_6KEY_LEFT_GUI
KEY_7KEY_8KEY_9KEY_0KEY_RIGHT_CTRL
KEY_ENTERKEY_ESCKEY_BACKSPACEKEY_TABKEY_RIGHT_SHIFT
KEY_SPACEKEY_MINUSKEY_EQUALKEY_LEFT_BRACEKEY_RIGHT_ALT
KEY_RIGHT_BRACEKEY_BACKSLASHKEY_NUMBERKEY_SEMICOLONKEY_RIGHT_GUI
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

Complex Keyboard Functionality

Most applications only require the single press function above, which rapidly presses and releases a single key (plus modifiers) at a time. However, for multiple simultaneous keys pressed, holding keys down for periods of time, and complex sequences, the raw USB key code data may be accessed.

For example, to copy from the clipboard in Windows, some programs may require the CTRL key to be held for a period of time before the C key is pressed. Using usb_keyboard_press() presses and quickly releases the C and CTRL keys together at exactly the same instant. To send a timed sequence, you must set the keyboard state variables and use usb_keyboard_send() to transmit each state change.

keyboard_keys[6]

This 6 byte array represents the non-modifier keys that are currently pressed. You can only press 6 of the non-modifier keys at once. Set these to zero when not pressing a key.

keyboard_modifier_keys

This variable represents the modifier keys currently pressed. Set this to a bitwise OR of all modifier keys pressed, or zero if none are pressed.

usb_keyboard_send()

After setting the varibles above, call this function to transmit the key state to the PC. The PC automatically implements auto-repeat when you send a key state that has a non-modifier key pressed, and you allow a long delay before sending a zero to release the key.

// first, press the CTRL key
keyboard_modifier_keys = KEY_CTRL;
keyboard_keys[0] = 0;
keyboard_keys[1] = 0;
keyboard_keys[2] = 0;
keyboard_keys[3] = 0;
keyboard_keys[4] = 0;
keyboard_keys[5] = 0;
usb_keyboard_send();
_delay_ms(50);

// next, press ALT while still holding CTRL
keyboard_modifier_keys = KEY_CTRL | KEY_ALT;
usb_keyboard_send();
_delay_ms(50);

// now press DELETE, while still keeping CTRL and ALT
keyboard_keys[0] = KEY_DELETE;
usb_keyboard_send();
_delay_ms(150);

// release DELETE, while still keeping CTRL and ALT
keyboard_keys[0] = 0;
usb_keyboard_send();
_delay_ms(50);

// release both CTRL and ALT at exactly the same moment
keyboard_modifier_keys = 0;
usb_keyboard_send();

keyboard_leds

This variable is updated with the current keyboard LED setting.

USB Connection Management Functions

usb_init()

Initialize the USB controller. This must be called before any others, typically as your program initializes everything. This function always returns immediately and never waits for any USB communication.

usb_configured()

Is the USB controller configured?

Returns 0 (false) if the host has not enumerated (auto-detected) and configured the USB controller. Returns non-zero (true) if configuration is complete.

Many PC and Macintosh drivers are not immediately ready to transfer data, even after configuration is complete. An additional delay of 1 second is generally a good idea to allow drivers to load on the PC before initiating data transfers.

USB Debug Message Functions

The debug version includes all the debug message functions, which may be used indepentently from the keyboard functions for display in HID Listen.

About USB Keyboard Bandwidth

The USB keyboard protocol is not designed for high bandwidth data transfer. Each change of keyboard state is transmitted as a packet. Because the USB interrupt transfer type is used, a maximum of 1000 packets per second can be sent.

Using usb_keyboard_press(), two packets are sent for every keystroke, the first to press the key (and modifier keys) and the second to release. This results in a maximum of 500 keystrokes per second. Using usb_keyboard_send(), a single packet is sent with the contents of the keyboard_keys[6] and keyboard_modifier_keys.

Software on the PC may spend considerable CPU time processing each keystroke, with the assumption that no human could possibly press more than several keys per second. Even 500 keys per second may overwhelm such software.