#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  keyfix.c keyfix.doc
# Wrapped by brant@manta on Tue Feb 14 14:45:19 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'keyfix.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'keyfix.c'\"
else
echo shar: Extracting \"'keyfix.c'\" \(4380 characters\)
sed "s/^X//" >'keyfix.c' <<'END_OF_FILE'
X/************************************************************
X *
X * This program was written by me, Mike "Ford" Ditto, and
X * I hereby release it into the public domain in the interest
X * of promoting the development of free, quality software
X * for the hackers and users of the world.
X *
X * Feel free to use, copy, modify, improve, and redistribute
X * this program, but keep in mind the spirit of this
X * contribution; always provide source, and always allow
X * free redistribution (shareware is fine with me).  If
X * you use a significant part of this code in a program of
X * yours, I would appreciate being given the appropriate
X * amount of credit.
X *				-=] Ford [=-
X *
X ************************************************************/
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <ctype.h>
X#include <errno.h>
X#include <pwd.h>
X#include <grp.h>
X#include <sys/types.h>
X#include <sys/kbd.h>
X#include <nlist.h>
X
X
Xextern long lseek(), strtol();
Xextern void perror(), exit();
X
X
Xvoid kcopy(), kwrite();
X
Xchar *progname;
X
X#define ldkeymapaddr (myldsyms[0].n_value)
X
Xstruct nlist myldsyms[] =
X{
X    { "ldkeymap", },
X    { (char *)0, },
X};
X
X#define keymapaddr (mysyms[0].n_value)
X
Xstruct nlist mysyms[] =
X{
X    { "keymap", },
X    { (char *)0, },
X};
X
Xchar buf[BUFSIZ];
X
Xint kmem;
Xint keynum, norm, shift, ctrl, flags;
X
X
Xvoid usage()
X{
X    fprintf(stderr, "usage: %s <keynum> [ <norm> <shift> <ctrl> <flags> ]\n",
X	    progname);
X    fprintf(stderr, "	Numbers are decimal unless preceded by 0 or 0x\n");
X    exit(-1);
X}
X
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X
X    progname = *argv;
X
X    setup();
X
X    if (argc != 2 && argc != 6)
X	usage();
X
X    keynum = numcvt(argv[1]);
X    if (keynum<0 || keynum>=0x80)
X    {
X	fprintf(stderr, "%s: invalid keynum 0x%02x\n", progname, keynum);
X	exit(-2);
X    }
X
X    if (argc>2)
X    {
X	norm = numcvt(argv[2]);
X	shift = numcvt(argv[3]);
X	ctrl = numcvt(argv[4]);
X	flags = numcvt(argv[5]);
X    }
X
X    return keyfix();
X}
X
X
Xint numcvt(str)
Xchar *str;
X{
X    long value;
X    char *ptr;
X
X    value = strtol(str, &ptr, 0);
X
X    if (*ptr)
X    {
X	fprintf(stderr, "%s: invalid number `%s'\n",
X		progname, str);
X	usage();
X    }
X
X    return value;
X}
X
X
X/* one-time setup of main data structures from the kernel */
Xsetup()
X{
X    if ( (kmem=open("/dev/kmem", O_RDWR)) < 0 )
X    {
X	sprintf(buf, "%s: can't open /dev/kmem", progname);
X	perror(buf);
X	exit(1);
X    }
X
X    if (nlist("/etc/lddrv/kbd", myldsyms))
X    {
X	if (nlist("/unix", mysyms))
X	{
X	    sprintf(buf, "%s: can't nlist /unix", progname);
X	    perror(buf);
X	    exit(1);
X	}
X#ifdef DEBUG
X	fputs("Using keymap from /unix\n", stderr);
X#endif DEBUG
X    }
X    else
X    {
X#ifdef DEBUG
X	fputs("Using ldkeymap from /etc/lddrv/kbd\n", stderr);
X#endif DEBUG
X	keymapaddr = ldkeymapaddr;
X    }
X
X#ifdef DEBUG
X    fprintf(stderr, "keymap:	0x%08lx\n", keymapaddr);
X#endif DEBUG
X}
X
X
X/* copy bytes from kernel address space to this process */
Xvoid kcopy(caddr, kaddr, nbytes)
Xchar *caddr;
Xlong kaddr;
Xlong nbytes;
X{
X    if ( lseek(kmem, kaddr, 0)<0L ||
X	read(kmem, caddr, (unsigned)nbytes) != nbytes )
X    {
X	sprintf(buf, "%s: can't read /dev/kmem", progname);
X	perror(buf);
X	exit(1);
X    }
X}
X
X
X/* write bytes from this process' address space to the kernel's */
Xvoid kwrite(kaddr, caddr, nbytes)
Xlong kaddr;
Xchar *caddr;
Xlong nbytes;
X{
X#ifdef DEBUG
X    fprintf(stderr, "Writing %ld bytes to kernel address 0x%08lx\n",
X	    nbytes, kaddr);
X#endif
X
X    if ( lseek(kmem, kaddr, 0)<0L ||
X	write(kmem, caddr, (unsigned)nbytes) != nbytes )
X    {
X	sprintf(buf, "%s: can't write /dev/kmem", progname);
X	perror(buf);
X	exit(1);
X    }
X}
X
X
X/* change the keymap of key `keynum' */
Xkeyfix()
X{
X    struct keydef mydef;
X
X    kcopy((char *)&mydef,
X	  (long)&((struct keydef *)keymapaddr)[keynum],
X	  (long)sizeof mydef);
X
X    printf("Old keymap[0x%02x] = 0x%04x,0x%04x,0x%04x,%2d\n",
X	   keynum,
X	   mydef.kt_codes[0],
X	   mydef.kt_codes[1],
X	   mydef.kt_codes[2],
X	   mydef.kt_flags);
X
X    if (!(norm||shift||ctrl||flags))
X	return 0;
X
X    mydef.kt_codes[0] = norm;
X    mydef.kt_codes[1] = shift;
X    mydef.kt_codes[2] = ctrl;
X    mydef.kt_flags = flags;
X
X    printf("New keymap[0x%02x] = 0x%04x,0x%04x,0x%04x,%2d\n",
X	   keynum,
X	   mydef.kt_codes[0],
X	   mydef.kt_codes[1],
X	   mydef.kt_codes[2],
X	   mydef.kt_flags);
X
X    kwrite((long)&((struct keydef *)keymapaddr)[keynum],
X	   (char *)&mydef,
X	   (long)sizeof mydef);
X
X    return 0;
X}
END_OF_FILE
if test 4380 -ne `wc -c <'keyfix.c'`; then
    echo shar: \"'keyfix.c'\" unpacked with wrong size!
fi
# end of 'keyfix.c'
fi
if test -f 'keyfix.doc' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'keyfix.doc'\"
else
echo shar: Extracting \"'keyfix.doc'\" \(4865 characters\)
sed "s/^X//" >'keyfix.doc' <<'END_OF_FILE'
X>From: ford@kenobi.UUCP (Mike Ditto)
XSubject: Keyboard remapper for Unix PC at Last!
XDate: 26 Oct 87 01:08:43 GMT
X
XWell, thanks to Paul Fox at AT&T for pointing me in the right direction (or
Xat the right include files).  I have used the information in his posting
X(which was paraphrased from <sys/kbd.h>) to write the much-needed keyboard
Xre-mapping program for the Unix PC.  The command is called 'keyfix' and it
Xlets you examine or modify the definition of any code-generating key on the
Xconsole keyboard (it will not affect the shift, control, or lock keys them-
Xselves).
X
XThe usage is: keyfix <keynum> [ <norm> <shift> <ctrl> <flags> ]
X
XAll arguments are numbers which are decimal unless preceded by 0 for octal
X	or 0x for hexadecimal.  If only <keynum> is given then the current
X	definition of that keycode is listed but not changed.
X
Xkeynum:	The hardware keycode of the key you are interested in.  You can
X	find these listed in the comments in /usr/include/sys/kbd.h.
X
Xnorm:	The ascii code this key should generate if pressed alone.
X
Xshift:	The ascii code this key should generate if pressed with SHIFT held.
X
Xcontrol:The ascii code this key should generate if pressed with CONTROL held.
X
Xflags:	The flags for this keycode, as defined in <sys/kbd.h>.
X
X
XNote that the 'ascii codes' are 16-bit numbers.  The low-order byte (last two
Xdigits) are the actual code.  If the high-order byte is non-zero, it is used
Xas an index into the kprefix[] table which you can see in <sys/kbd.h>.  This
Xis how one key (like HOME) can generate a multi-byte sequence (like ^[[H).
X
X
XFor example, suppose you want what is now the 'BREAK/RESET' key to be RUBOUT
X(a.k.a. DEL) instead.  You grep for BREAK in /usr/include/sys/kbd.h and see
Xthat it is keycode 0x25.  So you type "keyfix 0x25" to see what it's current
Xsetting is:
X
X	$ keyfix 0x25
X	Old keymap[0x25] = 0x00ff,0x00ff,0x00ff, 0
X	$ 
X
XYou see that it is currently set to generate 0x00ff regardless of whether
Xshift or control are pressed.  Apparrently, 0xff is what 'BREAK/RESET'
Xreturns by default.  Now you want it to be RUBOUT, again regardless of the
Xstate of shift and control.  So you type:
X
X	$ keyfix 0x25 0x7f 0x7f 0x7f 1
X	Old keymap[0x25] = 0x00ff,0x00ff,0x00ff, 0
X	New keymap[0x25] = 0x007f,0x007f,0x007f, 1
X	$ 
X
XNotice that the <flags> argument (the last one) was given as 1 instead of
X0, which it had been before.  In <sys/kbd.h> REPT is defined as 0x1, meaning
Xthat if that bit (bit 0, 0x0001) is set in the flags then the corresponding
Xkey will repeat if held down.  The other flags, CAPLCK (0x2) and NUMLCK (0x4)
Xdetermine whether the 'lock' keys will affect them.  You can add any or all
Xof the above flags together and use the result as the <flags> argument to
Xkeyfix.
X
XHere are the keyfixes that I recommend that everyone use:
X
X	keyfix 0x36 0x36 0x5e 0x1e 1	# Make control-^ work
X	keyfix 0x2d 0x2d 0x5f 0x1f 1	# Make control-_ work
X	keyfix 0x20 0x20 0x20 0x00 1	# Make control-space be a NUL
X	keyfix 0x25 0x7f 0x7f 0x7f 1	# Make BREAK/RESET be RUBOUT
X	keyfix 0x1b 0x1b 0x7f 0xff 1	# Make control-escape be BREAK/RESET
X					#  (just in case it is ever needed)
X
XNote that you must be super-user in order to run keyfix.  This is because
Xit writes to internal data structures in the kernel, and because it has a
Xglobal effect on the system (its effects last until the machine is booted).
XI suggest that your favorite keyfix commands be run after each reboot, perhaps
Xin /etc/rc, or in a file in the /etc/daemons directory.  If you really think
Xyou want to be running it all the time, you could make it set-uid to root.
X
XThere is one peculiarity in the process of changing these keymaps.  If you
Xhave CAPCTRL then you have a complete replacement for the normal keyboard
Xdriver and its tables.  Therefore, modifying the 'keymap' table in the kernel
Xhas no effect.  Don't worry, though.  keyfix is smart enough to check if you
Xhave the CAPCTRL driver in the /etc/lddrv directory and use its table if it
Xis there.  Otherwise the /unix table is used.  The only real problem with
Xthis is that it is possible for the driver to exist in /etc/lddrv but not be
Xloaded into the kernel.  This will only happen if you PARTIALLY de-installed
XCAPCTRL by some non-standard method (like typing "lddrv -d kbd").  If you
Xhave installed CAPCTRL and then removed it, make sure you remove or rename
X"/etc/lddrv/kbd".
X
XThanks again to Paul Fox for contributing to this newsgroup.  Now if he
Xcould only get me information (source?) for changing the extra control key
Xinto a meta-key.  Then I could actually start doing work on the console
Xinstead of from the Amiga on tty000.
X
XWell, here's the source to keyfix...
XIf somebody needs executables let me know.
X
X					-=] Ford [=-
X
X"GNU does not eliminate			(In Real Life:  Michael Ditto)
Xall the world's problems,		ford%kenobi@crash.CTS.COM
Xonly some of them." -rms		...!crash!kenobi!ford
END_OF_FILE
if test 4865 -ne `wc -c <'keyfix.doc'`; then
    echo shar: \"'keyfix.doc'\" unpacked with wrong size!
fi
# end of 'keyfix.doc'
fi
echo shar: End of shell archive.
exit 0

