pc-keyboard

A simple driver for handling PC keyboards, with both Scancode Set 1 (when running on a PC) and Scancode Set 2 support (when reading a PS/2 keyboard output directly).

Supports:

| Name | No. Keys | Description | Link | | ---------------------------------------------------- | -------- | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- | | Us104 | 101/104 | North American standard English | Wikipedia | | Uk105 | 102/105 | United Kingdom standard English | Wikipedia | | Azerty | 102/105 | Typically used in French locales | Wikipedia | | De104 | 102/105 | German layout | Wikipedia | | Jis109 | 106/109 | JIS 109-key layout (Latin chars only) | Wikipedia | | Colemak | 101/104 | A keyboard layout designed to make typing more efficient and comfortable | Wikipedia | | Dvorak104Key | 101/104 | The more 'ergonomic' alternative to QWERTY | Wikipedia | | DVP104Key | 101/104 | Dvorak for Programmers | Wikipedia |

101/104 keys is ANSI layout (wide Enter key) and 102/105 keys is ISO layout (tall Enter key). The difference between 101 and 104 (and between 102 and 105) comes from the two Windows keys and the Menu key that were added when Windows 95 came out. JIS keyboards have extra keys, added by making the space-bar and backspace keys shorter.

Usage

There are three basic steps to handling keyboard input. Your application may bypass some of these.

There is also Keyboard which combines the above three functions into a single object.

See the examples folder for more details.

Documentation

Keycodes

This crate uses symbolic keycodes to abstract over Scancode Set 1 and Scancode Set 2. They represented by the KeyCode enum. The scancodes can come from one of three supported keyboards: 102/105 key ISO, 101/104 key ANSI and 106/109-key JIS.

102/105 key ISO

This is the mapping of KeyCode to a 102/105-key ISO keyboard:

```text ┌────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┐ │Esc │ │ F1 │ F2 │ F3 │ F4 │ │ F5 │ F6 │ F7 │ F8 │ │ F9 │F10 │F11 │F12 │ │PrSc│Scrl│PBrk│ └────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┘

┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬─────────┐ ┌────┬────┬────┐ ┌────┬────┬────┬────┐ │Oem8│Key1│Key2│Key3│Key4│Key5│Key6│Key7│Key8│Key9│Key0│Oem─│Oem+│Backspace│ │Inse│Home│PgUp│ │NumL│Num/│Num*│Num─│ ├────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬────────┤ ├────┼────┼────┤ ├────┼────┼────┼────┤ │ Tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │Oem4│Oem6│ Enter │ │Dele│End │PgDo│ │Num7│Num8│Num9│ │ ├─────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┐ │ └────┴────┴────┘ ├────┼────┼────┤Num+│ │CapsLo│ A │ S │ D │ F │ G │ H │ J │ K │ L │Oem1│Oem3│Oem7│ │ │Num4│Num5│Num6│ │ ├────┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴────┴───────┤ ┌────┐ ├────┼────┼────┼────┤ │LShf│Oem5│ Z │ X │ C │ V │ B │ N │ M │OemC│OemP│Oem2│ RShift │ │ Up │ │Num1│Num2│Num3│ │ ├────┴┬───┴─┬──┴──┬─┴────┴────┴────┴────┴────┴───┬┴────┴────┴┬──────┬──────┤ ┌────┼────┼────┐ ├────┴────┼────┤Num │ │LCtrl│LWin │ Alt │ Space │AltGr│RWin │ Menu │RCtrl │ │Left│Down│Righ│ │Num0 │NumP│Ente│ └─────┴─────┴─────┴──────────────────────────────┴─────┴─────┴──────┴──────┘ └────┴────┴────┘ └─────────┴────┴────┘ ```

The 102-key is missing LWin, RWin, and Menu.

101/104 key ANSI

This is the mapping of KeyCode to a 101/104-key ANSI keyboard:

```text ┌────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┐ │Esc │ │ F1 │ F2 │ F3 │ F4 │ │ F5 │ F6 │ F7 │ F8 │ │ F9 │F10 │F11 │F12 │ │PrSc│Scrl│PBrk│ └────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┘

┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬─────────┐ ┌────┬────┬────┐ ┌────┬────┬────┬────┐ │Oem8│Key1│Key2│Key3│Key4│Key5│Key6│Key7│Key8│Key9│Key0│Oem─│Oem+│Backspace│ │Inse│Home│PgUp│ │NumL│Num/│Num*│Num─│ ├────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬────────┤ ├────+────+────┤ ├────┼────┼────┼────┤ │ Tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │Oem4│Oem6│ Oem5 │ │Dele│End │PgDo│ │Num7│Num8│Num9│ │ ├─────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴────────┤ └────┴────┴────┘ ├────┼────┼────┤Num+│ │CapsLo│ A │ S │ D │ F │ G │ H │ J │ K │ L │Oem1│Oem3│ Enter │ │Num4│Num5│Num6│ │ ├──────┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴────────────┤ ┌────┐ ├────┼────┼────┼────┤ │ LShift │ Z │ X │ C │ V │ B │ N │ M │OemC│OemP│Oem2│ RShift │ │ Up │ │Num1│Num2│Num3│ │ ├─────┬───┴─┬──┴──┬─┴────┴────┴────┴────┴────┴───┬┴────┴────┴┬──────┬──────┤ ┌────┼────┼────┐ ├────┴────┼────┤Num │ │LCtrl│LWin │ Alt │ Space │AltGr│RWin │ Menu │RCtrl │ │Left│Down│Righ│ │Num0 │NumP│Ente│ └─────┴─────┴─────┴──────────────────────────────┴─────┴─────┴──────┴──────┘ └────┴────┴────┘ └─────────┴────┴────┘ ```

Note that the Oem7 key is missing on the 104-key ANSI keyboard.

The 101-key is also missing LWin, RWin, and Menu.

106/109 key JIS

This is the mapping of KeyCode to a 106/109-key JIS keyboard:

```text ┌────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┬────┐ ┌────┬────┬────┐ │Esc │ │ F1 │ F2 │ F3 │ F4 │ │ F5 │ F6 │ F7 │ F8 │ │ F9 │F10 │F11 │F12 │ │PrSc│Scrl│PBrk│ └────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┴────┘ └────┴────┴────┘

┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ ┌────┬────┬────┐ ┌────┬────┬────┬────┐ │Oem8│Key1│Key2│Key3│Key4│Key5│Key6│Key7│Key8│Key9│Key0│Oem─│Oem+│Om13│BkSp│ │Inse│Home│PgUp│ │NumL│Num/│Num*│Num─│ ├────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬────────┤ ├────┼────┼────┤ ├────┼────┼────┼────┤ │ Tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │Oem4│Oem6│ Enter │ │Dele│End │PgDo│ │Num7│Num8│Num9│ │ ├─────┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┴┐ │ └────┴────┴────┘ ├────┼────┼────┤Num+│ │CapsLo│ A │ S │ D │ F │ G │ H │ J │ K │ L │Oem1│Oem3│Oem7│ │ │Num4│Num5│Num6│ │ ├──────┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴────┴───────┤ ┌────┐ ├────┼────┼────┼────┤ │LShift │ Z │ X │ C │ V │ B │ N │ M │OemC│OemP│Oem2│Oem12 │RShift │ │ Up │ │Num1│Num2│Num3│ │ ├─────┬───┴─┬──┴──┬─┴───┬┴────┴────┴────┴────┴┬───┴─┬──┴──┬─┴──┬────┬──────┤ ┌────┼────┼────┐ ├────┴────┼────┤Num │ │LCtrl│LWin │LAlt │Oem9 │ Space Bar │Oem10│Oem11│RWin│Menu│RCtrl │ │Left│Down│Righ│ │Num0 │NumP│Ente│ └─────┴─────┴─────┴─────┴─────────────────────┴─────┴─────┴────┴────┴──────┘ └────┴────┴────┘ └─────────┴────┴────┘ ```

Note that the Oem5 is missing on the 109-key JIS layout, but Oem9 (Muhenkan), Oem10 (Henkan/Zenkouho), Oem11 (Hiragana/Katakana), Oem12 (Backslash) and Oem13 (¥) are added.

The 106-key is also missing LWin, RWin, and Menu.

Conversion Table

Scancode Set 1 and Scancode Set 2 can be losslessly converted. Indeed, this is what the i8042 keyboard controller in your PC does - it takes Scancode Set 2 from the keyboard and provides Scancode Set 1 to the Operating System. This allowed them to change the keyboard design without breaking compatibility with any MS-DOS applications that read raw scancodes from the keyboard.

This table shows the correspondence between our symbolic KeyCode, Scancode Set 1 and Scancode Set 2. We may extend this in the future to also handle USB HID Scancodes. Any codes prefixed 0xE0 or 0xE1 are extended multi-byte scancodes. Typically these are keys that were not on the IBM PC and PC/XT keyboards so they they were added in such a way that if you ignored the 0xE0, you got a reasonable result anyway. For example ArrowLeft is 0xE04B in Scancode Set 1 because Numpad4 is 0x4B and that was the left-arrow key on an IBM PC or PC/XT.

| Symbolic Key | Scancode Set 1 | Scancode Set 2 | | -------------- | -------------- | -------------- | | Escape | 0x01 | 0x76 | | F1 | 0x3B | 0x05 | | F2 | 0x3C | 0x06 | | F3 | 0x3D | 0x04 | | F4 | 0x3E | 0x0C | | F5 | 0x3F | 0x03 | | F6 | 0x40 | 0x0B | | F7 | 0x41 | 0x83 | | F8 | 0x42 | 0x0A | | F9 | 0x43 | 0x01 | | F10 | 0x44 | 0x09 | | F11 | 0x57 | 0x78 | | F12 | 0x58 | 0x07 | | PrintScreen | 0xE037 | 0xE07C | | SysRq | 0x54 | 0x7F | | ScrollLock | 0x46 | 0x7E | | PauseBreak | -- | -- | | - | -- | -- | | Oem8 | 0x29 | 0x0E | | Key1 | 0x02 | 0x16 | | Key2 | 0x03 | 0x1E | | Key3 | 0x04 | 0x26 | | Key4 | 0x05 | 0x25 | | Key5 | 0x06 | 0x2E | | Key6 | 0x07 | 0x36 | | Key7 | 0x08 | 0x3D | | Key8 | 0x09 | 0x3E | | Key9 | 0x0A | 0x46 | | Key0 | 0x0B | 0x45 | | OemMinus | 0x0C | 0x4E | | OemPlus | 0x0D | 0x55 | | Backspace | 0x0E | 0x66 | | Insert | 0xE052 | 0xE070 | | Home | 0xE047 | 0xE06C | | PageUp | 0xE049 | 0xE07D | | NumpadLock | 0x45 | 0x77 | | NumpadDivide | 0xE035 | 0xE04A | | NumpadMultiply | 0x37 | 0x7C | | NumpadSubtract | 0x4A | 0x7B | | - | -- | -- | | Tab | 0x0F | 0x0D | | Q | 0x10 | 0x15 | | W | 0x11 | 0x1D | | E | 0x12 | 0x24 | | R | 0x13 | 0x2D | | T | 0x14 | 0x2C | | Y | 0x15 | 0x35 | | U | 0x16 | 0x3C | | I | 0x17 | 0x43 | | O | 0x18 | 0x44 | | P | 0x19 | 0x4D | | Oem4 | 0x1A | 0x54 | | Oem6 | 0x1B | 0x5B | | Oem5 | 0x56 | 0x61 | | Oem7 | 0x2B | 0x5D | | Delete | 0xE053 | 0xE071 | | End | 0xE04F | 0xE069 | | PageDown | 0xE051 | 0xE07A | | Numpad7 | 0x47 | 0x6C | | Numpad8 | 0x48 | 0x75 | | Numpad9 | 0x49 | 0x7D | | NumpadAdd | 0x4E | 0x79 | | - | -- | -- | | CapsLock | 0x3A | 0x58 | | A | 0x1E | 0x1C | | S | 0x1F | 0x1B | | D | 0x20 | 0x23 | | F | 0x21 | 0x2B | | G | 0x22 | 0x34 | | H | 0x23 | 0x33 | | J | 0x24 | 0x3B | | K | 0x25 | 0x42 | | L | 0x26 | 0x4B | | Oem1 | 0x27 | 0x4C | | Oem3 | 0x28 | 0x52 | | Return | 0x1C | 0x5A | | Numpad4 | 0x4B | 0x6B | | Numpad5 | 0x4C | 0x73 | | Numpad6 | 0x4D | 0x74 | | - | -- | -- | | LShift | 0x2A | 0x12 | | Z | 0x2C | 0x1A | | X | 0x2D | 0x22 | | C | 0x2E | 0x21 | | V | 0x2F | 0x2A | | B | 0x30 | 0x32 | | N | 0x31 | 0x31 | | M | 0x32 | 0x3A | | OemComma | 0x33 | 0x41 | | OemPeriod | 0x34 | 0x49 | | Oem2 | 0x35 | 0x4A | | RShift | 0x36 | 0x59 | | ArrowUp | 0xE048 | 0xE075 | | Numpad1 | 0x4F | 0x69 | | Numpad2 | 0x50 | 0x72 | | Numpad3 | 0x51 | 0x7A | | NumpadEnter | 0xE01C | 0xE075 | | - | -- | -- | | LControl | 0x1D | 0x14 | | LWin | 0xE05B | 0xE01F | | LAlt | 0x38 | 0x11 | | Spacebar | 0x39 | 0x29 | | RAltGr | 0xE038 | 0xE011 | | RWin | 0xE05C | 0xE027 | | Apps | 0xE05C | 0xE02F | | RControl | 0xE01D | 0xE014 | | ArrowLeft | 0xE04B | 0xE06B | | ArrowDown | 0xE050 | 0xE072 | | ArrowRight | 0xE04D | 0xE074 | | Numpad0 | 0x52 | 0x70 | | NumpadPeriod | 0x53 | 0x71 | | - | -- | -- | | Oem9 | 0x7B | 0x67 | | Oem10 | 0x79 | 0x64 | | Oem11 | 0x70 | 0x13 | | Oem12 | 0x73 | 0x51 | | Oem13 | 0x7D | 0x6A | | - | -- | -- | | PrevTrack | 0xE010 | 0xE015 | | NextTrack | 0xE019 | 0xE04D | | Mute | 0xE020 | 0xE023 | | Calculator | 0xE021 | 0xE02B | | Play | 0xE022 | 0xE034 | | Stop | 0xE024 | 0xE03B | | VolumeDown | 0xE02E | 0xE021 | | VolumeUp | 0xE030 | 0xE032 | | WWWHome | 0xE032 | 0xE03A | | TooManyKeys | -- | 0x00 | | PowerOnTestOk | -- | 0xAA | | RControl2 | 0xE11D | 0xE114 | | RAlt2 | 0xE02A | 0xE012 |

Note 1: PauseBreak does not have a scancode because it's something we infer from a sequence of other keypresses (NumLock with RControl2 held).

Note 2: SysReq doesn't have a key on the diagram, because the scancode is only generated when you do Alt + PrintScreen.

Minimum Supported Rust Version (MSRV)

This crate is guaranteed to compile on stable Rust 1.61 and up. It might compile with older versions but that may change in any new patch release.

Changelog

There is a changelog in CHANGELOG.md.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be licensed as above, without any additional terms or conditions.

Code of Conduct

Contribution to this crate is organized under the terms of the Rust Code of Conduct, the maintainer of this crate, the Rust Embedded Community, promises to intervene to uphold that code of conduct.