#include <exec/types.h>
#include <exec/ports.h>
#define function     /*  this is just used by the indenter  */
#define then     {
#define elsif    } else if
#define els      } else  {
#define fi       }
#define forever  for (;;) {
#define rof      }
#define or ||
#define and &&
#define not !
#define z if(1==0)
#include <devices/timer.h>
#include <exec/memory.h>
/* #include <exec/io.h>    */
/* #include <exec/tasks.h> */
#include <exec/interrupts.h>
#include <devices/input.h>
#include <exec/devices.h>
#include <devices/inputevent.h>
#include <stdio.h>

#define F1KEYUP 0xD0

struct InputEvent  copyevent;
struct MsgPort    *inputDevPort;
struct IOStdReq   *inputRequestBlock;
struct Interrupt   handlerStuff;
struct InputEvent  dummyEvent;
struct MsgPort    *CreatePort();
struct IOStdReq   *CreateStdIO();
struct MemEntry    me[10];
struct timerequest *PrepareTimer();

extern long OpenDevice();
extern Enable_Abort;
extern long SysBase;

int hcount = 0;
long int p1,p2,p3;
static 	char     str_buf[BUFSIZ];  /* used for buffered i/o  to terminal */

function struct InputEvent *myhandler(ev,mydata) struct InputEvent *ev; struct MemEntry *mydata[]; {

	p3 = SysBase;
	hcount++; p1 = (long)ev; p2 = (long)mydata;
	/* return ev; */
	if(ev->ie_Class == IECLASS_TIMER) then
		return(ev);
	els	
		Forbid();
		z Disable();
		copyevent.ie_NextEvent		= ev->ie_NextEvent;
		copyevent.ie_Class		= ev->ie_Class;
		copyevent.ie_SubClass		= ev->ie_SubClass;
		copyevent.ie_Code		= ev->ie_Code;
		copyevent.ie_Qualifier		= ev->ie_Qualifier;
		copyevent.ie_X			= ev->ie_X;
		copyevent.ie_Y			= ev->ie_Y;
		copyevent.ie_TimeStamp.tv_secs	= ev->ie_TimeStamp.tv_secs;
		copyevent.ie_TimeStamp.tv_micro	= ev->ie_TimeStamp.tv_micro;
		z Enable();
		Permit();
	fi
	return ev;
	
}	

extern struct Task *FindTask();
struct Task *mytask;
LONG mysingnal;
extern VOID HandlerInterface();

struct timerequest *mytimerRequest;
extern struct timerequest *PrepareTimer();
extern long int WaitTimer();
extern void     DeleteTimer();

LONG my_a4 = 0; extern LONG GetA4();
function void main(argc,argv) int argc; char **argv; {

	long error;
	ULONG oldseconds,oldmicro,oldclass;
	
	my_a4 = GetA4();  /* need current base for interrupt handler */
	

	dummyEvent.ie_Class = IECLASS_NULL;
	dummyEvent.ie_NextEvent = NULL;

	inputDevPort = CreatePort(0L,0L);
	if(inputDevPort == NULL) then
		printf("cant open dev port\n");
		exit(-1);
	fi

	inputRequestBlock = CreateStdIO(inputDevPort);
	if (inputRequestBlock == NULL) then 
		DeletePort(inputDevPort);
		printf("cant create stdio\n");
		exit(-2);
	fi
	mytimerRequest = PrepareTimer(1);
	if (mytimerRequest == NULL) then
		printf("cant open timer\n");
		exit(-3);
	fi

	handlerStuff.is_Data	   = (APTR) &me[0];
	handlerStuff.is_Code	   = HandlerInterface;
	handlerStuff.is_Node.ln_Pri= 51;
	printf("addr of handler   = %08lx\n",HandlerInterface);
	printf("addr of myhandler = %08lx\n",myhandler);
	printf("addr of mydata    = %08lx\n\n\n\n\n",&me[0]   );

	error = OpenDevice("input.device",0L,inputRequestBlock,0L);
	if (error == NULL ) then
		printf("Opened the input device\n");
	fi
	inputRequestBlock->io_Command = IND_ADDHANDLER;
	inputRequestBlock->io_Data    = (APTR) &handlerStuff;

	DoIO(inputRequestBlock); 
	copyevent.ie_TimeStamp.tv_secs  = 0;
	copyevent.ie_TimeStamp.tv_micro = 0;
	copyevent.ie_Class 		= 0;


	oldseconds = 0;
	oldmicro   = 0;
	oldclass   = 0;

	Enable_Abort = 0;
	forever
		if ( Chk_Abort() ) then
			printf("aborting\n");
			break;
		fi
		WaitForTimer(mytimerRequest,0L,100000L);
		if(copyevent.ie_Class == IECLASS_RAWKEY && copyevent.ie_Code == F1KEYUP) then
			break;
		els	
		  	z printf("checking %4d %08lx %08lx\n",hcount,p1,p2);
			Forbid();
			if (copyevent.ie_TimeStamp.tv_secs != oldseconds or
	    		   copyevent.ie_TimeStamp.tv_micro != oldmicro or
	    		                copyevent.ie_Class != oldclass )  then
	    
				oldseconds = copyevent.ie_TimeStamp.tv_secs;  
				oldmicro   = copyevent.ie_TimeStamp.tv_micro; 
				oldclass   = copyevent.ie_Class; 		
				showEvents(&copyevent);
			fi	
			Permit();
	  
		fi
	rof
	inputRequestBlock->io_Command = IND_REMHANDLER;
	inputRequestBlock->io_Data    = (APTR) &handlerStuff;
	DoIO(inputRequestBlock); 


	CloseDevice(inputRequestBlock);
	DeleteStdIO(inputRequestBlock);
	DeletePort(inputDevPort);
	DeleteTimer(mytimerRequest);
}

function showEvents(e) struct InputEvent *e; {
	static FILE *evio = NULL;
	short int cd;
	
	if (evio == NULL) then
	    evio = fopen("con:0/0/630/180/evio","w");
	    if (evio == NULL) then
	       printf("cant open evio\n");
	       return;
	    fi
	    setbuf(evio,str_buf);
	fi
	
	fprintf(evio,"--------------------------------------------------\n");
	if    (e->ie_Class ==  IECLASS_RAWKEY or e->ie_Class ==  IECLASS_RAWMOUSE) then
	        if    (e->ie_Class ==  IECLASS_RAWKEY ) then
		    fprintf(evio,"Class     = Key  : ");
	        elsif (e->ie_Class ==  IECLASS_RAWMOUSE) then
		    fprintf(evio,"Class     = Mouse: ");
	        fi	
	        
		if (e->ie_Qualifier & IEQUALIFIER_RSHIFT) then
			fprintf(evio," rshift ");
		fi	
		if (e->ie_Qualifier & IEQUALIFIER_LSHIFT) then
			fprintf(evio," lshift ");
		fi	
		if (e->ie_Qualifier & IEQUALIFIER_CAPSLOCK) then
			fprintf(evio," capslock ");
		fi	
		if (e->ie_Qualifier & IEQUALIFIER_CONTROL) then
			fprintf(evio," control ");
		fi	
		if (e->ie_Qualifier & IEQUALIFIER_LCOMMAND) then
			fprintf(evio," lcmd ");
		fi	
		if (e->ie_Qualifier & IEQUALIFIER_RCOMMAND) then
			fprintf(evio," rcmd ");
		fi	
		if (e->ie_Qualifier & IEQUALIFIER_LALT) then
			fprintf(evio," lalt ");
		fi	
		if (e->ie_Qualifier & IEQUALIFIER_RALT) then
			fprintf(evio," ralt ");
		fi	
		if (e->ie_Qualifier & IEQUALIFIER_LBUTTON) then
			fprintf(evio," lbut ");
		fi	
		if (e->ie_Qualifier & IEQUALIFIER_RBUTTON) then
			fprintf(evio," rbut ");
		fi	
		
		fprintf(evio,"\n");
	els	
		fprintf(evio,"Class     = %x\n",e->ie_Class);
	fi
	fprintf(evio,"SubClass  = %x\n",e->ie_SubClass);
        if    (e->ie_Class ==  IECLASS_RAWMOUSE ) then
        	  cd = e->ie_Code & 0x7f;
		  fprintf(evio,"Code      = %x ",e->ie_Code);
		  if (cd  == IECODE_LBUTTON) then
			fprintf(evio," lbut ");
		  fi
		  if (cd  == IECODE_RBUTTON) then
			fprintf(evio," rbut ");
		  fi
		  if (e->ie_Code & IECODE_UP_PREFIX and e->ie_Code != IECODE_NOBUTTON ) then
			fprintf(evio," UP ");
		  fi
		  fprintf(evio,"\n");
	els	
		fprintf(evio,"CODE      = %x\n",e->ie_Code);
	fi
	fprintf(evio,"Qualifier = %x\n",e->ie_Qualifier);
	fprintf(evio,"X         = %d\n",e->ie_X);
	fprintf(evio,"Y         = %d\n",e->ie_Y);
	fprintf(evio,"TimeStamp = %lx\n",e->ie_TimeStamp.tv_secs);
	fprintf(evio,"next      = %08lx p3 = %08lx\n",e->ie_NextEvent,p3);
	fflush(evio);
}


extern struct MsgPort *CreatePort();
extern struct IORequest *CreateExtIO();


function struct timerequest *PrepareTimer(precision) SHORT precision; {

	long int error; long whichunit;

	struct MsgPort *timerport;
	struct timerequest *timermsg;

	timerport = CreatePort(0L,0L);

	if (timerport == NULL) then
		printf("no port\n");
		return NULL;
	fi


	timermsg =(struct timerequest *) CreateExtIO(timerport,(long)sizeof(struct timerequest));
	if (timermsg == NULL) then
		printf("no timermsg\n");
		DeletePort(timerport);
		return NULL;

	fi

	if (precision) then
		whichunit = UNIT_MICROHZ;
	els
		whichunit = UNIT_VBLANK;
	fi

	error = OpenDevice(TIMERNAME,whichunit,timermsg,0L);
	if (error != NULL) then
		printf("opendevice = %ld\n",error);
		DeleteExtIO(timermsg,sizeof(struct timerequest));
		DeletePort(timerport);
		return NULL;
	fi
	return timermsg;

}

function WaitForTimer(tr,seconds,microseconds) 
			ULONG seconds,microseconds; struct timerequest *tr; {

	tr->tr_node.io_Command = TR_ADDREQUEST;
	tr->tr_time.tv_secs    = seconds;
	tr->tr_time.tv_micro   = microseconds;
	DoIO(tr);

	return 0;


}


function void DeleteTimer(tr) struct timerequest *tr; {
	struct MsgPort *tp;
	
	tp = tr->tr_node.io_Message.mn_ReplyPort;
	if (tr != 0) then
		CloseDevice(tr);
		DeleteExtIO(tr,sizeof(struct timerequest));
	fi	
	if (tp != 0) then
		DeletePort(tp);
	fi
	return ;
#ifndef _lint	
#asm


;-------------------------------------------------------------------------
; MAKE SURE THIS ASSEMBLY CODE IS AT THE END OF THIS C SOURCE FILE
;-------------------------------------------------------------------------
	far code	;make sure the below can load a4 without using a4
	far data	;ditto
_HandlerInterface:
	movem.l		saver,-(sp)
	move.l		_my_a4,a4
	movem.l		a0/a1,-(a7)
	
	jsr		_myhandler
	addq.l		#8,a7
	movem.l		(sp)+,saver
	rts
saver:	reg	a0-a6/d1-d7

_GetA4:
	move.l		a4,d0
	rts

#endasm
#endif
}
