#include "KeyboardX.h"

#define BREAKSIGS (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E|\
                   SIGBREAKF_CTRL_F)

/* Functions */
void cleanup();
BOOL AskDefaultKeyMap();
void SendTimeRequest();
void DoRemap();
ULONG Atol();
struct MsgPort *CreatePort();
struct IOStdReq *CreateExtIO();
struct Window *OpenWindow();
long OpenDevice();
struct IntuiMessage *GetMsg();
ULONG Wait();
BOOL CheckIO();
int rand();

/* Globals */
long _stack=4000,_priority=0,_BackGroundIO=0;
char *_procname="KeyboardX";
struct MsgPort *cp=NULL,*tp=NULL;
struct IOStdReq *creq=NULL;
struct timerequest *treq=NULL;
struct Window *w=NULL;
struct KeyMap km;
struct NewWindow nw={0,10,329,10,0,1,CLOSEWINDOW,WINDOWDRAG|WINDOWDEPTH|
                     WINDOWCLOSE|SMART_REFRESH,NULL,NULL,
                     (UBYTE *) "KeyboardX 1.0 by Stefan Becker",NULL,NULL,
                     0,0,0,0,WBENCHSCREEN};
BOOL ConsoleOpen=FALSE,TimerOpen=FALSE;
char *conname="console.device";
char *timname=TIMERNAME;
char *keyname="default keymap";

main(argc,argv)
int argc;
char *argv[];
{
 ULONG seconds=10;
 ULONG cl,tsig,wsig,sigs;
 ULONG oldktab[0x40];
 BOOL DoIt=TRUE;
 struct IntuiMessage *msg;

 if (argc>1)
  if ((seconds=Atol(argv[1]))==0) seconds=10;

 if (!(w=OpenWindow(&nw)))
  cleanup("window",0);
 srand(w);

 if (!(cp=CreatePort("KX.ConsolePort",0L)))
  cleanup("console port",1);
 if (!(creq=CreateExtIO(cp,(ULONG) sizeof(struct IOStdReq))))
  cleanup("console request",1);
 if (OpenDevice(conname,-1L,creq,0L))
  cleanup(conname,0);
 ConsoleOpen=TRUE;

 Forbid();
 if (AskDefaultKeyMap(creq,&km)==FALSE)
  {
   Permit();
   cleanup(keyname,0);
  }
 for (cl=0;cl<0x40;cl++) oldktab[cl]=km.km_LoKeyMap[cl];
 Permit();

 if (!(tp=CreatePort("KX.TimerPort",0L)))
  cleanup("timer port",1);
 if (!(treq=(struct timerequest *)
             CreateExtIO(tp,(ULONG) sizeof(struct timerequest))))
  cleanup("timer request",1);
 if (OpenDevice(timname,UNIT_MICROHZ,treq,0L))
  cleanup(timname,0);
 TimerOpen=TRUE;

 SendTimeRequest(treq,seconds);

 wsig=1L<<w->UserPort->mp_SigBit;
 tsig=1L<<tp->mp_SigBit;

 while (DoIt)
  {
   sigs=Wait(wsig|tsig|BREAKSIGS);

   if (sigs&wsig)
    while (msg=GetMsg(w->UserPort))
     {
      cl=msg->Class;
      ReplyMsg(msg);
      if (cl==CLOSEWINDOW) DoIt=FALSE;
     }

   if (sigs&tsig)
    {
     msg=GetMsg(tp);
     DoRemap();
     SendTimeRequest(treq,seconds);
    }

   if (sigs&BREAKSIGS) DoIt=FALSE;
  }

 Forbid();
 if (AskDefaultKeyMap(creq,&km)==FALSE)
  {
   Permit();
   cleanup(keyname,0);
  }
 for (cl=0;cl<0x40;cl++) km.km_LoKeyMap[cl]=oldktab[cl];
 Permit();

 if (!(CheckIO(treq))) AbortIO(treq);
 WaitIO(treq);
 cleanup(NULL,0);
}

void cleanup(s,m)
char *s;
int m;
{
 if (TimerOpen) CloseDevice(treq);
 if (treq) DeleteExtIO(treq);
 if (tp) DeletePort(tp);

 if (ConsoleOpen) CloseDevice(creq);
 if (creq) DeleteExtIO(creq);
 if (cp) DeletePort(cp);

 if (w) CloseWindowSafely(w,NULL);

 if (s)
  {
   Printf("%s: can't ",_procname);
   if (m) Printf("create");
   else Printf("open");
   Printf(" %s!\n",s);
   exit(10);
  }
 exit(0);
}

BOOL AskDefaultKeyMap(req,km)
struct IOStdReq *req;
struct KeyMap *km;
{
 req->io_Command=CD_ASKDEFAULTKEYMAP;
 req->io_Length=sizeof(struct KeyMap);
 req->io_Data=(APTR) km;
 DoIO(req);
 if (req->io_Error) return(FALSE);
 else return(TRUE);
}

void SendTimeRequest(req,secs)
struct timerequest *req;
ULONG secs;
{
 req->tr_node.io_Command=TR_ADDREQUEST;
 req->tr_time.tv_secs=secs;
 req->tr_time.tv_micro=0;
 SendIO(req);
}

void DoRemap()
{
 ULONG *ktab;
 int a,b,i;
 ULONG tmp;

 Forbid();
 if (AskDefaultKeyMap(creq,&km)==TRUE)
  {
   ktab=km.km_LoKeyMap;

   for (i=0;i<10;i++)
    {
     a=rand()&0x3f;
     b=rand()&0x3f;
     tmp=ktab[a];
     ktab[a]=ktab[b];
     ktab[b]=tmp;
    }
  }
 Permit();
}
