#define TASKNAME	"Mouse Zoom"
#define TERMINATE	0xff

#include <exec/types.h>
#include <exec/lists.h>
#include <exec/memory.h>
#include <exec/interrupts.h>
#include <exec/libraries.h>
#include <exec/io.h>
#include <exec/tasks.h>
#include <exec/devices.h>
#include <devices/input.h>
#include <devices/inputevent.h>
#include <intuition/intuition.h>
#include <libraries/dos.h>
#include <graphics/gfxmacros.h>

#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <string.h>

#define abs(x) ((x) < 0 ? -(x) : (x))

struct MsgPort *FindPort(), *CreatePort();
void DeletePort();

struct OURMSG {
 struct Message msgpart;
 short  Command;
 short  Misc;
 };

/* Declarations for CBACK */
extern BPTR _Backstdout;         /* standard output when run in background */
long _BackGroundIO = 0;          /* Flag to tell it we don't want to do I/O      */
long _stack = 4000;              /* Amount of stack space our task needs   */
char *_procname = "Mouse Zoom";  /* The name of the task to create         */
long _priority = 0;              /* The priority to run us at              */

/************************************************************************/
/* the handler subroutine - called through the handler stub             */
/************************************************************************/
struct InputEvent *myhandler(ev, gptr)
struct InputEvent *ev;            /* and a pointer to a list of events */
APTR   gptr;                      /* Everything we need to know about */
{
register struct InputEvent *ep;
register short i;

   /* run down the list of events to see if they are mouse-move */

for (ep = ev; ep != NULL; ep = ep->ie_NextEvent)
    {
    if ((ep->ie_Class == IECLASS_RAWMOUSE)    &&
        (ep->ie_Qualifier & IEQUALIFIER_RELATIVEMOUSE))
        {
	i = abs(ep->ie_X) >> 3;		/* adjust x value */
	if (i != 0) ep->ie_X *= i;
	i = abs(ep->ie_Y) >> 3;		/* adjust y value */
	if (i != 0) ep->ie_Y *= i;
        }
     }
   /* pass on the pointer to the event */
return(ev);
}

/* * * * * * * * * * * EXTERNAL ROUTINES * * * * * * * * * */

extern struct MsgPort  *CreatePort();
struct IOStdReq  *CreateIOReq(struct MsgPort *, int);
void              DeleteIOReq(struct IOStdReq *);
extern void       HandlerInterface();

/************************************************************************/
/* the main program to do the popcli stuff                              */
/************************************************************************/
void _main(cmd)
char *cmd;
{
struct OURMSG *msg;
short Command;
short Misc;
struct MsgPort     *port;
struct MsgPort     *inputDevPort;
struct IOStdReq    *inputRequestBlock;
struct Interrupt      handlerStuff;

port                = NULL;
inputDevPort        = NULL;
inputRequestBlock   = NULL;

	/* see if we already exist, and if so, wake up and die */

if ((port = FindPort(TASKNAME)) != NULL)
	{
	if ((msg = (struct OURMSG *)
              AllocMem(sizeof(struct OURMSG), MEMF_CLEAR|MEMF_PUBLIC)) == NULL)
	goto abort;
	msg->Command = TERMINATE;
	msg->msgpart.mn_Node.ln_Type = NT_MESSAGE;
	msg->msgpart.mn_Node.ln_Pri  = 0;
	msg->msgpart.mn_Length = sizeof(struct OURMSG);
	PutMsg(port,msg);
	port = NULL;
	goto abort;
	}		
   
   
if ((port  = CreatePort(TASKNAME,0)) == NULL) goto abort;

if (  ((inputDevPort = CreatePort(0,0)) == NULL)                        ||

      ((inputRequestBlock =
          CreateIOReq(inputDevPort, sizeof(struct IOStdReq))) == NULL)  ||

      OpenDevice("input.device",0,(struct IORequest *)inputRequestBlock,0))

      goto abort;

handlerStuff.is_Data = NULL;
handlerStuff.is_Code = HandlerInterface;
handlerStuff.is_Node.ln_Pri = 51;


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

DoIO((struct IORequest *)inputRequestBlock);

for(;;)         /* FOREVER */
      {
      WaitPort( port );

      while ((msg = (struct OURMSG *)GetMsg(port)) != NULL)
        {
	Command = msg->Command;
	Misc    = msg->Misc;
	FreeMem(msg, sizeof(struct OURMSG));
	switch(Command)
		{
		case TERMINATE:
			goto abort;
			break;
		
		default:
			break;
		}			
	}
      }

abort:

if (inputRequestBlock != NULL)
      {
      if (inputRequestBlock->io_Device != NULL)
         {
         inputRequestBlock->io_Command = IND_REMHANDLER;
         inputRequestBlock->io_Data = (APTR)&handlerStuff;
         DoIO((struct IORequest *)inputRequestBlock);
	 
         CloseDevice((struct IORequest *)inputRequestBlock);
         }
      DeleteIOReq(inputRequestBlock);
      }
if (inputDevPort != NULL)       DeletePort(inputDevPort);
if (port != NULL)               DeletePort(port);
}

void MemCleanup(){}

struct MsgPort *CreatePort(name, pri)
char *name;
int pri;
{
   UBYTE sigbit;
   register struct MsgPort *port;

   if ((sigbit = AllocSignal(-1)) == -1)
      return((struct MsgPort *)0);

   if ((port = (struct MsgPort *)AllocMem(sizeof(struct MsgPort),
                        MEMF_CLEAR|MEMF_PUBLIC)) == 0)
      {
      FreeSignal(sigbit);
      return((struct MsgPort *) (0));
      }
   port->mp_Node.ln_Name = name;
   port->mp_Node.ln_Pri = pri;
   port->mp_Node.ln_Type = NT_MSGPORT;
   port->mp_Flags = PA_SIGNAL;
   port->mp_SigBit = sigbit;
   port->mp_SigTask = (struct Task *)FindTask(0);
   AddPort(port);
   return(port);
}

void DeletePort(port)
struct MsgPort *port;
{
RemPort(port);
FreeSignal(port->mp_SigBit);
FreeMem((char *)port,sizeof(struct MsgPort));
}

struct IOStdReq *
CreateIOReq(port, size)
struct MsgPort *port;
int size;
{
   struct IOStdReq *ioReq;

   if ((ioReq = (struct IOStdReq *)
                AllocMem(size, MEMF_CLEAR | MEMF_PUBLIC)) != NULL)
      {
      ioReq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
      ioReq->io_Message.mn_Node.ln_Pri  = 0;
      ioReq->io_Message.mn_Length       = size;
      ioReq->io_Message.mn_ReplyPort    = port;
      }
   return(ioReq);
}

void DeleteIOReq(ioReq)
struct IOStdReq *ioReq;
{
ioReq->io_Message.mn_Node.ln_Type = 0xff;
ioReq->io_Device = (struct Device *) -1;
ioReq->io_Unit = (struct Unit *) -1;

FreeMem( (char *)ioReq, ioReq->io_Message.mn_Length);
}

