Article: 638 of unix-pc.sources
From: mark@crescent.uucp (Mark Schulman)
Newsgroups: unix-pc.sources
Subject: Take back those shifted function keys!
Message-ID: <1990Aug5.150010.12094@crescent.uucp>
Date: 5 Aug 90 15:00:10 GMT
Organization: Crescent Computing
Lines: 368


Folks --

Here's a piece that may be of some serious interest to you Unix PC users.
I always thought one of the biggest wastes on the Unix PC was to assign
the shifted function keys to the phone manager.  This program takes them
back by force.

'pfkeys' allows you to assign programs to the 8 shifted function keys.
When you press the key, a window opens and the program runs.  You
create a key definition file that looks like this:

	W /dev/w2
	F1 W EX /etc/fixes/pcal
	F2 F EX /usr/local/bin/vnews
	F3 W SH /usr/bin/MsdosF.sh
	F4 W SH /usr/bin/Fformat10.sh
	F7 F EX /usr/local/bin/elm
	F8 F EX /bin/ksh

The first line specifies the window device that is to be used.  You
should find that the Phone Manager has /dev/w2, but to a 'ps' to check
that out.

The remaining lines specify the programs to run when shifted function keys
are pressed.  The first field is the function key; the second field is a W
or F (W means that the program will create its own window; F means that
'pfkeys' should create a full-screen window for it), the third field
specifies that the program is a shell program (SH) or a binary executable
(EX).  The 4th field is the file to execute.

In this example, s-F1 displays the calendar, s-F2 runs vnews, s-F3 and s-F4
format MS-DOS or Unix floppies respectively, s-F7 runs elm, and s-F8 pops
up a spare K-shell.

Try a line in your .profile that says:

	pfkeys $HOME/.keydefs

where .keydefs is the key definition file described above.

I don't run the phone manager, but it should work OK even with the
phone manager running.  Try this and let me know what you think.


Mark Schulman					 (407) 661-8374
Cincinnati Bell Information Systems	  att!auxnj!icepit!mark
					att!auxnj!crescent!mark


-- (cut here) -- (cut here) -- (cut here) -- (cut here) -- (cut here) --
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by typing sh file.  To overwrite existing files, type "sh file -c".
# If this archive is complete, you will see the following message at the end:
#		"End of shell archive."
# Contents:  Makefile pfkeys.c
# Wrapped by crescent!mark on Sun Jul  8 12:24:29 EDT 1990
echo "extracting files ..."
if test -f 'Makefile' -a "${1}" != -c ; then 
echo "shar:  Will not clobber existing file \"Makefile\""
else
echo "x - Makefile (92 characters)"
sed 's/^X//' >'Makefile' <<'EOF'
XCFLAGS	=	-O
XLDFLAGS	=	-s
XCC	=	shcc
X
Xpfkeys:		pfkeys.o
X		$(CC) $(LDFLAGS) pfkeys.o -o pfkeys
EOF
if test 92 -ne `wc -c <'Makefile'`; then
echo shar:  Makefile unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'pfkeys.c' -a "${1}" != -c ; then 
echo "shar:  Will not clobber existing file \"pfkeys.c\""
else
echo "x - pfkeys.c (5211 characters)"
sed 's/^X//' >'pfkeys.c' <<'EOF'
X#include <stdio.h>
X#include <fcntl.h>
X#include <sys/types.h>
X#include <sys/signal.h>
X#include <sys/window.h>
X#include <sys/termio.h>
X
X
Xtypedef enum {
X	SHELL=1,	/*  shell program	*/
X	EXEC,		/*  executable		*/
X	} filetype;
X
Xtypedef enum {
X	NOWIN,		/*  will create its own window		*/
X	FULL,		/*  needs a full-screen window		*/
X	} wintype;
X
X
X/*  table of function keys  */
Xstruct KEYTAB {
X	wintype		wtype;
X	filetype	ftype;	
X	char		command[71];
X	} key[8];
X
Xchar *keydef;		/*  definition file  */
Xint linenum;
X/*  size 11 x 16  */
Xstatic unsigned short F_icon[] = {
X	65535,32769,33785,33297,32913,33009,38033,34833,37945,32769,65535};
X
X
Xvoid
Xcheck (status, msg, file)
Xint status;
Xchar *msg, *file;
X{
Xchar buffer[101];
Xextern char *sys_errlist[];
Xextern int errno, sys_nerr;
Xint fd;
X
X	if (status) {
X		sprintf (buffer, "pfkeys:  %s%s: %s\n", msg,
X			file ? file : "",
X			(errno < 1 || errno >= sys_nerr) ?
X				"unknown error code" :
X				sys_errlist[errno]);
X		if ((fd = open ("/dev/error", 1)) != -1) {
X			write (fd, buffer, strlen (buffer));
X			close (fd);
X			}
X		exit (1);
X		}
X}
X
X
Xvoid
Xupdate_icon (i)
Xint i;
X{
Xstruct urdata ur;
Xstatic int last_flag;	/*  0 = normal, 1 = reverse  */
X
X	if (i != last_flag) {
X		last_flag = i;
X		for (i=0; i<sizeof (F_icon)/sizeof (F_icon[0]); i++)
X			F_icon[i] ^= ~0;
X		}
X
X	ur.ur_srcbase = F_icon;
X	ur.ur_srcwidth = 2;
X	ur.ur_dstbase = NULL;
X	ur.ur_srcx = 0;
X	ur.ur_srcy = 0;
X	ur.ur_dstx = 240;
X	ur.ur_dsty = 0;
X	ur.ur_width = 16;
X	ur.ur_height = 11;
X	ur.ur_srcop = SRCSRC;
X	ur.ur_dstop = DSTSRC;
X	check (ioctl (0, WIOCRASTOP, &ur), "ioctl call WIOCRASTOP failed",
X			NULL);
X}
X
X
Xvoid
Xhangup ()
X{
X	memset (F_icon, 0, sizeof (F_icon));
X	update_icon (0);
X	exit (0);
X}
X
X
Xvoid
Xdeffile_error (msg)
Xchar *msg;
X{
X	fprintf (stderr, "\"%s\", line %d:  %s\n",
X		keydef, linenum, msg);
X	exit (1);
X}
X
X
Xvoid
Xsetup ()
X{
Xstruct termio tio;
XFILE *f;
Xchar buffer[81];
Xregister j;
Xchar *strchr ();
Xstatic char *linemask[] = {
X	"F", "12345678", " ", "WF", " ", "ES", "XH", " ", NULL};
X
X
X	/*  load the keydefs  */
X	check ((f = fopen (keydef, "r")) == NULL, "can't open ", keydef);
X	while (fgets (buffer, sizeof (buffer), f)) {
X		linenum++;
X		j = strlen (buffer);
X		if (buffer[j - 1] != '\n')
X			deffile_error ("line too long");
X		if (*buffer == '#')
X			continue;
X		buffer[j - 1] = 0;
X
X		if (*buffer == 'W') {
X			/*  Open the window that the phdaemon
X			    already has open.  */
X			close (0);
X			check (open (buffer+2,O_RDONLY), "can't open ",
X								buffer+2);
X			/*  Make it the phone manager window  */
X			check (ioctl (0, WIOCSYS,1),
X				"IOCTL call WIOCSYS failed", NULL);
X			continue;
X			}
X
X		if (j < 10)
X			deffile_error ("line too short");
X		for (j=0; linemask[j]; j++)
X			if (strchr (linemask[j], buffer[j]) == NULL) {
X				sprintf (buffer,
X					"syntax error in character %d",
X					j+1);
X				deffile_error (buffer);
X				}
X		j = buffer[1] - '1';
X		if (buffer[3] == 'F')
X			key[j].wtype = FULL;
X		else key[j].wtype = NOWIN;
X		if (buffer[5] == 'E')
X			key[j].ftype = EXEC;
X		else key[j].ftype = SHELL;
X		strcpy (key[j].command, buffer+8);
X		}
X	fclose (f);
X
X	/*  Catch hangups.  */
X	signal (SIGHUP, hangup);
X	signal (SIGINT, SIG_IGN);
X	signal (SIGQUIT, SIG_IGN);
X
X	/*  Set terminal characteristics  */
X	check (ioctl (0, TCGETA, &tio), "IOCTL call TCGETA failed", NULL);
X	tio.c_cc[4] = 1;
X	tio.c_iflag	= IGNBRK | IGNPAR ;
X	tio.c_oflag	= OPOST;
X	tio.c_cflag	&= ~CBAUD;
X	tio.c_cflag	|= CS8 | CREAD | HUPCL | CLOCAL;
X	tio.c_lflag	= 0;
X	tio.c_line	= 0;
X	check (ioctl (0, TCSETA, &tio), "IOCTL call TCSETA failed", NULL);
X	check (ioctl (0, WIOCSYS,1), "IOCTL call WIOCSYS failed", NULL);
X
X	/*  put up the icon  */
X	update_icon (0);
X
X	/*  flush input  */
X	check (ioctl (0, TCFLSH, 2), "ioctl call TCFLSH failed", NULL);
X}
X
X
Xvoid
Xperform_key (n)
Xint n;
X{
Xstruct uwdata uw;
Xstruct KEYTAB *kp;
X
X	/*  see if it's a valid key  */
X	if (n < 0 || n > 7) {
X		write (0, "\7", 1);
X		return;
X		}
X	kp = &key[n];
X	if (kp->ftype == 0) {
X		write (0, "\7", 1);
X		return;
X		}
X
X	/*  create a child  */
X	if (fork ()) {
X		/*  original parent  */
X		wait ((int*) NULL);
X		sleep (5);
X		return;
X		}
X
X	if (fork ()) {
X		/*  first child  */
X		exit (0);
X		}
X
X	/*  child - the new program  */
X	close (0);
X	close (1);
X	close (2);
X	setpgrp ();
X	check (open ("/dev/window", 2), "Can't open a new window",NULL);
X	dup (0);
X	dup (0);
X
X	/*  set the screen to full screen if required  */
X	if (kp->wtype == FULL) {
X		uw.uw_x		= 0;
X		uw.uw_y		= 12;
X		uw.uw_width	= 720;
X		uw.uw_height	= 288;
X		uw.uw_uflags	= 0x301;
X		check (ioctl (0, WIOCSETD, &uw),
X			"can't set window characteristics", NULL);
X		}
X
X	signal (SIGHUP, SIG_DFL);
X	signal (SIGINT, SIG_DFL);
X	if (kp->ftype == SHELL)
X		execl ("/bin/sh", "sh", kp->command, NULL);
X	else execl (kp->command, kp->command, NULL);
X
X	check (1, "can't execute ", kp->command);
X}
X
X
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
Xchar byte;
X
X	if (argc != 2) {
X		fputs ("usage:  pfkeys <keydeffile>\n", stderr);
X		exit (1);
X		}
X	keydef = argv[1];
X	setup ();
X	for (;;) {
X		if (read (0,&byte,1) != 1 || byte != 27)
X			continue;
X		if (read (0,&byte,1) != 1 || byte != 79)
X			continue;
X		if (read (0,&byte,1) != 1)
X			continue;
X
X		/*  got one  */
X		update_icon (1);
X		perform_key (byte - 'C');
X		update_icon (0);
X		}
X}
EOF
if test 5211 -ne `wc -c <'pfkeys.c'`; then
echo shar:  pfkeys.c unpacked with wrong size!
fi
# end of 'pfkeys.c'
fi
echo End of shell archive.
exit 0

---------------------------------------------------------------
Mark Schulman					 (407) 661-8374
Cincinnati Bell Information Systems	  att!auxnj!icepit!mark
					att!auxnj!crescent!mark
---------------------------------------------------------------



