bug-grub
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Let setkey handle Japanese keyboards


From: Norman Diamond
Subject: [PATCH] Let setkey handle Japanese keyboards
Date: Sat, 13 Sep 2003 14:06:10 +0900 (JST)

The setkey command can do a limited amount of keyboard remapping to
handle some non-U.S. keyboard layouts.  The Japanese layout is harder
to handle because the number of keys with "ordinary" characters (i.e.
essentially the same as ASCII) is larger than the number of keys on
a U.S. keyboard, and two of the keys have scan codes which the BIOS
doesn't translate.  So I have added code to the implementation of the
setkey command, and have added two options which can be used either
interactively or in the menu.lst file.
   setkey jp
   setkey jpn
The first of those is for an ordinary JP106 keyboard.  The second is
for a notebook's keyboard, or for any JP106 keyboard when NumLock is
not automatically enabled by the BIOS at the beginning of booting.

In the interrupt handler I swap the scan code of the hankaku/zenkaku key
(which is the backquote tilde key on a US keyboard) with the yen bar key
(which doesn't exist on a US keyboard), let the BIOS translate it as if
it were the `~ key, and then further translate the result in ordinary
key remapping.  Also in the interrupt handler I swap the scan code of
the Insert key (which is also the Insert key on a US keyboard) with the
backslash underscore key (which doesn't exist on a US keyboard), let
the BIOS translate it as if it were the Insert key, and then further
translate it twice more in Grub's control character remapping and
ordinary key remapping.  This abuse of the Insert key's scan code is
the reason why the NumLock state affects the shifted-vs-unshifted
state of the actual backslash underscore key.  This is why the jp and
jpn have to be two separate options.

Since the jp and jpn options already do so much gross manipulation of
the translation tables, I also made them finish the job of remapping
all keys for a Japanese keyboard.  There seemed to be no point in
imposing a list of ordinary setkey commands following a less thorough
job by setkey jp or jpn.

Fortunately Grub didn't already use the Insert key, so I could abuse
its scan code this way.  One side effect of this patch is that the
Insert key will never be usable (even if setkey jp or jpn is not
invoked).  But the alternative is that a Japanese keyboard remains
painful to use.  This is not a frivolous situation.  120 million
residents of Japan depend on Japanese keyboards just as much as 300
million residents of the US depend on US keyboards.  The number of
people who plan to make the Insert key actually do anything during
keyboard input to Grub during boot time is surely a lot smaller than
either of these numbers.  Even if there were any imagined potential
use of the Insert key, I think the loss is relatively small.

Of course some users might be surprised that Ctrl-O or Ctrl-_ could
have some effect during input to Grub.  But those users might already
be surprised that Ctrl-B has some effect, and I'm not changing that.

Of course this code is incredibly ugly.  It makes me want to throw up
on my keyboard.  But why should I do that when it's not the keyboard's
fault, it's the BIOS's fault  :-?)

Still, since this is the minimal amount of change to handle Japanese
keyboards and stay within Grub's architecture, I submit it for
consideration.

I do not reveal my e-mail address in this posting because my dial-up
account already gets too much spam and I do not intend to open up my
office e-mail address to the same.  I do intend to read the archives
of this mailing list occasionally.  Okuji-san knows my office e-mail
address.

If this patch is adopted, my employer has given permission for me to
transfer copyright to the FSF.

A few minor rewordings, and extension extension of F1 through F10 to
include F11 and F12, are also included.


diff -ru grub-20030715/stage2/asm.S grub-ndd/stage2/asm.S
--- grub-20030715/stage2/asm.S  Sat Dec 21 09:34:33 2002
+++ grub-ndd/stage2/asm.S       Tue Sep  9 13:40:57 2003
@@ -1952,6 +1952,16 @@
        .word   KEY_BACKSPACE, 8
        .word   KEY_PPAGE, 7
        .word   KEY_NPAGE, 3
+/* For Japanese keyboards, when scan codes 0x73 (backslash underscore)
+ * and 0x52 (Insert) are mapped to each other during the interrupt,
+ * the shifted version turns into 0x5200 (KEY_IC's scan code only),
+ * but the unshifted version turns into 0X5230 (KEY_IC | ascii '0').
+ * If NumLock off then the shifted and unshifted versions are swapped.
+ * Map these to ASCII Ctrl-O and Ctrl-_ now, and then ASCII character
+ * mappings map those to underscore and backslash.  For non-Japanese
+ * keyboards, the Insert key gets mapped here.  Barf bags anyone? */
+       .word   KEY_IC, 15
+       .word   0x5230, 31
        .word   0
        
 /*
diff -ru grub-20030715/stage2/builtins.c grub-ndd/stage2/builtins.c
--- grub-20030715/stage2/builtins.c     Mon Mar 10 10:12:26 2003
+++ grub-ndd/stage2/builtins.c  Tue Sep  9 13:40:48 2003
@@ -3484,6 +3484,8 @@
   {"F8",               0,              0,      0,      0x42},
   {"F9",               0,              0,      0,      0x43},
   {"F10",              0,              0,      0,      0x44},
+  {"F11",              0,              0,      0,      0x57},
+  {"F12",              0,              0,      0,      0x58},
   /* Caution: do not add NumLock here! we cannot deal with it properly.  */
   {"delete",           0,              0x7f,   0,      0x53}
 };
@@ -3493,7 +3495,6 @@
 {
   char *to_key, *from_key;
   int to_code, from_code;
-  int map_in_interrupt = 0;
   
   static int find_key_code (char *key)
     {
@@ -3528,43 +3529,8 @@
       
       return 0;
     }
-  
-  to_key = arg;
-  from_key = skip_to (0, to_key);
-
-  if (! *to_key)
-    {
-      /* If the user specifies no argument, reset the key mappings.  */
-      grub_memset (bios_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
-      grub_memset (ascii_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
 
-      return 0;
-    }
-  else if (! *from_key)
-    {
-      /* The user must specify two arguments or zero argument.  */
-      errnum = ERR_BAD_ARGUMENT;
-      return 1;
-    }
-  
-  nul_terminate (to_key);
-  nul_terminate (from_key);
-  
-  to_code = find_ascii_code (to_key);
-  from_code = find_ascii_code (from_key);
-  if (! to_code || ! from_code)
-    {
-      map_in_interrupt = 1;
-      to_code = find_key_code (to_key);
-      from_code = find_key_code (from_key);
-      if (! to_code || ! from_code)
-       {
-         errnum = ERR_BAD_ARGUMENT;
-         return 1;
-       }
-    }
-  
-  if (map_in_interrupt)
+  static int map_in_interrupt(int to_code, int from_code)
     {
       int i;
       
@@ -3596,8 +3562,11 @@
       /* Ugly but should work.  */
       unset_int15_handler ();
       set_int15_handler ();
+
+      return 0;
     }
-  else
+
+  static int map_in_ascii(int to_code, int from_code)
     {
       int i;
       
@@ -3625,9 +3594,104 @@
                      sizeof (unsigned short) * (KEY_MAP_SIZE - i));
       else
        ascii_key_map[i] = (to_code << 8) | from_code;
+
+      return 0;
+    }
+
+  to_key = arg;
+  from_key = skip_to(0, to_key);
+
+  /* Exceptional case:  If there is a single parameter "JP"/"JPN" then hack
+   * up some scan code swapping plus ASCII character mapping.  There is no
+   * other way to get a Japanese keyboard working under this architecture. */
+  if (grub_tolower(to_key[0]) == 'j' &&
+      grub_tolower(to_key[1]) == 'p')
+    {
+      grub_memset (bios_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
+      grub_memset (ascii_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
+      /* Swap scan code 0x29 (hankaku/zenkaku, backquote tilde in the US)
+       * with scan code 0x7D (yen bar), then map the resulting ASCII. */
+      map_in_interrupt(0x7D, 0x29);
+      map_in_interrupt(0x29, 0x7D);
+      map_in_ascii('\\', '`');
+      map_in_ascii('|', '~');
+      /* Swap scan code 0x52 (Insert) with scan code 0x7D (backslash
+       * underscore), let the hacked asm.S translate_keycode function
+       * map it to Ctrl-_ and Ctrl-O (shifty and shiftless depend on
+       * NumLock), then map the resulting ASCII.  Barf bags anyone? */
+      map_in_interrupt(0x73, 0x52);
+      map_in_interrupt(0x52, 0x73);
+      if (grub_tolower(to_key[2]) == 'n')
+       {
+         map_in_ascii('_', 31);
+         map_in_ascii('\\', 15);
+       }
+      else
+       {
+         map_in_ascii('\\', 31);
+         map_in_ascii('_', 15);
+       }
+      /* The rest of a Japanese keyboard could be handled by ordinary
+       * setkey commands, but let's finish the job here. */
+      map_in_ascii('"', '@');
+      map_in_ascii('&', '^');
+      map_in_ascii('\'', '&');
+      map_in_ascii('(', '*');
+      map_in_ascii(')', '(');
+      map_in_ascii(0, ')');
+      map_in_ascii('=', '_');
+      map_in_ascii('^', '=');
+      map_in_ascii('~', '+');
+      map_in_ascii('@', '[');
+      map_in_ascii('`', '{');
+      map_in_ascii('[', ']');
+      map_in_ascii('{', '}');
+      map_in_ascii('+', ':');
+      map_in_ascii(':', '\'');
+      map_in_ascii('*', '"');
+      map_in_ascii(']', '\\');
+      map_in_ascii('}', '|');
+      return 0;
+    }
+
+  if (! *to_key)
+    {
+      /* If the user specifies no argument, reset the key mappings.  */
+      grub_memset (bios_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
+      grub_memset (ascii_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
+
+      return 0;
+    }
+  else if (! *from_key)
+    {
+      /* The user must specify two arguments or zero argument.  */
+      errnum = ERR_BAD_ARGUMENT;
+      return 1;
+    }
+  
+  nul_terminate (to_key);
+  nul_terminate (from_key);
+
+  to_code = find_ascii_code (to_key);
+  from_code = find_ascii_code (from_key);
+  if (! to_code || ! from_code)
+    {
+      to_code = find_key_code (to_key);
+      from_code = find_key_code (from_key);
+      if (! to_code || ! from_code)
+        {
+          errnum = ERR_BAD_ARGUMENT;
+          return 1;
+        }
+      else
+        {
+          return map_in_interrupt(to_code, from_code);
+        }
+    }
+  else
+    {
+      return map_in_ascii(to_code, from_code);
     }
-      
-  return 0;
 }
 
 static struct builtin builtin_setkey =
@@ -3637,14 +3691,17 @@
   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
   "setkey [TO_KEY FROM_KEY]",
   "Change the keyboard map. The key FROM_KEY is mapped to the key TO_KEY."
-  " A key must be an alphabet, a digit, or one of these: escape, exclam,"
+  " A key must be a letter, a digit, or one of these: escape, exclam,"
   " at, numbersign, dollar, percent, caret, ampersand, asterisk, parenleft,"
   " parenright, minus, underscore, equal, plus, backspace, tab, bracketleft,"
   " braceleft, bracketright, braceright, enter, control, semicolon, colon,"
   " quote, doublequote, backquote, tilde, shift, backslash, bar, comma,"
   " less, period, greater, slash, question, alt, space, capslock, FX (X"
-  " is a digit), and delete. If no argument is specified, reset key"
-  " mappings."
+  " is a number from 1 to 12), and delete. If no argument is specified,"
+  " reset key mappings. If a single argument JP is specified, combine"
+  " all the necessary hacks to make a JP106 keyboard operate. If a single"
+  " argument JPN is specified, do the same for a Japanese notebook (or a"
+  " JP106 keyboard whose NumLock is not turned on by the BIOS)."
 };
 
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]