[comp.windows.x] Making X run under Suntools

dana@faline.UUCP (05/18/87)

Hi,
	To all of you who wish to get X running under suntools, here's
the two files needed for libsun and an updated CHANGES file.  I am
posting both files (events.c and initial.c) because there seem to
be enough versions running around that a context diff may not be
useful.  We have this running on Sun 2's and 3's running 3.2.

To use:
	Make a new Xsun using these files and -DRAW_KBD -DSUNTOOLS.
In suntools, give the command "overview -w Xsun 0 0".  This should
bring up an xterm window, use as normal.  In our local version, we
have changed initial.c to bring up xtools instead of xterm, an easy
change.

	Any problems, send me mail.
	
	
				Dana Chee
				MRE 2Q-250
				(201) 829-4488
				dana@thumper.bellcore.com

############################################################
#
# To extract the files from this shell archive file
# enter the command
#
# sh filename
# 
# Do not use csh
# The files will be extracted automatically
#
############################################################

echo "Extracting CHANGES"
cat << \===CHANGES=== > CHANGES
17 July	86	David C. Martin		(dcmartin@ingres)
 font.c 	Now reads in Sun vfont format files, fixed handling of 
		variable-width font widths.
 text.c		Fixed display of variable-width fonts.

17 July 86	Andrew Cherenson	(andrew@kim)
 put.c		Check pixmap type to see if it should be inverted when 
		displayed.
 tile.c		same
 Xsun.h		Added macro to support above changes.

18 July 86	Jordan Hubbard		(jkh@opal)
 fill.c		Patched invalid stencil in pixfill (xcf fix)
 		fixed invalid argument to pr_stencil

20 July 86	Ed James		(edjames@cory.berkeley.edu)
 fill.c		Re-fixed the xcf patch.  Now handles clipping to 
		windows properly.

21 July 86	Andrew Cherenson	(andrew@kim)
 font.c		Added check of widths of 'a' and 'i' before deciding 
		if a font is fixed-width or not.
		(changed, see next entry.)

25 July 1986	David C. Martin		(dcmartin@ingres)
 font.c		Changed algorithm to determine if a font is fixedwidth and
		changed all calls to Xalloc() to malloc() to get NULLs when
		ENOMEM.  Added code to free all sub-structures of FontPriv
		ptr in StrikeToPixfont().
 text.c		re-fixed diplay of variable-width fonts (TextMask)
 textutil.c	(should be 17 July) returns correct width of font

25 July 1986	Beorn Johnson, XCF	(beorn@scam)
 cursor.c	Added necessary call to change hardware mouse location
		in the mouse movement subroutine.  Now 'XWarpMouse' should
		work.

25 July 86	Andrew Cherenson	(andrew@kim)
 font.c		Changed LoadVFont to properly determine the baseline.

27 July 86	David C. Martin		(dcmartin@ingres)
 font.c		Now handles variable width/height vfont files correctly.
 text.c		removed debugging statements (#ifdef DEBUG)
 textutil.c	modifications to TextWidth() and CharWidth() to check for
		invalid characters when determining width.

28 July 86	Fred Douglis		(douglis@kim)
 util.c		Added real SoundBell() routine.  Note that /dev/bell must
		exist.

31 July 86	Ed James		(edjames@eros)
 font.c		Fixed the missing characters on the large fonts.

13 August 86	Beorn Johnson, XCF	(beorn@scam)
 util.c		Wrote SetVideo() routine.  Blanking screen saver now works.

17 August 86	Beorn Johnson, XCF	(beorn@scam)
 events.c	Fixed the "stuck in caps-lock mode" bug and caps-lock
 initial.c	toggling.

26 August 86	Beorn Johnson, XCF	(beorn@scam)
 Xsun.h		Made cursors perform to spec.  May have trouble on color suns.
 cursor.c

26 August 86	Beorn Johnson, XCF	(beorn@scam)
 font.c		De-allocates font data properly.

30 Sept 86	Andrew Cherenson (andrew@kim), Adam de Boor (deboor@buddy)
 bitpix.c	Changed MakePixmap to create color pixmaps.

14 October 86	David C. Martin (dcmartin@ingres)
 cursor.c	Fixed call to pr_stencil() in DisplayCursor().

30 October 86	Adam de Boor (deboor@buddy)
 tile.c		Implemented filled polygon function.

 3 November 86	Paul R Borman (prb@umn-rei-uc.arpa)
 events.c	Added code to allow access to the raw sun keyboard
 initial.c	This allows access to all the function keys
 lk201.h	Remove the #define RAW_KBD in lk201.h if you do not
		want raw access.
		
26 January 87	Andrew Cherenson (andrew@arpa)
 events.c	Fixed bug in converting an event timestamp from timeval
		format to X 10ms format (in ConvertEvent).

05 Feb 1987	Paul R Borman (prb@umn-rei-uc.arpa)
 events.c	Fixed the RAW_KBD code, added mouse acceleration and
 initial.c	added a SUNTOOLS option which allows better use of X under
		control of overivew -w.  Use "overview -w Xsun 0 0" A
		<LEFT><L2> will get you back to suntools.  Note that
		state_mask in ../X/input.c must be made non-static for
		the new RAW_KBD code to work.  One extra hint.  If you
		get stuck in SHIFT-LOCK mode for no apperant reason
		press down both shiftkeys.  Sometimes a UP event does not
		come in and this will correct the problem.

14 February 87	Beorn Johnson (beorn@scam)
 cursor.c	Fixed cursor display for cursor with no mask

23 March 1987	Adam de Boor (deboor@buddy)
 cursor.c	fixed cursor display so doesn't leave ghosts on left
		edge of screen.

18 May 1987	Dana Chee (chee@thumper.bellcore.com)
 initial.c	added remove/insert window to stopme to allow overview
		icon to display when in suntools mode.  Also reset
		state mask upon return to X to eliminate the extra
		MetaMask state caused by the M-L2 which shifted to
		suntools.

===CHANGES===
# ----------
echo "Extracting events.c"
cat << \===events.c=== > events.c
#ifndef lint
static char *rcsid_events_c = "$Header: events.c,v 10.2 86/02/01 16:20:48 tony Rel $";
#endif	lint
#ifdef	sun
/*
 * The Sun X drivers are a product of Sun Microsystems, Inc. and are provided
 * for unrestricted use provided that this legend is included on all tape
 * media and as a part of the software program in whole or part.  Users
 * may copy or modify these drivers without charge, but are not authorized
 * to license or distribute them to anyone else except as part of a product or
 * program developed by the user.
 * 
 * THE SUN X DRIVERS ARE PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND
 * INCLUDING THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE
 * PRACTICE.
 *
 * The Sun X Drivers are provided with no support and without any obligation
 * on the part of Sun Microsystems, Inc. to assist in their use, correction,
 * modification or enhancement.
 * 
 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THE SUN X
 * DRIVERS OR ANY PART THEREOF.
 * 
 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
 * or profits or other special, indirect and consequential damages, even if
 * Sun has been advised of the possibility of such damages.
 * 
 * Sun Microsystems, Inc.
 * 2550 Garcia Avenue
 * Mountain View, California  94043
 */

#ifndef	lint
static char sccsid[] = "@(#)events.c 1.7 87/02/05 Copyright 1986 Sun Micro";
#endif

/*-
 * Copyright (c) 1986 by Sun Microsystems,  Inc.
 */

/*
 *	ToDo:
 *		Up events on regular keys
 */

#include	<stdio.h>
#include	<sys/types.h>
#include	<sys/time.h>
#include	<sys/errno.h>
#include	"../X/X.h"
#include	"../X/vsinput.h"
#include	"../X/Xdev.h"
#include	<sundev/kbd.h>
#ifdef	RAW_KBD
#include	<sundev/kbio.h>
#endif
#include	<sunwindow/win_input.h>
#ifdef	SUNTOOLS
extern char *suntools;
#include	<sys/signal.h>
#endif

#ifndef	event_is_ascii
#define	event_is_ascii(e) (e->ie_code >= ASCII_FIRST && e->ie_code <= ASCII_LAST)
#endif
#ifndef	event_is_meta
#define	event_is_meta(e) (e->ie_code >= META_FIRST && e->ie_code <= META_LAST)
#endif
/* Should be qevent.h */
#define	VSE_LEFT_BUTTON	0
#define	VSE_MIDDLE_BUTTON	1
#define	VSE_RIGHT_BUTTON	2
#define	NOT_A_KEY	9

extern int errno;
extern int vsdev;
extern DEVICE *CurrentDevice;

int sunthreshold = 0;
int sunaccel = 0;

/*ARGSUSED*/
ProcessInput(ev)
	register vsEvent *ev;
{
	/*NOTREACHED*/
}

#include "lk201.h"

#ifdef	RAW_KBD
extern unsigned state_mask;
extern struct kiockey sunkeymap[];

/*
 * Convert from a Sun event to an X event
 */
unsigned
ConvertEvent(se, xe)
struct inputevent *se;
vsEvent *xe;
{
    int key;
    unsigned kludgekey;
    /* Map the coordinates */
    xe->vse_x = se->ie_locx;
    xe->vse_y = se->ie_locy;
    /* Map the time stamps */
    xe->vse_time = (se->ie_time.tv_usec/10000 + se->ie_time.tv_sec * 100);
    /* Set direction */
    xe->vse_direction = (win_inputposevent(se) ? VSE_KBTDOWN : VSE_KBTUP);
    /* Sort out the event codes */

    if (se->ie_code >= VKEY_FIRSTSHIFT && se->ie_code <= VKEY_LASTSHIFT) {
	/*
	 * this makes ie_code between 0 and 0200 inclusive.
	 */
	se->ie_code -= VKEY_FIRSTSHIFT;
	key = SHIFTKEYS + se->ie_code;
    } else if (se->ie_code >= 0 && se->ie_code < 0200)
	key = sunkeymap[se->ie_code].kio_entry;
    else
	key = -1;

    kludgekey = 0;
    if (key >= 0) {
	xe->vse_device = VSE_DKB;
	xe->vse_type = VSE_BUTTON;

	/*
	 * First deal with special keycodes
	 */
	if (key & 0x80) {
		switch(key & 0xf0) {
		case SHIFTKEYS:
			/*
			 * The static count is keeping track of how many
			 * keys I have down for the given function.
			 * Only need to do this for shift and meta.
			 * On an up event I decrease the count.  If it is
			 * not the last one up then I convert to a down event
			 * which really won't do anything.  I should ignore
			 * the event, but this works.
			 * At odd times the sun keyboard gets confused and I
			 * miss an UP event.  This may get you stuck in
			 * shift mode.  I assume there is only 2 shift keys
			 * and only two meta keys.  If count ever goes above
			 * 2 I make it 2 again, assuming I have missed an up
			 * event.  If you get stuck in shifted mode, just his
			 * both shift keys and you should be fixed.
			 */
			switch(key & 0x0f) {
			case 11:
			case 14:
			case LEFTSHIFT:
			case RIGHTSHIFT: {
				static count;

				kludgekey = 0256;

				if (win_inputposevent(se)) {
					if (++count > 2)
						count = 2;
				} else if (--count > 0)
					xe->vse_direction = VSE_KBTDOWN;
				else if (count < 0)
					count = 0;
				break;
			    }
			/* LEFT/RIGHT key */
			case 9:
			default: {
				static count;

				kludgekey = 0261;

				if (win_inputposevent(se)) {
					if (++count > 2)
						count = 2;
				} else if (--count > 0)
					xe->vse_direction = VSE_KBTDOWN;
				else if (count < 0)
					count = 0;
				break;
			    }
			case 10:
			case 13:
			case CAPSLOCK:
			case SHIFTLOCK:
				kludgekey = 0260;
				break;
			case 12:
			case 15:
			case LEFTCTRL:
			case RIGHTCTRL:
				kludgekey = 0257;
				break;
			}
			break;
		case STRING:
			switch(key & 0xf) {
			default:
			case HOMEARROW:
				kludgekey = 0206;
				break;
			case UPARROW:
				kludgekey = 0252;
				break;
			case DOWNARROW:
				kludgekey = 0251;
				break;
			case LEFTARROW:
				kludgekey = 0247;
				break;
			case RIGHTARROW:
				kludgekey = 0250;
				break;
			}
			break;
		case RIGHTFUNC:
			kludgekey = RightKeys[key&0xf];
			break;
		case LEFTFUNC:
			kludgekey = LeftKeys[key&0xf];
			break;
		case TOPFUNC:
			kludgekey = TopKeys[key&0xf];
			break;
		case BOTTOMFUNC:
			kludgekey = BotKeys[key&0xf];
			break;
		case BUCKYBITS:
		case FUNNY:
		default:
			kludgekey = 0;
		}
	} else {
	/*
	 * Now deal with regular keys.
	 * Note, I look up the key in the shift/ctrl/caps tables
	 * in case the keys are not quite like a lk201.
	 * I assume that a regular key shifted/ctrled/caped is also a
	 * regular key.  This may be naive.
	 */
		if (key == '\033' /*ESC*/ )
			kludgekey = 0161;
		else if (key == '\b')
			kludgekey = 0162;
		else if (key == '\n')
			kludgekey = 0163;
		else if (key == '\r')
			kludgekey = 0275;
		else if (key == '\t')
			kludgekey = 0276;
		else if (key == '\006' /*ALT*/)
			kludgekey = 0245;
		else if (key == '\177' /*DEL*/)
			kludgekey = 0274;
		else if(state_mask & ControlMask)
			kludgekey = LK201[sunkeymap[se->ie_code+00200].kio_entry];
		else if(state_mask & ShiftMask)
			kludgekey = LK201[sunkeymap[se->ie_code+00600].kio_entry];
		else if(state_mask & ShiftLockMask)
			kludgekey = LK201[sunkeymap[se->ie_code+00400].kio_entry];
		else
			kludgekey = LK201[key];
	}
	xe->vse_key = kludgekey & 0377;
	kludgekey &= (~state_mask)&(ControlMask|ShiftMask);
    } else switch (se->ie_code) {
	case LOC_MOVE:
	    xe->vse_device = VSE_MOUSE;	 /* XXX - should query shift state here but ... */
	    xe->vse_type = VSE_MMOTION;
	    break;
	case MS_LEFT:
	    xe->vse_key = VSE_LEFT_BUTTON;
	    xe->vse_device = VSE_MOUSE;
	    xe->vse_type = VSE_BUTTON;
	    break;
	case MS_MIDDLE:
	    xe->vse_device = VSE_MOUSE;
	    xe->vse_type = VSE_BUTTON;
	    xe->vse_key = VSE_MIDDLE_BUTTON;
	    break;
	case MS_RIGHT:
	    xe->vse_key = VSE_RIGHT_BUTTON;
	    xe->vse_device = VSE_MOUSE;
	    xe->vse_type = VSE_BUTTON;
	    break;
	default:
	    xe->vse_key = NOT_A_KEY;
	    xe->vse_device = VSE_MOUSE;
	    xe->vse_type = VSE_BUTTON;
	    break;
    }
    return(kludgekey);
}

#define	INPBUFSIZE	128

/*
 * Read pending input events
 */
InputReader()
{
    struct inputevent sunevents[INPBUFSIZE];
    int         n, m;

    if ((n = read(vsdev, sunevents, INPBUFSIZE * sizeof sunevents[0])) < 0
	&& errno != EWOULDBLOCK) {
	/*
	 * Error reading events 
	 */
	/* XXX_DO_SOMETHING(); */
	return;
    }
    for (n /= sizeof sunevents[0], m = 0; m < n; m++) {
	vsEvent Xevent;

	unsigned kludgekey = ConvertEvent(&(sunevents[m]), &Xevent);

	if (Xevent.vse_type == VSE_MMOTION) {
	    if (sunthreshold && (sunaccel > 1)) {
		int dx = Xevent.vse_x - CurrentDevice->mouse->x;
		int dy = Xevent.vse_y - CurrentDevice->mouse->y;

		if (sunthreshold <= (dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy)) {
			dx = CurrentDevice->mouse->x + dx * sunaccel;
			dy = CurrentDevice->mouse->y + dy * sunaccel;
			if (dx < 0)
				Xevent.vse_x = 0;
			else if (dx >= CurrentDevice->width)
				Xevent.vse_x = CurrentDevice->width - 1;
			else
				Xevent.vse_x = dx;
			if (dy < 0)
				Xevent.vse_y = 0;
			else if (dy >= CurrentDevice->height)
				Xevent.vse_y = CurrentDevice->height - 1;
			else
				Xevent.vse_y = dy;
		}
	    }

	    SetCursorPosition((vsCursor *) &Xevent);	/* XXX - tacky */
	}

	Xevent.vse_key;

	if (Xevent.vse_type == VSE_MMOTION) {
	    register vsBox *b = CurrentDevice->mbox;
	    register vsCursor *m = CurrentDevice->mouse;
	    /*
	     * Has it left the box? 
	     */
	    if (m->y >= b->bottom || m->y < b->top ||
		m->x >= b->right || m->x < b->left) {
		    b->bottom = 0;
		    Deal_with_movement();
	    }
#ifdef	SUNTOOLS
	} else if (suntools &&
		   Xevent.vse_device == VSE_DKB &&
		   Xevent.vse_key == 0213 /* L2 */ &&
		   (state_mask & MetaMask)) {
		/*
		 * <META><L2> returns control back to suntools
		 * if X is running under overview
		 */
		stopme();
#endif
	} else if (Xevent.vse_key != NOT_A_KEY ||
			Xevent.vse_device != VSE_MOUSE) {
	    state_mask |= kludgekey;
	    Deal_with_input(&Xevent);
	    state_mask &= ~kludgekey;
	}
    }
}
#else
static int
SunToXKeyCode(s)
int s;
{
    register int ret = LK201[s&0177];
    char *c = "^.";
    char *f = ".";

    c[1] = (s&0177)|0100;
    f[0] = (s&0177);

    return(ret);
}

/*
 * Convert from a Sun event to an X event
 */
int
ConvertEvent(se, xe)
struct inputevent *se;
vsEvent *xe;
{
    static unsigned lstate_mask;

    /* Map the coordinates */
    xe->vse_x = se->ie_locx;
    xe->vse_y = se->ie_locy;
    /* Map the time stamps */
    xe->vse_time = (se->ie_time.tv_usec/10000 + se->ie_time.tv_sec * 100);
    /* Set direction */
    xe->vse_direction = (win_inputposevent(se) ? VSE_KBTDOWN : VSE_KBTUP);
    /* Sort out the event codes */
    if (event_is_ascii(se)) {
	/* ASCII keystroke */
	int key = SunToXKeyCode(se->ie_code);
	xe->vse_key = (key & 0377);
	xe->vse_device = VSE_DKB;
	xe->vse_type = VSE_BUTTON;
	lstate_mask = (lstate_mask & ~(ControlMask|MetaMask|ShiftMask))
	    | (key & (ControlMask|MetaMask|ShiftMask));
    } else if (event_is_meta(se)) {
	/* META keystroke - map to ASCII for now */
	int key = SunToXKeyCode(se->ie_code - META_FIRST + ASCII_FIRST) | MetaMask;
	xe->vse_key = (key & 0377);
	xe->vse_device = VSE_DKB;
	xe->vse_type = VSE_BUTTON;
	lstate_mask = (lstate_mask & ~(ControlMask|MetaMask|ShiftMask))
	    | (key & (ControlMask|MetaMask|ShiftMask));
    } else switch (se->ie_code) {
	case LOC_MOVE:
	    xe->vse_device = VSE_MOUSE;		/* XXX - should query shift state here but ... */
	    xe->vse_type = VSE_MMOTION;
	    break;
	case MS_LEFT:
	    xe->vse_key = VSE_LEFT_BUTTON;
	    xe->vse_device = VSE_MOUSE;
	    xe->vse_type = VSE_BUTTON;
	    if (xe->vse_direction == VSE_KBTUP)
		lstate_mask &= ~LeftMask;
	    else
	        lstate_mask |= LeftMask;
	    goto ShiftKeys;
	case MS_MIDDLE:
	    xe->vse_device = VSE_MOUSE;
	    xe->vse_type = VSE_BUTTON;
	    xe->vse_key = VSE_MIDDLE_BUTTON;
	    if (xe->vse_direction == VSE_KBTUP)
		lstate_mask &= ~MiddleMask;
	    else
	        lstate_mask |= MiddleMask;
	    goto ShiftKeys;
	case MS_RIGHT:
	    xe->vse_key = VSE_RIGHT_BUTTON;
	    xe->vse_device = VSE_MOUSE;
	    xe->vse_type = VSE_BUTTON;
	    if (xe->vse_direction == VSE_KBTUP)
		lstate_mask &= ~RightMask;
	    else
	        lstate_mask |= RightMask;
	    goto ShiftKeys;
	default:
	    xe->vse_key = NOT_A_KEY;
	    xe->vse_device = VSE_MOUSE;
	    xe->vse_type = VSE_BUTTON;
	    if (xe->vse_direction == VSE_KBTUP)
		lstate_mask &= ~ShiftLockMask;
	    else
	        lstate_mask |= ShiftLockMask;
ShiftKeys:
	    if (se->ie_shiftmask & SHIFTMASK)
		lstate_mask |= ShiftMask;
	    else
	    	lstate_mask &= ~ShiftMask;
	    if (se->ie_shiftmask & CTRLMASK)
		lstate_mask |= ControlMask;
	    else
		lstate_mask &= ~ControlMask;
#ifdef	META_SHIFT_MASK
	    if (se->ie_shiftmask & META_SHIFT_MASK)
		lstate_mask |= MetaMask;
	    else
		lstate_mask &= ~MetaMask;
#endif
	    break;
    }
    return (lstate_mask);
}

#define	INPBUFSIZE	128

/*
 * Read pending input events
 */
InputReader()
{
    struct inputevent sunevents[INPBUFSIZE];
    int         n, m;
    static int last_mask;

    if ((n = read(vsdev, sunevents, INPBUFSIZE * sizeof sunevents[0])) < 0
	&& errno != EWOULDBLOCK) {
	/*
	 * Error reading events 
	 */
	/* XXX_DO_SOMETHING(); */
	return;
    }
    for (n /= sizeof sunevents[0], m = 0; m < n; m++) {
	vsEvent Xevent, Sevent;
	int mask;

	mask = ConvertEvent(&(sunevents[m]), &Xevent);
	if (Xevent.vse_type == VSE_MMOTION) {
	    if (sunthreshold && (sunaccel > 1)) {
		int dx = Xevent.vse_x - CurrentDevice->mouse->x;
		int dy = Xevent.vse_y - CurrentDevice->mouse->y;

		if (sunthreshold <= (dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy)) {
			dx = CurrentDevice->mouse->x + dx * sunaccel;
			dy = CurrentDevice->mouse->y + dy * sunaccel;
			if (dx < 0)
				Xevent.vse_x = 0;
			else if (dx >= CurrentDevice->width)
				Xevent.vse_x = CurrentDevice->width - 1;
			else
				Xevent.vse_x = dx;
			if (dy < 0)
				Xevent.vse_y = 0;
			else if (dy >= CurrentDevice->height)
				Xevent.vse_y = CurrentDevice->height - 1;
			else
				Xevent.vse_y = dy;
		}
	    }
	    SetCursorPosition((vsCursor *) &Xevent);	/* XXX - tacky */
	}

	if (mask != last_mask) {
	    last_mask ^= mask;
	    Sevent.vse_device = VSE_DKB;
	    Sevent.vse_x = Xevent.vse_x;
	    Sevent.vse_y = Xevent.vse_y;
	    Sevent.vse_time = Xevent.vse_time;
	    if (last_mask & ShiftMask) {
		if (mask & ShiftMask)
		    Sevent.vse_direction = VSE_KBTDOWN;
		else
		    Sevent.vse_direction = VSE_KBTUP;
		Sevent.vse_key = 0256;
		Deal_with_input(&Sevent);
	    }
	    if (last_mask & ControlMask) {
		if (mask & ControlMask)
		    Sevent.vse_direction = VSE_KBTDOWN;
		else
		    Sevent.vse_direction = VSE_KBTUP;
		Sevent.vse_key = 0257;
		Deal_with_input(&Sevent);
	    }
	    if (last_mask & ShiftLockMask) {
		if (mask & ShiftLockMask)
		    Sevent.vse_direction = VSE_KBTDOWN;
		else
		    Sevent.vse_direction = VSE_KBTUP;
		Sevent.vse_key = 0260;
		Deal_with_input(&Sevent);
	    }
	    if (last_mask & MetaMask) {
		if (mask & MetaMask)
		    Sevent.vse_direction = VSE_KBTDOWN;
		else
		    Sevent.vse_direction = VSE_KBTUP;
		Sevent.vse_key = 0261;
		Deal_with_input(&Sevent);
	    }
	    last_mask = mask;
	}
	if (Xevent.vse_type == VSE_MMOTION) {
	    register vsBox *b = CurrentDevice->mbox;
	    register vsCursor *m = CurrentDevice->mouse;
	    /*
	     * Has it left the box? 
	     */
	    if (m->y >= b->bottom || m->y < b->top ||
		m->x >= b->right || m->x < b->left) {
		    b->bottom = 0;
		    Deal_with_movement();
	    }
#ifdef	SUNTOOLS
	} else if (suntools &&
		   Xevent.vse_device == VSE_DKB &&
		   Xevent.vse_key == 0302 /* A */ &&
		   (mask & ControlMask)) {
		stopme();
#endif
	} else if (Xevent.vse_key != NOT_A_KEY ||
			Xevent.vse_device != VSE_MOUSE)
	    Deal_with_input(&Xevent);
    }
}
#endif
#endif	sun

===events.c===
# ----------
echo "Extracting initial.c"
cat << \===initial.c=== > initial.c
#ifndef lint
static char *rcsid = "$Header: initial.c,v 10.4 86/02/01 16:21:01 tony Rel $";
#endif lint
#ifdef	sun
/*
 * The Sun X drivers are a product of Sun Microsystems, Inc. and are provided
 * for unrestricted use provided that this legend is included on all tape
 * media and as a part of the software program in whole or part.  Users
 * may copy or modify these drivers without charge, but are not authorized
 * to license or distribute them to anyone else except as part of a product or
 * program developed by the user.
 * 
 * THE SUN X DRIVERS ARE PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND
 * INCLUDING THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE
 * PRACTICE.
 *
 * The Sun X Drivers are provided with no support and without any obligation
 * on the part of Sun Microsystems, Inc. to assist in their use, correction,
 * modification or enhancement.
 * 
 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THE SUN X
 * DRIVERS OR ANY PART THEREOF.
 * 
 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
 * or profits or other special, indirect and consequential damages, even if
 * Sun has been advised of the possibility of such damages.
 * 
 * Sun Microsystems, Inc.
 * 2550 Garcia Avenue
 * Mountain View, California  94043
 */

#ifndef	lint
static char sccsid[] = "@(#)initial.c 1.4 87/02/05 Copyright 1986 Sun Micro";
#endif

/*-
 * Copyright 1985, Massachusetts Institute of Technology
 * Copyright (c) 1986 by Sun Microsystems,  Inc.
 */

/* initial.c	Routines to open & close display
 *
 *	OpenDisplay		Open it
 *	InitDisplay		Download it
 *	DisplayDead		Check if dead
 *	Allocate_space		Allocate some temporary storage
 *
 */

/*
 *	ToDo:
 *		Look in environment/defaults for programs to start
 */


#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <sun/fbio.h>
#include "Xsun.h"
#include <pixrect/pixrect_hs.h>
#include <sunwindow/rect.h>
#include <sunwindow/rectlist.h>
#include <sunwindow/pixwin.h>
#include <sunwindow/win_screen.h>
#include <sunwindow/win_struct.h>
#include <sunwindow/win_input.h>
#include <sundev/kbd.h>
#include <sundev/kbio.h>

extern int InputReader();

struct pixwin *Display;
struct pixrect *PixRect;
u_char InvPix[256];

short Sun_From_X_Op[] = {
    	PIX_CLR,			/* GXclear */
	PIX_SRC&PIX_DST,		/* GXand */
	PIX_SRC&PIX_NOT(PIX_DST),	/* GXandReverse */
	PIX_SRC,			/* GXcopy */
	PIX_NOT(PIX_SRC)&PIX_DST,	/* GXandInverted */
	PIX_DST,			/* GXnoop */
	PIX_SRC^PIX_DST,		/* GXxor */
	PIX_SRC|PIX_DST,		/* GXor */
	PIX_NOT(PIX_SRC)&PIX_NOT(PIX_DST), /* GXnor */
	PIX_NOT(PIX_SRC)^PIX_DST,	/* GXequiv */
	PIX_NOT(PIX_DST),		/* GXinvert */
	PIX_SRC|PIX_NOT(PIX_DST),	/* GXorReverse */
	PIX_NOT(PIX_SRC),		/* GXcopyInverted */
	PIX_NOT(PIX_SRC)|PIX_DST,		/* GXorInverted */
	PIX_NOT(PIX_SRC)|PIX_NOT(PIX_DST), /* GXnand */
	PIX_SET,			/* GXset */
};

int vsdev = -1;
#ifdef	SUNTOOLS
static int vsdevflags;
#endif
extern int errno;
DEVICE *CurrentDevice;

#define PARENT "WINDOW_GFX"
/* Open the display */
char *suntools;

#ifdef	RAW_KBD
struct kiockey	sunkeymap[01200];
#endif

/*ARGSUSED*/
OpenDisplay (devname)
	char *devname;
{
    struct screen sc;
    extern char *getenv();

    signal (SIGWINCH, SIG_IGN);
    suntools = getenv(PARENT);
    bzero((caddr_t) & sc, sizeof sc);
    if (*devname != '/')
	devname = "/dev/fb";
    strncpy(sc.scr_fbname, devname, SCR_NAMESIZE);
    if (suntools) {
	/* Running under "overview" */
	int         pfd;

	if ((pfd = open(suntools, 2, 0)) < 0) {
	    fprintf(stderr, "Can't open parent %s\n", suntools);
	    return (-1);
	}
	vsdev = win_getnewwindow();
	win_setlink(vsdev, WL_PARENT, win_fdtonumber(pfd));
	win_insert(vsdev);
	close(pfd);
    }
    else {
	/* Running alone */
	vsdev = win_screennew(&sc);
    }
    return (vsdev);
}

/* Do sun specific initialization */
#ifdef	SUNTOOLS
static int pid;
#define	XTERM	"xtools"
static char *args[] = {
    XTERM,
    0,
};

#include <sys/wait.h>

static SigChildHandler()
{
    register int dead;
    union wait status;

    while ((dead = wait3(&status, WNOHANG, NULL)) > 0) {
	if (dead == pid) {
	    DisplayDead();
	    exit(0);
	}
    }
}

static StartShell()
{
    char *xgeom = getenv("XGEOM");

    signal(SIGCHLD, SigChildHandler);
    if ((pid = fork()) == 0) {
	{
	    register int i = getdtablesize();

	    while (--i >= 0) {
		close(i);
	    }
	}
	open("/dev/null", 2, 0);
	dup(0);
	dup(0);
	{
	    /* Copy the environment for Setenv */
	    extern char **environ;
	    register int i = 0;
	    char      **envnew;

	    while (environ[i] != NULL)
		i++;

	    envnew = (char **) malloc(sizeof(char *) * (i + 1));
	    for (; i >= 0; i--)
		envnew[i] = environ[i];
	    environ = envnew;
	}
	{
#define	HOSTNAMESIZE	128
	    char        DisplayName[HOSTNAMESIZE];

	    gethostname(DisplayName, HOSTNAMESIZE);
	    strcat(DisplayName, ":0");
	    Setenv("DISPLAY=", DisplayName);
#undef	HOSTNAMESIZE
	}
	if (xgeom)
		args[1] = xgeom;
	execvp(XTERM, args);
	_exit(1);
    }
}
#endif

InitDisplay (info)
	register DEVICE *info;
{
    register int i;
    static vsCursor vsc;
    static vsBox vsm;
    static vsEventQueue vsq = {
			       NULL,
			       0,
			       0,
			       0,
    };
    struct screen sc;

    win_screenget(vsdev, &sc);
    info->height = sc.scr_rect.r_height;
    info->width = sc.scr_rect.r_width;
    if (suntools) {
	/* running under "overview" */
	win_setrect(vsdev, &sc.scr_rect);
    }
    {
	struct fbtype fbt;
	int         fd = open(sc.scr_fbname, O_RDWR, 0);

	if (fd < 0 || ioctl(fd, FBIOGTYPE, &fbt) < 0) {
	    if (fd < 0)
		fprintf(stderr, "Can't open fb %s\n", sc.scr_fbname);
	    else
	        fprintf(stderr, "Can't FBIOGTYPE on %s\n", sc.scr_fbname);
	    return (-1);
	}
	close(fd);
	info->id = fbt.fb_type + SUN_BASE;
	info->planes = fbt.fb_depth;
	info->entries = fbt.fb_cmsize;
    }
    Display = pw_open(vsdev);
    PixRect = Display->pw_pixrect;
    pw_reversevideo(Display,0,1);

    {
	struct inputmask im;
	struct kiockey kk;
	int	kbfd, i = 0;

	if ((kbfd = open("/dev/kbd", O_RDWR, 0)) >= 0) {
#ifdef	RAW_KBD
		struct kiockey ok;

		for (i = 0; i < 0200; ++i) {
			ok.kio_station =
			kk.kio_station = kk.kio_entry = i;

			ok.kio_tablemask = kk.kio_tablemask = 0;
			ioctl(kbfd, KIOCGETKEY, &ok);
			sunkeymap[i] = ok;
			/*
			 * If I am a shift key then remap past what
			 * kbd.c knows about so no mapping is done
			 * Only shift keys can be used the with UPMASK
			 * due to assumptions in sun's kernel
			 */
			if ((ok.kio_entry & 0xf0) == SHIFTKEYS) {
				switch (ok.kio_entry) {
				default:
				case SHIFTKEYS+CAPSLOCK:
					kk.kio_entry = SHIFTKEYS+10;
					break;
				case SHIFTKEYS+SHIFTLOCK:
					kk.kio_entry = SHIFTKEYS+13;
					break;
				case SHIFTKEYS+LEFTSHIFT:
					kk.kio_entry = SHIFTKEYS+11;
					break;
				case SHIFTKEYS+RIGHTSHIFT:
					kk.kio_entry = SHIFTKEYS+14;
					break;
				case SHIFTKEYS+LEFTCTRL:
					kk.kio_entry = SHIFTKEYS+12;
					break;
				case SHIFTKEYS+RIGHTCTRL:
					kk.kio_entry = SHIFTKEYS+15;
					break;
				}
			} else if (ok.kio_entry == BUCKYBITS+METABIT)
				kk.kio_entry = SHIFTKEYS+09;
			else if (ok.kio_entry == BUCKYBITS+SYSTEMBIT)
				kk.kio_entry = ok.kio_entry;
			ioctl(kbfd, KIOCSETKEY, &kk);

			ok.kio_tablemask = kk.kio_tablemask = CTRLMASK;
			ioctl(kbfd, KIOCGETKEY, &ok);
			sunkeymap[i+00200] = ok;

			ok.kio_tablemask = kk.kio_tablemask = CAPSMASK;
			ioctl(kbfd, KIOCGETKEY, &ok);
			sunkeymap[i+00400] = ok;

			ok.kio_tablemask = kk.kio_tablemask = SHIFTMASK;
			ioctl(kbfd, KIOCGETKEY, &ok);
			sunkeymap[i+00600] = ok;

			ok.kio_tablemask = kk.kio_tablemask = UPMASK;
			ioctl(kbfd, KIOCGETKEY, &ok);
			sunkeymap[i+01000] = ok;
			if ((kk.kio_entry & 0xf0) == SHIFTKEYS)
				ioctl(kbfd, KIOCSETKEY, &kk);
		}
#else
		kk.kio_tablemask = 0;
		kk.kio_entry = ~(SHIFTKEYS+CAPSLOCK);
		do {
			kk.kio_station = i++;
			ioctl(kbfd, KIOCGETKEY, &kk);
		} while ( i < 128 && kk.kio_entry != SHIFTKEYS+CAPSLOCK);
		if (kk.kio_entry == SHIFTKEYS+CAPSLOCK) {
			kk.kio_tablemask = UPMASK;
			ioctl(kbfd, KIOCSETKEY, &kk);
			kk.kio_tablemask = CTRLMASK;
			ioctl(kbfd, KIOCSETKEY, &kk);
			kk.kio_tablemask = CAPSMASK;
			ioctl(kbfd, KIOCSETKEY, &kk);
			kk.kio_tablemask = SHIFTMASK;
			ioctl(kbfd, KIOCSETKEY, &kk);
		}
#endif
		close(kbfd);
	}
	input_imnull(&im);
	im.im_flags = IM_ASCII | IM_META | IM_NEGEVENT;
	win_setinputcodebit(&im, LOC_MOVE);
	win_setinputcodebit(&im, MS_LEFT);
	win_setinputcodebit(&im, MS_MIDDLE);
	win_setinputcodebit(&im, MS_RIGHT);
#ifdef	RAW_KBD
	win_setinputcodebit(&im, VKEY_FIRSTSHIFT+9);
	win_setinputcodebit(&im, VKEY_FIRSTSHIFT+10);
	win_setinputcodebit(&im, VKEY_FIRSTSHIFT+11);
	win_setinputcodebit(&im, VKEY_FIRSTSHIFT+12);
	win_setinputcodebit(&im, VKEY_FIRSTSHIFT+13);
	win_setinputcodebit(&im, VKEY_FIRSTSHIFT+14);
	win_setinputcodebit(&im, VKEY_FIRSTSHIFT+15);
#else
	win_setinputcodebit(&im, SHIFT_CAPSLOCK);
#endif
	win_setinputmask(vsdev, &im, NULL, WIN_NULLLINK);
    }

#ifdef	SUNTOOLS
    if ((vsdevflags = fcntl(vsdev, F_GETFL, 0)) < 0)
	return(-1);
#endif
    if (fcntl(vsdev, F_SETFL, O_NDELAY) < 0)
	return (-1);
    {
	/* Following struct cannot be included from win_cursor.h */
	struct cursor {
		short	cur_xhot, cur_yhot;	/* offset of mouse position from shape*/
		int	cur_function;		/* relationship of shape to screen */
		struct	pixrect *cur_shape;	/* memory image to use */
		int	flags;			/* various options */
	
		short	horiz_hair_thickness;	/* horizontal crosshair height */
		int	horiz_hair_op;		/*            drawing op       */
		int	horiz_hair_color;	/*            color            */ 
		short	horiz_hair_length;	/*            width           */ 
		short	horiz_hair_gap;		/*            gap             */ 
	
		short	vert_hair_thickness;	/* vertical crosshair width  */
		int	vert_hair_op;		/*          drawing op       */
		int	vert_hair_color;	/*          color            */ 
		short	vert_hair_length;	/*          height           */ 
		short	vert_hair_gap;   	/*          gap              */ 
	} cs;
	static struct pixrect pr;

	cs.cur_xhot = cs.cur_yhot = cs.cur_function = 0;
	cs.flags = 0;
	cs.cur_shape = &pr;
	pr.pr_size.x = pr.pr_size.y = 0;
	win_setcursor(vsdev, &cs);
	win_setmouseposition(vsdev, info->width >> 1, info->height >> 1);
    }
    info->mouse = &vsc;
    info->mbox = &vsm;
    info->queue = &vsq;
    Define_input_handler(InputReader);
    SetUpInvPix();
    CurrentDevice = info;
#ifdef	SUNTOOLS
    if (suntools)
	    StartShell();
#endif
    return (0);
}

/* Check if display is dead */

DisplayDead ()
{
#ifdef	RAW_KBD
	int i;
	int kbfd = open("/dev/kbd", O_RDWR, 0);

	for (i = 0; i < 0200; ++i) {
		ioctl(kbfd, KIOCSETKEY, &sunkeymap[i]);
		if ((sunkeymap[i].kio_entry & 0xf0) == SHIFTKEYS)
			ioctl(kbfd, KIOCSETKEY, &sunkeymap[i+01000]);
		else if (sunkeymap[i].kio_entry == BUCKYBITS+METABIT)
			ioctl(kbfd, KIOCSETKEY, &sunkeymap[i+01000]);
	}
	close(kbfd);
#endif
	return(0);
}

/* the presumption here is that only one Allocate_space call is made/request */

#define ABUFSIZE 3072
static char ABuffer[3072];	/* random size buffer for allocate space */
caddr_t AllocateSpace (size)
	register int size;
{
	if (size < ABUFSIZE) return(ABuffer);
	errno = ENOMEM;
	return (NULL);
}

/* XXX - should be static data */
SetUpInvPix()
{
    register int i;

    for (i = 255; i >= 0; i--) {
	register int j = 1, k = 128, l = 8;

	while (l--) {
	    if ((i & j) != 0)
		InvPix[i] |= k;
	    j <<= 1;
	    k >>= 1;
	}
    }
}

#ifdef	SUNTOOLS
Setenv (var, value)
/*
   sets the value of var to be arg in the Unix 4.2 BSD environment env.
   Var should end with '='.
   (bindings are of the form "var=value")
   This procedure assumes the memory for the first level of environ
   was allocated using malloc.
 */
register char *var, *value;
{
    extern char **environ;
    register int index = 0;

    while (environ[index] != NULL) {
	if (strncmp(environ[index], var, strlen(var)) == 0) {
	    /* found it */
	    environ[index] = (char *) malloc(strlen(var) + strlen(value));
	    strcpy(environ[index], var);
	    strcat(environ[index], value);
	    return;
	}
	index++;
    }

    if ((environ = (char **) realloc(environ, sizeof(char *) *
				     (index + 2))) == NULL) {
	fprintf(stderr, "Setenv: malloc out of memory\n");
	exit(1);
    }

    environ[index] = (char *) malloc(strlen(var) + strlen(value));
    strcpy(environ[index], var);
    strcat(environ[index], value);
    environ[++index] = NULL;
}
#endif


#ifdef	SUNTOOLS
extern	int	state_mask;

stopme()
{
	extern long rootwindow;
	struct inputmask im;
	int win;

	if (!suntools)
		return;

	fcntl(vsdev, F_SETFL, vsdevflags);
	uninitdkb();
	win_remove(vsdev);
	kill(0, SIGSTOP);
	win_insert(vsdev);
	state_mask &= ~MetaMask;
	initdkb();
	fcntl(vsdev, F_SETFL, O_NDELAY);
	Draw_window(rootwindow, 1, 1);
}

static
initdkb()
{
	struct inputmask im;
	struct kiockey kk;
	int	kbfd, i = 0;

	if ((kbfd = open("/dev/kbd", O_RDWR, 0)) >= 0) {
#ifdef	RAW_KBD
		struct kiockey ok;

		for (i = 0; i < 0200; ++i) {
			ok.kio_station =
			kk.kio_station = kk.kio_entry = i;

			ok.kio_tablemask = kk.kio_tablemask = 0;
			ioctl(kbfd, KIOCGETKEY, &ok);
			/*
			 * If I am a shift key then remap past what
			 * kbd.c knows about so no mapping is done
			 * Only shift keys can be used the with UPMASK
			 * due to assumptions in sun's kernel
			 */
			if ((ok.kio_entry & 0xf0) == SHIFTKEYS) {
				switch (ok.kio_entry) {
				default:
				case SHIFTKEYS+CAPSLOCK:
					kk.kio_entry = SHIFTKEYS+10;
					break;
				case SHIFTKEYS+SHIFTLOCK:
					kk.kio_entry = SHIFTKEYS+13;
					break;
				case SHIFTKEYS+LEFTSHIFT:
					kk.kio_entry = SHIFTKEYS+11;
					break;
				case SHIFTKEYS+RIGHTSHIFT:
					kk.kio_entry = SHIFTKEYS+14;
					break;
				case SHIFTKEYS+LEFTCTRL:
					kk.kio_entry = SHIFTKEYS+12;
					break;
				case SHIFTKEYS+RIGHTCTRL:
					kk.kio_entry = SHIFTKEYS+15;
					break;
				}
			} else if (ok.kio_entry == BUCKYBITS+METABIT)
				kk.kio_entry = SHIFTKEYS+09;
			else if (ok.kio_entry == BUCKYBITS+SYSTEMBIT)
				kk.kio_entry = ok.kio_entry;
			ioctl(kbfd, KIOCSETKEY, &kk);

			ok.kio_tablemask = kk.kio_tablemask = UPMASK;
			ioctl(kbfd, KIOCGETKEY, &ok);
			if ((kk.kio_entry & 0xf0) == SHIFTKEYS)
				ioctl(kbfd, KIOCSETKEY, &kk);
		}
#else
		kk.kio_tablemask = 0;
		kk.kio_entry = ~(SHIFTKEYS+CAPSLOCK);
		do {
			kk.kio_station = i++;
			ioctl(kbfd, KIOCGETKEY, &kk);
		} while ( i < 128 && kk.kio_entry != SHIFTKEYS+CAPSLOCK);
		if (kk.kio_entry == SHIFTKEYS+CAPSLOCK) {
			kk.kio_tablemask = UPMASK;
			ioctl(kbfd, KIOCSETKEY, &kk);
			kk.kio_tablemask = CTRLMASK;
			ioctl(kbfd, KIOCSETKEY, &kk);
			kk.kio_tablemask = CAPSMASK;
			ioctl(kbfd, KIOCSETKEY, &kk);
			kk.kio_tablemask = SHIFTMASK;
			ioctl(kbfd, KIOCSETKEY, &kk);
		}
#endif
		close(kbfd);
	}
	input_imnull(&im);
	im.im_flags = IM_ASCII | IM_META | IM_NEGEVENT;
	win_setinputcodebit(&im, LOC_MOVE);
	win_setinputcodebit(&im, MS_LEFT);
	win_setinputcodebit(&im, MS_MIDDLE);
	win_setinputcodebit(&im, MS_RIGHT);
#ifdef	RAW_KBD
	win_setinputcodebit(&im, VKEY_FIRSTSHIFT+9);
	win_setinputcodebit(&im, VKEY_FIRSTSHIFT+10);
	win_setinputcodebit(&im, VKEY_FIRSTSHIFT+11);
	win_setinputcodebit(&im, VKEY_FIRSTSHIFT+12);
	win_setinputcodebit(&im, VKEY_FIRSTSHIFT+13);
	win_setinputcodebit(&im, VKEY_FIRSTSHIFT+14);
	win_setinputcodebit(&im, VKEY_FIRSTSHIFT+15);
#else
	win_setinputcodebit(&im, SHIFT_CAPSLOCK);
#endif
	win_setinputmask(vsdev, &im, NULL, WIN_NULLLINK);
}

static
uninitdkb()
{
	struct inputmask im;
	struct kiockey kk;
	int	kbfd, i = 0;

#ifdef	RAW_KBD
	if ((kbfd = open("/dev/kbd", O_RDWR, 0)) >= 0) {
		for (i = 0; i < 0200; ++i) {
			ioctl(kbfd, KIOCSETKEY, &sunkeymap[i]);
			if ((sunkeymap[i].kio_entry & 0xf0) == SHIFTKEYS)
				ioctl(kbfd, KIOCSETKEY, &sunkeymap[i+01000]);
			else if (sunkeymap[i].kio_entry == BUCKYBITS+METABIT)
				ioctl(kbfd, KIOCSETKEY, &sunkeymap[i+01000]);
		}
		close(kbfd);
	}
#endif
	input_imnull(&im);
	im.im_flags = IM_ASCII | IM_META | IM_NEGEVENT;
	win_unsetinputcodebit(&im, LOC_MOVE);
	win_unsetinputcodebit(&im, MS_LEFT);
	win_unsetinputcodebit(&im, MS_MIDDLE);
	win_unsetinputcodebit(&im, MS_RIGHT);
#ifdef	RAW_KBD
	win_unsetinputcodebit(&im, VKEY_FIRSTSHIFT+9);
	win_unsetinputcodebit(&im, VKEY_FIRSTSHIFT+10);
	win_unsetinputcodebit(&im, VKEY_FIRSTSHIFT+11);
	win_unsetinputcodebit(&im, VKEY_FIRSTSHIFT+12);
	win_unsetinputcodebit(&im, VKEY_FIRSTSHIFT+13);
	win_unsetinputcodebit(&im, VKEY_FIRSTSHIFT+14);
	win_unsetinputcodebit(&im, VKEY_FIRSTSHIFT+15);
#else
	win_unsetinputcodebit(&im, SHIFT_CAPSLOCK);
#endif
	win_setinputmask(vsdev, &im, NULL, WIN_NULLLINK);
}
#endif
#endif sun

===initial.c===
# ----------6