support for unicode dead keys

From: Jirka Bohac (jbohac_at_suse.cz)
Date: 03/22/05

  • Next message: K.R. Foley: "Re: [patch] Real-Time Preemption, -RT-2.6.12-rc1-V0.7.41-07"
    Date:	Tue, 22 Mar 2005 16:00:35 +0100
    To: lkml <linux-kernel@vger.kernel.org>
    
    

    Hello,

    the current keyboard mapping code allows for unicode characters
    in the keyboard maps. There is also a "compose" table which
    allows characters to be combined from two (=dead key) or three
    (=compose key) different keystrokes. This table, however, does not
    support unicode. This patch adds unicode support for composed
    chars:

    diff -Naur 2.6.11-bk-orig/drivers/char/defkeymap.c_shipped 2.6.11-bk-d2/drivers/char/defkeymap.c_shipped
    --- 2.6.11-bk-orig/drivers/char/defkeymap.c_shipped 2005-01-20 15:28:26.000000000 +0100
    +++ 2.6.11-bk-d2/drivers/char/defkeymap.c_shipped 2005-02-15 16:09:26.000000000 +0100
    @@ -222,7 +222,7 @@
             NULL,
     };
     
    -struct kbdiacr accent_table[MAX_DIACR] = {
    +struct kbdiacruc accent_table[MAX_DIACR] = {
             {'`', 'A', '\300'}, {'`', 'a', '\340'},
             {'\'', 'A', '\301'}, {'\'', 'a', '\341'},
             {'^', 'A', '\302'}, {'^', 'a', '\342'},
    diff -Naur 2.6.11-bk-orig/drivers/char/keyboard.c 2.6.11-bk-d2/drivers/char/keyboard.c
    --- 2.6.11-bk-orig/drivers/char/keyboard.c 2005-01-20 15:28:57.000000000 +0100
    +++ 2.6.11-bk-d2/drivers/char/keyboard.c 2005-02-15 16:09:26.000000000 +0100
    @@ -329,7 +329,7 @@
      * in utf-8 already. UTF-8 is defined for words of up to 31 bits,
      * but we need only 16 bits here
      */
    -static void to_utf8(struct vc_data *vc, ushort c)
    +static void to_utf8(struct vc_data *vc, unsigned int c)
     {
             if (c < 0x80)
                     /* 0******* */
    @@ -391,7 +391,7 @@
      * Otherwise, conclude that DIACR was not combining after all,
      * queue it and return CH.
      */
    -static unsigned char handle_diacr(struct vc_data *vc, unsigned char ch)
    +static unsigned int handle_diacr(struct vc_data *vc, unsigned char ch)
     {
             int d = diacr;
             int i;
    @@ -614,11 +614,26 @@
     
     static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
     {
    + unsigned int v;
    +
    +
             if (up_flag)
                     return; /* no action, if this is a key release */
     
    - if (diacr)
    - value = handle_diacr(vc, value);
    + if (diacr) {
    + v = handle_diacr(vc, value);
    +
    + if (kbd->kbdmode == VC_UNICODE) {
    + to_utf8(vc, v & 0xFFFF);
    + return;
    + }
    +
    + /*
    + * this makes at least latin-1 compose chars work
    + * even when using unicode keymap in non-unicode mode
    + */
    + value = v & 0xFF;
    + }
     
             if (dead_key_next) {
                     dead_key_next = 0;
    @@ -637,7 +652,7 @@
     {
             if (up_flag)
                     return;
    - diacr = (diacr ? handle_diacr(vc, value) : value);
    + diacr = (diacr ? handle_diacr(vc, value) & 0xff : value);
     }
     
     /*
    diff -Naur 2.6.11-bk-orig/drivers/char/vt_ioctl.c 2.6.11-bk-d2/drivers/char/vt_ioctl.c
    --- 2.6.11-bk-orig/drivers/char/vt_ioctl.c 2005-01-20 15:28:36.000000000 +0100
    +++ 2.6.11-bk-d2/drivers/char/vt_ioctl.c 2005-02-15 20:06:24.000000000 +0100
    @@ -583,19 +583,46 @@
             case KDGKBDIACR:
             {
                     struct kbdiacrs __user *a = up;
    + struct kbdiacr diacr;
    + int i;
     
                     if (put_user(accent_table_size, &a->kb_cnt))
                             return -EFAULT;
    - if (copy_to_user(a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr)))
    + for (i = 0; i < accent_table_size; i++) {
    + diacr.diacr = accent_table[i].diacr;
    + diacr.base = accent_table[i].base;
    + diacr.result = accent_table[i].result> 0xff ? 0 : accent_table[i].result;
    + if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr)))
    + return -EFAULT;
    + }
    + return 0;
    + }
    +
    + case KDGKBDIACRUC:
    + {
    + struct kbdiacrsuc32 __user *a = up;
    + struct kbdiacruc32 diacr;
    + int i;
    +
    + if (put_user(accent_table_size, &a->kb_cnt))
                             return -EFAULT;
    + for (i = 0; i < accent_table_size; i++) {
    + diacr.diacr = accent_table[i].diacr;
    + diacr.base = accent_table[i].base;
    + diacr.result = accent_table[i].result;
    + if (copy_to_user(a->kbdiacruc + i, &diacr, sizeof(struct kbdiacruc32)))
    + return -EFAULT;
    + }
                     return 0;
             }
     
             case KDSKBDIACR:
             {
                     struct kbdiacrs __user *a = up;
    + struct kbdiacr diacr;
                     unsigned int ct;
    -
    + int i;
    +
                     if (!perm)
                             return -EPERM;
                     if (get_user(ct,&a->kb_cnt))
    @@ -603,8 +630,37 @@
                     if (ct >= MAX_DIACR)
                             return -EINVAL;
                     accent_table_size = ct;
    - if (copy_from_user(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr)))
    + for (i = 0; i < ct; i++) {
    + if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr)))
    + return -EFAULT;
    + accent_table[i].diacr = diacr.diacr;
    + accent_table[i].base = diacr.base;
    + accent_table[i].result = diacr.result;
    + }
    + return 0;
    + }
    +
    + case KDSKBDIACRUC:
    + {
    + struct kbdiacrsuc32 __user *a = up;
    + struct kbdiacruc32 diacr;
    + unsigned int ct;
    + int i;
    +
    + if (!perm)
    + return -EPERM;
    + if (get_user(ct,&a->kb_cnt))
                             return -EFAULT;
    + if (ct >= MAX_DIACR)
    + return -EINVAL;
    + accent_table_size = ct;
    + for (i = 0; i < ct; i++) {
    + if (copy_from_user(&diacr, a->kbdiacruc + i, sizeof(struct kbdiacruc32)))
    + return -EFAULT;
    + accent_table[i].diacr = diacr.diacr;
    + accent_table[i].base = diacr.base;
    + accent_table[i].result = diacr.result;
    + }
                     return 0;
             }
     
    diff -Naur 2.6.11-bk-orig/drivers/s390/char/defkeymap.c 2.6.11-bk-d2/drivers/s390/char/defkeymap.c
    --- 2.6.11-bk-orig/drivers/s390/char/defkeymap.c 2005-01-20 15:28:52.000000000 +0100
    +++ 2.6.11-bk-d2/drivers/s390/char/defkeymap.c 2005-02-15 15:32:01.000000000 +0100
    @@ -148,7 +148,7 @@
             0,
     };
     
    -struct kbdiacr accent_table[MAX_DIACR] = {
    +struct kbdiacruc accent_table[MAX_DIACR] = {
             {'^', 'c', '\003'}, {'^', 'd', '\004'},
             {'^', 'z', '\032'}, {'^', '\012', '\000'},
     };
    diff -Naur 2.6.11-bk-orig/drivers/s390/char/keyboard.c 2.6.11-bk-d2/drivers/s390/char/keyboard.c
    --- 2.6.11-bk-orig/drivers/s390/char/keyboard.c 2005-01-20 15:28:25.000000000 +0100
    +++ 2.6.11-bk-d2/drivers/s390/char/keyboard.c 2005-02-15 18:30:57.000000000 +0100
    @@ -87,11 +87,11 @@
                     goto out_func;
             memset(kbd->fn_handler, 0, sizeof(fn_handler_fn *) * NR_FN_HANDLER);
             kbd->accent_table =
    - kmalloc(sizeof(struct kbdiacr)*MAX_DIACR, GFP_KERNEL);
    + kmalloc(sizeof(struct kbdiacruc)*MAX_DIACR, GFP_KERNEL);
             if (!kbd->accent_table)
                     goto out_fn_handler;
             memcpy(kbd->accent_table, accent_table,
    - sizeof(struct kbdiacr)*MAX_DIACR);
    + sizeof(struct kbdiacruc)*MAX_DIACR);
             kbd->accent_table_size = accent_table_size;
             return kbd;
     
    @@ -464,7 +464,6 @@
     kbd_ioctl(struct kbd_data *kbd, struct file *file,
               unsigned int cmd, unsigned long arg)
     {
    - struct kbdiacrs __user *a;
             void __user *argp;
             int ct, perm;
     
    @@ -485,17 +484,45 @@
             case KDSKBSENT:
                     return do_kdgkb_ioctl(kbd, argp, cmd, perm);
             case KDGKBDIACR:
    - a = argp;
    -
    + {
    + struct kbdiacrs __user *a = argp;
    + struct kbdiacr diacr;
    + int i;
    +
                     if (put_user(kbd->accent_table_size, &a->kb_cnt))
                             return -EFAULT;
    - ct = kbd->accent_table_size;
    - if (copy_to_user(a->kbdiacr, kbd->accent_table,
    - ct * sizeof(struct kbdiacr)))
    + for (i = 0; i < kbd->accent_table_size; i++) {
    + diacr.diacr = kbd->accent_table[i].diacr;
    + diacr.base = kbd->accent_table[i].base;
    + diacr.result = kbd->accent_table[i].result > 0xff ? 0 : accent_table[i].result;
    + if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr)))
    + return -EFAULT;
    + }
    + return 0;
    + }
    + case KDGKBDIACRUC:
    + {
    + struct kbdiacrsuc32 __user *a = argp;
    + struct kbdiacruc32 diacr;
    + int i;
    +
    + if (put_user(kbd->accent_table_size, &a->kb_cnt))
                             return -EFAULT;
    + for (i = 0; i < kbd->accent_table_size; i++) {
    + diacr.diacr = kbd->accent_table[i].diacr;
    + diacr.base = kbd->accent_table[i].base;
    + diacr.result = accent_table[i].result;
    + if (copy_to_user(a->kbdiacruc + i, &diacr, sizeof(struct kbdiacruc32)))
    + return -EFAULT;
    + }
                     return 0;
    + }
             case KDSKBDIACR:
    - a = argp;
    + {
    + struct kbdiacrs __user *a = argp;
    + struct kbdiacr diacr;
    + int i;
    +
                     if (!perm)
                             return -EPERM;
                     if (get_user(ct, &a->kb_cnt))
    @@ -503,10 +530,37 @@
                     if (ct >= MAX_DIACR)
                             return -EINVAL;
                     kbd->accent_table_size = ct;
    - if (copy_from_user(kbd->accent_table, a->kbdiacr,
    - ct * sizeof(struct kbdiacr)))
    + for (i = 0; i < ct; i++) {
    + if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr)))
    + return -EFAULT;
    + accent_table[i].diacr = diacr.diacr;
    + accent_table[i].base = diacr.base;
    + accent_table[i].result = diacr.result;
    + }
    + return 0;
    + }
    + case KDSKBDIACRUC:
    + {
    + struct kbdiacrsuc32 __user *a = argp;
    + struct kbdiacruc32 diacr;
    + int i;
    +
    + if (!perm)
    + return -EPERM;
    + if (get_user(ct, &a->kb_cnt))
                             return -EFAULT;
    + if (ct >= MAX_DIACR)
    + return -EINVAL;
    + kbd->accent_table_size = ct;
    + for (i = 0; i < ct; i++) {
    + if (copy_from_user(&diacr, a->kbdiacruc + i, sizeof(struct kbdiacruc32)))
    + return -EFAULT;
    + accent_table[i].diacr = diacr.diacr;
    + accent_table[i].base = diacr.base;
    + accent_table[i].result = diacr.result;
    + }
                     return 0;
    + }
             default:
                     return -ENOIOCTLCMD;
             }
    diff -Naur 2.6.11-bk-orig/drivers/s390/char/keyboard.h 2.6.11-bk-d2/drivers/s390/char/keyboard.h
    --- 2.6.11-bk-orig/drivers/s390/char/keyboard.h 2005-01-20 15:28:56.000000000 +0100
    +++ 2.6.11-bk-d2/drivers/s390/char/keyboard.h 2005-02-15 16:09:26.000000000 +0100
    @@ -25,7 +25,7 @@
             unsigned short **key_maps;
             char **func_table;
             fn_handler_fn **fn_handler;
    - struct kbdiacr *accent_table;
    + struct kbdiacruc *accent_table;
             unsigned int accent_table_size;
             unsigned char diacr;
             unsigned short sysrq;
    diff -Naur 2.6.11-bk-orig/include/linux/kbd_diacr.h 2.6.11-bk-d2/include/linux/kbd_diacr.h
    --- 2.6.11-bk-orig/include/linux/kbd_diacr.h 2005-01-20 15:28:19.000000000 +0100
    +++ 2.6.11-bk-d2/include/linux/kbd_diacr.h 2005-02-15 16:32:48.000000000 +0100
    @@ -2,7 +2,7 @@
     #define _DIACR_H
     #include <linux/kd.h>
     
    -extern struct kbdiacr accent_table[];
    +extern struct kbdiacruc accent_table[];
     extern unsigned int accent_table_size;
     
     #endif /* _DIACR_H */
    diff -Naur 2.6.11-bk-orig/include/linux/kd.h 2.6.11-bk-d2/include/linux/kd.h
    --- 2.6.11-bk-orig/include/linux/kd.h 2005-01-20 15:28:40.000000000 +0100
    +++ 2.6.11-bk-d2/include/linux/kd.h 2005-02-15 17:57:08.000000000 +0100
    @@ -122,12 +122,25 @@
             unsigned int kb_cnt; /* number of entries in following array */
             struct kbdiacr kbdiacr[256]; /* MAX_DIACR from keyboard.h */
     };
    +
     #define KDGKBDIACR 0x4B4A /* read kernel accent table */
     #define KDSKBDIACR 0x4B4B /* write kernel accent table */
     
    +struct kbdiacruc32 {
    + __u32 diacr, base, result;
    +};
    +struct kbdiacrsuc32 {
    + unsigned int kb_cnt; /* number of entries in following array */
    + struct kbdiacruc32 kbdiacruc[256]; /* MAX_DIACR from keyboard.h */
    +};
    +
    +#define KDGKBDIACRUC 0x4BFA /* read kernel accent table - UCS */
    +#define KDSKBDIACRUC 0x4BFB /* write kernel accent table - UCS */
    +
     struct kbkeycode {
             unsigned int scancode, keycode;
     };
    +
     #define KDGETKEYCODE 0x4B4C /* read kernel keycode table entry */
     #define KDSETKEYCODE 0x4B4D /* write kernel keycode table entry */
     
    diff -Naur 2.6.11-bk-orig/include/linux/keyboard.h 2.6.11-bk-d2/include/linux/keyboard.h
    --- 2.6.11-bk-orig/include/linux/keyboard.h 2005-01-20 15:28:20.000000000 +0100
    +++ 2.6.11-bk-d2/include/linux/keyboard.h 2005-02-15 16:33:33.000000000 +0100
    @@ -28,6 +28,12 @@
     extern unsigned short *key_maps[MAX_NR_KEYMAPS];
     extern unsigned short plain_map[NR_KEYS];
     extern unsigned char keyboard_type;
    +
    +struct kbdiacruc {
    + unsigned char diacr, base;
    + unsigned short result;
    +};
    +
     #endif
     
     #define MAX_NR_FUNC 256 /* max nr of strings assigned to keys */

    (I did not manage to identify the author of the original patch
    that this one is based on....)

    To take advantage of this kernel patch, a patched version of the kbd
    package can be used. You can get my kbd patch at
    http://jikos.cz/~jbohac/tmp/kbd-1.12-to-2.00.diff
    Please note, that this patch does much more changes to kbd than
    necessary for unicode compose chars to be used. I will split it
    into smaller patches eventually...

    Regards,

    Jirka

    -- 
    Jirka Bohac <jbohac@suse.cz>
    SUSE Labs, SUSE CR
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at  http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at  http://www.tux.org/lkml/
    

  • Next message: K.R. Foley: "Re: [patch] Real-Time Preemption, -RT-2.6.12-rc1-V0.7.41-07"

    Relevant Pages

    • Re: TCHAR and buffer overflows
      ... This would be a problem if you hadn't defined UNICODE in your build. ... unsigned char *_mbsncpy(unsigned char *strDest, ... >> macro WCHAR was introduced to switch between ascii and unicode chars as ... > I think you mean TCHAR. ...
      (comp.security.misc)
    • Re: TCHAR and buffer overflows
      ... This would be a problem if you hadn't defined UNICODE in your build. ... unsigned char *_mbsncpy(unsigned char *strDest, ... >> macro WCHAR was introduced to switch between ascii and unicode chars as ... > I think you mean TCHAR. ...
      (comp.os.ms-windows.nt.admin.security)
    • Re: Most used codification for emails.
      ... of an 'Everything' encoding. ... I tend to ignore Unicode for a practical, if trivial, reason. ... "Japanese " as the first choice when trying to view ... >> It's the only one Mozilla will let you compose in as well. ...
      (sci.lang.japan)
    • Re: There has gotta be an easy answer - binding commands to keys ??
      ... If I can write a bash script to do it, can I bind the script? ... Is there a way to add U2714 to the compose list? ... I have very little experience with inputting unicode chars, ...
      (GNOME)
    • Re: how to convert an unsigned short to an unsigned char?
      ... You are asking about some very basic C/C++ programming. ... chapter 1 or 2 of a C/C++ Programming book. ... CString to unsigned char -> really can't be done and doesn't make any sense. ... What I think you want to do is look into UNICODE. ...
      (microsoft.public.windowsce.embedded.vc)