1#![deny(missing_docs)]
41#![warn(clippy::all)]
42
43pub mod error;
45pub mod mapping;
47pub mod parser;
49pub mod types;
51pub mod utils;
53
54pub use error::KeyParseError;
56pub use mapping::custom::{CustomKey, CustomKeyMap};
57pub use types::{Key, KeyCodeMapper, KeyboardInput, Modifier, Platform};
58
59pub use mapping::standard::{parse_key_ignore_case, parse_modifier_ignore_case};
61
62pub use parser::{
64 parse_input, parse_keyboard_input, parse_modifier_with_aliases, parse_shortcut_flexible,
65 parse_shortcut_sequence, parse_shortcut_with_aliases, Shortcut,
66};
67
68use std::str::FromStr;
69
70impl FromStr for Key {
72 type Err = KeyParseError;
73
74 fn from_str(s: &str) -> Result<Self, Self::Err> {
75 mapping::standard::parse_key_from_str(s)
76 }
77}
78
79impl FromStr for Modifier {
81 type Err = KeyParseError;
82
83 fn from_str(s: &str) -> Result<Self, Self::Err> {
84 mapping::standard::parse_modifier_from_str(s)
85 }
86}
87
88pub fn current_platform() -> Platform {
90 #[cfg(target_os = "windows")]
91 return Platform::Windows;
92
93 #[cfg(target_os = "linux")]
94 return Platform::Linux;
95
96 #[cfg(target_os = "macos")]
97 return Platform::MacOS;
98
99 #[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
100 panic!("Unsupported platform");
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn test_key_from_str() {
109 assert_eq!("Escape".parse::<Key>().unwrap(), Key::Escape);
110 assert_eq!("A".parse::<Key>().unwrap(), Key::A);
111 assert!("UnknownKey".parse::<Key>().is_err());
112 }
113
114 #[test]
115 fn test_modifier_from_str() {
116 assert_eq!("Shift".parse::<Modifier>().unwrap(), Modifier::Shift);
117 assert_eq!("Control".parse::<Modifier>().unwrap(), Modifier::Control);
118 assert!("UnknownModifier".parse::<Modifier>().is_err());
119 }
120
121 #[test]
122 fn test_keyboard_input_unified() {
123 let input1: KeyboardInput = "A".parse().unwrap();
125 let input2: KeyboardInput = "Control".parse().unwrap();
126 let input3: KeyboardInput = "ctrl".parse().unwrap();
127 let input4: KeyboardInput = "esc".parse().unwrap();
128
129 assert_eq!(input1, KeyboardInput::Key(Key::A));
130 assert_eq!(input2, KeyboardInput::Modifier(Modifier::Control));
131 assert_eq!(input3, KeyboardInput::Modifier(Modifier::Control));
132 assert_eq!(input4, KeyboardInput::Key(Key::Escape));
133
134 assert_eq!(input1.to_code(Platform::Windows), 0x41);
136 assert_eq!(input2.to_code(Platform::Windows), 0x11);
137
138 assert_eq!(
140 KeyboardInput::from_code(0x41, Platform::Windows),
141 Some(KeyboardInput::Key(Key::A))
142 );
143 assert_eq!(
144 KeyboardInput::from_code(0x11, Platform::Windows),
145 Some(KeyboardInput::Modifier(Modifier::Control))
146 );
147
148 assert_eq!(
150 parse_keyboard_input("A").unwrap(),
151 KeyboardInput::Key(Key::A)
152 );
153 assert_eq!(
154 parse_keyboard_input("ctrl").unwrap(),
155 KeyboardInput::Modifier(Modifier::Control)
156 );
157 }
158
159 #[test]
160 fn test_current_platform() {
161 let platform = current_platform();
162 assert!(matches!(
163 platform,
164 Platform::Windows | Platform::Linux | Platform::MacOS
165 ));
166 }
167
168 #[test]
169 fn test_parse_modifier_with_aliases() {
170 assert_eq!(
171 parse_modifier_with_aliases("ctrl").unwrap(),
172 Modifier::Control
173 );
174 assert_eq!(parse_modifier_with_aliases("Cmd").unwrap(), Modifier::Meta);
175 assert_eq!(parse_modifier_with_aliases("win").unwrap(), Modifier::Meta);
176 assert_eq!(
177 parse_modifier_with_aliases("lctrl").unwrap(),
178 Modifier::LeftControl
179 );
180 }
181
182 #[test]
183 fn test_parse_shortcut_with_aliases() {
184 let shortcut = parse_shortcut_with_aliases("ctrl+shift+a").unwrap();
185 assert_eq!(shortcut.modifiers, vec![Modifier::Control, Modifier::Shift]);
186 assert_eq!(shortcut.key, Key::A);
187
188 let shortcut = parse_shortcut_with_aliases("cmd+q").unwrap();
189 assert_eq!(shortcut.modifiers, vec![Modifier::Meta]);
190 assert_eq!(shortcut.key, Key::Q);
191 }
192
193 #[test]
194 fn test_parse_input() {
195 let shortcut = parse_input("a").unwrap();
196 assert!(shortcut.is_simple());
197 assert_eq!(shortcut.key, Key::A);
198
199 let shortcut = parse_input("ctrl+a").unwrap();
200 assert_eq!(shortcut.modifiers, vec![Modifier::Control]);
201 assert_eq!(shortcut.key, Key::A);
202 }
203}