1use std::collections::HashMap;
4use std::sync::LazyLock;
5use terminfo::capability as cap;
6
7use crate::{error, interfaces};
8
9macro_rules! key {
10 ( $terminfo:expr , $our_key:expr, $terminfo_key:ty ) => {{
11 (
12 $our_key,
13 $terminfo
14 .get::<$terminfo_key>()
15 .map(|k| k.expand().to_vec()),
16 )
17 }};
18}
19
20fn build_terminfo_key_map() -> HashMap<Vec<u8>, interfaces::Key> {
21 let mut map: HashMap<Vec<u8>, interfaces::Key> = HashMap::new();
22
23 if let Ok(ti) = terminfo::Database::from_env() {
24 let key_capabilities = [
26 key!(ti, interfaces::Key::F(1), cap::KeyF1<'_>),
27 key!(ti, interfaces::Key::F(2), cap::KeyF2<'_>),
28 key!(ti, interfaces::Key::F(3), cap::KeyF3<'_>),
29 key!(ti, interfaces::Key::F(4), cap::KeyF4<'_>),
30 key!(ti, interfaces::Key::F(5), cap::KeyF5<'_>),
31 key!(ti, interfaces::Key::F(6), cap::KeyF6<'_>),
32 key!(ti, interfaces::Key::F(7), cap::KeyF7<'_>),
33 key!(ti, interfaces::Key::F(8), cap::KeyF8<'_>),
34 key!(ti, interfaces::Key::F(9), cap::KeyF9<'_>),
35 key!(ti, interfaces::Key::F(10), cap::KeyF10<'_>),
36 key!(ti, interfaces::Key::F(11), cap::KeyF11<'_>),
37 key!(ti, interfaces::Key::F(12), cap::KeyF12<'_>),
38 key!(ti, interfaces::Key::Backspace, cap::KeyBackspace<'_>),
39 key!(ti, interfaces::Key::Enter, cap::KeyEnter<'_>),
40 key!(ti, interfaces::Key::Left, cap::KeyLeft<'_>),
41 key!(ti, interfaces::Key::Right, cap::KeyRight<'_>),
42 key!(ti, interfaces::Key::Up, cap::KeyUp<'_>),
43 key!(ti, interfaces::Key::Down, cap::KeyDown<'_>),
44 key!(ti, interfaces::Key::Home, cap::KeyHome<'_>),
45 key!(ti, interfaces::Key::End, cap::KeyEnd<'_>),
46 key!(ti, interfaces::Key::PageUp, cap::KeyPPage<'_>),
47 key!(ti, interfaces::Key::PageDown, cap::KeyNPage<'_>),
48 key!(ti, interfaces::Key::BackTab, cap::BackTab<'_>),
49 key!(ti, interfaces::Key::Up, cap::CursorUp<'_>),
52 key!(ti, interfaces::Key::Down, cap::CursorDown<'_>),
53 key!(ti, interfaces::Key::Left, cap::CursorLeft<'_>),
54 key!(ti, interfaces::Key::Right, cap::CursorRight<'_>),
55 ];
56
57 for (key, v) in key_capabilities {
58 if let Some(Ok(v)) = v {
59 map.insert(v.clone(), key.clone());
60 }
61 }
62 }
63
64 map
65}
66
67pub(crate) static TERMINFO_KEY_MAP: LazyLock<HashMap<Vec<u8>, interfaces::Key>> =
68 LazyLock::new(build_terminfo_key_map);
69
70pub fn try_get_key_from_key_code(key_code: &[u8]) -> Option<interfaces::Key> {
77 if let Some(key) = TERMINFO_KEY_MAP.get(key_code) {
78 Some(key.clone())
79 } else if key_code.len() == 1 && !key_code[0].is_ascii_control() {
80 Some(interfaces::Key::Character(key_code[0] as char))
81 } else {
82 None
83 }
84}