/* $Revision Header * Header built automatically - do not edit! *************
 *
 *	(C) Copyright 1991 by Olaf 'Olsen' Barthel & MXM
 *
 *	Name .....: Console.c
 *	Created ..: Monday 21-Jan-91 20:12
 *	Revision .: 1
 *
 *	Date            Author          Comment
 *	=========       ========        ====================
 *	14-Apr-91       Olsen           Rewrote double-dead-key support.
 *	05-Feb-91       Olsen           Added double-dead-key support.
 *	21-Jan-91       Olsen           Created this file!
 *
 * $Revision Header ********************************************************/

#include "TermGlobal.h"

	/* Use a simple address trick instead of the predefined
	 * address in amiga.lib.
	 */

#ifndef custom
#define custom (*(struct Custom *)0xDFF000)
#endif	/* custom */

	/* Local temporary buffer to be used for filtering control
	 * sequences from strings to be passed through to the buffer
	 * display. Length cannot exceed serial buffer size since
	 * the calling routine is always fed by ConProcess() and the
	 * like.
	 */

STATIC UBYTE	FatBuffer[SERBUFF_SIZE];

	/* StripSequence():
	 *
	 *	Strips a string from ESC and CSI introduced control
	 *	sequences.
	 */

STATIC LONG __regargs
StripSequence(UBYTE *Src,UBYTE *Dst,LONG Length)
{
	STATIC BYTE	HasESC = FALSE,HasCSI = FALSE;
	LONG		Size = 0;

	while(Length--)
	{
		if(*Src == 24 || *Src == 26)
		{
			HasESC = HasCSI = FALSE;

			Src++;

			continue;
		}

		if(*Src == '\r')
		{
			Src++;

			continue;
		}

		if(HasESC)
		{
			if(*Src == '[')
			{
				HasESC = FALSE;
				HasCSI = TRUE;
			}
			else
			{
				if(*Src >= '0')
					HasESC = FALSE;
			}

			Src++;

			continue;
		}

		if(HasCSI)
		{
			if(*Src >= '@')
				HasCSI = FALSE;

			Src++;

			continue;
		}

		switch(*Src)
		{
			case ESC:	HasESC = TRUE;
					Src++;
					continue;

			case CSI:	HasCSI = TRUE;
					Src++;
					continue;

			default:	if(!ValidTab[*Src])
					{
						Src++;

						continue;
					}

					break;
		}

		*Dst++ = *Src++;

		Size++;
	}

	return(Size);
}

	/* CaptureToFile(APTR Buffer,LONG Size):
	 *
	 *	Send data to the capture file.
	 */

VOID __regargs
CaptureToFile(APTR Buffer,LONG Size)
{
	if(FileCapture && Size)
	{
		struct MenuItem	*SomeItem;

		if(BufferWrite(FileCapture,Buffer,Size) != Size)
		{
			BlockWindows();

				/* We had an error writing to the file. */

			switch(MyEasyRequest(NULL,"Error writing to capture\nfile %s!","Ignore Error|Close & Discard File|Close File",CaptureName))
			{
				case 0:	break;

				case 1:	BufferClose(FileCapture);

					DeleteFile(CaptureName);

					if(SomeItem = FindThisItem(MEN_CAPTUREDISK))
						SomeItem -> Flags &= ~CHECKED;

					FileCapture = NULL;

					break;

				case 2:	BufferClose(FileCapture);

					if(SomeItem = FindThisItem(MEN_CAPTUREDISK))
						SomeItem -> Flags &= ~CHECKED;

					FileCapture = NULL;

					if(!GetFileSize(CaptureName))
						DeleteFile(CaptureName);
					else
						SetProtection(CaptureName,FIBF_EXECUTE);

					break;
			}

			ReleaseWindows();
		}
	}
}

	/* Capture(APTR Buffer,LONG Size):
	 *
	 *	Send the buffer contents to the display/disk capture.
	 */

VOID __regargs
Capture(APTR Buffer,LONG Size)
{
	struct MenuItem *SomeItem;

		/* Send the filtered data to the capture file. */

	if(Config . CaptureFilter)
		CaptureToFile(Buffer,Size);

		/* Store data in the log book. */

	StoreBuffer(Buffer,Size);

		/* Send the buffer to the printer. */

	if(PrinterCapture)
	{
		if(!FWrite(PrinterCapture,Buffer,Size,1))
		{
			BlockWindows();

			if(!MyEasyRequest(NULL,"Error writing to printer!","Ignore Error|Close Printer"))
			{
				Close(PrinterCapture);

				if(SomeItem = FindThisItem(MEN_CAPTUREPRINTER))
					SomeItem -> Flags &= ~CHECKED;

				PrinterCapture = NULL;
			}

			ReleaseWindows();
		}
	}
}

	/* HandleCursor(UBYTE Char):
	 *
	 *	This routine handles the somewhat strange behaviour of
	 *	an assorted set of keys in VT100 applications mode.
	 */

BYTE
HandleCursor(UBYTE Char)
{
	STATIC struct
	{
		UBYTE	 Char;
		UBYTE	*VanillaString;
		UBYTE	*ApplicationString;
	} Table[18] =
	{
		CUP,	"\033[A",	"\033OA",
		CDN,	"\033[B",	"\033OB",
		CFW,	"\033[C",	"\033OC",
		CBK,	"\033[D",	"\033OD",

		'0',	"0",		"\033Op",
		'1',	"1",		"\033Oq",
		'2',	"2",		"\033Or",
		'3',	"3",		"\033Os",
		'4',	"4",		"\033Ot",
		'5',	"5",		"\033Ou",
		'6',	"6",		"\033Ov",
		'7',	"7",		"\033Ow",
		'8',	"8",		"\033Ox",
		'9',	"9",		"\033Oy",
		'-',	"-",		"\033Om",
		'*',	"*",		"\033Ol",
		'.',	".",		"\033On",
		'\r',	"\r",		"\033OM"
	};

	BYTE i;

		/* Look for the cursor keys first. */

	for(i = 0 ; i < 4 ; i++)
	{
		if(Table[i] . Char == Char)
		{
			if(Config . CursorApp)
				SerWrite(Table[i] . ApplicationString,strlen(Table[i] . ApplicationString));
			else
				SerWrite(Table[i] . VanillaString,strlen(Table[i] . VanillaString));

			return(TRUE);
		}
	}

		/* Then take a look at the numeric pad. */

	for(i = 4 ; i < 18 ; i++)
	{
		if(Table[i] . Char == Char)
		{
			if(Config . NumApp)
				SerWrite(Table[i] . ApplicationString,strlen(Table[i] . ApplicationString));
			else
			{
				if(i == 17)
				{
					switch(Config . SendCR)
					{
						case CR_IGNORE:	break;

						case CR_ASCR:	SerWrite("\r",1);
								break;

						case CR_ASCRLF:	SerWrite("\r\n",2);
								break;
					}
				}
				else
					SerWrite(Table[i] . VanillaString,strlen(Table[i] . VanillaString));
			}

			return(TRUE);
		}
	}

	return(FALSE);
}

	/* DoBackspace():
	 *
	 *	Special function: perform backspace.
	 */

VOID
DoBackspace()
{
	Capture("\b",1);

	if(CursorX)
	{
		ClearCursor();

		CursorX--;

			/* If destructive, shift the remaining line
			 * one character to the right.
			 */

		if(Config . DestructiveBackspace)
		{
			BackupRender();

			SetBPen(RPort,0);

			if(Config . RasterEnabled)
				RasterEraseCharacters(1);

			ScrollRaster(RPort,8,0,CursorX * 8,CursorY * 8,Window -> Width - 1,(CursorY + 1) * 8 - 1);

			BackupRender();
		}

		SetCursor();
	}
}

	/* Raise(UWORD Colour):
	 *
	 *	Make an RGB value brighter.
	 */

STATIC UWORD
Raise(UWORD Colour)
{
	WORD r,g,b;

	r = ((Colour >> 8) & 0xF) + 4;
	g = ((Colour >> 4) & 0xF) + 4;
	b = ((Colour     ) & 0xF) + 4;

	if(r > 15)
		r = 15;

	if(g > 15)
		g = 15;

	if(b > 15)
		b = 15;

	return(r << 8 | g << 4 | b);
}

	/* VisualBeep():
	 *
	 *	`Beep' the screen visually.
	 */

STATIC BYTE
VisualBeep()
{
	struct UCopList	*UserCopperList;

		/* Create a user copper list. */

	if(UserCopperList = (struct UCopList *)AllocMem(sizeof(struct UCopList),MEMF_PUBLIC|MEMF_CLEAR))
	{
			/* Initialize for 35 commands. */

		if(UCopperListInit(UserCopperList,1 + 16 + 1 + 16 + 1))
		{
			WORD i;

				/* Wait until first line of window. */

			CWAIT(UserCopperList,Window -> TopEdge,0);

				/* Set the light colours. */

			for(i = 0 ; i < 16 ; i++)
				CMOVE(UserCopperList,custom . color[i],Raise(GetRGB4(Screen -> ViewPort . ColorMap,i)));

				/* Wait until bottom of window. */

			CWAIT(UserCopperList,Window -> TopEdge + Window -> Height - 1,0);

				/* Set the standard colours. */

			for(i = 0 ; i < 16 ; i++)
				CMOVE(UserCopperList,custom . color[i],GetRGB4(Screen -> ViewPort . ColorMap,i));

				/* Finish list. */

			CEND(UserCopperList);

				/* Lock the screen. */

			LockLayers(&Screen -> LayerInfo);

				/* Install user copper list... */

			Screen -> ViewPort . UCopIns = UserCopperList;

				/* ...and display it. */

			RethinkDisplay();

			return(TRUE);
		}

		FreeMem(UserCopperList,sizeof(struct UCopList));
	}

	return(FALSE);
}

	/* RealBeep():
	 *
	 *	Special function: beep the terminal.
	 */

VOID
RealBeep()
{
		/* Handle the visual part. */

	if(Config . VisibleBell)
	{
		if(VisualBeep())
		{
			if(Config . AudibleBell)
				Beep();

			Delay(25);

				/* Remove the copper list. */

			FreeVPortCopLists(&Screen -> ViewPort);

				/* Really remove it. */

			RemakeDisplay();

				/* Unlock screen layers. */

			UnlockLayers(&Screen -> LayerInfo);
		}
		else
		{
			if(Config . AudibleBell)
				Beep();
		}
	}
	else
	{
			/* Let it beep. */

		if(Config . AudibleBell)
			Beep();

		Delay(25);
	}
}

	/* DoSomeBeep():
	 *
	 *	The real interface to the beep routine.
	 */

VOID
DoSomeBeep()
{
	RealBeep();

	if(!Config . CaptureFilter)
		Capture("\a",1);
}

	/* DoLF():
	 *
	 *	Special function: perform line feed.
	 */

VOID
DoLF()
{
	ClearCursor();

	DownLine();

	SetCursor();
}

	/* DoShiftIn():
	 *
	 *	Special function: Shift into graphics mode
	 */

VOID
DoShiftIn()
{
	if(GFX)
		CurrentFont = GFX;

	SetFont(RPort,CurrentFont);
}

	/* DoShiftOut():
	 *
	 *	Special function: Shift out of graphics mode
	 */

VOID
DoShiftOut()
{
	if(Config . Font == FONT_IBM && IBM)
		CurrentFont = IBM;
	else
		CurrentFont = Topaz;

	SetFont(RPort,CurrentFont);
}

	/* DoIgnore():
	 *
	 *	Special function: don't do anything.
	 */

VOID
DoIgnore()
{
}

	/* DoCR_LF():
	 *
	 *	Special function: perform carriage return and line feed.
	 */

VOID
DoCR_LF()
{
	ClearCursor();

	CursorX = 0;

	DownLine();

	SetCursor();

	Capture("\n",1);
}

	/* DoFF():
	 *
	 *	Special function: perform form feed.
	 */

VOID
DoFF()
{
	ClearCursor();

	if(Config . NewLine)
	{
		CursorX = 0;

		DoCR_LF();
	}
	else
	{
		CursorX = CursorY = 0;

		EraseScreen("2");

		SetCursor();

		Capture("\n",1);
	}
}

	/* DoLF_FF_VT():
	 *
	 *	Special function: handle line feed, form feed and vertical
	 *	tab.
	 */

VOID
DoLF_FF_VT()
{
	if(Config . NewLine)
		DoCR_LF();
	else
		DoLF();
}

	/* DoCR():
	 *
	 *	Special function: handle carriage return.
	 */

VOID
DoCR()
{
	if(Config . NewLine)
		DoCR_LF();
	else
	{
		ClearCursor();

		CursorX = 0;

		SetCursor();

		Capture("\n",1);
	}
}

	/* DoTab():
	 *
	 *	Special function: handle tab, move cursor to next
	 *	tab stop.
	 */

VOID
DoTab()
{
	ClearCursor();

	while(CursorX <= LastColumn)
	{
		CursorX++;

		if(TabStops[CursorX])
			break;
	}

	if(Config . AutoWrap)
	{
		if(CursorX > LastColumn)
		{
			CursorX = 0;

			DownLine();
		}
	}

	SetCursor();

	Capture("\t",1);
}

	/* SpillTheBeans(UBYTE *Buffer,LONG Size):
	 *
	 *	Output a buffer of given size to the terminal
	 *	window.
	 */

VOID
SpillTheBeans(UBYTE *Buffer,LONG Size)
{
	UBYTE	Scale,CharScale;
	WORD	Offset,lc;

		/* Reposition the cursor and turn it off. */

	ClearCursor();

	ClipBlitCursor(FALSE,TRUE);

	if(Config . RasterEnabled)
	{
		Scale = RasterAttr[CursorY];

		if(((Config . FontScale == SCALE_NORMAL) && (Scale == SCALE_ATTR_NORMAL)) || ((Config . FontScale == SCALE_HALF) && (Scale == SCALE_ATTR_2X)))
			CharScale = FALSE;
		else
			CharScale = TRUE;

		if(Scale == SCALE_ATTR_NORMAL)
			lc = LastColumn;
		else
			lc = LastColumn >> 1;
	}
	else
	{
		if(Config . FontScale == SCALE_NORMAL)
			lc = LastColumn;
		else
			lc = LastColumn >> 1;
	}

		/* Do we still have a character in the
		 * magnificient buffer?
		 */

	while(Size)
	{
		/* Cursor is positioned at
		 * the right hand side of the
		 * display. If auto-wrap is
		 * enabled, perform some
		 * kind of CR/LF, else leave
		 * the cursor where it is and
		 * quit the show.
		 */

		if(CursorX > lc)
		{
				/* Wrap cursor. */

			if(Config . AutoWrap)
			{
					/* Move to beginning of next line. */

				CursorX = 0;

				DownLine();

				Capture("\n",1);

				Scale = SCALE_ATTR_NORMAL;

				CharScale = (Config . FontScale == SCALE_NORMAL) ? FALSE : TRUE;

				lc = LastColumn;

					/* Reposition cursor, don't redraw it. */

				ClipBlitCursor(FALSE,TRUE);
			}
			else
			{
					/* Stop the cursor. */

				CursorX = lc;

				Capture(Buffer,Size);

					/* Make it reappear. */

				SetCursor();

				return;
			}
		}

		if(CursorX <= lc)
		{

				/* We won't have to take
				 * care of characters to shift.
				 * We'll collect as many
				 * characters in the buffer as will
				 * fit into the current line
				 * and print them.
				 */

			if((Offset = lc + 1 - CursorX) > Size)
			{
				Offset = Size;

				if(Config . InsertChar)
				{
					if(Config . RasterEnabled)
						RasterShiftChar(Offset);

					ShiftChar(Offset);
				}
			}

			if(Config . RasterEnabled)
			{
				RasterPutString(Buffer,Offset);

				if(CharScale)
					PrintScaled(Buffer,Offset,Scale);
				else
					Text(RPort,Buffer,Offset);
			}
			else
				Text(RPort,Buffer,Offset);

			Capture(Buffer,Offset);

			Buffer	+= Offset;

			Size	-= Offset;

			CursorX	+= Offset;
		}
	}

		/* Make the cursor reappear. */

	SetCursor();
}

	/* ConWrite(APTR Buffer,LONG Size):
	 *
	 *	Write a string to the console window.
	 */

VOID
ConWrite(APTR Buffer,LONG Size)
{
	STATIC UBYTE	 StringBuffer[200],BufSize = 0;
	UBYTE		*Char = Buffer;

		/* Run down the buffer. */

	while(Size--)
	{
			/* Are we parsing a control sequence? */

		if(InSequence)
		{
			if(*Char == ESC)
			{
				DoCancel();

				InSequence = TRUE;
			}
			else
			{
					/* See if we are already done. */

				InSequence = ParseCode(*Char++);
			}
		}
		else
		{
				/* This looks like a control sequence
				 * introducing character.
				 */

			if(*Char == ESC || *Char == CSI)
			{
				if(BufSize)
				{
					SpillTheBeans(&StringBuffer[0],BufSize);

					BufSize = 0;
				}

					/* So we're in TTY mode,
					 * escape the `escape' character
					 * and continue.
					 */

				if(Config . Emulation == EMULATION_TTY)
				{
					StringBuffer[BufSize++] = '^';
					StringBuffer[BufSize++] = '[';
				}
				else
				{
					if(*Char == ESC)
						InSequence = TRUE;
					else
						CSIFake();
				}

				Char++;
			}
			else
			{
					/* Stuff the character into
					 * the buffer.
					 */

				StringBuffer[BufSize++] = *Char++;

					/* If buffer is full, spill it. */

				if(BufSize == 200)
				{
					SpillTheBeans(&StringBuffer[0],BufSize);

					BufSize = 0;
				}
			}
		}
	}

		/* Any characters in the buffer we didn't process yet? */

	if(!InSequence && BufSize)
	{
		SpillTheBeans(&StringBuffer[0],BufSize);

		BufSize = 0;
	}
}

	/* ConProcess(UBYTE *String,LONG Size):
	 *
	 *	Process the contents of a string to be sent to the
	 *	console window.
	 */

VOID
ConProcess(UBYTE *String,LONG Size)
{
	LONG i;

	if(!Config . CaptureFilter)
		CaptureToFile(String,Size);

		/* Oh dear, an external emulation will take care of
		 * displaying the data so we will need to make sure
		 * that the data flow filter and the capture streams
		 * are properly fed.
		 */

	if(Console && Config . Emulation == EMULATION_EXTERNAL)
	{
			/* Feed the flow filter... */

		if(Config . StripBit8)
		{
			for(i = 0 ; i < Size ; i++)
				FlowFilter(String[i] & 0x7F);
		}
		else
		{
			for(i = 0 ; i < Size ; i++)
				FlowFilter(String[i]);
		}

			/* Are we to output data? */

		if(!Quiet)
		{
				/* Build another string to contain
				 * the pure ASCII contents, i.e.
				 * not including any ESC control
				 * sequences.
				 */

			if(i = StripSequence(String,FatBuffer,Size))
				Capture(FatBuffer,i);

			if(i = Console -> hostmon((APTR)Console,String,Size))
				Console -> writecon((APTR)Console,String,i);
		}
	}
	else
	{
		LONG j;

			/* If the eighth bit is to be stripped from incoming
			 * characters, let's process the whole stuff
			 * in a different loop... (and that's all for the
			 * sake of speed).
			 */

		if(Config . StripBit8)
		{
				/* In quiet mode no characters are echoed to the
				 * console window, they are just passed through
				 * the data flow filter. Usually, this mode is
				 * enabled by the dial panel.
				 */

			if(Quiet)
			{
				for(i = 0 ; i < Size ; i++)
					FlowFilter(String[i] & 0x7F);
			}
			else
			{
				UBYTE c;

					/* Check which font we are in, if other than Topaz
					 * the only invalid char is a Null (0) which will
					 * display as a space if let to continue.
					 */

				if(Config . Font == FONT_TOPAZ)
				{
					for(i = 0, j = 0 ; i < Size ; i++)
					{
						c = String[i] & 0x7F;

						FlowFilter(c);

						if(IsPrintable(c))
						{
							/* This character is associated with a
							 * special function (bell, xon, xoff, etc.).
							 */

							if(SpecialMap[c] != -1)
							{
								if(j)
								{
									ConWrite(SharedBuffer,j);

									j = 0;
								}

								SpecialKeys[SpecialMap[c]] . Routine();
							}
							else
							{
								/* Put the character into the buffer
								 * and flush it if necessary.
								 */

								SharedBuffer[j] = c;

								if(j++ == 512)
								{
									ConWrite(SharedBuffer,j);

									j = 0;
								}
							}
						}
					}
				}
				else
				{
					for(i = 0, j = 0 ; i < Size ; i++)
					{
						if(c = String[i] & 0x7F)
						{
							FlowFilter(c);

							/* This character is associated with a
							 * special function (bell, xon, xoff, etc.).
							 */

							if(SpecialMap[c] != -1)
							{
								if(j)
								{
									ConWrite(SharedBuffer,j);

									j = 0;
								}

								SpecialKeys[SpecialMap[c]] . Routine();
							}
							else
							{
								/* Put the character into the buffer
								 * and flush it if necessary.
								 */

								SharedBuffer[j] = c;

								if(j++ == 512)
								{
									ConWrite(SharedBuffer,j);

									j = 0;
								}
							}
						}
					}
				}

				if(j)
					ConWrite(SharedBuffer,j);
			}
		}
		else
		{
			if(Quiet)
			{
				for(i = 0 ; i < Size ; i++)
					FlowFilter(String[i]);
			}
			else
			{
				UBYTE c;

				if(Config . Font == FONT_TOPAZ)
				{
					for(i = 0, j = 0 ; i < Size ; i++)
					{
						c = String[i];

						FlowFilter(c);

						if(IsPrintable(c))
						{
							if(SpecialMap[c] != -1)
							{
								if(j)
								{
									ConWrite(SharedBuffer,j);

									j = 0;
								}

								SpecialKeys[SpecialMap[c]] . Routine();
							}
							else
							{
								SharedBuffer[j] = c;

								if(j++ == 512)
								{
									ConWrite(SharedBuffer,j);

									j = 0;
								}
							}
						}
					}
				}
				else
				{
					for(i = 0, j = 0 ; i < Size ; i++)
					{
						if(c = String[i])
						{
							FlowFilter(c);

							if(SpecialMap[c] != -1)
							{
								if(j)
								{
									ConWrite(SharedBuffer,j);

									j = 0;
								}

								SpecialKeys[SpecialMap[c]] . Routine();
							}
							else
							{
								SharedBuffer[j] = c;

								if(j++ == 512)
								{
									ConWrite(SharedBuffer,j);

									j = 0;
								}
							}
						}
					}
				}

				if(j)
					ConWrite(SharedBuffer,j);
			}
		}
	}
}

	/* ConWrites(UBYTE *String,...):
	 *
	 *	Output a string to the console.
	 */

VOID __stdargs
ConWrites(UBYTE *String,...)
{
	va_list	VarArgs;

	va_start(VarArgs,String);
	VSPrintf(SharedBuffer,String,VarArgs);
	va_end(VarArgs);

	ConProcess(SharedBuffer,strlen(SharedBuffer));
}

	/* KeyConvert(struct IntuiMessage *Massage,UBYTE *Buffer):
	 *
	 *	Convert a raw key information according to the
	 *	current keymap settings.
	 */

UBYTE
KeyConvert(struct IntuiMessage *Massage,UBYTE *Buffer)
{
	if(Buffer)
		Buffer[0] = 0;

	if(Massage -> Class == IDCMP_RAWKEY)
	{
			/* These are the sequences mapped to special
			 * control keys (cursor keys, function keys,
			 * the help key).
			 */

		STATIC struct
		{
			UBYTE *RawCode;
			UBYTE Result;
		} ConversionTable[16] =
		{
			(UBYTE *)"A",	CUP,
			(UBYTE *)"B",	CDN,
			(UBYTE *)"C",	CFW,
			(UBYTE *)"D",	CBK,

			(UBYTE *)"?~",	HLP,

			(UBYTE *)"0~",	FN1,
			(UBYTE *)"1~",	FN2,
			(UBYTE *)"2~",	FN3,
			(UBYTE *)"3~",	FN4,
			(UBYTE *)"4~",	FN5,
			(UBYTE *)"5~",	FN6,
			(UBYTE *)"6~",	FN7,
			(UBYTE *)"7~",	FN8,
			(UBYTE *)"8~",	FN9,
			(UBYTE *)"9~",	F10
		};

			/* Key was pressed, not released. */

		if(!(Massage -> Code & IECODE_UP_PREFIX))
		{
			UBYTE	ConvertBuffer[257],i;
			ULONG	Qualifier = Massage -> Qualifier;

				/* If it's a function key clear the qualifier. */

			if(Massage -> Code >= 80 && Massage -> Code <= 89)
				Qualifier = 0;

				/* Clear the buffer. */

			memset(&ConvertBuffer[0],0,257);

				/* Convert the key. */

			FakeInputEvent -> ie_Code		= Massage -> Code;
			FakeInputEvent -> ie_Qualifier		= Qualifier;
			FakeInputEvent -> ie_position . ie_addr	= *((APTR *)Massage -> IAddress);

			if(RawKeyConvert(FakeInputEvent,(UBYTE *)ConvertBuffer,256,NULL) > 0)
			{
				if(ConvertBuffer[0])
				{
					if(Config . SwapBSDelete)
					{
						if(ConvertBuffer[0] == BKS)
							ConvertBuffer[0] = DEL;
						else
						{
							if(ConvertBuffer[0] == DEL)
								ConvertBuffer[0] = BKS;
						}
					}

					if(Buffer)
						strcpy(Buffer,ConvertBuffer);

						/* Translated sequence starts
						 * with a CSI, let's have a look
						 * at the associated control
						 * key.
						 */

					if(ConvertBuffer[0] == CSI)
					{
						for(i = 0 ; i < 16 ; i++)
						{
							if(!Stricmp(&ConvertBuffer[1],ConversionTable[i] . RawCode))
							{
								ConvertBuffer[0] = ConversionTable[i] . Result;

								if(Buffer)
								{
									Buffer[0] = ConversionTable[i] . Result;
									Buffer[1] = 0;
								}

								break;
							}
						}
					}

					return(ConvertBuffer[0]);
				}
			}
		}
	}

	return(0);
}
