In principle, GRUB2 allows you to change the keyboard layout through its 'at_keyboard' input terminal. You can use the 'grub-mklayout' utility to create a GRUB keyboard layout, e.g., for dvorak:

   ckbcomp dvorak | grub-mklayout -o dvorak.gkb

Create a 'layouts' subdirectory under your 'grub' directory, and copy the GRUB keyboard layout to it, e.g.:

   mkdir /boot/grub/layouts
   cp dvorak.gkb /boot/grub/layouts

The 'keymap' command under GRUB (e.g., in your 'grub.cfg') will then load the keymap:

   keymap dvorak

To actually use the keymap, you will have to switch the the 'at_keyboard' input terminal:

   terminal_input at_keyboard

Trouble is, under a PC BIOS system, the 'at_keyboard' input terminal is broken.
It is unclear to me how (or even, whether) it can be fixed.

Since I, too, got frustrated that I couldn't change the keyboard layout, I decided to try and create my own 'ext_kbd' input terminal, for personal use. The 'ext_kbd' input terminal implements something akin to the 'setkey' command that was available under what is now known as GRUB Legacy. It won't go into upstream, since it deviates from the infrastructure that GRUB already provides for changing the keyboard layout.

In any case, I'll attach a patch that will add support for my 'ext_kbd' module to GRUB, in case anyone is interested enough to try it. If you decide to apply the patch, then you will subsequently have to run './autogen.sh' before you run './configure'. Otherwise, the build process will not pick up the definition of the 'ext_kbd' module that the patch adds to the 'grub-core/Makefile.core.def' file.

I'm afraid that this is the best that I can do for now.

-- Luc.

diff -Naur grub.orig/docs/grub.texi grub/docs/grub.texi
--- grub.orig/docs/grub.texi	2015-07-23 12:11:11.000000000 +0200
+++ grub/docs/grub.texi	2015-07-26 14:10:24.956277000 +0200
@@ -3660,13 +3660,57 @@
 Commands usable anywhere in the menu and in the command-line.
 
 @menu
+* keymap::                      Load a keyboard layout
 * serial::                      Set up a serial device
+* setkey::                      Change the keyboard map
+* setnumpad::                   Change the numeric keypad behavior
 * terminal_input::              Manage input terminals
 * terminal_output::             Manage output terminals
 * terminfo::                    Define terminal type
 @end menu
 
 
+@node keymap
+@subsection keymap
+
+@deffn Command keymap LAYOUT
+Load a keyboard layout.
+
+If @var{LAYOUT} is just the identifier of a keyboard layout, then GRUB will
+look for file @file{$prefix/layouts/@var{LAYOUT}.gkb}.
+Alternatively, @var{LAYOUT} may be the full path to a GRUB keyboard layout file.
+
+This command will have no effect unless and until you use the
+@command{terminal_input} command to activate either the @samp{at_keyboard}
+input terminal:
+
+@example
+terminal_input at_keyboard
+@end example
+
+or the @samp{usb_keyboard} input terminal:
+
+@example
+terminal_input usb_keyboard
+@end example
+
+@table @asis
+@item Creating a GRUB keyboard layout file:
+
+To generate a GRUB keyboard layout file, you can use the @command{grub-mklayout}
+command-line utility, which takes a Linux console keyboard layout description
+as input, and converts it to a format that GRUB can understand.
+
+For instance, if you use the @samp{dvorak} keyboard layout, then the following
+command will create the @file{dvorak.gkb} file for use with GRUB:
+
+@example
+ckbcomp dvorak | grub-mklayout -o dvorak.gkb
+@end example
+@end table
+@end deffn
+
+
 @node serial
 @subsection serial
 
@@ -3689,6 +3733,112 @@
 @end deffn
 
 
+@node setkey
+@subsection setkey
+
+@deffn Command setkey [[TO_KEY] FROM_KEY]
+Change the keyboard map.
+
+With no arguments, reset the keyboard map to its default U.S. layout.
+
+When only the @var{FROM_KEY} argument is given, or when @var{TO_KEY} is equal to
+@var{FROM_KEY}, the mapping entry for the specified key will be cleared.
+Keep in mind that @var{FROM_KEY} identifies the position of the key under the default
+U.S. layout.
+
+With two unequal arguments, the key @var{FROM_KEY} will be mapped to @var{TO_KEY}.
+In effect, the @var{FROM_KEY} argument identifies the position of the key under the
+default U.S. layout, and @var{TO_KEY} specifies how the key should behave under your
+local keyboard layout.
+
+A key must be:
+@itemize @bullet
+@item
+a lowercase letter;
+@item
+an uppercase letter;
+@item
+a decimal digit;
+@item
+a function key---i.e., @kbd{F1} through @kbd{F12};
+@end itemize
+
+or one of the following:
+
+@verbatim
+  ampersand    barx         delete       less         question
+  asterisk     braceleft    dollar       minus        quote
+  at           braceright   doublequote  numbersign   semicolon
+  backslash    bracketleft  enter        parenleft    slash
+  backslashx   bracketright equal        parenright   space
+  backquote    caret        escape       percent      tab
+  backspace    colon        exclam       period       tilde
+  bar          comma        greater      plus         underscore
+@end verbatim
+
+This command is only available on PC BIOS systems. It will have no effect unless
+and until you use the @command{terminal_input} command to activate the @samp{ext_kbd}
+input terminal:
+
+@example
+terminal_input ext_kbd
+@end example
+
+Differences with the @command{setkey} command under GRUB Legacy:
+
+@itemize @bullet
+@item
+This @command{setkey} command does not support the modifier keys---i.e., @kbd{shift},
+@kbd{control}, @kbd{alt}, @kbd{capslock}.
+
+@item
+This @command{setkey} command supports all twelve function keys.
+
+@item
+Depending on your keyboard layout, there may be an extra key between the @key{Left Shift}
+key and the row of letter keys to its right. This extra key will output a backslash (i.e.,
+@kbd{@backslashchar{}}) or, when shifted, a vertical bar (i.e., @kbd{|}), by default.
+
+This @command{setkey} command will not affect this extra key when you remap the
+@kbd{backslash} or @kbd{bar} keys. You can instead remap the key separately, using the
+@kbd{backslashx} or @kbd{barx} values for the @var{FROM_KEY} argument.
+
+For instance, under the Belgian keyboard layout, this key will output a @kbd{<} or, when
+shifted, a @kbd{>} character. The following GRUB commands will, then, appropriately remap
+the key:
+
+@example
+setkey less    backslashx
+setkey greater barx
+@end example
+@end itemize
+@end deffn
+
+
+@node setnumpad
+@subsection setnumpad
+
+@deffn Command setnumpad [@option{--force}|@option{--noforce}]
+Change the behavior of the numeric keypad.
+
+With @option{--force}, make the keys on the numeric keypad emit the numeric
+characters on their keycaps, irrespective of the @key{NumLock} and @key{Shift}
+key states.
+
+With @option{--noforce}, or if no option is given, restore default behavior
+of the keys on the numeric keypad, which depends on the @key{NumLock} and
+@key{Shift} states.
+
+This command is only available on PC BIOS systems. It will have no effect unless
+and until you use the @command{terminal_input} command to activate the @samp{ext_kbd}
+input terminal:
+
+@example
+terminal_input ext_kbd
+@end example
+@end deffn
+
+
 @node terminal_input
 @subsection terminal_input
 
diff -Naur grub.orig/grub-core/Makefile.core.def grub/grub-core/Makefile.core.def
--- grub.orig/grub-core/Makefile.core.def	2015-07-23 12:11:11.000000000 +0200
+++ grub/grub-core/Makefile.core.def	2015-07-26 14:15:05.476288703 +0200
@@ -2313,3 +2313,9 @@
   common = loader/i386/xen_file64.c;
   extra_dist = loader/i386/xen_fileXX.c;
 };
+
+module = {
+  name = ext_kbd;
+  i386_pc = term/i386/pc/ext_kbd.c;
+  enable = i386_pc;
+};
diff -Naur grub.orig/grub-core/term/i386/pc/ext_kbd.c grub/grub-core/term/i386/pc/ext_kbd.c
--- grub.orig/grub-core/term/i386/pc/ext_kbd.c	1970-01-01 01:00:00.000000000 +0100
+++ grub/grub-core/term/i386/pc/ext_kbd.c	2015-07-26 14:10:31.492277000 +0200
@@ -0,0 +1,658 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2003,2005,2007,2008,2009  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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/machine/memory.h>
+#include <grub/term.h>
+#include <grub/extcmd.h>
+#include <grub/types.h>
+#include <grub/machine/int.h>
+
+#define  GRUB_SETKEY_KEYMAP_TABLE_SIZE   128
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options_setkey[] =
+  {
+    /********************************************************************************************************/
+    /*                                                                                                      */
+    /* The 'setkey' command does not provide any specific options.                                          */
+    /* This entry is required, however, to make the '--help' and '--usage' options work.                    */
+    /*                                                                                                      */
+    /********************************************************************************************************/
+    { 0                                                                 ,     /* const char       *longarg  */
+      0                                                                 ,     /* int               shortarg */
+      0                                                                 ,     /* int               flags    */
+      0                                                                 ,     /* const char       *doc      */
+      0                                                                 ,     /* const char       *arg      */
+      0                                                                       /* grub_arg_type_t  type      */
+    }                                                                         /******************************/
+  } ;
+
+static const struct grub_arg_option options_setnumpad[] =
+  {
+    /********************************************************************************************************/
+    /*                                                                                                      */
+    /* The '--force' option.                                                                                */
+    /*                                                                                                      */
+    /********************************************************************************************************/
+    { "force"                                                           ,     /* const char       *longarg  */
+      'f'                                                               ,     /* int               shortarg */
+      0                                                                 ,     /* int               flags    */
+      N_("Force the keys on the numeric keypad "                              /* const char       *doc      */
+         "to emit the numeric characters on their keycaps, "                  /*                            */
+         "irrespective of the NumLock and the Shift key states.")       ,     /*                            */
+      0                                                                 ,     /* const char       *arg      */
+      ARG_TYPE_NONE                                                           /* grub_arg_type_t  type      */
+    } ,                                                                       /******************************/
+    /********************************************************************************************************/
+    /*                                                                                                      */
+    /* The '--noforce' option.                                                                              */
+    /*                                                                                                      */
+    /********************************************************************************************************/
+    { "noforce"                                                         ,     /* const char       *longarg  */
+      'n'                                                               ,     /* int               shortarg */
+      0                                                                 ,     /* int               flags    */
+      N_("(Default) "                                                         /* const char       *doc      */
+         "Restore default behavior of the keys on the numeric keypad, "       /*                            */
+         "which depends on the NumLock and the Shift key states.")      ,     /*                            */
+      0                                                                 ,     /* const char       *arg      */
+      ARG_TYPE_NONE                                                           /* grub_arg_type_t  type      */
+    } ,                                                                       /******************************/
+    /********************************************************************************************************/
+    /*                                                                                                      */
+    /* End of option definitions.                                                                           */
+    /*                                                                                                      */
+    /********************************************************************************************************/
+    { 0                                                                 ,     /* const char       *longarg  */
+      0                                                                 ,     /* int               shortarg */
+      0                                                                 ,     /* int               flags    */
+      0                                                                 ,     /* const char       *doc      */
+      0                                                                 ,     /* const char       *arg      */
+      0                                                                       /* grub_arg_type_t  type      */
+    }                                                                         /******************************/
+  } ;
+
+static const struct grub_setkey_numpad_entry
+  {
+    grub_uint16_t keycode;
+    grub_uint16_t keycode_shifted;
+    int           grubkey;
+    int           grubkey_shifted;
+  }
+    numpad_table[] =
+  {
+    { 0x4f00 , 0x4f31 , 0x0080004f , 0x00000031 } ,   /* Numeric Keypad '1'.     */
+    { 0x5000 , 0x5032 , 0x00800050 , 0x00000032 } ,   /* Numeric Keypad '2'.     */
+    { 0x5100 , 0x5133 , 0x00800051 , 0x00000033 } ,   /* Numeric Keypad '3'.     */
+    { 0x4b00 , 0x4b34 , 0x0080004b , 0x00000034 } ,   /* Numeric Keypad '4'.     */
+    { 0x4c00 , 0x4c35 , 0x0080004c , 0x00000035 } ,   /* Numeric Keypad '5'.     */
+    { 0x4d00 , 0x4d36 , 0x0080004d , 0x00000036 } ,   /* Numeric Keypad '6'.     */
+    { 0x4700 , 0x4737 , 0x00800047 , 0x00000037 } ,   /* Numeric Keypad '7'.     */
+    { 0x4800 , 0x4838 , 0x00800048 , 0x00000038 } ,   /* Numeric Keypad '8'.     */
+    { 0x4900 , 0x4939 , 0x00800049 , 0x00000039 } ,   /* Numeric Keypad '9'.     */
+    { 0x5200 , 0x5230 , 0x00800052 , 0x00000030 } ,   /* Numeric Keypad '0'.     */
+    { 0x5300 , 0x532e , 0x00800053 , 0x0000002e } ,   /* Numeric Keypad '.'.     */
+    { 0xe02f , 0xe02f , 0x0000002f , 0x0000002f } ,   /* Numeric Keypad '/'.     */
+    { 0x372a , 0x372a , 0x0000002a , 0x0000002a } ,   /* Numeric Keypad '*'.     */
+    { 0x4a2d , 0x4a2d , 0x0000002d , 0x0000002d } ,   /* Numeric Keypad '-'.     */
+    { 0x4e2b , 0x4e2b , 0x0000002b , 0x0000002b } ,   /* Numeric Keypad '+'.     */
+    { 0xe00d , 0xe00d , 0x0000000d , 0x0000000d }     /* Numeric Keypad 'Enter'. */
+  } ;
+
+static const struct grub_setkey_keysym_entry
+  {
+    const char    *name;
+    grub_uint16_t keycode;
+  }
+    keysym_table[] =
+  {
+    { "a"            , 0x1e61 } ,
+    { "b"            , 0x3062 } ,
+    { "c"            , 0x2e63 } ,
+    { "d"            , 0x2064 } ,
+    { "e"            , 0x1265 } ,
+    { "f"            , 0x2166 } ,
+    { "g"            , 0x2267 } ,
+    { "h"            , 0x2368 } ,
+    { "i"            , 0x1769 } ,
+    { "j"            , 0x246a } ,
+    { "k"            , 0x256b } ,
+    { "l"            , 0x266c } ,
+    { "m"            , 0x326d } ,
+    { "n"            , 0x316e } ,
+    { "o"            , 0x186f } ,
+    { "p"            , 0x1970 } ,
+    { "q"            , 0x1071 } ,
+    { "r"            , 0x1372 } ,
+    { "s"            , 0x1f73 } ,
+    { "t"            , 0x1474 } ,
+    { "u"            , 0x1675 } ,
+    { "v"            , 0x2f76 } ,
+    { "w"            , 0x1177 } ,
+    { "x"            , 0x2d78 } ,
+    { "y"            , 0x1579 } ,
+    { "z"            , 0x2c7a } ,
+    { "A"            , 0x1e41 } ,
+    { "B"            , 0x3042 } ,
+    { "C"            , 0x2e43 } ,
+    { "D"            , 0x2044 } ,
+    { "E"            , 0x1245 } ,
+    { "F"            , 0x2146 } ,
+    { "G"            , 0x2247 } ,
+    { "H"            , 0x2348 } ,
+    { "I"            , 0x1749 } ,
+    { "J"            , 0x244a } ,
+    { "K"            , 0x254b } ,
+    { "L"            , 0x264c } ,
+    { "M"            , 0x324d } ,
+    { "N"            , 0x314e } ,
+    { "O"            , 0x184f } ,
+    { "P"            , 0x1950 } ,
+    { "Q"            , 0x1051 } ,
+    { "R"            , 0x1352 } ,
+    { "S"            , 0x1f53 } ,
+    { "T"            , 0x1454 } ,
+    { "U"            , 0x1655 } ,
+    { "V"            , 0x2f56 } ,
+    { "W"            , 0x1157 } ,
+    { "X"            , 0x2d58 } ,
+    { "Y"            , 0x1559 } ,
+    { "Z"            , 0x2c5a } ,
+    { "0"            , 0x0b30 } ,
+    { "1"            , 0x0231 } ,
+    { "2"            , 0x0332 } ,
+    { "3"            , 0x0433 } ,
+    { "4"            , 0x0534 } ,
+    { "5"            , 0x0635 } ,
+    { "6"            , 0x0736 } ,
+    { "7"            , 0x0837 } ,
+    { "8"            , 0x0938 } ,
+    { "9"            , 0x0a39 } ,
+    { "ampersand"    , 0x0826 } ,
+    { "asterisk"     , 0x092a } ,
+    { "at"           , 0x0340 } ,
+    { "backslash"    , 0x2b5c } ,
+    { "backslashx"   , 0x565c } ,
+    { "backquote"    , 0x2960 } ,
+    { "backspace"    , 0x0e08 } ,
+    { "bar"          , 0x2b7c } ,
+    { "barx"         , 0x567c } ,
+    { "braceleft"    , 0x1a7b } ,
+    { "braceright"   , 0x1b7d } ,
+    { "bracketleft"  , 0x1a5b } ,
+    { "bracketright" , 0x1b5d } ,
+    { "caret"        , 0x075e } ,
+    { "colon"        , 0x273a } ,
+    { "comma"        , 0x332c } ,
+    { "delete"       , 0x53e0 } ,
+    { "dollar"       , 0x0524 } ,
+    { "doublequote"  , 0x2822 } ,
+    { "enter"        , 0x1c0d } ,
+    { "equal"        , 0x0d3d } ,
+    { "escape"       , 0x011b } ,
+    { "exclam"       , 0x0221 } ,
+    { "greater"      , 0x343e } ,
+    { "less"         , 0x333c } ,
+    { "minus"        , 0x0c2d } ,
+    { "numbersign"   , 0x0423 } ,
+    { "parenleft"    , 0x0a28 } ,
+    { "parenright"   , 0x0b29 } ,
+    { "percent"      , 0x0625 } ,
+    { "period"       , 0x342e } ,
+    { "plus"         , 0x0d2b } ,
+    { "question"     , 0x353f } ,
+    { "quote"        , 0x2827 } ,
+    { "semicolon"    , 0x273b } ,
+    { "slash"        , 0x352f } ,
+    { "space"        , 0x3920 } ,
+    { "tab"          , 0x0f09 } ,
+    { "tilde"        , 0x297e } ,
+    { "underscore"   , 0x0c5f } ,
+    { "F1"           , 0x3b00 } ,
+    { "F2"           , 0x3c00 } ,
+    { "F3"           , 0x3d00 } ,
+    { "F4"           , 0x3e00 } ,
+    { "F5"           , 0x3f00 } ,
+    { "F6"           , 0x4000 } ,
+    { "F7"           , 0x4100 } ,
+    { "F8"           , 0x4200 } ,
+    { "F9"           , 0x4300 } ,
+    { "F10"          , 0x4400 } ,
+    { "F11"          , 0x8500 } ,
+    { "F12"          , 0x8600 }
+  } ;
+
+static const grub_uint16_t bypass_table[] =
+  {
+    0x0e00 | '\b' ,   /* Backspace.       */
+    0x0100 | '\e' ,   /* Escape.          */
+    0x1c00 | '\n' ,   /* Line Feed.       */
+    0x1c00 | '\r' ,   /* Carriage Return. */
+    0x0f00 | '\t'     /* Tab.             */
+  } ;
+
+static int numpad_force = 0;
+
+static struct grub_setkey_keymap_entry
+  {
+    grub_uint16_t keycode_from;
+    grub_uint16_t keycode_to;
+  }
+    keymap_table[GRUB_SETKEY_KEYMAP_TABLE_SIZE];
+
+/*
+ * grubkey_numpad - For a key code  that  corresponds  to  a  key  on  the
+ *                  numeric keypad,  return the  GRUB  key value.  If  the
+ *                  'setnumpad --force'  option is in effect,  then return
+ *                  the printable  ASCII character,  irrespective  of  the
+ *                  NumLock and the Shift key states;  otherwise,  do  not
+ *                  remap the key code.
+ *                  For a  key  code  that  does not belong to the numeric
+ *                  keypad, return 0.
+ */
+static int
+grubkey_numpad (grub_uint16_t key)
+{
+  unsigned int i;
+
+  for (i = 0; i < ARRAY_SIZE (numpad_table); i++)
+    if (key == numpad_table[i].keycode)
+      if (numpad_force)
+        return numpad_table[i].grubkey_shifted;
+      else
+        return numpad_table[i].grubkey;
+    else if (key == numpad_table[i].keycode_shifted)
+      return numpad_table[i].grubkey_shifted;
+  return 0;
+}
+
+/*
+ * grubkey_mapkey - If a mapping entry was set up  for the given key code,
+ *                  then return the remapped key code.
+ *                  Otherwise, return the given key code unchanged.
+ */
+static grub_uint16_t
+grubkey_mapkey (grub_uint16_t key)
+{
+  unsigned int i;
+
+  for (i = 0; i < GRUB_SETKEY_KEYMAP_TABLE_SIZE; i++)
+    if (!keymap_table[i].keycode_from)
+      break;
+    else if (key == keymap_table[i].keycode_from)
+      return keymap_table[i].keycode_to;
+  return (key);
+}
+
+/*
+ * grubkey_bypass - For a key code  that  produces  a  'well-known'  ASCII
+ *                  control character (cfr. 'bypass_table', above), return
+ *                  the ASCII character value.
+ *                  For any other key code, return 0.
+ */
+static int
+grubkey_bypass (grub_uint16_t key)
+{
+  unsigned int i;
+
+  for (i = 0; i < ARRAY_SIZE (bypass_table); i++)
+    if (key == bypass_table[i])
+      return key & 0xff;
+  return 0;
+}
+
+/*
+ * grub_ext_kbd_xlat - Convert a key code  to  a  GRUB  key  value,  while
+ *                     taking  into  account  any key mapping entries that
+ *                     were requested  by the 'setkey' and the 'setnumpad'
+ *                     commands.
+ *                     If  the  key  code  corresponds  to  a key  on  the
+ *                     numeric keypad, then:
+ *                       -  If  the  '--force'  option of the  'setnumpad'
+ *                          command is in effect,  then return the numeric
+ *                          ASCII character for the key,  irrespective  of
+ *                          the NumLock and Shift key states.
+ *                       -  Otherwise,  return  either the printable ASCII
+ *                          character,  or the extended  GRUB  key  value,
+ *                          depending on the NumLock and Shift key states.
+ *                     Any other key will first be remapped  according  to
+ *                     the mapping entries  set up  through  the  'setkey'
+ *                     command.  Then:
+ *                       -  If the key code  does  not  produce  an  ASCII
+ *                          character,  then  return its extended GRUB key
+ *                          value.
+ *                       -  If the key code  produces  a  printable  ASCII
+ *                          character (including DEL), then return that.
+ *                       -  Otherwise,  the key code will produce an ASCII
+ *                          control character.
+ *                          For  a  'well-known'  ASCII control character,
+ *                          return its  ASCII  character  value;  for  any
+ *                          other  ASCII  control  character,  return  the
+ *                          GRUB control key value.
+ *
+ *                     This  function  will  be  called by  the  'ext_kbd'
+ *                     input terminal  whenever it reads a keystroke  from
+ *                     the keyboard.
+ */
+static int
+grub_ext_kbd_xlat (grub_uint16_t key)
+{
+  int grubkey;
+
+  /*
+   * Handle the keys on the numeric keypad.  These should not be remapped,
+   * except according to the 'numpad_force' setting.
+   */
+  if ((grubkey = grubkey_numpad (key)))
+    return grubkey;
+
+  /*
+   * Remap the key according to the keymap table.
+   */
+  key = grubkey_mapkey (key);
+
+  /*
+   * Handle extended keys,  i.e.,  those  for which the ASCII character is
+   * either null (0x00) or the extended key indicator (0xe0).
+   * Note that, instead of testing for the extact value of 0xe0,  the code
+   * here simply tests  if the high-order bit of the  ASCII  character  is
+   * set.  (No other value with the high-order bit set  should ever appear
+   * for a correctly functioning keyboard.)
+   */
+  if ((!(key & 0xff)) || (key & 0x80))
+    return (key >> 8) | GRUB_TERM_EXTENDED;
+
+
+  /*
+   * Handle printable ASCII characters (including DEL).
+   */
+  if ((key & 0xff) >= ' ')
+    return key & 0xff;
+
+  /*
+   * Handle well-known control characters.
+   */
+  if ((grubkey = grubkey_bypass (key)))
+    return grubkey;
+
+  /*
+   * Handle the less common control characters.
+   */
+  return (key & 0xff) + (('a' - 1) | GRUB_TERM_CTRL);
+}
+
+/*
+ * grub_keysym_code - Return  the key code that corresponds to  the  given
+ *                    name (cfr. 'keysym_table', above).
+ *                    If an invalid name is given, then return 0.
+ */
+static grub_uint16_t
+grub_keysym_code (char *name)
+{
+  unsigned int i;
+
+  for (i = 0; i < ARRAY_SIZE (keysym_table); i++)
+    if (!grub_strcmp (name, keysym_table[i].name))
+      return keysym_table[i].keycode;
+  return 0;
+}
+
+/*
+ * grubkey_map_entry - Return the subscript of the keymap entry  for which
+ *                     the keycode_from value is  equal  to  the given key
+ *                     code.
+ *                     If no keymap entry  exists  for the given key code,
+ *                     then return the subscript of the first empty entry.
+ *
+ *                     Since the keymap table  should  be  large enough to
+ *                     hold  an  entry  for  all supported keycode values,
+ *                     plus  at least  one  terminating  null  entry,  the
+ *                     subscript  returned  by  this  function  should not
+ *                     go out of range.
+ */
+static unsigned int
+grubkey_map_entry (grub_uint16_t key)
+{
+  unsigned int i;
+
+  for (i = 0; i < GRUB_SETKEY_KEYMAP_TABLE_SIZE; i++)
+    if (!keymap_table[i].keycode_from)
+      break;
+    else if (key == keymap_table[i].keycode_from)
+      break;
+  return i;
+}
+
+/*
+ * grub_cmd_setkey - Implement the 'setkey' command.
+ *                   If no arguments are given, then clear any key mapping
+ *                   entries that were set up.
+ *                   With one argument  (or  with  two  equal  arguments),
+ *                   delete the mapping entry for the given key.
+ *                   With two  (unequal)  arguments,  set up a key mapping
+ *                   entry for the key  that  corresponds  to  the  second
+ *                   argument string  (i.e., FROM_KEY), and make it output
+ *                   the key code  that  corresponds to the first argument
+ *                   string instead (i.e., TO_KEY).
+ */
+static grub_err_t
+grub_cmd_setkey (grub_extcmd_context_t ctxt __attribute__ ((unused)), int argc, char *args[])
+{
+  if (argc > 2)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("too many parameters"));
+  if (!argc)
+    /*
+     * Clear the keymap table.
+     */
+    grub_memset (keymap_table, 0, GRUB_SETKEY_KEYMAP_TABLE_SIZE * sizeof (keymap_table[0]));
+  else
+    {
+      grub_uint16_t keycode_from;
+      grub_uint16_t keycode_to;
+      unsigned int  i_keymap;
+
+      /*
+       * CAUTION: The argc value is decremented here.
+       *          Consequently,  if  two arguments were given,  then  argc
+       *          will be set to 1 from this point on.
+       *          Otherwise, only one argument was present,  and argc will
+       *          be 0.
+       *          All other cases were excluded by the code above.
+       *          Note  also  that  args[argc]  will  reference  the  last
+       *          argument string.
+       */
+      argc--;
+      /*
+       * The last argument string is FROM_KEY.
+       */
+      keycode_from = grub_keysym_code (args[argc]);
+      keycode_to   = 0;
+      if (argc && grub_strcmp (args[0], args[1]))
+        /*
+         * The first argument string is TO_KEY.
+         */
+        if (!(keycode_to = grub_keysym_code (args[0])))
+          return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid parameter `%s'"), args[0]);
+      if (!keycode_from)
+        return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid parameter `%s'"), args[argc]);
+      if ((i_keymap = grubkey_map_entry (keycode_from)) >= GRUB_SETKEY_KEYMAP_TABLE_SIZE)
+        /*
+         * This should not happen,  since the keymap table should be large
+         * enough to hold a keymap entry for all supported keycode values,
+         * plus at least one terminating null entry.
+         */
+        {
+          if (keycode_to)
+            return grub_error (GRUB_ERR_BUG, N_("keymap table full"));
+        }
+      else if (keycode_to)
+        {
+          keymap_table[i_keymap].keycode_from = keycode_from;
+          keymap_table[i_keymap].keycode_to   = keycode_to;
+        }
+      else if (keymap_table[i_keymap].keycode_from)
+        grub_memmove (keymap_table + i_keymap, keymap_table + (i_keymap + 1),
+                      (GRUB_SETKEY_KEYMAP_TABLE_SIZE - i_keymap - 1) * sizeof (keymap_table[0]));
+    }
+  return GRUB_ERR_NONE;
+}
+
+/*
+ * grub_cmd_setnumpad - Implement the 'setnumpad' command.
+ *                      When  the  '--force'  option  is  given,  make the
+ *                      numeric keypad output  printable ASCII characters,
+ *                      irrespective of the  NumLock  and  the  Shift  key
+ *                      states.
+ *                      With the '--noforce' option,  or when no option is
+ *                      specified,  the default behavior  of  the  numeric
+ *                      keypad (depending on the NumLock and the Shift key
+ *                      key states) will be restored.
+ */
+static grub_err_t
+grub_cmd_setnumpad (grub_extcmd_context_t ctxt, int argc, char *args[] __attribute__ ((unused)))
+{
+  if (argc)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("too many parameters"));
+  if ((ctxt->state[0].set) && (ctxt->state[1].set))
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("conflicting options"));
+  numpad_force = ctxt->state[0].set;
+  return GRUB_ERR_NONE;
+}
+
+/*
+ * grub_ext_kbd_getkey - If  a  character  is  pending,  then  return  it.
+ *                       Otherwise, return GRUB_TERM_NO_KEY (i.e., -1).
+ *
+ *                       BIOS call  'INT 16H Function 11H'  checks whether
+ *                       a  character  is  pending,  supporting  so-called
+ *                       'extended' key codes.
+ *                       Call this function with:
+ *                         -  %ah = 0x11.
+ *                       When the function returns:
+ *                         -  If a character is pending, then:
+ *                              -  Zero flag is clear.
+ *                              -  %ah = keyboard scan code.
+ *                              -  %al = ASCII character.
+ *                         -  If there is no character pending, then:
+ *                              -  Zero flag is set.
+ *
+ *                       BIOS call 'INT 16H Function 10H' gets a character
+ *                       from the keyboard,  again  supporting  'extended'
+ *                       key codes.
+ *                       Call this function with:
+ *                         -  %ah = 0x10.
+ *                       When the function returns:
+ *                         -  %ah = keyboard scan code.
+ *                         -  %al = ASCII character.
+ */
+static int
+grub_ext_kbd_getkey (struct grub_term_input *term __attribute__ ((unused)))
+{
+  struct grub_bios_int_registers regs;
+
+  /*
+   * Check if a character is pending.
+   */
+  regs.eax = 0x1100;
+  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+  grub_bios_interrupt (0x16, &regs);
+  if (regs.flags & GRUB_CPU_INT_FLAGS_ZERO)
+    return GRUB_TERM_NO_KEY;
+
+  /*
+   * Read the character that is pending.
+   */
+  regs.eax = 0x1000;
+  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+  grub_bios_interrupt (0x16, &regs);
+
+  /*
+   * Process the key code that was read from the keyboard,  and return the
+   * corresponding GRUB key code.
+   */
+  return grub_ext_kbd_xlat (regs.eax);
+}
+
+static const struct grub_machine_bios_data_area *bios_data_area =
+  (struct grub_machine_bios_data_area *) GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR;
+
+/*
+ * grub_ext_kbd_getkeystatus - Return the Shift, Ctrl,  and  Alt  modifier
+ *                             states.
+ */
+static int
+grub_ext_kbd_getkeystatus (struct grub_term_input *term __attribute__ ((unused)))
+{
+  /* conveniently GRUB keystatus is modelled after BIOS one.  */
+  return bios_data_area->keyboard_flag_lower & ~0x80;
+}
+
+static struct grub_term_input grub_ext_kbd_term_input =
+  {
+    .name = "ext_kbd",
+    .getkey = grub_ext_kbd_getkey,
+    .getkeystatus = grub_ext_kbd_getkeystatus
+  };
+
+static grub_extcmd_t cmd_setkey;
+static grub_extcmd_t cmd_setnumpad;
+
+GRUB_MOD_INIT(ext_kbd)
+{
+  grub_term_register_input ("ext_kbd", &grub_ext_kbd_term_input);
+  cmd_setkey    = grub_register_extcmd (   /* const char                   *name        */   "setkey"
+                                       ,   /* grub_extcmd_func_t            func        */    grub_cmd_setkey
+                                       ,   /* grub_command_flags_t          flags       */   0
+                                       ,   /* const char                   *summary     */   N_("[[TO_KEY] FROM_KEY]")
+                                       ,   /* const char                   *description */   N_("Change the keyboard map.\n"
+                                                                                                "The key FROM_KEY is mapped to the key TO_KEY.\n"
+                                                                                                "If TO_KEY is missing, or if it is equal to FROM_KEY, "
+                                                                                                "then remove the mapping entry.\n"
+                                                                                                "If no parameters are specified, then remove all key mappings.\n\n"
+                                                                                                "A key must be:\n"
+                                                                                                "  - a  lowercase letter;\n"
+                                                                                                "  - an uppercase letter;\n"
+                                                                                                "  - a  decimal digit;\n"
+                                                                                                "  - a  function key, F1 through F12;\n"
+                                                                                                "or one of the following:\n"
+                                                                                                "  ampersand    barx         delete       less         question\n"
+                                                                                                "  asterisk     braceleft    dollar       minus        quote\n"
+                                                                                                "  at           braceright   doublequote  numbersign   semicolon\n"
+                                                                                                "  backslash    bracketleft  enter        parenleft    slash\n"
+                                                                                                "  backslashx   bracketright equal        parenright   space\n"
+                                                                                                "  backquote    caret        escape       percent      tab\n"
+                                                                                                "  backspace    colon        exclam       period       tilde\n"
+                                                                                                "  bar          comma        greater      plus         underscore")
+                                       ,   /* const struct grub_arg_option *parser      */   options_setkey
+                                       ) ;
+  cmd_setnumpad = grub_register_extcmd (   /* const char                   *name        */   "setnumpad"
+                                       ,   /* grub_extcmd_func_t            func        */   grub_cmd_setnumpad
+                                       ,   /* grub_command_flags_t          flags       */   0
+                                       ,   /* const char                   *summary     */   N_("[--force|--noforce]")
+                                       ,   /* const char                   *description */   N_("Change the behavior of the numeric keypad.\n")
+                                       ,   /* const struct grub_arg_option *parser      */   options_setnumpad
+                                       ) ;
+}
+
+GRUB_MOD_FINI(ext_kbd)
+{
+  grub_unregister_extcmd (cmd_setnumpad);
+  grub_unregister_extcmd (cmd_setkey);
+  grub_term_unregister_input (&grub_ext_kbd_term_input);
+}
diff -Naur grub.orig/include/grub/i386/pc/memory.h grub/include/grub/i386/pc/memory.h
--- grub.orig/include/grub/i386/pc/memory.h	2015-07-23 12:11:11.000000000 +0200
+++ grub/include/grub/i386/pc/memory.h	2015-07-26 14:10:24.952277000 +0200
@@ -45,7 +45,7 @@
 
 #ifndef ASM_FILE
 
-/* See http://heim.ifi.uio.no/~stanisls/helppc/bios_data_area.html for a
+/* See http://stanislavs.org/helppc/bios_data_area.html for a
    description of the BIOS Data Area layout.  */
 struct grub_machine_bios_data_area
 {

Reply via email to