keyboard_codes/
lib.rs

1//! keyboard-codes: Cross-platform keyboard key code mapping and conversion
2//!
3//! This crate provides comprehensive keyboard key definitions and cross-platform
4//! code mapping for Windows, Linux, and macOS. It supports standard keys,
5//! modifiers, custom key mapping, and bidirectional conversion between key names
6//! and platform-specific codes.
7//!
8//! # Examples
9//!
10//! ```rust
11//! use keyboard_codes::{Key, Modifier, Platform, KeyCodeMapper};
12//!
13//! // Parse key from string
14//! let key: Key = "Enter".parse().unwrap();
15//! assert_eq!(key, Key::Enter);
16//!
17//! // Convert key to platform-specific code
18//! let windows_code = key.to_code(Platform::Windows);
19//! let linux_code = key.to_code(Platform::Linux);
20//!
21//! // Parse key from code
22//! let key_from_code = Key::from_code(0x0D, Platform::Windows).unwrap();
23//! assert_eq!(key_from_code, Key::Enter);
24//! ```
25//!
26//! # Features
27//!
28//! - `serde`: Enables serialization/deserialization support
29//! - `phf`: Uses perfect hash functions for faster lookups
30
31#![deny(missing_docs)]
32#![warn(clippy::all)]
33
34/// Error types for keyboard parsing and mapping
35pub mod error;
36/// Key code mapping implementations
37pub mod mapping;
38/// Advanced keyboard input parsing with alias support
39pub mod parser;
40/// Core type definitions for keyboard keys and platforms
41pub mod types;
42/// Utility functions and helpers
43pub mod utils;
44
45// Re-export main types for convenient access
46pub use error::KeyParseError;
47pub use mapping::custom::{CustomKey, CustomKeyMap};
48pub use types::{Key, KeyCodeMapper, Modifier, Platform};
49
50// Re-export core parsing functions
51pub use mapping::standard::{parse_key_ignore_case, parse_modifier_ignore_case};
52
53// Re-export advanced parser functionality
54pub 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
61// Implement FromStr for Key using the standard mappings
62impl 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
70// Implement FromStr for Modifier using the standard mappings
71impl 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
79/// Get the current platform based on compilation target
80pub 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}