handrake

About myself

I am a student in computer engineering at University of Waterloo. I have been using Ubuntu Linux for 2 months now. Right now, I'm living in Etobicoke, it's a part of GTA (around Toronto area), working as co-op (co-op is like an intern program). I'm dying to get a computer sometime next week so that I can participate.

I finally got my computer, fujitsu P7120, and I'm totally satisfied with what I've got. Looks all good to me Smile :)

Known Bugs

There is a bug in gaim 2.0 beta, the one with not being able to send a last character if you are writing in Korean. Currently, you can send messages in Korean without a problem in a message tab, which has been a problem back in gaim 1.5, but in "Set friendly name" menu, the problem seems to still exist.

I think this bug can be fixed with a simple patch, doing the same thing Gaim team has done for a message tab.

-- this bug is fixed in gaim 2.0 beta cvs version.

Translated Documents

I have translated the following documents so far.

http://www.ubuntu.or.kr/wiki.php/KernelHowTo

http://www.ubuntu.or.kr/wiki.php/KernelPatchHowTo

http://www.ubuntu.or.kr/ubuntu/wiki.php/ApacheMySQLPHP

Hacking Linux Keyboard Driver

It is a well-known problem (among Korean users) Linux kernel & X windows do not support Korean/English and Korean/Chinese toggle keys as default. To use them, you have to manually create a keymap for them, which is usually done like the following.

$ setkeycodes 71 123   # Korean/Chinese toggle key
$ setkeycodes 72 122   # Korean/English toggle key

This will tell Linux kernel that those two keys are going to be used as we expect. However, it's not all done yet; because X11 does not have a complete keymap (with keysym and all that) for Korean keyboard, we have to tell X, too, just about the same thing.

$ xmodmap -e "keycode 209 = Hangul"   # Korean/English
$ xmodmap -e "keycode 210 = Hangul_Hanja"   # Korean/Chinese

This is it. This was a quick nice way to get your two keys working in Breezy. However, in Dapper, I heard from a lot of people those two keys don't work any more as they did back in Breezy. So I decided to dig it a little to see what's possibly going wrong and hopefully, how to get it working without setting them if at all possible.

Keyboard Scancode

To hack keyboard driver (which is located in kernel source under drivers/input/keyboard/atkbd.c AT keyboard driver looks like it's always built-in to the kernel) I needed to have some background information to understand what's really going on behind the scene. Without a solid knowledge of how keyboard works (at least how scancodes are translated from set 2 to set 1 and all that) keyboard driver looks like a mess of unsolved mathematical problems.

http://www.win.tue.nl/~aeb/linux/kbd/scancodes.html

this is where you can get all the gory details needed to understand how keyboard driver works. Just read section 10 first then 8 and 9 since all other sections talk about special keyboards and mouse we are not really interested in. Now let's look at the source code.

 /* drivers/input/keyboard/atkbd.c */

static unsigned char atkbd_set2_keycode[512] = {

#ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES

/* XXX: need a more general approach */

#include "hpps2atkbd.h" /* include the keyboard scancodes */

#else
          0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,
          0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,
          0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,
          0, 49, 48, 35, 34, 21,  7,184,  0,  0, 50, 36, 22,  8,  9,185,
          0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
          0, 89, 40,  0, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0, 85,
          0, 86, 91, 90, 92,  0, 14, 94,  0, 79,124, 75, 71,121,  0,  0,
         82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,

          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,
        173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,
        159,  0,115,  0,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,
        157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,
        226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,
          0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,
        110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,

          0,  0,  0, 65, 99,
#endif
};
... set 3 scancodes

static unsigned char atkbd_unxlate_table[128] = {
          0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
         21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
         35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
         50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,
         11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,
        114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,
         71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
         19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
};

this is the set 2 keymap and its translated set 1 scancodes as well; all default keys are registered here.

/* include/linux/input.h */
#define KEY_HANGUEL             122
#define KEY_HANJA               123

However, there is no 122 or 123 in set 2 keymap which are Korean/English and Korean/Chinese keys respectively defined in kernel under include/linux/input.h

From the above keymap, first 0x7f(=127) keys (0, 67 ... 70, 99) are the ones that have their position as their set 2 scancode. For example, 67 is located in 0x01, which is F9 (see the very bottom in section 10 of the website far above). 82 is located 0x70, and that's keypad 0. The bottom half from 0x80 to 0xff is the keymap for escape scancodes that start with e0 xx (2 bytes). So what are the scancodes for Korean/English and Korean/Chinese keys? 0xf2 and 0xf1. There seems to be no room for them because first half is 0x00-0x7f and the other half is 0x80-0xff. Well, but actually there is. If you scrutinize every line of the source code (atkbd.c), you will find that

        if (atkbd->translated) {

                if (atkbd->emul ||
                    !(code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1 ||
                     (code == ATKBD_RET_ERR && !atkbd->err_xl) ||
                     (code == ATKBD_RET_BAT && !atkbd->bat_xl))) {
                        atkbd->release = code >> 7;
                        code &= 0x7f;
                }

                if (!atkbd->emul) {
                     if ((code & 0x7f) == (ATKBD_RET_BAT & 0x7f))
                        atkbd->bat_xl = !atkbd->release;
                     if ((code & 0x7f) == (ATKBD_RET_ERR & 0x7f))
                        atkbd->err_xl = !atkbd->release;
                }
        }

something like this. Basically what it does is,

  • if scancode is in range 0x00~0x7f, leave it as it is.
  • if scancode is more than 0x7f, AND(&) it with 0x7f.

So all I need to do is to include those two keys appropriately in keymap. They are going to be

  • 0xf2 & 0x7f = 0x72 // Korean/English

  • 0xf1 & 0x7f = 0x71 // Korean/Chinese

But these are translated set 1 scancodes. If you want to find out where they are in set 2 keymap, you have to look at the translation table. From the table, we can see it right away that it's 0x72->0x39 (Korean/English) and 0x71->0x19 (Korean/Chinese).

However, I need to delete all the exceptions about those two keys that already exist in the source code (looks like they tried to implement but stopped trying while doing it.)

So the patch would look like the following.

--- a/drivers/input/keyboard/atkbd.c    2006-01-31 01:25:07.000000000 -0500
+++ b/drivers/input/keyboard/atkbd.c    2006-03-11 12:55:25.000000000 -0500
@@ -81,9 +81,9 @@ static unsigned char atkbd_set2_keycode[

 #else
          0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,
-         0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,
+         0, 56, 42, 93, 29, 16,  2,  0,  0,123, 44, 31, 30, 17,  3,  0,
          0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,
-         0, 49, 48, 35, 34, 21,  7,184,  0,  0, 50, 36, 22,  8,  9,185,
+         0, 49, 48, 35, 34, 21,  7,184,  0,122, 50, 36, 22,  8,  9,185,
          0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
          0, 89, 40,  0, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0, 85,
          0, 86, 91, 90, 92,  0, 14, 94,  0, 79,124, 75, 71,121,  0,  0,
@@ -149,8 +149,6 @@ static unsigned char atkbd_unxlate_table
 #define ATKBD_RET_EMUL0                0xe0
 #define ATKBD_RET_EMUL1                0xe1
 #define ATKBD_RET_RELEASE      0xf0
-#define ATKBD_RET_HANGUEL      0xf1
-#define ATKBD_RET_HANJA                0xf2
 #define ATKBD_RET_ERR          0xff

 #define ATKBD_KEY_UNKNOWN        0
@@ -303,7 +301,6 @@ static irqreturn_t atkbd_interrupt(struc

                if (atkbd->emul ||
                    !(code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1 ||
-                     code == ATKBD_RET_HANGUEL || code == ATKBD_RET_HANJA ||
                     (code == ATKBD_RET_ERR && !atkbd->err_xl) ||
                     (code == ATKBD_RET_BAT && !atkbd->bat_xl))) {
                        atkbd->release = code >> 7;
@@ -332,12 +329,6 @@ static irqreturn_t atkbd_interrupt(struc
                case ATKBD_RET_RELEASE:
                        atkbd->release = 1;
                        goto out;
-               case ATKBD_RET_HANGUEL:
-                       atkbd_report_key(atkbd->dev, regs, KEY_HANGUEL, 3);
-                       goto out;
-               case ATKBD_RET_HANJA:
-                       atkbd_report_key(atkbd->dev, regs, KEY_HANJA, 3);
-                       goto out;
                case ATKBD_RET_ERR:
                        printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys);
                        goto out;

Many thanks to ganacoconut. This could be all done for his help.

After testing using getkeycodes, it is confirmed that the two keys are mapped into the right position (0x71 and 0x72) as expected. However, showkey still doesn't react when pressing the two in dapper; I personally think that it's from some bug in hotkey-setup or something because other distos or breezy don't have this problem. Once it's set up, I should be able to see the key event with xev and showkey.

USB Keyboard

Some people have told me that in USB Keyboard, X keycodes are reversed. So I took a quick look at the kernel USB Keyboard driver and found out that,

static unsigned char usb_kbd_keycode[256] = {
          0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
         50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
          4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
         27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
         65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
        105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
         72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
        191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
        115,114,  0,  0,  0,121,  0, 89, 93,124, 92, 94, 95,  0,  0,  0,
        122,123, 90, 91, 85,  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,  0,  0,  0,
         29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
        150,158,159,128,136,177,178,176,142,152,173,140
};

122, 123 are in ascending order. Well, at least for PS/2, it was descending. I guess (can't be better than a guess since I never tried it) this needs to be 123, 122 to fix the problem.

Things to be done for complete solution

This is somehow repetitive, but I'm going to try to be more descriptive.

1. Kernel has to be able to indentify two keys (Korean/English and Korean/Chinese toggle keys). This is described in detail in the above section.

2. Dapper version of xserver-xorg-input-kbd contains a patch which has disabled the two keys (can't enable them even with setkeycodes). That's the following.

--- xserver-xorg-input-keyboard-1.0.1.3.orig/src/kbd.c
+++ xserver-xorg-input-keyboard-1.0.1.3/src/kbd.c
@@ -770,7 +770,7 @@
   /*
    * check for an autorepeat-event
    */
-  if (down && KeyPressed(keycode)) {
+  if (down && KeyPressed(keycode) && keycode < 146) {
       int num = keycode >> 3;
       int bit = 1 << (keycode & 7);

@@ -783,11 +783,25 @@
    if (UsePrefix) {
       xf86PostKeyboardEvent(device,
               keyc->modifierKeyMap[keyc->maxKeysPerModifier*7], TRUE);
-      xf86PostKeyboardEvent(device, keycode, down);
+      if (keycode < 146) {
+             xf86PostKeyboardEvent(device, keycode, down);
+      } else if (down) {
+             /* If it's a key down event, send a down and up. Otherwise
+                drop it */
+             xf86PostKeyboardEvent(device, keycode, TRUE);
+             xf86PostKeyboardEvent(device, keycode, FALSE);
+      }
       xf86PostKeyboardEvent(device,
               keyc->modifierKeyMap[keyc->maxKeysPerModifier*7], FALSE);
    } else {
-      xf86PostKeyboardEvent(device, keycode, down);
+          if (keycode < 146) {
+                  xf86PostKeyboardEvent(device, keycode, down);
+          } else if (down) {
+                  /* If it's a key down event, send a down and up. Otherwise
+                     drop it */
+                  xf86PostKeyboardEvent(device, keycode, TRUE);
+                  xf86PostKeyboardEvent(device, keycode, FALSE);
+          }
    }

As you can see, this patch would let X to only accept keycodes less than 146; however, the two keys I've been talking about all along have keycodes 209 and 210, which are obvious greater than 146. Thus, they will be rejected and not post keyboard event as they should.

To tell you the truth, a quick way to get rid of this problem would be to reverse the patch; however, I do not think it's the right way to do it. The more right way to approach would be to create a whole new keymap, geometry, and symbol for Korean Keyboard. If it's done, the two keys will be considered as special keys, and X will be happy to take care of them (I suppose?)

3. /usr/include/X11/keysymdef.h file needs to be changed such that it supports the two keys.

4. We need to create a new keymap, geometry, symbol, and whatever else needs to be done for Korean Keyboard in /etc/X11/xkb

5. Make sure X provides the same keycodes for PS/2 and USB keyboards. This is also discussed in the above.


CategoryHomepage

handrake (last edited 2008-08-06 16:26:29 by localhost)