1#![doc(html_playground_url = "https://play.rust-lang.org/")]
2#![forbid(unsafe_code)]
32#![cfg_attr(not(feature = "std"), no_std)]
33#[cfg(feature = "serde")]
34use serde::{Deserialize, Serialize};
35
36include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
37
38pub const MODIFIER_CODE_CTRL: u8 = 1;
39pub const MODIFIER_CODE_SHIFT: u8 = 2;
40pub const MODIFIER_CODE_ALT: u8 = 4;
41pub const MODIFIER_CODE_META: u8 = 8;
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
45#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
46pub enum Keyboard {
47 #[default]
49 US,
50 UK,
52}
53
54impl Keyboard {
55 pub fn dom_key_to_usage_id(&self, key_code: &str) -> Option<&u8> {
58 match self {
59 Self::US => DOM_KEYS_US.get(key_code),
60 Self::UK => DOM_KEYS_UK.get(key_code),
61 }
62 }
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
67#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
68pub struct MappedKey<'a> {
69 pub usage_id: u8,
71 pub dom_key: &'a str,
73 pub prefix: &'a str,
75 pub visual: &'a str,
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
83pub struct KeyboardAction {
84 pub keys: [Keys; 6],
86 pub alt: bool,
88 pub ctrl: bool,
90 pub shift: bool,
92 pub meta: bool,
94}
95
96impl Default for KeyboardAction {
97 fn default() -> Self {
98 Self {
99 keys: [
100 Keys::None,
101 Keys::None,
102 Keys::None,
103 Keys::None,
104 Keys::None,
105 Keys::None,
106 ],
107 alt: Default::default(),
108 ctrl: Default::default(),
109 shift: Default::default(),
110 meta: Default::default(),
111 }
112 }
113}
114
115#[cfg(feature = "usbd-hid")]
116impl From<KeyboardAction> for usbd_hid::descriptor::KeyboardReport {
117 fn from(value: KeyboardAction) -> Self {
118 let mut keycodes = [0; 6];
119 for (i, v) in value.keys.into_iter().map(|v| v as u8).enumerate() {
120 keycodes[i] = v;
121 }
122 Self {
123 modifier: value.get_modifer_code(),
124 reserved: 0,
125 leds: 0,
126 keycodes,
127 }
128 }
129}
130
131impl KeyboardAction {
132 pub fn get_modifer_code(&self) -> u8 {
134 let mut result = 0;
135 if self.ctrl {
136 result |= MODIFIER_CODE_CTRL;
137 }
138 if self.shift {
139 result |= MODIFIER_CODE_SHIFT;
140 }
141 if self.alt {
142 result |= MODIFIER_CODE_ALT;
143 }
144 if self.meta {
145 result |= MODIFIER_CODE_META;
146 }
147 result
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use crate::{Keyboard, Keys, MappedKey, MAPPED_KEYS};
154
155 #[test]
156 fn dom_key_to_hid() {
157 assert_eq!(0x04, *Keyboard::US.dom_key_to_usage_id("KeyA").unwrap());
158 assert_eq!(
159 0x31,
160 *Keyboard::US.dom_key_to_usage_id("Backslash").unwrap()
161 );
162 assert_eq!(
163 0x32,
164 *Keyboard::UK.dom_key_to_usage_id("Backslash").unwrap()
165 );
166 }
167
168 #[test]
169 fn u8_key_to_key() {
170 assert_eq!(Keys::try_from(0x04), Ok(Keys::A));
171 assert_eq!(Keys::try_from(0xff), Err(()));
172 }
173
174 #[test]
175 fn usage_id_to_mapping() {
176 assert_eq!(
177 MAPPED_KEYS.get(&0x04),
178 Some(&MappedKey {
179 usage_id: 0x04,
180 dom_key: "KeyA",
181 prefix: "A",
182 visual: "A",
183 })
184 );
185 }
186}