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 <[email protected]>
SUSE Labs, SUSE CR
Hello,
there is also another UTF8 related patch (regarding composition of utf8 chars)
that has not been merged yet:
http://marc.theaimsgroup.com/?l=linux-kernel&m=110292073210868&w=2
Jan Engelhardt
--