1#![deny(missing_docs)]
32#![warn(clippy::all)]
33
34pub mod error;
36pub mod mapping;
38pub mod parser;
40pub mod types;
42pub mod utils;
44
45pub use error::KeyParseError;
47pub use mapping::custom::{CustomKey, CustomKeyMap};
48pub use types::{Key, KeyCodeMapper, Modifier, Platform};
49
50pub use mapping::standard::{parse_key_ignore_case, parse_modifier_ignore_case};
52
53pub use parser::{
55 parse_input, parse_modifier_with_aliases, parse_shortcut_flexible, parse_shortcut_sequence,
56 parse_shortcut_with_aliases, Shortcut,
57};
58
59use std::str::FromStr;
60
61impl FromStr for Key {
63 type Err = KeyParseError;
64
65 fn from_str(s: &str) -> Result<Self, Self::Err> {
66 mapping::standard::parse_key_from_str(s)
67 }
68}
69
70impl FromStr for Modifier {
72 type Err = KeyParseError;
73
74 fn from_str(s: &str) -> Result<Self, Self::Err> {
75 mapping::standard::parse_modifier_from_str(s)
76 }
77}
78
79pub fn current_platform() -> Platform {
81 #[cfg(target_os = "windows")]
82 return Platform::Windows;
83
84 #[cfg(target_os = "linux")]
85 return Platform::Linux;
86
87 #[cfg(target_os = "macos")]
88 return Platform::MacOS;
89
90 #[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
91 panic!("Unsupported platform");
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn test_key_from_str() {
100 assert_eq!("Escape".parse::<Key>().unwrap(), Key::Escape);
101 assert_eq!("A".parse::<Key>().unwrap(), Key::A);
102 assert!("UnknownKey".parse::<Key>().is_err());
103 }
104
105 #[test]
106 fn test_modifier_from_str() {
107 assert_eq!("Shift".parse::<Modifier>().unwrap(), Modifier::Shift);
108 assert_eq!("Control".parse::<Modifier>().unwrap(), Modifier::Control);
109 assert!("UnknownModifier".parse::<Modifier>().is_err());
110 }
111
112 #[test]
113 fn test_current_platform() {
114 let platform = current_platform();
115 assert!(matches!(
116 platform,
117 Platform::Windows | Platform::Linux | Platform::MacOS
118 ));
119 }
120
121 #[test]
122 fn test_parse_modifier_with_aliases() {
123 assert_eq!(
124 parse_modifier_with_aliases("ctrl").unwrap(),
125 Modifier::Control
126 );
127 assert_eq!(parse_modifier_with_aliases("Cmd").unwrap(), Modifier::Meta);
128 assert_eq!(parse_modifier_with_aliases("win").unwrap(), Modifier::Meta);
129 assert_eq!(
130 parse_modifier_with_aliases("lctrl").unwrap(),
131 Modifier::LeftControl
132 );
133 }
134
135 #[test]
136 fn test_parse_shortcut_with_aliases() {
137 let shortcut = parse_shortcut_with_aliases("ctrl+shift+a").unwrap();
138 assert_eq!(shortcut.modifiers, vec![Modifier::Control, Modifier::Shift]);
139 assert_eq!(shortcut.key, Key::A);
140
141 let shortcut = parse_shortcut_with_aliases("cmd+q").unwrap();
142 assert_eq!(shortcut.modifiers, vec![Modifier::Meta]);
143 assert_eq!(shortcut.key, Key::Q);
144 }
145
146 #[test]
147 fn test_parse_input() {
148 let shortcut = parse_input("a").unwrap();
149 assert!(shortcut.is_simple());
150 assert_eq!(shortcut.key, Key::A);
151
152 let shortcut = parse_input("ctrl+a").unwrap();
153 assert_eq!(shortcut.modifiers, vec![Modifier::Control]);
154 assert_eq!(shortcut.key, Key::A);
155 }
156}