/* ***********************************************************************

Programma ...... LeftyMouse.c - V1.0i
Funzione ....... Rendere Amiga ambidestro
Software ....... Lattice C V5.02 || Aztec C V3.6a
Hardware ....... Amiga 500/2500 + Kickstart V1.2/1.3
Sintassi ....... Click da Workbench o RUN LeftyMouse

Lattice: lc -vbr -O LeftMouse
         asm hndstub.asm
         blink from lib:c.o+LeftyMouse.o+hndstub.o lib lib:lc.lib sc nd sd

Aztec:   cc +L LeftyMouse
         as HndStub.asm
         ln LeftyMouse hndstub -lc32

*********************************************************************** */

#include <exec/types.h>
#include <intuition/intuitionbase.h>
#include <devices/input.h>

#ifdef LATTICE
#include <proto/exec.h>
#include <proto/intuition.h>
#else
#include <functions.h>
#endif

#define PORTNAME "-<:RBE_Lefty:>-"

struct Interrupt handlerptr;           /* Struttura interrupt handler */
struct MsgPort *inputport, *replyport; /* Porte comunicazione messaggi */
struct IOStdReq *inputreq;             /* Richiesta IO per device */
struct Message kill;                   /* Messaggio omicida */

struct IntuitionBase *IntuitionBase;

extern void hndstub();                 /* Codice assembly di interfaccia */

void _main()   /* name is _main() not main() to save space (Lattice) */
{
  inputport = FindPort(PORTNAME);   /*  Porta già esistente? */

  if (inputport == NULL)            /*  Programma in esecuzione? */
  {                                 /*  No - installa input handler  */
    IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
    inputport = CreatePort(PORTNAME,0);  /* make port for IO request */

    if (IntuitionBase== NULL || inputport==NULL) _exit(20);

    inputreq = CreateStdIO(inputport);
    if (inputreq == NULL) _exit( 21L ); /* Request inapribile */

    if (OpenDevice("input.device",0,(struct IORequest *)inputreq,0) != NULL)
      _exit(22);                /* device inapribile */

    handlerptr.is_Code = hndstub;     /* Fissa handler di interrupt  */
    handlerptr.is_Data = NULL;
    handlerptr.is_Node.ln_Pri = 127;  /* Massima priorità  */

    inputreq->io_Command = IND_ADDHANDLER;
    inputreq->io_Data = (APTR)&handlerptr;  /* Request IO al device di input */
    DoIO((struct IORequest *)inputreq);     /* Installa handler di input */

/* L'handler di input è installato ed operante. Non possiamo però
terminare ora perchè lo stesso handler verrebbe eliminato. Così 
attendiamo un messaggio qualunque, possibilmente per sempre. Quando lo
riceviamo deinstalliamo lo handler e terminiamo */

    ReplyMsg(WaitPort(inputport));    /* Attende messaggio */

    inputreq->io_Command = IND_REMHANDLER;  /* Inizio pacchetto  */

    DoIO((struct IORequest *)inputreq);     /* Rimuove input handler */

    CloseDevice((struct IORequest *)inputreq);  /* Chiude e cancella */

    DeleteStdIO(inputreq);                      /* tutto ciò che è stato */
    DeletePort(inputport);                      /* aperto o allocato */

    CloseLibrary((struct Library *)IntuitionBase);

    _exit(0);                 /* Torna a casa, Lassie! */
  }

  else    /* Programma già in esecuzione. Messaggio per ucciderlo  */
  {
    replyport = CreatePort(0,0);       /* Crea reply port per messaggio */

    if (replyport == NULL) _exit(20);  /* Termina se impossibilitato */

    kill.mn_ReplyPort = replyport;
    kill.mn_Length = 0;

    PutMsg(inputport,&kill);  /* Invia messaggio di uccisione a task */

    while(WaitPort(replyport) != &kill)  /* Attende risposta */
    {}

    DeletePort(replyport);    /* Pulizia */

    _exit(100);               /* Fine */
  }
    
}

/* Questo è il codice di gestione dell'evento di input effettivo.
E' chiamato dal codice assembly hndstub() tutte le volte che si verifica
un evento di input. ************************************************** */

struct InputEvent *hndcode(ie,data)
struct InputEvent *ie;
int data;
{
  register unsigned short x;     /* Per tenere codice di input */
  register struct InputEvent *e;

  e = ie;
  do
  {
             /* E' pressione del mouse?  */
    if (e->ie_Class==IECLASS_RAWMOUSE && e->ie_Code!=IECODE_NOBUTTON)
    {
      x = e->ie_Code & 0x007f;   /* Maschera IECODE_UP_PREFIX per ora */

   /* Scambia codici bottoni, e ripone IECODE_UP_PREFIX */

      if (x == IECODE_LBUTTON)
        e->ie_Code = IECODE_RBUTTON | (e->ie_Code & IECODE_UP_PREFIX);
      else if (x == IECODE_RBUTTON)
        e->ie_Code = IECODE_LBUTTON | (e->ie_Code & IECODE_UP_PREFIX);
    }
    e = e->ie_NextEvent;
  }  while (e != NULL);  /* Passa tutta la lista di eventi */

  return(ie);  /* Passa eventi */
}

#ifdef LATTICE
void MemCleanup() {}  /* dummy function to save space (Lattice) */
#endif
