/*
  Copyright (c) 1988 Commodore-Amiga, Inc.
 
  Executables based on this information may be used in software
  for Commodore Amiga computers.  All other rights reserved.
 
  This information is provided "as is"; no warranties are made.
  All use is at your own risk, and no liability or responsibility is assumed.
*/

#define	DEBUG
#include	"exec/types.h"
#include	"exec/nodes.h"
#include	"exec/lists.h"
#include	"exec/ports.h"
#include	"exec/interrupts.h"
#include	"devices/gameport.h"
#include	"devices/input.h"
#include	"devices/inputevent.h"
#include	"libraries/dos.h"

struct Task *FindTask();

struct MsgPort iorp = {
    {0, 0, NT_MSGPORT, 0, 0}, 0, SIGF_SINGLE, 0, {0, 0, 0, 0, 0}
};

struct IOStdReq ior = {
    {{0, 0, NT_MESSAGE, 0, 0}, &iorp, 0},
    0, 0, 0, 0, 0, 0, 0, 0, 0
};

struct InputEvent nullEvent = {
    NULL, IECLASS_NULL
};

struct GamePortTrigger joyTrigger = {
    GPTF_DOWNKEYS|GPTF_UPKEYS, 1, 1, 1
};

struct GamePortTrigger mouseTrigger = {
    GPTF_DOWNKEYS|GPTF_UPKEYS, 0, 1, 1
};

extern VOID eventAFunction();

struct Interrupt inputHandler = {
    {0, 0, NT_INTERRUPT, 100, 0}, 0, eventAFunction
};

#define	MAXDELTA	255
#define	DELTASHIFT	4

int deltaX = 0;
int deltaY = 0;

struct InputEvent *
eventFunction(event, data)
struct InputEvent *event;
{
    struct InputEvent *loopevent;

#ifdef	DEBUG
kprintf(".");
#endif

    loopevent = event;
    do {
	if (loopevent->ie_Class == IECLASS_RAWMOUSE) {
	    /* handle X, then Y.  slow down faster than speed up */
	    /* this could use another iteration to get it to "feel" right */
	    if (loopevent->ie_X < 0) {
#ifdef	DEBUG
kprintf("<");
#endif
		if (deltaX <= 0) {
		    if (deltaX > -MAXDELTA) deltaX--;
		}
		else deltaX = deltaX/2;
	    }
	    else if (loopevent->ie_X > 0) {
#ifdef	DEBUG
kprintf(">");
#endif
		if (deltaX >= 0) {
		    if (deltaX < MAXDELTA) deltaX++;
		}
		else deltaX = deltaX/2;
	    }
	    else if (loopevent->ie_Y != 0) {
		if (deltaX != 0) deltaX += (deltaX<0)?1:-1;
	    }
	    else deltaX = deltaX/2;
	    if (deltaX < 0)
		loopevent->ie_X = (deltaX-((1<<DELTASHIFT)+1))>>DELTASHIFT;
	    else
		loopevent->ie_X = (deltaX+((1<<DELTASHIFT)-1))>>DELTASHIFT;

	    if (loopevent->ie_Y < 0) {
#ifdef	DEBUG
kprintf("v");
#endif
		if (deltaY <= 0) {
		    if (deltaY > -MAXDELTA) deltaY--;
		}
		else deltaY = deltaY/2;
	    }
	    else if (loopevent->ie_Y > 0) {
#ifdef	DEBUG
kprintf("^");
#endif
		if (deltaY >= 0) {
		    if (deltaY < MAXDELTA) deltaY++;
		}
		else deltaY = deltaY/2;
	    }
	    else if (loopevent->ie_X != 0) {
		if (deltaY != 0) deltaY += (deltaY<0)?1:-1;
	    }
	    else deltaY = deltaY/2;
	    if (deltaY < 0)
		loopevent->ie_Y = (deltaY-((1<<DELTASHIFT)+1))>>DELTASHIFT;
	    else
		loopevent->ie_Y = (deltaY+((1<<DELTASHIFT)-1))>>DELTASHIFT;
	}
    }
    while ((loopevent = loopevent->ie_NextEvent) != 0);
    return(event);
}


main(argc, argv)
int argc;
char *argv[];
{
    char c;
    int result;

    NewList(&iorp.mp_MsgList);
    iorp.mp_SigTask = (struct Task *) FindTask((char *) NULL);

    if (OpenDevice("input.device", 0, &ior, 0)) exit(20);

    /* free this controller */
    c = GPCT_NOCONTROLLER;
    ior.io_Command = IND_SETMTYPE;
    ior.io_Length = 1;
    ior.io_Data = (APTR) &c;
    DoIO(&ior);

    /* wait for the SETM to take effect with a side effect */
    ior.io_Command = IND_WRITEEVENT;
    ior.io_Length = (LONG) sizeof(nullEvent);
    ior.io_Data = (APTR) &nullEvent;
    DoIO(&ior);

    /* switch to the right game port */
    c = 1;
    ior.io_Command = IND_SETMPORT;
    ior.io_Length = 1;
    ior.io_Data = (APTR) &c;
    DoIO(&ior);

    /* set this controller to a joystick */
    c = GPCT_ABSJOYSTICK;
    ior.io_Command = IND_SETMTYPE;
    ior.io_Length = 1;
    ior.io_Data = (APTR) &c;
    DoIO(&ior);

    /* set the trigger for the joystick */
    ior.io_Command = IND_SETMTRIG;
    ior.io_Length = (LONG) sizeof(joyTrigger);
    ior.io_Data = (APTR) &joyTrigger;
    DoIO(&ior);

    /* insert the accellerator handler into the food chain */
    ior.io_Command = IND_ADDHANDLER;
    ior.io_Data = (APTR) &inputHandler;
    ior.io_Length = (LONG) sizeof(struct Interrupt);
    DoIO(&ior);

    /* wait for this program to terminate */
    Wait(SIGBREAKF_CTRL_C);

    /* free this controller */
    c = GPCT_NOCONTROLLER;
    ior.io_Command = IND_SETMTYPE;
    ior.io_Length = 1;
    ior.io_Data = (APTR) &c;
    DoIO(&ior);

    /* remove the accellerator handler from the food chain */
    ior.io_Command = IND_REMHANDLER;
    ior.io_Data = (APTR) &inputHandler;
    ior.io_Length = (LONG) sizeof(struct Interrupt);
    DoIO(&ior);

    /* switch to the left game port */
    c = 0;
    ior.io_Command = IND_SETMPORT;
    ior.io_Length = 1;
    ior.io_Data = (APTR) &c;
    result = DoIO(&ior);

    /* set the trigger for a mouse */
    ior.io_Command = IND_SETMTRIG;
    ior.io_Length = sizeof(mouseTrigger);
    ior.io_Data = (APTR) &mouseTrigger;
    DoIO(&ior);

    /* set this controller to a mouse */
    c = GPCT_MOUSE;
    ior.io_Command = IND_SETMTYPE;
    ior.io_Length = 1;
    ior.io_Data = (APTR) &c;
    result = DoIO(&ior);
}
