/************************************************************************
windrv.c        -       Test stub for AUTOSCREEN functions

Programmer      -       E.J.Pugh, FIAP

Copyright       -       (C) Edward James Pugh, 7-Aug-1991.
*************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include "ibmpc.h" /* PC specific */

#define ON 1

/* declare the public variables required to implement the system */

extern Thread_t *MAINTHREAD; /* The main thread to which processes
				are added.  This will be instantiated
				in our main() function */

extern Window_t *ACTWINDOW;  /* the active window structure */

extern Window_t *CURWINDOW;  /* used by output routines */

extern int QUIT_PROGRAM;     /* each time GetEvent is called, this variable
				is checked to see if any bits are set. If
				any are, then an EXIT_PROGRAM event is
				returned to the active thread.
				This variable is made PUBLIC for the benefit
				of those processes that do not call the
				Event Manager - it enables a standard means
				by which a user exit request can be detected.
				The programmer is responsible for setting
				bits in this variable.
				*/

extern DateType_s DATETYPE; /* in dialogue.c - ENG, USA or JAP */
static DateType_s tdate = ENG; /* temporary resevoir for DATETYPE setting */
extern void (*DO_HELP_FUNCTION)(void); /* in input.c */
extern BOOLEAN HELP_ON; /* in input.c */
extern unsigned HELP_STACK_SIZE; /* in input.c */
extern Border_t S_BORDER, D_BORDER;

/* function prototypes */

/* Threads */

/* Objects options */
void check_box(void);
void show_settings(void);
void mixed_objects(void);

void date_format(void);
void do_dialogues(void);

void MyHelp(void);
void DemoThreads(void);
void threads(void);

/* Quit options */
void myquit(void);

/* Support functions */
void main(void);

int GenAccept(Dialogue_t *data);

void ShowHelp(Window_t *window);

void task1(void);
void task2(void);
void task3(void);
void task4(void);
void task5(void);
void sleep(void);
void bounceletter(void);


Option_t Objects[] = {
	{ "@Check Box ...", ON, check_box, 800},
		/* AUTOSCREEN uses the @ character internally
		to denote a Hot Key */
	{ "@Variable Settings", ON, show_settings, 800},
	{ "@Mixed Objects ...", ON, mixed_objects, 800},
	{ "Date @Format ...", ON, date_format, 800},
	{ "@Dialogue Boxes ...", ON, do_dialogues, 800},
	{ "."},
		/* AUTOSCREEN interprets a single '.' as a
		menu division line */
	{ "@Help Window", ON, MyHelp, 800},
	{ NULL }};

Option_t Threads[] = {
	{ "@Thread Demo", ON, DemoThreads, 800},
	{ "Thread@s Demo", ON, threads, 800},
	{ NULL }};

Option_t Quit[] = {
	{ "@Quit", ON, myquit, 800},
	{ NULL }};

Menu_t MainMenu[] = {
	{ " @Objects ", Objects},
	{ " @Threads ", Threads},
	{ " @Quit ", Quit},
	{ NULL }};

Button_t Buttons[] = {
	{ "@Cancel", ON, CANCELfunc},
	{ "Co@ntinue", ON, CONTINUEfunc}};

int var1 = 3;
int temp1 = 3;

#define SWMSG "The current SWITCH setting is for a value of %d\n\
and has a temporary value of %d\n", var1, temp1

int var2 = 3;
int temp2 = 3;

#define CHMSG "The current CHECK setting is for a value of %d\n\
and has a temporary value of %d\n\n", var2, temp2


/*************************************************************************
main            -       main()

Description     -       Main control function.

Returns         -       NOTHING
**************************************************************************/
void    main(void)
{
Window_t *menubar;
Event_t *event;

InitUI(-1); /* select the best video mode */


DO_HELP_FUNCTION = MyHelp;
HELP_ON = TRUE;

/* create the menu title bar */
menubar = NewMenuBar(MainMenu, MYATTRIB(WHITE, RED));

/* create a window based thread */
MAINTHREAD = NewThread(WINDOW);

/* and open it */
OpenWindow(menubar);

/* now we set up a continuous loop */
for(;;)
	{
	/* reject all events until user selects a new process */
	do
		event = GetEvent(ALLOW_MENU_BAR);
	while(event->Event != NEW_PROCESS);

	/* add the process to the MAINTHREAD */
	NewProcess(MAINTHREAD, event->TgtProcess, event->StackSize);

	/* and launch the thread */
	LaunchThread(MAINTHREAD);

	/* control returns here when all processes have ended */

	if(QUIT_PROGRAM)
		break;
	/* otherwise we simply continue */
	} // end for loop
/* clear up */
free(MAINTHREAD->PList);
free(MAINTHREAD);
LeaveUI();
}

/*************************************************************************
do_dialogues    -       Do Dialogues

Description     -       Presents a number of mixed dialogue
			boxes for test entries
**************************************************************************/
void do_dialogues(void)
{
Window_t *window;
Event_t *event;
llnode_t *next = NULL;

window = NewWindow(SCREEN_W, "@Dialogue Boxes", 1, 38, 12, 73,
       MYATTRIB(WHITE,RED), &D_BORDER);

AddDBox(window, "@String: ", STRING_D,
NewDialogue(STRING_D, 40, GenAccept, 0, 0, NULL, FALSE),
2, 19, 20);

AddDBox(window, "@Int: ", INT_D,
NewDialogue(INT_D, 6, GenAccept, 1, 0, NULL, FALSE),
5, 19, 5);

AddDBox(window, "@UInt: ", INT_D,
NewDialogue(INT_D, 6, GenAccept, 0, 0, NULL, FALSE),
5, 35, 5);

AddDBox(window, "@Number: ", NUMBER_D,
NewDialogue(NUMBER_D, 14, GenAccept, 1, 4, NULL, FALSE),
8, 19, 13);

AddDBox(window, "@Date :", DATE_D,
NewDialogue(DATE_D, 9, GenAccept, 0, 0, NULL, FALSE),
11, 19, 8);

AddButton(window, &Buttons[0], 14, 30);

window->Bounds = window->MinBounds;

window->Process = MAINTHREAD->CurProc;

OpenWindow(window);

for(;;)
	{
	event = DoObjects(window, next, ALLOW_MENU_BAR | ALLOW_ALTER_WINDOW);

	switch(event->Event)
	{
	case EXIT_PROGRAM:
	case BUTTON_VALUE:
	case CLOSE_WINDOW:
		goto end;
	case NEW_PROCESS:
		{
		llnode_t *process;

		next = event->Node;
		if(process = NewProcess(MAINTHREAD, event->TgtProcess,
			event->StackSize))
			{
			Yield(process);
			PopWindow(window);
			}
		}
	break;
	case CHANGE_WINDOW:
		{
		next = event->Node;
		Yield(event->Window->Process);
		PopWindow(window);
		}
	break;
	} // end switch
	} // end for loop
end:
free(KillWindow(window));
}

/*************************************************************************
date_format     -       Date Format

Description     -       Provides user with means to change the current
			date format setting via a switch box
**************************************************************************/
void date_format(void)
{
Window_t *window;
Event_t *event;
llnode_t *this_process = MAINTHREAD->CurProc;
llnode_t *next = NULL;
static Switch_t Switches[] = {
	{"@English Date Format", ON, &tdate, &DATETYPE, ENG},
	{"@USA Date Format", ON, &tdate, &DATETYPE, USA},
	{"@Japanese Date Format", ON, &tdate, &DATETYPE, JAP},
	{NULL}};


TOFF(Objects[3].State);

window = NewWindow(SCREEN_W, "Switch @Box", 16, 38, 22, 63,
       MYATTRIB(WHITE,RED), &D_BORDER);

AddSwitches(window, Switches, 17, 39);

AddButton(window, &Buttons[0], 21, 40);

AddButton(window, &Buttons[1], 21, 52);

window->Process = this_process;

OpenWindow(window);

for(;;)
	{
	event = DoObjects(window, next, ALLOW_MENU_BAR | ALLOW_ALTER_WINDOW);

	switch(event->Event)
	{
	case BUTTON_VALUE:
		goto end;
	break;
	case CLOSE_WINDOW:
		goto end;
	case NEW_PROCESS:
		{
		llnode_t *process;

		next = event->Node;
		if(process = NewProcess(MAINTHREAD, event->TgtProcess,
			event->StackSize))
			{
			Yield(process);

			PopWindow(window);
			}
		}
	break;
	case CHANGE_WINDOW:
		{
		next = event->Node;

		Yield(event->Window->Process);

		PopWindow(window);
		}
	break;
	case EXIT_PROGRAM:
		goto end;
	break;
	} // end switch
	} // end for loop
end:
TON(Objects[3].State);
free(KillWindow(window));
}

/*************************************************************************
check_box       -       Check Box

Description     -       Provides an example check box using the
			global temp2 and var2 entities
**************************************************************************/
void check_box(void)
{
Event_t *event;
llnode_t *next = NULL;
static CheckBox_t CheckBoxes[] = {
	{"Box @a", ON, &temp2, &var2, 1,},
	{"Bo@x b", ON, &temp2, &var2, 2,},
	{"Box @c", ON, &temp2, &var2, 4,},
	{NULL}};
Window_t *window;

window = NewWindow(SCREEN_W, "@Check Box", 16, 8, 22, 30,
       MYATTRIB(WHITE,RED), &D_BORDER);

AddCBoxes(window, CheckBoxes, 17, 15);

AddButton(window, &Buttons[0], 21, 9);

AddButton(window, &Buttons[1], 21, 20);

TOFF(Objects[0].State);
TOFF(Objects[2].State);

window->Process = MAINTHREAD->CurProc;

OpenWindow(window);

for(;;)
	{
	event = DoObjects(window, next, ALLOW_MENU_BAR | ALLOW_ALTER_WINDOW);
	switch(event->Event)
	{
	case BUTTON_VALUE:
	case CLOSE_WINDOW:
		goto end;
	case NEW_PROCESS:
		{
		llnode_t *process;

		next = event->Node;
		if(process = NewProcess(MAINTHREAD, event->TgtProcess,
			event->StackSize))
			{
			Yield(process);
			PopWindow(window);
			}
		}
	break;
	case CHANGE_WINDOW:
		{
		next = event->Node;
		Yield(event->Window->Process);

		PopWindow(window);
		}
	break;
	case EXIT_PROGRAM:
		goto end;
	} // end switch
	} // end for loop
end:
TON(Objects[0].State);
TON(Objects[2].State);
free(KillWindow(window));
}

/*************************************************************************
mixed_objects   -       Mixed Objects

Description     -       Provides for testing a number of different object
			types contained within the one window
**************************************************************************/
void mixed_objects(void)
{
Event_t *event;
llnode_t *next = NULL;
static Switch_t Switches[] = {
	{"Value = @1", ON, &temp1, &var1, 1},
	{"Value = @2", ON, &temp1, &var1, 2},
	{"Value = @3", ON, &temp1, &var1, 3},
	{NULL}};
static CheckBox_t CheckBoxes[] = {
	{"@Low Bit 0 Set", ON, &temp2, &var2, 1,},
	{"@Middle Bit 1 Set", ON, &temp2, &var2, 2,},
	{"@High Bit 2 Set", ON, &temp2, &var2, 4,},
	{NULL}};

Window_t *window;

window = NewWindow(SCREEN_W,"@Mixed Objects", 11, 38, 22, 74,
	MYATTRIB(WHITE,RED),&D_BORDER);
AddDBox(window, "@String: ", STRING_D,
NewDialogue(STRING_D, 40, GenAccept, 0, 0, NULL, FALSE),
13, 43, 15);

AddSwitches(window, Switches, 17, 39);

AddCBoxes(window, CheckBoxes, 17, 54);

AddButton(window, &Buttons[0], 21, 45);

AddButton(window, &Buttons[1], 21, 56);

TOFF(Objects[0].State);
TOFF(Objects[2].State);

window->Process = MAINTHREAD->CurProc;

OpenWindow(window); // open the window

for(;;)
	{
	event = DoObjects(window, next, ALLOW_MENU_BAR | ALLOW_ALTER_WINDOW);
	switch(event->Event)
	{
	case BUTTON_VALUE:
	case CLOSE_WINDOW:
		goto end;
	case NEW_PROCESS:
		{
		llnode_t *process;
		next = event->Node;

		if(process = NewProcess(MAINTHREAD, event->TgtProcess,
			event->StackSize))
			{
			Yield(process);
			PopWindow(window);
			}
		}
	break;
	case CHANGE_WINDOW:
		{
		next = event->Node;
		Yield(event->Window->Process);

		PopWindow(window);
		}
	break;
	case EXIT_PROGRAM:
		goto end;
	} // end switch
	} // end for loop
end:
TON(Objects[0].State);
TON(Objects[2].State);
free(KillWindow(window));
}

/*************************************************************************
show_settings           -       Show Settings

Description             -       Example use of wprintf function
*************************************************************************/
void show_settings(void)
{
Event_t *event;
Window_t *window;

window = NewWindow(SCREEN_W, "@Window", 5, 10, 15, 70,MYATTRIB(WHITE, BLUE),
	&S_BORDER);

window->Process = MAINTHREAD->CurProc;
OpenWindow(window);
wprintf(window, FALSE, SWMSG);
wprintf(window, FALSE, CHMSG);
for(;;)
	{
	event = GetEvent(ALLOW_MENU_BAR | ALLOW_ALTER_WINDOW);
	if(event->Event == CHANGE_WINDOW)
		{
		Yield(event->Window->Process);
		PopWindow(window);
		wprintf(window, FALSE, SWMSG);
		wprintf(window, FALSE, CHMSG);
		}
	else if(event->Event == ALTER_WINDOW)
		{
		switch(event->RetValue)
			{
			case 0: // nothing happened
			case 1: // a move occurred, but no sizing
			break;
			case 2: // sizing occurred
			case 3: // move and sizing occurred
				{
				/* reposition the window cursor in the
				top left hand corner to redisplay
				window contents */
				wprintf(window, FALSE, SWMSG);
				wprintf(window, FALSE, CHMSG);
				}
			break;
			}
		}
	else if(event->Event == NEW_PROCESS)
		{
		llnode_t *process;

		if(process = NewProcess(MAINTHREAD, event->TgtProcess,
			event->StackSize))
			{
			Yield(process);
			PopWindow(window);
			wprintf(window, FALSE, SWMSG);
			wprintf(window, FALSE, CHMSG);
			}
		}
	else if(event->Event == CLOSE_WINDOW)
			{
			free(KillWindow(window));
			return;
			}
	else if(event->Event == EXIT_PROGRAM)
			{
			free(KillWindow(window));
			return;
			}
	}
}

/**************************************************************************
myquit          -       My Quit Function

Description     -       Sets QUIT_PROGRAM low bit which will be used
			to exit program
***************************************************************************/
void myquit(void)
{
QUIT_PROGRAM |= 1;
}

/**************************************************************************
GenAccept       -       General Acceptance Function

Description     -       Simply returns -1 to indicate no fault in
			supplied Dialogue buffer
**************************************************************************/
int GenAccept(Dialogue_t *data)
{
return(-1);
}

/**************************************************************************
MyHelp          -       My Help

Description     -       A simple help window
***************************************************************************/
void MyHelp(void)
{
Window_t *window;
Event_t *event;

HELP_ON = FALSE;
TOFF(Objects[6].State);

window = NewWindow(SCREEN_W, "QUICK @HELP", 2, 0, 10, 79,
MYATTRIB(WHITE, BLUE), &S_BORDER);
window->Process = MAINTHREAD->CurProc;
OpenWindow(window);
ShowHelp(window);
for(;;)
	{
	event = GetEvent(ALLOW_MENU_BAR | ALLOW_ALTER_WINDOW);
	if(event->Event == CHANGE_WINDOW)
		{
		Yield(event->Window->Process);
		PopWindow(window);
		}
	else if(event->Event == ALTER_WINDOW)
		{
		switch(event->RetValue)
			{
			case 0: // nothing happened
			case 1: // a move occurred, but no sizing
			break;
			case 2: // sizing occurred
			case 3: // move and sizing occurred
				{
				/* re display */
				ShowHelp(window);
				}
			break;
			}
		}
	else if(event->Event == NEW_PROCESS)
		{
		llnode_t *process;

		if(process = NewProcess(MAINTHREAD, event->TgtProcess,
			event->StackSize))
			{
			Yield(process);
			PopWindow(window);
			}
		}
	else if(event->Event == CLOSE_WINDOW)
		goto end;
	else if(event->Event == EXIT_PROGRAM)
		goto end;
	}
end:
free(KillWindow(window));

TON(Objects[6].State);
HELP_ON = TRUE;
}

/*************************************************************************
ShowHelp        -       Show Help

Description     -       Uses wprintf to diplay a brief help note in
			the given window
**************************************************************************/
void ShowHelp(Window_t *window)
{
wprintf(window, FALSE,
"Use ALT + letter to access menu titles or active options\n");
wprintf(window, FALSE,
"Use SHIFT+ALT+letter to change to a process window\n");
wprintf(window, FALSE,
"F10 closes the active process window\n");

wprintf(window, FALSE,
"F6 moves between process windows\n");
wprintf(window, FALSE,
"F9 moves and resizes the active window \
in conjunction with mouse or Grey keys.\n");
wprintf(window, FALSE,
"Move between window objects using Grey keys or mouse.\n");
wprintf(window, FALSE,
"Date separator can be space, '-', '/', or '.', on its own for system.");
}

/**************************************************************************
DemoThreads     -       Demonstrate process threads

Description     -       Instantiates a new thread of NEXT type
			and adds three processes to it.

			Launches the thread and then returns.
**************************************************************************/
void DemoThreads(void)
{
Window_t *window;
Event_t *event;

if(window = NewWindow(SCREEN_W, "THREAD DEMONSTRATION", 3, 17, 17,
	48, MYATTRIB(BLACK, GREEN), &D_BORDER))
	{
	Thread_t *mythread;

	OpenWindow(window);
	window->Process = MAINTHREAD->CurProc;
	for(;;)
		{
		if(mythread = NewThread(NEXT))
			{
			ClearWindow();
			NewProcess(mythread, task1, 800);
			NewProcess(mythread, task2, 800);
			NewProcess(mythread, task3, 800);
			NewProcess(mythread, task4, 800);
			NewProcess(mythread, task5, 800);
			LaunchThread(mythread);
			free(mythread->PList);
			free(mythread);
			}
		window->CursPosn.Row = 16;
		window->CursPosn.Col = 21;
		wprintf(window, FALSE, "Any key to continue...");
		event = GetEvent(0);
		if(event->Event == CLOSE_WINDOW)
			break;
		if(event->Event == ASCII_KEY)
			if(event->Input == '\033')
				break;
		}
	free(KillWindow(window));
	}
}

void task1(void)
{
char *string = "*Simulating";
char *ch;
Curs_t cposn;

ch = &string[10];
PosnCurs(14, 21);
SaveCurs(&cposn);
while(*ch != '*')
	{
	ResCurs(&cposn);
	PutChar(*ch, MYATTRIB(BLACK, GREEN));
	CursUp();
	SaveCurs(&cposn);
	sleep();
	Yield(NULL);
	--ch;
	}
}

void task2(void)
{
char *string = "five different";
char *ch;
Curs_t cposn;

ch = string;
PosnCurs(7, 26);
SaveCurs(&cposn);
while(*ch)
	{
	ResCurs(&cposn);
	PutChar(*ch, MYATTRIB(BLACK, GREEN));
	CursR();
	SaveCurs(&cposn);
	sleep();
	Yield(NULL);
	++ch;
	}

}

void task3(void)
{
char *string = "tasks";
char *ch;
Curs_t cposn;

ch = string;
PosnCurs(9, 31);
SaveCurs(&cposn);
while(*ch)
	{
	ResCurs(&cposn);
	PutChar(*ch, MYATTRIB(BLACK, GREEN));
	CursR();
	SaveCurs(&cposn);
	sleep();
	Yield(NULL);
	++ch;
	}

}

void task4(void)
{
char *string = "*running at the";
char *ch;
Curs_t cposn;

ch = &string[14];
PosnCurs(11, 39);
SaveCurs(&cposn);
while(*ch != '*')
	{
	ResCurs(&cposn);
	PutChar(*ch, MYATTRIB(BLACK, GREEN));
	CursL();
	SaveCurs(&cposn);
	sleep();
	Yield(NULL);
	--ch;
	}

}

void task5(void)
{
char *string = "same time.";
char *ch;
Curs_t cposn;

ch = string;
PosnCurs(5, 43);
SaveCurs(&cposn);
while(*ch)
	{
	ResCurs(&cposn);
	PutChar(*ch, MYATTRIB(BLACK, GREEN));
	CursDn();
	SaveCurs(&cposn);
	++ch;
	sleep();
	Yield(NULL);
	}

}

void sleep(void)
{
int n;

for(n = 0; n < 3000; n++);
}

static int count = 0;
static Window_t *TWINDOW;
static int STOPTHREADS = FALSE;
static Thread_t *MYTHREAD;

#define MAX 26
#define NE 1
#define NW 2
#define SW 3
#define SE 4

static int DIRECTION = SE;

void threads(void)
{
llnode_t *process;
char *msg1 = "\tPress a key to start a new thread.  [ESC] to Quit.\n";
char *msg2 = "\tFreeze action with Grey Key -- restart with any other.\n";
if(!(TWINDOW = NewWindow(SCREEN_W, "THREAD DEMO", 3, 5, 23,
	75, MYATTRIB(BLACK, GREEN), &D_BORDER)))
	return;
OpenWindow(TWINDOW);
wprintf(TWINDOW, FALSE, msg1);
wprintf(TWINDOW, FALSE, msg2);
PosnCurs(13, 40);
MYTHREAD = NewThread(PREV);
NewProcess(MYTHREAD, bounceletter, 800);
LaunchThread(MYTHREAD);
count = 0;
STOPTHREADS = FALSE;
free(MYTHREAD->PList);
free(MYTHREAD);
free(KillWindow(TWINDOW));
}

void bounceletter(void)
{
Curs_t posn;
char ID;
int move;

if(count == MAX) return;
ID = (char)('A' + count);
++ count;
switch(DIRECTION)
	{
	case NE: move = SW; //SE;
	break;
	case SW: move = NE; //NW;
	break;
	case SE: move = NW; //NE;
	break;
	case NW: move = SE; //SW;
	break;
	}
SaveCurs(&posn);
for(;;)
	{
	fflush(stdin);
	ResCurs(&posn);
	PutChar(' ', TWINDOW->Attrib);
	update:
	switch(move)
		{
		case NE:
			{
			if(((int)posn.Row > TWINDOW->Bounds.TRow + 2) &&
			((int)posn.Col < TWINDOW->Bounds.BCol - 1))
				{
				posn.Row --;
				posn.Col ++;
				}
			else
				{
				if(((int)posn.Row == TWINDOW->Bounds.TRow + 2) &&
					((int)posn.Col == TWINDOW->Bounds.BCol - 1))
					move = SW;
				else if(((int)posn.Col == TWINDOW->Bounds.BCol - 1))
					move = NW;
				else
					move = SE;
				goto update;
				}
			}
		break;
		case SE:
			{
			if(((int)posn.Row < TWINDOW->Bounds.BRow - 1) &&
			((int)posn.Col < TWINDOW->Bounds.BCol - 1))
				{
				posn.Row ++;
				posn.Col ++;
				}
			else
				{
				if(((int)posn.Row == TWINDOW->Bounds.BRow - 1) &&
				((int)posn.Col == TWINDOW->Bounds.BCol - 1))
					move = NW;
				else if(((int)posn.Col == TWINDOW->Bounds.BCol - 1))
					move = SW;
				else
					move = NE;
				goto update;
				}
			}
		break;
		case SW:
			{
			if(((int)posn.Row < TWINDOW->Bounds.BRow - 1) &&
			((int)posn.Col > TWINDOW->Bounds.TCol + 1))
				{
				posn.Row ++;
				posn.Col --;
				}
			else
				{
				if(((int)posn.Row == TWINDOW->Bounds.BRow - 1) &&
				((int)posn.Col == TWINDOW->Bounds.TCol + 1))
					move = NE;
				else if(((int)posn.Col == TWINDOW->Bounds.TCol + 1))
					move = SE;
				else
					move = NW;
				goto update;
				}
			}
		break;
		case NW:
			{
			if(((int)posn.Row > TWINDOW->Bounds.TRow + 2) &&
			((int)posn.Col > TWINDOW->Bounds.TCol + 1))
				{
				posn.Row --;
				posn.Col --;
				}
			else
				{
				if(((int)posn.Row == TWINDOW->Bounds.TRow + 2) &&
				((int)posn.Col == TWINDOW->Bounds.TCol + 1))
					move = SE;
				else if(((int)posn.Col == TWINDOW->Bounds.TCol + 1))
					move = NE;
				else
					move = SW;
				goto update;
				}
			}
		break;
		} // end switch
	DIRECTION = move;
	ResCurs(&posn);
	PutChar(ID, TWINDOW->Attrib);
	if(kbhit())
		{
		Event_t *event;

		event = GetEvent(NO_FLUSH_KEYBD);
		if( (event->Event == CLOSE_WINDOW) ||
		((event->Event == ASCII_KEY) && (event->Input == '\033')) )
			STOPTHREADS = TRUE;
		else
			NewProcess(MYTHREAD, bounceletter, 800);
		}
	Yield(NULL);
	if(STOPTHREADS == TRUE)
		return;
	} // end for loop
}
