1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
#![doc(html_playground_url = "https://play.rust-lang.org/")]
//! key-mapping library allows for keyboard key code conversion between systems such as the DOM and
//! HID usage-ids. With Rust `[no_std]` support.
//!
//! # Features
//!
//! Extra functionality is behind optional features to optimize compile time and binary size.
//!
//! - **`std`** *(enabled by default)* - Add support for Rust's libstd types.
//! - **`serde`** Add support for `serde` de/serializing library.
//! - **`usbd-hid`** Add support for converting between the usbd-hid library KeyboardReport.
//!
//! # Example Usage
//!
//! ```toml
//! [dependencies]
//! key-mapping = "0.1"
//! ```
//!
//! ```rust,editable
//! use key_mapping::Keyboard;
//!
//! fn main() {
//! let dom_code = "KeyA";
//! let usage_id = Keyboard::US.dom_key_to_usage_id(dom_code).unwrap();
//!
//! assert_eq!(0x04, *usage_id);
//! }
//! ```
#![forbid(unsafe_code)]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
pub const MODIFIER_CODE_CTRL: u8 = 1;
pub const MODIFIER_CODE_SHIFT: u8 = 2;
pub const MODIFIER_CODE_ALT: u8 = 4;
pub const MODIFIER_CODE_META: u8 = 8;
/// Keyboard layouts, used to convert between key-code types.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Keyboard {
/// US keyboard layout *(default)*
#[default]
US,
/// UK keyboard layout
UK,
}
impl Keyboard {
/// Convert key-code into a hid usage id, using the given keyboard layout.
/// Uses a performant O(1) operation.
pub fn dom_key_to_usage_id(&self, key_code: &str) -> Option<&u8> {
match self {
Self::US => DOM_KEYS_US.get(key_code),
Self::UK => DOM_KEYS_UK.get(key_code),
}
}
}
/// A single mapped keyboard key.
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MappedKey<'a> {
/// HID usage-id for keyboard key
pub usage_id: u8,
/// The DOM key representation
pub dom_key: &'a str,
/// Machine friendly key name
pub prefix: &'a str,
}
/// A keyboard action, could be used for making key press/release events,
/// Defaults to no keys or modifiers.
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct KeyboardAction {
/// Keys included in action, represented as usage-ids
pub keys: [Keys; 6],
/// Whether ALT is held
pub alt: bool,
/// Whether CTRL is held
pub ctrl: bool,
/// Whether SHIFT is held
pub shift: bool,
/// Whether META is held
pub meta: bool,
}
impl Default for KeyboardAction {
fn default() -> Self {
Self {
keys: [
Keys::None,
Keys::None,
Keys::None,
Keys::None,
Keys::None,
Keys::None,
],
alt: Default::default(),
ctrl: Default::default(),
shift: Default::default(),
meta: Default::default(),
}
}
}
#[cfg(feature = "usbd-hid")]
impl From<KeyboardAction> for usbd_hid::descriptor::KeyboardReport {
fn from(value: KeyboardAction) -> Self {
let mut keycodes = [0; 6];
for (i, v) in value.keys.into_iter().map(|v| v as u8).enumerate() {
keycodes[i] = v;
}
Self {
modifier: value.get_modifer_code(),
reserved: 0,
leds: 0,
keycodes,
}
}
}
impl KeyboardAction {
/// Get the modifiers as their code representation
pub fn get_modifer_code(&self) -> u8 {
let mut result = 0;
if self.ctrl {
result |= MODIFIER_CODE_CTRL;
}
if self.shift {
result |= MODIFIER_CODE_SHIFT;
}
if self.alt {
result |= MODIFIER_CODE_ALT;
}
if self.meta {
result |= MODIFIER_CODE_META;
}
result
}
}
#[cfg(test)]
mod tests {
use crate::Keyboard;
#[test]
fn dom_key_to_hid() {
assert_eq!(0x04, *Keyboard::US.dom_key_to_usage_id("KeyA").unwrap());
assert_eq!(
0x31,
*Keyboard::US.dom_key_to_usage_id("Backslash").unwrap()
);
assert_eq!(
0x32,
*Keyboard::UK.dom_key_to_usage_id("Backslash").unwrap()
);
}
}