From 4fb839e6784c55fee7d5ef299139ea90f4786271 Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Tue, 16 Nov 2021 20:49:12 +0100 Subject: [PATCH] Document the `livesplit-hotkey` crate There was basically not documentation at all. --- crates/livesplit-hotkey/src/key_code.rs | 1046 ++++++++++++++++- crates/livesplit-hotkey/src/lib.rs | 16 +- crates/livesplit-hotkey/src/linux/mod.rs | 21 +- crates/livesplit-hotkey/src/macos/mod.rs | 19 +- crates/livesplit-hotkey/src/other/mod.rs | 7 + .../livesplit-hotkey/src/wasm_unknown/mod.rs | 9 + crates/livesplit-hotkey/src/wasm_web/mod.rs | 10 + crates/livesplit-hotkey/src/windows/mod.rs | 15 +- 8 files changed, 1075 insertions(+), 68 deletions(-) diff --git a/crates/livesplit-hotkey/src/key_code.rs b/crates/livesplit-hotkey/src/key_code.rs index 96af5d0e..f2199411 100644 --- a/crates/livesplit-hotkey/src/key_code.rs +++ b/crates/livesplit-hotkey/src/key_code.rs @@ -1,10 +1,10 @@ use alloc::borrow::Cow; use core::str::FromStr; -// Based on -// https://www.w3.org/TR/uievents-code/ +// This is based on the web KeyboardEvent code Values specification and the +// individual mappings are based on the following sources: // -// Also somewhat based on MDN, but it turns out to be wrong in many ways: +// MDN, but it turns out to be wrong in many ways: // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values // // Chromium's sources: @@ -13,8 +13,7 @@ use core::str::FromStr; // Firefox's sources: // https://github.com/mozilla/gecko-dev/blob/25002b534963ad95ff0c1a3dd0f906ba023ddc8e/widget/NativeKeyToDOMCodeName.h // -// Safari's sources: -// Windows: +// Safari's sources: Windows: // https://github.com/WebKit/WebKit/blob/8afe31a018b11741abdf9b4d5bb973d7c1d9ff05/Source/WebCore/platform/win/WindowsKeyNames.cpp // macOS: // https://github.com/WebKit/WebKit/blob/main/Source/WebCore/platform/mac/PlatformEventFactoryMac.mm @@ -23,267 +22,1192 @@ use core::str::FromStr; // WPE: // https://github.com/WebKit/WebKit/blob/8afe31a018b11741abdf9b4d5bb973d7c1d9ff05/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp +/// A key code represents a physical key on a keyboard and is independent of the +/// keyboard layout. The values are based on the [`UI Events KeyboardEvent code +/// Values`](https://www.w3.org/TR/uievents-code/) specification. There are some +/// additional values for Gamepad support and some browser specific values. #[derive(Debug, Eq, PartialEq, Hash, Copy, Clone, serde::Serialize, serde::Deserialize)] +#[non_exhaustive] pub enum KeyCode { - // Writing System Keys + /// `Backtick` and `~` on a US keyboard. This is the `半角/全角/漢字` + /// (`hankaku/zenkaku/kanji`) key on Japanese keyboards + /// + /// USB HID: + /// - `Keyboard Grave Accent and Tilde` `Keyboard Page 0x35` Backquote, + /// Used for both the US `\|` (on the 101-key layout) and also for the key + /// located between the `"` and `Enter` keys on row C of the 102-, 104- and + /// 106-key layouts. Labelled `#~` on a UK (102) keyboard. + /// + /// USB HID: + /// - `Keyboard \ and |` `Keyboard Page 0x31` + /// - `Keyboard Non-US # and ~` `Keyboard Page 0x32` Backslash, - Backspace, + /// `[{` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard [ and {` `Keyboard Page 0x2f` BracketLeft, + /// `]}` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard ] and }` `Keyboard Page 0x30` BracketRight, + /// `,<` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard , and <` `Keyboard Page 0x36` Comma, + /// `0)` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard 0 and )` `Keyboard Page 0x27` Digit0, + /// `1!` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard 1 and !` `Keyboard Page 0x1e` Digit1, + /// `2@` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard 2 and @` `Keyboard Page 0x1f` Digit2, + /// `3#` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard 3 and #` `Keyboard Page 0x20` Digit3, + /// `4$` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard 4 and $` `Keyboard Page 0x21` Digit4, + /// `5%` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard 5 and %` `Keyboard Page 0x22` Digit5, + /// `6^` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard 6 and ^` `Keyboard Page 0x23` Digit6, + /// `7&` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard 7 and &` `Keyboard Page 0x24` Digit7, + /// `8*` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard 8 and *` `Keyboard Page 0x25` Digit8, + /// `9(` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard 9 and (` `Keyboard Page 0x26` Digit9, + /// `=+` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard = and +` `Keyboard Page 0x2e` Equal, + /// Located between the left `Shift` and `Z` keys. Labelled `\|` on a UK + /// keyboard. + /// + /// USB HID: + /// - `Keyboard Non-US \ and |` `Keyboard Page 0x64` IntlBackslash, + /// Located between the `/` and right `Shift` keys. Labelled `\ろ` (`ro`) on + /// a Japanese keyboard. + /// + /// USB HID: + /// - `Keyboard International1` `Keyboard Page 0x87` IntlRo, + /// Located between the `=` and `Backspace` keys. Labelled `¥` (`yen`) on a + /// Japanese keyboard. `\/` on a Russian keyboard. + /// + /// USB HID: + /// - `Keyboard International3` `Keyboard Page 0x89` IntlYen, + /// `a` on a US keyboard. Labelled `q` on an AZERTY (e.g., French) keyboard. + /// + /// USB HID: + /// - `Keyboard a and A` `Keyboard Page 0x4` KeyA, + /// `b` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard b and B` `Keyboard Page 0x5` KeyB, + /// `c` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard c and C` `Keyboard Page 0x6` KeyC, + /// `d` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard d and D` `Keyboard Page 0x7` KeyD, + /// `e` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard e and E` `Keyboard Page 0x8` KeyE, + /// `f` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard f and F` `Keyboard Page 0x9` KeyF, + /// `g` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard g and G` `Keyboard Page 0xa` KeyG, + /// `h` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard h and H` `Keyboard Page 0xb` KeyH, + /// `i` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard i and I` `Keyboard Page 0xc` KeyI, + /// `j` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard j and J` `Keyboard Page 0xd` KeyJ, + /// `k` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard k and K` `Keyboard Page 0xe` KeyK, + /// `l` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard l and L` `Keyboard Page 0xf` KeyL, + /// `m` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard m and M` `Keyboard Page 0x10` KeyM, + /// `n` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard n and N` `Keyboard Page 0x11` KeyN, + /// `o` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard o and O` `Keyboard Page 0x12` KeyO, + /// `p` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard p and P` `Keyboard Page 0x13` KeyP, + /// `q` on a US keyboard. Labelled `a` on an AZERTY (e.g., French) keyboard. + /// + /// USB HID: + /// - `Keyboard q and Q` `Keyboard Page 0x14` KeyQ, + /// `r` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard r and R` `Keyboard Page 0x15` KeyR, + /// `s` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard s and S` `Keyboard Page 0x16` KeyS, + /// `t` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard t and T` `Keyboard Page 0x17` KeyT, + /// `u` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard u and U` `Keyboard Page 0x18` KeyU, + /// `v` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard v and V` `Keyboard Page 0x19` KeyV, + /// `w` on a US keyboard. Labelled `z` on an AZERTY (e.g., French) keyboard. + /// + /// USB HID: + /// - `Keyboard w and W` `Keyboard Page 0x1a` KeyW, + /// `x` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard x and X` `Keyboard Page 0x1b` KeyX, + /// `y` on a US keyboard. Labelled `z` on a QWERTZ (e.g., German) keyboard. + /// + /// USB HID: + /// - `Keyboard y and Y` `Keyboard Page 0x1c` KeyY, + /// `z` on a US keyboard. Labelled `w` on an AZERTY (e.g., French) keyboard, + /// and `y` on a QWERTZ (e.g., German) keyboard. + /// + /// USB HID: + /// - `Keyboard z and Z` `Keyboard Page 0x1d` KeyZ, + /// `-_` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard - and (underscore)` `Keyboard Page 0x2d` Minus, + /// `.>` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard . and >` `Keyboard Page 0x37` Period, + /// `'"` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard ‘ and “` `Keyboard Page 0x34` Quote, + /// `;:` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard ; and :` `Keyboard Page 0x33` Semicolon, + /// `/?` on a US keyboard. + /// + /// USB HID: + /// - `Keyboard / and ?` `Keyboard Page 0x38` Slash, - // Functional Keys + /// `Alt`, `Option` or + /// `⌥`. + /// + /// USB HID: + /// - `Keyboard LeftAlt` `Keyboard Page 0xe2` AltLeft, + /// `Alt`, `Option` or `⌥`. This is labelled `AltGr` key on many keyboard + /// layouts. + /// + /// USB HID: + /// - `Keyboard RightAlt` `Keyboard Page 0xe6` AltRight, + /// `Backspace` or `⌫`. Labelled `Delete` on Apple keyboards. + /// + /// USB HID: + /// - `Keyboard DELETE (Backspace)` `Keyboard Page 0x2a` + Backspace, + /// `CapsLock` or `⇪` + /// + /// USB HID: + /// - `Keyboard Caps Lock` `Keyboard Page 0x39` CapsLock, + /// The application context menu key, which is typically found between the + /// right `Meta` key and the right `Control` key. + /// + /// USB HID: + /// - `Keyboard Application` `Keyboard Page 0x65` ContextMenu, + /// `Control` or `⌃` + /// + /// USB HID: + /// - `Keyboard LeftControl` `Keyboard Page 0xe0` ControlLeft, + /// `Control` or `⌃` + /// + /// USB HID: + /// - `Keyboard RightControl` `Keyboard Page 0xe4` ControlRight, + /// `Enter` or `↵`. Labelled `Return` on Apple keyboards. + /// + /// USB HID: + /// - `Keyboard Return (ENTER)` `Keyboard Page 0x28` + /// - `Enter Channel` `Consumer Page 0x84` Enter, - MetaLeft, // Known as OSLeft in all Firefox versions and Chrome <52, as well as all versions of Safari GTK and WPE. - MetaRight, // Known as OSRight in all Firefox versions and Chrome <52, as well as all versions of Safari GTK and WPE. + /// The Windows, `⌘`, `Command` or other OS symbol key. + /// + /// USB HID: + /// - `Keyboard Left GUI` `Keyboard Page 0xe3` + MetaLeft, + /// The Windows, `⌘`, `Command` or other OS symbol key. + /// + /// USB HID: + /// - `Keyboard Right GUI` `Keyboard Page 0xe7` + MetaRight, + /// `Shift` or `⇧` + /// + /// USB HID: + /// - `Keyboard LeftShift` `Keyboard Page 0xe1` ShiftLeft, + /// `Shift` or `⇧` + /// + /// USB HID: + /// - `Keyboard RightShift` `Keyboard Page 0xe5` ShiftRight, + /// ` ` (space) + /// + /// USB HID: + /// - `Keyboard Spacebar` `Keyboard Page 0x2c` Space, + /// `Tab` or `⇥` + /// + /// USB HID: + /// - `Keyboard Tab` `Keyboard Page 0x2b` Tab, - // Functional Keys found on Japanese and Korean keyboards + /// Japanese: `変換` (`henkan`) + /// + /// USB HID: + /// - `Keyboard International4` `Keyboard Page 0x8a` Convert, + /// Japanese: `カタカナ/ひらがな/ローマ字` (`katakana/hiragana/romaji`) + /// + /// USB HID: + /// - `Keyboard International2` `Keyboard Page 0x88` KanaMode, + /// Korean: HangulMode `한/영` (`han/yeong`) + /// + /// Japanese (Mac keyboard): `かな` (`kana`) + /// + /// USB HID: + /// - `Keyboard LANG1` `Keyboard Page 0x90` Lang1, + /// Korean: Hanja `한자` (`hanja`) + /// + /// Japanese (Mac keyboard): `英数` (`eisu`) + /// + /// USB HID: + /// - `Keyboard LANG2` `Keyboard Page 0x91` Lang2, + /// Japanese (word-processing keyboard): Katakana + /// + /// USB HID: + /// - `Keyboard LANG3` `Keyboard Page 0x92` Lang3, + /// Japanese (word-processing keyboard): Hiragana + /// + /// USB HID: + /// - `Keyboard LANG4` `Keyboard Page 0x93` Lang4, + /// Japanese (word-processing keyboard): Zenkaku/Hankaku + /// + /// USB HID: + /// - `Keyboard LANG5` `Keyboard Page 0x94` Lang5, + /// Japanese: `無変換` (`muhenkan`) + /// + /// USB HID: + /// - `Keyboard International5` `Keyboard Page 0x8b` NonConvert, - // Control Pad Section + /// `⌦`. The forward delete key. Note that on Apple keyboards, the key + /// labelled `Delete` on the main part of the keyboard should be encoded as + /// `"Backspace"`. + /// + /// USB HID: + /// - `Keyboard Delete Forward` `Keyboard Page 0x4c` + /// - `Keyboard Clear` `Keyboard Page 0x9c` + /// - `Keypad Clear` `Keyboard Page 0xd8` + /// - `AC Delete` `Consumer Page 0x26a` Delete, + /// `Page Down`, `End` or `↘` + /// + /// USB HID: + /// - `Keyboard End` `Keyboard Page 0x4d` End, + /// `Help`. Not present on standard PC keyboards. + /// + /// USB HID: + /// - `Keyboard Help` `Keyboard Page 0x75` + /// - `Help` `Consumer Page 0x95` + /// - `AL Integrated Help Center` `Consumer Page 0x1a6` Help, + /// `Home` or `↖` + /// + /// USB HID: + /// - `Keyboard Home` `Keyboard Page 0x4a` Home, + /// `Insert` or `Ins`. Not present on Apple keyboards. + /// + /// USB HID: + /// - `Keyboard Insert` `Keyboard Page 0x49` + /// - `AC Insert Mode` `Consumer Page 0x269` Insert, + /// `Page Down`, `PgDn` or `⇟` + /// + /// USB HID: + /// - `Keyboard PageDown` `Keyboard Page 0x4e` PageDown, + /// `Page Up`, `PgUp` or + /// `⇞` + /// + /// USB HID: + /// - `Keyboard PageUp` `Keyboard Page 0x4b` PageUp, - // Arrow Pad Section + /// `↓` + /// + /// USB HID: + /// - `Keyboard DownArrow` `Keyboard Page 0x51` + /// - `Menu Down` `Consumer Page 0x43` ArrowDown, + /// `←` + /// + /// USB HID: + /// - `Keyboard LeftArrow` `Keyboard Page 0x50` + /// - `Menu Left` `Consumer Page 0x44` ArrowLeft, + /// `→` + /// + /// USB HID: + /// - `Keyboard RightArrow` `Keyboard Page 0x4f` + /// - `Menu Right` `Consumer Page 0x45` ArrowRight, + /// `↑` + /// + /// USB HID: + /// - `Keyboard UpArrow` `Keyboard Page 0x52` + /// - `Menu Up` `Consumer Page 0x42` ArrowUp, - // Numpad Section + /// On the Mac, the `"NumLock"` code should be used for the numpad `Clear` + /// key. + /// + /// USB HID: + /// - `Keypad Num Lock and Clear` `Keyboard Page 0x53` NumLock, + /// `0 Ins` on a keyboard + /// + /// `0` on a phone or remote control + /// + /// USB HID: + /// - `Keypad 0 and Insert` `Keyboard Page 0x62` + /// - `Phone Key 0` `Telephony Device Page 0xb0` Numpad0, + /// `1 End` on a keyboard + /// + /// `1` or `1 QZ` on a phone or remote control + /// + /// USB HID: + /// - `Keypad 1 and End` `Keyboard Page 0x59` + /// - `Phone Key 1` `Telephony Device Page 0xb1` Numpad1, + /// `2 ↓` on a keyboard + /// + /// `2 ABC` on a phone or remote control + /// + /// USB HID: + /// - `Keypad 2 and Down Arrow` `Keyboard Page 0x5a` + /// - `Phone Key 2` `Telephony Device Page 0xb2` Numpad2, + /// `3 PgDn` on a keyboard + /// + /// `3 DEF` on a phone or remote control + /// + /// USB HID: + /// - `Keypad 3 and PageDn` `Keyboard Page 0x5b` + /// - `Phone Key 3` `Telephony Device Page 0xb3` Numpad3, + /// `4 ←` on a keyboard + /// + /// `4 GHI` on a phone or remote control + /// + /// USB HID: + /// - `Keypad 4 and Left Arrow` `Keyboard Page 0x5c` + /// - `Phone Key 4` `Telephony Device Page 0xb4` Numpad4, + /// `5` on a keyboard + /// + /// `5 JKL` on a phone or remote control + /// + /// USB HID: + /// - `Keypad 5` `Keyboard Page 0x5d` + /// - `Phone Key 5` `Telephony Device Page 0xb5` Numpad5, + /// `6 →` on a keyboard + /// + /// `6 MNO` on a phone or remote control + /// + /// USB HID: + /// - `Keypad 6 and Right Arrow` `Keyboard Page 0x5e` + /// - `Phone Key 6` `Telephony Device Page 0xb6` Numpad6, + /// `7 Home` on a keyboard + /// + /// `7 PQRS` or `7 PRS` on a phone or remote control + /// + /// USB HID: + /// - `Keypad 7 and Home` `Keyboard Page 0x5f` + /// - `Phone Key 7` `Telephony Device Page 0xb7` Numpad7, + /// `8 ↑` on a keyboard + /// + /// `8 TUV` on a phone or remote control + /// + /// USB HID: + /// - `Keypad 8 and Up Arrow` `Keyboard Page 0x60` + /// - `Phone Key 8` `Telephony Device Page 0xb8` Numpad8, + /// `9 PgUp` on a keyboard + /// + /// `9 WXYZ` or `9 WXY` on a phone or remote control + /// + /// USB HID: + /// - `Keypad 9 and PageUp` `Keyboard Page 0x61` + /// - `Phone Key 9` `Telephony Device Page 0xb9` Numpad9, + /// `+` + /// + /// USB HID: + /// - `Keypad +` `Keyboard Page 0x57` + /// - `Menu Value Increase` `Consumer Page 0x47` NumpadAdd, - NumpadBackspace, // No browser seems to use these? - NumpadClear, // No browser seems to use these? - NumpadClearEntry, // No browser seems to use these? + /// Found on the Microsoft Natural Keyboard. + /// + /// USB HID: + /// - `Keypad Backspace` `Keyboard Page 0xbb` + NumpadBackspace, + /// `C` or `AC` (All Clear). Also for use with numpads that have a `Clear` + /// key that is separate from the `NumLock` key. On the Mac, the numpad + /// `Clear` key should always be encoded as `"NumLock"`. + /// + /// USB HID: + /// - `Keypad Clear` `Keyboard Page 0xd8` + NumpadClear, + /// `CE` (Clear Entry) + /// + /// USB HID: + /// - `Keypad Clear Entry` `Keyboard Page 0xd9` + NumpadClearEntry, + /// `,` (thousands separator). For locales where the thousands separator is + /// a "." (e.g., Brazil), this key may generate a `.`. + /// + /// USB HID: + /// - `Keypad Comma` `Keyboard Page 0x85` NumpadComma, + /// `. Del`. For locales where the decimal separator is "," (e.g., Brazil), + /// this key may generate a `,`. + /// + /// USB HID: + /// - `Keypad . and Delete` `Keyboard Page 0x63` NumpadDecimal, + /// `/` + /// + /// USB HID: + /// - `Keypad /` `Keyboard Page 0x54` NumpadDivide, + /// USB HID: + /// - `Keypad ENTER` `Keyboard Page 0x58` NumpadEnter, + /// `=` + /// + /// USB HID: + /// - `Keypad =` `Keyboard Page 0x67` NumpadEqual, - NumpadHash, // No browser seems to use these? - NumpadMemoryAdd, // No browser seems to use these? - NumpadMemoryClear, // No browser seems to use these? - NumpadMemoryRecall, // No browser seems to use these? - NumpadMemoryStore, // No browser seems to use these? - NumpadMemorySubtract, // No browser seems to use these? + /// `#` on a phone or remote control device. This key is typically found + /// below the `9` key and to the right of the `0` key. + /// + /// USB HID: + /// - `Phone Key Pound` `Telephony Device Page 0xbb` + NumpadHash, + /// `M+` Add current entry to the value stored in memory. + /// + /// USB HID: + /// - `Keypad Memory Add` `Keyboard Page 0xd3` + NumpadMemoryAdd, + /// `MC` Clear the value stored in memory. + /// + /// USB HID: + /// - `Keypad Memory Clear` `Keyboard Page 0xd2` + NumpadMemoryClear, + /// `MR` Replace the current entry with the value stored in memory. + /// + /// USB HID: + /// - `Keypad Memory Recall` `Keyboard Page 0xd1` + NumpadMemoryRecall, + /// `MS` Replace the value stored in memory with the current entry. + /// + /// USB HID: + /// - `Keypad Memory Store` `Keyboard Page 0xd0` + NumpadMemoryStore, + /// `M-` Subtract current entry from the value + /// stored in memory. + /// + /// USB HID: + /// - `Keypad Memory Subtract` `Keyboard Page 0xd4` + NumpadMemorySubtract, + /// `*` on a keyboard. For use with numpads that provide mathematical + /// operations (`+`, `-`, `*` and `/`). + /// + /// Use [`KeyCode::NumpadStar`] for the `*` key on phones and remote controls. + /// + /// USB HID: + /// - `Keypad *` `Keyboard Page 0x55` NumpadMultiply, + /// `(` Found on the Microsoft Natural Keyboard. + /// + /// USB HID: + /// - `Keypad (` `Keyboard Page 0xb6` NumpadParenLeft, + /// `)` Found on the Microsoft Natural Keyboard. + /// + /// USB HID: + /// - `Keypad )` `Keyboard Page 0xb7` NumpadParenRight, - NumpadStar, // No browser seems to use these? + /// `*` on a phone or remote control device. This key is typically found + /// below the `7` key and to the left of the `0` key. + /// + /// Use [`KeyCode::NumpadMultiply`] for the `*` key on numeric keypads. + /// + /// USB HID: + /// - `Phone Key Star` `Telephony Device Page 0xba` + NumpadStar, + /// `-` + /// + /// USB HID: + /// - `Keypad -` `Keyboard Page 0x56` + /// - `Menu Value Decrease` `Consumer Page 0x48` NumpadSubtract, - // Function Section + /// `Esc` or `⎋` + /// + /// USB HID: + /// - `Keyboard ESCAPE` `Keyboard Page 0x29` + /// - `Menu Escape` `Consumer Page 0x46` Escape, + /// `F1` + /// + /// USB HID: + /// - `Keyboard F1` `Keyboard Page 0x3a` F1, + /// `F2` + /// + /// USB HID: + /// - `Keyboard F2` `Keyboard Page 0x3b` F2, + /// `F3` + /// + /// USB HID: + /// - `Keyboard F3` `Keyboard Page 0x3c` F3, + /// `F4` + /// + /// USB HID: + /// - `Keyboard F4` `Keyboard Page 0x3d` F4, + /// `F5` + /// + /// USB HID: + /// - `Keyboard F5` `Keyboard Page 0x3e` F5, + /// `F6` + /// + /// USB HID: + /// - `Keyboard F6` `Keyboard Page 0x3f` F6, + /// `F7` + /// + /// USB HID: + /// - `Keyboard F7` `Keyboard Page 0x40` F7, + /// `F8` + /// + /// USB HID: + /// - `Keyboard F8` `Keyboard Page 0x41` F8, + /// `F9` + /// + /// USB HID: + /// - `Keyboard F9` `Keyboard Page 0x42` F9, + /// `F10` + /// + /// USB HID: + /// - `Keyboard F10` `Keyboard Page 0x43` F10, + /// `F11` + /// + /// USB HID: + /// - `Keyboard F11` `Keyboard Page 0x44` F11, + /// `F12` + /// + /// USB HID: + /// - `Keyboard F12` `Keyboard Page 0x45` F12, + /// `F13` + /// + /// USB HID: + /// - `Keyboard F13` `Keyboard Page 0x68` F13, + /// `F14` + /// + /// USB HID: + /// - `Keyboard F14` `Keyboard Page 0x69` F14, + /// `F15` + /// + /// USB HID: + /// - `Keyboard F15` `Keyboard Page 0x6a` F15, + /// `F16` + /// + /// USB HID: + /// - `Keyboard F16` `Keyboard Page 0x6b` F16, + /// `F17` + /// + /// USB HID: + /// - `Keyboard F17` `Keyboard Page 0x6c` F17, + /// `F18` + /// + /// USB HID: + /// - `Keyboard F18` `Keyboard Page 0x6d` F18, + /// `F19` + /// + /// USB HID: + /// - `Keyboard F19` `Keyboard Page 0x6e` F19, + /// `F20` + /// + /// USB HID: + /// - `Keyboard F20` `Keyboard Page 0x6f` F20, + /// `F21` + /// + /// USB HID: + /// - `Keyboard F21` `Keyboard Page 0x70` F21, + /// `F22` + /// + /// USB HID: + /// - `Keyboard F22` `Keyboard Page 0x71` F22, + /// `F23` + /// + /// USB HID: + /// - `Keyboard F23` `Keyboard Page 0x72` F23, + /// `F24` + /// + /// USB HID: + /// - `Keyboard F24` `Keyboard Page 0x73` F24, + /// `Fn` This is typically a hardware key that does not generate a separate + /// code. Most keyboards do not place this key in the function section, but + /// it is included here to keep it with related keys. + /// + /// USB HID: + /// Fn, - FnLock, // No browser seems to use this? + /// `FLock` or `FnLock`. Function Lock key. Found on the Microsoft Natural + /// Keyboard. + /// + /// USB HID: + /// + FnLock, + /// `PrtScr SysRq` or `Print Screen` + /// + /// USB HID: + /// - `Keyboard PrintScreen` `Keyboard Page 0x46` PrintScreen, + /// `Scroll Lock` + /// + /// USB HID: + /// - `Keyboard Scroll Lock` `Keyboard Page 0x47` ScrollLock, + /// `Pause Break` + /// + /// USB HID: + /// - `Keyboard Pause` `Keyboard Page 0x48` + /// - `Pause` `Consumer Page 0xb1` Pause, - // Media Keys + /// Some laptops place this key to the left of the `↑` key. + /// + /// USB HID: + /// - `Reserved` `Keyboard Page 0xf1` + /// - `AC Back` `Consumer Page 0x224` BrowserBack, + /// USB HID: + /// - `AL Programmable Button Configuration` `Consumer Page 0x182` + /// - `AC Bookmarks` `Consumer Page 0x22a` BrowserFavorites, + /// Some laptops place this key to the right of the `↑` key. + /// + /// USB HID: + /// - `Reserved` `Keyboard Page 0xf2` + /// - `AC Forward` `Consumer Page 0x225` BrowserForward, + /// USB HID: + /// - `AC Home` `Consumer Page 0x223` BrowserHome, + /// USB HID: + /// - `Reserved` `Keyboard Page 0xfa` + /// - `AC Refresh` `Consumer Page 0x227` BrowserRefresh, + /// USB HID: + /// - `AC Search` `Consumer Page 0x221` BrowserSearch, + /// USB HID: + /// - `Keyboard Stop` `Keyboard Page 0x78` + /// - `Reserved` `Keyboard Page 0xf3` + /// - `AC Stop` `Consumer Page 0x226` BrowserStop, + /// `Eject` or `⏏`. This key is placed in the function section on some Apple + /// keyboards. + /// + /// USB HID: + /// - `Reserved` `Keyboard Page 0xec` + /// - `Eject` `Consumer Page 0xb8` Eject, + /// Sometimes labelled `My Computer` on the keyboard + /// + /// USB HID: + /// - `AL Local Machine Browser` `Consumer Page 0x194` + /// - `AL File Browser` `Consumer Page 0x1b4` LaunchApp1, + /// Sometimes labelled `Calculator` on the keyboard + /// + /// USB HID: + /// - `Reserved` `Keyboard Page 0xfb` + /// - `AL Calculator` `Consumer Page 0x192` LaunchApp2, + /// USB HID: + /// - `AL Email Reader` `Consumer Page 0x18a` LaunchMail, + /// USB HID: + /// - `Reserved` `Keyboard Page 0xe8` + /// - `Play/Pause` `Consumer Page 0xcd` MediaPlayPause, + /// USB HID: + /// - `AL Consumer Control Configuration` `Consumer Page 0x183` MediaSelect, + /// USB HID: + /// - `Reserved` `Keyboard Page 0xe9` + /// - `Stop` `Consumer Page 0xb7` MediaStop, + /// USB HID: + /// - `Reserved` `Keyboard Page 0xeb` + /// - `Scan Next Track` `Consumer Page 0xb5` MediaTrackNext, + /// USB HID: + /// - `Reserved` `Keyboard Page 0xea` + /// - `Scan Previous Track` `Consumer Page 0xb6` MediaTrackPrevious, + /// This key is placed in the function section on some Apple keyboards, + /// replacing the `Eject` key. + /// + /// USB HID: + /// - `Keyboard Power` `Keyboard Page 0x66` + /// - `Power` `Consumer Page 0x30` Power, + /// USB HID: + /// - `Reserved` `Keyboard Page 0xf8` + /// - `Sleep` `Consumer Page 0x32` + /// - `Sleep Mode` `Consumer Page 0x34` Sleep, + /// USB HID: + /// - `Keyboard Volume Down` `Keyboard Page 0x81` + /// - `Reserved` `Keyboard Page 0xee` + /// - `Volume Decrement` `Consumer Page 0xea` AudioVolumeDown, + /// USB HID: + /// - `Keyboard Mute` `Keyboard Page 0x7f` + /// - `Reserved` `Keyboard Page 0xef` + /// - `Mute` `Consumer Page 0xe2` AudioVolumeMute, + /// USB HID: + /// - `Keyboard Volume Up` `Keyboard Page 0x80` + /// - `Reserved` `Keyboard Page 0xed` + /// - `Volume Increment` `Consumer Page 0xe9` AudioVolumeUp, + /// USB HID: + /// - `System Wake Up` `Generic Desktop Page 0x83` WakeUp, - // Legacy, Non-Standard and Special Keys + /// Found on Sun’s USB keyboard. + /// + /// USB HID: + /// - `Keyboard Again` `Keyboard Page 0x79` Again, + /// Found on Sun’s USB keyboard. + /// + /// USB HID: + /// - `Keyboard Copy` `Keyboard Page 0x7c` + /// - `AC Copy` `Consumer Page 0x21b` Copy, + /// Found on Sun’s USB keyboard. + /// + /// USB HID: + /// - `Keyboard Cut` `Keyboard Page 0x7b` + /// - `AC Cut` `Consumer Page 0x21c` Cut, + /// Found on Sun’s USB keyboard. + /// + /// USB HID: + /// - `Keyboard Find` `Keyboard Page 0x7e` + /// - `Reserved` `Keyboard Page 0xf4` + /// - `AC Find` `Consumer Page 0x21f` Find, + /// Found on Sun’s USB keyboard. + /// + /// USB HID: + /// - `Keyboard Execute` `Keyboard Page 0x74` + /// - `AC Open` `Consumer Page 0x202` Open, + /// Found on Sun’s USB keyboard. + /// + /// USB HID: + /// - `Keyboard Paste` `Keyboard Page 0x7d` + /// - `AC Paste` `Consumer Page 0x21d` Paste, + /// Found on Sun’s USB keyboard. + /// + /// USB HID: + /// - `Keyboard Menu` `Keyboard Page 0x76` + /// - `AC Properties` `Consumer Page 0x209` Props, + /// Found on Sun’s USB keyboard. + /// + /// USB HID: + /// - `Keyboard Select` `Keyboard Page 0x77` Select, + /// Found on Sun’s USB keyboard. + /// + /// USB HID: + /// - `Keyboard Undo` `Keyboard Page 0x7a` + /// - `AC Undo` `Consumer Page 0x21a` Undo, - // Gamepad Keys + /// USB HID: + /// - `Button 1 (primary/trigger)` `Button Page 0x1` Gamepad0, + /// USB HID: + /// - `Button 2 (secondary)` `Button Page 0x2` Gamepad1, + /// USB HID: + /// - `Button 3 (tertiary)` `Button Page 0x3` Gamepad2, + /// USB HID: + /// - `Button 4` `Button Page 0x4` Gamepad3, + /// USB HID: + /// - `Button 5` `Button Page 0x5` Gamepad4, + /// USB HID: + /// - `Button 6` `Button Page 0x6` Gamepad5, + /// USB HID: + /// - `Button 7` `Button Page 0x7` Gamepad6, + /// USB HID: + /// - `Button 8` `Button Page 0x8` Gamepad7, + /// USB HID: + /// - `Button 9` `Button Page 0x9` Gamepad8, + /// USB HID: + /// - `Button 10` `Button Page 0xa` Gamepad9, + /// USB HID: + /// - `Button 11` `Button Page 0xb` Gamepad10, + /// USB HID: + /// - `Button 12` `Button Page 0xc` Gamepad11, + /// USB HID: + /// - `Button 13` `Button Page 0xd` Gamepad12, + /// USB HID: + /// - `Button 14` `Button Page 0xe` Gamepad13, + /// USB HID: + /// - `Button 15` `Button Page 0xf` Gamepad14, + /// USB HID: + /// - `Button 16` `Button Page 0x10` Gamepad15, + /// USB HID: + /// - `Button 17` `Button Page 0x11` Gamepad16, + /// USB HID: + /// - `Button 18` `Button Page 0x12` Gamepad17, + /// USB HID: + /// - `Button 19` `Button Page 0x13` Gamepad18, + /// USB HID: + /// - `Button 20` `Button Page 0x14` Gamepad19, - // Chrome only Keys + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `Display Brightness Decrement` `Consumer Page 0x70` BrightnessDown, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `Display Brightness Increment` `Consumer Page 0x6f` BrightnessUp, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `System Display Toggle Int/Ext Mode` `Generic Desktop Page 0xb5` DisplayToggleIntExt, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `AC Next Keyboard Layout Select` `Consumer Page 0x29d` KeyboardLayoutSelect, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `AL Context-aware Desktop Assistant` `Consumer Page 0x1cb` LaunchAssistant, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `AL Control Panel` `Consumer Page 0x19f` LaunchControlPanel, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `AL Screen Saver` `Consumer Page 0x1b1` LaunchScreenSaver, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `AC Forward Msg` `Consumer Page 0x28b` MailForward, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `AC Reply` `Consumer Page 0x289` MailReply, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `AC Send` `Consumer Page 0x28c` MailSend, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `Fast Forward` `Consumer Page 0xb3` MediaFastForward, - MediaPause, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `Play` `Consumer Page 0xb0` MediaPlay, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `Pause` `Consumer Page 0xb1` + MediaPause, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `Record` `Consumer Page 0xb2` MediaRecord, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `Rewind` `Consumer Page 0xb4` MediaRewind, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `Phone Mute` `Telephony Device Page 0x2f` + MicrophoneMuteToggle, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `Privacy Screen Toggle` `Consumer Page 0x2d0` PrivacyScreenToggle, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `AL Select Task/Application` `Consumer Page 0x1a2` SelectTask, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `AC Desktop Show All Windows` `Consumer Page 0x29f` ShowAllWindows, + /// Non-standard code value supported by Chromium. + /// + /// USB HID: + /// - `AC View Toggle` `Consumer Page 0x232` ZoomToggle, } +/// Every [`KeyCode`] is grouped into one of these classes. #[derive(Debug, Eq, PartialEq, Hash, Copy, Clone, serde::Serialize, serde::Deserialize)] pub enum KeyCodeClass { + /// The *writing system keys* are those that change meaning (i.e., they + /// produce different key values) based on the current locale and keyboard + /// layout. WritingSystem, + /// The *functional keys* (not to be confused with the [function + /// keys](KeyCodeClass::Function) described later) are those keys in the + /// alphanumeric section that provide general editing functions that are + /// common to all locales (like `Shift`, `Tab`, `Enter` and `Backspace`). + /// With a few exceptions, these keys do not change meaning based on the + /// current keyboard layout. Functional, + /// The *control pad* section of the keyboard is the set of (usually 6) keys + /// that perform navigating and editing operations, for example, `Home`, + /// `PageUp` and `Insert`. ControlPad, + /// The *arrow pad* contains the 4 arrow keys. The keys are commonly + /// arranged in an "upside-down T" configuration. ArrowPad, + /// The *numpad section* is the set of keys on the keyboard arranged in a + /// grid like a calculator or mobile phone. This section contains numeric + /// and mathematical operator keys. Often this section will contain a + /// `NumLock` key which causes the keys to switch between the standard + /// numeric functions and mimicking the keys of the [control + /// pad](KeyCodeClass::ControlPad) and arrow pad. Laptop computers and + /// compact keyboards will commonly omit these keys to save space. Numpad, + /// The *function section* runs along the top of the keyboard (above the + /// alphanumeric section) and contains the function keys and a few + /// additional special keys (for example, `Esc` and `Print Screen`). Function, + /// *Media keys* are extra keys added to a keyboard that provide media related + /// functionality like play, pause or volume control. These keys do not have + /// a standard location on the keyboard so keyboards from different + /// manufacturers are likely to have a different arrangement of keys or a + /// completely different sets of keys. Media, + /// These keys are not found on modern standard keyboards. They are listed + /// here for reference purposes. Legacy, + /// These buttons are found on gamepads. Gamepad, + /// These keys are supported by some browsers. NonStandard, } impl KeyCode { /// Resolve the KeyCode according to the standard US layout. - pub fn as_str(self) -> &'static str { + pub const fn as_str(self) -> &'static str { use self::KeyCode::*; match self { Backquote => "`", Backslash => r"\", - Backspace => "⌫", BracketLeft => "[", BracketRight => "]", Comma => ",", @@ -334,6 +1258,7 @@ impl KeyCode { Slash => "/", AltLeft => "Alt Left", AltRight => "Alt Right", + Backspace => "⌫", CapsLock => "⇪", ContextMenu => "Context Menu", ControlLeft => "Control Left", @@ -491,6 +1416,7 @@ impl KeyCode { MediaPlay => "▶", MediaRecord => "⏺", MediaRewind => "⏪", + MicrophoneMuteToggle => "Microphone Mute Toggle", PrivacyScreenToggle => "Privacy Screen Toggle", SelectTask => "Select Task", ShowAllWindows => "Show All Windows", @@ -498,21 +1424,24 @@ impl KeyCode { } } - pub fn classify(self) -> KeyCodeClass { + /// Classifies a key based on its grouping on the Keyboard. + pub const fn classify(self) -> KeyCodeClass { use self::KeyCode::*; match self { // Writing System Keys - Backquote | Backslash | Backspace | BracketLeft | BracketRight | Comma | Digit0 - | Digit1 | Digit2 | Digit3 | Digit4 | Digit5 | Digit6 | Digit7 | Digit8 | Digit9 - | Equal | IntlBackslash | IntlRo | IntlYen | KeyA | KeyB | KeyC | KeyD | KeyE - | KeyF | KeyG | KeyH | KeyI | KeyJ | KeyK | KeyL | KeyM | KeyN | KeyO | KeyP | KeyQ - | KeyR | KeyS | KeyT | KeyU | KeyV | KeyW | KeyX | KeyY | KeyZ | Minus | Period - | Quote | Semicolon | Slash => KeyCodeClass::WritingSystem, + Backquote | Backslash | BracketLeft | BracketRight | Comma | Digit0 | Digit1 + | Digit2 | Digit3 | Digit4 | Digit5 | Digit6 | Digit7 | Digit8 | Digit9 | Equal + | IntlBackslash | IntlRo | IntlYen | KeyA | KeyB | KeyC | KeyD | KeyE | KeyF | KeyG + | KeyH | KeyI | KeyJ | KeyK | KeyL | KeyM | KeyN | KeyO | KeyP | KeyQ | KeyR | KeyS + | KeyT | KeyU | KeyV | KeyW | KeyX | KeyY | KeyZ | Minus | Period | Quote + | Semicolon | Slash => KeyCodeClass::WritingSystem, // Functional Keys - AltLeft | AltRight | CapsLock | ContextMenu | ControlLeft | ControlRight | Enter - | MetaLeft | MetaRight | ShiftLeft | ShiftRight | Space | Tab | Convert | KanaMode - | Lang1 | Lang2 | Lang3 | Lang4 | Lang5 | NonConvert => KeyCodeClass::Functional, + AltLeft | AltRight | Backspace | CapsLock | ContextMenu | ControlLeft + | ControlRight | Enter | MetaLeft | MetaRight | ShiftLeft | ShiftRight | Space + | Tab | Convert | KanaMode | Lang1 | Lang2 | Lang3 | Lang4 | Lang5 | NonConvert => { + KeyCodeClass::Functional + } // Control Pad Section Delete | End | Help | Home | Insert | PageDown | PageUp => KeyCodeClass::ControlPad, @@ -559,12 +1488,12 @@ impl KeyCode { BrightnessDown | BrightnessUp | DisplayToggleIntExt | KeyboardLayoutSelect | LaunchAssistant | LaunchControlPanel | LaunchScreenSaver | MailForward | MailReply | MailSend | MediaFastForward | MediaPause | MediaPlay | MediaRecord - | MediaRewind | PrivacyScreenToggle | SelectTask | ShowAllWindows | ZoomToggle => { - KeyCodeClass::NonStandard - } + | MediaRewind | MicrophoneMuteToggle | PrivacyScreenToggle | SelectTask + | ShowAllWindows | ZoomToggle => KeyCodeClass::NonStandard, } } + /// Resolves the key according to the current keyboard layout. pub fn resolve(self) -> Cow<'static, str> { let class = self.classify(); if class == KeyCodeClass::WritingSystem { @@ -589,7 +1518,6 @@ impl FromStr for KeyCode { // Writing System Keys "Backquote" => Backquote, "Backslash" => Backslash, - "Backspace" => Backspace, "BracketLeft" => BracketLeft, "BracketRight" => BracketRight, "Comma" => Comma, @@ -642,6 +1570,7 @@ impl FromStr for KeyCode { // Functional Keys "AltLeft" => AltLeft, "AltRight" => AltRight, + "Backspace" => Backspace, "CapsLock" => CapsLock, "ContextMenu" => ContextMenu, "ControlLeft" => ControlLeft, @@ -695,24 +1624,24 @@ impl FromStr for KeyCode { "Numpad8" => Numpad8, "Numpad9" => Numpad9, "NumpadAdd" => NumpadAdd, - "NumpadBackspace" => NumpadBackspace, // No browser seems to use these? - "NumpadClear" => NumpadClear, // No browser seems to use these? - "NumpadClearEntry" => NumpadClearEntry, // No browser seems to use these? + "NumpadBackspace" => NumpadBackspace, // Not exposed by any OS. + "NumpadClear" => NumpadClear, // Not exposed by any OS. + "NumpadClearEntry" => NumpadClearEntry, // Not exposed by any OS. "NumpadComma" => NumpadComma, "NumpadDecimal" => NumpadDecimal, "NumpadDivide" => NumpadDivide, "NumpadEnter" => NumpadEnter, "NumpadEqual" => NumpadEqual, - "NumpadHash" => NumpadHash, // No browser seems to use these? - "NumpadMemoryAdd" => NumpadMemoryAdd, // No browser seems to use these? - "NumpadMemoryClear" => NumpadMemoryClear, // No browser seems to use these? - "NumpadMemoryRecall" => NumpadMemoryRecall, // No browser seems to use these? - "NumpadMemoryStore" => NumpadMemoryStore, // No browser seems to use these? - "NumpadMemorySubtract" => NumpadMemorySubtract, // No browser seems to use these? + "NumpadHash" => NumpadHash, // Not exposed by any OS. + "NumpadMemoryAdd" => NumpadMemoryAdd, // Not exposed by any OS. + "NumpadMemoryClear" => NumpadMemoryClear, // Not exposed by any OS. + "NumpadMemoryRecall" => NumpadMemoryRecall, // Not exposed by any OS. + "NumpadMemoryStore" => NumpadMemoryStore, // Not exposed by any OS. + "NumpadMemorySubtract" => NumpadMemorySubtract, // Not exposed by any OS. "NumpadMultiply" => NumpadMultiply, "NumpadParenLeft" => NumpadParenLeft, "NumpadParenRight" => NumpadParenRight, - "NumpadStar" => NumpadStar, // No browser seems to use these? + "NumpadStar" => NumpadStar, // Not exposed by any OS. "NumpadSubtract" => NumpadSubtract, // Function Section @@ -742,7 +1671,7 @@ impl FromStr for KeyCode { "F23" => F23, "F24" => F24, "Fn" => Fn, - "FnLock" => FnLock, // No browser seems to use these? + "FnLock" => FnLock, // Not exposed by any OS. "PrintScreen" => PrintScreen, "ScrollLock" => ScrollLock, "Pause" => Pause, @@ -823,6 +1752,7 @@ impl FromStr for KeyCode { "MediaPlay" => MediaPlay, "MediaRecord" => MediaRecord, "MediaRewind" => MediaRewind, + "MicrophoneMuteToggle" => MicrophoneMuteToggle, "PrivacyScreenToggle" => PrivacyScreenToggle, "SelectTask" => SelectTask, "ShowAllWindows" => ShowAllWindows, diff --git a/crates/livesplit-hotkey/src/lib.rs b/crates/livesplit-hotkey/src/lib.rs index cfa3e64e..2117f40b 100644 --- a/crates/livesplit-hotkey/src/lib.rs +++ b/crates/livesplit-hotkey/src/lib.rs @@ -1,7 +1,19 @@ -// For js! macro. -#![recursion_limit = "1024"] +#![warn( + clippy::complexity, + clippy::correctness, + clippy::perf, + clippy::style, + missing_docs, + rust_2018_idioms +)] #![cfg_attr(not(feature = "std"), no_std)] +//! `livesplit-hotkey` is a crate that allows listening to hotkeys even when the +//! application is not in focus. The crate currently supports Windows, macOS, +//! Linux and the web via wasm-bindgen. On unsupported platforms the crate still +//! compiles but uses a stubbed out implementation instead that never receives +//! any hotkeys. + extern crate alloc; cfg_if::cfg_if! { diff --git a/crates/livesplit-hotkey/src/linux/mod.rs b/crates/livesplit-hotkey/src/linux/mod.rs index a0e9b0d2..638d8b00 100644 --- a/crates/livesplit-hotkey/src/linux/mod.rs +++ b/crates/livesplit-hotkey/src/linux/mod.rs @@ -9,15 +9,23 @@ use std::{ thread::{self, JoinHandle}, }; +/// The error type for this crate. #[derive(Debug, Copy, Clone, snafu::Snafu)] +#[non_exhaustive] pub enum Error { - EPoll, - ThreadStopped, + /// The hotkey was already registered. AlreadyRegistered, + /// The hotkey to unregister was not registered. NotRegistered, + /// Failed fetching events from evdev. EvDev, + /// Failed polling the event file descriptors. + EPoll, + /// The background thread stopped unexpectedly. + ThreadStopped, } +/// The result type for this crate. pub type Result = std::result::Result; enum Message { @@ -33,6 +41,7 @@ enum Message { // Low numbered tokens are allocated to devices. const PING_TOKEN: Token = Token(usize::MAX); +/// A hook allows you to listen to hotkeys. pub struct Hook { sender: Sender, waker: Waker, @@ -49,7 +58,7 @@ impl Drop for Hook { } } -fn code_for(key: KeyCode) -> Option { +const fn code_for(key: KeyCode) -> Option { // This mapping is based on all the different browsers. They however all use // the X11 scan codes. Fortunately those have a trivial 1:1 mapping to evdev // scan codes. @@ -57,6 +66,8 @@ fn code_for(key: KeyCode) -> Option { // You simply need to subtract 8 from the X11 scan code to get to the evdev // scan code. So we take the mapping from the browsers, subtract 8 from each // value and then use the named constant for that value. + // The USB HID to scan code translation in Linux is this table: + // https://github.com/torvalds/linux/blob/fe91c4725aeed35023ba4f7a1e1adfebb6878c23/drivers/hid/hid-input.c#L27-L44 use self::KeyCode::*; Some(match key { Escape => Key::KEY_ESC, @@ -234,6 +245,7 @@ fn code_for(key: KeyCode) -> Option { MailSend => Key::KEY_SEND, // Chrome only MailReply => Key::KEY_REPLY, // Chrome only MailForward => Key::KEY_FORWARDMAIL, // Chrome only + MicrophoneMuteToggle => Key::KEY_MICMUTE, // Chrome only ZoomToggle => Key::KEY_ZOOM, // Chrome only LaunchControlPanel => Key::KEY_CONTROLPANEL, // Chrome only SelectTask => Key::KEY_APPSELECT, // Chrome only @@ -272,6 +284,7 @@ fn code_for(key: KeyCode) -> Option { } impl Hook { + /// Creates a new hook. pub fn new() -> Result { let (sender, receiver) = channel(); let mut poll = Poll::new().map_err(|_| Error::EPoll)?; @@ -353,6 +366,7 @@ impl Hook { }) } + /// Registers a hotkey to listen to. pub fn register(&self, hotkey: KeyCode, callback: F) -> Result<()> where F: FnMut() + Send + 'static, @@ -368,6 +382,7 @@ impl Hook { future.value().ok_or(Error::ThreadStopped)? } + /// Unregisters a previously registered hotkey. pub fn unregister(&self, hotkey: KeyCode) -> Result<()> { let (future, promise) = future_promise(); diff --git a/crates/livesplit-hotkey/src/macos/mod.rs b/crates/livesplit-hotkey/src/macos/mod.rs index 4850a7fe..d75f9ef2 100644 --- a/crates/livesplit-hotkey/src/macos/mod.rs +++ b/crates/livesplit-hotkey/src/macos/mod.rs @@ -28,16 +28,25 @@ use std::{ thread, }; +/// The error type for this crate. #[derive(Debug, snafu::Snafu)] +#[non_exhaustive] pub enum Error { + /// The hotkey was already registered. AlreadyRegistered, + /// The hotkey to unregister was not registered. NotRegistered, + /// Failed creating the event tap. CouldntCreateEventTap, + /// Failed creating the run loop source. CouldntCreateRunLoopSource, + /// Failed getting the current run loop. CouldntGetCurrentRunLoop, + /// The background thread stopped unexpectedly. ThreadStoppedUnexpectedly, } +/// The result type for this crate. pub type Result = std::result::Result; struct Owned(*mut T); @@ -57,6 +66,7 @@ unsafe impl Send for RunLoop {} type RegisteredKeys = Mutex>>; +/// A hook allows you to listen to hotkeys. pub struct Hook { event_loop: RunLoop, hotkeys: Arc, @@ -75,6 +85,7 @@ impl Drop for Hook { } impl Hook { + /// Creates a new hook. pub fn new() -> Result { let hotkeys = Arc::new(Mutex::new(HashMap::new())); let thread_hotkeys = hotkeys.clone(); @@ -135,6 +146,7 @@ impl Hook { }) } + /// Registers a hotkey to listen to. pub fn register(&self, hotkey: KeyCode, callback: F) -> Result<()> where F: FnMut() + Send + 'static, @@ -147,6 +159,7 @@ impl Hook { } } + /// Unregisters a previously registered hotkey. pub fn unregister(&self, hotkey: KeyCode) -> Result<()> { if self.hotkeys.lock().remove(&hotkey).is_some() { Ok(()) @@ -281,8 +294,9 @@ unsafe extern "C" fn callback( 0x6E => KeyCode::ContextMenu, // Missing on MDN 0x6F => KeyCode::F12, 0x71 => KeyCode::F15, - // `Help` sometimes replaces the `Insert` key on mac keyboards, Chrome prefers `Insert`. - 0x72 => KeyCode::Help, + // Apple hasn't been producing any keyboards with `Help` anymore since + // 2007. So this can be considered Insert instead. + 0x72 => KeyCode::Insert, 0x73 => KeyCode::Home, 0x74 => KeyCode::PageUp, 0x75 => KeyCode::Delete, @@ -337,7 +351,6 @@ pub(crate) fn try_resolve(key_code: KeyCode) -> Option { let key_code = match key_code { KeyCode::Backquote => 0x32, KeyCode::Backslash => 0x2A, - KeyCode::Backspace => 0x33, KeyCode::BracketLeft => 0x21, KeyCode::BracketRight => 0x1E, KeyCode::Comma => 0x2B, diff --git a/crates/livesplit-hotkey/src/other/mod.rs b/crates/livesplit-hotkey/src/other/mod.rs index 463b19a6..27740d56 100644 --- a/crates/livesplit-hotkey/src/other/mod.rs +++ b/crates/livesplit-hotkey/src/other/mod.rs @@ -1,18 +1,24 @@ use crate::KeyCode; use alloc::string::String; +/// The error type for this crate. #[derive(Debug, snafu::Snafu)] +#[non_exhaustive] pub enum Error {} +/// The result type for this crate. pub type Result = core::result::Result; +/// A hook allows you to listen to hotkeys. pub struct Hook; impl Hook { + /// Creates a new hook. pub fn new() -> Result { Ok(Hook) } + /// Registers a hotkey to listen to. pub fn register(&self, _: KeyCode, _: F) -> Result<()> where F: FnMut() + Send + 'static, @@ -20,6 +26,7 @@ impl Hook { Ok(()) } + /// Unregisters a previously registered hotkey. pub fn unregister(&self, _: KeyCode) -> Result<()> { Ok(()) } diff --git a/crates/livesplit-hotkey/src/wasm_unknown/mod.rs b/crates/livesplit-hotkey/src/wasm_unknown/mod.rs index b258e68b..de418382 100644 --- a/crates/livesplit-hotkey/src/wasm_unknown/mod.rs +++ b/crates/livesplit-hotkey/src/wasm_unknown/mod.rs @@ -5,16 +5,22 @@ use std::{ sync::{Arc, Mutex}, }; +/// The error type for this crate. #[derive(Debug, snafu::Snafu)] +#[non_exhaustive] pub enum Error { + /// The hotkey was already registered. AlreadyRegistered, + /// The hotkey to unregister was not registered. NotRegistered, } +/// The result type for this crate. pub type Result = std::result::Result; pub type EventListenerHandle = Box; +/// A hook allows you to listen to hotkeys. pub struct Hook { hotkeys: Arc>>>, event: Option>, @@ -46,6 +52,7 @@ pub unsafe extern "C" fn HotkeyHook_callback( } impl Hook { + /// Creates a new hook. pub fn new() -> Result { let hotkeys = Arc::new(Mutex::new(HashMap::< KeyCode, @@ -71,6 +78,7 @@ impl Hook { }) } + /// Registers a hotkey to listen to. pub fn register(&self, hotkey: KeyCode, callback: F) -> Result<()> where F: FnMut() + Send + 'static, @@ -83,6 +91,7 @@ impl Hook { } } + /// Unregisters a previously registered hotkey. pub fn unregister(&self, hotkey: KeyCode) -> Result<()> { if self.hotkeys.lock().unwrap().remove(&hotkey).is_some() { Ok(()) diff --git a/crates/livesplit-hotkey/src/wasm_web/mod.rs b/crates/livesplit-hotkey/src/wasm_web/mod.rs index 3a46e39a..1203aa65 100644 --- a/crates/livesplit-hotkey/src/wasm_web/mod.rs +++ b/crates/livesplit-hotkey/src/wasm_web/mod.rs @@ -8,15 +8,22 @@ use std::{ sync::{Arc, Mutex}, }; +/// The error type for this crate. #[derive(Debug, snafu::Snafu)] +#[non_exhaustive] pub enum Error { + /// The hotkey was already registered. AlreadyRegistered, + /// The hotkey to unregister was not registered. NotRegistered, + /// Failed creating the hook. FailedToCreateHook, } +/// The result type for this crate. pub type Result = std::result::Result; +/// A hook allows you to listen to hotkeys. pub struct Hook { hotkeys: Arc>>>, keyboard_callback: Closure, @@ -63,6 +70,7 @@ static GAMEPAD_BUTTONS: [KeyCode; TOTAL_BUTTONS] = [ ]; impl Hook { + /// Creates a new hook. pub fn new() -> Result { let hotkeys = Arc::new(Mutex::new(HashMap::< KeyCode, @@ -130,6 +138,7 @@ impl Hook { }) } + /// Registers a hotkey to listen to. pub fn register(&self, hotkey: KeyCode, callback: F) -> Result<()> where F: FnMut() + Send + 'static, @@ -152,6 +161,7 @@ impl Hook { } } + /// Unregisters a previously registered hotkey. pub fn unregister(&self, hotkey: KeyCode) -> Result<()> { if self.hotkeys.lock().unwrap().remove(&hotkey).is_some() { Ok(()) diff --git a/crates/livesplit-hotkey/src/windows/mod.rs b/crates/livesplit-hotkey/src/windows/mod.rs index d6809375..941a753a 100644 --- a/crates/livesplit-hotkey/src/windows/mod.rs +++ b/crates/livesplit-hotkey/src/windows/mod.rs @@ -29,17 +29,26 @@ use winapi::{ const MSG_EXIT: UINT = 0x400; +/// The error type for this crate. #[derive(Debug, snafu::Snafu)] +#[non_exhaustive] pub enum Error { + /// The hotkey was already registered. AlreadyRegistered, + /// The hotkey to unregister was not registered. NotRegistered, + /// An error in the Windows API occurred. WindowsHook, + /// The background thread stopped unexpectedly. ThreadStopped, + /// An error occurred in the message loop. MessageLoop, } +/// The result type for this crate. pub type Result = std::result::Result; +/// A hook allows you to listen to hotkeys. pub struct Hook { thread_id: DWORD, hotkeys: Arc>>>, @@ -62,7 +71,7 @@ thread_local! { static STATE: RefCell> = RefCell::new(None); } -fn parse_scan_code(value: DWORD) -> Option { +const fn parse_scan_code(value: DWORD) -> Option { // Windows uses PS/2 scan code set 1. // https://www.avrfreaks.net/sites/default/files/PS2%20Keyboard.pdf Page 19 use self::KeyCode::*; @@ -256,6 +265,7 @@ unsafe extern "system" fn callback_proc(code: c_int, wparam: WPARAM, lparam: LPA } impl Hook { + /// Creates a new hook. pub fn new() -> Result { let hotkeys = Arc::new(Mutex::new(HashMap::< KeyCode, @@ -329,6 +339,7 @@ impl Hook { Ok(Hook { thread_id, hotkeys }) } + /// Registers a hotkey to listen to. pub fn register(&self, hotkey: KeyCode, callback: F) -> Result<()> where F: FnMut() + Send + 'static, @@ -341,6 +352,7 @@ impl Hook { } } + /// Unregisters a previously registered hotkey. pub fn unregister(&self, hotkey: KeyCode) -> Result<()> { if self.hotkeys.lock().remove(&hotkey).is_some() { Ok(()) @@ -355,7 +367,6 @@ pub(crate) fn try_resolve(key_code: KeyCode) -> Option { let scan_code = match key_code { Backquote => 0x0029, Backslash => 0x002B, - Backspace => 0x000E, BracketLeft => 0x001A, BracketRight => 0x001B, Comma => 0x0033,