Subject: kern/8456: Enhanced wscons keyboard handling
To: None <gnats-bugs@gnats.netbsd.org>
From: Michael Eriksson <eramore@era-t.ericsson.se>
List: netbsd-bugs
Date: 09/20/1999 15:54:57
>Number:         8456
>Category:       kern
>Synopsis:       Enhanced wscons keyboard handling
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Mon Sep 20 15:50:01 1999
>Last-Modified:
>Originator:     Michael Eriksson
>Organization:
Ericsson Radio Systems AB
>Release:        NetBSD-release as of early September 1999 or so
>Environment:
System: NetBSD burken 1.4.1 NetBSD 1.4.1 (EMT) #0: Mon Sep 13 09:41:04 CEST 1999 eramore@burken:/var/home/eramore/wrk/maestro2/sys/arch/i386/compile/EMT i386


>Description:

The keyboard mapping in wscons has a few problems:

1. You can only have at most one variant active.
2. It puts the encoding and the variants in the same table, which
   creates confusion in wsconsctl.
3. There's no support for Swedish keyboard layout.
4. Standard Swedish keyboard mapping sucks for hacking anyway. :-)

>How-To-Repeat:

Get a Swedish keyboard, and fumble in darkness as the key-tops doesn't
correspond to what's sent.

>Fix:

Here's a patch to add a mapping for the Swedish PC keyboard. It also
adds support for multiple concurrent keyboard variants, and includes
two variants of the Swedish keyboard map:

nodead - Same as the other nodead key maps.
ascii -  Sends the ASCII equivalent of some national keys. This is
         *much* nicer for programming, as a-with-ring is mapped to
         '}', etc.

The syntax for multiple concurrent variants is '+' between the
variants, like this.

datan>wsconsctl -w encoding=se.nodead+ascii

Index: sys/dev/wscons/wsksymdef.h
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/wscons/wsksymdef.h,v
retrieving revision 1.24
diff -u -r1.24 wsksymdef.h
--- wsksymdef.h	1999/02/12 11:14:49	1.24
+++ wsksymdef.h	1999/09/20 22:17:02
@@ -467,13 +467,15 @@
 #define KB_FR			0x0600
 #define KB_UK			0x0700
 #define KB_JP			0x0800
+#define KB_SE			0x0900
 
 #define KB_NODEAD		0x0001
 #define KB_DECLK		0x0002	/* DEC LKnnn layout */
 #define KB_LK401		0x0004	/* DEC LK401 instead LK201 */
 #define KB_SWAPCTRLCAPS		0x0008	/* Swap Control-L and Caps-Lock */
+#define KB_ASCII		0x0010	/* Use ASCII keys for national kbds */
 
-#define KB_NAMETAB \
+#define KB_ENCTAB \
 	{ KB_USER,	"user" }, \
 	{ KB_US,	"us" }, \
 	{ KB_DE,	"de" }, \
@@ -482,9 +484,13 @@
 	{ KB_FR,	"fr" }, \
 	{ KB_UK,	"uk" }, \
 	{ KB_JP,	"jp" }, \
+	{ KB_SE,	"se" }
+
+#define KB_VARTAB \
 	{ KB_NODEAD,	"nodead" }, \
 	{ KB_DECLK,	"declk" }, \
 	{ KB_LK401,	"lk401" }, \
-	{ KB_SWAPCTRLCAPS, "swapctrlcaps" }
+	{ KB_SWAPCTRLCAPS, "swapctrlcaps" }, \
+	{ KB_ASCII,	"ascii" }
 
 #endif /* !_DEV_WSCONS_WSKSYMDEF_H_ */
Index: sys/dev/pckbc/wskbdmap_mfii.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/pckbc/wskbdmap_mfii.c,v
retrieving revision 1.9
diff -u -r1.9 wskbdmap_mfii.c
--- wskbdmap_mfii.c	1999/01/23 17:04:43	1.9
+++ wskbdmap_mfii.c	1999/09/20 22:17:21
@@ -319,6 +319,46 @@
     KC(125), KS_backslash,      KS_bar,
 };
 
+static const keysym_t pckbd_keydesc_se[] = {
+/*  pos      normal		shifted		altgr		shift-altgr */
+    KC(3),   KS_2,		KS_quotedbl,	KS_at,
+    KC(4),   KS_3,		KS_numbersign,	KS_sterling,
+    KC(5),   KS_4,		KS_currency,	KS_dollar,
+    KC(7),   KS_6,		KS_ampersand,
+    KC(8),   KS_7,		KS_slash,	KS_braceleft,
+    KC(9),   KS_8,		KS_parenleft,	KS_bracketleft,
+    KC(10),  KS_9,		KS_parenright,	KS_bracketright,
+    KC(11),  KS_0,		KS_equal,	KS_braceright,
+    KC(12),  KS_plus,		KS_question,	KS_backslash,
+    KC(13),  KS_dead_acute,	KS_dead_grave,
+    KC(26),  KS_aring,
+    KC(27),  KS_dead_diaeresis,	KS_dead_circumflex, KS_dead_tilde,
+    KC(39),  KS_odiaeresis,
+    KC(40),  KS_adiaeresis,
+    KC(41),  KS_section,	KS_onehalf,
+    KC(43),  KS_apostrophe,	KS_asterisk,
+    KC(51),  KS_comma,		KS_semicolon,
+    KC(52),  KS_period,		KS_colon,
+    KC(53),  KS_minus,		KS_underscore,
+    KC(86),  KS_less,		KS_greater,	KS_bar,
+    KC(184), KS_Mode_switch,	KS_Multi_key,
+};
+
+static const keysym_t pckbd_keydesc_se_nodead[] = {
+/*  pos      normal		shifted		altgr		shift-altgr */
+    KC(13),  KS_apostrophe,	KS_grave,
+    KC(27),  KS_diaeresis,	KS_asciicircum,	KS_asciitilde,
+};
+
+static const keysym_t pckbd_keydesc_se_ascii[] = {
+/*  pos      normal		shifted		altgr		shift-altgr */
+    KC(5),   KS_4,		KS_dollar,	KS_currency,
+    KC(26),  KS_braceright,	KS_bracketright, KS_aring,	KS_Aring,
+    KC(39),  KS_bar,		KS_backslash,	KS_odiaeresis,	KS_Odiaeresis,
+    KC(40),  KS_braceleft,	KS_bracketleft,	KS_adiaeresis,	KS_Adiaeresis,
+    KC(41),  KS_asciitilde,
+};
+
 static const keysym_t pckbd_keydesc_us_declk[] = {
 /*  pos      normal		shifted		altgr		shift-altgr */
     KC(1),	KS_grave,	KS_asciitilde, /* replace escape */
@@ -377,6 +417,12 @@
 	KBD_MAP(KB_IT,			KB_US,	pckbd_keydesc_it),
 	KBD_MAP(KB_UK,			KB_US,	pckbd_keydesc_uk),
 	KBD_MAP(KB_JP,			KB_US,	pckbd_keydesc_jp),
+	KBD_MAP(KB_SE,			KB_US,	pckbd_keydesc_se),
+	KBD_MAP(KB_SE | KB_NODEAD,	KB_SE,	pckbd_keydesc_se_nodead),
+	KBD_MAP(KB_SE | KB_ASCII,	KB_SE,	pckbd_keydesc_se_ascii),
+	KBD_MAP(KB_SE | KB_ASCII | KB_NODEAD,
+					KB_SE | KB_ASCII,
+						pckbd_keydesc_se_nodead),
 	KBD_MAP(KB_US | KB_DECLK,	KB_US,	pckbd_keydesc_us_declk),
 	KBD_MAP(KB_US | KB_SWAPCTRLCAPS, KB_US,	pckbd_keydesc_swapctrlcaps),
 	KBD_MAP(KB_JP | KB_SWAPCTRLCAPS, KB_JP, pckbd_keydesc_swapctrlcaps),
Index: sbin/wsconsctl/util.c
===================================================================
RCS file: /cvsroot/basesrc/sbin/wsconsctl/util.c,v
retrieving revision 1.4
diff -u -r1.4 util.c
--- util.c	1998/12/30 19:15:11	1.4
+++ util.c	1999/09/20 22:17:39
@@ -85,14 +85,20 @@
 };
 
 static struct nameint kbdenc_tab[] = {
-	KB_NAMETAB
+	KB_ENCTAB
 };
 
+static struct nameint kbdvar_tab[] = {
+	KB_VARTAB
+};
+
 static struct field *field_tab;
 static int field_tab_len;
 
 static char *int2name __P((int, int, struct nameint *, int));
 static int name2int __P((char *, struct nameint *, int));
+static char *int2flags __P((int, int, struct nameint *, int));
+static int flags2int __P((char *, int, struct nameint *, int));
 static void print_kmap __P((struct wskbd_map_data *));
 
 void
@@ -165,6 +171,64 @@
 	return(-1);
 }
 
+static char *
+int2flags(val, sep, tab, len)
+	int val;
+	int sep;
+	struct nameint *tab;
+	int len;
+{
+	int i;
+	static char buf[256];
+	char sepbuf[2];
+
+	sepbuf[0] = sep;
+	sepbuf[1] = 0;
+	buf[0] = 0;
+	for (i = 0; i < len; i++) {
+		if (val & tab[i].value) {
+			/* This is O(n**2), but n won't be very big */
+			if (buf[0] != 0)
+				strncat(buf, sepbuf, sizeof(buf) - 1);
+			strncat(buf, tab[i].name, sizeof(buf) - 1);
+		}
+	}
+	return (buf[0] != 0 ? buf : 0);
+}
+
+static int
+flags2int(flags, sep, tab, len)
+	char *flags;
+	int sep;
+	struct nameint *tab;
+	int len;
+{
+	int i, val;
+	char *p;
+
+	val = 0;
+	for (;;) {
+		p = strchr(flags, sep);
+		if (p != 0)
+			len = p - flags;
+		else
+			len = strlen(flags);
+		for (i = 0; i < len; i++) {
+			if (strlen(tab[i].name) == len &&
+			    strncmp(tab[i].name, flags, len) == 0) {
+				val |= tab[i].value;
+				goto next;
+			}
+		}
+		return (0);
+	next:
+		if (p == 0)
+			break;
+		flags = p + 1;
+	}
+	return (val);
+}
+
 void
 pr_field(f, sep)
 	struct field *f;
@@ -199,8 +263,8 @@
 			     kbdenc_tab, TABLEN(kbdenc_tab));
 		printf("%s", p);
 
-		p = int2name(KB_VARIANT(*((u_int *) f->valp)), 0,
-			     kbdenc_tab, TABLEN(kbdenc_tab));
+		p = int2flags(KB_VARIANT(*((u_int *) f->valp)), '+',
+			     kbdvar_tab, TABLEN(kbdvar_tab));
 		if (p)
 			printf(".%s", p);
 		break;
@@ -248,9 +312,9 @@
 		if (p == NULL)
 			break;
 
-		i = name2int(p, kbdenc_tab, TABLEN(kbdenc_tab));
-		if (i == -1)
-			errx(1, "%s: not a valid variant", val);
+		i = flags2int(p, '+', kbdvar_tab, TABLEN(kbdvar_tab));
+		if (i == 0)
+			errx(1, "%s: not a valid variant", p);
 		*((u_int *) f->valp) |= i;
 		break;
 	case FMT_KBMAP:
>Audit-Trail:
>Unformatted: