]> git.proxmox.com Git - grub2.git/blob - util/grub-mklayout.c
merge usb into keylayouts
[grub2.git] / util / grub-mklayout.c
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2010 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/util/misc.h>
20 #include <grub/i18n.h>
21 #include <grub/term.h>
22 #include <grub/keyboard_layouts.h>
23 #include <grub/at_keyboard.h>
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <getopt.h>
29 #include <unistd.h>
30 #include <errno.h>
31
32 #include "progname.h"
33
34 #define CKBCOMP "ckbcomp"
35
36 static struct option options[] = {
37 {"output", required_argument, 0, 'o'},
38 {"help", no_argument, 0, 'h'},
39 {"version", no_argument, 0, 'V'},
40 {"verbose", no_argument, 0, 'v'},
41 {0, 0, 0, 0}
42 };
43
44 struct console_grub_equivalence
45 {
46 char *layout;
47 grub_uint32_t grub;
48 };
49
50 static struct console_grub_equivalence console_grub_equivalences[] = {
51 {"Escape", GRUB_TERM_ESC},
52 {"Tab", GRUB_TERM_TAB},
53 {"Delete", GRUB_TERM_BACKSPACE},
54
55 {"KP_Multiply", '*'},
56 {"KP_Subtract", '-'},
57 {"KP_Add", '+'},
58 {"KP_Divide", '/'},
59
60 {"KP_Enter", '\n'},
61 {"Return", '\n'},
62
63 {"F1", GRUB_TERM_KEY_F1},
64 {"F2", GRUB_TERM_KEY_F2},
65 {"F3", GRUB_TERM_KEY_F3},
66 {"F4", GRUB_TERM_KEY_F4},
67 {"F5", GRUB_TERM_KEY_F5},
68 {"F6", GRUB_TERM_KEY_F6},
69 {"F7", GRUB_TERM_KEY_F7},
70 {"F8", GRUB_TERM_KEY_F8},
71 {"F9", GRUB_TERM_KEY_F9},
72 {"F10", GRUB_TERM_KEY_F10},
73 {"F11", GRUB_TERM_KEY_F11},
74 {"F12", GRUB_TERM_KEY_F12},
75 {"F13", GRUB_TERM_KEY_F1 | GRUB_TERM_SHIFT},
76 {"F14", GRUB_TERM_KEY_F2 | GRUB_TERM_SHIFT},
77 {"F15", GRUB_TERM_KEY_F3 | GRUB_TERM_SHIFT},
78 {"F16", GRUB_TERM_KEY_F4 | GRUB_TERM_SHIFT},
79 {"F17", GRUB_TERM_KEY_F5 | GRUB_TERM_SHIFT},
80 {"F18", GRUB_TERM_KEY_F6 | GRUB_TERM_SHIFT},
81 {"F19", GRUB_TERM_KEY_F7 | GRUB_TERM_SHIFT},
82 {"F20", GRUB_TERM_KEY_F8 | GRUB_TERM_SHIFT},
83 {"F21", GRUB_TERM_KEY_F9 | GRUB_TERM_SHIFT},
84 {"F22", GRUB_TERM_KEY_F10 | GRUB_TERM_SHIFT},
85 {"F23", GRUB_TERM_KEY_F11 | GRUB_TERM_SHIFT},
86 {"F24", GRUB_TERM_KEY_F12 | GRUB_TERM_SHIFT},
87 {"Console_13", GRUB_TERM_KEY_F1 | GRUB_TERM_ALT},
88 {"Console_14", GRUB_TERM_KEY_F2 | GRUB_TERM_ALT},
89 {"Console_15", GRUB_TERM_KEY_F3 | GRUB_TERM_ALT},
90 {"Console_16", GRUB_TERM_KEY_F4 | GRUB_TERM_ALT},
91 {"Console_17", GRUB_TERM_KEY_F5 | GRUB_TERM_ALT},
92 {"Console_18", GRUB_TERM_KEY_F6 | GRUB_TERM_ALT},
93 {"Console_19", GRUB_TERM_KEY_F7 | GRUB_TERM_ALT},
94 {"Console_20", GRUB_TERM_KEY_F8 | GRUB_TERM_ALT},
95 {"Console_21", GRUB_TERM_KEY_F9 | GRUB_TERM_ALT},
96 {"Console_22", GRUB_TERM_KEY_F10 | GRUB_TERM_ALT},
97 {"Console_23", GRUB_TERM_KEY_F11 | GRUB_TERM_ALT},
98 {"Console_24", GRUB_TERM_KEY_F12 | GRUB_TERM_ALT},
99 {"Console_25", GRUB_TERM_KEY_F1 | GRUB_TERM_SHIFT | GRUB_TERM_ALT},
100 {"Console_26", GRUB_TERM_KEY_F2 | GRUB_TERM_SHIFT | GRUB_TERM_ALT},
101 {"Console_27", GRUB_TERM_KEY_F3 | GRUB_TERM_SHIFT | GRUB_TERM_ALT},
102 {"Console_28", GRUB_TERM_KEY_F4 | GRUB_TERM_SHIFT | GRUB_TERM_ALT},
103 {"Console_29", GRUB_TERM_KEY_F5 | GRUB_TERM_SHIFT | GRUB_TERM_ALT},
104 {"Console_30", GRUB_TERM_KEY_F6 | GRUB_TERM_SHIFT | GRUB_TERM_ALT},
105 {"Console_31", GRUB_TERM_KEY_F7 | GRUB_TERM_SHIFT | GRUB_TERM_ALT},
106 {"Console_32", GRUB_TERM_KEY_F8 | GRUB_TERM_SHIFT | GRUB_TERM_ALT},
107 {"Console_33", GRUB_TERM_KEY_F9 | GRUB_TERM_SHIFT | GRUB_TERM_ALT},
108 {"Console_34", GRUB_TERM_KEY_F10 | GRUB_TERM_SHIFT | GRUB_TERM_ALT},
109 {"Console_35", GRUB_TERM_KEY_F11 | GRUB_TERM_SHIFT | GRUB_TERM_ALT},
110 {"Console_36", GRUB_TERM_KEY_F12 | GRUB_TERM_SHIFT | GRUB_TERM_ALT},
111
112 {"Insert", GRUB_TERM_KEY_INSERT},
113 {"Down", GRUB_TERM_KEY_DOWN},
114 {"Up", GRUB_TERM_KEY_UP},
115 {"Home", GRUB_TERM_KEY_HOME},
116 {"End", GRUB_TERM_KEY_END},
117 {"Right", GRUB_TERM_KEY_RIGHT},
118 {"Left", GRUB_TERM_KEY_LEFT},
119 {"VoidSymbol", 0},
120
121 /* "Undead" keys since no dead key support in GRUB. */
122 {"dead_acute", '\''},
123 {"dead_circumflex", '^'},
124 {"dead_grave", '`'},
125 {"dead_tilde", '~'},
126 {"dead_diaeresis", '"'},
127
128 /* Following ones don't provide any useful symbols for shell. */
129 {"dead_cedilla", 0},
130 {"dead_ogonek", 0},
131 {"dead_caron", 0},
132 {"dead_breve", 0},
133 {"dead_doubleacute", 0},
134
135 /* NumLock not supported yet. */
136 {"KP_0", GRUB_TERM_KEY_INSERT},
137 {"KP_1", GRUB_TERM_KEY_END},
138 {"KP_2", GRUB_TERM_KEY_DOWN},
139 {"KP_3", GRUB_TERM_KEY_NPAGE},
140 {"KP_4", GRUB_TERM_KEY_LEFT},
141 {"KP_5", 0},
142 {"KP_6", GRUB_TERM_KEY_RIGHT},
143 {"KP_7", GRUB_TERM_KEY_HOME},
144 {"KP_8", GRUB_TERM_KEY_UP},
145 {"KP_9", GRUB_TERM_KEY_PPAGE},
146 {"KP_Period", GRUB_TERM_KEY_DC},
147
148 /* Unused in GRUB. */
149 {"Pause", 0},
150 {"Remove", 0},
151 {"Next", 0},
152 {"Prior", 0},
153 {"Scroll_Forward", 0},
154 {"Scroll_Backward", 0},
155 {"Hex_0", 0},
156 {"Hex_1", 0},
157 {"Hex_2", 0},
158 {"Hex_3", 0},
159 {"Hex_4", 0},
160 {"Hex_5", 0},
161 {"Hex_6", 0},
162 {"Hex_7", 0},
163 {"Hex_8", 0},
164 {"Hex_9", 0},
165 {"Hex_A", 0},
166 {"Hex_B", 0},
167 {"Hex_C", 0},
168 {"Hex_D", 0},
169 {"Hex_E", 0},
170 {"Hex_F", 0},
171 {"Scroll_Lock", 0},
172 {"Show_Memory", 0},
173 {"Show_Registers", 0},
174 {"Control_backslash", 0},
175 {"Compose", 0},
176
177 /* Keys currently not remappable. */
178 {"CtrlL_Lock", 0},
179 {"Caps_Lock", 0},
180 {"ShiftL", 0},
181 {"Num_Lock", 0},
182 {"Alt", 0},
183 {"AltGr", 0},
184 {"Control", 0},
185 {"Shift", 0},
186
187 {NULL, '\0'}
188 };
189
190 static void
191 usage (int status)
192 {
193 if (status)
194 fprintf (stderr, "Try `%s --help' for more information.\n", program_name);
195 else
196 printf ("\
197 Usage: %s [OPTIONS] LAYOUT\n\
198 -o, --output set output base name file. Default is LAYOUT.gkb\n\
199 -h, --help display this message and exit.\n\
200 -V, --version print version information and exit.\n\
201 -v, --verbose print verbose messages.\n\
202 \n\
203 Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT);
204
205 exit (status);
206 }
207
208 void
209 add_special_keys (struct grub_keyboard_layout *layout)
210 {
211 /* OLPC keys. */
212 layout->keyboard_map[101] = GRUB_TERM_KEY_UP;
213 layout->keyboard_map[102] = GRUB_TERM_KEY_DOWN;
214 layout->keyboard_map[103] = GRUB_TERM_KEY_LEFT;
215 layout->keyboard_map[104] = GRUB_TERM_KEY_RIGHT;
216 }
217
218 static unsigned
219 lookup (char *code)
220 {
221 int i;
222
223 for (i = 0; console_grub_equivalences[i].layout != NULL; i++)
224 if (strcmp (code, console_grub_equivalences[i].layout) == 0)
225 return console_grub_equivalences[i].grub;
226
227 fprintf (stderr, "Unknown key %s\n", code);
228
229 return '\0';
230 }
231
232 static unsigned int
233 get_grub_code (char *layout_code)
234 {
235 unsigned int code;
236
237 if (strncmp (layout_code, "U+", sizeof ("U+") - 1) == 0)
238 sscanf (layout_code, "U+%x", &code);
239 else if (strncmp (layout_code, "+U+", sizeof ("+U+") - 1) == 0)
240 sscanf (layout_code, "+U+%x", &code);
241 else
242 code = lookup (layout_code);
243 return code;
244 }
245
246 static void
247 write_file (FILE *out, struct grub_keyboard_layout *layout)
248 {
249 grub_uint32_t version;
250 unsigned i;
251
252 version = grub_cpu_to_le32 (GRUB_KEYBOARD_LAYOUTS_VERSION);
253
254 for (i = 0; i < ARRAY_SIZE (layout->keyboard_map); i++)
255 layout->keyboard_map[i] = grub_cpu_to_le32(layout->keyboard_map[i]);
256
257 for (i = 0; i < ARRAY_SIZE (layout->keyboard_map_shift); i++)
258 layout->keyboard_map_shift[i]
259 = grub_cpu_to_le32(layout->keyboard_map_shift[i]);
260
261 for (i = 0; i < ARRAY_SIZE (layout->keyboard_map_l3); i++)
262 layout->keyboard_map_l3[i]
263 = grub_cpu_to_le32(layout->keyboard_map_l3[i]);
264
265 for (i = 0; i < ARRAY_SIZE (layout->keyboard_map_shift_l3); i++)
266 layout->keyboard_map_shift_l3[i]
267 = grub_cpu_to_le32(layout->keyboard_map_shift_l3[i]);
268
269 fwrite (GRUB_KEYBOARD_LAYOUTS_FILEMAGIC, 1,
270 GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE, out);
271 fwrite (&version, sizeof (version), 1, out);
272 fwrite (layout, 1, sizeof (*layout), out);
273 }
274
275 static void
276 write_keymaps (FILE *in, FILE *out)
277 {
278 struct grub_keyboard_layout layout;
279 char line[2048];
280 int ok;
281
282 memset (&layout, 0, sizeof (layout));
283
284 /* Process the ckbcomp output and prepare the layouts. */
285 ok = 0;
286 while (fgets (line, sizeof (line), in))
287 {
288 if (strncmp (line, "keycode", sizeof ("keycode") - 1) == 0)
289 {
290 unsigned keycode;
291 char normal[64];
292 char shift[64];
293 char normalalt[64];
294 char shiftalt[64];
295
296 sscanf (line, "keycode %u = %60s %60s %60s %60s", &keycode,
297 normal, shift, normalalt, shiftalt);
298 if (keycode < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE)
299 {
300 layout.keyboard_map[keycode] = get_grub_code (normal);
301 layout.keyboard_map_shift[keycode] = get_grub_code (shift);
302 layout.keyboard_map_l3[keycode] = get_grub_code (normalalt);
303 layout.keyboard_map_shift_l3[keycode]
304 = get_grub_code (shiftalt);
305 ok = 1;
306 }
307 }
308 }
309
310 if (ok == 0)
311 {
312 fprintf (stderr, "ERROR: no keycodes found. Check output of %s.\n",
313 CKBCOMP);
314 exit (1);
315 }
316
317 add_special_keys (&layout);
318
319 write_file (out, &layout);
320 }
321
322 int
323 main (int argc, char *argv[])
324 {
325 int verbosity;
326 char *infile_name = NULL;
327 char *outfile_name = NULL;
328 FILE *in, *out;
329
330 set_program_name (argv[0]);
331
332 verbosity = 0;
333
334 /* Check for options. */
335 while (1)
336 {
337 int c = getopt_long (argc, argv, "o:i:hVv", options, 0);
338
339 if (c == -1)
340 break;
341 else
342 switch (c)
343 {
344 case 'h':
345 usage (0);
346 break;
347
348 case 'i':
349 infile_name = optarg;
350 break;
351
352 case 'o':
353 outfile_name = optarg;
354 break;
355
356 case 'V':
357 printf ("%s (%s) %s\n", program_name, PACKAGE_NAME,
358 PACKAGE_VERSION);
359 return 0;
360
361 case 'v':
362 verbosity++;
363 break;
364
365 default:
366 usage (1);
367 break;
368 }
369 }
370
371 if (infile_name)
372 in = fopen (infile_name, "r");
373 else
374 in = stdin;
375
376 if (!in)
377 grub_util_error ("Couldn't open input file: %s\n", strerror (errno));
378
379 if (outfile_name)
380 out = fopen (outfile_name, "wb");
381 else
382 out = stdout;
383
384 if (!out)
385 {
386 if (in != stdin)
387 fclose (in);
388 grub_util_error ("Couldn't open output file: %s\n", strerror (errno));
389 }
390
391 write_keymaps (in, out);
392
393 if (in != stdin)
394 fclose (in);
395
396 if (out != stdout)
397 fclose (out);
398
399 return 0;
400 }