/* TxHelp v1.0  Add Numeric Keypad Control To TxEd
 * 		(or a general input.device example)
 * 		(Can you say "Hotkeys"??)
 * Placed in the public domain, but
 * Copyright (c) 1987 Anson Mah
 * Last modified:  Jan. 26, 1987
 */

#include <exec/types.h>
#include <exec/ports.h>
#include <exec/memory.h>
#include <exec/interrupts.h>
#include <exec/io.h>
#include <exec/tasks.h>
#include <devices/input.h>
#include <devices/inputevent.h>

/* Intuition stuff commented out.
   Will generate a screen flash when terminated if code used */
/* #include <intuition/intuitionbase.h> */

#define QUIT_TXHELP	0x4A	/* left-amiga-minus to quit history */
#define IE_SIZE		sizeof(struct InputEvent)
#define R_AMIGA		IEQUALIFIER_RCOMMAND
#define LETTER_D	0x22	/* self-explanatory */
#define LETTER_J	0x26
#define LETTER_T	0x14
#define LETTER_U	0x16
#define LETTER_V	0x34
#define NUMBER_1	0x01
#define RETURN		0x44
#define DEL_KEY		0x46
#define ENTER		0x43
#define UP_ARROW	0x4C
#define DOWN_ARROW	0x4D
#define LEFT_ARROW	0x4F
#define RIGHT_ARROW	0x4E

#define BEGINNING	0x3D	/* Numeric keypad 7 */
#define END		0x1D	/* Numeric keypad 1 */
#define PAGEUP		0x3F	/* Numeric keypad 9 */
#define PAGEDOWN	0x1F	/* Numeric keypad 3 */
#define CURSORUP	0x3E	/* Numeric keypad 8 */
#define CURSORDOWN	0x1E	/* Numeric keypad 2 */
#define CURSORLEFT	0x2D	/* Numeric keypad 4 */
#define CURSORRIGHT	0x2F	/* Numeric keypad 6 */
#define DONOTHING	0x2E	/* Numeric keypad 5 */
#define DELETE		0x3C	/* Numeric keypad . */
#define INSERT		0x0F	/* Numeric keypad 0 */


struct MsgPort *inputDevPort;
struct IOStdReq *inputRequestBlock;
struct Interrupt handlerStuff;
struct Task *ThisTask;
struct IntuitionBase *IntuitionBase;

extern void HandlerInterface();
extern struct MsgPort *CreatePort();
extern struct IOStdReq *CreateStdIO();
extern struct Task *FindTask();

struct MemEntry me[1];
ULONG PrintSig, PSig, QuitSig, QSig;	/* signals */
UWORD code;	/* inputevent code */


void WriteRAWKEYEvent(code, qualifier)
UWORD code, qualifier;
{
	struct InputEvent event;

	inputRequestBlock->io_Command = IND_WRITEEVENT;
	inputRequestBlock->io_Flags = 0;
	inputRequestBlock->io_Length = IE_SIZE;
	inputRequestBlock->io_Data = (APTR)&event;

	event.ie_NextEvent = NULL;
	event.ie_Class = IECLASS_RAWKEY;
	event.ie_Code = code;
	event.ie_Qualifier = qualifier;

	DoIO(inputRequestBlock);
}


struct InputEvent *myhandler(ev, mydata)
struct InputEvent *ev;
struct MemEntry *mydata[];
{
	struct InputEvent *temp, *prev;
	UWORD qual;

	for (temp = ev, prev = NULL; temp != NULL; temp = temp->ie_NextEvent) {

		if (temp->ie_Class != IECLASS_RAWKEY)
			prev = temp;
		else {
			code = temp->ie_Code;
			/* mask qualifier to extract IEQUALIFIER value */
			qual = temp->ie_Qualifier & 0x7FFF;

			if ((code == QUIT_TXHELP) && (qual & R_AMIGA)) {
				/* remove event */
				if (prev == NULL)
					ev = temp->ie_NextEvent;
				else
					prev->ie_NextEvent = temp->ie_NextEvent;
				Signal(ThisTask, QuitSig);
				return(ev);
			}
			if (qual & IEQUALIFIER_NUMERICPAD) {
				/* remove event */
				if (prev == NULL)
					ev = temp->ie_NextEvent;
				else
					prev->ie_NextEvent = temp->ie_NextEvent;
				Signal(ThisTask, PrintSig);
			}
		} /* end of large 'else' */
	} /* 'for' ends here */

	return(ev);
}

void Cleanup()
{
	/* remove input handler */
	inputRequestBlock->io_Command = IND_REMHANDLER;
	inputRequestBlock->io_Data = (APTR)&handlerStuff;
	DoIO(inputRequestBlock);

	CloseDevice(inputRequestBlock);
	DeleteStdIO(inputRequestBlock);
	DeletePort(inputDevPort);
	FreeSignal(QSig);
	FreeSignal(PSig);

/*	if (IntuitionBase)  CloseLibrary( (void *)IntuitionBase);   */

	exit(TRUE);
}


void main()
{
	ULONG sig;	/* note: sig is used for all sorts of purposes */

	/* allocate signals for use */
	if ((QSig = AllocSignal(-1)) == -1)
		exit(FALSE);
	QuitSig = 1 << QSig;

	if ((PSig = AllocSignal(-1)) == -1)
		exit(FALSE);
	PrintSig = 1 << PSig;

	ThisTask = FindTask(0);
	SetTaskPri(ThisTask, 25);

	if ((inputDevPort = CreatePort(0, 0)) == NULL)
		exit(FALSE);
	if ((inputRequestBlock = CreateStdIO(inputDevPort)) == NULL) {
		DeletePort(inputDevPort);
		exit(FALSE);
	}
	handlerStuff.is_Data = (APTR)&me[0];
	handlerStuff.is_Code = HandlerInterface;
	handlerStuff.is_Node.ln_Pri = 51;

	if (OpenDevice("input.device", 0, inputRequestBlock, 0)) {
		DeletePort(inputDevPort);
		exit(FALSE);
	}

/*	if ((IntuitionBase = (struct IntuitionBase *)
	    OpenLibrary("intuition.library", 0)) == NULL)
		Cleanup();	*/

	inputRequestBlock->io_Command = IND_ADDHANDLER;
	inputRequestBlock->io_Data = (APTR)&handlerStuff;
	DoIO(inputRequestBlock);

	Write(Output(), "TxHelp v1.0 \251 1987 Anson Mah\n", 29);

	for (;;) {
		sig = Wait(QuitSig | PrintSig);
		if (sig & QuitSig) {
/*			DisplayBeep(IntuitionBase->ActiveScreen);	*/
			Cleanup();
		}
		if (sig & PrintSig)
			switch (code) {
				case BEGINNING:
					/* jump to line 1 */
				    WriteRAWKEYEvent(LETTER_J, R_AMIGA);
				    WriteRAWKEYEvent(NUMBER_1, 0);
				    WriteRAWKEYEvent(RETURN, 0);
				    break;
				case END:
					/* jump to line 1 */
				    WriteRAWKEYEvent(LETTER_J, R_AMIGA);
				    WriteRAWKEYEvent(NUMBER_1, 0);
				    WriteRAWKEYEvent(RETURN, 0);
					/* toggle top to bottom */
				    WriteRAWKEYEvent(LETTER_T, R_AMIGA);
				    break;
				case PAGEUP:
				    WriteRAWKEYEvent(LETTER_U, R_AMIGA);
				    break;
				case PAGEDOWN:
				    WriteRAWKEYEvent(LETTER_D, R_AMIGA);
				    break;
				case CURSORUP:
				    WriteRAWKEYEvent(UP_ARROW, 0);
				    break;
				case CURSORDOWN:
				    WriteRAWKEYEvent(DOWN_ARROW, 0);
				    break;
				case CURSORLEFT:
				    WriteRAWKEYEvent(LEFT_ARROW, 0);
				    break;
				case CURSORRIGHT:
				    WriteRAWKEYEvent(RIGHT_ARROW, 0);
				    break;
				case DELETE:
				    WriteRAWKEYEvent(DEL_KEY, 0);
				    break;
				case ENTER:
				    WriteRAWKEYEvent(ENTER, 0);
				    break;
				case INSERT:
				    WriteRAWKEYEvent(LETTER_V, R_AMIGA);
				    break;
				case DONOTHING:
				    break;
			} /* switch */

	}
}
