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.