[net.micro.amiga] Bugs in key mapping

pk@pid.UUCP (Pushpa Kumar) (03/24/86)

*** REPLACE THIS LINE WITH YOUR MESSAGE ***

	There appears to be a bug in the keymapping routines when more than one 
qualifier is applied to a key.  I have setup a test program to illustrate this
problem.

	In the test program keys 1, 2 ,3, & 4 only have been mapped.
Key 4 + SHIFT is used to exit from the program.

The setup is as follows:

key   key type   qualifiers     expected code output      code actually output
---   --------   ----------     --------------------      --------------------

1     0x05       NOQUAL         'a'                       'a'
                 SHIFT          'b'                       'b'
                 CTRL           'c'                       'b'
                 CTRL + SHIFT   'd'                       'd'
					                
2     0x43       NOQUAL         "2 + noqual"              "2 + noqual"
                 SHIFT          "2 + shift"               "2 + shif" 
                 ALT            "2 + alt"                 "2 + shif"
                 SHIFT + ALT    "2 + shift + alt"         "t2 + a"

3     0x47       NOQUAL         "3 + noqual"              "3 + noqual"
                 SHIFT          "3 + shift"               "3 + shif"
                 ALT            "3 + alt"                 "3 + shif"
                 CTRL           "3 + ctrl"                "3 + shif"
                 ALT + SHIFT    "3 + alt + shift"         "t3 + a"
                 CTRL + ALT     "3 + ctrl + alt"          "t3 + a"
                 CTRL + SHIFT   "3 + ctrl + shift"        "t3 + a"
                 CTRL + ALT     "3 + ctrl + alt + shift"  "lt3 + c"
                      + SHIFT

4     0x01       NOQUAL         '4'                       '4'
                 SHIFT          '$'                       '$'



I have several questions regarding the keymapping setup:

1) Are the qualifiers for keytype 0x47 in the right order? It isn't very clear
   what the order should be in the case when more than one qualifier is used.  
   The ordering above for key 3 (keytype 0x47) is per table 4-7 of
   the Console Device chapter in RKM vol 1.

2) The Console Device chapter also refers to routines:
            . GetKeyMap()
            . SetKeyMap()

   Where are these documented?  I can't find any reference to them under
   console.doc in RKM vol 2.  I did find CDAskKeyMap and CDSetKeyMap.
   
   Are the routines GetKeyMap() & SetKeyMap() in some special library?
   I got linker error messages when I tried to use them.  So I had to use the
   CD_ASKKEYMAP & CD_SETKEYMAP commands instead.

3) The documentation says that " the high keytype table covers the raw    
   keycodes from hex 40-67, and contains 38 (decimal) bytes".
   Shouldn't that be 40 (decimal) bytes ?

4) Also why doesn't Chk_Abort() work in this program ?

I hope you Amiga Experts out there can provide the answers and maybe a fix to
the keymapping problem.  

There is also a bug in Lattice C that I might as well include in this article.
I stumbled on it when dumping out the default Amiga keymap.

      UBYTE *p;
      int    len, i;

      /* The expression on the RHS of the assignment statement below is
       * evaluated correctly
       */
      len = *p + *(p+2) + 4;       

      /* The same expression when used in a "for" statement does not work 
       */
      for (i = 1; i <= (*p + *(p+2) +4); i++)
        {
        }

      /* But the statement below works fine
       */
      for (i = 1; i <= len; i++)
        {
        }



The keymapping test program is given below:


/****     keymap_test.h   **********/

/* INCLUDES  **************************************************/

#include  <exec/types.h>
#include  <exec/ports.h>
#include  <exec/io.h>
#include  <exec/devices.h>
#include  <exec/memory.h>

#include  <intuition/intuition.h>
#include  <intuition/intuitionbase.h>

#include  <devices/console.h>
#include  <devices/keymap.h>

#include  <libraries/dos.h>

#include  <stdio.h>


/* EXTERNALS  **************************************************/


extern ULONG                    *OpenLibrary();     /* Intuition functions */
extern struct   Window          *OpenWindow();

extern struct   MsgPort         *CreatePort();       /* Console Device IO  */ 
extern struct   IOStdReq        *CreateStdIO();
extern int      OpenDevice();                       



/*******  keymap_test.c  **********/

/***************************************************************************
 *
 *             Test program to illustrate bug in keymapping
 *
 **************************************************************************/


#include "keymap_test.h"


extern Enable_Abort;


ULONG  IntuitionBase;
ULONG  GfxBase;
struct Window    *te_window; /* ptr to a window to which the
                              * console is bound
                              */

struct  NewWindow  NewWindow =
   {
   0, 0,                                /* starting position              */
   640, 200,                            /* window width and height        */
   -1, -1,                              /* use same pens as screen        */
   NULL,                                /* no IDCMP flags                 */
   SMART_REFRESH | BORDERLESS | ACTIVATE, /* window flags      */
   NULL, NULL, NULL,                    /* no gadgets, checkmark & text   */
   NULL,                                /* pointer to screen              */
   NULL,                                /* no bit map                     */
   NULL, NULL, NULL, NULL,              /* window sizing parameters       */
   WBENCHSCREEN,                        /* screen type                    */
   };

struct IOStdReq  *con_write_req, *con_read_req;
struct MsgPort   *con_write_port, *con_read_port;

UBYTE conchar;         /* used for QueueRead() */

struct KeyMap     keymap;

UBYTE lo_types[64];
ULONG lo_keymap[64];
UBYTE lo_cap[8];
UBYTE lo_rep[8];

UBYTE hi_types[40];
ULONG hi_keymap[40];
UBYTE hi_cap[8];
UBYTE hi_rep[8];

UBYTE string_alt_shift[] =
         {
         10,            /* length of string with no qualifier         */
         8,             /* dist of string from beg of descriptor      */
         9,             /* length of string with SHIFT                */
         18,            /* dist of string from beg of descriptor      */
         7,             /* length of string with ALT                  */
         27,            /* dist of string from beg of descriptor      */
         15,            /* length of string with ALT + SHIFT          */
         34,            /* dist of string from beg of descriptor      */
         "2 + noqual",
         "2 + shift",
         "2 + alt",
         "2 + alt + shift",
         };

UBYTE string_vanilla[] =
         {
         10,            /* length of string with no qualifier         */
         16,            /* dist of string from beg of descriptor      */
         9,             /* length of string with SHIFT                */
         26,            /* dist of string from beg of descriptor      */
         7,             /* length of string with ALT                  */
         35,            /* dist of string from beg of descriptor      */
         8,             /* length of string with CTRL                 */
         42,            /* dist of string from beg of descriptor      */
         15,            /* length of string with ALT + SHIFT          */
         50,            /* dist of string from beg of descriptor      */
         14,            /* length of string with CTRL + ALT           */
         65,            /* dist of string from beg of descriptor      */
         16,            /* length of string with CTRL + SHIFT         */
         79,            /* dist of string from beg of descriptor      */
         22,            /* length of string with CTRL + ALT + SHIFT   */
         95,            /* dist of string from beg of descriptor      */
         "3 + noqual",
         "3 + shift",
         "3 + alt",
         "3 + ctrl",
         "3 + alt + shift",
         "3 + ctrl + alt",
         "3 + ctrl + shift",
         "3 + ctrl + alt + shift",
         };

init_window()
{
   GfxBase = (ULONG) OpenLibrary("graphics.library", 0);
   IntuitionBase = (ULONG) OpenLibrary("intuition.library", 0);
   te_window = OpenWindow(&NewWindow);
}


init_req()
{
   con_write_port = CreatePort("my.con.write",0);
   con_write_req  = CreateStdIO(con_write_port);

   con_read_port = CreatePort("my.con.read",0);
   con_read_req =  CreateStdIO(con_read_port);
  
   OpenConsole(con_write_req, con_read_req, te_window);

}



main()
{
   UBYTE c;
   int i;


   init_window();
   init_req();

   QueueRead (con_read_req, &conchar);

   /* initialize keymap tables to zeroes
    */
   for (i = 0; i <= 63; i++)
      {
      lo_types[i] = 0x00;
      lo_keymap[i] = 0x00;
      }

   for (i = 0; i <= 39
      {
      hi_types[i] = 0x00;
      hi_keymap[i] = 0x00;
      }

   for (i = 0; i <= 7; i++)
      {
      lo_cap[i] = 0x00;
      lo_rep[i] = 0x00;
      hi_cap[i] = 0x00;
      hi_rep[i] = 0x00;
      }

   /* setup key types for keys 1, 2, 3, & 4
    */
   lo_types[1] = 0x05;        /* KCF_CONTROL + KCF_SHIFT           */
   lo_types[2] = 0x43;        /* KCF_STRING + KCF_ALT + KCF_SHIFT  */
   lo_types[3] = 0x47;        /* KCF_STRING + KC_VANILLA           */
   lo_types[4] = 0x01;        /* KC_NOQUAL  + KCF_SHIFT            */


   /* setup key codes for keys 1, 2, 3, & 4
    */
   lo_keymap[1]   = (ULONG) 0x64636261;  /* d = key 1 with CTRL + SHIFT */
                                         /* c = key 1 with CTRL         */
                                         /* b = key 1 with SHIFT        */
                                         /* a = key 1 alone             */
   lo_keymap[2]   = (ULONG) 0x00000000;  /*     key 2                   */
   lo_keymap[3]   = (ULONG) 0x00000000;  /*     key 3                   */
   lo_keymap[4]   = (ULONG) 0x00002434;  /*     key 4                   */


   /* plug in addresses of string descriptors into low keymap
    */
   lo_keymap[2] = (ULONG) string_alt_shift;
   lo_keymap[3] = (ULONG) string_vanilla;


   /* setup pointers to members of keymap structure
    */
   keymap.km_LoKeyMapTypes = (APTR) lo_types;
   keymap.km_LoKeyMap      = (APTR) lo_keymap;
   keymap.km_LoCapsable    = (APTR) lo_cap;
   keymap.km_LoRepeatable  = (APTR) lo_rep;
   keymap.km_HiKeyMapTypes = (APTR) hi_types;
   keymap.km_HiKeyMap      = (APTR) hi_keymap;
   keymap.km_HiCapsable    = (APTR) hi_cap;
   keymap.km_HiRepeatable  = (APTR) hi_rep;

   /* Now set the new keymap
    */
   con_write_req-> io_Command = CD_SETKEYMAP;
   con_write_req-> io_Length  = sizeof(keymap);
   con_write_req-> io_Data    = (APTR) &keymap;

   DoIO (con_write_req);

   Enable_Abort = 0;

   /* Keys 1, 2 & 3 have been setup with key types 0x05, 0x43 & 0x47 
    * respectively.
    * Press key 4 + SHIFT to exit
    */

    for (;;)
      {
      /* Note: Chk_Abort() does not work here
       */

      if (Chk_Abort() != 0)
         break;               /* ctrl-c or ctrl-d was pressed */
      
      c = (UBYTE) ConMayGetChar (con_read_req, con_read_port, &conchar);
      if (c != '$')
         {
         ConPutChar (con_write_req, c);
         }
      else
         break;
      }

   AbortIO(con_read_req);
   CloseDevice(con_read_req);

   DeletePort(con_read_port);
   DeletePort(con_write_port);
   DeleteStdIO(con_read_req);
   DeleteStdIO(con_write_req);

   CloseWindow(te_window);
   CloseLibrary(IntuitionBase);
   CloseLibrary(GfxBase);

}



/******  con_io.c  *********/

/************************************************************************
 *
 *                    Console Device functions
 *
 ************************************************************************/


#include "keymap_test.h"

/* These functions are taken directly from the console.device chapter
 * in the Amiga V1.1 ROM KERNEL manual.  See manual for documentation. */


/* Open a console device */
      int
OpenConsole(writerequest,readrequest,window)
      struct IOStdReq *writerequest;
      struct IOStdReq *readrequest;
      struct Window *window;
      {
            int error; 
            writerequest->io_Data = (APTR) window;
            writerequest->io_Length = sizeof(*window);
            error = OpenDevice("console.device", 0, writerequest, 0);
            readrequest->io_Device = writerequest->io_Device;
            readrequest->io_Unit   = writerequest->io_Unit;
                  /* clone required parts of the request */
            return(error);
      }

/* Output a single character to a specified console */ 

      int
ConPutChar(request,character)
      struct IOStdReq *request;
      char character;
      {
            request->io_Command = CMD_WRITE;
            request->io_Data = (APTR)&character;
            request->io_Length = 1;
            DoIO(request);
            return(0);
      }
 
/* Output a NULL-terminated string of characters to a console */ 

      int
ConPutStr(request,string)
      struct IOStdReq *request;
      char *string;
      {
            request->io_Command = CMD_WRITE;
            request->io_Data = (APTR)string;
            request->io_Length = -1;
            DoIO(request);
            return(0);
      }
 
      /* queue up a read request to a console */

      int
QueueRead(request,whereto)
      struct IOStdReq *request;
      char *whereto;
      {
            request->io_Command = CMD_READ;
            request->io_Data = (APTR)whereto;
            request->io_Length = 1;
            SendIO(request);
            return(0);
      }

/* see if there is a character to read.  If none, don't wait,
 * come back with a value of 0 
 */
	int  
ConMayGetChar (request, requestPort, whereto)
	struct IOStdReq *request;
	struct MsgPort  *requestPort;
	UBYTE *whereto;
	{
		register int temp;

		if (CheckIO (request) == FALSE)
			return (0);     /* no char typed in */
		
		GetMsg (requestPort):
		temp = *whereto;

		QueueRead (request, whereto);
		return (temp);
	}
-- 
Pushpa Kumar 
akgua!pid!pk
404/952-1572 (voice)