]>
Commit | Line | Data |
---|---|---|
87fae34a VS |
1 | /* |
2 | * GRUB -- GRand Unified Bootloader | |
3 | * Copyright (C) 2002,2003,2005,2007,2008,2009 Free Software Foundation, Inc. | |
4 | * | |
5 | * GRUB is free software: you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, either version 3 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * GRUB is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with GRUB. If not, see <http://www.gnu.org/licenses/>. | |
17 | */ | |
18 | ||
19 | #include <grub/term.h> | |
20 | #include <grub/err.h> | |
21 | #include <grub/mm.h> | |
22 | #include <grub/misc.h> | |
23 | #include <grub/env.h> | |
24 | #include <grub/time.h> | |
25 | #include <grub/dl.h> | |
d90aa784 VS |
26 | #include <grub/keyboard_layouts.h> |
27 | #include <grub/command.h> | |
d90aa784 | 28 | #include <grub/i18n.h> |
fea90138 | 29 | #include <grub/file.h> |
87fae34a | 30 | |
e745cf0c VS |
31 | GRUB_MOD_LICENSE ("GPLv3+"); |
32 | ||
e55e0962 | 33 | static struct grub_keyboard_layout layout_us = { |
5ef4e084 | 34 | .keyboard_map = { |
c32f26bc VS |
35 | /* Keyboard errors. Handled by driver. */ |
36 | /* 0x00 */ 0, 0, 0, 0, | |
37 | ||
38 | /* 0x04 */ 'a', 'b', 'c', 'd', | |
39 | /* 0x08 */ 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', | |
40 | /* 0x10 */ 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', | |
41 | /* 0x18 */ 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', | |
42 | /* 0x20 */ '3', '4', '5', '6', '7', '8', '9', '0', | |
bdd89d23 | 43 | /* 0x28 */ '\n', GRUB_TERM_ESC, GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, ' ', '-', '=', '[', |
c32f26bc VS |
44 | /* According to usage table 0x31 should be mapped to '/' |
45 | but testing with real keyboard shows that 0x32 is remapped to '/'. | |
46 | Map 0x31 to 0. | |
47 | */ | |
48 | /* 0x30 */ ']', 0, '\\', ';', '\'', '`', ',', '.', | |
49 | /* 0x39 is CapsLock. Handled by driver. */ | |
50 | /* 0x38 */ '/', 0, GRUB_TERM_KEY_F1, GRUB_TERM_KEY_F2, | |
51 | /* 0x3c */ GRUB_TERM_KEY_F3, GRUB_TERM_KEY_F4, | |
52 | /* 0x3e */ GRUB_TERM_KEY_F5, GRUB_TERM_KEY_F6, | |
53 | /* 0x40 */ GRUB_TERM_KEY_F7, GRUB_TERM_KEY_F8, | |
54 | /* 0x42 */ GRUB_TERM_KEY_F9, GRUB_TERM_KEY_F10, | |
55 | /* 0x44 */ GRUB_TERM_KEY_F11, GRUB_TERM_KEY_F12, | |
56 | /* PrtScr and ScrollLock. Not handled yet. */ | |
57 | /* 0x46 */ 0, 0, | |
58 | /* 0x48 is Pause. Not handled yet. */ | |
59 | /* 0x48 */ 0, GRUB_TERM_KEY_INSERT, | |
60 | /* 0x4a */ GRUB_TERM_KEY_HOME, GRUB_TERM_KEY_PPAGE, | |
61 | /* 0x4c */ GRUB_TERM_KEY_DC, GRUB_TERM_KEY_END, | |
62 | /* 0x4e */ GRUB_TERM_KEY_NPAGE, GRUB_TERM_KEY_RIGHT, | |
63 | /* 0x50 */ GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_DOWN, | |
64 | /* 0x53 is NumLock. Handled by driver. */ | |
65 | /* 0x52 */ GRUB_TERM_KEY_UP, 0, | |
66 | /* 0x54 */ '/', '*', | |
67 | /* 0x56 */ '-', '+', | |
68 | /* 0x58 */ '\n', GRUB_TERM_KEY_END, | |
69 | /* 0x5a */ GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_NPAGE, | |
70 | /* 0x5c */ GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_CENTER, | |
71 | /* 0x5e */ GRUB_TERM_KEY_RIGHT, GRUB_TERM_KEY_HOME, | |
72 | /* 0x60 */ GRUB_TERM_KEY_UP, GRUB_TERM_KEY_PPAGE, | |
73 | /* 0x62 */ GRUB_TERM_KEY_INSERT, GRUB_TERM_KEY_DC, | |
74 | /* 0x64 */ '\\' | |
5ef4e084 VS |
75 | }, |
76 | .keyboard_map_shift = { | |
c32f26bc VS |
77 | /* Keyboard errors. Handled by driver. */ |
78 | /* 0x00 */ 0, 0, 0, 0, | |
79 | ||
80 | /* 0x04 */ 'A', 'B', 'C', 'D', | |
81 | /* 0x08 */ 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', | |
82 | /* 0x10 */ 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', | |
83 | /* 0x18 */ 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@', | |
84 | /* 0x20 */ '#', '$', '%', '^', '&', '*', '(', ')', | |
bdd89d23 PB |
85 | /* 0x28 */ '\n' | GRUB_TERM_SHIFT, GRUB_TERM_ESC | GRUB_TERM_SHIFT, |
86 | /* 0x2a */ GRUB_TERM_BACKSPACE | GRUB_TERM_SHIFT, GRUB_TERM_TAB | GRUB_TERM_SHIFT, | |
c32f26bc VS |
87 | /* 0x2c */ ' ' | GRUB_TERM_SHIFT, '_', '+', '{', |
88 | /* According to usage table 0x31 should be mapped to '/' | |
89 | but testing with real keyboard shows that 0x32 is remapped to '/'. | |
90 | Map 0x31 to 0. | |
91 | */ | |
92 | /* 0x30 */ '}', 0, '|', ':', '"', '~', '<', '>', | |
93 | /* 0x39 is CapsLock. Handled by driver. */ | |
94 | /* 0x38 */ '?', 0, | |
95 | /* 0x3a */ GRUB_TERM_KEY_F1 | GRUB_TERM_SHIFT, | |
96 | /* 0x3b */ GRUB_TERM_KEY_F2 | GRUB_TERM_SHIFT, | |
97 | /* 0x3c */ GRUB_TERM_KEY_F3 | GRUB_TERM_SHIFT, | |
98 | /* 0x3d */ GRUB_TERM_KEY_F4 | GRUB_TERM_SHIFT, | |
99 | /* 0x3e */ GRUB_TERM_KEY_F5 | GRUB_TERM_SHIFT, | |
100 | /* 0x3f */ GRUB_TERM_KEY_F6 | GRUB_TERM_SHIFT, | |
101 | /* 0x40 */ GRUB_TERM_KEY_F7 | GRUB_TERM_SHIFT, | |
102 | /* 0x41 */ GRUB_TERM_KEY_F8 | GRUB_TERM_SHIFT, | |
103 | /* 0x42 */ GRUB_TERM_KEY_F9 | GRUB_TERM_SHIFT, | |
104 | /* 0x43 */ GRUB_TERM_KEY_F10 | GRUB_TERM_SHIFT, | |
105 | /* 0x44 */ GRUB_TERM_KEY_F11 | GRUB_TERM_SHIFT, | |
106 | /* 0x45 */ GRUB_TERM_KEY_F12 | GRUB_TERM_SHIFT, | |
107 | /* PrtScr and ScrollLock. Not handled yet. */ | |
108 | /* 0x46 */ 0, 0, | |
109 | /* 0x48 is Pause. Not handled yet. */ | |
110 | /* 0x48 */ 0, GRUB_TERM_KEY_INSERT | GRUB_TERM_SHIFT, | |
111 | /* 0x4a */ GRUB_TERM_KEY_HOME | GRUB_TERM_SHIFT, | |
112 | /* 0x4b */ GRUB_TERM_KEY_PPAGE | GRUB_TERM_SHIFT, | |
113 | /* 0x4c */ GRUB_TERM_KEY_DC | GRUB_TERM_SHIFT, | |
114 | /* 0x4d */ GRUB_TERM_KEY_END | GRUB_TERM_SHIFT, | |
115 | /* 0x4e */ GRUB_TERM_KEY_NPAGE | GRUB_TERM_SHIFT, | |
116 | /* 0x4f */ GRUB_TERM_KEY_RIGHT | GRUB_TERM_SHIFT, | |
117 | /* 0x50 */ GRUB_TERM_KEY_LEFT | GRUB_TERM_SHIFT, | |
118 | /* 0x51 */ GRUB_TERM_KEY_DOWN | GRUB_TERM_SHIFT, | |
119 | /* 0x53 is NumLock. Handled by driver. */ | |
120 | /* 0x52 */ GRUB_TERM_KEY_UP | GRUB_TERM_SHIFT, 0, | |
121 | /* 0x54 */ '/', '*', | |
122 | /* 0x56 */ '-', '+', | |
123 | /* 0x58 */ '\n' | GRUB_TERM_SHIFT, '1', '2', '3', '4', '5','6', '7', | |
124 | /* 0x60 */ '8', '9', '0', '.', '|' | |
e55e0962 VS |
125 | } |
126 | }; | |
127 | ||
128 | static struct grub_keyboard_layout *grub_current_layout = &layout_us; | |
129 | ||
130 | static int | |
131 | map_key_core (int code, int status, int *alt_gr_consumed) | |
132 | { | |
133 | *alt_gr_consumed = 0; | |
134 | ||
bbdd6305 VS |
135 | if (code >= GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE) |
136 | return 0; | |
137 | ||
e55e0962 VS |
138 | if (status & GRUB_TERM_STATUS_RALT) |
139 | { | |
140 | if (status & (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT)) | |
141 | { | |
5ef4e084 | 142 | if (grub_current_layout->keyboard_map_shift_l3[code]) |
e55e0962 VS |
143 | { |
144 | *alt_gr_consumed = 1; | |
5ef4e084 | 145 | return grub_current_layout->keyboard_map_shift_l3[code]; |
e55e0962 | 146 | } |
e55e0962 | 147 | } |
c32f26bc | 148 | else if (grub_current_layout->keyboard_map_l3[code]) |
e55e0962 VS |
149 | { |
150 | *alt_gr_consumed = 1; | |
5ef4e084 | 151 | return grub_current_layout->keyboard_map_l3[code]; |
e55e0962 VS |
152 | } |
153 | } | |
154 | if (status & (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT)) | |
c32f26bc | 155 | return grub_current_layout->keyboard_map_shift[code]; |
e55e0962 | 156 | else |
5ef4e084 | 157 | return grub_current_layout->keyboard_map[code]; |
e55e0962 VS |
158 | } |
159 | ||
160 | unsigned | |
9e91bd9d | 161 | grub_term_map_key (grub_keyboard_key_t code, int status) |
e55e0962 | 162 | { |
49c822bc | 163 | int alt_gr_consumed = 0; |
e55e0962 VS |
164 | int key; |
165 | ||
c32f26bc VS |
166 | if (code >= 0x59 && code <= 0x63 && (status & GRUB_TERM_STATUS_NUM)) |
167 | { | |
168 | if (status & (GRUB_TERM_STATUS_RSHIFT | GRUB_TERM_STATUS_LSHIFT)) | |
169 | status &= ~(GRUB_TERM_STATUS_RSHIFT | GRUB_TERM_STATUS_LSHIFT); | |
170 | else | |
171 | status |= GRUB_TERM_STATUS_RSHIFT; | |
172 | } | |
173 | ||
174 | key = map_key_core (code, status, &alt_gr_consumed); | |
e55e0962 | 175 | |
7c378c39 | 176 | if (key == 0 || key == GRUB_TERM_SHIFT) { |
c32f26bc | 177 | grub_printf ("Unknown key 0x%x detected\n", code); |
7c378c39 VS |
178 | return GRUB_TERM_NO_KEY; |
179 | } | |
e55e0962 VS |
180 | |
181 | if (status & GRUB_TERM_STATUS_CAPS) | |
182 | { | |
183 | if ((key >= 'a') && (key <= 'z')) | |
184 | key += 'A' - 'a'; | |
185 | else if ((key >= 'A') && (key <= 'Z')) | |
186 | key += 'a' - 'A'; | |
187 | } | |
188 | ||
189 | if ((status & GRUB_TERM_STATUS_LALT) || | |
190 | ((status & GRUB_TERM_STATUS_RALT) && !alt_gr_consumed)) | |
191 | key |= GRUB_TERM_ALT; | |
192 | if (status & (GRUB_TERM_STATUS_LCTRL | GRUB_TERM_STATUS_RCTRL)) | |
193 | key |= GRUB_TERM_CTRL; | |
194 | ||
195 | return key; | |
196 | } | |
197 | ||
d90aa784 VS |
198 | static grub_err_t |
199 | grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)), | |
200 | int argc, char *argv[]) | |
201 | { | |
202 | char *filename; | |
203 | grub_file_t file; | |
204 | grub_uint32_t version; | |
205 | grub_uint8_t magic[GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE]; | |
ed19677f | 206 | struct grub_keyboard_layout *newmap = NULL; |
d90aa784 VS |
207 | unsigned i; |
208 | ||
209 | if (argc < 1) | |
210 | return grub_error (GRUB_ERR_BAD_ARGUMENT, "file or layout name required"); | |
211 | if (argv[0][0] != '(' && argv[0][0] != '/' && argv[0][0] != '+') | |
212 | { | |
213 | const char *prefix = grub_env_get ("prefix"); | |
214 | if (!prefix) | |
9c4b5c13 | 215 | return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("variable `%s' isn't set"), "prefix"); |
d90aa784 VS |
216 | filename = grub_xasprintf ("%s/layouts/%s.gkb", prefix, argv[0]); |
217 | if (!filename) | |
218 | return grub_errno; | |
219 | } | |
220 | else | |
221 | filename = argv[0]; | |
222 | ||
ca0a4f68 | 223 | file = grub_file_open (filename, GRUB_FILE_TYPE_KEYBOARD_LAYOUT); |
d90aa784 VS |
224 | if (! file) |
225 | goto fail; | |
226 | ||
227 | if (grub_file_read (file, magic, sizeof (magic)) != sizeof (magic)) | |
228 | { | |
229 | if (!grub_errno) | |
9c4b5c13 VS |
230 | grub_error (GRUB_ERR_BAD_ARGUMENT, N_("premature end of file %s"), |
231 | filename); | |
d90aa784 VS |
232 | goto fail; |
233 | } | |
234 | ||
235 | if (grub_memcmp (magic, GRUB_KEYBOARD_LAYOUTS_FILEMAGIC, | |
236 | GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE) != 0) | |
237 | { | |
238 | grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid magic"); | |
239 | goto fail; | |
240 | } | |
241 | ||
242 | if (grub_file_read (file, &version, sizeof (version)) != sizeof (version)) | |
243 | { | |
244 | if (!grub_errno) | |
9c4b5c13 VS |
245 | grub_error (GRUB_ERR_BAD_ARGUMENT, N_("premature end of file %s"), |
246 | filename); | |
d90aa784 VS |
247 | goto fail; |
248 | } | |
249 | ||
bbdd6305 | 250 | if (version != grub_cpu_to_le32_compile_time (GRUB_KEYBOARD_LAYOUTS_VERSION)) |
d90aa784 VS |
251 | { |
252 | grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid version"); | |
253 | goto fail; | |
254 | } | |
255 | ||
ed19677f VS |
256 | newmap = grub_malloc (sizeof (*newmap)); |
257 | if (!newmap) | |
258 | goto fail; | |
d90aa784 | 259 | |
ed19677f | 260 | if (grub_file_read (file, newmap, sizeof (*newmap)) != sizeof (*newmap)) |
eb628338 VS |
261 | { |
262 | if (!grub_errno) | |
9c4b5c13 VS |
263 | grub_error (GRUB_ERR_BAD_ARGUMENT, N_("premature end of file %s"), |
264 | filename); | |
eb628338 VS |
265 | goto fail; |
266 | } | |
267 | ||
5ef4e084 VS |
268 | for (i = 0; i < ARRAY_SIZE (newmap->keyboard_map); i++) |
269 | newmap->keyboard_map[i] = grub_le_to_cpu32(newmap->keyboard_map[i]); | |
e55e0962 | 270 | |
5ef4e084 VS |
271 | for (i = 0; i < ARRAY_SIZE (newmap->keyboard_map_shift); i++) |
272 | newmap->keyboard_map_shift[i] | |
273 | = grub_le_to_cpu32(newmap->keyboard_map_shift[i]); | |
e55e0962 | 274 | |
5ef4e084 VS |
275 | for (i = 0; i < ARRAY_SIZE (newmap->keyboard_map_l3); i++) |
276 | newmap->keyboard_map_l3[i] | |
277 | = grub_le_to_cpu32(newmap->keyboard_map_l3[i]); | |
e55e0962 | 278 | |
5ef4e084 VS |
279 | for (i = 0; i < ARRAY_SIZE (newmap->keyboard_map_shift_l3); i++) |
280 | newmap->keyboard_map_shift_l3[i] | |
281 | = grub_le_to_cpu32(newmap->keyboard_map_shift_l3[i]); | |
e55e0962 VS |
282 | |
283 | grub_current_layout = newmap; | |
284 | ||
d90aa784 VS |
285 | return GRUB_ERR_NONE; |
286 | ||
287 | fail: | |
288 | if (filename != argv[0]) | |
289 | grub_free (filename); | |
ed19677f | 290 | grub_free (newmap); |
d90aa784 VS |
291 | if (file) |
292 | grub_file_close (file); | |
293 | return grub_errno; | |
294 | } | |
295 | ||
d90aa784 VS |
296 | static grub_command_t cmd; |
297 | ||
87fae34a VS |
298 | GRUB_MOD_INIT(keylayouts) |
299 | { | |
d90aa784 VS |
300 | cmd = grub_register_command ("keymap", grub_cmd_keymap, |
301 | 0, N_("Load a keyboard layout.")); | |
87fae34a VS |
302 | } |
303 | ||
304 | GRUB_MOD_FINI(keylayouts) | |
305 | { | |
d90aa784 | 306 | grub_unregister_command (cmd); |
87fae34a | 307 | } |