Linux console tools development discussion
 help / color / mirror / Atom feed
* [kbd] [PATCH] loadkeys: Auto-convert “traditional”/Unicode keysyms
@ 2009-04-14 17:45 Michael Schutte
  2009-04-14 21:37 ` Alexey Gladkov
  2009-04-16 23:36 ` Alexey Gladkov
  0 siblings, 2 replies; 15+ messages in thread
From: Michael Schutte @ 2009-04-14 17:45 UTC (permalink / raw)
  To: kbd; +Cc: 524057

[-- Attachment #1: Type: text/plain, Size: 11321 bytes --]

The Linux kernel distinguishes between K(KTYP, KVAL) keysyms and Unicode
characters.  This patch makes loadkeys query the console’s Unicode mode
and convert between the two keysym types according to the result.  The
theoretical advantage is that less keymaps need both an 8-bit and a
Unicode variant (cf. trq[u], ua[-utf]).

A similar patch (read_keymaps_fmt) has been in use in Debian’s version
of kbd since 2004; see <http://bugs.debian.org/251550> for a discussion.
Credit for this goes to Denis Barbier <barbier@linuxfr.org>.

Signed-off-by: Michael Schutte <michi@uiae.at>
---

Alexey, may I ask you to keep the Cc when you reply to this mail?  I’d
like to keep a record in the Debian BTS <http://bugs.debian.org/524057>.

I tried my best to check that this patch does no harm, but it is quite
invasive.  I think you really have to triple-check before you git-am – I
don’t want to lock out users from their machines because I missed one or
the other corner case.

src/loadkeys.c is not included in this patch for readability reasons.

 src/dumpkeys.c |    3 +-
 src/ksyms.c    |  112 ++++++++++++++++++++++++++++++++------------------------
 src/ksyms.h    |    4 +-
 src/loadkeys.y |   72 ++++++++++++++----------------------
 4 files changed, 95 insertions(+), 96 deletions(-)

diff --git a/src/dumpkeys.c b/src/dumpkeys.c
index 879c96f..1e6acba 100644
--- a/src/dumpkeys.c
+++ b/src/dumpkeys.c
@@ -135,8 +135,7 @@ print_keysym(int code, char numeric) {
 	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);
diff --git a/src/ksyms.c b/src/ksyms.c
index e8a494a..6946e0b 100644
--- a/src/ksyms.c
+++ b/src/ksyms.c
@@ -1644,7 +1644,7 @@ struct cs {
 
 /* Functions for both dumpkeys and loadkeys. */
 
-static int prefer_unicode = 0;
+int prefer_unicode = 0;
 static const char *chosen_charset = NULL;
 
 void
@@ -1685,11 +1685,6 @@ set_charset(const char *charset) {
 	sym *p;
 	unsigned int i;
 
-	if (!strcasecmp(charset, "unicode")) {
-		prefer_unicode = 1;
-		return 0;
-	}
-
 	for (i = 1; i < sizeof(charsets)/sizeof(charsets[0]); i++) {
 		if (!strcasecmp(charsets[i].charset, charset)) {
 			charsets[0].charset = charsets[i].charset;
@@ -1700,7 +1695,7 @@ set_charset(const char *charset) {
 				if(p->name[0])
 					syms[0].table[i] = p->name;
 			}
-			chosen_charset = charset;
+			chosen_charset = strdup(charset);
 			return 0;
 		}
 	}
@@ -1710,38 +1705,66 @@ set_charset(const char *charset) {
 }
 
 const char *
-unicodetoksym(int code) {
+codetoksym(int code) {
 	unsigned int i;
 	int j;
 	sym *p;
 
 	if (code < 0)
 		return NULL;
-	if (code < 0x80)
-		return iso646_syms[code];
-	for (i = 0; i < sizeof(charsets)/sizeof(charsets[0]); i++) {
-		p = charsets[i].charnames;
-		for (j = charsets[i].start; j < 256; j++, p++) {
-			if (p->uni == code && p->name[0])
+
+	if (code < 0x1000) {	/* "traditional" keysym */
+		if (KTYP(code) == KT_META)
+			return NULL;
+		if (KTYP(code) == KT_LETTER)
+			code = K(KT_LATIN, KVAL(code));
+		if (KTYP(code) > KT_LATIN)
+			return syms[KTYP(code)].table[KVAL(code)];
+
+		for (i = 0; i < sizeof(charsets)/sizeof(charsets[0]); i++) {
+			p = charsets[i].charnames;
+			if (!p)
+				continue;
+			p += KVAL(code) - charsets[i].start;
+			if (p->name[0])
 				return p->name;
 		}
 	}
+
+	else {			/* Unicode keysym */
+		code ^= 0xf000;
+
+		if (code < 0x80)
+			return iso646_syms[code];
+
+		for (i = 0; i < sizeof(charsets)/sizeof(charsets[0]); i++) {
+			p = charsets[i].charnames;
+			if (!p)
+				continue;
+			for (j = charsets[i].start; j < 256; j++, p++) {
+				if (p->uni == code && p->name[0])
+					return p->name;
+			}
+		}
+	}
+
 	return NULL;
 }
 
 /* Functions for loadkeys. */
 
-int unicode_used = 0;
-
 int
 ksymtocode(const char *s) {
 	unsigned int i;
 	int j, jmax;
 	int keycode;
 	sym *p;
+	int save_prefer_unicode;
 
 	if (!strncmp(s, "Meta_", 5)) {
+		save_prefer_unicode = prefer_unicode;
 		keycode = ksymtocode(s+5);
+		prefer_unicode = save_prefer_unicode;
 		if (KTYP(keycode) == KT_LATIN)
 			return K(KT_META, KVAL(keycode));
 
@@ -1767,10 +1790,8 @@ ksymtocode(const char *s) {
 		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,
@@ -1821,38 +1842,33 @@ ksymtocode(const char *s) {
 }
 
 int
-unicodetocode(int code) {
-	const char *s;
-
-	s = unicodetoksym(code);
-	if (s)
-		return ksymtocode(s);
-	else {
-		unicode_used = 1;
-		return (code ^ 0xf000); /* %%% */
-	}
+convert_code(int code)
+{
+	const char *ksym;
+
+	if (KTYP(code) == KT_META)
+		return code;
+	else if (prefer_unicode == (code >= 0x1000))
+		return code;		/* no conversion necessary */
+
+	/* depending on prefer_unicode, this will give us either an 8-bit
+	 * K(KTYP, KVAL) or a Unicode keysym xor 0xf000 */
+	ksym = codetoksym(code);
+	if (ksym)
+		return ksymtocode(ksym);
+	else
+		return code;
 }
 
 int
 add_capslock(int code)
 {
-	char buf[7];
-	const char *p;
-
-	if (KTYP(code) == KT_LATIN)
+	if (KTYP(code) == KT_LATIN && (!prefer_unicode || code < 0x80))
 		return K(KT_LETTER, KVAL(code));
-	if ((unsigned) 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;
+	else if ((code ^ 0xf000) < 0x100)
+		/* Unicode Latin-1 Supplement */
+		/* a bit dirty to use KT_LETTER here, but it should work */
+		return K(KT_LETTER, code ^ 0xf000);
+	else
+		return convert_code(code);
 }
diff --git a/src/ksyms.h b/src/ksyms.h
index 74cff92..b3c3d0c 100644
--- a/src/ksyms.h
+++ b/src/ksyms.h
@@ -26,10 +26,10 @@ extern const unsigned int syn_size;
 #define CODE_FOR_UNKNOWN_KSYM (-1)
 
 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 convert_code(int code);
 extern int add_capslock(int code);
 
 #endif
diff --git a/src/loadkeys.y b/src/loadkeys.y
index 9ff4759..13faf42 100644
--- a/src/loadkeys.y
+++ b/src/loadkeys.y
@@ -63,7 +63,7 @@ static void killkey(int index, int table);
 static void compose(int diacr, int base, int res);
 static void do_constant(void);
 static void do_constant_key (int, u_short);
-static void loadkeys(char *console, int *warned);
+static void loadkeys(char *console);
 static void mktable(void);
 static void bkeymap(void);
 static void strings_as_usual(void);
@@ -73,10 +73,10 @@ static void strings_as_usual(void);
 static void compose_as_usual(char *charset);
 static void lkfatal0(const char *, int);
 extern int set_charset(const char *charset);
+extern int prefer_unicode;
 extern char *xstrdup(char *);
 int key_buf[MAX_NR_KEYMAPS];
 int mod;
-extern int unicode_used;
 int private_error_ct = 0;
 
 extern int rvalct;
@@ -240,11 +240,13 @@ rvalue1		: rvalue
 			}
 		;
 rvalue		: NUMBER
-			{$$=$1;}
-		| UNUMBER
-			{$$=($1 ^ 0xf000); unicode_used=1;}
+			{$$=convert_code($1);}
                 | PLUS NUMBER
                         {$$=add_capslock($2);}
+		| UNUMBER
+			{$$=convert_code($1^0xf000);}
+		| PLUS UNUMBER
+			{$$=add_capslock($2^0xf000);}
 		| LITERAL
 			{$$=$1;}
                 | PLUS LITERAL
@@ -302,8 +304,9 @@ main(int argc, char *argv[]) {
 		{ NULL, 0, NULL, 0 }
 	};
 	int c;
+	int fd;
+	int mode;
 	char *console = NULL;
-        int warned = 0;
 
 	set_progname(argv[0]);
 
@@ -333,7 +336,7 @@ main(int argc, char *argv[]) {
 				opts = 1;
 				break;
 			case 'u':
-				set_charset("unicode");
+				prefer_unicode = 1;
 				break;
 			case 'q':
 				quiet = 1;
@@ -349,8 +352,20 @@ main(int argc, char *argv[]) {
 		}
 	}
 
+	if (!optm && !prefer_unicode) {
+		/* no -u option: auto-enable it if console is in Unicode mode */
+		fd = getfd(NULL);
+		if (ioctl(fd, KDGKBMODE, &mode)) {
+			perror("KDGKBMODE");
+			fprintf(stderr, _("loadkeys: error reading keyboard mode\n"));
+			exit(1);
+		}
+		if (mode == K_UNICODE)
+			prefer_unicode = 1;
+		close(fd);
+	}
+
 	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"));
@@ -375,14 +390,14 @@ main(int argc, char *argv[]) {
 		char ch = *e;
 		*e = '\0';
 		if (verbose) printf("%s\n", s);
-	        loadkeys(s, &warned);
+	        loadkeys(s);
 		*e = ch;
 		s = e;
 	      }
 	    free(buf);
 	  }
 	else
-	  loadkeys(NULL, &warned);
+	  loadkeys(NULL);
 	exit(0);
 }
 
@@ -811,20 +826,10 @@ compose(int diacr, int base, int res) {
 }
 
 static int
-defkeys(int fd, char *cons, int *warned) {
+defkeys(int fd) {
 	struct kbentry ke;
 	int ct = 0;
 	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]) {
@@ -891,27 +896,6 @@ defkeys(int fd, char *cons, int *warned) {
 	    }
 	}
 
-	if(unicode_used && oldm != K_UNICODE) {
-	     if (ioctl(fd, KDSKBMODE, oldm)) {
-		  fprintf(stderr, _("%s: failed to restore keyboard mode\n"),
-			  progname);
-	     }
-
-	     if (!warned++)
-	       {
-		     int kd_mode = -1;
-		     if (ioctl(fd, KDGETMODE, &kd_mode) || (kd_mode != KD_GRAPHICS))
-		       {
-			 /*
-			  * It is okay for the graphics console to have a non-unicode mode.
-			  * only talk about other consoles
-			  */
-			 fprintf(stderr, _("%s: warning: this map uses Unicode symbols, %s mode=%d\n"
-				     "    (perhaps you want to do `kbd_mode -u'?)\n"),
-			     progname, cons ? cons : "NULL", kd_mode);
-		       }
-	       }
-	}
 	return ct;
 }
 
@@ -1044,12 +1028,12 @@ do_constant (void) {
 }
 
 static void
-loadkeys (char *console, int *warned) {
+loadkeys (char *console) {
         int fd;
         int keyct, funcct, diacct = 0;
 
 	fd = getfd(console);
-	keyct = defkeys(fd, console, warned);
+	keyct = defkeys(fd);
 	funcct = deffuncs(fd);
 	if (verbose) {
 	        printf(_("\nChanged %d %s and %d %s.\n"),
-- 
1.6.2.1


-- 
Michael Schutte <michi@uiae.at>

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 489 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2009-04-21 13:20 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-04-14 17:45 [kbd] [PATCH] loadkeys: Auto-convert “traditional”/Unicode keysyms Michael Schutte
2009-04-14 21:37 ` Alexey Gladkov
2009-04-15 13:53   ` Michael Schutte
2009-04-16  0:07     ` Alexey Gladkov
2009-04-16 15:45       ` Michael Schutte
2009-04-16 23:01         ` Alexey Gladkov
2009-04-17 13:44           ` Alexey Gladkov
2009-04-17 20:01     ` Michael Schutte
2009-04-19 15:59       ` Alexey Gladkov
2009-04-19 16:50         ` Michael Schutte
2009-04-19 17:14           ` Alexey Gladkov
2009-04-20 18:39             ` Michael Schutte
2009-04-21 10:08             ` Alexey Gladkov
2009-04-21 13:20               ` Michael Schutte
2009-04-16 23:36 ` Alexey Gladkov

Linux console tools development discussion

This inbox may be cloned and mirrored by anyone:

	git clone --mirror http://lore.altlinux.org/kbd/0 kbd/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 kbd kbd/ http://lore.altlinux.org/kbd \
		kbd@lists.altlinux.org kbd@lists.altlinux.ru kbd@lists.altlinux.com
	public-inbox-index kbd

Example config snippet for mirrors.
Newsgroup available over NNTP:
	nntp://lore.altlinux.org/org.altlinux.lists.kbd


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git