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

Bug#251550: Keyboard freezes when typing non-ASCII letters



[Christian Perrier]
> So, this bug should finally be assigned to console-data with the
> request for creating Unicode keymaps for layouts which don't have
> one (Recai mentions Turkish for instance)?

This is a solution.  IMO a better one is to patch loadkeys as explained
in my previous post.  Here is a first try, I patched kbd 1.12 instead
of console-tools because I do not know dpatch.  Keymap files must
declare a charset so that conversion between Unicode, literal and
decimal notations can be performed.

> What about kbd? You mentioned me in another mail this supposedly more
> recent system for handling keyboard layouts....

Not exactly, Turkish keymaps are better in console-data than in kbd,
but others are better in kbd.  As I said months ago, I do not see the
point in maintaining console-tools when it is dead upstream, and am
quite upset to see that fr-latin0 was chosen as default for French
when it is obsolete and has been removed from kbd.

> Should we start to build a fr-latin0u keyboard, german people a
> Unicode german keyboard layout and so on?

It depends whether Alastair is willing to patch loadkeys or not.

> Or could a switch to another keyboard handling system help?

No, kbd and console-tools are mostly similar, and kbd has the same
problem,

Denis
diff -ur kbd-1.12.orig/src/analyze.l kbd-1.12/src/analyze.l
--- kbd-1.12.orig/src/analyze.l	2004-01-16 22:51:44.000000000 +0100
+++ kbd-1.12/src/analyze.l	2004-06-24 21:28:14.000000000 +0200
@@ -77,7 +77,7 @@
 \-			{return(DASH);}
 \,			{return(COMMA);}
 \+			{return(PLUS);}
-{Unicode}		{yylval=strtol(yytext+1,NULL,16);return(UNUMBER);}
+{Unicode}		{yylval=strtol(yytext+1,NULL,16) ^ 0xf000;return(UNUMBER);}
 {Decimal}|{Octal}|{Hex}	{yylval=strtol(yytext,NULL,0);return(NUMBER);}
 <RVALUE>{Literal}	{return((yylval=ksymtocode(yytext))==-1?ERROR:LITERAL);}
 {Charset}		{return(CHARSET);}
diff -ur kbd-1.12.orig/src/dumpkeys.c kbd-1.12/src/dumpkeys.c
--- kbd-1.12.orig/src/dumpkeys.c	2004-01-16 20:45:31.000000000 +0100
+++ kbd-1.12/src/dumpkeys.c	2004-06-24 23:50:48.000000000 +0200
@@ -131,11 +131,10 @@
 	t = KTYP(code);
 	v = KVAL(code);
 	if (t >= syms_size) {
-		code = code ^ 0xf000;
-		if (!numeric && (p = unicodetoksym(code)) != NULL)
+		if (!numeric && (p = codetoksym(code)) != NULL)
 			printf("%-16s", p);
 		else
-			printf("U+%04x          ", code);
+			printf("U+%04x          ", code ^ 0xf000);
 		return;
 	}
 	if (t == KT_LETTER) {
diff -ur kbd-1.12.orig/src/ksyms.c kbd-1.12/src/ksyms.c
--- kbd-1.12.orig/src/ksyms.c	2004-01-16 20:45:31.000000000 +0100
+++ kbd-1.12/src/ksyms.c	2004-06-25 01:14:42.000000000 +0200
@@ -1,7 +1,9 @@
+#include <linux/kd.h>
 #include <linux/keyboard.h>
 #include <stdio.h>
 #include <string.h>
 #include "ksyms.h"
+#include "getfd.h"
 #include "nls.h"
 
 /* Keysyms whose KTYP is KT_LATIN or KT_LETTER and whose KVAL is 0..127. */
@@ -1615,9 +1617,6 @@
 
 /* Functions for both dumpkeys and loadkeys. */
 
-static int prefer_unicode = 0;
-static const char *chosen_charset = NULL;
-
 void
 list_charsets(FILE *f) {
 	int i,j,lth,ct;
@@ -1655,10 +1654,8 @@
 	sym *p;
 	int i;
 
-	if (!strcasecmp(charset, "unicode")) {
-		prefer_unicode = 1;
+	if (!strcasecmp(charset, "unicode"))
 		return 0;
-	}
 
 	for (i = 0; i < sizeof(charsets)/sizeof(charsets[0]); i++) {
 		if (!strcasecmp(charsets[i].charset, charset)) {
@@ -1667,7 +1664,6 @@
 				if(p->name[0])
 					syms[0].table[i] = p->name;
 			}
-			chosen_charset = charset;
 			return 0;
 		}
 	}
@@ -1677,10 +1673,15 @@
 }
 
 const char *
-unicodetoksym(int code) {
+codetoksym(int code) {
 	int i, j;
 	sym *p;
 
+	if (KTYP(code) == KT_META)
+		return NULL;
+	if (KTYP(code) < syms_size)
+		return syms[KTYP(code)].table[KVAL(code)];
+	code = code ^ 0xf000;
 	if (code < 0)
 		return NULL;
 	if (code < 0x80)
@@ -1697,49 +1698,60 @@
 
 /* Functions for loadkeys. */
 
-int unicode_used = 0;
-
 int
 ksymtocode(const char *s) {
 	int i;
-	int j, jmax;
+	int j;
 	int keycode;
+	int fd;
+	int kbd_mode;
+	int syms_start = 0;
 	sym *p;
 
+	if (!s) {
+		fprintf(stderr, "%s\n", _("null symbol found"));
+		return -1;
+	}
+
+	fd = getfd(NULL);
+	ioctl(fd, KDGKBMODE, &kbd_mode);
 	if (!strncmp(s, "Meta_", 5)) {
+		/* Temporarily change kbd_mode to ensure that keycode is
+		   right. */
+		ioctl(fd, KDSKBMODE, K_XLATE);
 		keycode = ksymtocode(s+5);
+		ioctl(fd, KDSKBMODE, kbd_mode);
 		if (KTYP(keycode) == KT_LATIN)
 			return K(KT_META, KVAL(keycode));
 		/* fall through to error printf */
 	}
 
-	for (i = 0; i < syms_size; i++) {
-		jmax = ((i == 0 && prefer_unicode) ? 128 : syms[i].size);
-		for (j = 0; j < jmax; j++)
+	if (kbd_mode == K_UNICODE) {
+		for (j = 0; j < 0x80; j++)
+			if (!strcmp(s,iso646_syms[j]))
+				return (j ^ 0xf000);
+		syms_start = 1;
+	}
+	for (i = syms_start; i < syms_size; i++) {
+		for (j = 0; j < syms[i].size; j++)
 			if (!strcmp(s,syms[i].table[j]))
 				return K(i, j);
 	}
-
 	for (i = 0; i < syn_size; i++)
 		if (!strcmp(s, synonyms[i].synonym))
 			return ksymtocode(synonyms[i].official_name);
 
-	if (prefer_unicode) {
+	if (kbd_mode == K_UNICODE) {
 		for (i = 0; i < sizeof(charsets)/sizeof(charsets[0]); i++) {
 			p = charsets[i].charnames;
 			for (j = charsets[i].start; j < 256; j++, p++)
-				if (!strcmp(s,p->name)) {
-					unicode_used = 1;
-					return (p->uni ^ 0xf000); /* %%% */
-				}
+				if (!strcmp(s,p->name))
+					return (p->uni ^ 0xf000);
 		}
-	} else /* if (!chosen_charset) */ {
-		/* note: some keymaps use latin1 but with euro,
-		   so set_charset() would fail */
+	} else {
 		/* note: some keymaps with charset line still use
 		   symbols from more than one character set,
-		   so we cannot have the  `if (!chosen_charset)'  here */
-
+		   so we cannot have get charset from set_charset() */
 		for (i = 0; i < 256 - 160; i++)
 			if (!strcmp(s, latin1_syms[i].name)) {
 				fprintf(stderr,
@@ -1782,38 +1794,23 @@
 }
 
 int
-unicodetocode(int code) {
-	const char *s;
-
-	s = unicodetoksym(code);
-	if (s)
-		return ksymtocode(s);
-	else {
-		unicode_used = 1;
-		return (code ^ 0xf000); /* %%% */
-	}
+add_number(int code)
+{
+	int kbd_mode;
+	if (KTYP(code) == KT_META)
+		return code;
+	ioctl(getfd(NULL), KDGKBMODE, &kbd_mode);
+	if (kbd_mode == K_UNICODE && KTYP(code) >= syms_size)
+		return code;
+	if (kbd_mode != K_UNICODE && KTYP(code) < syms_size)
+		return code;
+	return ksymtocode(codetoksym(code));
 }
 
 int
 add_capslock(int code)
 {
-	char buf[7];
-	const char *p;
-
 	if (KTYP(code) == KT_LATIN)
 		return K(KT_LETTER, KVAL(code));
-	if (KTYP(code) >= syms_size) {
-		if ((p = unicodetoksym(code ^ 0xf000)) == NULL) {
-			sprintf(buf, "U+%04x", code ^ 0xf000);
-			p = buf;
-		}
-	} else {
-		sprintf(buf, "0x%04x", code);
-		p = buf;
-	}
-#if 0
-	/* silence the common usage  dumpkeys | loadkeys -u  */
-	fprintf(stderr, _("plus before %s ignored\n"), p);
-#endif
 	return code;
 }
diff -ur kbd-1.12.orig/src/ksyms.h kbd-1.12/src/ksyms.h
--- kbd-1.12.orig/src/ksyms.h	1999-10-05 13:42:16.000000000 +0200
+++ kbd-1.12/src/ksyms.h	2004-06-25 00:38:08.000000000 +0200
@@ -23,10 +23,10 @@
 extern const int syn_size;
 
 extern int set_charset(const char *name);
-extern const char *unicodetoksym(int code);
+extern const char *codetoksym(int code);
 extern void list_charsets(FILE *f);
 extern int ksymtocode(const char *s);
-extern int unicodetocode(int code);
+extern int add_number(int code);
 extern int add_capslock(int code);
 
 #endif
diff -ur kbd-1.12.orig/src/loadkeys.y kbd-1.12/src/loadkeys.y
--- kbd-1.12.orig/src/loadkeys.y	2004-01-16 22:51:25.000000000 +0100
+++ kbd-1.12/src/loadkeys.y	2004-06-25 00:37:21.000000000 +0200
@@ -74,7 +74,6 @@
 extern char *xstrdup(char *);
 int key_buf[MAX_NR_KEYMAPS];
 int mod;
-extern int unicode_used;
 int private_error_ct = 0;
 
 extern int rvalct;
@@ -227,13 +226,15 @@
 			}
 		;
 rvalue		: NUMBER
-			{$$=$1;}
+			{$$=add_number($1);}
+		| LITERAL
+			{$$=add_number($1);}
 		| UNUMBER
-			{$$=($1 ^ 0xf000); unicode_used=1;}
+			{$$=add_number($1);}
                 | PLUS NUMBER
                         {$$=add_capslock($2);}
-		| LITERAL
-			{$$=$1;}
+                | PLUS UNUMBER
+                        {$$=add_capslock($2);}
                 | PLUS LITERAL
                         {$$=add_capslock($2);}
 		;
@@ -319,7 +320,6 @@
 	}
 
 	args = argv + optind - 1;
-	unicode_used = 0;
 	yywrap();	/* set up the first input file, if any */
 	if (yyparse() || private_error_ct) {
 		fprintf(stderr, _("syntax error in map file\n"));
@@ -766,15 +766,6 @@
 	int i,j,fail;
 	int oldm;
 
-	if (unicode_used) {
-	     /* Switch keyboard mode for a moment -
-		do not complain about errors.
-		Do not attempt a reset if the change failed. */
-	     if (ioctl(fd, KDGKBMODE, &oldm)
-	        || (oldm != K_UNICODE && ioctl(fd, KDSKBMODE, K_UNICODE)))
-		  oldm = K_UNICODE;
-	}
-
 	for(i=0; i<MAX_NR_KEYMAPS; i++) {
 	    if (key_map[i]) {
 		for(j=0; j<NR_KEYS; j++) {
@@ -839,16 +830,6 @@
 		}
 	    }
 	}
-
-	if(unicode_used && oldm != K_UNICODE) {
-	     if (ioctl(fd, KDSKBMODE, oldm)) {
-		  fprintf(stderr, _("%s: failed to restore keyboard mode\n"),
-			  progname);
-	     }
-	     fprintf(stderr, _("%s: warning: this map uses Unicode symbols\n"
-		             "    (perhaps you want to do `kbd_mode -u'?)\n"),
-		     progname);
-	}
 	return ct;
 }
 

Reply to: