Linux console tools development discussion
 help / color / mirror / Atom feed
From: Michael Schutte <michi@uiae.at>
To: Linux console tools development discussion <kbd@lists.altlinux.org>
Subject: Re: [kbd] [PATCH] loadkeys: Auto-convert “traditional”/Unicode keysyms
Date: Wed, 15 Apr 2009 15:53:44 +0200
Message-ID: <20090415135344.GA3881@graeme> (raw)
In-Reply-To: <49E5021C.5040703@gmail.com>


[-- Attachment #1.1: Type: text/plain, Size: 1247 bytes --]

Hi Alexey,

On Wed, Apr 15, 2009 at 01:37:32AM +0400, Alexey Gladkov wrote:
> 14.04.2009 21:45, Michael Schutte wrote:
> > 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]).
> 
> I have a problem with your patch:
> 
> LANG: ru_RU.UTF-8
> keymap: data/keymaps/i386/qwerty/ruwin_cplk-UTF-8.map
> 
> The difference between the old and the new behavior is attached. This
> is 'dumpkeys -n' output.

Thanks for your testing, I completely missed this.  But you can still
type the affected characters, right?  As far as I can tell, it’s only
dumpkeys which is wrong here.

> And also, you have not updated the documentation for new behaviour.

loadkeys(1) didn’t even document the old meaning of -u.  I’ve added a
short section about the features of this patch.  If you want me to add
more information, please let me know.

A fixed version of the patch is attached to this mail.

Cheers,
-- 
Michael Schutte <michi@uiae.at>

[-- Attachment #1.2: auto_convert.patch --]
[-- Type: text/x-diff, Size: 12752 bytes --]

From 8139d872c6797d73da3465c9839ee98ae865396d Mon Sep 17 00:00:00 2001
From: Michael Schutte <michi@uiae.at>
Date: Tue, 14 Apr 2009 10:46:32 +0200
Subject: [PATCH] loadkeys: Auto-convert “traditional”/Unicode keysyms
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit

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>
---
 man/man1/loadkeys.1.in |   19 ++++++++
 src/dumpkeys.c         |    5 +-
 src/ksyms.c            |  113 +++++++++++++++++++++++++++--------------------
 src/ksyms.h            |    4 +-
 src/loadkeys.y         |   74 ++++++++++++-------------------
 5 files changed, 117 insertions(+), 98 deletions(-)

diff --git a/man/man1/loadkeys.1.in b/man/man1/loadkeys.1.in
index ab4c973..64031af 100644
--- a/man/man1/loadkeys.1.in
+++ b/man/man1/loadkeys.1.in
@@ -23,6 +23,8 @@ loadkeys \- load keyboard translation tables
 ] [
 .I -s --clearstrings
 ] [
+.I -u --unicode
+] [
 .I -v --verbose
 ] [
 .I filename...
@@ -144,6 +146,23 @@ prints to the standard output a file that may be used as a binary
 keymap as expected by Busybox
 .B loadkmap
 command (and does not modify the current keymap).
+.SH "UNICODE MODE"
+.B loadkeys
+automatically detects whether the console is in Unicode or
+ASCII (XLATE) mode.  When a keymap is loaded, literal
+keysyms (such as
+.BR section )
+are resolved accordingly; numerical keysyms are converted to
+fit the current console mode, regardless of the way they are
+specified (decimal, octal, hexadecimal or Unicode).
+.LP
+The
+.I -u
+(or
+.IR --unicode )
+switch tells
+.B loadkeys
+to bypass the check and assume that the console is in Unicode mode.
 .SH "OTHER OPTIONS"
 .TP
 .B \-h \-\-help
diff --git a/src/dumpkeys.c b/src/dumpkeys.c
index 879c96f..580d480 100644
--- a/src/dumpkeys.c
+++ b/src/dumpkeys.c
@@ -135,11 +135,10 @@ 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);
+			printf("U+%04x          ", code ^ 0xf000);
 		return;
 	}
 	plus = 0;
diff --git a/src/ksyms.c b/src/ksyms.c
index e8a494a..36196f1 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,67 @@ 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;
+		prefer_unicode = 0;
 		keycode = ksymtocode(s+5);
+		prefer_unicode = save_prefer_unicode;
 		if (KTYP(keycode) == KT_LATIN)
 			return K(KT_META, KVAL(keycode));
 
@@ -1767,10 +1791,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 +1843,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..a4a2f30 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
@@ -270,7 +272,7 @@ usage(void) {
 "  -h --help          display this help text\n"
 "  -m --mktable       output a \"defkeymap.c\" to stdout\n"
 "  -s --clearstrings  clear kernel string table\n"
-"  -u --unicode       implicit conversion to Unicode\n"
+"  -u --unicode       force conversion to Unicode\n"
 "  -v --verbose       report the changes\n"), PACKAGE_VERSION, DEFMAP);
 	exit(1);
 }
@@ -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


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

  reply	other threads:[~2009-04-15 13:53 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-04-14 17:45 Michael Schutte
2009-04-14 21:37 ` Alexey Gladkov
2009-04-15 13:53   ` Michael Schutte [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090415135344.GA3881@graeme \
    --to=michi@uiae.at \
    --cc=kbd@lists.altlinux.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

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