Rust · 3170 bytes Raw Blame History
1 //! Keyboard input handling for the greeter
2 //!
3 //! Converts X11 keycodes to characters with basic shift support.
4
5 use x11rb::protocol::xproto::KeyButMask;
6
7 /// Common X11 keycodes (evdev-based, typical for modern Linux)
8 pub mod keycodes {
9 pub const ESCAPE: u8 = 9;
10 pub const BACKSPACE: u8 = 22;
11 pub const TAB: u8 = 23;
12 pub const RETURN: u8 = 36;
13 pub const SHIFT_L: u8 = 50;
14 pub const SHIFT_R: u8 = 62;
15 pub const CAPS_LOCK: u8 = 66;
16 pub const LEFT: u8 = 113;
17 pub const UP: u8 = 111;
18 pub const RIGHT: u8 = 114;
19 pub const DOWN: u8 = 116;
20 pub const HOME: u8 = 110;
21 pub const END: u8 = 115;
22 pub const DELETE: u8 = 119;
23 }
24
25 /// Convert a keycode to a character, considering shift and caps lock state
26 pub fn keycode_to_char(keycode: u8, state: KeyButMask) -> Option<char> {
27 let shift_pressed = state.contains(KeyButMask::SHIFT);
28 let caps_lock_on = state.contains(KeyButMask::LOCK);
29
30 // Main alphanumeric keys (evdev keycodes)
31 let base = match keycode {
32 // Number row
33 10 => '1',
34 11 => '2',
35 12 => '3',
36 13 => '4',
37 14 => '5',
38 15 => '6',
39 16 => '7',
40 17 => '8',
41 18 => '9',
42 19 => '0',
43 20 => '-',
44 21 => '=',
45
46 // Top row (QWERTY)
47 24 => 'q',
48 25 => 'w',
49 26 => 'e',
50 27 => 'r',
51 28 => 't',
52 29 => 'y',
53 30 => 'u',
54 31 => 'i',
55 32 => 'o',
56 33 => 'p',
57 34 => '[',
58 35 => ']',
59
60 // Home row (ASDF)
61 38 => 'a',
62 39 => 's',
63 40 => 'd',
64 41 => 'f',
65 42 => 'g',
66 43 => 'h',
67 44 => 'j',
68 45 => 'k',
69 46 => 'l',
70 47 => ';',
71 48 => '\'',
72 51 => '\\',
73
74 // Bottom row (ZXCV)
75 52 => 'z',
76 53 => 'x',
77 54 => 'c',
78 55 => 'v',
79 56 => 'b',
80 57 => 'n',
81 58 => 'm',
82 59 => ',',
83 60 => '.',
84 61 => '/',
85
86 // Space
87 65 => ' ',
88
89 // Grave/tilde
90 49 => '`',
91
92 _ => return None,
93 };
94
95 // For letters: uppercase if shift XOR caps_lock (one but not both)
96 // For symbols: only shift matters
97 let c = if base.is_ascii_lowercase() {
98 // Letters: shift XOR caps_lock determines case
99 if shift_pressed != caps_lock_on {
100 base.to_ascii_uppercase()
101 } else {
102 base
103 }
104 } else if shift_pressed {
105 // Non-letters: only shift affects them
106 match base {
107 // Numbers to symbols
108 '1' => '!',
109 '2' => '@',
110 '3' => '#',
111 '4' => '$',
112 '5' => '%',
113 '6' => '^',
114 '7' => '&',
115 '8' => '*',
116 '9' => '(',
117 '0' => ')',
118 '-' => '_',
119 '=' => '+',
120 '[' => '{',
121 ']' => '}',
122 ';' => ':',
123 '\'' => '"',
124 '\\' => '|',
125 ',' => '<',
126 '.' => '>',
127 '/' => '?',
128 '`' => '~',
129 c => c,
130 }
131 } else {
132 base
133 };
134
135 Some(c)
136 }
137