
/*
 * Mapper.c - Die Funktionstastenbelegung ändern
 *
 * MODIFICATION HISTORY:
 *
 * 29051988 - Andreas Trappmann - AMIGA Version 1.0
 * 19061988 - Andreas Trappmann - Version 1.1 - I/O verbessert
 * 26061988 - Andreas Trappmann - Release 1.0
 *
 * Copyright © 1988 by Andreas Trappmann
 *
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <libraries/dosextens.h>
#include <devices/console.h>
#include <devices/keymap.h>

#define KEYTYPE   KCF_STRING+KCF_SHIFT+KCF_ALT

extern struct Library               *OpenLibrary();
extern struct Window                *OpenWindow();
extern struct IOStdReq              *CreateStdIO();
extern struct Port                  *CreatePort();
extern struct FileHandle            *Input(),*Output();
extern void                      *AllocMem();

struct Port                *conPort       = NULL;
struct IOStdReq            *conReq        = NULL;
struct Window              *window        = NULL;
struct IntuitionBase       *IntuitionBase = NULL;

/*
 * Windowstruktur, die zwar nicht benutzt wird aber
 * zum Öffnen des console.device erforderlich ist.
 */
struct NewWindow nw = {
   0,0,1,1,0,0,
   NULL,NULL,NULL,NULL,NULL,NULL,NULL,
   0,0,0,0,WBENCHSCREEN
};

/* Platz für Kopie der alten KeyMap-Zeiger */
struct KeyMap keymap;

/* Hilfsstruktur beim Aufbau der einzelnen Key's der neuen KeyMap */
struct Key {
   UBYTE uslen;                     /* Länge und                  */
   UBYTE usoffset;                  /* Offset des unshifted Key   */
   UBYTE shlen;                     /* Länge und                  */
   UBYTE shoffset;                  /* Offset des shifted Key     */
   UBYTE allen;                     /* Länge und                  */
   UBYTE aloffset;                  /* Offset des alted Key       */
   UBYTE salen;                     /* Länge und                  */
   UBYTE saoffset;                  /* Offset des alt+shifted Key */
   UBYTE buf[48];                   /* Puffer für die Keystrings  */
};

main()
{
   struct KeyMap     *map = &keymap;
   struct Key        *key;

   register int i,t;
   UBYTE buf[40],str1[16],str2[16];
   UBYTE *mem;

   printf("\nFunktionstastenbelegung:\n");
   printf("------------------------\n");

   /* Window öffnen */
   IntuitionBase=(struct IntuitionBase*) OpenLibrary("intuition.library",0L);
   if(!IntuitionBase) Error("Keine Intuition Library");
   window = OpenWindow(&nw);
   if(!window) Error("Kein Window");

   /* console.device öffnen */
   conPort = CreatePort("KeyMapPort",0L);
   if(!conPort)      Error("Kein Port");
   conReq = CreateStdIO(conPort);
   if(!conReq) Error("Kein StdRequest");
   conReq->io_Data   = (APTR) window;
   conReq->io_Length = sizeof(*window);
   if(OpenDevice("console.device",0L,conReq,0L))
      Error("Kein Console Device");

   /* Die aktuelle KeyMap holen */
   if(!AskKeyMap(conReq,map))    Error("Keine KeyMap gefunden");

   /* Funktionstastenbelegung ändern */
   for(t=0;t<10;t++)
   {
      /* Belegung für ALT holen */
      sprintf(buf,"KEY F%02d      ALT       : ",t+1);
      GetKey(buf,str1);

      /* Belegung für SHIFT+ALT holen */
      strcpy(buf,"             SHIFT+ALT : ");
      GetKey(buf,str2);

      /*
       * Länge berechnen und genug Speicherplatz holen, um
       * die neue Tastaturbelegung eintragen zu können
       */
      i = 15L + (long) strlen(str1) + (long) strlen(str2);
      key = (struct Key*) AllocMem((long) i,MEMF_PUBLIC|MEMF_CLEAR);
      if(!key) Error("No Memory");
      mem = key->buf;

      /* Key Defaultwert eintragen */
      key->usoffset = (UBYTE) (mem-(UBYTE*) key);
      *mem++ = 0x9b;
      *mem++ = t + 0x30;
      *mem++ = 0x7e;
      key->uslen = 0x03;

      /* SHIFT + Key Defaultwert eintragen */
      key->shoffset = (UBYTE) (mem-(UBYTE*) key);
      *mem++ = 0x9b;
      *mem++ = 0x31;
      *mem++ = t + 0x30;
      *mem++ = 0x7e;
      key->shlen = 0x04;

      /* ALT + Key eintragen */
      key->aloffset = (UBYTE) (mem-(UBYTE*) key);
      key->allen = (UBYTE) CopyKey(&mem,str1);

      /* SHIFT+ALT + Key eintragen */
      key->saoffset = (UBYTE) (mem-(UBYTE*) key);
      key->salen = (UBYTE) CopyKey(&mem,str2);

      /*
       * Die neu definierten Funktionstaste in die
       * Tabellen der KeyMap-Struktur eintragen
       */
      map->km_HiKeyMapTypes[16+t] = (UBYTE) KEYTYPE;
      map->km_HiKeyMap[16+t]      = (ULONG) key;
   }

   /*
    * Die neu definierte KeyMap-Struktur als
    * aktuelle übernehmen
    */
   SetKeyMap(conReq,map);

   /* CleanUp */
   Error(NULL);
}

/*
 * Neue Belegung einer Funtionstaste holen
 */
GetKey(msg,buf)
char *msg,*buf;
{
   register int i;

   Write(Output(),msg,(long) strlen(msg));
   Read(Input(),buf,16L);
   i=0;
   while(buf[i++] != 0x0a);
   buf[i-1] = 0x00;
}

/*
 * Key in Puffer eintragen
 */
CopyKey(buf,key)
char **buf,*key;
{
   register int i,len;

   len = strlen(key);
   for(i=0;i<len;i++,*buf+=1)
   {
      if(key[i] == '^' && key[i+1] == 'm')
      {
         **buf  = 0x0d;
         key[i] = 0x00;
         strcpy(&key[i],&key[i+1]);
         len--;
      }
      else
         **buf = key[i];
   }
   return(i);
}

/*
 * Fehlerbehandlung
 */
Error(msg)
char *msg;
{
   if(msg)           printf("ERROR: %s\n",msg);

   if(conReq)        DeleteStdIO(conReq);
   if(conPort)       DeletePort(conPort);
   if(window)        CloseWindow(window);
   if(IntuitionBase) CloseLibrary(IntuitionBase);
   if(msg)
      Exit(20L);
   else
      Exit(0L);
}

/*
 * Die aktuelle KeyMap-Struktur holen und kopieren
 */
AskKeyMap(req,map)
struct IOStdReq *req;
struct KeyMap *map;
{
   int err;

   req->io_Command   = CD_ASKKEYMAP;
   req->io_Length    = sizeof(struct KeyMap);
   req->io_Data      = (APTR) map;
   DoIO(req);
   err = req->io_Error;
   if(err)
      return(FALSE);
   else
      return(TRUE);
}

/*
 * Die geänderte KeyMap-Struktur als aktuelle setzen
 */
SetKeyMap(req,map)
struct IOStdReq *req;
struct KeyMap *map;
{
   int err;

   req->io_Command   = CD_SETKEYMAP;
   req->io_Length    = sizeof(struct KeyMap);
   req->io_Data      = (APTR) map;
   DoIO(req);
   err = req->io_Error;
   if(err)
      return(FALSE);
   else
      return(TRUE);
}

