/* $Revision Header *** Header built automatically - do not edit! ***********
 *
 *	(C) Copyright 1991 by Peter Vorwerk
 *
 *	Name .....: PCExecute.c
 *	Created ..: Monday 05-Aug-91 11:03
 *	Revision .: 2
 *
 *	Date            Author          Comment
 *	=========       ========        ====================
 *	03-Sep-91       Peter Vorwerk   Added AREXX port
 *	01-Sep-91       Peter Vorwerk   Added Gadgets for F-keys
 *	                                and some other keys
 *
 *	05-Aug-91       Peter Vorwerk   Created this file!
 *
 * $Revision Header ********************************************************/
 #define REVISION 2

#define VERSION 1

#include <exec/types.h>
#include <intuition/intuition.h>
#include <exec/libraries.h>
#include <janus/janus.h>
#include <libraries/arpbase.h>
#include <libraries/reqbase.h>
#include <proto/req.h>
#include <functions.h>
#include <libraries/rexxhostbase.h>

extern char *strupr(char *);

UBYTE  *KeyB;
UBYTE  *IntR;

struct Syscall86 *Ptr;
RPTR OldPtr;

struct Library      *JanusBase;
struct ReqLib       *ReqBase;
struct RexxHostBase *RexxHostBase;
struct RexxHost     *rexx_host;

struct Window       *window;
struct GadgetBlock  *first_row;
struct GadgetBlock  *second_row;
struct GadgetBlock  *third_row;

UBYTE tab[] = {
    /* 00 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    /* 08 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    /* 10 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    /* 18 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    /* 20 */    0x39, 0x82, 0xa8, 0x84, 0x85, 0x86, 0x2b, 0x28,
    /* 28 */    0x8a, 0x8b, 0x89, 0x8d, 0x33, 0x0c, 0x34, 0x35,
    /* 30 */    0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
    /* 38 */    0x09, 0x0a, 0xa7, 0x27, 0xb3, 0x0d, 0xb4, 0xb5,
    /* 40 */    0x83, 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22,
    /* 48 */    0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18,
    /* 50 */    0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11,
    /* 58 */    0x2d, 0x15, 0x2c, 0x1a, 0x2b, 0x1b, 0x87, 0x8c
};

UBYTE key[] = {
    /* 00 */    0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44,
    /* 10 */    0x4b, 0x48, 0x50, 0x4d, 0x47, 0x49, 0x51, 0x4f, 0x01, 0x0f,
    /* 20 */    0x45, 0x46, 0x3a, 0x52, 0x37, 0x1d, 0x2a, 0x38, 0x53, 0x0e,
                0x39, 0x1c
};

void PCKeyB(void)
{
    UBYTE *ptr;
    UWORD *offset;

/* Die Keyboard Addresse ist als positiver Offset 0x72 in der Janus.library abgelegt. */
/* Achtung! Im 'Amiga SYSTEM-Handbuch wird die feste Addresse 0x7ffff als Keyboard Addresse
   genannt. Bei meinem Amiga 2000 mit AT Karte stimmte dies, jedoch nicht beim SideCar.

   Die Offset Struktur wurde experimentell ( teilweiser Speicherdump vom Programm
   PCWINDOW ) ermittelt. Zum Glück stimmte wenigstens die Adresse des Interrupts,
   so konnte ich im Speicher nach dem Auftreten dieser Kombination suchen und die
   nähere Umgebung disassemblieren. */

/* Keyboard address. Please note 0x7ffff is NOT the correct address in ALL Systems.
   You must calculate it by contents of (JanusBase + 0x72) + 0x7e000 !! */

/* I found this by disassembling the file PCWINDOW. */

    KeyB     = (UBYTE *) JanusBase;
    KeyB    += 0x72;
    offset   = (UWORD *) KeyB;
    ptr      = (UBYTE *) GetJanusStart();
    KeyB     = ptr + 0x7e000;
    KeyB    += *offset;
    IntR     = ptr + 0x7fffb; /* Addresse aus 'Amiga SYSTEM-Handbuch' */
}

void PC_Cmd(char *cmd)
{
    UBYTE wert;

    if (cmd == NULL || *cmd == 0)
        return;

    *KeyB = 0x1d; /* CTRL */
    *IntR = 0xff;
    Delay(1);
    *KeyB = 0x38; /* ALT */
    *IntR = 0xff;
    Delay(1);
    *KeyB = 0x3b; /* F1 */
    *IntR = 0xff;
    Delay(1);
    *KeyB = 0xbb; /* ~F1 */
    *IntR = 0xff;
    Delay(1);
    *KeyB = 0xb8; /* ~ALT */
    *IntR = 0xff;
    Delay(1);
    *KeyB = 0x9d; /* ~CTRL */
    *IntR = 0xff;
    Delay(1);

    while(*cmd != '\0')
    {
        wert = tab[*cmd++];
        if (wert > 0x80)
        {
            wert -= 0x80;

            *KeyB = (UBYTE) 0x2a;
            *IntR = (UBYTE) 0xff;
            Delay(1);

            *KeyB = wert;
            *IntR = (UBYTE) 0xff;
            Delay(1);

            *KeyB = (UBYTE) 0xaa;
            *IntR = (UBYTE) 0xff;
            Delay(1);
        }
        else
        {
            *KeyB = wert;
            *IntR = (UBYTE) 0xff;
            Delay(1);
        }
    }

    *KeyB = 0x1d; /* CTRL */
    *IntR = 0xff;
    Delay(1);
    *KeyB = 0x38; /* ALT */
    *IntR = 0xff;
    Delay(1);
    *KeyB = 0x3c; /* F2 */
    *IntR = 0xff;
    Delay(1);
    *KeyB = 0xbc; /* ~F2 */
    *IntR = 0xff;
    Delay(1);
    *KeyB = 0xb8; /* ~ALT */
    *IntR = 0xff;
    Delay(1);
    *KeyB = 0x9d; /* ~CTRL */
    *IntR = 0xff;
    Delay(1);
}

char text1[10][6] =
        { " F1  ", " F2  ", " F3  ", " F4  ", " F5  ",
          " F6  ", " F7  ", " F8  ", " F9  ", " F10 " };
char text2[10][6] =
        { " <-  ", " up  ", "down ", " ->  ", "Home ",
          "Pg Up", "Pg Dn", " End ", " ESC ", " TAB " };
char text3[10][6] =
        { "NumL ", "ScrL ", "CapsL", " Ins ", "PrtSc",
          "CTRL ", "SHIFT", " ALT ", " Del ", " BS  " };

char *cmdlist[] = {
"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10",

"RIGHT", "UP", "DOWN", "LEFT", "HOME", "PAGE_UP", "PAGE_DOWN",
"END", "ESC", "TAB",

"NUM_LOCK", "SCROLL_LOCK", "CAPS_LOCK", "INS", "PRINT_SCREEN",
"CTRL", "SHIFT", "ALT", "DEL", "BACKSPACE",

"SPACE", "ENTER"
};

void Press(char *cmd)
{
    int i,j;
    struct GadgetBlock *gadget;

    for(i = 0; i < 32; i++)
    {
        if (Strcmp(cmd,cmdlist[i]) == 0)
        {
            *KeyB = key[i];
            *IntR = (UBYTE) 0xff; /* Send Key-Interrupt */
            Delay(1);
            if (i > 30)
                break;
            else if (i > 20)
            {
                i -= 20;
                gadget = third_row;
            }
            else if (i >10)
            {
                i -= 10;
                gadget = second_row;
            }
            else
                gadget = first_row;
            while(--i >= 0)
                gadget++;
            j = RemoveGadget(window,&gadget->Gadget);
            gadget->Gadget.Flags |= SELECTED;
            AddGadget(window,&gadget->Gadget,j);
            RefreshGadgets(&gadget->Gadget,window,NULL);
            break;
        }
    }
}

void Release(char *cmd)
{
    int i,j;
    struct GadgetBlock *gadget;

    for(i = 0; i < 32; i++)
    {
        if (Strcmp(cmd,cmdlist[i]) == 0)
        {
            *KeyB = key[i] + 0x80;
            *IntR = (UBYTE) 0xff; /* Send Key-Interrupt */
            Delay(1);
            if (i > 30)
                break;
            else if (i > 20)
            {
                i -= 20;
                gadget = third_row;
            }
            else if (i >10)
            {
                i -= 10;
                gadget = second_row;
            }
            else
                gadget = first_row;
            while(--i >= 0)
                gadget++;
            j = RemoveGadget(window,&gadget->Gadget);
            gadget->Gadget.Flags &= ~SELECTED;
            AddGadget(window,&gadget->Gadget,j);
            RefreshGadgets(&gadget->Gadget,window,NULL);
            break;
        }
    }
}

void GetCmd(char *Buffer)
{
    char                           Undobuffer[256];
    register short                 gadgetnum,class,select;
    register struct  IntuiMessage  *message;
    register int                   i;

    struct GadgetBlock             *ok_block;
    struct GadgetBlock             *cancel_block;
    struct StringBlock             *string_block;

    struct GadgetBlock             *row;

    struct RexxMsg *rexxmessage;   /* incoming rexx messages */
    STRPTR         Arg;            /* Temporary string pointer */
    char           ArgBuff[40];    /* Temporary argument buffer */
    ULONG          SignalSet;      /* Incoming signals. */
    LONG           NumResult;      /* Return code. */
    STRPTR         StringResult;   /* Result string (error message). */

    struct NewWindow nw =
        {
            0,0,                                /* LeftEdge, TopEdge */
            640,90,                             /* Width, Height */
            -1,-1,                              /* DetailPen, BlockPen */
            GADGETUP | CLOSEWINDOW,             /* IDCMPFlags */
            SMART_REFRESH | ACTIVATE |
            WINDOWDRAG | WINDOWDEPTH |
            WINDOWCLOSE,                        /* Flags */
            NULL,                               /* FirstGadget */
            NULL,                               /* CheckMark */
            (UBYTE *) "Enter your PC command",  /* Title */
            NULL,                               /* Screen */
            NULL,                               /* BitMap */
            0,0,                                /* MinWidth, MinHeight */
            0,0,                                /* MaxWidth, MaxHeight */
            WBENCHSCREEN                        /* Type (of screen) */
        };

    if ((ok_block     = AllocMem(sizeof(struct GadgetBlock),MEMF_CLEAR)) == NULL)
        return;
    if ((cancel_block = AllocMem(sizeof(struct GadgetBlock),MEMF_CLEAR)) == NULL)
        return;
    if ((string_block = AllocMem(sizeof(struct StringBlock),MEMF_CLEAR)) == NULL)
        return;

    if ((first_row    = AllocMem(sizeof(struct GadgetBlock) * 10,MEMF_CLEAR)) == NULL)
        return;
    if ((second_row   = AllocMem(sizeof(struct GadgetBlock) * 10,MEMF_CLEAR)) == NULL)
        return;
    if ((third_row    = AllocMem(sizeof(struct GadgetBlock) * 10,MEMF_CLEAR)) == NULL)
        return;

    LinkGadget(ok_block,     "Ok",     &nw,  12, 75);
    LinkGadget(cancel_block, "Cancel", &nw, 628, 75);
    LinkStringGadget(string_block, Buffer, Undobuffer, &nw, 616, 255, 12, 60);
    ok_block    ->Gadget.GadgetID  = 1;
    cancel_block->Gadget.GadgetID  = 2;
    string_block->Gadget.GadgetID  = 3;
    cancel_block->Gadget.LeftEdge -= cancel_block->Gadget.Width;

    row = first_row;
    for(i = 0; i < 10; i++)
    {
        LinkGadget(row, text1[i], &nw, 12+i*64, 15);
        row->Gadget.Activation |= TOGGLESELECT;
        row->Gadget.GadgetID    = i+4;
        row++;
    }
    row = second_row;
    for(i = 0; i < 10; i++)
    {
        LinkGadget(row, text2[i], &nw, 12+i*64, 30);
        row->Gadget.Activation |= TOGGLESELECT;
        row->Gadget.GadgetID    = i+14;
        row++;
    }
    row = third_row;
    for(i = 0; i < 10; i++)
    {
        LinkGadget(row, text3[i], &nw, 12+i*64, 45);
        row->Gadget.Activation |= TOGGLESELECT;
        if (i == 0 && (Ptr->s86_AX & 0x20))
            row->Gadget.Flags |= SELECTED;
        if (i == 1 && (Ptr->s86_AX & 0x10))
            row->Gadget.Flags |= SELECTED;
        if (i == 2 && (Ptr->s86_AX & 0x40))
            row->Gadget.Flags |= SELECTED;
        if (i == 3 && (Ptr->s86_AX & 0x80))
            row->Gadget.Flags |= SELECTED;
        row->Gadget.GadgetID    = i+24;
        row++;
    }
    Center(&nw, nw.Width - (cancel_block->Gadget.Width >> 1) - 12, 75 + (cancel_block->Gadget.Height >> 1));

    if (!(window = (struct Window *) OpenWindow(&nw)))
        return;

    ActivateGadget(&string_block->Gadget,window,NULL);

    do
    {
        SignalSet = Wait(1L << window->UserPort->mp_SigBit | HOSTMASK(rexx_host));
        if (SignalSet & (1L << window->UserPort->mp_SigBit))
        {
            message   = (struct IntuiMessage *) GetMsg(window->UserPort);
            gadgetnum = ((struct Gadget *) (message->IAddress))->GadgetID;
            select    = ((struct Gadget *) (message->IAddress))->Flags;
            class     = message->Class;
            ReplyMsg((struct Message *)message);
        }
        if (class != CLOSEWINDOW && gadgetnum != 2)
        {
            OldPtr = SetParamOffset(JSERV_PCCALL,JanusMemToOffset(Ptr));
            Ptr->s86_AX  = 0x0200;
            Ptr->s86_INT = 0x16;
            SendJanusInt(JSERV_PCCALL);
            Delay(10);
            SetParamOffset(JSERV_PCCALL,OldPtr);
        }

            /* did we get something from rexx? */

        if (RexxHostBase)
        {
            while(rexxmessage = GetRexxMsg(rexx_host,FALSE))
            {
                /* Getting a string pointer means
                 * that we've received a command.
                 */

                StringResult = NULL;
                NumResult    = 0;

                if(Arg = GetRexxCommand(rexxmessage))
                {
                    LONG CharCount = 0; /* Need counter, function reentrant. */

                    /* Now split the command string into arguments. */

                    GetToken(Arg,&CharCount,(STRPTR) ArgBuff,40);

                    if (Strcmp(ArgBuff,"COMMAND") == 0)
                    {
                        while(GetToken(Arg,&CharCount,(STRPTR) ArgBuff,40))
                        {
                            PC_Cmd(strupr(ArgBuff));
                            Delay(1);
                            *KeyB = (UBYTE) 0x39; /* SPACE */
                            *IntR = (UBYTE) 0xff; /* Send Key-Interrupt */
                            Delay(1);
                        }
                        *KeyB = (UBYTE) 0x1c;     /* ENTER */
                        *IntR = (UBYTE) 0xff;     /* Send Key-Interrupt */
                    }
                    else if (Strcmp(ArgBuff,"KEY") == 0)
                    {
                        char dummy[1024];

                        strcpy(dummy,(char *) Arg);
                        while(GetToken(Arg,&CharCount,(STRPTR) ArgBuff,40))
                            Press((char *) ArgBuff);

                        CharCount = 0;
                        GetToken((STRPTR) dummy,&CharCount,(STRPTR) ArgBuff,40);
                        while(GetToken((STRPTR) dummy,&CharCount,(STRPTR) ArgBuff,40))
                            Release((char *) ArgBuff);
                    }
                    else if (Strcmp(ArgBuff,"PRESS") == 0)
                    {
                        while(GetToken(Arg,&CharCount,(STRPTR) ArgBuff,40))
                            Press((char *) ArgBuff);
                    }
                    else if (Strcmp(ArgBuff,"RELEASE") == 0)
                    {
                        while(GetToken(Arg,&CharCount,(STRPTR) ArgBuff,40))
                            Release((char *) ArgBuff);
                    }
                    else
                    {
                        char dummy[80];

                        NumResult = 10;
                        SPrintf(dummy,"ERROR: Command \"%s\" is not supported in this version",
                                    ArgBuff);
                        StringResult = (STRPTR) dummy;
                    }
                }
                /* Reply the rexx command. */
                ReplyRexxCommand(rexxmessage,NumResult,0,StringResult);
            }
        }

        if (gadgetnum >= 4 && gadgetnum <= 34)
        {
            if (select & SELECTED)
            {
                *KeyB = key[gadgetnum-4];
                *IntR = (UBYTE) 0xff; /* Send Key-Interrupt */
                Delay(1);
            }
            else
            {
                if (gadgetnum != 26)
                    *KeyB = key[gadgetnum-4] + 0x80;
                else
                    *KeyB = key[gadgetnum-4];

/* Caps Lock is a (hardware) switch key. So this key must
   be pressed to send the release code! */

                *IntR = (UBYTE) 0xff; /* Send Key-Interrupt */
                Delay(1);
            }
        }
        if (gadgetnum == 1 || gadgetnum == 3)
        {
            int j;

            PC_Cmd(strupr(Buffer));
            *KeyB = (UBYTE) 0x1c;     /* ENTER */
            *IntR = (UBYTE) 0xff;     /* Send Key-Interrupt */
            Delay(1);

            j = RemoveGadget(window,&string_block->Gadget);
            *Buffer = 0;
            AddGadget(window,&string_block->Gadget,j);
            RefreshGadgets(&string_block->Gadget,window,NULL);
            ActivateGadget(&string_block->Gadget,window,NULL);
        }
    }
    while((gadgetnum != 2) && (class != CLOSEWINDOW));
    CloseWindow(window);
    FreeMem(ok_block,    sizeof(struct GadgetBlock));
    FreeMem(cancel_block,sizeof(struct GadgetBlock));
    FreeMem(string_block,sizeof(struct StringBlock));

    FreeMem(first_row,   sizeof(struct GadgetBlock) *10);
    FreeMem(second_row,  sizeof(struct GadgetBlock) *10);
    FreeMem(third_row,   sizeof(struct GadgetBlock) *10);
}

void main(int argc, char *argv[])
{
    int i;
    char buf[256] = 0;

    if (!(JanusBase   = ArpOpenLibrary("janus.library",0L)))
    {
        Puts("ERROR: Can't find Janus.library");
        exit(10);
    }
    if (!(ReqBase     = (struct ReqLib *) ArpOpenLibrary("req.library",0L)))
    {
        Puts("ERROR: Can't find Req.library");
        exit(10);
    }
    if (!(RexxHostBase = (struct RexxHostBase *) ArpOpenLibrary(REXXHOSTNAME,REXXHOSTMINIMUM)))
    {
        Puts("Sorry, couldn't open rexxhost library.");
    }
    if (RexxHostBase)
    {
        if (!(rexx_host    = CreateRexxHost((STRPTR)"PC_EX")))
        {
            Puts("Sorry, couldn't set up our public rexx port");
        }
    }
    if (RexxHostBase == NULL | rexx_host == NULL)
    {
        Puts("\nSo you can't use the AREXX port.\n");
    }
    if ((Ptr = (struct Syscall86 *) AllocJanusMem(sizeof(struct Syscall86),
        MEMF_PARAMETER | MEM_WORDACCESS)) != NULL)
    {
        OldPtr = SetParamOffset(JSERV_PCCALL,JanusMemToOffset(Ptr));
        Ptr->s86_AX  = 0x0200;
        Ptr->s86_INT = 0x16;
        SendJanusInt(JSERV_PCCALL);
        Delay(10);
        SetParamOffset(JSERV_PCCALL,OldPtr);
    }
    else
    {
        Puts("ERROR: No Janus mem free.");
        if (rexx_host)
            rexx_host = DeleteRexxHost(rexx_host);
        exit(10);
    }
    PCKeyB();
    Printf("[33m[1m%s[0m V%ld.%ld by Peter Vorwerk\t[1mPUBLIC DOMAIN[0m\n",
        BaseName(argv[0]),VERSION,REVISION);

    if (argc < 2)
    {
        GetCmd(buf);
        FreeJanusMem(Ptr,sizeof(struct Syscall86));
        if (rexx_host)
            rexx_host = DeleteRexxHost(rexx_host);
        exit(0);
    }

    for(i = 1; i < argc; i++)
    {
        PC_Cmd(strupr(argv[i])); /* Only upper case letters and digits are allowed */
        Delay(1);
        *KeyB = (UBYTE) 0x39; /* SPACE */
        *IntR = (UBYTE) 0xff; /* Send Key-Interrupt */
        Delay(1);
    }
    *KeyB = (UBYTE) 0x1c;     /* ENTER */
    *IntR = (UBYTE) 0xff;     /* Send Key-Interrupt */
    FreeJanusMem(Ptr,sizeof(struct Syscall86));
    if (rexx_host)
        rexx_host = DeleteRexxHost(rexx_host);
    exit(0);
}
