=== added file 'ChangeLog.keyboard_layouts' --- ChangeLog.keyboard_layouts 1970-01-01 00:00:00 +0000 +++ ChangeLog.keyboard_layouts 2010-01-18 21:27:43 +0000 @@ -0,0 +1,22 @@ +2010-01-18 Carles Pina i Estany + + Adds keyboard layouts support. + + * conf/common.rmk (bin_UTILITIES): Add grub-mklayouts rules. + (pkglib_MODULES): Add module `keyboard_layouts.mod'. + * include/grub/keyboard_layouts.h: New file. + * include/grub/term.h: New struct `grub_keyboard_map_s'. New + EXPORTED_VAR `grub_keyboard_map'. Move GRUB_TERM_* keys definitions + to... + * include/grub/keys.h: ... here. New file. + * kern/term.c (grub_keyboard_map): Initialise to NULL. + * keyboard_layouts/keyboard_layouts.c: New file. + * term/i386/pc/at_keyboard.c: Include `'. + (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_term_input): Initialise `grub_keyboard_map->normal' and + `grub_keyboard_map->shift'. + * util/grub-mklayouts.c: New file. + * util/grub-mkconfig.in: New variable `GRUB_KEYBOARD_LAYOUT'. + * util/grub.d/00_header.in: Set up layout configuration. === modified file 'conf/common.rmk' --- conf/common.rmk 2010-01-14 14:04:44 +0000 +++ conf/common.rmk 2010-01-17 14:35:00 +0000 @@ -88,6 +88,10 @@ endif bin_UTILITIES += grub-mkrelpath grub_mkrelpath_SOURCES = gnulib/progname.c util/grub-mkrelpath.c util/misc.c +# For grub-mklayouts. +bin_UTILITIES += grub-mklayouts +grub_mklayouts_SOURCES = gnulib/progname.c util/grub-mklayouts.c util/misc.c + # For the parser. grub_script.tab.c grub_script.tab.h: script/parser.y $(YACC) -d -p grub_script_yy -b grub_script $(srcdir)/script/parser.y @@ -647,6 +651,12 @@ gettext_mod_SOURCES = gettext/gettext.c gettext_mod_CFLAGS = $(COMMON_CFLAGS) gettext_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For keyboard_layouts.mod +pkglib_MODULES += keyboard_layouts.mod +keyboard_layouts_mod_SOURCES = keyboard_layouts/keyboard_layouts.c +keyboard_layouts_mod_CFLAGS = $(COMMON_CFLAGS) +keyboard_layouts_mod_LDFLAGS = $(COMMON_LDFLAGS) + # Misc. pkglib_MODULES += xnu_uuid.mod === 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-01-18 22:13:06 +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_USB_H */ === 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-01-09 22:42:17 +0000 +++ include/grub/term.h 2010-01-17 22:25:58 +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 @@ -198,6 +186,14 @@ extern struct grub_term_input *EXPORT_VA extern struct grub_term_output *EXPORT_VAR(grub_term_outputs); extern struct grub_term_input *EXPORT_VAR(grub_term_inputs); +struct grub_keyboard_map_s +{ + char *normal; + char *shift; +}; + +extern struct grub_keyboard_map_s *EXPORT_VAR(grub_keyboard_map); + static inline void grub_term_register_input (const char *name __attribute__ ((unused)), grub_term_input_t term) === modified file 'kern/term.c' --- kern/term.c 2009-12-27 21:35:40 +0000 +++ kern/term.c 2010-01-17 21:52:16 +0000 @@ -30,6 +30,8 @@ struct grub_term_input *grub_term_inputs void (*grub_newline_hook) (void) = NULL; +struct grub_keyboard_map_s *grub_keyboard_map = NULL; + /* Put a Unicode character. */ void grub_putcode (grub_uint32_t code, struct grub_term_output *term) === added directory 'keyboard_layouts' === 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-01-18 22:47:22 +0000 @@ -0,0 +1,186 @@ +/* keyboard_layouts.c - 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 +#include + +#include + +static char original_keyboard_layout_normal[128]; +static char original_keyboard_layout_shift[128]; + +static char *active_layout; + +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; + + 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 = + grub_malloc (grub_strlen (prefix) + grub_strlen ("/") + + grub_strlen (args[0]) + 1); + grub_sprintf (filename, "%s/%s", prefix, args[0]); + + 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, grub_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, grub_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 (grub_keyboard_map->normal, original_keyboard_layout_normal, + 128); + grub_memcpy (grub_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; +} + +GRUB_MOD_INIT (keyboard_layouts) +{ + grub_memcpy (original_keyboard_layout_normal, grub_keyboard_map->normal, + 128); + grub_memcpy (original_keyboard_layout_shift, grub_keyboard_map->shift, 128); + + active_layout = grub_strdup("default"); + + grub_register_command_p1 ("load_layout", grub_cmd_load_layout, + N_("LAYOUT"), N_("Set up the new layout.")); + + grub_register_command_p1 ("show_layout", + grub_cmd_show_active_keyboardlayout, 0, + N_("Show the active layout.")); + + grub_register_command_p1 ("**", + grub_cmd_set_default_keyboard, 0, + N_("Set up the default keyboard.")); + +} + +GRUB_MOD_FINI (keyboard_layouts) +{ + set_default_keyboard(); +} === modified file 'term/i386/pc/at_keyboard.c' --- term/i386/pc/at_keyboard.c 2010-01-09 22:42:17 +0000 +++ term/i386/pc/at_keyboard.c 2010-01-18 21:15:59 +0000 @@ -22,6 +22,7 @@ #include #include #include +#include static short at_keyboard_status = 0; @@ -40,7 +41,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, @@ -213,12 +214,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_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_keyboard_map->shift[code]) + key = grub_keyboard_map->shift[code]; else - key = keyboard_map[code]; + key = grub_keyboard_map->normal[code]; if (key == 0) grub_dprintf ("atkeyb", "Unknown key 0x%x detected\n", code); @@ -279,6 +280,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_keyboard_map->normal = keyboard_map_normal; + grub_keyboard_map->shift = keyboard_map_shift; } GRUB_MOD_FINI(at_keyboard) === modified file 'util/grub-mkconfig.in' --- util/grub-mkconfig.in 2009-12-12 00:43:32 +0000 +++ util/grub-mkconfig.in 2010-01-18 22:44:55 +0000 @@ -220,7 +220,8 @@ export GRUB_DEFAULT \ GRUB_DISABLE_LINUX_UUID \ GRUB_DISABLE_LINUX_RECOVERY \ GRUB_GFXMODE \ - GRUB_DISABLE_OS_PROBER + GRUB_DISABLE_OS_PROBER \ + GRUB_KEYBOARD_LAYOUT if test "x${grub_cfg}" != "x"; then rm -f ${grub_cfg}.new === added file 'util/grub-mklayouts.c' --- util/grub-mklayouts.c 1970-01-01 00:00:00 +0000 +++ util/grub-mklayouts.c 2010-01-18 22:36:46 +0000 @@ -0,0 +1,308 @@ +/* + * 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 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 file name. Default is LAYOUT.\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_keymap (char *keymap, char *output_file) +{ + char keyboard_map_normal[128]; + char keyboard_map_shift[128]; + + char line[2048]; + char normal[64]; + char shift[64]; + int key_code; + int i; + pid_t pid; + int pipe_communication[2]; + int ok; + + FILE *fp_pipe; + FILE *fp_output; + + 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 (keyboard_map_normal, 0, 128); + memset (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) + { + keyboard_map_normal[key_code] = (char) get_grub_code (normal); + keyboard_map_shift[key_code] = (char) get_grub_code (shift); + ok = 1; + } + } + } + + add_special_keys (keyboard_map_normal); + + if (ok == 0) + { + fprintf (stderr, "ERROR: no keycodes found. Check output of %s %s.\n", + CKBCOMP, keymap); + exit (1); + } + + /* Save the layouts to the file. */ + fp_output = fopen (output_file, "w"); + + if (!fp_output) + { + grub_util_error ("cannot open `%s'", output_file); + exit (1); + } + + int version; + 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); +} + +int +main (int argc, char *argv[]) +{ + int verbosity; + char *output_file = 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': + output_file = 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 (output_file == NULL) + { + output_file = argv[optind]; + } + + write_keymap (argv[optind], output_file); + + return 0; +} === modified file 'util/grub.d/00_header.in' --- util/grub.d/00_header.in 2010-01-05 10:53:03 +0000 +++ util/grub.d/00_header.in 2010-01-18 22:45:47 +0000 @@ -129,6 +129,14 @@ insmod gettext EOF fi +if [ "x${GRUB_KEYBOARD_LAYOUT}" != "x" ] ; then + cat << EOF +insmod keyboard_layouts +set keymaps_dir=${grub_prefix}/layouts +load_layout ${GRUB_KEYBOARD_LAYOUT} +EOF +fi + if [ "x${GRUB_HIDDEN_TIMEOUT}" != "x" ] ; then if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then verbose=