Skip to main content

rpk_config/
keycodes.rs

1use std::collections::HashMap;
2
3use lazy_static::lazy_static;
4use rpk_common::keycodes::key_range;
5
6const DASH_USCORE: [char; 2] = ['_', '-'];
7
8const MODIFIER_BITS: [&str; 8] = ["C", "S", "A", "G", "RC", "RS", "RA", "RG"];
9lazy_static! {
10    static ref MODIFIER_BIT_MAP: HashMap<&'static str, u8> = {
11        let mut m = HashMap::new();
12        for (i, c) in MODIFIER_BITS.iter().enumerate() {
13            m.insert(*c, 1 << i);
14        }
15        m
16    };
17    static ref ACTION_NAMES: HashMap<&'static str, u16> = {
18        let mut m = HashMap::new();
19        m.insert("layer", key_range::LAYER);
20        m.insert("toggle", key_range::TOGGLE);
21        m.insert("setlayout", key_range::SET_LAYOUT);
22        m.insert("oneshot", key_range::ONESHOT);
23        m.insert("overload", key_range::MACROS_MIN);
24        m.insert("dualaction", key_range::MACROS_MIN);
25        m.insert("macro", key_range::MACROS_MIN);
26        m.insert("hold", key_range::MACROS_MIN);
27        m.insert("release", key_range::MACROS_MIN);
28        m.insert("unicode", key_range::MACROS_MIN);
29        m.insert("delay", key_range::MACROS_MIN);
30        m
31    };
32    static ref SHIFT_KEY_NAMES : HashMap<char, char> = {
33        let mut m = HashMap::new();
34        let mut n = '\0';
35        for c in r#"`~-_=+[{]}\|;:'",<.>/?1!2@3#4$5%6^7&8*9(0)"#.chars() {
36            if n == '\0' {
37                n = c;
38            } else {
39                m.insert(c, n);
40                n = '\0';
41            }
42        }
43        m
44    };
45    static ref FULL_KEY_NAMES: HashMap<&'static str, u16> = {
46        let mut m = HashMap::new();
47        m.insert("Transparent", 0);
48        m.insert("No_op", 1);
49        m.insert("Nop", 1);
50        m.insert("/", 0x38);
51        let mut ins = |a: &'static str, b: u16| {
52            for k in a.split('/') {
53                if k.is_empty() {
54                    panic!("empty symbol in {a}");
55                }
56                if m.contains_key(k) {
57                    panic!("key already added {a}");
58                }
59                m.insert(k, b);
60            }
61        };
62        for (i, name) in r#"
63A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
641 2 3 4 5 6 7 8 9 0
65Enter/Return/ent/⏎
66Escape/Esc/⎋
67backspace/bksp/⌫
68Tab/⇥
69Spacebar/Space/spc/␣
70Dash/minus/-
71Equals/equal/=
72LeftBrace/leftsquarebracket/[
73RightBrace/rightsquarebracket/]
74Backslash/\
75Hash/NonUsHash/#
76Semicolon/;
77LeftApos/apostrophe/'
78GraveAccent/grave/`
79Comma/,
80Period/dot/.
81Forwardslash/slash
82CapsLock/caps/⇪
83F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12
84Printscreen/print
85ScrollLock
86Pause
87Insert
88Home/⇱
89PageUp/PgUp/⇞
90Delete/del/⌦
91End/⇲
92PageDown/PgDn/⇟
93Right/→ Left/← Down/↓ Up/↑
94NumLock/KpNumLock/⇭
95KpForwardslash KpStar KpDash KpPlus KpEnter
96Kp1 Kp2 Kp3 Kp4 Kp5 Kp6 Kp7 Kp8 Kp9 Kp0
97KpPeriod
98NonUsBackslash
99Application/App
100Power
101KpEquals
102F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24
103Execute
104Help
105Menu
106Select
107Stop
108Again Undo
109Cut Copy Paste
110Find
111Mute
112VolumeUp VolumeDown
113LockingCapsLock LockingNumLock LockingScrollLock
114KpComma KpEqualSign
115International1 International2 International3 International4
116International5 International6 International7 International8 International9
117Lang1 Lang2 Lang3 Lang4 Lang5 Lang6 Lang7 Lang8 Lang9
118AlternateErase
119SysreqAttention
120Cancel
121Clear
122Prior
123KeyboardReturn
124Separator
125Out
126Oper
127ClearAgain
128CrselProps
129Exsel
130A5 A6 A7 A8 A9 AA AB AC AD AE AF
131KpDouble0 KpTriple0
132ThousandsSeparator DecimalSeparator CurrencyUnit CurrencySubUnit
133KpLeftBracket KpRightBracket KpLeftBrace KpRightBrace
134KpTab KpBackspace
135KpA KpB KpC KpD KpE KpF
136KpXor
137KpCaret
138KpPercentage
139KpLess KpGreater
140KpAmpersand KpDoubleAmpersand KpBar KpDoubleBar
141KpColon KpHash KpSpace KpAt KpBang
142KpMemoryStore KpMemoryRecall KpMemoryClear
143KpMemoryAdd KpMemorySubtract KpMemoryMultiply KpMemoryDivide KpPlusMinus
144KpClear KpClearEntry
145KpBinary KpOctal KpDecimal KpHexadecimal
146DE DF
147LeftControl/LCtrl/LCTL/⌃
148LeftShift/LShift/LSFT/⇧
149LeftAlt/LAlt
150LeftGui/LeftMeta/LGUI
151RightControl/RCtrl/RCtl
152RightShift/RShift/RSFT
153RightAlt/AltGr/RAlt
154RightGui/RightMeta/RGUI
155Media_Play_Pause
156Media_Stop_CD
157Media_Previous_Song
158Media_Next_Song
159Media_Eject_CD
160Media_Volume_Up
161Media_Volume_Down
162Media_Mute
163Media_WWW
164Media_Back
165Media_Forward
166Media_Stop
167Media_Find
168Media_Scroll_Up
169Media_Scroll_Down
170Media_Edit
171Media_Sleep
172Media_Coffee
173Media_Refresh
174Media_Calc
175"#
176        .split_whitespace().enumerate()
177        {
178            ins(name, (i + 4) as u16);
179        }
180
181        for (i, name) in r#"
182Mouse1 Mouse2 Mouse3 Mouse4 Mouse5 Mouse6 Mouse7 Mouse8
183MouseLeft MouseRight MouseUp MouseDown
184MouseScrollDown/MouseWheelDown
185MouseScrollUp/MouseWheelUp
186MouseScrollRight/MouseWheelRight
187MouseScrollLeft/MouseWheelLeft
188MouseAccel1 MouseAccel2 MouseAccel3
189"#
190        .split_whitespace()
191        .enumerate()
192        {
193            for name in name.split('/') {
194                ins(name, i as u16 + key_range::MOUSE_MIN);
195            }
196        }
197
198        let mut i = |a: &'static str, b: u16| {
199            ins(a, b+key_range::CONSUMER_MIN);
200        };
201
202        // 15.5 Display Controls
203        i("Snapshot"        ,0x065);
204        i("Brightness_Up"   ,0x06F);
205        i("Brightness_Down" ,0x070);
206        // 15.7 Transport Controls
207        i("TC_Record"       ,0x0b2);
208        i("TC_Fast_Forward" ,0x0B3);
209        i("TC_Rewind"       ,0x0B4);
210        i("TC_Next_Track"   ,0x0B5);
211        i("TC_Prev_Track"   ,0x0B6);
212        i("TC_Stop"         ,0x0B7);
213        i("TC_Eject"        ,0x0B8);
214        i("TC_Random_Play"  ,0x0B9);
215        i("TC_Stop_Eject"   ,0x0CC);
216        i("TC_Play_Pause"   ,0x0CD);
217        // 15.9.1 Audio Controls - Volume
218        i("Audio_Mute"     ,0x0E2);
219        i("Audio_Vol_Up"   ,0x0E9);
220        i("Audio_Vol_Down" ,0x0EA);
221        // 15.15 Application Launch Buttons
222        i("AL_Cc_Config"       ,0x183);
223        i("AL_Email"           ,0x18A);
224        i("AL_Calculator"      ,0x192);
225        i("AL_Local_Browser"   ,0x194);
226        i("AL_Lock"            ,0x19E);
227        i("AL_Control_Panel"   ,0x19F);
228        i("AL_Assistant"       ,0x1CB);
229        i("AL_Keyboard_Layout" ,0x1AE);
230        // 15.16 Generic GUI Application Controls
231        i("AC_New"                         ,0x201);
232        i("AC_Open"                        ,0x202);
233        i("AC_Close"                       ,0x203);
234        i("AC_Exit"                        ,0x204);
235        i("AC_Maximize"                    ,0x205);
236        i("AC_Minimize"                    ,0x206);
237        i("AC_Save"                        ,0x207);
238        i("AC_Print"                       ,0x208);
239        i("AC_Properties"                  ,0x209);
240        i("AC_Undo"                        ,0x21A);
241        i("AC_Copy"                        ,0x21B);
242        i("AC_Cut"                         ,0x21C);
243        i("AC_Paste"                       ,0x21D);
244        i("AC_Select_All"                  ,0x21E);
245        i("AC_Find"                        ,0x21F);
246        i("AC_Search"                      ,0x221);
247        i("AC_Homepage"                    ,0x223);
248        i("AC_Back"                        ,0x224);
249        i("AC_Forward"                     ,0x225);
250        i("AC_Cancel"                      ,0x226);
251        i("AC_Refresh"                     ,0x227);
252        i("AC_Bookmarks"                   ,0x22A);
253        i("AC_Next_Keyboard_Layout_Select" ,0x29D);
254        i("AC_Desktop_Show_All_Windows"    ,0x29F);
255        i("AC_Soft_Key_Left"               ,0x2A);
256
257        // SYS_CTL
258        i("System_Power_Down", 0x2a1);
259        i("System_Sleep/Sleep", 0x2a2);
260        i("System_Wake_Up/Wakeup", 0x2a3);
261        i("System_Restart", 0x2af);
262        i("System_Display_Toggle_Int_Ext", 0x2d);
263
264        // FIRMWARE
265
266        ins("Reset_Keyboard", key_range::FW_RESET_KEYBOARD);
267        ins("Clear_All", key_range::FW_CLEAR_ALL);
268        ins("Clear_Layers", key_range::FW_CLEAR_LAYERS);
269        ins("Stop_Active", key_range::FW_STOP_ACTIVE);
270        ins("Reset_To_Usb_Boot", key_range::FW_RESET_TO_USB_BOOT);
271// clear_layers clear_input clear_all
272
273        m
274    };
275        static ref KEY_NAMES: HashMap<String, u16> = {
276            let mut m = HashMap::new();
277            for (r, v) in FULL_KEY_NAMES.iter() {
278                let k = if r.len() == 1 {r.to_lowercase()} else {r.replace(DASH_USCORE, "").to_lowercase()};
279                if m.contains_key(k.as_str()) {
280                    panic!("duplicate key {}, {}", r, &k);
281                }
282                m.insert(k, *v);
283            }
284            m
285        };
286}
287
288pub const SHIFT_MOD: u8 = 2;
289
290pub fn unshifted_char_code(c: char) -> char {
291    match c {
292        'A'..='Z' => c.to_ascii_lowercase(),
293        c => *SHIFT_KEY_NAMES.get(&c).unwrap_or(&c),
294    }
295}
296
297pub fn char_to_code(c: char) -> u16 {
298    match c {
299        'a'..='z' => ((c as u8) - b'a' + 4) as u16,
300        '1'..='9' => ((c as u8) - b'1' + 30) as u16,
301        '0' => 39,
302        c => *KEY_NAMES.get(c.to_string().as_str()).unwrap_or(&0),
303    }
304}
305
306pub fn key_code(name: &str) -> Option<u16> {
307    let name = if name.len() > 1 && name.starts_with('\\') {
308        &name[1..]
309    } else {
310        name
311    };
312    if name.contains(DASH_USCORE) {
313        let n2 = name.replace(DASH_USCORE, "");
314
315        KEY_NAMES
316            .get(n2.as_str())
317            .or_else(|| FULL_KEY_NAMES.get(name))
318            .copied()
319    } else {
320        KEY_NAMES
321            .get(name)
322            .or_else(|| FULL_KEY_NAMES.get(name))
323            .copied()
324    }
325}
326
327pub fn action_code(name: &str) -> Option<u16> {
328    ACTION_NAMES.get(name).copied()
329}
330
331pub fn modifier_macro(_name: &str) -> Option<u16> {
332    Some(key_range::MACROS_MIN)
333}
334
335pub fn modifiers_to_bit_map(text: &str) -> Option<u8> {
336    if text.is_empty() {
337        return Some(0);
338    }
339    let mut bm = 0;
340    for s in text.split('-') {
341        match MODIFIER_BIT_MAP.get(s) {
342            Some(bit) => bm |= bit,
343            None => return None,
344        }
345    }
346
347    Some(bm)
348}
349
350pub fn modifiers_to_string(mut modifiers: u8) -> String {
351    let mut ans = String::new();
352
353    for m in MODIFIER_BITS {
354        if modifiers == 0 {
355            return ans;
356        }
357        if modifiers & 1 == 1 {
358            if !ans.is_empty() {
359                ans += "-";
360            }
361            ans += m;
362        }
363
364        modifiers >>= 1;
365    }
366    ans
367}
368
369pub struct KeycodeDescriptor {
370    pub name: &'static str,
371    pub code: u16,
372}
373
374pub fn keycodes_iter() -> impl Iterator<Item = KeycodeDescriptor> {
375    let iter = FULL_KEY_NAMES.iter();
376    iter.map(|(name, code)| KeycodeDescriptor { name, code: *code })
377}
378
379#[cfg(test)]
380#[path = "keycodes_test.rs"]
381mod test;