=== added file 'ChangeLog.keyboard_layouts' --- ChangeLog.keyboard_layouts 1970-01-01 00:00:00 +0000 +++ ChangeLog.keyboard_layouts 2010-02-13 23:49:34 +0000 @@ -0,0 +1,31 @@ +2010-01-18 Carles Pina i Estany + + Adds keyboard layouts support (AT and USB) + + * conf/common.rmk (bin_UTILITIES): Add grub-mklayouts rules. + (pkglib_MODULES): Add module `at_keyboard_layouts.mod' and + `usb_keyboard_layouts.mod'. + * include/grub/at_keyboard.h: Include `"keyboard.h"'. New EXPORT_VAR + `grub_keyboard_map'. + * include/grub/keyboard.h: New file. + * include/grub/keyboard_layouts.h: New file. + * include/grub/term.h: Move macros from here ... + * include/grub/keys.h: ... to here. New file. + * include/grub/usb_keyboard.h: New file. + * keyboard_layouts/keyboard_layouts.c: New file. + * keyboard_layouts/at_keyboard_layouts.c: New file. + * keyboard_layouts/usb_keyboard_layouts.c: New file. + * term/at_keyboard.c: Include `'. + (grub_at_keyboard_map): Declare. + (keyboard_map_normal): Renamed from keyboard_map. + (grub_at_keyboard_getkey_noblock): Use `grub_keyboard_map' instead of + `keyboard_map' and `keyboard_map_shift'. + (GRUB_MOD_INIT): Initialise `grub_at_keyboard_map'. + * term/usb_keyboard.c: Include `' and + `'. + (grub_usb_keyboard_map): Declare. + (keyboard_map_normal): Renamed from keyboard_map. + (grub_usb_keyboard_checkkey): Use `keyboard_map_normal' instead of + `keyboard_map'. + (GRUB_MOD_INIT): Initialise `grub_usb_keyboard_map'. + * util/grub-mklayouts.c: New file. === modified file 'conf/common.rmk' --- conf/common.rmk 2010-02-06 14:37:23 +0000 +++ conf/common.rmk 2010-02-13 23:35:33 +0000 @@ -91,6 +91,10 @@ grub_mkrelpath_SOURCES = gnulib/progname bin_UTILITIES += grub-bin2h grub_bin2h_SOURCES = gnulib/progname.c util/bin2h.c +# For grub-mklayouts. +bin_UTILITIES += grub-mklayouts +grub_mklayouts_SOURCES = gnulib/progname.c util/grub-mklayouts.c util/misc.c + # For grub-script-check. bin_UTILITIES += grub-script-check util/grub-script-check.c_DEPENDENCIES = grub_script_check_init.h @@ -105,6 +109,18 @@ grub_script.tab.c grub_script.tab.h: scr $(YACC) -d -p grub_script_yy -b grub_script $(srcdir)/script/parser.y DISTCLEANFILES += grub_script.tab.c grub_script.tab.h +# For at_keyboard_layouts.mod +pkglib_MODULES += at_keyboard_layouts.mod +at_keyboard_layouts_mod_SOURCES = keyboard_layouts/at_keyboard_layouts.c +at_keyboard_layouts_mod_CFLAGS = $(COMMON_CFLAGS) +at_keyboard_layouts_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For usb_keyboard_layouts.mod +pkglib_MODULES += usb_keyboard_layouts.mod +usb_keyboard_layouts_mod_SOURCES = keyboard_layouts/usb_keyboard_layouts.c +usb_keyboard_layouts_mod_CFLAGS = $(COMMON_CFLAGS) +usb_keyboard_layouts_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For grub-script-check. grub_script_check_init.lst: geninit.sh $(filter-out grub_script_check_init.c,$(grub_script_check_SOURCES)) rm -f $@; grep GRUB_MOD_INIT $(filter %.c,$^) /dev/null > $@ === modified file 'include/grub/at_keyboard.h' --- include/grub/at_keyboard.h 2009-12-25 22:29:47 +0000 +++ include/grub/at_keyboard.h 2010-02-13 23:05:39 +0000 @@ -19,6 +19,10 @@ #ifndef GRUB_AT_KEYBOARD_HEADER #define GRUB_AT_KEYBOARD_HEADER 1 +#include "keyboard.h" + +extern struct grub_keyboard_map_s *EXPORT_VAR(grub_at_keyboard_map); + #define SHIFT_L 0x2a #define SHIFT_R 0x36 #define CTRL 0x1d === added file 'include/grub/keyboard.h' --- include/grub/keyboard.h 1970-01-01 00:00:00 +0000 +++ include/grub/keyboard.h 2010-02-13 23:29:48 +0000 @@ -0,0 +1,28 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_KEYBOARD_HEADER +#define GRUB_KEYBOARD_HEADER 1 + +struct grub_keyboard_map_s +{ + char *normal; + char *shift; +}; + +#endif === added file 'include/grub/keyboard_layouts.h' --- include/grub/keyboard_layouts.h 1970-01-01 00:00:00 +0000 +++ include/grub/keyboard_layouts.h 2010-02-05 18:58:05 +0000 @@ -0,0 +1,25 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_KEYBOARD_LAYOUTS_H +#define GRUB_KEYBOARD_LAYOUTS_H 1 + +#define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC "GRUBLAYO" +#define GRUB_KEYBOARD_LAYOUTS_VERSION 1 + +#endif /* GRUB_KEYBOARD_LAYOUTS */ === added file 'include/grub/keys.h' --- include/grub/keys.h 1970-01-01 00:00:00 +0000 +++ include/grub/keys.h 2010-01-17 18:21:42 +0000 @@ -0,0 +1,36 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_KEYS_HEADER +#define GRUB_KEYS_HEADER 1 + +/* Internal codes used by GRUB to represent terminal input. */ +#define GRUB_TERM_LEFT 2 +#define GRUB_TERM_RIGHT 6 +#define GRUB_TERM_UP 16 +#define GRUB_TERM_DOWN 14 +#define GRUB_TERM_HOME 1 +#define GRUB_TERM_END 5 +#define GRUB_TERM_DC 4 +#define GRUB_TERM_PPAGE 7 +#define GRUB_TERM_NPAGE 3 +#define GRUB_TERM_ESC '\e' +#define GRUB_TERM_TAB '\t' +#define GRUB_TERM_BACKSPACE 8 + +#endif /* ! GRUB_KEYS_HEADER */ === modified file 'include/grub/term.h' --- include/grub/term.h 2010-02-03 00:24:07 +0000 +++ include/grub/term.h 2010-01-29 23:31:29 +0000 @@ -19,19 +19,7 @@ #ifndef GRUB_TERM_HEADER #define GRUB_TERM_HEADER 1 -/* Internal codes used by GRUB to represent terminal input. */ -#define GRUB_TERM_LEFT 2 -#define GRUB_TERM_RIGHT 6 -#define GRUB_TERM_UP 16 -#define GRUB_TERM_DOWN 14 -#define GRUB_TERM_HOME 1 -#define GRUB_TERM_END 5 -#define GRUB_TERM_DC 4 -#define GRUB_TERM_PPAGE 7 -#define GRUB_TERM_NPAGE 3 -#define GRUB_TERM_ESC '\e' -#define GRUB_TERM_TAB '\t' -#define GRUB_TERM_BACKSPACE 8 +#include #ifndef ASM_FILE === added file 'include/grub/usb_keyboard.h' --- include/grub/usb_keyboard.h 1970-01-01 00:00:00 +0000 +++ include/grub/usb_keyboard.h 2010-02-13 23:29:58 +0000 @@ -0,0 +1,26 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_USB_KEYBOARD_HEADER +#define GRUB_USB_KEYBOARD_HEADER 1 + +#include "keyboard.h" + +extern struct grub_keyboard_map_s *EXPORT_VAR(grub_usb_keyboard_map); + +#endif === added directory 'keyboard_layouts' === added file 'keyboard_layouts/at_keyboard_layouts.c' --- keyboard_layouts/at_keyboard_layouts.c 1970-01-01 00:00:00 +0000 +++ keyboard_layouts/at_keyboard_layouts.c 2010-02-13 23:22:51 +0000 @@ -0,0 +1,6 @@ +#define DO_AT_KEYBOARD_LAYOUT 1 +#define COMMAND_NAME_LOAD "at_load_layout" +#define COMMAND_NAME_SHOW "at_show_layout" +#define COMMAND_NAME_RESTORE "at**" +#define FILE_SUFFIX ".at" +#include "keyboard_layouts.c" === added file 'keyboard_layouts/keyboard_layouts.c' --- keyboard_layouts/keyboard_layouts.c 1970-01-01 00:00:00 +0000 +++ keyboard_layouts/keyboard_layouts.c 2010-02-13 23:24:16 +0000 @@ -0,0 +1,213 @@ +/* at_keyboard_layouts.c - at_keyboard_layouts module */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DO_AT_KEYBOARD_LAYOUT + #include +#else + #include +#endif + +#include + +#include + +static char original_keyboard_layout_normal[128]; +static char original_keyboard_layout_shift[128]; + +static char *active_layout; + +static struct grub_keyboard_map_s *keyboard_map; + +static grub_err_t +grub_cmd_load_layout(grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + char magic[8]; + int check; + char *filename; + char *prefix; + int filename_length; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "usage: load_layout LAYOUT"); + + prefix = grub_env_get ("keymaps_dir"); + if (!prefix) + return grub_error (GRUB_ERR_READ_ERROR, + "`keymaps_dir' variable not set up"); + + filename_length = grub_strlen (prefix) + grub_strlen ("/") + + grub_strlen (args[0]) + grub_strlen(FILE_SUFFIX) + 1; + + filename = + grub_malloc (filename_length); + + if (! filename) + return grub_errno; + + grub_snprintf (filename, filename_length, "%s/%s%s", prefix, args[0], + FILE_SUFFIX); + + grub_file_t keyboard_file; + keyboard_file = grub_file_open (filename); + + if (!keyboard_file) + { + return grub_error (GRUB_ERR_READ_ERROR, "cannot open file `%s'", + filename); + return 0; + } + + check = + grub_file_read (keyboard_file, magic, + sizeof (GRUB_KEYBOARD_LAYOUTS_FILEMAGIC) - 1); + + if (check != sizeof (GRUB_KEYBOARD_LAYOUTS_FILEMAGIC) - 1) + { + return grub_error (GRUB_ERR_READ_ERROR, + "cannot read the file header from `%s'", filename); + } + + if (grub_memcmp + (magic, GRUB_KEYBOARD_LAYOUTS_FILEMAGIC, + sizeof (GRUB_KEYBOARD_LAYOUTS_FILEMAGIC) - 1) != 0) + { + grub_file_close (keyboard_file); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "file not recognised (`%s')", + filename); + } + grub_uint32_t version; + check = grub_file_read (keyboard_file, &version, 4); + + if (check != 4) + { + grub_file_close (keyboard_file); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "cannot check file version (`%s')", filename); + } + + version = grub_be_to_cpu32 (version); + if (version != GRUB_KEYBOARD_LAYOUTS_VERSION) + { + grub_file_close (keyboard_file); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "invalid file version: %d (`%s')", version, + filename); + } + + + + check = grub_file_read (keyboard_file, keyboard_map->normal, 128); + if (check != 128) + { + grub_file_close (keyboard_file); + return grub_error (GRUB_ERR_READ_ERROR, + "problem reading normal keyboard from `%s'", + filename); + } + + check = grub_file_read (keyboard_file, keyboard_map->shift, 128); + if (check != 128) + { + grub_file_close (keyboard_file); + return grub_error (GRUB_ERR_READ_ERROR, + "problem reading shift keyboard from `%s'", + filename); + } + + grub_free (active_layout); + active_layout = grub_strdup (args[0]); + + grub_file_close (keyboard_file); + return 0; +} + +static grub_err_t +grub_cmd_show_active_keyboardlayout (grub_command_t cmd + __attribute__ ((unused)), int argc + __attribute__ ((unused)), char **args + __attribute__ ((unused))) +{ + grub_printf ("Active layout: `%s'.\n", active_layout); + return 0; +} + +static void +set_default_keyboard(void) +{ + grub_free (active_layout); + active_layout = grub_strdup("default"); + grub_memcpy (keyboard_map->normal, original_keyboard_layout_normal, + 128); + grub_memcpy (keyboard_map->shift, original_keyboard_layout_shift, 128); +} + +static grub_err_t +grub_cmd_set_default_keyboard (grub_command_t cmd __attribute__ ((unused)), int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) +{ + set_default_keyboard(); + grub_printf_ (N_("Reverted to default keymap layout.\n")); + return 0; +} + +#ifdef DO_AT_KEYBOARD_LAYOUT +GRUB_MOD_INIT (at_keyboard_layouts) +#else +GRUB_MOD_INIT (usb_keyboard_layouts) +#endif +{ +#ifdef DO_AT_KEYBOARD_LAYOUT + keyboard_map = grub_at_keyboard_map; +#else + keyboard_map = grub_usb_keyboard_map; +#endif + + grub_memcpy (original_keyboard_layout_normal, keyboard_map->normal, + 128); + grub_memcpy (original_keyboard_layout_shift, keyboard_map->shift, 128); + + active_layout = grub_strdup("default"); + + grub_register_command_p1 (COMMAND_NAME_LOAD, grub_cmd_load_layout, + N_("LAYOUT"), N_("Set up the new layout.")); + + grub_register_command_p1 (COMMAND_NAME_SHOW, + grub_cmd_show_active_keyboardlayout, 0, + N_("Show the active layout.")); + + grub_register_command_p1 (COMMAND_NAME_RESTORE, + grub_cmd_set_default_keyboard, 0, + N_("Set up the default keyboard.")); + +} + +GRUB_MOD_FINI (at_keyboard_layouts) +{ + set_default_keyboard(); +} === added file 'keyboard_layouts/usb_keyboard_layouts.c' --- keyboard_layouts/usb_keyboard_layouts.c 1970-01-01 00:00:00 +0000 +++ keyboard_layouts/usb_keyboard_layouts.c 2010-02-13 23:22:53 +0000 @@ -0,0 +1,6 @@ +#define DO_USB_KEYBOARD_LAYOUT 1 +#define COMMAND_NAME_LOAD "usb_load_layout" +#define COMMAND_NAME_SHOW "usb_show_layout" +#define COMMAND_NAME_RESTORE "usb**" +#define FILE_SUFFIX ".usb" +#include "keyboard_layouts.c" === modified file 'term/at_keyboard.c' --- term/at_keyboard.c 2010-01-10 12:34:48 +0000 +++ term/at_keyboard.c 2010-02-13 23:05:51 +0000 @@ -22,6 +22,9 @@ #include #include #include +#include + +struct grub_keyboard_map_s *grub_at_keyboard_map = NULL; static short at_keyboard_status = 0; static int pending_key = -1; @@ -41,7 +44,7 @@ static grub_uint8_t led_status; #define KEYBOARD_LED_NUM (1 << 1) #define KEYBOARD_LED_CAPS (1 << 2) -static char keyboard_map[128] = +static char keyboard_map_normal[128] = { '\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, @@ -214,12 +217,12 @@ grub_at_keyboard_getkey_noblock (void) break; default: if (at_keyboard_status & (KEYBOARD_STATUS_CTRL_L | KEYBOARD_STATUS_CTRL_R)) - key = keyboard_map[code] - 'a' + 1; + key = grub_at_keyboard_map->normal[code] - 'a' + 1; else if ((at_keyboard_status & (KEYBOARD_STATUS_SHIFT_L | KEYBOARD_STATUS_SHIFT_R)) - && keyboard_map_shift[code]) - key = keyboard_map_shift[code]; + && grub_at_keyboard_map->shift[code]) + key = grub_at_keyboard_map->shift[code]; else - key = keyboard_map[code]; + key = grub_at_keyboard_map->normal[code]; if (key == 0) grub_dprintf ("atkeyb", "Unknown key 0x%x detected\n", code); @@ -295,6 +298,9 @@ static struct grub_term_input grub_at_ke GRUB_MOD_INIT(at_keyboard) { grub_term_register_input ("at_keyboard", &grub_at_keyboard_term); + + grub_at_keyboard_map->normal = keyboard_map_normal; + grub_at_keyboard_map->shift = keyboard_map_shift; } GRUB_MOD_FINI(at_keyboard) === modified file 'term/usb_keyboard.c' --- term/usb_keyboard.c 2009-12-02 09:00:54 +0000 +++ term/usb_keyboard.c 2010-02-13 23:05:58 +0000 @@ -26,9 +26,14 @@ #include #include #include +#include +#include -static char keyboard_map[128] = + +struct grub_keyboard_map_s *grub_usb_keyboard_map = NULL; + +static char keyboard_map_normal[128] = { '\0', '\0', '\0', '\0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', @@ -152,11 +157,11 @@ grub_usb_keyboard_checkkey (void) /* Check if the Control or Shift key was pressed. */ if (data[0] & 0x01 || data[0] & 0x10) - key = keyboard_map[data[2]] - 'a' + 1; + key = keyboard_map_normal[data[2]] - 'a' + 1; else if (data[0] & 0x02 || data[0] & 0x20) key = keyboard_map_shift[data[2]]; else - key = keyboard_map[data[2]]; + key = keyboard_map_normal[data[2]]; if (key == 0) grub_printf ("Unknown key 0x%x detected\n", data[2]); @@ -321,6 +326,9 @@ GRUB_MOD_INIT(usb_keyboard) { grub_usb_hid (); grub_term_register_input ("usb_keyboard", &grub_usb_keyboard_term); + + grub_usb_keyboard_map->normal = keyboard_map_normal; + grub_usb_keyboard_map->shift = keyboard_map_shift; } GRUB_MOD_FINI(usb_keyboard) === added file 'util/grub-mklayouts.c' --- util/grub-mklayouts.c 1970-01-01 00:00:00 +0000 +++ util/grub-mklayouts.c 2010-01-31 18:08:14 +0000 @@ -0,0 +1,396 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "progname.h" + +#define CKBCOMP "ckbcomp" + +static int at_to_usb_map_normal[128] = +{ + 0, 41, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 45, 46, 42, 43, + 20, 26, 8, 21, 23, 28, 24, 12, + 18, 19, 47, 48, 40, 0, 4, 22, + 7, 9, 10, 11, 13, 14, 15, 51, + 52, 53, 0, 49, 29, 27, 6, 25, + 5, 17, 16, 54, 55, 56, 0, 0, + 0, 44, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 74, + 82, 78, 45, 80, 0, 79, 0, 77, + 81, 75, 0, 76, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static int at_to_usb_map_shift[128] = +{ + 0, 0, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 45, 46, 0, 0, + 20, 26, 8, 21, 23, 28, 24, 12, + 18, 19, 47, 48, 40, 0, 4, 22, + 7, 9, 10, 11, 13, 14, 15, 51, + 52, 0, 0, 49, 29, 27, 6, 25, + 5, 17, 16, 54, 55, 56, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static struct option options[] = { + {"output", required_argument, 0, 'o'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} +}; + +struct console_grub_equivalence +{ + char *layout; + char grub; +}; + +static struct console_grub_equivalence console_grub_equivalences[] = { + {"Escape", GRUB_TERM_ESC}, + {"Tab", GRUB_TERM_TAB}, + {"Delete", GRUB_TERM_BACKSPACE}, + + {"KP_1", '1'}, + {"KP_2", '2'}, + {"KP_3", '3'}, + {"KP_4", '4'}, + {"KP_5", '5'}, + {"KP_6", '6'}, + {"KP_7", '7'}, + {"KP_8", '8'}, + {"KP_9", '9'}, + + {"KP_Multiply", '*'}, + {"KP_Substract", '-'}, + {"KP_Add", '+'}, + {"KP_Divide", '/'}, + + {"KP_Enter", '\n'}, + {"Return", '\n'}, + {"", '\0'} +}; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try `%s --help' for more information.\n", program_name); + else + printf ("\ +Usage: %s [OPTIONS] LAYOUT\n\ + -o, --output set output base name file. Default is LAYOUT\n\ + .at or .usb suffixes will be automatically added.\n\ + -h, --help display this message and exit.\n\ + -V, --version print version information and exit.\n\ + -v, --verbose print verbose messages.\n\ +\n\ +Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); + + exit (status); +} + +void +add_special_keys (char keyboard_map[128]) +{ + keyboard_map[71] = GRUB_TERM_HOME; + keyboard_map[72] = GRUB_TERM_UP; + keyboard_map[73] = GRUB_TERM_NPAGE; + keyboard_map[75] = GRUB_TERM_LEFT; + keyboard_map[77] = GRUB_TERM_RIGHT; + keyboard_map[79] = GRUB_TERM_END; + keyboard_map[80] = GRUB_TERM_DOWN; + keyboard_map[81] = GRUB_TERM_PPAGE; + keyboard_map[83] = GRUB_TERM_DC; + +/* + * TODO: defined in include/grub/i386/at_keyboard.h + keyboard_map[101] = OLPC_UP; + keyboard_map[102] = OLPC_DOWN; + keyboard_map[103] = OLPC_LEFT; + keyboard_map[104] = OLPC_RIGHT; +*/ + +} + +char +lookup (char *code) +{ + int i; + + for (i = 0; console_grub_equivalences[i].grub != '\0'; i++) + { + if (strcmp (code, console_grub_equivalences[i].layout) == 0) + { + return console_grub_equivalences[i].grub; + } + } + + return '\0'; +} + +unsigned int +get_grub_code (char *layout_code) +{ + unsigned int code; + + if (strncmp (layout_code, "U+", sizeof ("U+") - 1) == 0) + { + sscanf (layout_code, "U+%x", &code); + } + else if (strncmp (layout_code, "+U+", sizeof ("+U+") - 1) == 0) + { + sscanf (layout_code, "+U+%x", &code); + } + else + { + code = lookup (layout_code); + } + return code; +} + +void +write_file (char* filename, char keyboard_map_normal[128], + char keyboard_map_shift[128]) +{ + FILE *fp_output; + int version; + int i; + + fp_output = fopen (filename, "w"); + + if (!fp_output) + { + grub_util_error ("cannot open `%s'", filename); + exit (1); + } + + version = GRUB_KEYBOARD_LAYOUTS_VERSION; + version = grub_cpu_to_be32 (version); + + grub_util_write_image (GRUB_KEYBOARD_LAYOUTS_FILEMAGIC, + sizeof (GRUB_KEYBOARD_LAYOUTS_FILEMAGIC) - 1, + fp_output); + + grub_util_write_image ((char *) &version, 4, fp_output); + + for (i = 0; i < 128; i++) + { + fprintf (fp_output, "%c", keyboard_map_normal[i]); + } + + for (i = 0; i < 128; i++) + { + fprintf (fp_output, "%c", keyboard_map_shift[i]); + } + fclose (fp_output); + +} + +void +write_files_at_usb (char* base_filename, char at_keyboard_map_normal[128], + char at_keyboard_map_shift[128]) +{ + char *at_file; + char *usb_file; + int i; + char usb_keyboard_map_normal[128]; + char usb_keyboard_map_shift[128]; + + /* AT layout. */ + at_file = (char*) xmalloc (strlen(base_filename) + strlen(".at") + 1); + sprintf (at_file, "%s.at", base_filename); + + write_file (at_file, at_keyboard_map_normal, at_keyboard_map_shift); + free (at_file); + + /* Convert and write USB layout. */ + memset (usb_keyboard_map_normal, 0, 128); + memset (usb_keyboard_map_shift, 0, 128); + + usb_file = (char*) xmalloc (strlen(base_filename) + strlen(".usb") + 1); + sprintf (usb_file, "%s.usb", base_filename); + + for (i=0; i<128; i++) + { + usb_keyboard_map_normal[at_to_usb_map_normal[i] ] = + at_keyboard_map_normal[i]; + + usb_keyboard_map_shift[at_to_usb_map_shift[i] ] = + at_keyboard_map_shift[i]; + } + + write_file (usb_file, usb_keyboard_map_normal, usb_keyboard_map_shift); + free (usb_file); +} + +void +write_keymaps (char *keymap, char *file_basename) +{ + char at_keyboard_map_normal[128]; + char at_keyboard_map_shift[128]; + + char line[2048]; + char normal[64]; + char shift[64]; + int key_code; + pid_t pid; + int pipe_communication[2]; + int ok; + + FILE *fp_pipe; + + if (pipe (pipe_communication) == -1) + { + grub_util_error ("cannot prepare the pipe"); + exit (2); + } + + pid = fork (); + if (pid < 0) + { + grub_util_error ("cannot fork"); + exit (2); + } + else if (pid == 0) + { + close (1); + dup (pipe_communication[1]); + close (pipe_communication[0]); + execlp (CKBCOMP, CKBCOMP, keymap, NULL); + grub_util_error ("%s %s cannot be executed", CKBCOMP, keymap); + exit (3); + } + close (pipe_communication[1]); + fp_pipe = fdopen (pipe_communication[0], "r"); + + memset (at_keyboard_map_normal, 0, 128); + memset (at_keyboard_map_shift, 0, 128); + + /* Process the ckbcomp output and prepare the layouts. */ + ok = 0; + while (fgets (line, sizeof (line), fp_pipe)) + { + if (strncmp (line, "keycode", sizeof ("keycode") - 1) == 0) + { + sscanf (line, "keycode %d = %s %s", &key_code, normal, shift); + if (key_code < 128) + { + at_keyboard_map_normal[key_code] = (char) get_grub_code (normal); + at_keyboard_map_shift[key_code] = (char) get_grub_code (shift); + ok = 1; + } + } + } + + add_special_keys (at_keyboard_map_normal); + + if (ok == 0) + { + fprintf (stderr, "ERROR: no keycodes found. Check output of %s %s.\n", + CKBCOMP, keymap); + exit (1); + } + + write_files_at_usb (file_basename, at_keyboard_map_normal, + at_keyboard_map_shift); +} + +int +main (int argc, char *argv[]) +{ + int verbosity; + char *file_basename = NULL; + + set_program_name (argv[0]); + + verbosity = 0; + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "o:hVv", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'h': + usage (0); + break; + + case 'o': + file_basename = optarg; + break; + + case 'V': + printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, + PACKAGE_VERSION); + return 0; + + case 'v': + verbosity++; + break; + + default: + usage (1); + break; + } + } + + /* Obtain LAYOUT. */ + if (optind >= argc) + { + fprintf (stderr, "No layout is specified.\n"); + usage (1); + } + + if (file_basename == NULL) + { + file_basename = argv[optind]; + } + + write_keymaps (argv[optind], file_basename); + + return 0; +}