#include <stdio.h>
#include <exec/types.h>
#include <exec/io.h>
#include <exec/memory.h>

#include <graphics/gfxbase.h>
#include <graphics/text.h>
#include <graphics/gfxmacros.h>
#include <devices/console.h>
#include <devices/keymap.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <intuition/intuition.h>
#include <functions.h>

#define IMSG struct IntuiMessage *
#define KEYBASE 63

UBYTE the_name[96];
UBYTE buffer[96];
struct GfxBase *GfxBase;
struct IntuitionBase *IntuitionBase;

/*  All the intuition structs & screen array data is in intui.c  */

#include "externs.h"
#include "i.c"


main(argc,argv)
int argc;
char *argv[];
{
   struct IntuiMessage *NewMessage; /* msg structure for GetMsg() */
   struct Gadget *the_gadget;
   ULONG class;
   USHORT mode,menunumber,code,pos,quit_sig,val;
   USHORT itemnum,subnum;
   long position;
   struct MenuItem *item;
   char *go;
   SHORT KeepGoing = TRUE;    /* main loop control value */

   BOOL modified = FALSE;
   BOOL success;
   short i,j,k,l,q,which;
   long qual_flag,num1,oflg;
   USHORT rawkey;
   short totlen,toolong;

   mode = 1;

   if(!(IntuitionBase=(struct IntuitionBase *)
                            OpenLibrary("intuition.library",0L)))
      exit(100);
   if(!(GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0L)))
      exit(101);
   if((w=OpenWindow(&nw))==NULL)
      exit(102);
   if (OpenConsole(w)!=NULL)     exit(103);

   AllocKeyMap();
   if(abort) goto error;
   
   DefaultKeyMap();
   if(abort) goto error;

   filestring[0] = NULL;

   if(argc == 2) {
       strcpy(filestring, argv[1]);
       strcpy(the_name, dirstring);
       if((!(the_name[strlen(the_name)-1] == '/'))
              && (!(the_name[strlen(the_name)-1] == ':')))
                   strcat(the_name,"/");
       strcat(the_name, filestring);
       if(!LoadKeyMap(the_name)) {
          oflg = AutoRequest(w,&err_txt,NULL,
                     &no_txt,NULL,NULL,330L,60L);
       }
       if(abort) goto error;
    }

/*  Initialize the keyboard gadgets.          */

for(i=0;i<90;i++) {
   if(i!=89)
      gadget[i].NextGadget = &gadget[i+1];
   gadget[i].LeftEdge = l_edge[i];
   gadget[i].TopEdge = KEYBASE + t_edge[i];
   gadget[i].Width = width[i];
   gadget[i].Height = 11;
   gadget[i].Flags = GADGHNONE;
   gadget[i].Activation = GADGIMMEDIATE;
   gadget[i].GadgetType = BOOLGADGET;
   gadget[i].GadgetRender = NULL;
   gadget[i].SelectRender = NULL;
   gadget[i].GadgetText = NULL;
   gadget[i].MutualExclude = 0;
   gadget[i].SpecialInfo = NULL;
   gadget[i].GadgetID = i;
   gadget[i].UserData = NULL;
   };
gadget[89].NextGadget = NULL;

/*----------------------------------------------------------------------*/
/*  Special non-universal gadget initializations.     */

/* Return Key */
gadget[89].Height = 13;

/* The qualifier keys */
gadget[47].UserData = gadget[48].UserData = gadget[65].UserData = 
  gadget[76].UserData = gadget[81].UserData = gadget[85].UserData = (APTR)1L;
gadget[47].Flags = gadget[48].Flags = gadget[65].Flags = 
  gadget[76].Flags = gadget[81].Flags = gadget[85].Flags = GADGHNONE;

/* Disable Amiga Keys!!!!!  */
gadget[84].Flags = gadget[82].Flags = GADGDISABLED;

/*----------------------------------------------------------------------*/

qual_flag = 0;

instring[0] = undostring[0] = NULL;
hexinstring[0] = hexundostring[0] = NULL;

/*   Turn on the screen image!   */
DrawImage(w->RPort,(struct Image *)&skl_img,1L,15L);
if (argc==0) sv_st_item.Flags &= (~ITEMENABLED);
SetMenuStrip(w, &menu);

   while( KeepGoing )
   {
      /* stay here until a message is received from Intuition */
      Wait( 1L << w->UserPort->mp_SigBit);

      while(NewMessage=(IMSG)GetMsg(w->UserPort))  {
      class = NewMessage->Class;
      code = NewMessage->Code;
      the_gadget = (struct Gadget *)NewMessage->IAddress;
      ReplyMsg( NewMessage );

      /* enter switch on type of message received */
      switch( class )
      {
         case CLOSEWINDOW:
            goto get_out;
            break;

         case MENUPICK:
            menunumber = code;
               itemnum = ITEMNUM(menunumber);
               switch(itemnum) {

                  case MODE_IT:   /* Change Modes */
                  mode = SUBNUM(menunumber);
                  break;
                     
                  case LOAD_IT:   /* Load */
                  if(modified) {
                   oflg = AutoRequest(w,&ald_txt,&ayes_txt,
                                 &no_txt,NULL,NULL,310L,60L);
                   if(!oflg)
                     goto skip1;
                  }
          /********************************************************/
          /*  here's where you load a keymap                      */
          /********************************************************/
                  /*   if go, load it.   */
                  if(go = get_name(w)) {
                    if(LoadKeyMap(the_name)) 
                        modified = FALSE;
                    else {
                        oflg = AutoRequest(w,&err_txt,NULL,
                                 &no_txt,NULL,NULL,330L,60L);
                    }
                  }
                  if(abort) goto error;
                  skip1:
                  break;

                  case SAVE_IT:   /* Save */
                  /*   if go, save it.   */
          /********************************************************/
          /*  here's where you save a keymap                      */
          /********************************************************/
                  if(go = get_name(w)) {
                    if(SaveKeyMap(the_name)) 
                        modified = FALSE;
                    else {
                        oflg = AutoRequest(w,&err_txt,NULL,
                                 &no_txt,NULL,NULL,330L,60L);
                    }
                  }
                  if(abort) goto error;
                  break;

                  case EXIT_OPT:   /* Quit */
                  get_out:
                  if(modified) {
                   oflg = AutoRequest(w,&auto_txt,&yes_txt,
                                 &no_txt,NULL,NULL,380L,60L);
                   if(!oflg)
                     goto skip;
                  }
                  if(class == CLOSEWINDOW) goto gone;
                  subnum = SUBNUM(menunumber);
                  if(subnum) {                /* Exit without setting */
                    gone:
                    KeepGoing = FALSE;
                    break;
                    }
                  else {                      /* Exit & Set           */
                    strcpy(buffer,"setmap ");
                    strcat(buffer,filestring);
                    Execute(buffer,0L,0L);
                    KeepGoing = FALSE;
          /********************************************************/
          /*  here's where you setmap                             */
          /********************************************************/
                    break;
                    }
                  skip:
                  break;

                  case CRED_IT:
                   oflg = AutoRequest(w,&cred_txt,NULL,
                                 &no_txt,NULL,NULL,500L,85L);
                  break;

                  default:
                  break;

               }
            break;

         default:

            if((class == RAWKEY) && (code > 0x65)) 
                break;

         /*  Set which & rawkey                            */
         /*  "which" corresponds to my gadget list index.  */
         /*  rawkey corresponds to the Amiga keycode       */
            if(class == GADGETDOWN) {
               which = the_gadget->GadgetID;
               rawkey = g_to_key[which];
               }
            if(class == RAWKEY) {
               which = key_to_g[code];
               rawkey = code;
               }

    /* This test determines whether this is a qualifier key selected
       or a "normal" key                                             */

         num1 = (LONG)gadget[which].UserData;
         switch(num1) {
   /*----------------------------------------------------------------------*/
             case 0:

         /*  This is a normal key                          */

          /*  put ASCII keycode into text string for requester    */
               sprintf(&code_buff[10],"%02.2x (hex)",rawkey);
          /*  put qualifiers into text string for requester       */
               sprintf(&qualtxt[11],"%s",&qual_name[qual_flag][0]);
          /*  set name of key for requester                       */
               name_text.IText = (UBYTE *)&name[which][0];

             if((which==89) || (which==60))
                return_key(w->RPort);
             else
                fillup(w->RPort,which);

          /********************************************************/
          /* here's where you copy key string text into &instring */
          /********************************************************/

               String(rawkey);
               strcpy(instring, DStr[qual_flag].string);

               if(mode) {
          /*  set up the hex string buffer                        */
               pos = stringinfo.BufferPos;
               val = (SHORT)instring[pos];
               sprintf(&hexval[0],"%02.2x",val);
               hexinstring[0] = '\0';

          /*  turn on main requester                              */
               Request(&main_requester, w);

               quit_sig = 0;

          /*  wait for the user to hit the gadgets                */

             do {
               Wait( 1L << w->UserPort->mp_SigBit);

          /*  Get the message & copy the stuff.                   */
               while(NewMessage=(IMSG)GetMsg(w->UserPort)) {
               class = NewMessage->Class;
               code = NewMessage->Code;
               the_gadget = (struct Gadget *)NewMessage->IAddress;
          /*  Reply to the message     */
               ReplyMsg( NewMessage );
               if (class==REQSET)
                  success = ActivateGadget(&input_gadget,w,&main_requester);
               else
                  switch(the_gadget->GadgetID)
                  {

              case STRING_ID:
                 if(class == GADGETUP)
                 {
                    pos = stringinfo.BufferPos;
                    if(pos == stringinfo.NumChars)
                       instring[pos+1] = '\0';
                    instring[pos] = 0x0d;
                    stringinfo.BufferPos++;
                    pos++;
                    val = (SHORT)instring[pos];
                    sprintf(&hexval[0],"%02.2x",val);
                 }
                 EndRequest(&main_requester, w);
                 Request(&main_requester, w);
                 break;

              case HEX_ID:
                 if(class == GADGETDOWN)
                 {
                   pos = stringinfo.BufferPos;
                   val = (SHORT)instring[pos];
                   sprintf(&hexval[0],"%02.2x",val);
                   hexinstring[0] = '\0';
                 }
                 else
                 {
                 /* Save current hex char at old pos          */
                    if(pos == stringinfo.NumChars)
                       instring[pos+1] = '\0';
                    sscanf(&hexinstring[0],"%x",&val);
                    strcpy(&hexval[0],&hexinstring[0]);
                    instring[pos] = val;
                 }
                 RefreshGList(&quitgadget,w,&main_requester,-1L);
                 break;

              case CANCEL_ID:  /*  This is the "cancel request" exit */
                 quit_sig = 1;
                 break;

              case QUIT_ID:    /*  This is the "Modify keymap" exit  */
          /********************************************************/
          /*  here's where you modify the keymap                  */
          /********************************************************/

                 strcpy(DStr[qual_flag].string,instring);
                 DStr[qual_flag].length = strlen(DStr[qual_flag].string);
                 toolong=totlen=0;
                 for(i=0;i<8;i++)
                 {
                    if(totlen>127)toolong=1;
                    totlen+=DStr[i].length;
                 }

                 modified = TRUE;
                 if(toolong) 
                 {
                    EndRequest(&main_requester, w);
                    Request(&main_requester, w);
                    AutoRequest(w,&toolong_txt,NULL,&no_txt,NULL,NULL,400L,60L);
                 }
                 else 
                 {
                    quit_sig = 1;
                    DeString(rawkey);
                 }
                 break;

              default:
                 break;
               }
             }  /* End of message response while */
             } while(!quit_sig);
             EndRequest(&main_requester, w);
             if(abort) goto error;
             }
             else {
                strcpy(&dstr_msg[24],name[which]);
                for (q=0;q<8;q++) {
                    for(l=0;qual_name[q][l]!='\0';l++)
                        kstr[q][l] = qual_name[q][l];

                    kstr[q][l++] = ' ';
                    kstr[q][l++] = ' ';

                    for(k=0;DStr[q].string[k] != '\0';k++)
                    {
                       switch(DStr[q].string[k]) {
                         case 0x0D:
                             kstr[q][l++] = '<';
                             kstr[q][l++] = 'C';
                             kstr[q][l++] = 'R';
                             kstr[q][l++] = '>';
                             break;
                            case 0x1F: case 0x1E: case 0x1D:
                            case 0x1C: case 0x1B: case 0x1A: case 0x19:
                         case 0x18: case 0x17: case 0x16: case 0x15:
                         case 0x14: case 0x13: case 0x12: case 0x11:
                         case 0x10: case 0x0F: case 0x0E:
                         case 0x0C: case 0x0B: case 0x0A: case 0x09:
                         case 0x08: case 0x07: case 0x06: case 0x05:
                         case 0x04: case 0x03: case 0x02: case 0x01:
                             kstr[q][l++] = 0x9B;
                               break;
                         default:
                             kstr[q][l++] = DStr[q].string[k];
                                break;
                   }
                }
                kstr[q][l] = '\0';
               }
               oflg = AutoRequest(w,&dstr,NULL,
                                 &no_txt,NULL,NULL,640L,130L);

             }

             if((which==89) || (which==60))
                return_key(w->RPort);
             else
                fillup(w->RPort,which);

   /*----------------------------------------------------------------------*/
             break;             /*  end of "normal" key handler            */

         case 1:
   /*    This is the qualifier handler.                */
         switch (which) {

           case 47:   /*  Control */
             qual_flag ^= KCF_CONTROL;
             fillup(w->RPort, 47);
             break;

           case 48:   /*  Shift   */
           case 65:
           case 76:
             qual_flag ^= KCF_SHIFT;
             fillup(w->RPort, 65);
             fillup(w->RPort, 76);
             fillup(w->RPort, 48);
             break;

           case 81:   /*  alt     */
           case 85:
             qual_flag ^= KCF_ALT;
             fillup(w->RPort, 81);
             fillup(w->RPort, 85);
             break;

           default:
             break;
         }
   /*----------------------------------------------------------------------*/
           break;                            /*  End of qualifier handler  */
      }                                      /*  End of UserData switch    */
    }                                        /*  End of type of message    */
   }                                         /*  End of while messages     */
   }                                         /*  End of "keep going"       */

   ClearStr(120);
   FreeKeyMap(4);

error:
   if(abort) Exit(103L);
   ClearMenuStrip(w);
   ConsoleCleanup();
   CloseWindow(w);
   CloseLibrary(GfxBase);
   CloseLibrary(IntuitionBase);
}


fillup(rp, gadget_no)
struct RastPort *rp;
SHORT gadget_no;
{
long le,te,re,be;

SetAPen(rp, 3L);
SetDrMd(rp,COMPLEMENT);

 le = l_edge[gadget_no];
 te = KEYBASE+t_edge[gadget_no];
 re = l_edge[gadget_no] + width[gadget_no] - 1;
 be = te + 10;
 RectFill(rp,le,te,re,be);
}

return_key(rp)
struct RastPort *rp;
{
SetAPen(rp, 0L);
SetDrMd(rp,COMPLEMENT);
RectFill(rp,439L,87L,479L,109L);
RectFill(rp,417L,99L,438L,109L);
}
