File grub.tastaturbelegung.patch of Package grub2

From: Olaf Hering <olaf@aepfle.de>
Date: Wed, 13 Dec 2017 08:14:44 +0000
Subject: tastaturbelegung

---
 grub-core/term/efi/console.c     | 156 +++++-
 grub-core/term/i386/pc/console.c | 210 ++++++++-
 2 files changed, 352 insertions(+), 14 deletions(-)

--- a/grub-core/term/efi/console.c
+++ b/grub-core/term/efi/console.c
@@ -195,52 +195,204 @@ grub_console_putchar (struct grub_term_output *term,
 }
 
 const unsigned efi_codes[] =
   {
     0, GRUB_TERM_KEY_UP, GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_RIGHT,
     GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_HOME, GRUB_TERM_KEY_END, GRUB_TERM_KEY_INSERT,
     GRUB_TERM_KEY_DC, GRUB_TERM_KEY_PPAGE, GRUB_TERM_KEY_NPAGE, GRUB_TERM_KEY_F1,
     GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5,
     GRUB_TERM_KEY_F6, GRUB_TERM_KEY_F7, GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9,
     GRUB_TERM_KEY_F10, GRUB_TERM_KEY_F11, GRUB_TERM_KEY_F12, GRUB_TERM_ESC
   };
 
+static const int tastatur_deutsch[] = {
+	/* Reihe 1, ohne Shift */
+	['`'] = '^',
+	['1'] = '1',
+	['2'] = '2',
+	['3'] = '3',
+	['4'] = '4',
+	['5'] = '5',
+	['6'] = '6',
+	['7'] = '7',
+	['8'] = '8',
+	['9'] = '9',
+	['0'] = '0',
+	['-'] = 'ß',
+	['='] = '´',
+
+	/* Reihe 2, ohne Shift */
+	['q'] = 'q',
+	['w'] = 'w',
+	['e'] = 'e',
+	['r'] = 'r',
+	['t'] = 't',
+	['y'] = 'z',
+	['u'] = 'u',
+	['i'] = 'i',
+	['o'] = 'o',
+	['p'] = 'p',
+	['['] = 'ü',
+	[']'] = '+',
+
+	/* Reihe 3, ohne Shift */
+	['a'] = 'a',
+	['s'] = 's',
+	['d'] = 'd',
+	['f'] = 'f',
+	['g'] = 'g',
+	['h'] = 'h',
+	['j'] = 'j',
+	['k'] = 'k',
+	['l'] = 'l',
+	[';'] = 'ö',
+	['\''] = 'ä',
+	['\\'] = '#',
+
+	/* Reihe 4, ohne Shift */
+/*	['\\'] = '<', */
+	['z'] = 'y',
+	['x'] = 'x',
+	['c'] = 'c',
+	['v'] = 'v',
+	['b'] = 'b',
+	['n'] = 'n',
+	['m'] = 'm',
+	[','] = ',',
+	['.'] = '.',
+	['/'] = '-',
+
+	/* Reihe 1, mit Shift */
+	['~'] = '\0',
+	['!'] = '!',
+	['@'] = '"',
+	['#'] = '§',
+	['$'] = '$',
+	['%'] = '%',
+	['^'] = '&',
+	['&'] = '/',
+	['*'] = '(',
+	['('] = ')',
+	[')'] = '=',
+	['_'] = '?',
+	['+'] = '`',
+
+	/* Reihe 2, mit Shift */
+	['Q'] = 'Q',
+	['W'] = 'W',
+	['E'] = 'E',
+	['R'] = 'R',
+	['T'] = 'T',
+	['Y'] = 'Z',
+	['U'] = 'U',
+	['I'] = 'I',
+	['O'] = 'O',
+	['P'] = 'P',
+	['{'] = 'Ü',
+	['}'] = '*',
+
+
+	/* Reihe 3, mit Shift */
+	['A'] = 'A',
+	['S'] = 'S',
+	['D'] = 'D',
+	['F'] = 'F',
+	['G'] = 'G',
+	['H'] = 'H',
+	['J'] = 'J',
+	['K'] = 'K',
+	['L'] = 'L',
+	[':'] = 'Ö',
+	['"'] = 'ä',
+	['|'] = '#',
+
+	/* Reihe 4, mit Shift */
+/*	['|'] = '>',*/
+	['Z'] = 'Y',
+	['X'] = 'X',
+	['C'] = 'C',
+	['V'] = 'V',
+	['B'] = 'B',
+	['N'] = 'N',
+	['M'] = 'M',
+	['<'] = ';',
+	['>'] = ':',
+	['?'] = '_',
+
+};
+
+static struct belegung {
+	const char *hinweis;
+	const char *name;
+	const int *map;
+} belegung[] = {
+	{
+		.hinweis = "Tastaturbelegung ist jetzt",
+		.name = "deutsch",
+		.map = tastatur_deutsch,
+	},
+	{
+		.name = "none",
+		.map = NULL,
+	},
+};
+static int *tastatur_belegung;
+
+static int deutsch(grub_efi_char16_t unicode_char)
+{
+  int i, ret;
+  if (!tastatur_belegung) {
+  for (i = 0; belegung[i].map; i++)
+  {
+    if (grub_strcmp("deutsch", belegung[i].name) == 0)
+    {
+      grub_printf("%s %s\n", belegung[i].hinweis ? : "", belegung[i].name);
+      tastatur_belegung = belegung[i].map;
+    }
+  }
+  }
+  ret = i = unicode_char;
+  if (tastatur_belegung && tastatur_belegung[i])
+    ret = tastatur_belegung[i];
+  return ret;
+}
+
 static int
 grub_efi_translate_key (grub_efi_input_key_t key)
 {
   if (key.scan_code == 0)
     {
       /* Some firmware implementations use VT100-style codes against the spec.
 	 This is especially likely if driven by serial.
        */
       if (key.unicode_char < 0x20 && key.unicode_char != 0
 	  && key.unicode_char != '\t' && key.unicode_char != '\b'
 	  && key.unicode_char != '\n' && key.unicode_char != '\r')
 	return GRUB_TERM_CTRL | (key.unicode_char - 1 + 'a');
       else
-	return key.unicode_char;
+	return deutsch(key.unicode_char);
     }
   /* Some devices use power key (key.scan_code 0x0102, suspend) as Enter. */
   else if (key.scan_code == 0x0102)
     return '\r';
   /* Some devices send enter with scan_code 0x0d (F3) and unicode_char 0x0d. */
   else if (key.scan_code == '\r' && key.unicode_char == '\r')
     return key.unicode_char;
   else if (key.scan_code < ARRAY_SIZE (efi_codes))
     return efi_codes[key.scan_code];
 
   if ((key.unicode_char >= 0x20 && key.unicode_char <= 0x7f)
       || key.unicode_char == '\t' || key.unicode_char == '\b'
       || key.unicode_char == '\n' || key.unicode_char == '\r')
-    return key.unicode_char;
+    return deutsch(key.unicode_char);
 
   return GRUB_TERM_NO_KEY;
 }
 
 static int
 grub_console_getkey_con (struct grub_term_input *term __attribute__ ((unused)))
 {
   grub_efi_simple_input_interface_t *i;
   grub_efi_input_key_t key;
   grub_efi_status_t status;
 
   i = grub_efi_system_table->con_in;
--- a/grub-core/term/i386/pc/console.c
+++ b/grub-core/term/i386/pc/console.c
@@ -11,24 +11,25 @@
  *  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/machine/memory.h>
 #include <grub/machine/console.h>
 #include <grub/term.h>
 #include <grub/types.h>
+#include <grub/command.h>
 #include <grub/machine/int.h>
 
 static grub_uint8_t grub_console_cur_color = 0x7;
 
 static void
 int10_9 (grub_uint8_t ch, grub_uint16_t n)
 {
   struct grub_bios_int_registers regs;
 
   regs.eax = ch | 0x0900;
   regs.ebx = grub_console_cur_color & 0xff;
   regs.ecx = n;
@@ -114,31 +115,24 @@ grub_console_putchar_real (grub_uint8_t c)
 
   /* check the column with the width */
   if (pos.x >= 79)
     {
       grub_console_putchar_real (0x0d);
       grub_console_putchar_real (0x0a);
     }
   else
     grub_console_gotoxy (NULL, (struct grub_term_coordinate) { pos.x + 1,
 	  pos.y });
 }
 
-static void
-grub_console_putchar (struct grub_term_output *term __attribute__ ((unused)),
-		      const struct grub_unicode_glyph *c)
-{
-  grub_console_putchar_real (c->base);
-}
-
 /*
  * BIOS call "INT 10H Function 09h" to write character and attribute
  *	Call with	%ah = 0x09
  *                      %al = (character)
  *                      %bh = (page number)
  *                      %bl = (attribute)
  *                      %cx = (number of times)
  */
 static void
 grub_console_cls (struct grub_term_output *term)
 {
   /* move the cursor to the beginning */
@@ -191,60 +185,219 @@ grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)),
  *		If key waiting to be input:
  *			%ah = keyboard scan code
  *			%al = ASCII character
  *			Zero flag = clear
  *		else
  *			Zero flag = set
  * BIOS call "INT 16H Function 00H" to read character from keyboard
  *	Call with	%ah = 0x0
  *	Return:		%ah = keyboard scan code
  *			%al = ASCII character
  */
 
+static const int tastatur_deutsch[] = {
+	/* Reihe 1, ohne Shift */
+	['`'] = '^',
+	['1'] = '1',
+	['2'] = '2',
+	['3'] = '3',
+	['4'] = '4',
+	['5'] = '5',
+	['6'] = '6',
+	['7'] = '7',
+	['8'] = '8',
+	['9'] = '9',
+	['0'] = '0',
+	['-'] = 'ß',
+	['='] = '´',
+
+	/* Reihe 2, ohne Shift */
+	['q'] = 'q',
+	['w'] = 'w',
+	['e'] = 'e',
+	['r'] = 'r',
+	['t'] = 't',
+	['y'] = 'z',
+	['u'] = 'u',
+	['i'] = 'i',
+	['o'] = 'o',
+	['p'] = 'p',
+	['['] = 'ü',
+	[']'] = '+',
+
+	/* Reihe 3, ohne Shift */
+	['a'] = 'a',
+	['s'] = 's',
+	['d'] = 'd',
+	['f'] = 'f',
+	['g'] = 'g',
+	['h'] = 'h',
+	['j'] = 'j',
+	['k'] = 'k',
+	['l'] = 'l',
+	[';'] = 'ö',
+	['\''] = 'ä',
+	['\\'] = '#',
+
+	/* Reihe 4, ohne Shift */
+/*	['\\'] = '<', */
+	['z'] = 'y',
+	['x'] = 'x',
+	['c'] = 'c',
+	['v'] = 'v',
+	['b'] = 'b',
+	['n'] = 'n',
+	['m'] = 'm',
+	[','] = ',',
+	['.'] = '.',
+	['/'] = '-',
+
+	/* Reihe 1, mit Shift */
+	['~'] = '\0',
+	['!'] = '!',
+	['@'] = '"',
+	['#'] = '§',
+	['$'] = '$',
+	['%'] = '%',
+	['^'] = '&',
+	['&'] = '/',
+	['*'] = '(',
+	['('] = ')',
+	[')'] = '=',
+	['_'] = '?',
+	['+'] = '`',
+
+	/* Reihe 2, mit Shift */
+	['Q'] = 'Q',
+	['W'] = 'W',
+	['E'] = 'E',
+	['R'] = 'R',
+	['T'] = 'T',
+	['Y'] = 'Z',
+	['U'] = 'U',
+	['I'] = 'I',
+	['O'] = 'O',
+	['P'] = 'P',
+	['{'] = 'Ü',
+	['}'] = '*',
+
+
+	/* Reihe 3, mit Shift */
+	['A'] = 'A',
+	['S'] = 'S',
+	['D'] = 'D',
+	['F'] = 'F',
+	['G'] = 'G',
+	['H'] = 'H',
+	['J'] = 'J',
+	['K'] = 'K',
+	['L'] = 'L',
+	[':'] = 'Ö',
+	['"'] = 'ä',
+	['|'] = '#',
+
+	/* Reihe 4, mit Shift */
+/*	['|'] = '>',*/
+	['Z'] = 'Y',
+	['X'] = 'X',
+	['C'] = 'C',
+	['V'] = 'V',
+	['B'] = 'B',
+	['N'] = 'N',
+	['M'] = 'M',
+	['<'] = ';',
+	['>'] = ':',
+	['?'] = '_',
+
+};
+
+static struct belegung {
+	const char *hinweis;
+	const char *name;
+	const int *map;
+} belegung[] = {
+	{
+		.hinweis = "Tastaturbelegung ist jetzt",
+		.name = "deutsch",
+		.map = tastatur_deutsch,
+	},
+	{
+		.name = "none",
+		.map = NULL,
+	},
+};
+static int *tastatur_belegung;
 static int
 grub_console_getkey (struct grub_term_input *term __attribute__ ((unused)))
 {
   const grub_uint16_t bypass_table[] = {
     0x0100 | GRUB_TERM_ESC, 0x0f00 | GRUB_TERM_TAB, 0x0e00 | GRUB_TERM_BACKSPACE, 0x1c00 | '\r', 0x1c00 | '\n'
   };
   struct grub_bios_int_registers regs;
   unsigned i;
+  int ret, orig;
+  static int prev;
 
   /*
    * Due to a bug in apple's bootcamp implementation, INT 16/AH = 0 would
    * cause the machine to hang at the second keystroke. However, we can
    * work around this problem by ensuring the presence of keystroke with
    * INT 16/AH = 1 before calling INT 16/AH = 0.
    */
 
   regs.eax = 0x0100;
   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;
+  {
+    ret =  GRUB_TERM_NO_KEY;
+    goto out;
+  }
 
   regs.eax = 0x0000;
   regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
   grub_bios_interrupt (0x16, &regs);
   if (!(regs.eax & 0xff))
-    return ((regs.eax >> 8) & 0xff) | GRUB_TERM_EXTENDED;
+{
+orig =
+    ret =  ((regs.eax >> 8) & 0xff) | GRUB_TERM_EXTENDED;
+    goto out;
+  }
 
   if ((regs.eax & 0xff) >= ' ')
-    return regs.eax & 0xff;
+{
+orig =
+    ret =  regs.eax & 0xff;
+    i = ret;
+    if (tastatur_belegung && tastatur_belegung[i])
+	    ret = tastatur_belegung[i];
+    goto out;
+  }
 
   for (i = 0; i < ARRAY_SIZE (bypass_table); i++)
     if (bypass_table[i] == (regs.eax & 0xffff))
-      return regs.eax & 0xff;
+{
+orig =
+      ret =  regs.eax & 0xff;
+    goto out;
+  }
 
-  return (regs.eax & 0xff) + (('a' - 1) | GRUB_TERM_CTRL);
+orig =
+  ret =  (regs.eax & 0xff) + (('a' - 1) | GRUB_TERM_CTRL);
+out:
+  if (0 && ret != prev) {
+  grub_printf("\n %04x %04x > %08x > %04x\n ", regs.eax, regs.flags, orig, ret);
+  prev = ret;
+  }
+  return ret;
 }
 
 static int
 grub_console_getkeystatus (struct grub_term_input *term __attribute__ ((unused)))
 {
   const struct grub_machine_bios_data_area *bios_data_area =
   (struct grub_machine_bios_data_area *) grub_absolute_pointer (GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR);
   /* conveniently GRUB keystatus is modelled after BIOS one.  */
   return bios_data_area->keyboard_flag_lower & ~0x80;
 }
 
 static struct grub_term_coordinate
@@ -264,24 +417,55 @@ grub_console_setcolorstate (struct grub_term_output *term
       break;
     case GRUB_TERM_COLOR_NORMAL:
       grub_console_cur_color = grub_term_normal_color & 0x7f;
       break;
     case GRUB_TERM_COLOR_HIGHLIGHT:
       grub_console_cur_color = grub_term_highlight_color & 0x7f;
       break;
     default:
       break;
   }
 }
 
+static grub_err_t
+grub_cmd_tastatur_belegung (struct grub_command *cmd __attribute__ ((unused)),
+		 int argc, char *argv[])
+{
+  int i;
+  if (argc < 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "layout name required");
+
+  for (i = 0; belegung[i].map; i++)
+  {
+    if (grub_strcmp(argv[0], belegung[i].name) == 0)
+    {
+      grub_printf("%s %s\n", belegung[i].hinweis ? : "", belegung[i].name);
+      tastatur_belegung = belegung[i].map;
+      return GRUB_ERR_NONE;
+    }
+  }
+  return grub_error (GRUB_ERR_BAD_ARGUMENT, "layout %s not found.", argv[0]);
+}
+
+static grub_command_t cmd;
+static void
+grub_console_putchar (struct grub_term_output *term __attribute__ ((unused)),
+		      const struct grub_unicode_glyph *c)
+{
+  if (!cmd)
+    cmd = grub_register_command ("tastatur_belegung", grub_cmd_tastatur_belegung,
+                                0, N_("Set a keyboard layout."));
+  grub_console_putchar_real (c->base);
+}
+
 static struct grub_term_input grub_console_term_input =
   {
     .name = "console",
     .getkey = grub_console_getkey,
     .getkeystatus = grub_console_getkeystatus
   };
 
 static struct grub_term_output grub_console_term_output =
   {
     .name = "console",
     .putchar = grub_console_putchar,
     .getwh = grub_console_getwh,
@@ -295,15 +479,17 @@ static struct grub_term_output grub_console_term_output =
   };
 
 void
 grub_console_init (void)
 {
   grub_term_register_output ("console", &grub_console_term_output);
   grub_term_register_input ("console", &grub_console_term_input);
 }
 
 void
 grub_console_fini (void)
 {
+  if (cmd)
+    grub_unregister_command (cmd);
   grub_term_unregister_input (&grub_console_term_input);
   grub_term_unregister_output (&grub_console_term_output);
 }
openSUSE Build Service is sponsored by