1use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
14use serde::{Deserialize, Serialize};
15use std::collections::HashMap;
16use std::path::Path;
17
18#[derive(Debug, Clone, Default)]
24pub struct KeyTranslator {
25 translations: HashMap<KeyEventKey, KeyEventKey>,
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
31pub struct KeyEventKey {
32 pub code: SerializableKeyCode,
34 pub modifiers: u8, }
37
38impl KeyEventKey {
39 pub fn from_key_event(event: &KeyEvent) -> Self {
41 Self {
42 code: SerializableKeyCode::from_key_code(&event.code),
43 modifiers: event.modifiers.bits(),
44 }
45 }
46
47 pub fn to_key_event(&self) -> KeyEvent {
49 KeyEvent::new(
50 self.code.to_key_code(),
51 KeyModifiers::from_bits_truncate(self.modifiers),
52 )
53 }
54}
55
56#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
58#[serde(tag = "type", content = "value")]
59pub enum SerializableKeyCode {
60 Backspace,
62 Enter,
64 Left,
66 Right,
68 Up,
70 Down,
72 Home,
74 End,
76 PageUp,
78 PageDown,
80 Tab,
82 BackTab,
84 Delete,
86 Insert,
88 F(u8),
90 Char(char),
92 Null,
94 Esc,
96 CapsLock,
98 ScrollLock,
100 NumLock,
102 PrintScreen,
104 Pause,
106 Menu,
108 Modifier(String),
110 Unknown,
112}
113
114impl SerializableKeyCode {
115 pub fn from_key_code(code: &KeyCode) -> Self {
117 match code {
118 KeyCode::Backspace => SerializableKeyCode::Backspace,
119 KeyCode::Enter => SerializableKeyCode::Enter,
120 KeyCode::Left => SerializableKeyCode::Left,
121 KeyCode::Right => SerializableKeyCode::Right,
122 KeyCode::Up => SerializableKeyCode::Up,
123 KeyCode::Down => SerializableKeyCode::Down,
124 KeyCode::Home => SerializableKeyCode::Home,
125 KeyCode::End => SerializableKeyCode::End,
126 KeyCode::PageUp => SerializableKeyCode::PageUp,
127 KeyCode::PageDown => SerializableKeyCode::PageDown,
128 KeyCode::Tab => SerializableKeyCode::Tab,
129 KeyCode::BackTab => SerializableKeyCode::BackTab,
130 KeyCode::Delete => SerializableKeyCode::Delete,
131 KeyCode::Insert => SerializableKeyCode::Insert,
132 KeyCode::F(n) => SerializableKeyCode::F(*n),
133 KeyCode::Char(c) => SerializableKeyCode::Char(*c),
134 KeyCode::Null => SerializableKeyCode::Null,
135 KeyCode::Esc => SerializableKeyCode::Esc,
136 KeyCode::CapsLock => SerializableKeyCode::CapsLock,
137 KeyCode::ScrollLock => SerializableKeyCode::ScrollLock,
138 KeyCode::NumLock => SerializableKeyCode::NumLock,
139 KeyCode::PrintScreen => SerializableKeyCode::PrintScreen,
140 KeyCode::Pause => SerializableKeyCode::Pause,
141 KeyCode::Menu => SerializableKeyCode::Menu,
142 KeyCode::Modifier(m) => SerializableKeyCode::Modifier(format!("{:?}", m)),
143 _ => SerializableKeyCode::Unknown,
144 }
145 }
146
147 pub fn to_key_code(&self) -> KeyCode {
149 match self {
150 SerializableKeyCode::Backspace => KeyCode::Backspace,
151 SerializableKeyCode::Enter => KeyCode::Enter,
152 SerializableKeyCode::Left => KeyCode::Left,
153 SerializableKeyCode::Right => KeyCode::Right,
154 SerializableKeyCode::Up => KeyCode::Up,
155 SerializableKeyCode::Down => KeyCode::Down,
156 SerializableKeyCode::Home => KeyCode::Home,
157 SerializableKeyCode::End => KeyCode::End,
158 SerializableKeyCode::PageUp => KeyCode::PageUp,
159 SerializableKeyCode::PageDown => KeyCode::PageDown,
160 SerializableKeyCode::Tab => KeyCode::Tab,
161 SerializableKeyCode::BackTab => KeyCode::BackTab,
162 SerializableKeyCode::Delete => KeyCode::Delete,
163 SerializableKeyCode::Insert => KeyCode::Insert,
164 SerializableKeyCode::F(n) => KeyCode::F(*n),
165 SerializableKeyCode::Char(c) => KeyCode::Char(*c),
166 SerializableKeyCode::Null => KeyCode::Null,
167 SerializableKeyCode::Esc => KeyCode::Esc,
168 SerializableKeyCode::CapsLock => KeyCode::CapsLock,
169 SerializableKeyCode::ScrollLock => KeyCode::ScrollLock,
170 SerializableKeyCode::NumLock => KeyCode::NumLock,
171 SerializableKeyCode::PrintScreen => KeyCode::PrintScreen,
172 SerializableKeyCode::Pause => KeyCode::Pause,
173 SerializableKeyCode::Menu => KeyCode::Menu,
174 SerializableKeyCode::Modifier(_) | SerializableKeyCode::Unknown => KeyCode::Null,
175 }
176 }
177}
178
179#[derive(Debug, Serialize, Deserialize)]
181struct CalibrationFile {
182 #[serde(rename = "_comment")]
184 comment: String,
185 #[serde(rename = "_format")]
187 format: String,
188 translations: Vec<TranslationEntry>,
190}
191
192#[derive(Debug, Serialize, Deserialize)]
194struct TranslationEntry {
195 raw: KeyEventKey,
197 expected: KeyEventKey,
199}
200
201impl KeyTranslator {
202 pub fn new() -> Self {
204 Self {
205 translations: HashMap::new(),
206 }
207 }
208
209 pub fn translate(&self, raw: KeyEvent) -> KeyEvent {
214 let key = KeyEventKey::from_key_event(&raw);
215 if let Some(normalized) = self.translations.get(&key) {
216 normalized.to_key_event()
217 } else {
218 raw
219 }
220 }
221
222 pub fn has_translation(&self, raw: &KeyEvent) -> bool {
224 let key = KeyEventKey::from_key_event(raw);
225 self.translations.contains_key(&key)
226 }
227
228 pub fn add_translation(&mut self, raw: KeyEvent, expected: KeyEvent) {
230 let raw_key = KeyEventKey::from_key_event(&raw);
231 let expected_key = KeyEventKey::from_key_event(&expected);
232 self.translations.insert(raw_key, expected_key);
233 }
234
235 pub fn remove_translation(&mut self, raw: &KeyEvent) {
237 let key = KeyEventKey::from_key_event(raw);
238 self.translations.remove(&key);
239 }
240
241 pub fn len(&self) -> usize {
243 self.translations.len()
244 }
245
246 pub fn is_empty(&self) -> bool {
248 self.translations.is_empty()
249 }
250
251 pub fn clear(&mut self) {
253 self.translations.clear();
254 }
255
256 pub fn load_from_file(path: &Path) -> Result<Self, std::io::Error> {
261 if !path.exists() {
262 return Ok(Self::new());
263 }
264
265 let content = std::fs::read_to_string(path)?;
266 let file: CalibrationFile = serde_json::from_str(&content).map_err(|e| {
267 std::io::Error::new(
268 std::io::ErrorKind::InvalidData,
269 format!("Invalid calibration file: {}", e),
270 )
271 })?;
272
273 let mut translator = Self::new();
274 for entry in file.translations {
275 translator.translations.insert(entry.raw, entry.expected);
276 }
277
278 tracing::info!(
279 "Loaded {} key translations from {}",
280 translator.len(),
281 path.display()
282 );
283
284 Ok(translator)
285 }
286
287 pub fn save_to_file(&self, path: &Path) -> Result<(), std::io::Error> {
289 if let Some(parent) = path.parent() {
291 std::fs::create_dir_all(parent)?;
292 }
293
294 let entries: Vec<TranslationEntry> = self
295 .translations
296 .iter()
297 .map(|(raw, expected)| TranslationEntry {
298 raw: raw.clone(),
299 expected: expected.clone(),
300 })
301 .collect();
302
303 let file = CalibrationFile {
304 comment: "Generated by 'Calibrate Input Keys' wizard".to_string(),
305 format: "raw_key → expected_key".to_string(),
306 translations: entries,
307 };
308
309 let content = serde_json::to_string_pretty(&file)?;
310 std::fs::write(path, content)?;
311
312 tracing::info!(
313 "Saved {} key translations to {}",
314 self.len(),
315 path.display()
316 );
317
318 Ok(())
319 }
320
321 pub fn calibration_path(config_dir: &std::path::Path) -> std::path::PathBuf {
323 config_dir.join("key_calibration.json")
324 }
325
326 pub fn load_from_config_dir(config_dir: &std::path::Path) -> Result<Self, std::io::Error> {
328 let path = Self::calibration_path(config_dir);
329 Self::load_from_file(&path)
330 }
331
332 pub fn save_to_config_dir(&self, config_dir: &std::path::Path) -> Result<(), std::io::Error> {
334 let path = Self::calibration_path(config_dir);
335 self.save_to_file(&path)
336 }
337}
338
339#[cfg(test)]
340mod tests {
341 use super::*;
342
343 #[test]
344 fn test_translator_empty() {
345 let translator = KeyTranslator::new();
346 assert!(translator.is_empty());
347
348 let raw = KeyEvent::new(KeyCode::Backspace, KeyModifiers::NONE);
350 let result = translator.translate(raw);
351 assert_eq!(result.code, KeyCode::Backspace);
352 }
353
354 #[test]
355 fn test_translator_with_mapping() {
356 let mut translator = KeyTranslator::new();
357
358 let raw = KeyEvent::new(KeyCode::Char('\x7f'), KeyModifiers::NONE);
360 let expected = KeyEvent::new(KeyCode::Backspace, KeyModifiers::NONE);
361 translator.add_translation(raw, expected);
362
363 assert_eq!(translator.len(), 1);
364 assert!(translator.has_translation(&raw));
365
366 let result = translator.translate(raw);
368 assert_eq!(result.code, KeyCode::Backspace);
369 }
370
371 #[test]
372 fn test_translator_preserves_unmapped() {
373 let mut translator = KeyTranslator::new();
374
375 let mapped_raw = KeyEvent::new(KeyCode::Char('\x7f'), KeyModifiers::NONE);
377 let mapped_expected = KeyEvent::new(KeyCode::Backspace, KeyModifiers::NONE);
378 translator.add_translation(mapped_raw, mapped_expected);
379
380 let unmapped = KeyEvent::new(KeyCode::Char('a'), KeyModifiers::NONE);
382 let result = translator.translate(unmapped);
383 assert_eq!(result.code, KeyCode::Char('a'));
384 }
385
386 #[test]
387 fn test_translator_with_modifiers() {
388 let mut translator = KeyTranslator::new();
389
390 let raw = KeyEvent::new(KeyCode::Char('b'), KeyModifiers::ALT);
392 let expected = KeyEvent::new(KeyCode::Left, KeyModifiers::ALT);
393 translator.add_translation(raw, expected);
394
395 let result = translator.translate(raw);
396 assert_eq!(result.code, KeyCode::Left);
397 assert!(result.modifiers.contains(KeyModifiers::ALT));
398 }
399
400 #[test]
401 fn test_key_event_key_serialization() {
402 let key = KeyEventKey {
403 code: SerializableKeyCode::Backspace,
404 modifiers: KeyModifiers::NONE.bits(),
405 };
406
407 let json = serde_json::to_string(&key).unwrap();
408 let deserialized: KeyEventKey = serde_json::from_str(&json).unwrap();
409
410 assert_eq!(key, deserialized);
411 }
412
413 #[test]
414 fn test_roundtrip_key_event() {
415 let original = KeyEvent::new(KeyCode::Home, KeyModifiers::SHIFT);
416 let key = KeyEventKey::from_key_event(&original);
417 let restored = key.to_key_event();
418
419 assert_eq!(original.code, restored.code);
420 assert_eq!(original.modifiers, restored.modifiers);
421 }
422}