[comp.sources.unix] v20i081: Rebind the console keyboard in Xenix or System Vr3.2.1+

rsalz@uunet.uu.net (Rich Salz) (10/28/89)

Submitted-by: Eric S. Raymond <eric@snark.uu.net>
Posting-number: Volume 20, Issue 81
Archive-name: keybind

[  I have not even tried to compile this this.  /r$  ]

This program is an editor/minilanguage that lets you tweak the tables in
the XENIX or System Vr3.2.1+ console keyboard driver for fun and profit.

It is particularly useful if you use GNU EMACS or anything else that likes
to have a real Meta key; see the -m option and `meta' directive. You can
also map your virtual terminal selector functions to more convenient
places than the bizarre Alt-cokebottle-foobar sequences they default to.

Some may also find klex[12].l and kgram.y interesting as a simple but
nontrivial example of lex/yacc usage, illustrating how to build a
minilanguage with per-line error recovery.

This release adds the capability to `precompile' keyboard mappings using
the -o option; the binary dump files produced can be loaded by subsequent
keybind runs, avoiding the interpreter's lexer and parser overhead.

#!/bin/sh
: "This is a shell archive, meaning:                              "
: "1. Remove everything above the #! /bin/sh line.                "
: "2. Save the resulting test in a file.                          "
: "3. Execute the file with /bin/sh (not csh) to create the files:"
: "	READ.ME"
: "	Makefile"
: "	keybind.c"
: "	kgram.y"
: "	klex1.l"
: "	klex2.l"
: "	kdefaults.h"
: "	keycaps"
: "	keybind.1"
: "	sample.kmf"
echo file: READ.ME
sed 's/^X//' >READ.ME << 'END-of-READ.ME'
X		Release 1.1 notes -- August 1, 1989
X
XThis program is an editor/minilanguage that lets you tweak the tables in the
XXENIX or System Vr3.2.1+ console keyboard driver for fun and profit.
X
XIt is particularly useful if you use GNU EMACS or anything else that likes
Xto have a real Meta key; see the -m option and `meta' directive. You can also
Xmap your virtual terminal selector functions to more convenient places than
Xthe bizarre Alt-cokebottle-foobar sequences they default to.
X
XSome may also find klex[12].l and kgram.y interesting as a simple but
Xnontrivial example of lex/yacc usage, illustrating how to build a minilanguage
Xwith per-line error recovery.
X
XThis replaces and extends the `alter' program I posted a couple of weeks ago;
Xyou can throw that out now.
X
X		Release 1.2 notes -- August 14 1989
X
XThis release adds the capability to `precompile' keyboard mappings using
Xthe -o option; the binary dump files produced can be loaded by subsequent
Xkeybind runs, avoiding the interpreter's lexer and parser overhead.
X
X					Eric S. Raymond (eric@snark.uu.net)
END-of-READ.ME
echo file: Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
X# Makefile for the key mapper utility
X#
X#	@(#)Makefile	1.2
X#
X# Copyright 1989 by Eric S. Raymond (eric@snark.uu.net), all rights reserved
X# You may use, modify or redistribute this code freely, but do not delete
X# this notice. Check with me before you make money with it.
X#
X# Note: if you are running 3.2.1 rather than 3.2u, you have only 256 bytes of
X# string definition space per tty, and you need to add -DMAXSTRINGS=256 to your
X# compile flags. Otherwise it will be assumed that you have 512 bytes of
X# string space per tty.
X#
XCFLAGS = -O	# -g -DYYDEBUG	# -DMAXSTRINGS=256
XLDFLAGS = -s
XYFLAGS = -v
X
Xkeybind: keybind.o kgram.o klex.o
X	$(CC) $(LDFLAGS) keybind.o kgram.o klex.o -ll -o keybind
X
Xkeybind.o: keybind.c kdefaults.h keycaps.h keybind.h
Xkgram.o: kgram.c keybind.h
Xklex.o: klex.c y.tab.h
X
Xklex.l: klex1.l keycaps.l klex2.l
X	cat klex1.l keycaps.l klex2.l >klex.l
X
Xkdefaults.h:
X	keybind -c >kdefaults.h
X
X# keycaps.h is the keycaps include file for C programs
XCFILTER = '/^\([^	]*\).*/s//"@\1",/p'
Xkeycaps.h:
X	sed -n -e '/^#/d' -e $(CFILTER) <keycaps >keycaps.h
X
X# keycaps.l is the keycaps include file for lex programs
XLFILTER = '/\(.*\)	\(.*\)/s//"@\1"	{yylval=\2;yytokno++;return(SCANCODE);}/'
Xkeycaps.l:
X	tr <keycaps "[A-Z]" "[a-z]" | sort -r | sed -e '/^#/d' -e $(LFILTER) >keycaps.l
X
Xkgram.c y.tab.h: kgram.y
X	@echo expect conflicts: 3 shift/reduce
X	yacc -d $(YFLAGS) kgram.y
X	mv y.tab.c kgram.c
X
X# This is a lexical analyzer tester
Xklex: klex.c y.tab.h
X	$(CC) $(CFLAGS) -DMAIN klex.c -ll -o klex
X
Xlint: keybind.c kgram.c klex.c
X	lint keybind.c kgram.c klex.c
X
Xkeybind.lpr:
X	nroff -T$(LPT) -man keybind.1 $(REGS) >$keybind.lpr
X
Xhelp:
X	@nroff -e -man keybind.1 | more
X
XSOURCES = keybind.c kgram.y klex[12].l kdefaults.h keycaps
Xshar:
X	shar READ.ME Makefile $(SOURCES) keybind.1 sample.kmf >keybind.shar
X
Xclean:
X	rm -f kgram.c klex.c y.tab.h y.output klex keybind *.o *~
X	rm -f keycaps.h keycaps.l klex.[lc] keybind.shar
END-of-Makefile
echo file: keybind.c
sed 's/^X//' >keybind.c << 'END-of-keybind.c'
X/*
X * keybind -- console/virtual tty keyboard remapper for 6386WGS systems
X *
X *	@(#)keybind.c	1.2
X *
X * Copyright 1989 by Eric S. Raymond (eric@snark.uu.net), all rights reserved
X * You may use, modify or redistribute this code freely, but do not delete
X * this notice. Check with me before you make money with it.
X */
X#ifndef lint
Xstatic char *sccsid = "@(#)keybind.c	1.2";
X#endif /* lint */
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <sys/types.h>
X#include <sys/at_ansi.h>
X#include <sys/kd.h>
X#include <ctype.h>
X#include <sys/ascii.h>
X#include "keybind.h"
X
X#ifndef MAXSTRINGS
X#define MAXSTRINGS	STRTABLN
X#endif /* MAXSTRINGS */
X
Xextern FILE *yyin;
X#ifdef YYDEBUG
Xextern int yydebug;
X#endif /* YYDEBUG */
X
Xextern void exit();
Xextern void perror();
X
X#define M(c)		(0x80 | (c))
X#define F(n)		((n) + K_FUNF - 1)
X#define VTK(n)		((n) + K_VTF)
X#define IS_VTKEY(c)	(((c) >= K_VTF) && ((c) <= K_VTL))
X#define MGR(n)		((n) + K_MGRF)
X#define IS_MGRKEY(c)	(((c) >= K_MGRF) && ((c) <= K_MGRL))
X#define PFX(n)		((n) + K_PFXF)
X#define IS_PFXKEY(c)	(((c) >= K_PFXF) && ((c) <= K_PFXL))
X
X#define META		0x80
X#define PSPECIAL(p,i)	(p->spcl & (0x80>>(i)))
X
Xtypedef struct
X{
X    int val;
X    char *name;
X}
Xsymbol;
X
Xtypedef struct
X{
X    int val;
X    char *aname;
X    char *mname;
X}
Xtriple;
X
Xkbd_t kbd = {KBDHDMAGIC};			/* our workspace */
X
Xstatic char	funkeys[NSTRKEYS][MAXFK+1];	/* function key strings */
Xstatic int	mapmods = 0;			/* count map table changes */
Xstatic int	stringmods = 0;			/* count string key changes */
Xstatic int	ttyfd;				/* fd of console */
X
X/*
X * The name table for printout of keycaps is generated from the master
X * keycaps table.
X */
Xstatic char *keycaps[] =
X{
X#include "keycaps.h"
X};
X
X/*
X * Defaults tables -- regen defaults.h with keybind -c output if the system
X * defaults ever change. Be sure to do this *before* you let vtlmgr run!
X */
X#include "kdefaults.h"
X
Xstatic triple specvals[] =
X/* note: the second-column token have to match up with the lexical analyzer */
X{
X    K_NOP,    "nop",	"NOP",	/* Keys with no function */
X    K_LSH,    "lshft",	"LSH",	/* Left shift */
X    K_RSH,    "rshft",	"RSH",	/* Right shift */
X    K_CLK,    "clock",	"CLK",	/* Caps lock */
X    K_NLK,    "nlock",	"NLK",	/* Num lock */
X    K_SLK,    "slock",	"SLK",	/* Scroll lock */
X    K_ALT,    "alt",	"ALT",	/* Alt */
X    K_BTAB,   "btab",	"BTAB",	/* Back tab */
X    K_CTL,    "ctl",	"CTL",	/* Control */
X    K_LAL,    "lalt",	"LAL",	/* Left alt */
X    K_RAL,    "ralt",	"RAL",	/* Right alt */
X    K_LCT,    "lctrl",	"LCT",	/* Left control */
X    K_RCT,    "rctrl",	"RCT",	/* Right control */
X    K_SRQ,    "sysreq",	"SRQ",	/* System request */
X    K_BRK,    "break",	"BRK",	/* Break */
X    K_ESN,    "escn",	"ESN",	/* <ESC> N <unalt'd value> sequence */
X    K_ESO,    "esco",	"ESO",	/* <ESC> O <unalt'd value> sequence */
X    K_ESL,    "escl",	"ESL",	/* <ESC> L <unalt'd value> sequence */
X    K_RBT,    "reboot",	"RBT",	/* Reboot system */
X    K_DBG,    "debug",	"DBG",	/* Invoke debugger */
X    K_NEXT,    "next",	"NEXT",	/* Next virtual terminal */
X    K_PREV,    "prev",	"PREV",	/* Previous virtual terminal */
X    K_FRCNEXT,    "frcnext",    "FRCNEXT",
X    K_FRCPREV,    "frcprev",    "FRCPREV",
X    -1
X};
X
X#ifdef REGEN
X/*
X * This enables us to regenerate the defaults
X */
Xstatic void cdump_keymap()
X{
X    int	j;
X
X    static char *mascii[] =		/* use Microsoft's IBM-style NL/HT */
X    {
X	"NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
X	"BS",  "HT",  "NL",  "VT",  "FF",  "CR",  "SO",  "SI", 
X	"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
X	"CAN", "EM",  "SUB", "ESC", "FS",  "GS",  "RS",  "US",
X    };
X
X    struct key_t *kp;
X
X    (void) printf("static keymap_t keydefaults[] = \n{\n    %d,\n    {\n",
X		  kbd.keymap.n_keys);
X
X    for (kp = &(kbd.keymap.key[0]); kp < &(kbd.keymap.key[kbd.keymap.n_keys]); kp++)
X    {
X	char	repbuf[10];
X
X	(void) printf("/*%03d*/{{", kp - &(kbd.keymap.key[0]));
X	for (j = 0; j < NUM_STATES; j++)
X	{
X	    int	c = kp->map[j];
X
X	    if (PSPECIAL(kp, j))
X	    {
X		triple *sp;
X	
X		for (sp = specvals; sp->val != -1; sp++)
X		    if (sp->val == c)
X		    {
X			(void) strcpy(repbuf, "K_");
X			(void) strcat(repbuf, sp->mname);
X			break;
X		    }
X		if (sp->val == -1)
X		    if (IS_FUNKEY(c))
X			(void) sprintf(repbuf, "F(%d)", c - K_FUNF + 1);
X		    else if (IS_VTKEY(c))
X			(void) sprintf(repbuf, "VTK(%d)", c - K_VTF + 1);
X		    else if (IS_MGRKEY(c))
X			(void) sprintf(repbuf, "MGR(%d)", c - K_MGRF + 1);
X		    else if (IS_PFXKEY(c))
X			(void) sprintf(repbuf, "PFX(%d)", c - K_PFXF + 1);
X		    else
X			(void) sprintf(repbuf, "%d", c);
X	    }
X	    else
X	    {
X		int alt = (c & 0x80);
X
X		if (alt)
X		{
X		    (void) strcpy(repbuf, "M(");
X		    c &= 0x7F;
X		}
X		else
X		    (void) strcpy(repbuf, "");
X		if (isprint(c))
X		{
X		    if (c == '\'')
X			(void) strcat(repbuf, "'\\''");
X		    else if (c == '\\')
X			(void) strcat(repbuf, "'\\\\'");
X		    else
X			(void) sprintf(repbuf + strlen(repbuf), "'%c'", c);
X		}
X		else if (c == A_DEL)
X		    (void) strcat(repbuf, "A_DEL");
X		else if (iscntrl(c))
X		{
X		    (void) strcat(repbuf, "A_");
X		    (void) strcat(repbuf, mascii[c]);
X		}
X		if (alt)
X		    (void) strcat(repbuf + strlen(repbuf), ")");
X	    }
X
X	    if (j < NUM_STATES - 1)
X		(void) strcat(repbuf + strlen(repbuf), ",");
X	    (void) printf("%-7s", repbuf);
X	}
X	(void) printf("}, 0x%02x,0x%02x},\n", kp->spcl, kp->flgs);
X    }
X    (void) printf("    }\n};\n\n");
X
X    (void) printf("static char *stringdefaults[] =\n{\n");
X    for (j = 0; j < NSTRKEYS; j++)
X    {
X	register char *cp;
X
X	(void) printf("    \"");
X	for (cp = funkeys[j]; *cp; cp++)
X	    if (isprint(*cp))
X		(void) putchar(*cp);
X	    else
X		(void) printf("\\%03o", *cp);
X	(void) printf("\",\n");
X    }
X    (void) printf("};\n");
X}
X#endif /* REGEN */
X
X/*
X * Here are the dump functions for human use. Each of these may be
X * called by YACC productions, all are called by dump_all() below.
X */
X
Xvoid list_shift(flag, leader)
Xint flag;
Xchar *leader;
X{
X    struct key_t *kp;
X
X    for (kp = kbd.keymap.key; kp < &(kbd.keymap.key[kbd.keymap.n_keys]); kp++)
X	if (kp[0].flgs & flag)
X	    break;
X
X    (void) printf("%s enabled\t", leader);
X    if (kp >= kbd.keymap.key + kbd.keymap.n_keys)
X    {
X	(void) printf("# nowhere\n");
X	return;
X    }
X    else
X	(void) printf("%s", keycaps[kp - kbd.keymap.key]);
X
X    kbd.keymap.key[NUM_KEYS].flgs = ~kbd.keymap.key[NUM_KEYS - 1].flgs;
X    for (++kp ; kp <= kbd.keymap.key + kbd.keymap.n_keys; kp++)
X	if ((kp[0].flgs & flag) != (kp[-1].flgs & flag))
X	    if (kp[0].flgs & flag)
X	    {
X		if (kp < kbd.keymap.key + NUM_KEYS)
X		    (void) printf(" %s", keycaps[kp - kbd.keymap.key]); 
X	    }
X    	    else
X		(void) printf(" - %s", keycaps[kp - kbd.keymap.key - 1]); 
X    (void) putchar('\n');
X}
X
Xvoid dump_keymap(lower, upper)
Xint lower, upper;
X{
X    int i;
X
X    static char *ascii[] =		/* use common names */
X    {
X	"nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
X	"bs",  "tab",  "lf",  "vt",  "ff",  "cr",  "so",  "si", 
X	"dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
X	"can", "em",  "sub", "esc", "fs",  "gs",  "rs",  "us",
X    };
X    struct key_t *kp;
X
X    for (kp = &(kbd.keymap.key[lower]); kp <= kbd.keymap.key + upper; kp++)
X    {
X	char	repbuf[10];
X	int	j;
X
X	(void) printf("%-12s  ", keycaps[kp - &(kbd.keymap.key[0])]);
X
X	for (j = 0; j < NUM_STATES; j++)
X	{
X	    int	c = kp->map[j];
X
X	    if (PSPECIAL(kp, j))
X	    {
X		triple *sp;
X	
X		for (sp = specvals; sp->val != -1; sp++)
X		    if (sp->val == c)
X		    {
X			(void) strcpy(repbuf, sp->aname);
X			break;
X		    }
X		if (sp->val == -1)
X		    if (IS_FUNKEY(c))
X			(void) sprintf(repbuf, "fkey%d", c - K_FUNF + 1);
X		    else if (IS_VTKEY(c))
X			(void) sprintf(repbuf, "vt%d", c - K_VTF + 1);
X		    else if (IS_MGRKEY(c))
X			(void) sprintf(repbuf, "mgr%d", c - K_MGRF + 1);
X		    else if (IS_PFXKEY(c))
X			(void) sprintf(repbuf, "pfx%d", c - K_PFXF + 1);
X		    else
X			(void) sprintf(repbuf, "%d", c);
X	    }
X	    else
X	    {
X		int alt = (c & META);
X
X		if (alt)
X		    c = (c & ~META);
X		if (isprint(c))
X		{
X		    if (alt)
X			(void) strcpy(repbuf, "'!");
X		    else
X			(void) strcpy(repbuf, "'");
X		    if (c == '\'')
X			(void) strcat(repbuf, "\\''");
X		    else if (c == '\\')
X			(void) strcat(repbuf, "\\\\'");
X		    else
X			(void) sprintf(repbuf+strlen(repbuf), "%c'", c);
X		}
X		else if (iscntrl(c) || c == A_DEL)
X		{
X		    if (alt)
X			(void) strcpy(repbuf, "!");
X		    else
X			(void) strcpy(repbuf, "");
X		    if (c == A_DEL)
X			(void) strcat(repbuf, "del");
X		    else
X			(void) strcat(repbuf, ascii[c]);
X		}
X	    }
X
X	    (void) printf("%-8s", repbuf);
X	}
X	(void) putchar('\n');
X    }
X}
X
Xvoid dump_funkeys(lower, upper)
Xint lower, upper;  
X{
X    int i;
X
X    for (i = lower; i <= upper; i++)
X	if (strlen(funkeys[i - 1]))
X	{
X	    (void) printf("fkey%d = \"", i);
X	    dump_string(funkeys[i-1]);
X	    (void) putchar('"');
X	    (void) putchar('\n');
X	}
X}
X
Xstatic void dump_all()
X{
X    time_t	now = time((time_t *)0);
X    int i;
X
X    (void) printf("#\n# Key bindings:\n#\n");
X    (void) printf(
X"#                                     Ctrl             Alt    Alt    Alt-Ctrl\n");
X    (void) printf(
X"#Code         Normal  Shift   Ctrl    Shift   Alt     Shift   Ctrl    Shift\n");
X    (void) printf(
X"#--------------------------------------------------------------------------\n");
X
X    dump_keymap(0, kbd.keymap.n_keys - 1);
X
X    (void) printf("#\n# Shift keys:\n#\n");
X    list_shift(KMF_CLOCK, "capslock");
X    list_shift(KMF_NLOCK, "numlock ");
X
X    (void) printf("#\n# Function keys:\n#\n");
X    dump_funkeys(1, NSTRKEYS);
X}
X
X/*
X * Functions for meta-key enabling
X */
X
Xint weak_binding(p, state)
X/* test if key state has a `weak binding', not char or important special */
Xstruct key_t *p;
Xint state;
X{
X    if (!PSPECIAL(p, state))
X	return(0);
X    else
X    {
X	register unchar val = p->map[state];
X
X	return(val == K_NOP || val == K_ESN || val == K_ESO || val == K_ESL);
X    }
X}
X
Xvoid enable_alt()
X{
X    struct key_t *kp;
X
X    /* for each non-special key that is ASCII printable in base state */
X    for (kp = &(kbd.keymap.key[0]); kp < &(kbd.keymap.key[kbd.keymap.n_keys]); kp++)
X	if (!PSPECIAL(kp, NORMAL) && isprint(kp->map[NORMAL]))
X	{
X	    if (weak_binding(kp, ALTED))
X	    {
X		kp->map[ALTED] 	= (kp->map[NORMAL] | META);
X		kp->spcl &=~ 0x08;
X	    }
X	    if (weak_binding(kp, ALTSHF))
X	    {
X		kp->map[ALTSHF]	= (kp->map[SHIFT] | META);
X		kp->spcl &=~ 0x04;
X	    }
X	    if (weak_binding(kp, ALTCTL))
X	    {
X		kp->map[ALTCTL]	= (kp->map[CTRL] | META);
X		kp->spcl &=~ 0x02;
X	    }
X	    if (weak_binding(kp, ALTSHFCTL))
X	    {
X		kp->map[ALTSHFCTL] = (kp->map[SHFCTL] | META);
X		kp->spcl &=~ 0x01;
X	    }
X	}
X    mapmods++;
X}
X
X/*
X * Other major functions. If it isn't static, it's because YACC may call it.
X */
X
Xvoid restore_defaults()
X{
X    int	i;
X
X    (void) memcpy(&kbd.keymap, &keydefaults, sizeof(keymap_t));
X
X    for (i = 0; i < NSTRKEYS; i++)
X	(void) strcpy(funkeys[i], stringdefaults[i]);
X    mapmods++;
X    
X}
X
Xint setkey(scancode, indx, kfunc)
Xint scancode;	/* scancode */
Xint indx;	/* map index */
Xint kfunc;	/* key function */
X{
X    struct key_t	*kp = kbd.keymap.key + scancode;
X#ifdef DEBUG
X    (void) printf("keybind: code %d/state %d becomes %s%d\n",
X		  scancode, indx,
X		  (kfunc >= NUM_KEYS ? "special ": "character "),
X		  kfunc - (kfunc >= NUM_KEYS) * NUM_KEYS);
X#endif /* DEBUG */
X
X    if (kfunc < NUM_KEYS)
X	kp->spcl &=~ (0x80>>indx);
X    else
X    {
X	kp->spcl |= (0x80>>indx);
X	kfunc -= NUM_KEYS;
X    }
X    kp->map[indx] = kfunc;
X    mapmods++;
X}
X
Xint setstring(fnkey, str)
Xint fnkey;
Xchar *str;
X{
X    extern char *malloc();
X    char *cp, *tp;
X
X#ifdef DEBUG
X    (void) printf("keybind: binding function key %d to \"", fnkey);
X    dump_string(str);
X    (void) putchar('"');
X    (void) putchar('\n');
X#endif /* DEBUG */
X
X    (void) strncpy(funkeys[fnkey], str, MAXFK);
X    stringmods++;
X}
X
Xvoid clear_strings()
X{
X    (void) memset(funkeys, '\0', (MAXFK + 1) * NSTRKEYS);
X}
X
Xvoid do_changes()
X/* execute all pending changes to key and string maps */
X{
X    if (mapmods)
X	if (ioctl(ttyfd, PIO_KEYMAP, &kbd.keymap) == -1)
X	    perror("keybind: PIO_KEYMAP ioctl failed");
X
X    if (stringmods)
X    {
X	int		i;
X	unchar		*sp = kbd.strmap;
X	
X	for (i = 0; i < NSTRKEYS; i++)
X	{
X	    if (sp + strlen(sp) + 1 - kbd.strmap > MAXSTRINGS)
X	    {
X		(void) fprintf(stderr,
X			       "keybind: out of string space at fkey %d\n", i);
X		return;
X	    }
X	    (void) strcpy(sp, funkeys[i]);
X	    sp += strlen(sp) + 1;
X	}
X	    
X	if (ioctl(ttyfd, PIO_STRMAP, kbd.strmap) == -1)
X	    perror("keybind: PIO_STRMAP ioctl failed");
X    }
X}
X
X/*
X * The main sequence. All this does is the keymap read, a dispatch on options,
X * and the keymap write.
X */
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X    int i, c, inputcount = 0;
X    unchar *cp;
X    char ofname[BUFSIZ];
X
X    if ((ttyfd = open("/dev/tty", O_RDONLY)) < 0
X    		&& (ttyfd = open("/dev/console", O_RDONLY)) < 0)
X    {
X	perror("keybind: tty open failed!");
X	exit(1);
X    }
X
X    if (ioctl(ttyfd, GIO_KEYMAP, &kbd.keymap) == -1)
X    {
X	perror("keybind: GIO_KEYMAP ioctl failed");
X	exit(1);
X    }
X
X    if (ioctl(ttyfd, GIO_STRMAP, kbd.strmap) == -1)
X    {
X	perror("keybind: GIO_STRMAP ioctl failed");
X	exit(1);
X    }
X    for (i = 0, cp = kbd.strmap; *cp; cp += strlen(cp) + 1)
X	(void) strcpy(funkeys[i++], cp);
X
X    for (++argv, --argc; argc; ++argv, --argc)
X    {
X	if (**argv == '-' && argv[0][1])
X	{
X	    while (*++*argv != '\0')
X		switch(**argv)
X		{
X		case 'm': enable_alt(); break;
X#ifdef REGEN
X		case 'c': cdump_keymap(); break;
X#endif /* REGEN */
X		case 'd': dump_all(); break;
X		case 'r': restore_defaults(); inputcount++; break;
X		case 'o':
X		    (void)strcpy(ofname, *++argv);
X		    argc--;
X		    goto nextarg;	/* ick... */
X		default:
X		    (void) fputs("usage: keymap [-mdrv] [-] [files...]\n",
X				 stderr);
X		    exit(1);
X		}
X	    continue;
X	}
X	else
X	{
X	    FILE	*fp;
X
X	    if (**argv == '-')
X	    {
X		inputcount++;
X		yyin = stdin;
X		yyparse();
X	    }
X	    else if ((fp = fopen(*argv, "r")) == (FILE *)NULL)
X	    {
X		perror(*argv);
X		exit(1);
X	    }
X	    else	/* O.K., it's a valid input source */
X	    {
X		int	c = fgetc(fp);	/* peek at first character */
X
X		inputcount++;
X		(void) ungetc(c, fp);
X
X		/* if it looks like ascii, run source through interpreter */
X		if (isprint(c))
X		{
X		    yyin = fp;
X		    yyparse();
X		}
X		else if (fread(&kbd,sizeof(kbd_t),1,fp)!=1 || kbd.magic!=KBDHDMAGIC)
X		{
X		    (void) fprintf(stderr, "keybind: garbled map dump file\n");
X		    exit(1);
X		}
X		else		/* we have a valid dump file */
X		{
X		    mapmods++;
X		    stringmods++;
X
X		    /* massage the loaded fundefs into something useful */
X		    for (i = 0, cp = kbd.strmap; *cp; cp += strlen(cp) + 1)
X			(void) strcpy(funkeys[i++], cp);
X		}
X	    }
X	}
X    nextarg:;
X    }
X
X    /* if no file or - arguments, process stdin once */
X    if (inputcount == 0)
X    {
X	yyin = stdin;
X	yyparse();
X    }
X    
X    if (ofname[0] == '\0')
X	do_changes();
X    else
X    {
X	FILE	*ofp;
X
X	ofp = fopen(ofname, "w");
X	(void) fwrite(&kbd, sizeof(kbd_t), 1, ofp);
X	(void) fclose(ofp);
X    }
X
X    (void) close(ttyfd);
X    exit(0);    
X}
X
X/* keybind.c ends here */
END-of-keybind.c
echo file: kgram.y
sed 's/^X//' >kgram.y << 'END-of-kgram.y'
X/*
X * kgram.y -- YACC grammar for key-map interpreter
X *
X *	@(#)kgram.y	1.2
X *
X * Copyright 1989 by Eric S. Raymond (eric@snark.uu.net), all rights reserved
X * You may use, modify or redistribute this code freely, but do not delete
X * this notice. Check with me before you make money with it.
X */
X%{
X/*LINTLIBRARY*/
X#ifndef lint
Xstatic char *sccsid = "@(#)kgram.y	1.2";
X#endif /* lint */
X
X#include <stdio.h>
X#include <string.h>
X#include <sys/types.h>
X#include <sys/at_ansi.h>
X#include <sys/kd.h>
X#include "keybind.h"
X
Xextern kbd_t	kbd;
Xextern char yytext[];
X
Xextern void enable_alt(), list_shift(), restore_defaults();
Xextern void dump_keymap(), dump_funkeys();
Xextern void set_key(), set_string(), clear_strings();
Xextern void do_changes();
X
Xstatic int	prefval;
Xstatic int	codes1[NUM_KEYS];
Xstatic int	ccount;
Xstatic int	codes2[NUM_KEYS];
X
Xstatic void do_help();
X%}   
X
X%start map
X
X%token SCANCODE CHARKEY FUNKEY SPECIAL
X%token PREFIX STRING
X%token SHIFTER ENABLED DISABLED
X%token META RESTORE DUMP SHIFTS FUNKEYS CLEARSTRINGS EXECUTE HELP
X%token ASSIGN DASH
X%token NEWLINE	10
X%token LEXERR
X
X%%	/* beginning of rules section */
X
X/* a map description consists of a sequence of commands */
Xmap	:    /* EMPTY */
X	|    map command NEWLINE
X	|    map error NEWLINE
X		{yyerrok;}
X	|    map NEWLINE
X	;
X
Xcommand	:    SCANCODE funcs
X		{
X		    int i;
X
X		    if (ccount > NUM_STATES)
X			yyerror("too many functions in scancode spec");
X		    else
X			for (i = 0; i < ccount; i++)
X			    if (codes1[i] >= 0)
X				setkey($1, i, codes1[i]);
X		}
X
X	|    SCANCODE ASSIGN func
X		{setkey($1, 0, $3);}
X	|    PREFIX SCANCODE ASSIGN func
X		{setkey($2, $1, $4);}
X	|    PREFIX PREFIX SCANCODE ASSIGN func
X		{setkey($3, ($1 | $2), $5);}
X	|    PREFIX PREFIX PREFIX SCANCODE ASSIGN func
X		{setkey($4, ($1 | $2 | $3), $6);}
X
X	|    FUNKEY ASSIGN STRING
X    		{setstring($1 - K_FUNF, yytext);}
X	|    SHIFTER ENABLED ranges
X		{
X		    int i, j;
X
X		    if (ccount == 0)
X		    {
X			codes1[0] = 0;
X			codes2[0] = NUM_KEYS - 1;
X			ccount++;
X		    }
X		    for (i = 0; i < ccount; i++)
X			for (j = codes1[i]; j <= codes2[i]; j++)
X			    kbd.keymap.key[j].flgs |= $1;
X		}
X
X	|    SHIFTER DISABLED ranges
X		{
X		    int i, j;
X
X		    if (ccount == 0)
X		    {
X			codes1[0] = 0;
X			codes2[0] = NUM_KEYS - 1;
X			ccount++;
X		    }
X		    for (i = 0; i < ccount; i++)
X			for (j = codes1[i]; j <= codes2[i]; j++)
X			    kbd.keymap.key[j].flgs &=~ $1;
X		}
X	|    DUMP ranges
X		{
X		    int i, j;
X
X		    if (ccount == 0)
X			dump_keymap(0, kbd.keymap.n_keys - 1);
X		    else
X			for (i = 0; i < ccount; i++)
X			    dump_keymap(codes1[i], codes2[i]);
X		}
X	|    FUNKEYS franges
X		{
X		    int i, j;
X
X		    if (ccount == 0)
X			dump_funkeys(1, NSTRKEYS);
X		    else
X			for (i = 0; i < ccount; i++)
X			    dump_funkeys(codes1[i]-K_FUNF+1,codes2[i]-K_FUNF+1);
X		}
X	|    SHIFTER
X		{
X		    if ($1 == KMF_CLOCK)
X			list_shift(KMF_CLOCK, "capslock");
X		    else
X			list_shift(KMF_NLOCK, "numlock ");
X		}
X	|    META
X		{enable_alt();}
X	|    RESTORE
X		{restore_defaults();}
X	|    CLEARSTRINGS
X		{clear_strings();}
X	|    EXECUTE
X		{do_changes();};
X	|    HELP
X		{do_help();};
X	;
X
Xranges	:    /* EMPTY */
X		{ccount = 0;}
X	|    ranges SCANCODE DASH SCANCODE
X		{codes1[ccount] = $2; codes2[ccount] = $4; ccount++;}
X	|    ranges SCANCODE
X		{codes1[ccount] = codes2[ccount] = $2; ccount++;}
X	;
X
Xfranges	:    /* EMPTY */
X		{ccount = 0;}
X	|    franges FUNKEY DASH FUNKEY
X		{codes1[ccount] = $2; codes2[ccount] = $4; ccount++;}
X	|    franges FUNKEY
X		{codes1[ccount] = codes2[ccount] = $2; ccount++;}
X	;
X
Xfunc	:    CHARKEY		{$$ = ($1 & 0xff);}
X	|    FUNKEY		{$$ = ($1 & 0xff);}
X	|    SPECIAL		{$$ = $1 + NUM_KEYS;}
X	;
X
Xfuncs	:    func
X		{ccount = 0; codes1[ccount++] = $1;}
X	|    funcs func
X		{codes1[ccount++] = $2;}
X	|    funcs DASH
X		{codes1[ccount++] = -1;}
X	|    /* EMPTY */
X		{(void)yyerror("expected a list of function codes"); YYERROR;}
X	;
X%%
X
Xint yyerror(message)
Xchar	*message;
X{
X    (void) fprintf(stderr, "keybind: %s\n", message);
X}
X
Xvoid do_help()
X{
X#define P(s)	(void) printf(s)
XP("Keybind commands are:\n\n");
X
XP("@scancode [func...]              -- assign functions to scancode\n");
XP("[prefix] @scancode = [func]      -- assign to key/state pair\n\n");
X
XP("fkey<nn> = \"string\"              -- load string key\n\n");
X
XP("cl[earstrings]                   -- clear the string table\n");
XP("capslock di[sabled] [range...]   -- disable capslock on chars\n");
XP("numlock di[sabled] [range...]    -- disable numlock on chars\n");
XP("du[mp] [range...]                -- show functions of given keys\n");
XP("[ca]pslock en[abled] [range...]  -- enable capslock on chars\n");
XP("[nu]mlock en[abled] [range...]   -- enable numlock on chars\n");
XP("ex[ecute]                        -- write changes to the driver\n");
XP("fu[nkeys] [range...]             -- show bindings of string keys\n");
XP("he[lp]                           -- display this message\n");
XP("me[ta]                           -- enable the Alt key as meta\n");
XP("re[store]                        -- restore defaults\n");
XP("ca[pslock]                       -- show keys capslock affects\n");
XP("nu[mlock]                        -- show keys numlock affects\n\n");
X
XP("Ranges may be a character literal or two dash-separated char literals.\n");
XP("Functions may be char literals or one of the named special functions\n");
XP("documented in keyboard(7)\n");
X}
X
X/* kgram.y ends here */
END-of-kgram.y
echo file: klex1.l
sed 's/^X//' >klex1.l << 'END-of-klex1.l'
X%{
X/*
X * klex.l -- lexical analyzer for the keybind mini-language interpreter
X *
X *	@(#)klex1.l	1.2
X *
X * Copyright 1989 by Eric S. Raymond (eric@snark.uu.net), all rights reserved
X * You may use, modify or redistribute this code freely, but do not delete
X * this notice. Check with me before you make money with it.
X */
X/*LINTLIBRARY*/
X#ifndef lint
Xstatic char *sccsid = "@(#)klex1.l	1.2";
X#endif /* lint */
X
X#include <sys/types.h>
X#include <sys/at_ansi.h>
X#include <sys/kd.h>
X#include <sys/ascii.h>
X#include <string.h>
X#include <ctype.h>
X#include "keybind.h"
X#include "y.tab.h"
X
Xextern yylval;	/* used to pass token values to YACC */
X
Xstatic int yytokno = 0;
Xstatic int smashcase = 1;
Xstatic int interactive = 0;
X
X#undef input
Xint input()
X{
X    static int doprompt;
X    int c;
X
X    if (doprompt-- == 1)
X	(void) fputs("*", stdout);
X
X    if ((c = getc(yyin)) == '\n')
X    {
X	yylineno++;
X	if (interactive)
X	    doprompt = 1;
X    }
X
X    if (feof(yyin))
X	return(0);
X    else if (smashcase && isupper(c))    
X	return(tolower(c));
X    else
X	return(c);
X}
X
X#undef unput
X#define unput(c)	ungetc(c, yyin)
X
Xextern void dump_string();
Xstatic void getstring();
X%}
X
X%e	1700
X%p	3700
X%n	500
X%k	50
X%a	900
X%o	800
X
X%%
X
Xclearstrings|cl	{yytokno++; return(CLEARSTRINGS);}
Xdisabled|di	{yytokno++; return(DISABLED);}
Xdump|du		{yytokno++; return(DUMP);}
Xenabled|en	{yytokno++; return(ENABLED);}
Xexecute|ex	{yytokno++; return(EXECUTE);}
Xfunkeys|fu	{yytokno++; return(FUNKEYS);}
Xhelp|he		{yytokno++; interactive++; return(HELP);}
Xmeta|me		{yytokno++; return(META);}
Xrestore|re	{yytokno++; return(RESTORE);}
X
Xshift-?		{yylval = SHIFTED; yytokno++; return(PREFIX);}
Xctrl-?		{yylval = CTRLED; yytokno++; return(PREFIX);}
Xalt-?		{yylval = ALTED; yytokno++; return(PREFIX);}
X
Xcapslock|ca	{yylval = KMF_CLOCK; yytokno++; return(SHIFTER);}
Xshiftlock|sh	{yylval = KMF_CLOCK; yytokno++; return(SHIFTER);}
Xnumlock|nu	{yylval = KMF_NLOCK; yytokno++; return(SHIFTER);}
X
X\"		{getstring(yytext, '"'); yytokno++; return(STRING);}
X'		{
X		    getstring(yytext, '\'');
X		    if (strlen(yytext) == 1)
X		    {
X			yylval = yytext[0];
X			yytokno++;
X			return(CHARKEY);
X		    }
X	    	    else
X		    {
X			(void) fprintf(stderr,
X			    "keybind: bad character syntax, line %d token %d\n",
X			     yylineno + 1, yytokno);
X			interactive--;
X			while (input() != '\n')
X			    continue;
X			interactive++;
X			return(LEXERR);
X		    }
X		}
X
X@[0-9][0-9][0-9]	{yylval=atoi(yytext+1); yytokno++; return(SCANCODE);}
END-of-klex1.l
echo file: klex2.l
sed 's/^X//' >klex2.l << 'END-of-klex2.l'
X@.		{
X		    (void) fprintf(stderr,
X			"keybind: bad scan-code specifier, line %d, token %d\n",
X			yylineno, yytokno);
X			interactive--;
X			while (input() != '\n')
X			    continue;
X			interactive++;
X		    return(LEXERR);
X		}
X
Xnul		{yylval = A_NUL; yytokno++; return(CHARKEY);}
Xsoh		{yylval = A_SOH; yytokno++; return(CHARKEY);}
Xstx		{yylval = A_STX; yytokno++; return(CHARKEY);}
Xetx		{yylval = A_ETX; yytokno++; return(CHARKEY);}
Xeot		{yylval = A_EOT; yytokno++; return(CHARKEY);}
Xenq		{yylval = A_ENQ; yytokno++; return(CHARKEY);}
Xack		{yylval = A_ACK; yytokno++; return(CHARKEY);}
Xbel		{yylval = A_BEL; yytokno++; return(CHARKEY);}
Xbs		{yylval = A_BS; yytokno++; return(CHARKEY);}
Xht		{yylval = A_HT; yytokno++; return(CHARKEY);}
Xtab		{yylval = A_HT; yytokno++; return(CHARKEY);}
Xnl		{yylval = A_NL; yytokno++; return(CHARKEY);}
Xlf		{yylval = A_NL; yytokno++; return(CHARKEY);}
Xvt		{yylval = A_VT; yytokno++; return(CHARKEY);}
Xff		{yylval = A_FF; yytokno++; return(CHARKEY);}
Xcr		{yylval = A_CR; yytokno++; return(CHARKEY);}
Xso		{yylval = A_SO; yytokno++; return(CHARKEY);}
Xsi		{yylval = A_SI; yytokno++; return(CHARKEY);}
Xdle		{yylval = A_DLE; yytokno++; return(CHARKEY);}
Xdc1		{yylval = A_DC1; yytokno++; return(CHARKEY);}
Xxon		{yylval = A_DC1; yytokno++; return(CHARKEY);}
Xdc2		{yylval = A_DC2; yytokno++; return(CHARKEY);}
Xdc3		{yylval = A_DC3; yytokno++; return(CHARKEY);}
Xxoff		{yylval = A_DC3; yytokno++; return(CHARKEY);}
Xdc4		{yylval = A_DC4; yytokno++; return(CHARKEY);}
Xnak		{yylval = A_NAK; yytokno++; return(CHARKEY);}
Xsyn		{yylval = A_SYN; yytokno++; return(CHARKEY);}
Xetb		{yylval = A_ETB; yytokno++; return(CHARKEY);}
Xcan		{yylval = A_CAN; yytokno++; return(CHARKEY);}
Xem		{yylval = A_EM; yytokno++; return(CHARKEY);}
Xsub		{yylval = A_SUB; yytokno++; return(CHARKEY);}
Xesc		{yylval = A_ESC; yytokno++; return(CHARKEY);}
Xfs		{yylval = A_FS; yytokno++; return(CHARKEY);}
Xgs		{yylval = A_GS; yytokno++; return(CHARKEY);}
Xrs		{yylval = A_RS; yytokno++; return(CHARKEY);}
Xus		{yylval = A_US; yytokno++; return(CHARKEY);}
Xdel		{yylval = A_DEL; yytokno++; return(CHARKEY);}
Xcsi		{yylval = A_CSI; yytokno++; return(CHARKEY);}
X
Xnop		{yylval = K_NOP; yytokno++; return(SPECIAL);}
Xlshift		{yylval = K_LSH; yytokno++; return(SPECIAL);}
Xrshift		{yylval = K_RSH; yytokno++; return(SPECIAL);}
Xclock		{yylval = K_CLK; yytokno++; return(SPECIAL);}
Xnlock		{yylval = K_NLK; yytokno++; return(SPECIAL);}
Xslock		{yylval = K_SLK; yytokno++; return(SPECIAL);}
Xalt		{yylval = K_ALT; yytokno++; return(SPECIAL);}
Xbtab		{yylval = K_BTAB; yytokno++; return(SPECIAL);}
Xctrl		{yylval = K_CTL; yytokno++; return(SPECIAL);}
Xlalt		{yylval = K_LAL; yytokno++; return(SPECIAL);}
Xralt		{yylval = K_RAL; yytokno++; return(SPECIAL);}
Xlctrl		{yylval = K_LCT; yytokno++; return(SPECIAL);}
Xrctrl		{yylval = K_RCT; yytokno++; return(SPECIAL);}
X
Xfkey[0-9][0-9]?	{yylval = K_FUNF+atoi(yytext+4)-1; yytokno++; return(FUNKEY);}
X
Xsysreq		{yylval = K_SRQ; yytokno++; return(SPECIAL);}
Xbrk		{yylval = K_BRK; yytokno++; return(SPECIAL);}
Xescn		{yylval = K_ESN; yytokno++; return(SPECIAL);}
Xesco		{yylval = K_ESO; yytokno++; return(SPECIAL);}
Xescl		{yylval = K_ESL; yytokno++; return(SPECIAL);}
Xrboot		{yylval = K_RBT; yytokno++; return(SPECIAL);}
Xdebug		{yylval = K_DBG; yytokno++; return(SPECIAL);}
Xnext		{yylval = K_NEXT; yytokno++; return(SPECIAL);}
Xprev		{yylval = K_PREV; yytokno++; return(SPECIAL);}
Xfnext		{yylval = K_FRCNEXT; yytokno++; return(SPECIAL);}
Xfprev		{yylval = K_FRCPREV; yytokno++; return(SPECIAL);}
X
Xvt[0-9][0-9]?	{yylval = K_VTF+atoi(yytext+2); yytokno++; return(SPECIAL);}
Xvtf		{yylval = K_VTF; yytokno++; return(SPECIAL);}
Xvtl		{yylval = K_VTL; yytokno++; return(SPECIAL);}
Xmgr[0-9][0-9]?	{yylval = K_MGRF+atoi(yytext+3); yytokno++; return(SPECIAL);}
Xmgrf		{yylval = K_MGRF; yytokno++; return(SPECIAL);}
Xmgrl		{yylval = K_MGRL; yytokno++; return(SPECIAL);}
Xpfx[0-9][0-9]?	{yylval = K_PFXF+atoi(yytext+3); yytokno++; return(SPECIAL);}
Xpfxf		{yylval = K_PFXF; yytokno++; return(SPECIAL);}
Xpfxl		{yylval = K_PFXL; yytokno++; return(SPECIAL);}
X
X"#"		{while (input() != '\n') continue; unput('\n');}
X
X[\n;]		{yytokno = 0; return(NEWLINE);}
X=		{yytokno++; return(ASSIGN);}
X-		{yytokno++; return(DASH);}
X[\ \t,]		;
X
X"?"		{yytokno++; interactive++; return(HELP);}
X
X.		{
X		    (void) fprintf(stderr,
X			    "keybind: bad char, line %d, after token %d = \"",
X			     yylineno, yytokno);
X		    dump_string(yytext);
X		    (void) fputs("\"\n", stdout);
X		    interactive--;
X		    while (input() != '\n')
X			continue;
X		    interactive++;
X		    return(LEXERR);
X		}
X
X%%
X/*
X * klex2.l -- lexical analyzer for keymap editor program, part 2
X *
X *	@(#)klex2.l	1.2
X *
X * Copyright 1989 by Eric S. Raymond (eric@snark.uu.net), all rights reserved
X * You may use, modify or redistribute this code freely, but do not delete
X * this notice. Check with me before you make money with it.
X */
X
Xstatic int yywrap()
X{
X    if (interactive)
X	(void) putchar('\n');
X    interactive = 0;
X    return(EOF);
X}
X
Xvoid getstring(buf, term)
Xchar	*buf, term;
X{
X    char *tp;
X    int c, cval;
X
X    smashcase = 0;
X    buf[0] = '\0';
X    for (tp = buf; (c = input()) != term && c != EOF; *tp++ = cval)
X    {
X	if (c == '\\')
X	{
X	    c = input();
X	    if (strchr("0123456789xX", c))
X	    {
X		char *dp, *hex = "0123456789abcdef";
X		int dcount = 0;
X
X		if (c == 'x' || c == 'X')
X		    while ((dp = strchr(hex, (c = input()))) && (dcount++ < 2))
X			cval = (cval * 16) + (dp - hex);
X		else if (c == '0')
X		    while (strchr("01234567", (c = input())) && (dcount++ < 3))
X			cval = (cval * 8) + (c - '0');
X		else
X		    while (strchr("0123456789", (c = input())) && (dcount++ < 3))
X			cval = (cval * 10) + (c - '0');
X		unput(c);
X	    }
X	    else		/* C-style character escapes */
X	    {
X		switch (c)
X		{
X		case '\\': cval = '\\'; break;
X		case 'e': cval = '\033'; break;
X		case 'n': cval = '\n'; break;
X		case 't': cval = '\t'; break;
X		case 'b': cval = '\b'; break;
X		case 'r': cval = '\r'; break;
X		case 'v': cval = '\v'; break;
X		default: cval = c;
X		}
X	    }
X	}
X	else if (c == '^')	/* control-character syntax */
X	    cval = (input() & 0x1f);
X	else if (c == '!')	/* alt-character syntax */
X	    cval = (input() | 0x80);
X	else
X	    cval = c;
X    }
X    *tp = '\0';
X    smashcase = 1;
X}
X
Xvoid dump_string(str)
Xchar *str;
X{
X    register char *cp;
X
X    for (cp = str; *cp; cp++)
X	if (isprint(*cp))
X	    (void) putchar(*cp);
X	else if (*cp == '"')
X	    (void) fputs("\\\"", stdout);
X	else if (*cp == '\b')
X	    (void) fputs("\\b", stdout);
X	else if (*cp == '\033')
X	    (void) fputs("\\e", stdout);
X	else if (*cp == '\n')
X	    (void) fputs("\\n", stdout);
X	else if (*cp == '\r')
X	    (void) fputs("\\r", stdout);
X	else if (*cp == '\t')
X	    (void) fputs("\\t", stdout);
X	else if (*cp == '\v')
X	    (void) fputs("\\v", stdout);
X	else
X	    (void) printf("\\x%02x", *cp);
X}
X
X#ifdef MAIN
Xint yylval;
X
Xmain()
X{
X    int class;
X
X    while ((class = yylex()) > 0)
X    {
X	if (class == NEWLINE)
X	    (void) fputs("NEWLINE\n", stdout);
X	else
X	    (void) printf("text \"%s\", class %d, value %d\n",
X						yytext, class, yylval);
X	yylval = 0;
X    }
X}
X
X#endif /* MAIN */
X
X/* klex.l ends here */
END-of-klex2.l
echo file: kdefaults.h
sed 's/^X//' >kdefaults.h << 'END-of-kdefaults.h'
X/*
X *	@(#)kdefaults.h	1.1
X *
X * Copyright 1989 by Eric S. Raymond (eric@snark.uu.net), all rights reserved
X * You may use, modify or redistribute this code freely, but do not delete
X * this notice. Check with me before you make money with it.
X */
Xstatic keymap_t keydefaults =
X{
X    128,
X    {
X/*000*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*001*/{{A_ESC, A_ESC, A_ESC, A_ESC, A_ESC, A_ESC, A_ESC, A_ESC  }, 0x00,0x00},
X/*002*/{{'1',   '!',   '1',   '1',   K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*003*/{{'2',   '@',   '2',   A_NUL, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*004*/{{'3',   '#',   '3',   '3',   K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*005*/{{'4',   '$',   '4',   '4',   K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*006*/{{'5',   '%',   '5',   '5',   K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*007*/{{'6',   '^',   '6',   A_RS,  K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*008*/{{'7',   '&',   '7',   '7',   K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*009*/{{'8',   '*',   '8',   '8',   K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*010*/{{'9',   '(',   '9',   '9',   K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*011*/{{'0',   ')',   '0',   '0',   K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*012*/{{'-',   '_',   '-',   A_US,  K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*013*/{{'=',   '+',   '=',   '=',   K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*014*/{{A_BS,  A_BS,  A_BS,  A_BS,  A_BS,  A_BS,  A_BS,  A_BS   }, 0x00,0x00},
X/*015*/{{A_HT,  A_GS,  A_HT,  A_GS,  A_HT,  A_GS,  A_HT,  A_GS   }, 0x00,0x00},
X/*016*/{{'q',   'Q',   A_DC1, A_DC1, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*017*/{{'w',   'W',   A_ETB, A_ETB, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*018*/{{'e',   'E',   A_ENQ, A_ENQ, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*019*/{{'r',   'R',   A_DC2, A_DC2, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*020*/{{'t',   'T',   A_DC4, A_DC4, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*021*/{{'y',   'Y',   A_EM,  A_EM,  K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*022*/{{'u',   'U',   A_NAK, A_NAK, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*023*/{{'i',   'I',   A_HT,  A_HT,  K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*024*/{{'o',   'O',   A_SI,  A_SI,  K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*025*/{{'p',   'P',   A_DLE, A_DLE, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*026*/{{'[',   '{',   A_ESC, K_NOP, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x1f,0x00},
X/*027*/{{']',   '}',   A_GS,  K_NOP, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x1f,0x00},
X/*028*/{{A_CR,  A_CR,  A_CR,  A_CR,  A_CR,  A_CR,  A_CR,  A_CR   }, 0x00,0x00},
X/*029*/{{K_LCT, K_LCT, K_LCT, K_LCT, K_LCT, K_LCT, K_LCT, K_LCT  }, 0xff,0x00},
X/*030*/{{'a',   'A',   A_SOH, A_SOH, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*031*/{{'s',   'S',   A_DC3, A_DC3, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*032*/{{'d',   'D',   A_EOT, A_EOT, K_ESN, K_ESN, K_DBG, K_NOP  }, 0x0f,0x01},
X/*033*/{{'f',   'F',   A_ACK, A_ACK, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*034*/{{'g',   'G',   A_BEL, A_BEL, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*035*/{{'h',   'H',   A_BS,  A_BS,  K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*036*/{{'j',   'J',   A_NL,  A_NL,  K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*037*/{{'k',   'K',   A_VT,  A_VT,  K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*038*/{{'l',   'L',   A_FF,  A_FF,  K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*039*/{{';',   ':',   ';',   ':',   K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*040*/{{'\'',  '"',   '\'',  '"',   K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*041*/{{'`',   '~',   '`',   '~',   K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*042*/{{K_LSH, K_LSH, K_LSH, K_LSH, K_LSH, K_LSH, K_LSH, K_LSH  }, 0xff,0x00},
X/*043*/{{'\\',  '|',   A_FS,  '|',   K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*044*/{{'z',   'Z',   A_SUB, A_SUB, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*045*/{{'x',   'X',   A_CAN, A_CAN, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*046*/{{'c',   'C',   A_ETX, A_ETX, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*047*/{{'v',   'V',   A_SYN, A_SYN, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*048*/{{'b',   'B',   A_STX, A_STX, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*049*/{{'n',   'N',   A_SO,  A_SO,  K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*050*/{{'m',   'M',   A_CR,  A_CR,  K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x01},
X/*051*/{{',',   '<',   ',',   '<',   K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*052*/{{'.',   '>',   '.',   '>',   K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*053*/{{'/',   '?',   '/',   A_US,  K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*054*/{{K_RSH, K_RSH, K_RSH, K_RSH, K_RSH, K_RSH, K_RSH, K_RSH  }, 0xff,0x00},
X/*055*/{{'*',   '*',   '*',   '*',   K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*056*/{{K_LAL, K_LAL, K_LAL, K_LAL, K_LAL, K_LAL, K_LAL, K_LAL  }, 0xff,0x00},
X/*057*/{{' ',   ' ',   A_NUL, A_NUL, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x0f,0x00},
X/*058*/{{K_CLK, K_CLK, K_CLK, K_CLK, K_CLK, K_CLK, K_CLK, K_CLK  }, 0xff,0x00},
X/*059*/{{F(1),  F(13), F(25), F(37), F(1),  F(13), F(25), F(37)  }, 0xff,0x00},
X/*060*/{{F(2),  F(14), F(26), F(38), F(2),  F(14), F(26), F(38)  }, 0xff,0x00},
X/*061*/{{F(3),  F(15), F(27), F(39), F(3),  F(15), F(27), F(39)  }, 0xff,0x00},
X/*062*/{{F(4),  F(16), F(28), F(40), F(4),  F(16), F(28), F(40)  }, 0xff,0x00},
X/*063*/{{F(5),  F(17), F(29), F(41), F(5),  F(17), F(29), F(41)  }, 0xff,0x00},
X/*064*/{{F(6),  F(18), F(30), F(42), F(6),  F(18), F(30), F(42)  }, 0xff,0x00},
X/*065*/{{F(7),  F(19), F(31), F(43), F(7),  F(19), F(31), F(43)  }, 0xff,0x00},
X/*066*/{{F(8),  F(20), F(32), F(44), F(8),  F(20), F(32), F(44)  }, 0xff,0x00},
X/*067*/{{F(9),  F(21), F(33), F(45), F(9),  F(21), F(33), F(45)  }, 0xff,0x00},
X/*068*/{{F(10), F(22), F(34), F(46), F(10), F(22), F(34), F(46)  }, 0xff,0x00},
X/*069*/{{K_NLK, K_NLK, K_NLK, K_NLK, K_NLK, K_NLK, K_NLK, K_NLK  }, 0xff,0x00},
X/*070*/{{K_SLK, K_SLK, K_BRK, K_BRK, K_SLK, K_SLK, K_BRK, K_BRK  }, 0xff,0x00},
X/*071*/{{F(49), '7',   F(49), '7',   F(49), K_ESN, K_NOP, K_NOP  }, 0xaf,0x02},
X/*072*/{{F(50), '8',   F(50), '8',   F(50), K_ESN, K_NOP, K_NOP  }, 0xaf,0x02},
X/*073*/{{F(51), '9',   F(51), '9',   F(51), K_ESN, K_NOP, K_NOP  }, 0xaf,0x02},
X/*074*/{{F(52), '-',   F(52), '-',   F(52), K_ESN, K_NOP, K_NOP  }, 0xaf,0x02},
X/*075*/{{F(53), '4',   F(53), '4',   F(53), K_ESN, K_NOP, K_NOP  }, 0xaf,0x02},
X/*076*/{{F(54), '5',   F(54), '5',   F(54), K_ESN, K_NOP, K_NOP  }, 0xaf,0x02},
X/*077*/{{F(55), '6',   F(55), '6',   F(55), K_ESN, K_NOP, K_NOP  }, 0xaf,0x02},
X/*078*/{{F(56), '+',   F(56), '+',   F(56), K_ESN, K_NOP, K_NOP  }, 0xaf,0x02},
X/*079*/{{F(57), '1',   F(57), '1',   F(57), K_ESN, K_NOP, K_NOP  }, 0xaf,0x02},
X/*080*/{{F(58), '2',   F(58), '2',   F(58), K_ESN, K_NOP, K_NOP  }, 0xaf,0x02},
X/*081*/{{F(59), '3',   F(59), '3',   F(59), K_ESN, K_NOP, K_NOP  }, 0xaf,0x02},
X/*082*/{{F(60), '0',   F(60), '0',   F(60), K_ESN, K_NOP, K_NOP  }, 0xaf,0x02},
X/*083*/{{A_DEL, '.',   A_DEL, '.',   A_DEL, K_ESN, K_RBT, K_NOP  }, 0x07,0x02},
X/*084*/{{F(60), F(26), F(60), K_NOP, K_SRQ, K_SRQ, K_SRQ, K_SRQ  }, 0xff,0x00},
X/*085*/{{F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58)  }, 0xff,0x00},
X/*086*/{{F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53)  }, 0xff,0x00},
X/*087*/{{F(11), F(23), F(35), F(47), F(11), F(23), F(35), F(47)  }, 0xff,0x00},
X/*088*/{{F(12), F(24), F(36), F(48), F(12), F(24), F(36), F(48)  }, 0xff,0x00},
X/*089*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*090*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*091*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*092*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*093*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*094*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*095*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*096*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*097*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*098*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*099*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*100*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*101*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*102*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*103*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*104*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*105*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*106*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*107*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*108*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*109*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*110*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*111*/{{F(51), F(51), K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*112*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*113*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*114*/{{K_RAL, K_RAL, K_RAL, K_RAL, K_RAL, K_RAL, K_RAL, K_RAL  }, 0xff,0x00},
X/*115*/{{K_RCT, K_RCT, K_RCT, K_RCT, K_RCT, K_RCT, K_RCT, K_RCT  }, 0xff,0x00},
X/*116*/{{A_NL,  A_NL,  A_NL,  A_NL,  A_NL,  A_NL,  A_NL,  A_NL   }, 0x00,0x00},
X/*117*/{{'/',   '/',   K_NOP, K_NOP, K_ESN, K_ESN, K_NOP, K_NOP  }, 0x3f,0x00},
X/*118*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*119*/{{K_BRK, K_BRK, K_BRK, K_BRK, K_BRK, K_BRK, K_BRK, K_BRK  }, 0xff,0x00},
X/*120*/{{F(50), F(50), K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*121*/{{A_DEL, A_DEL, A_DEL, A_DEL, A_DEL, A_DEL, A_DEL, A_DEL  }, 0x00,0x00},
X/*122*/{{F(57), F(57), K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*123*/{{F(60), F(60), K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*124*/{{K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*125*/{{F(55), F(55), K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*126*/{{F(59), F(59), K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X/*127*/{{F(49), F(49), K_NOP, K_NOP, K_NOP, K_NOP, K_NOP, K_NOP  }, 0xff,0x00},
X    }
X};
X
Xstatic char *stringdefaults[] =
X{
X    "\033OP", "\033OQ", "\033OR", "\033OS", "\033OT", "\033OU", "\033OV",
X    "\033OW", "\033OX", "\033OY", "\033OZ", "\033OA", "\033Op", "\033Oq",
X    "\033Or", "\033Os", "\033Ot", "\033Ou", "\033Ov", "\033Ow", "\033Ox",
X    "\033Oy", "\033Oz", "\033Oa", "\033OP", "\033OQ", "\033OR", "\033OS",
X    "\033OT", "\033OU", "\033OV", "\033OW", "\033OX", "\033OY", "\033OZ",
X    "\033OA", "\033Op", "\033Oq", "\033Or", "\033Os", "\033Ot", "\033Ou",
X    "\033Ov", "\033Ow", "\033Ox", "\033Oy", "\033Oz", "\033Oa", "\033[H",
X    "\033[A", "\033[V", "-",    "\033[D",   "\033[G", "\033[C", "+",
X    "\033[Y", "\033[B", "\033[U", "\033[@", "\033[2",
X    "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 
X    "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
X};
END-of-kdefaults.h
echo file: keycaps
sed 's/^X//' >keycaps << 'END-of-keycaps'
X#
X# Keycaps name list
X#	@(#)keycaps	1.1
X000	0
XEsc	1
X1	2
X2	3
X3	4
X4	5
X5	6
X6	7
X7	8
X8	9
X9	10
X0	11
X-	12
X=	13
XBackspace	14
XTab	15
XQ	16
XW	17
XE	18
XR	19
XT	20
XY	21
XU	22
XI	23
XO	24
XP	25
X[	26
X]	27
XEnter	28
XLCtrl	29
XA	30
XS	31
XD	32
XF	33
XG	34
XH	35
XJ	36
XK	37
XL	38
X;	39
X'	40
X`	41
XLShift	42
X\\	43
XZ	44
XX	45
XC	46
XV	47
XB	48
XN	49
XM	50
X,	51
X.	52
X/	53
XRShift	54
X*	55
XLAlt	56
XSpc	57
XRAlt	58
XF1	59
XF2	60
XF3	61
XF4	62
XF5	63
XF6	64
XF7	65
XF8	66
XF9	67
XF10	68
XNumLock	69
XScrollLock	70
XHome	71
XUp	72
XPgUp	73
XPadMinus	74
XLeft	75
XCenter	76
XRight	77
XPadPlus	78
XEnd	79
XDown	80
XPgEnd	81
XIns	82
XDel	83
X# All following keys are on the 101-key keyboard only
XSysReq	84
X085	85
X086	86
XF11	87
XF12	88
X089	89
X090	90
X091	91
X092	92
X093	93
X094	94
X095	95
X096	96
X097	97
X098	98
X099	99
X100	100
X101	101
X102	102
X103	103
X104	104
X105	105
X106	106
X107	107
X108	108
X109	109
X110	110
X111	111
X112	112
X113	113
XRAlt	114
XRCtrl	115
XPadEnter	116
XPadSlash	117
X118	118
XPause	119
X120	120
X121	121
X122	122
X123	123
X124	124
X125	125
X126	126
X127	127
END-of-keycaps
echo file: keybind.1
sed 's/^X//' >keybind.1 << 'END-of-keybind.1'
X.\"	@(#)keybind.1	1.2
X.\"
X.\" Copyright 1989 by Eric S. Raymond (eric@snark.uu.net), all rights reserved
X.\" You may use, modify or redistribute this code freely, but do not delete
X.\" this notice. Check with me before you make money with it.
X.\" 
X.TH KEYBIND 1 "Local"
X.SH NAME
Xkeybind \- key-map editor for XENIX and UNIX V.3.2 386 machines
X.SH SYNOPSIS
Xkeybind [-mdr] [-] [\fIfiles\fR...] [ -o \fIoutfile\fR ]
X.SH DESCRIPTION
XThis utility enables you to inspect and modify the console keyboard driver
Xtables on for any UNIX version using the XENIX/386 keyboard driver (this
Xincludes recent and future AT&T UNIX releases).
X.SS Theory of Operation
XAt startup, keybind reads in the current keyboard maps. After interpreting all
Xswitches and digesting whatever input sources are specified, it attempts to
Xwrite the resulting map and any changes in string assignments back to the
Xmapping tables for your tty.
X.PP
XCalled with no arguments or with the argument - representing standard input,
Xkeybind may be used interactively or fed from a keyboard map file; the
Xmini-language used to describe key definitions is documented below.
X.PP
XThe -d flag dumps the current keyboard table in a format keybind will accept as
Xinput; this is useful for inspecting key definitions. The -r and -m flags are
Xintended to facilitate noninteractive use from scripts; the former restores
Xthe default key mappings, and the latter enables Alt as a true Meta key.
X.PP
XThe flags (and -) may be used in any combination and will trigger their
Xactions in the order they are given. Arguments mixed with the flags are
Xtaken as the names of keyboard map files to be processed.
X.PP
XThe -o flag (which requires a filename argument) causes the contents of the
Xkeymap and stringmap tables at the end of a keybind run to be dumped in binary
Xform to the given filename. These dump files will be read in properly (and
Xtheir contents loaded into the program's map-table space) when presented as
Xfilename arguments to later keybind runs.
X.PP
XThis is much faster than an interpreting the equivalent text, because
Xit concentrates the I/O into one belt and avoids the lexer/parser execution
Xtime cost. Thus you can use -o to precompile a keyboard setup so that
Xsubsequent keymap runs are very quick.
X.SS Enabling Alt as a Meta key
XThe -m option or the `meta' directive will remap the keyboard on so that the
XAlt key acts as a meta key when combined with any printable character, or any
Xshift-control modification of a printable; that is, it turns on the high (0x80)
Xbit of the character.
X.PP
XThis is useful with GNU EMACS. To see why, run it, pull up an EMACS, set
Xthe meta-flag global to non-nil, type ALT-x, and notice that it works!
XTo arrange this behavior by default, you might put a `keybind -m' in an
Xinitialization script under /etc/rc2.d to be executed whenever the system
Xenters multiuser mode.
X.PP
XNote: the ISTRIP bit must be off in your termio structure for your meta key
Xto work (otherwise the driver will happily strip the meta bit off your input
Xkeystroke before making it available to the application). GNU EMACS does this
Xitself; for other applications you may need to do an explicit stty -istrip or a
XTCSETA{W} ioctl.
X.PP
XFunction keys and control-character keys and other special keys are not
Xaffected by the alt-enable operation. Pains are also taken that this change not
Xstep on window manager keys or other important special functions; specifically,
Xit only modifies key/state pairs that are bound to the \fInop\fR, \fIescl\fR,
X\fIescn\fR or \fIesco\fR functions.
X.SS Keymap Definition Files
XThe output of keybind -d is a keymap definition file describing the current
Xstate of your keyboard. The syntax has been designed to resemble the
Xconventions used in the \fIkeyboard\fR(7) entry as closely as possible.
X.PP
XEach map file is parsed as a sequence of newline- or semicolon-separated
X\fIcommands\fR or comments.
XCase of alphabetics and whitespace are ignored everywhere except within
Xcharacter literals and strings.
XComments may begin at any point with # and
Xcontinue to end of line. Each command may be a \fIdirective\fR, a \fIkey
Xdefinition\fR, a \fIstring assignment\fR, or a \fRshift modifier\fR.
X.PP
XThe following directives are defined:
X.PP
X\fIrestore\fR \-\- resets to the default bindings given in the
X\fIkeyboard\fR(7) manual. Must be used with caution, see the BUGS note below.
X.PP
X\fImeta\fR \-\- enables the Alt key to function as a true meta, as with the
X-m option (see above).
X.PP
X\fIdump\fR \-\- dumps portions of the keymap table. Without arguments it dumps
Xthe entire table. It may take a list of scan-code ranges (see below) as
Xarguments, in which case it dumps only the relevant characters.
X.PP
X\fIfunkeys\fR \-\- dumps portions of the function key table. Without arguments
Xit dumps the entire table. It may take a list of function-key ranges (that is,
Xfkey special values or dash-separated pairs of same) as arguments, in which
Xcase it dumps only those function keys.
X.PP
X\fIclearstrings\fR \-\- normally, strings assigned to function keys are added
Xto those already present in the keyboard driver's string table. If you don't
Xneed the defaults, this wastes some of the limited space available for key
Xmappings. The \fIclearstrings\fR directive clears the string assignment table
X(no defaults are saved). Try using it if you get the `out of string space'
Xabort message.
X.PP
X\fIcapslock\fR \-\- dumps information on which keys are affected by caps lock.
X.PP
X\fInumlock\fR \-\- dumps information on which keys are affected by num lock.
X.PP
X\fIexecute\fR \-\- sends pending keymap changes to the tty immediately using
Xthe code normally called just before program exit. Intended for interactive
Xuse.
X.PP
X\fIhelp\fR \-\- prints a command summary. Intended for interactive use; it
Xalso turns on an asterisk prompt, which is turned off on EOF.
X.PP
XAs a convenience for interactive use, any directive may be abbreviated to its
Xfirst two letters.
X.PP
XKey definitions may consist of \fIscan-code assignments\fR or \fIkey-state
Xassignments\fR. The output of `keybind -d' is a list of scan-code assignments
Xfor all defined scan-codes. Each one consists of a \fIscan-code specifier\fR
Xfollowed by at most eight \fIkey values\fR, one for each shift state. If fewer
Xthan eight values are given, states changed start from the left of the table.
XA state may be skipped by putting a dash in its place in the list.
X.PP
XScan-code specifiers always begin with a @ (at-sign). There are two kinds;
X\fInumeric\fR and \fImnemonic\fR. The former always consists of three zero
Xfilled decimal digits after the @, giving the scan code's value. Mnemonic
Xspecifiers, usually duplicate the graphic on the key cap to which the scan code
Xcorresponds after the @. The output of `keybind -d' includes all valid 
Xmnemonic scan-code specifiers in the leftmost column. The two sets are not
Xmutually exclusive; the unlisted numeric specifiers corresponding to mnemonics
Xare also valid.
X.PP
XKey values may consist of \fIcharacter values\fR or \fIspecial values\fR.
XSpecial values are those listed in \fIkeyboard\fR(7), plus the following
Xadditions:
X.PP
Xvt[0-9]* \- the virtual terminal selectors.
X.PP
Xmgr[0-9]* \- the virtual terminal manager selectors.
X.PP
Xpfx[0-9]* \- undocumented, but in sys/kd.h; \fIyou\fR tell \fIme\fR.
X.PP
XA character value may consist of any of the standard mnemonics for control
Xcharacters (refer to keybind -rd output for a nearly complete list; `nl' (0x0a),
X`ht' (0x08) and `csi' (0x9b) are also accepted) or a \Iliteral\fR.
X.PP
XLiterals have the syntax of C character constants, with some additions.
XThe backslash escape form \\xnn permits the use of two-digit hex constants.
XThe backslash escape form \\dnnn permits the use of three-digit decimal
Xconstants.
XC-style octal escapes and special characters \\n, \\r, \\t, \\b, \\v are
Xcorrecrtly interpreted.
XAlso, the literal '\\e' is interpreted as ASCII escape (0x1b).
XTwo-character literals of the form '^c' are interpreted as control characters.
XTwo-character literals of the form '!c' are interpreted as meta characters;
Xthat is, the value is that of the second character with the meta (0x80) bit
Xturned on.
XThe case of literals is preserved.
X.PP
XKey-state assignments set the value of a single key/state combination. They
Xconsist of an optional \fIshift prefix\fR, a scan-code specifier, an equals
Xsign and a key value. The shift prefix identifies the state of the key
Xcorresponding to the scan code to which the key value should be assigned.
XThe shift prefix may consist of the combination of the words \fBalt\fR,
X\fIshift\fR, \fIctrl\fR, optionally trailed by hyphens. A key-state
Xassignment with no prefix applies to the normal (unshifted) state of the
Xkey.
X.PP
XString assignments consist of a function key name, followed by an equals sign,
Xfollowed by a \fIstring literal\fR. String literals preserve case and have the
Xsyntax of C strings, with the same additional escape conventions as described
Xabove for character literals.
X.PP
XFinally, shift modifiers are used to control which characters are subject
Xto shift-key modification. Each should begin with one of the keywords
X\fIshiftlock\fR, \fIcapslock\fR, or \fInumlock\fR; \fIshiftlock\fR and
X\fIcapslock\fR are equivalent. This should be followed by one of the words
X`enabled' or `disabled' and a list of ranges of scan codes. If the list is
Xempty, the shift modifier is applied to all scan codes.
X.PP
XA \fIrange\fR may be either a single scan code or a dash-separated pair of
Xscan codes; the latter is interpreted as all scan codes numerically greater
Xthan or equal to the first and less than or equal to the second.
X.PP
X.SH EXAMPLE
XThe author finds the command file given as figure 1 below quite useful. To
Xunderstand what it does, first note the following:
X.PP
XIf keybind is run from the console before vtlmgr, the key mappings will apply
Xto all virtual terminals. However, string-key loadings will be changed on the
Xconsole only. Thus, to give a key/state combination the same value (usable by
Xan application that can do its own key bindings, such as EMACS) across all
Xvirtual terminals, it is best to bind it to an esco/escn/escl value rather
Xthan indirecting through a function key.
X
X.ce 1
XFig 1: sample.kmf
X
X.in +10n
X.nf
X.so sample.kmf
X.fi
X.in
X
X.SH BUGS
XDue to the absence of a reset ioctl(), the mappings that -r and the `restore'
Xcommand reset to come from tables dumped out of 3.2u, tweaked to match the
Xdefaults tables in \fIkeyboard\fR(7) and included into the code. If you have
Xreason to suspect that the system defaults have changed, you can recompile
Xwith -DREGEN and replace the system-default initializers with the output of
Xa `keybind -c'.
X.PP
XRestoring defaults doesn't undo changes in the enabling of the shift-lock and
Xnum-lock keys.
X.PP
XError handling in the keyboard map description parser is rudimentary.
X.PP
XBeware of confusing @[0-9] with @00[9]; the former are mnemonics for the
Xdigit-key scan codes, the latter represent numeric scan codes. 
X.SH PORTABILITY NOTE
XThis code should work on any AT/ISA/EISA box running XENIX/386 or an un-munged
Xport of AT&T UNIX at release 3.2 or later. To check this, look for the
XGIO_KEYMAP and SIO_KEYMAP ioctls in \fIkeyboard\fR(7); if these are present,
Xyou have the XENIX keyboard driver and keybind should do the right thing.
X.SH AUTHOR
XEric S. Raymond (eric@snark.uu.net)
X.SH SEE ALSO
Xkeyboard(7)
X
X
END-of-keybind.1
echo file: sample.kmf
sed 's/^X//' >sample.kmf << 'END-of-sample.kmf'
X# Eric's keymap-refinition script for use with GNU EMACS
X#
X#	@(#)sample.kmf	1.1
X#
Xkeybind <<EOF
Xmeta                    # This helps with GNU EMACS
Xalt-@F1 = vt0           # More convenient vt-select keys
Xalt-@F2 = vt1
Xalt-@F3 = vt2
Xalt-@F4 = vt3
Xalt-@F5 = vt4
Xalt-@F6 = vt5
Xalt-@F7 = vt6
Xalt-@F8 = vt7
X@PadMinus = escn        # Use this for (kill-compilation)
X@PadPlus = escn         # Use this for (compile)
X@ScrollLock = xoff      # ^S
Xcapslock disabled       # Because I'm a poor typist
XEOF
END-of-sample.kmf
exit

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.