Copyright (c) Hyperion Entertainment and contributors.

Difference between revisions of "Keymap Library"

From AmigaOS Documentation Wiki
Jump to navigation Jump to search
m (Fixed small typos in MapRawKey.c preventing accurate value to be printed to the console)
 
(62 intermediate revisions by one other user not shown)
Line 1: Line 1:
  +
{{WIP}}
= Keymap Library =
 
  +
== Keymap Library ==
   
 
Amiga computers are sold internationally with a variety of local keyboards which match the standards of particular countries. All Amigas have keyboards which are physically similar, and keys which output the same low-level raw key code for any particular physical key. However, in different countries, the keycaps of the keys may contain different letters or symbols. Since the physical position of a key determines the raw key code that it generates, raw key codes are not internationally compatible. For instance, on the German keyboard, the Y and Z keys are swapped when compared to the USA keyboard. The second key on the fifth row will generate the same raw key code on all Amiga keyboards, but should be decoded as a Z on a US keyboard and as a Y on a German keyboard.
 
Amiga computers are sold internationally with a variety of local keyboards which match the standards of particular countries. All Amigas have keyboards which are physically similar, and keys which output the same low-level raw key code for any particular physical key. However, in different countries, the keycaps of the keys may contain different letters or symbols. Since the physical position of a key determines the raw key code that it generates, raw key codes are not internationally compatible. For instance, on the German keyboard, the Y and Z keys are swapped when compared to the USA keyboard. The second key on the fifth row will generate the same raw key code on all Amiga keyboards, but should be decoded as a Z on a US keyboard and as a Y on a German keyboard.
   
The Amiga uses the ECMA-94 Latin 1 International 8-bit character set, and can map raw key codes to any desired ANSI character value, string, or escape sequence. This allows national keyboards to be supported by using keymaps. A keymap is a file which describes what character or string is tied to what key code. Generally, the user's startup-sequence will set a system default keymap that is correct for the user's keyboard. The console.device translates the raw key codes into the correct characters based on the installed keymap. This includes the translation of special deadkey sequential key combinations to produce accented international characters.
+
The Amiga uses the [http://www.ecma-international.org/publications/standards/Ecma-094.htm ECMA-94 Latin 1 International 8-bit] character set, and can map raw key codes to any desired ANSI character value, string, or escape sequence. This allows national keyboards to be supported by using keymaps. A keymap is a file which describes what character or string is tied to what key code. Generally, the user's startup-sequence will set a system default keymap that is correct for the user's keyboard. The console.device translates the raw key codes into the correct characters based on the installed keymap. This includes the translation of special deadkey sequential key combinations to produce accented international characters.
   
Programs which perform keyboard input using the console.device, CON:, RAW:, or Intuition VANILLAKEY, will receive custom keymaps, or may need to perform their own translation between raw key codes and ANSI characters. In this chapter, the term ANSI refers to the standard 8-bit character definitions which include printable ASCII characters, special characters, and escape sequences.
+
Programs which perform keyboard input using the console.device, CON:, RAW:, or Intuition VANILLAKEY, will receive custom keymaps, or may need to perform their own translation between raw key codes and ANSI characters. In this article, the term ANSI refers to the standard 8-bit character definitions which include printable ASCII characters, special characters, and escape sequences.
   
Unit V37, keymapping command were only available in the console.device. Keymap.library is a new library in Release 2 (V37). It offers some of the keymap commands of the console.device, enabling applications to inquire after the default keymap and map key codes to ANSI characters. It also provides the ability to map ANSI characters back into raw codes. Unlike the console.device however, it can not be used to select a keymap for only one application, i.e., one console window.
+
Keymap.library offers some of the keymap commands of the console.device, enabling applications to inquire after the default keymap and map key codes to ANSI characters. It also provides the ability to map ANSI characters back into raw codes. Unlike the console.device however, it can not be used to select a keymap for only one application, i.e., one console window.
   
 
As a prelude to the following material, note that the Amiga keyboard transmits raw key information to the computer in the form of a key position and a transition. Raw key positions range from hexadecimal 00 to 7F. When a key is released, its raw key position, plus hexadecimal 80, is transmitted.
 
As a prelude to the following material, note that the Amiga keyboard transmits raw key information to the computer in the form of a key position and a transition. Raw key positions range from hexadecimal 00 to 7F. When a key is released, its raw key position, plus hexadecimal 80, is transmitted.
   
 
== Keymap Functions ==
 
== Keymap Functions ==
 
Table 34-1: Keymap Library Functions
 
   
 
{| class="wikitable"
 
{| class="wikitable"
  +
|+Keymap Library Functions
  +
|-
 
|AskKeyMapDefault()
 
|AskKeyMapDefault()
 
|Ask for a pointer to the current default keymap
 
|Ask for a pointer to the current default keymap
Line 28: Line 29:
 
|Set the current default keymap
 
|Set the current default keymap
 
|}
 
|}
 
Table 34-2: Console Device Keymap Commands
 
   
 
{| class="wikitable"
 
{| class="wikitable"
  +
|+Console Device Keymap Commands
  +
|-
 
|CD_ASKKEYMAP
 
|CD_ASKKEYMAP
 
|Ask for the current console's keymap
 
|Ask for the current console's keymap
Line 51: Line 52:
 
All of these commands deal with a set of pointers to key translation arrays, known as the KeyMap structure. The KeyMap structure is defined in <devices/keymap.h> and is shown below.
 
All of these commands deal with a set of pointers to key translation arrays, known as the KeyMap structure. The KeyMap structure is defined in <devices/keymap.h> and is shown below.
   
  +
<syntaxhighlight>
<pre>struct KeyMap
 
  +
struct KeyMap
 
{
 
{
 
UBYTE *km_LoKeyMapTypes;
 
UBYTE *km_LoKeyMapTypes;
Line 61: Line 63:
 
UBYTE *km_HiCapsable;
 
UBYTE *km_HiCapsable;
 
UBYTE *km_HiRepeatable;
 
UBYTE *km_HiRepeatable;
};</pre>
+
};
  +
</syntaxhighlight>
   
 
The KeyMap structure contains pointers to arrays which define the ANSI character or string that should be produced when a key or a combination of keys are pressed. For example, a keymap might specify that the key with raw value hex 20 should produce the ANSI character "a", and if the Shift key is being held it should produce the character "A".
 
The KeyMap structure contains pointers to arrays which define the ANSI character or string that should be produced when a key or a combination of keys are pressed. For example, a keymap might specify that the key with raw value hex 20 should produce the ANSI character "a", and if the Shift key is being held it should produce the character "A".
Line 67: Line 70:
 
=== Asking for the Default Keymap ===
 
=== Asking for the Default Keymap ===
   
  +
The '''AskKeyMapDefault()''' returns a pointer to the current default keymap. To use the mapping functions in keymap.library it is normally not necessary to call this function. They accept NULL as equivalent to 'use default keymap' and will call this function for you. You can use this pointer for example to cache the system default in order to temporarily change the keymap your applications uses, or find the keymap in the keymap.resource list of loaded keymaps. You should never change the system wide default keymap unless the user asks you to do so; since the Amiga is a multitasking system, changing the keymap could interfere with the behaviour of other applications.
The '''AskKeyMapDefault()''' returns a pointer to the current default
 
keymap. To use the mapping functions in keymap.library it is normally
 
not necessary to call this function. They accept NULL as equivalent to
 
'use default keymap' and will call this function for you. You can use
 
this pointer for example to cache the system default in order to
 
temporarily change the keymap your applications uses, or find the
 
keymap in the keymap.resource list of loaded keymaps. You should
 
never change the system wide default keymap unless the user asks
 
you to do so; since the Amiga is a multitasking system,
 
changing the keymap could interfere with the behaviour of other
 
applications.
 
   
 
=== Setting the Default Keymap ===
 
=== Setting the Default Keymap ===
   
The system default keymap can be set with the '''SetKeyMapDefault()'''
+
The system default keymap can be set with the '''SetKeyMapDefault()''' function. This function takes a pointer to a loaded keymap.
  +
In general, this function should never be used by an application unless the application is a system Preferences editor, or an
function. This function takes a pointer to a loaded keymap.
 
  +
application that takes over the system. Normal applications should instead attach a console.device unit to their own Intuition window (see the ''Devices'' volume), and use the console.device command '''CD_SETKEYMAP''' to set a keymap only for their own console.
In general, this function should never be used by an application
 
unless the application is a system Preferences editor, or an
 
application that takes over the system.
 
Normal applications should instead attach a console.device unit to their
 
own Intuition window (see the ''Devices'' volume), and use
 
the console.device command '''CD_SETKEYMAP''' to set a keymap
 
only for their own console.
 
onsole.
 
   
  +
When making a keymap the system default, first check whether the keymap has been loaded previously by checking the keymap list of the keymap.resource. If it has not been loaded already, it can be loaded from DEVS:Keymaps, and added to the keymap list of keymap.resource. This will ensure that other applications which may want the keymap will not have to load a second instance. Once made the default, the keymap can never be safely removed from memory, even after if it is no longer the default, since other applications may still have and use a pointer to it.
When making a keymap the system default, first check whether the keymap
 
has been loaded previously by checking the keymap list of the
 
keymap.resource. If it has not been loaded already, it can be loaded
 
from devs:Keymaps, and added to the keymap list of keymap.resource.
 
This will ensure that other applications which may want the keymap will
 
not have to load a second instance.
 
Once made the default, the keymap can never be safely removed
 
from memory, even after if it is no longer the default, since other
 
applications may still have and use a pointer to it.
 
   
 
=== Accessing the Keymap for the Current Console ===
 
=== Accessing the Keymap for the Current Console ===
   
The function '''AskKeyMap()''' shown below does not return a pointer
+
The function '''AskKeyMap()''' shown below does not return a pointer to a table of pointers to currently assigned key mapping. Instead, it ''copies'' the current set of pointers to a user-designated area of memory. '''AskKeyMap()''' returns a TRUE or FALSE value that says whether or not the function succeeded.
to a table of pointers to currently assigned key mapping.
 
Instead, it ''copies'' the current set of pointers to a
 
user-designated area of memory. '''AskKeyMap()''' returns a
 
TRUE or FALSE value that says whether or not the function succeeded.
 
   
The function '''SetKeyMap()''', also shown below, copies the
+
The function '''SetKeyMap()''', also shown below, copies the designated key map data structure to the console device. Thus this routine is complementary to '''AskKeymap()''' in that it can restore an original key mapping as well as establish a new one.
designated key map data structure to the console device. Thus this
 
routine is complementary to '''AskKeymap()''' in that it can restore
 
an original key mapping as well as establish a new one.
 
   
  +
{{Note|title=Ask/SetKeyMap()|text=These functions assume that you have already opened the ''console.device'' and that ''request'' is a valid IOStdReq structure for the newly opened console. These functions are not part of the keymap.library, nor of the console.device. These merely demonstrate '''CD_ASKKEYMAP''' and '''CD_SETKEYMAP''' which are console.device commands.}}
{| class="wikitable"
 
|''Ask/SetKeyMap() functions''.
 
These functions assume that you have already opened the
 
''console.device'' and that ''request'' is a valid IOStdReq
 
structure for the newly opened console.
 
These functions are not part of the keymap.library, nor of the
 
console.device. These merely demonstrate '''CD_ASKKEYMAP''' and
 
'''CD_SETKEYMAP''' which are console.device commands.
 
|}
 
   
  +
<syntaxhighlight>
<pre>
 
 
/* These functions require that you have created a port and an IO request,
 
/* These functions require that you have created a port and an IO request,
* and have opened the console device as shown in the Console Device chapter
+
* and have opened the console device as shown in the "Console Device" section.
* of the Devices volume of this manual set.
 
 
*/
 
*/
 
#include <devices/keymap.h>
 
#include <devices/keymap.h>
Line 137: Line 99:
 
request->io_Length = sizeof(struct KeyMap);
 
request->io_Length = sizeof(struct KeyMap);
 
request->io_Data = (APTR)keymap; /* where to put it */
 
request->io_Data = (APTR)keymap; /* where to put it */
DoIO(request);
+
IExec->DoIO(request);
 
if(request->io_Error) return(FALSE);
 
if(request->io_Error) return(FALSE);
 
else return(TRUE); /* if no error, it worked. */
 
else return(TRUE); /* if no error, it worked. */
 
}
 
}
   
BOOL SetKeyMap(struct IOStdReq *request,struct KeyMap *keymap)
+
BOOL SetKeyMap(struct IOStdReq *request, struct KeyMap *keymap)
 
{
 
{
 
request->io_Command = CD_SETKEYMAP;
 
request->io_Command = CD_SETKEYMAP;
 
request->io_Length = sizeof(struct KeyMap);
 
request->io_Length = sizeof(struct KeyMap);
 
request->io_Data = (APTR)keymap; /* where to get it */
 
request->io_Data = (APTR)keymap; /* where to get it */
DoIO(request);
+
IExec->DoIO(request);
 
if(request->io_Error) return(FALSE);
 
if(request->io_Error) return(FALSE);
 
else return(TRUE); /* if no error, it worked. */
 
else return(TRUE); /* if no error, it worked. */
 
}
 
}
  +
</syntaxhighlight>
</pre>
 
   
 
=== Mapping Key Codes to ANSI Strings ===
 
=== Mapping Key Codes to ANSI Strings ===
Line 157: Line 119:
 
'''MapRawKey()''' converts raw key codes in ANSI characters based on a default or supplied keymap.
 
'''MapRawKey()''' converts raw key codes in ANSI characters based on a default or supplied keymap.
   
  +
<syntaxhighlight>
<pre>WORD MapRawKey(struct InputEvent *inputevent, STRPTR buffer,
 
WORD bufferlength, struct Keymap *keymap);</pre>
+
WORD MapRawKey(struct InputEvent *inputevent, STRPTR buffer, WORD bufferlength, struct Keymap *keymap);
  +
</syntaxhighlight>
   
 
'''MapRawKey()''' takes an IECLASS_RAWKEY inputevent, which may be chained, and converts the key codes to ANSI characters which are placed in the specified buffer. If the buffer would overflow, for example because a longer string is attached to a key, -1 will be returned. If no error occured, '''MapRawKey()''' will return the number of bytes written in the buffer. The keymap argument can be set to NULL if the default keymap is to be used for translation, or can be a pointer to a specific '''KeyMap''' structure.
 
'''MapRawKey()''' takes an IECLASS_RAWKEY inputevent, which may be chained, and converts the key codes to ANSI characters which are placed in the specified buffer. If the buffer would overflow, for example because a longer string is attached to a key, -1 will be returned. If no error occured, '''MapRawKey()''' will return the number of bytes written in the buffer. The keymap argument can be set to NULL if the default keymap is to be used for translation, or can be a pointer to a specific '''KeyMap''' structure.
Line 164: Line 127:
 
The following example shows how to implement the '''MapRawKey()''' function.
 
The following example shows how to implement the '''MapRawKey()''' function.
   
  +
<syntaxhighlight>
<pre>
 
  +
/*
;/* maprawkey.c - Execute me to compile me with SAS C 5.10
 
  +
* maprawkey.c - Map Intuition RAWKEY events to ANSI with MapRawKey();
LC -b1 -cfistq -v -y -j73 maprawkey.c
 
  +
*/
Blink FROM LIB:c.o,maprawkey.o TO maprawkey LIBRARY LIB:LC.lib,LIB:Amiga.lib
 
quit
 
* maprawkey.c - Map Intuition RAWKEY events to ANSI with MapRawKey();
 
*/
 
 
#include <exec/types.h>
 
#include <exec/types.h>
 
#include <exec/memory.h>
 
#include <exec/memory.h>
Line 177: Line 137:
 
#include <devices/inputevent.h>
 
#include <devices/inputevent.h>
   
#include <clib/exec_protos.h>
+
#include <proto/exec.h>
#include <clib/dos_protos.h>
+
#include <proto/dos.h>
#include <clib/keymap_protos.h>
+
#include <proto/keymap.h>
#include <clib/intuition_protos.h>
+
#include <proto/intuition.h>
 
#include <stdio.h>
 
#include <stdlib.h>
 
 
#ifdef LATTICE
 
int CXBRK(void) { return(0); } /* Disable Lattice CTRL/C handling */
 
void chkabort(void) { return; } /* really */
 
#endif
 
   
 
/* our function prototypes */
 
/* our function prototypes */
Line 195: Line 147:
 
void closeout(UBYTE *errstring, LONG rc);
 
void closeout(UBYTE *errstring, LONG rc);
   
struct Library *IntuitionBase = NULL;
+
struct Library *IntuitionBase = NULL;
struct Library *KeymapBase = NULL;
+
struct IntuitionIFace *IIntuition = NULL;
  +
struct Window *window = NULL;
 
  +
struct Library *KeymapBase = NULL;
  +
struct KeymapIFace *IKeymap = NULL;
  +
  +
struct Window *window = NULL;
   
void main(int argc, char **argv)
+
int main(int argc, char **argv)
 
{
 
{
 
struct IntuiMessage *imsg;
 
struct IntuiMessage *imsg;
Line 211: Line 167:
 
openall();
 
openall();
   
window = OpenWindowTags(NULL,
+
window = IIntuition->OpenWindowTags(NULL,
 
WA_Width, 500,
 
WA_Width, 500,
 
WA_Height, 60,
 
WA_Height, 60,
Line 217: Line 173:
 
WA_Flags, WFLG_CLOSEGADGET | WFLG_ACTIVATE,
 
WA_Flags, WFLG_CLOSEGADGET | WFLG_ACTIVATE,
 
WA_IDCMP, IDCMP_RAWKEY | IDCMP_CLOSEWINDOW,
 
WA_IDCMP, IDCMP_RAWKEY | IDCMP_CLOSEWINDOW,
TAG_DONE);
+
TAG_END);
 
if(window == NULL) closeout("Can't open window",RETURN_FAIL);
 
if(window == NULL) closeout("Can't open window",RETURN_FAIL);
 
 
Line 227: Line 183:
 
while(!Done)
 
while(!Done)
 
{
 
{
Wait(windowsignal);
+
IExec->Wait(windowsignal);
   
while (imsg = (struct IntuiMessage *)GetMsg(window->UserPort))
+
while (imsg = (struct IntuiMessage *)IExec->GetMsg(window->UserPort))
 
{
 
{
 
switch(imsg->Class)
 
switch(imsg->Class)
Line 241: Line 197:
 
inputevent.ie_Qualifier = imsg->Qualifier;
 
inputevent.ie_Qualifier = imsg->Qualifier;
   
printf("RAWKEY: Code=$%04x Qualifier=$%04lx\en",
+
IDOS->Printf("RAWKEY: Code=$%04lx Qualifier=$%04lx\n",
 
imsg->Code, imsg->Qualifier);
 
imsg->Code, imsg->Qualifier);
   
Line 251: Line 207:
   
 
/* Map RAWKEY to ANSI */
 
/* Map RAWKEY to ANSI */
i = MapRawKey(&inputevent, buffer, 8, NULL);
+
i = IKeymap->MapRawKey(&inputevent, buffer, 8, NULL);
   
if (i == -1) Write(Output(),"*Overflow*",10);
+
if (i == -1) IDOS->Write(IDOS->Output(),"*Overflow*",10);
 
else if (i)
 
else if (i)
 
{
 
{
 
/* This key or key combination mapped to something */
 
/* This key or key combination mapped to something */
printf("MAPS TO: ");
+
IDOS->Printf("MAPS TO: ");
Write(Output(),buffer,i);
+
IDOS->Write(IDOS->Output(),buffer,i);
printf("\en");
+
IDOS->Printf("\en");
 
}
 
}
 
break;
 
break;
 
}
 
}
ReplyMsg((struct Message *)imsg);
+
IExec->ReplyMsg((struct Message *)imsg);
 
}
 
}
 
}
 
}
CloseWindow(window);
+
IIntuition->CloseWindow(window);
 
closeall();
 
closeall();
exit(RETURN_OK);
+
return RETURN_OK;
 
}
 
}
   
 
void openall(void)
 
void openall(void)
 
{
 
{
  +
KeymapBase = IExec->OpenLibrary("keymap.library", 50);
  +
IKeymap = (struct KeymapIFace*)IExec->GetInterface(KeymapBase, "main", 1, NULL);
  +
if (IKeymap == NULL) closeout("Can't get IKeymap",RETURN_FAIL);
   
KeymapBase = OpenLibrary("keymap.library", 37);
+
IntuitionBase = IExec->OpenLibrary("intuition.library", 50);
  +
IIntuition = (struct IntuitionIFace*)IExec->GetInterface(IntuitionBase, "main", 1, NULL);
if (KeymapBase == NULL) closeout("Kickstart 2.0 required",RETURN_FAIL);
 
  +
if (IIntuition == NULL) closeout("Can't get IIntuition",RETURN_FAIL);
 
IntuitionBase = OpenLibrary("intuition.library", 37);
 
if (IntuitionBase == NULL) closeout("Can't open intuition",RETURN_FAIL);
 
 
}
 
}
   
 
void closeall(void)
 
void closeall(void)
 
{
 
{
  +
IExec->DropInterface((struct Interface*)IIntuition);
if (IntuitionBase) CloseLibrary(IntuitionBase);
 
if (KeymapBase) CloseLibrary(KeymapBase);
+
IExec->CloseLibrary(IntuitionBase);
  +
  +
IExec->DropInterface((struct Interface*)IKeymap);
  +
IExec->CloseLibrary(KeymapBase);
 
}
 
}
   
 
void closeout(UBYTE *errstring, LONG rc)
 
void closeout(UBYTE *errstring, LONG rc)
 
{
 
{
if (*errstring) printf("%s\en",errstring);
+
if (*errstring) IDOS->Printf("%s\en",errstring);
 
closeall();
 
closeall();
 
exit(rc);
 
exit(rc);
 
}
 
}
  +
</syntaxhighlight>
</pre>
 
   
 
=== Mapping ANSI Strings to Key Codes ===
 
=== Mapping ANSI Strings to Key Codes ===
   
The '''MapANSI()''' function translates ANSI strings
+
The '''MapANSI()''' function translates ANSI strings into raw key codes, complete with qualifiers and (double) dead keys, based on a default or supplied keymap.
into raw key codes, complete with qualifiers
 
and (double) dead keys, based on a default or supplied keymap.
 
   
  +
<syntaxhighlight>
<pre>
 
LONG MapANSI(UBYTE *string, LONG stringlength, UBYTE *buffer,
+
LONG MapANSI(UBYTE *string, LONG stringlength, UBYTE *buffer, LONG bufferlength, struct KeyMap *keymap);
  +
</syntaxhighlight>
LONG bufferlength, struct KeyMap *keymap);
 
</pre>
 
   
  +
The string argument is a pointer to an ANSI string, of length stringlength. The buffer argument is a pointer to the memory block where the translated key codes will be placed. The length of this buffer must be indicated in WORDs since each translation will occupy one byte for the key code and one for the qualifier. Since one ANSI character can be translated to two dead keys and one key, the buffer must be at least 3 WORDs per character in the string to be translated. The keymap argument can be set to NULL if the default keymap is to be used, or can be a pointer to a '''KeyMap''' structure. Upon return, the function will indicate how many key code/qualifier combinations are placed in the buffer or a negative number in case an error occurred. If zero is returned, the character could not be translated.
The string argument is a pointer to an ANSI string, of length
 
stringlength. The buffer argument is a pointer to the memory block
 
where the translated key codes will be placed. The length of this
 
buffer must be indicated in WORDs since each translation will occupy
 
one byte for the key code and one for the qualifier. Since one ANSI
 
character can be translated to two dead keys and one key, the buffer
 
must be at least 3 WORDs per character in the string to be translated.
 
The keymap argument can be set to NULL if the default keymap is to be
 
used, or can be a pointer to a '''KeyMap''' structure. Upon return, the
 
function will indicate how many key code/qualifier combinations are
 
placed in the buffer or a negative number in case an error occurred. If
 
zero is returned, the character could not be translated.
 
   
The following example shows the usage of '''MapANSI()''' and demonstrates
+
The following example shows the usage of '''MapANSI()''' and demonstrates how returned key codes can be processed.
how returned key codes can be processed.
 
 
<pre>
 
;/* mapansi.c - Execute me to compile me with SAS C 5.10
 
LC -b1 -cfistq -v -y -j73 mapansi.c
 
Blink FROM LIB:c.o,mapansi.o TO mapansi LIBRARY LIB:LC.lib,LIB:Amiga.lib
 
quit
 
   
  +
<syntaxhighlight>
  +
/*
 
mapansi.c - converts a string to input events using MapANSI() function.
 
mapansi.c - converts a string to input events using MapANSI() function.
   
Line 344: Line 285:
 
#include <devices/inputevent.h>
 
#include <devices/inputevent.h>
   
#include <clib/exec_protos.h>
+
#include <proto/exec.h>
#include <clib/dos_protos.h>
+
#include <proto/dos.h>
#include <clib/keymap_protos.h>
+
#include <proto/keymap.h>
#include <clib/commodities_protos.h>
+
#include <proto/commodities.h>
 
#include <stdio.h>
 
#include <stdlib.h>
 
   
  +
struct Library *KeymapBase = NULL; /* MapAnsi() function */
#ifdef LATTICE
 
  +
struct KeymapIFace *IKeymap = NULL;
int CXBRK(void) { return(0); } /* Disable Lattice CTRL/C handling */
 
void chkabort(void) { return; } /* really */
 
#endif
 
   
struct Library *KeymapBase = NULL; /* MapAnsi() function */
+
struct Library *CxBase = NULL; /* AddIEvents() function */
struct Library *CxBase = NULL; /* AddIEvents() function */
+
struct CommoditiesIFace *ICommodities = NULL;
   
 
struct InputEvent *InputEvent = NULL; /* we'll allocate this */
 
struct InputEvent *InputEvent = NULL; /* we'll allocate this */
Line 369: Line 305:
   
   
void main(int argc, char **argv)
+
int main(int argc, char **argv)
 
{
 
{
 
UBYTE *string;
 
UBYTE *string;
Line 382: Line 318:
 
openall();
 
openall();
   
string = ";String converted to input events and sent to input device\en";
+
string = ";String converted to input events and sent to input device\n";
   
 
InputEvent->ie_Class = IECLASS_RAWKEY;
 
InputEvent->ie_Class = IECLASS_RAWKEY;
Line 392: Line 328:
 
{
 
{
 
/* Convert one character, use default key map */
 
/* Convert one character, use default key map */
i = MapANSI(tmp1, 1, iebuffer, 3, NULL);
+
i = IKeymap->MapANSI(tmp1, 1, iebuffer, 3, NULL);
   
 
/* Make sure we start without deadkeys */
 
/* Make sure we start without deadkeys */
Line 403: Line 339:
 
{
 
{
 
case -2:
 
case -2:
printf("Internal error\en", NULL);
+
IDOS->Printf("Internal error\n", NULL);
 
rc = RETURN_FAIL;
 
rc = RETURN_FAIL;
 
break;
 
break;
   
 
case -1:
 
case -1:
printf("Overflow\en", NULL);
+
IDOS->Printf("Overflow\n", NULL);
 
rc = RETURN_FAIL;
 
rc = RETURN_FAIL;
 
break;
 
break;
   
 
case 0:
 
case 0:
printf("Can't generate code\en", NULL);
+
IDOS->Printf("Can't generate code\n", NULL);
 
break;
 
break;
   
Line 435: Line 371:
 
{
 
{
 
/* Send the key down event */
 
/* Send the key down event */
AddIEvents(InputEvent);
+
ICommodities->AddIEvents(InputEvent);
   
 
/* Create a key up event */
 
/* Create a key up event */
Line 441: Line 377:
   
 
/* Send the key up event */
 
/* Send the key up event */
AddIEvents(InputEvent);
+
ICommodities->AddIEvents(InputEvent);
 
}
 
}
   
Line 451: Line 387:
   
 
closeall();
 
closeall();
exit(rc);
+
return rc;
 
}
 
}
   
Line 457: Line 393:
 
void openall(void)
 
void openall(void)
 
{
 
{
KeymapBase = OpenLibrary("keymap.library", 37);
+
KeymapBase = IExec->OpenLibrary("keymap.library", 50);
  +
IKeymap = (struct KeymapIFace*)IExec->GetInterface(KeymapBase, "main", 1, NULL);
if (KeymapBase == NULL) closeout("Kickstart 2.0 required", RETURN_FAIL);
 
  +
if (IKeymap == NULL) closeout("Can't get IKeymap", RETURN_FAIL);
   
CxBase = OpenLibrary("commodities.library", 37);
+
CxBase = IExec->OpenLibrary("commodities.library", 50);
  +
ICommodities = (struct CommoditiesIFace*)IExec->GetInterface(CxBase, "main", 1, NULL);
if (CxBase == NULL) closeout("Kickstart 2.0 required", RETURN_FAIL);
 
  +
if (ICommodities == NULL) closeout("Can't get ICommodities", RETURN_FAIL);
   
InputEvent = AllocMem(sizeof(struct InputEvent), MEMF_CLEAR);
+
InputEvent = IExec->AllocMem(sizeof(struct InputEvent), MEMF_CLEAR);
 
if (InputEvent == NULL) closeout("Can't allocate input event",RETURN_FAIL);
 
if (InputEvent == NULL) closeout("Can't allocate input event",RETURN_FAIL);
 
}
 
}
Line 470: Line 408:
 
void closeall()
 
void closeall()
 
{
 
{
if (InputEvent) FreeMem(InputEvent, sizeof(struct InputEvent));
+
if (InputEvent) IExec->FreeMem(InputEvent, sizeof(struct InputEvent));
  +
if (CxBase) CloseLibrary(CxBase);
 
  +
IExec->DropInterface((struct Interface*)ICommodities);
if (KeymapBase) CloseLibrary(KeymapBase);
 
  +
IExec->CloseLibrary(CxBase);
  +
  +
IExec->DropInterface((struct Interface*)IKeymap);
  +
IExec->CloseLibrary(KeymapBase);
 
}
 
}
   
Line 478: Line 420:
 
void closeout(UBYTE *errstring, LONG rc)
 
void closeout(UBYTE *errstring, LONG rc)
 
{
 
{
if(*errstring) printf("%s\en",errstring);
+
if(*errstring) IDOS->Printf("%s\n",errstring);
 
closeall();
 
closeall();
 
exit(rc);
 
exit(rc);
 
}
 
}
  +
</syntaxhighlight>
</pre>
 
   
 
=== Details of the Keymap Structure ===
 
=== Details of the Keymap Structure ===
   
A '''KeyMap''' structure contains pointers to arrays which determine
+
A '''KeyMap''' structure contains pointers to arrays which determine the translation from raw key codes to ANSI characters.
the translation from raw key codes to ANSI characters.
 
   
  +
<syntaxhighlight>
<pre>
 
 
struct KeyMap
 
struct KeyMap
 
{
 
{
Line 501: Line 442:
 
UBYTE *km_HiRepeatable;
 
UBYTE *km_HiRepeatable;
 
};
 
};
  +
</syntaxhighlight>
</pre>
 
   
 
==== LoKeyMap and HighKeyMap ====
 
==== LoKeyMap and HighKeyMap ====
   
  +
The low key map provides translation of the key values from hex 00-3F; the high key map provides translation of key values from hex 40-7F. Key values from hex 68-7F are not used by the existing keyboards, but this may change in the future. A raw key value (hex 00-7F) plus hex 80 is the release of that key. If you need to check for raw key releases do it like this:
The low key map provides translation of the key values from hex 00-3F;
 
the high key map provides translation of key values from hex 40-7F.
 
Key values from hex 68-7F are not used by the existing keyboards, but
 
this may change in the future.
 
A raw key value (hex 00-7F) plus hex 80 is the release of that key.
 
If you need to check for raw key releases do it like this:
 
   
  +
<syntaxhighlight>
<pre>
 
 
if (keyvalue & 0x80) { /* do key up processing */ }
 
if (keyvalue & 0x80) { /* do key up processing */ }
 
else { /* do key down processing */ }
 
else { /* do key down processing */ }
  +
</syntaxhighlight>
</pre>
 
   
Raw output from the keyboard for the low key map
+
Raw output from the keyboard for the low key map does not include the space bar, Tab, Alt, Ctrl, arrow keys, and several other keys.
does not include the space bar, Tab, Alt, Ctrl, arrow keys, and
 
several other keys.
 
   
  +
{| class="wikitable"
Table 34-3: High Key Map Hex Values
 
  +
|+High Key Map Hex Values
 
{|
+
|-
 
!Key Number
 
!Key Number
 
!Keycap Legend for Function
 
!Keycap Legend for Function
Line 597: Line 531:
 
|}
 
|}
   
The keymap table for the low and high keymaps consists of 4-byte
+
The keymap table for the low and high keymaps consists of 4-byte entries, one per hex key code. These entries are interpreted in one of two possible ways:
entries, one per hex key code.
 
These entries are interpreted in one of two possible
 
ways:
 
   
 
* As four separate bytes, specifying how the key is to be interpreted when pressed alone, with one qualifier, with another qualifier, or with both qualifiers (where a qualifier is one of three possible keys: Ctrl, Alt, or Shift).
 
* As four separate bytes, specifying how the key is to be interpreted when pressed alone, with one qualifier, with another qualifier, or with both qualifiers (where a qualifier is one of three possible keys: Ctrl, Alt, or Shift).
Line 608: Line 539:
 
* As a longword containing the address of a dead-key descriptor, where additional data describe the character to be output when this key is pressed alone or with another dead key.
 
* As a longword containing the address of a dead-key descriptor, where additional data describe the character to be output when this key is pressed alone or with another dead key.
   
  +
{{Note|title=The keymap tables must be word aligned|text=The keymap tables ''must'' begin aligned on a word boundary. Each entry is four bytes long, thereby maintaining word alignment throughout the table. This is necessary because some of the entries may be longword addresses and ''must'' be aligned properly for the 68000.}}
{| class="wikitable"
 
|''The keymap tables must be word aligned''. The keymap tables ''must'' begin aligned on a word boundary. Each entry is four bytes long, thereby maintaining word alignment throughout the table. This is necessary because some of the entries may be longword addresses and ''must'' be aligned properly for the 68000.
 
|}
 
   
 
==== LoKeyMapTypes and HiKeyMapTypes ====
 
==== LoKeyMapTypes and HiKeyMapTypes ====
Line 620: Line 549:
 
* Any of the qualifier groupings noted above
 
* Any of the qualifier groupings noted above
   
* KCF_STRING + any combination of KCF_SHIFT, KCF_ALT, KCF_CONTROL (or KC_NOQUAL) if the result of pressing the key is to be a stream of bytes (and key-with-one-or-more-qualifiers is to be one or more alternate streams of bytes). Any key can be made to output up to eight unique byte streams if KCF_STRING is set in its keytype. The only limitation is that the total length of all of the strings assigned to a key must be within the "jump range" of a single byte increment. See the "String-Output Keys" section below for more information.
+
* KCF_STRING + any combination of KCF_SHIFT, KCF_ALT, KCF_CONTROL (or KC_NOQUAL) if the result of pressing the key is to be a stream of bytes (and key-with-one-or-more-qualifiers is to be one or more alternate streams of bytes). Any key can be made to output up to eight unique byte streams if KCF_STRING is set in its keytype. The only limitation is that the total length of all of the strings assigned to a key must be within the "jump range" of a single byte increment. See the "String Output Keys" section below for more information.
   
 
* KCF_DEAD + any combination of KCF_SHIFT, KCF_ALT, KCF_CONTROL (or KC_NOQUAL) if the key is a dead-class key and can thus modify or be modified by another dead-class key. See the "Dead-Class Keys" section below for more information.
 
* KCF_DEAD + any combination of KCF_SHIFT, KCF_ALT, KCF_CONTROL (or KC_NOQUAL) if the key is a dead-class key and can thus modify or be modified by another dead-class key. See the "Dead-Class Keys" section below for more information.
Line 630: Line 559:
 
For keys such as the Return key or Esc key, the qualifiers specified in the keytypes table (up to two) are the qualifiers used to establish the response to the key. This is done as follows. In the keytypes table, the values listed for the key types are those listed for the qualifiers in &lt;devices/keymap.h&gt; and &lt;devices/keymap&gt;. Specifically, these qualifier equates are:
 
For keys such as the Return key or Esc key, the qualifiers specified in the keytypes table (up to two) are the qualifiers used to establish the response to the key. This is done as follows. In the keytypes table, the values listed for the key types are those listed for the qualifiers in &lt;devices/keymap.h&gt; and &lt;devices/keymap&gt;. Specifically, these qualifier equates are:
   
  +
{| class="wikitable"
{|
 
 
| KC_NOQUAL || 0x00
 
| KC_NOQUAL || 0x00
 
|-
 
|-
Line 650: Line 579:
 
Keys of type KC_VANILLA use the 4 bytes to represent the data output for the key alone, Shifted key, Alt'ed key, and Shifted-and-Alt'ed key. Then for the Ctrl-key-plus-vanilla-key, use the code for the key alone with bits 6 and 5 set to 0.
 
Keys of type KC_VANILLA use the 4 bytes to represent the data output for the key alone, Shifted key, Alt'ed key, and Shifted-and-Alt'ed key. Then for the Ctrl-key-plus-vanilla-key, use the code for the key alone with bits 6 and 5 set to 0.
   
  +
{{Note|title=The Vanilla Qualifier Does Not Mean Plain|text=The qualifier KC_VANILLA is equivalent to KCF_SHIFT+KCF_ALT+KCF_CONTROL.
{| class="wikitable"
 
  +
}}
|'''The Vanilla Qualifier Does Not Mean Plain'''. The qualifier KC_VANILLA is equivalent to KCF_SHIFT+KCF_ALT+KCF_CONTROL.
 
|}
 
   
 
This table shows how to interpret the keymap for various combinations of the qualifier bits:
 
This table shows how to interpret the keymap for various combinations of the qualifier bits:
   
  +
{| class="wikitable"
Table 34-4: Keymap Qualifier Bits
 
  +
|+Keymap Qualifier Bits
 
{|
+
|-
 
| If Keytype is:
 
| If Keytype is:
 
| colspan="4" | Then data at this position in the keytable is output when the key is pressed along with:
 
| colspan="4" | Then data at this position in the keytable is output when the key is pressed along with:
Line 681: Line 609:
 
|}
 
|}
   
=== Keytype Table Entries ===
+
==== String Output Keys ====
   
  +
When a key is to output a string, the keymap table contains the address of a string descriptor in place of a 4-byte mapping of a key as shown above. Here is a partial table for a new high keymap table that contains only three entries thus far. The first two are for the space bar and the backspace key; the third is for the tab key, which is to output a string that says "[TAB]". An alternate string, "[SHIFTED-TAB]", is also to be output when a shifted TAB key is pressed.
The vectors named km_LoKeyTypes and km_HiKeyTypes contain one byte per raw key code. This byte defines the entry type that is made in the key table by a set of bit positions.
 
   
  +
<pre>
Possible key types are:
 
  +
newHiMapTypes:
 
<ul>
 
<li><p>Any of the qualifier groupings noted above</p></li>
 
<li><p>KCF_STRING</p>
 
<p>+ any combination of KCF_SHIFT, KCF_ALT, KCF_CONTROL (or KC_NOQUAL) if the result of pressing the key is to be a stream of bytes (and key-with-one-or-more-qualifiers is to be one or more alternate streams of bytes).</p>
 
<p>''Any''</p>
 
<p>key can be made to output up to eight unique byte streams if KCF_STRING is set in its keytype. The only limitation is that the total length of all of the strings assigned to a key must be within the “jump range” of a single byte increment. See the “String-Output Keys” section below for more information.</p></li>
 
<li><p>KCF_DEAD</p>
 
<p>+ any combination of KCF_SHIFT, KCF_ALT, KCF_CONTROL (or KC_NOQUAL) if the key is a dead-class key and can thus modify or be modified by another dead-class key. See the “Dead-Class Keys” section below for more information.</p></li></ul>
 
 
The low keytype table covers the raw key codes from hex 00-3F and contains one byte per key code. Therefore this table contains 64 (decimal) bytes. The high keytype table covers the raw key codes from hex 40-67 and contains 38 (decimal) bytes.
 
 
=== String-Output Keys ===
 
 
When a key is to output a string, the keymap table contains the address of a string descriptor in place of a 4-byte mapping of a key as shown above. Here is a partial table for a new high keymap table that contains only three entries thus far. The first two are for the space bar and the backspace key; the third is for the tab key, which is to output a string that says “[TAB]”. An alternate string, “[SHIFTED-TAB]”, is also to be output when a shifted Tab key is pressed.
 
 
<pre>newHiMapTypes:
 
 
DC.B KCF_ALT,KC_NOQUAL, ;key 41
 
DC.B KCF_ALT,KC_NOQUAL, ;key 41
 
DC.B KCF_STRING+KCF_SHIFT, ;key 42
 
DC.B KCF_STRING+KCF_SHIFT, ;key 42
Line 718: Line 630:
 
DC.B new42ss - newkey42 ;number of bytes from start of
 
DC.B new42ss - newkey42 ;number of bytes from start of
 
;string descriptor to start of this string
 
;string descriptor to start of this string
new42us:
+
new42us: DC.B '[TAB]'
DC.B '[TAB]'
 
 
new42ue:
 
new42ue:
new42ss:
+
new42ss: DC.B '[SHIFTED-TAB]'
  +
new42se:
DC.B '[SHIFTED-TAB]'
 
new42se:</pre>
+
</pre>
  +
 
The new high map table points to the string descriptor at address newkey42. The new high map types table says that there is one qualifier, which means that there are two strings in the key string descriptor.
 
The new high map table points to the string descriptor at address newkey42. The new high map types table says that there is one qualifier, which means that there are two strings in the key string descriptor.
   
Each string in the descriptor takes two bytes in this part of the table: the first byte is the length of the string, and the second byte is the distance from the start of the descriptor to the start of the string. Therefore, a single string (KCF_STRING + KC_NOQUAL) takes 2 bytes of string descriptor. If there is one qualifier, 4 bytes of descriptor are used. If there are two qualifiers, 8 bytes of descriptor are used. If there are 3 qualifiers, 16 bytes of descriptor are used. All strings start immediately following the string descriptor in that they are accessed as single-byte offsets from the start of the descriptor itself. Therefore, the distance from the start of the descriptor to the last string in the set (the one that uses the entire set of specified qualifiers) must start within 255 bytes of the descriptor address.
+
Each string in the descriptor takes two bytes in this part of the table: the first byte is the length of the string, and the second byte is the distance from the start of the descriptor to the start of the string. Therefore, a single string (KCF_STRING + KC_NOQUAL) takes 2 bytes of string descriptor. If there is one qualifier, 4 bytes of descriptor are used. If there are two qualifiers, 8 bytes of descriptor are used. If there are 3 qualifiers, 16 bytes of descriptor are used. All strings start immediately following the string descriptor in that they are accessed as single-byte offsets from the start of the descriptor itself. Therefore, the distance from the start of the descriptor to the last string in the set (the one that uses the entire set of specified qualifiers) must start within 255 bytes of the descriptor address.
   
Because the length of the string is contained in a single byte, the length of any single string must be 255 bytes or less while also meeting the “reach” requirement. However, the console input buffer size limits the string output from any individual key to 32 bytes maximum.
+
Because the length of the string is contained in a single byte, the length of any single string must be 255 bytes or less while also meeting the "reach" requirement. However, the console input buffer size limits the string output from any individual key to 32 bytes maximum.
   
 
The length of a keymap containing string descriptors and strings is variable and depends on the number and size of the strings that you provide.
 
The length of a keymap containing string descriptors and strings is variable and depends on the number and size of the strings that you provide.
   
=== Capsable Bit Table ===
+
==== Capsable Bit Tables ====
   
  +
The vectors '''km_LoCapsable''' and '''km_HiCapsable''' each point to an array of 8 bytes that contain more information about the keytable entries. Specifically, if the Caps Lock key has been pressed (the Caps Lock LED is on) and if there is a bit \fIon\fP in that position in the capsable map, then this key will be treated as though the Shift key is now currently pressed. For example, in the default key mapping, the alphabetic keys are "capsable" but the punctuation keys are not. This allows you to set the Caps Lock key, just as on a normal typewriter, and get all capital letters. However, unlike a normal typewriter, you need not go out of Caps Lock to correctly type the punctuation symbols or numeric keys.
   
  +
In the byte array, the bits that control this feature are numbered from the lowest bit in the byte, and from the lowest memory byte address to the highest. For example, the bit representing capsable status for the key that transmits raw code 00 is bit 0 in byte 0; for the key that transmits raw code 08 it is bit 0 in byte 1, and so on.
   
  +
There are 64 bits (8 bytes) in each of the two capsable tables.
The vectors called km_LoCapsable and km_HiCapsable point to the first byte in an 8-byte table that contains more information about the keytable entries. Specifically, if the Caps Lock key has been pressed (the Caps Lock LED is on) and if there is a bit ''on'' in that position in the capsable map, then this key will be treated as though the Shift key is now currently pressed. For example, in the default key mapping, the alphabetic keys are “capsable” but the punctuation keys are not. This allows you to set the Caps Lock key, just as on a normal typewriter, and get all capital letters. However, unlike a normal typewriter, you need not go out of Caps Lock to correctly type the punctuation symbols or numeric keys.
 
   
  +
==== Repeatable Bit Tables ====
In the table, the bits that control this feature are numbered from the lowest bit in the byte, and from the lowest memory byte address to the highest. For example, the bit representing capsable status for the key that transmits raw code 00 is bit 0 in byte 0; for the key that transmits raw code 08 it is bit 0 in byte 1, and so on.
 
   
  +
The vectors '''km_LoRepeatable''' and '''km_HiRepeatable''' each point to an array of 8 bytes that contain additional information about
There are 64 bits (8-bytes) in each of the two capsable tables.
 
  +
the keytable entries. A bit for each key indicates whether or not the specified key should repeat at the rate set by the Input Preferences program.
   
  +
The bit positions correspond to those specified in the capsable bit table. If there is a 1 in a specific position, the key can repeat. There are 64 bits (8 bytes) in each of the two repeatable tables.
=== Repeatable Bit Table ===
 
 
For both the low and high key maps there is an 8-byte table that provides one bit per possible raw key code. This bit indicates whether or not the specified key should repeat at the rate set by the Preferences program. The bit positions correspond to those specified in the capsable bit table.
 
 
If there is a 1 in a specific position, the key can repeat. The vectors that point to these tables are called km_LoRepeatable and km_HiRepeatable.
 
   
 
=== Key Map Standards ===
 
=== Key Map Standards ===
   
Users and programs depend on certain predictable behaviors from all keyboards and keymaps. With the exception of dead-class keys (see “Dead-Class Keys” section), mapping of keys in the low key map should follow these general rules:
+
Users and programs depend on certain predictable behaviors from all keyboards and keymaps. With the exception of dead-class keys (see "Dead-Class Keys" section), mapping of keys in the low key map should follow these general rules:
   
 
* When pressed alone, keys should transmit the ASCII equivalent of the unshifted letter or lower symbol on the keycap.
 
* When pressed alone, keys should transmit the ASCII equivalent of the unshifted letter or lower symbol on the keycap.
  +
 
* When Shifted, keys should transmit the ASCII equivalent of the shifted letter or upper symbol printed on the keycap.
 
* When Shifted, keys should transmit the ASCII equivalent of the shifted letter or upper symbol printed on the keycap.
* When Alt’ed, keys should generally transmit the same character (or act as the same deadkey) as the Alt’ed key in the usa1 keymap.
 
* When pressed with CTRL alone, alphabetic keys should generally transmit their unshifted value but with bits 5 and 6 cleared. This allows keyboard typing of “control characters.” For example, the '''C''' key (normally value $63) should transmit value $03 (Ctrl-C) when '''Ctrl''' and '''C''' are pressed together.
 
   
  +
* When Alt'ed, keys should generally transmit the same character (or act as the same deadkey) as the Alt'ed key in the usa1 keymap.
The keys in the high key map (keys with raw key values $40 and higher) are generally non-alphanumeric keys such as those used for editing (backspace, delete, cursor keys, etc.), and special Amiga keys such as the function and help keys. Keymaps should translate these keys as to the same values or strings as those shown in the table labeled “ROM Default Key Mapping”.
 
   
  +
* When pressed with CTRL alone, alphabetic keys should generally transmit their unshifted value but with bits 5 and 6 cleared. This allows keyboard typing of "control characters." For example, the C key (normally value $63) should transmit value $03 (Ctrl-C) when Ctrl and C are pressed together.
In addition to their normal unshifted and shifted values, the following translations are standard for particular qualified high keymap keys:
 
   
  +
The keys in the high key map (keys with raw key values $40 and higher) are generally non-alphanumeric keys such as those used for editing
[h]
 
  +
(backspace, delete, cursor keys, etc.), and special Amiga keys such as the function and help keys. Keymaps should translate these keys to the same values or strings as those shown in ROM Default Key Mapping table.
   
  +
In addition to their normal unshifted and shifted values, the following translations are standard for particular qualified high keymap keys:
<table>
 
  +
<tbody>
 
<tr class="odd">
+
{| class="wikitable"
  +
! Key
<td align="left"></td>
 
  +
! Generates This Value
<td align="left"></td>
 
<td align="left">'''If Used with Qualifier'''</td>
+
! If Used with Qualifier, Generates This Value
  +
|-
</tr>
 
  +
| Space || $20 || $A0 with qualifier KCF_ALT
<tr class="even">
 
  +
|-
<td align="left">'''Key'''</td>
 
  +
| Return || $0D || $0A with qualifier KCF_CONTROL
<td align="left">'''Generates This Value'''</td>
 
  +
|-
<td align="left">'''Generates This Value'''</td>
 
  +
| Esc || $1B || $9B with qualifier KCF_ALT
</tr>
 
  +
|}
<tr class="odd">
 
<td align="left">Space</td>
 
<td align="left">$20</td>
 
<td align="left">$A0 with qualifier KCF_ALT</td>
 
</tr>
 
<tr class="even">
 
<td align="left">Return</td>
 
<td align="left">$0D</td>
 
<td align="left">$0A with qualifier KCF_CONTROL</td>
 
</tr>
 
<tr class="odd">
 
<td align="left">Esc</td>
 
<td align="left">$1B</td>
 
<td align="left">$9B with qualifier KCF_ALT</td>
 
</tr>
 
</tbody>
 
</table>
 
   
 
=== Dead-Class Keys ===
 
=== Dead-Class Keys ===
   
All of the national keymaps, including USA, contain ''dead-class'' keys. This term refers to keys that either modify or can themselves be modified by other dead-class keys. There are two types of dead-class keys: dead and deadable. A dead key is one which can modify certain keys pressed immediately following. For example, on the German keyboard there is a dead key marked with the grave accent (`). The dead key produces no console output, but when followed by (for instance) the '''A''' key, the combination will produce the a-grave (à) character (National Character Code $E0). On the U.S. keyboard, Alt-G is the deadkey used to add the grave accent (`) to the next appropriate character typed. A deadable key is one that can be prefixed by a dead key. The '''A''' key in the previous example is a deadable key. Thus, a dead key can only affect the output of a deadable key.
+
All of the national keymaps, including USA, contain ''dead-class'' keys. This term refers to keys that either modify or can themselves be modified by other dead-class keys. There are two types of dead-class keys: dead and deadable. A dead key is one which can modify certain keys pressed immediately following. For example, on the German keyboard there is a dead key marked with the grave accent (`). The dead key produces no console output, but when followed by (for instance) the A key, the combination will produce the a-grave (à) character (National Character Code $E0). On the U.S. keyboard, Alt-G is the deadkey used to add the grave accent (`) to the next appropriate character typed.
   
  +
A deadable key is one that can be prefixed by a dead key. The A key in the previous example is a deadable key. Thus, a dead key can only affect the output of a deadable key.
For any key that is to have a dead-class function, whether dead or deadable, the qualifier KCF_DEAD flag must be included in the entry for the key in the KeyMapTypes table. The KCF_DEAD type may also be used in conjunction with the other qualifiers. Furthermore, the key’s keymap table entry must contain the longword address of the key’s dead-key descriptor data area in place of the usual 4 ASCII character mapping.
 
   
  +
For any key that is to have a dead-class function, whether dead or deadable, the qualifier KCF_DEAD flag must be included in the entry for the key in the KeyMapTypes table. The KCF_DEAD type may also be used in conjunction with the other qualifiers. Furthermore, the key's keymap table entry must contain the longword address of the key's dead-key descriptor data area in place of the usual 4 ASCII character mapping.
Below is an excerpt from the ''Amiga 1000'' German key map which is referred to in the following discussion.
 
   
  +
Below is an excerpt from the Amiga 1000 German key map which is referred to in the following discussion.
<pre>KMLowMapType:
 
  +
  +
<pre>
  +
KMLowMapType:
 
DC.B KCF_DEAD+KC_VANILLA ; aA (Key 20)
 
DC.B KCF_DEAD+KC_VANILLA ; aA (Key 20)
 
... ; (more...)
 
... ; (more...)
DC.B KCF_DEAD+KC_VANILLA ; hH (Key 20)
+
DC.B KCF_DEAD+KC_VANILLA ; hH (Key 25)
 
... ; (more...)
 
... ; (more...)
 
KMLowMap:
 
KMLowMap:
Line 840: Line 738:
 
; prefixed by a dead key
 
; prefixed by a dead key
 
DC.B $C1,$C1,$C2,$C1,$C1,$C1 ; most recent is '
 
DC.B $C1,$C1,$C2,$C1,$C1,$C1 ; most recent is '
DC.B $C0,$C2,$C0,$C0,$C0,$C0 ; most recent is `</pre>
+
DC.B $C0,$C2,$C0,$C0,$C0,$C0 ; most recent is `
  +
</pre>
In the example, key 25 (the '''H''' key) is a dead key and key 20 (the '''A''' key) is a deadable key. Both keys use the addresses of their descriptor data areas as entries in the LoKeyMap table. The LoKeyMapTypes table says that there are four qualifiers for both: the requisite KCF_DEAD, as well as KCF_SHIFT, KCF_ALT, and KCF_CONTROL. The number of qualifiers determine length and arrangement of the descriptor data areas for each key. The next table shows how to interpret the KeyMapTypes for various combinations of the qualifier bits. For each possible position a pair of bytes is needed. The first byte in each pair tells how to interpret the second byte (more about this below).
 
   
  +
In the example, key 25 (the H key) is a dead key and key 20 (the A key) is a deadable key. Both keys use the addresses of their descriptor data areas as entries in the LoKeyMap table. The LoKeyMapTypes table says that there are four qualifiers for both: the requisite KCF_DEAD, as well as KCF_SHIFT, KCF_ALT, and KCF_CONTROL. The number of qualifiers determine length and arrangement of the descriptor data areas for each key. The next table shows how to interpret the KeyMapTypes for various combinations of the qualifier bits. For each possible position a pair of bytes is needed. The first byte in each pair tells how to interpret the second byte (more about this below).
[h] Dead Key Qualifier Bits
 
   
  +
{| class="wikitable"
|l|l|l|l|l|l|l|l|l|
 
  +
|+Dead Key Qualifier Bits
 
  +
|-
&amp; 8l'''Then the pair of bytes in this position in the dead-class key'''<br />
 
  +
! If type is:
'''If type is:''' &amp; 8l'''descriptor data is output when the key is pressed along with:'''<br />
 
  +
! colspan="8" | Then the pair of bytes in this position in the dead-class key descriptor data is output when the key is pressed along with:
''NOQUAL'' &amp; alone &amp; – &amp; – &amp; – &amp; – &amp; – &amp; – &amp; –<br />
 
  +
|-
''A'' &amp; alone &amp; ''A'' &amp; – &amp; – &amp; – &amp; – &amp; – &amp; –<br />
 
  +
| NOQUAL || alone || - || - || - || - || - || - || -
''C'' &amp; alone &amp; ''C'' &amp; – &amp; – &amp; – &amp; – &amp; – &amp; –<br />
 
  +
|-
''S'' &amp; alone &amp; ''S'' &amp; – &amp; – &amp; – &amp; – &amp; – &amp; –<br />
 
  +
| A || alone || - || - || - || - || - || - || -
''A+C'' &amp; alone &amp; ''A'' &amp; ''C'' &amp; ''A+C'' &amp; – &amp; – &amp; – &amp; –<br />
 
  +
|-
''A+S'' &amp; alone &amp; ''S'' &amp; ''A'' &amp; ''A+S'' &amp; – &amp; – &amp; – &amp; –<br />
 
  +
| C || alone || C || - || - || - || - || - || -
''C+S'' &amp; alone &amp; ''S'' &amp; ''C'' &amp; ''C+S'' &amp; – &amp; – &amp; – &amp; –<br />
 
  +
|-
''S+A+C (VANILLA)'' &amp; alone &amp; ''S'' &amp; ''A'' &amp; ''S+A'' &amp; ''C'' &amp; ''C+S'' &amp; ''C+A'' &amp; ''C+S+A''<br />
 
  +
| S || alone || S || - || - || - || - || - || -
 
  +
|-
 
  +
| A+C || alone || A || C || A+C || - || - || - || -
The abbreviations ''A'', ''C'', ''S'' stand for KCF_ALT, KCF_CONTROL, and KCF_SHIFT, respectively. Also note that the ordering is reversed from that in the normal KeyMap table.
 
  +
|-
  +
| A+S || alone || S || A || A+S || - || - || - || -
  +
|-
  +
| C+S || alone || S || C || C+S || - || - || - || -
  +
|-
  +
| S+A+C (VANILLA) || alone || S || A || S+A || C || C+S || C+A || C+S+A
  +
|-
  +
| colspan="9" | The abbreviations A, C, S stand for KCF_ALT, KCF_CONTROL, and KCF_SHIFT, respectively. Also note that the ordering is reversed from that in the normal '''KeyMap''' table.
  +
|}
   
 
Because keys 20 and 25 each use three qualifier bits (not including KCF_DEAD), according to the table there must be 8 pairs of data, arranged as shown. Had only KCF_ALT been set, for instance, (not including KCF_DEAD), just two pairs would have been needed.
 
Because keys 20 and 25 each use three qualifier bits (not including KCF_DEAD), according to the table there must be 8 pairs of data, arranged as shown. Had only KCF_ALT been set, for instance, (not including KCF_DEAD), just two pairs would have been needed.
   
As mentioned earlier, the first byte of each data pair in the descriptor data area specifies how to interpret the second byte. There are three possible values: 0, DPF_DEAD and DPF_MOD. In the ''Amiga 1000'' German keymap listed above, DPF_DEAD appears in the data for key 25, while DPF_MOD is used for key 20. It is the use of these flags that determines whether a dead-class key has dead or deadable function. A value of zero causes the unrestricted output of the following byte.
+
As mentioned earlier, the first byte of each data pair in the descriptor data area specifies how to interpret the second byte. There are three possible values: 0, DPF_DEAD and DPF_MOD. In the Amiga 1000 German keymap listed above, DPF_DEAD appears in the data for key 25, while DPF_MOD is used for key 20. It is the use of these flags that determines whether a dead-class key has dead or deadable function. A value of zero causes the unrestricted output of the following byte.
   
 
If the flag byte is DPF_DEAD, then that particular key combination (determined by the placement of the pair of bytes in the data table) is dead and will modify the output of the next key pressed (if deadable). How it modifies is controlled by the second byte of the pair which is used as an index into part(s) of the data area for ALL the deadable (DPF_MOD set) keys.
 
If the flag byte is DPF_DEAD, then that particular key combination (determined by the placement of the pair of bytes in the data table) is dead and will modify the output of the next key pressed (if deadable). How it modifies is controlled by the second byte of the pair which is used as an index into part(s) of the data area for ALL the deadable (DPF_MOD set) keys.
   
Before going further, an understanding of the structure of a descriptor data area wherein DPF_MOD is set for one (or more) of its members is necessary. Referring to the example, we see that DPF_MOD is set for the first and second pairs of bytes. According to its LoKeyMapTypes entry, and using the table labeled “Dead Key Qualifier Bits” as a guide, these pairs represent the alone and SHIFTed values for the key. When DPF_MOD is set, the byte immediately following the flag must be the offset from the start of the key’s descriptor data area to the start of a table of bytes describing the characters to output when this key combination is preceded by any dead keys. This is where the index mentioned above comes in. The value of the index from a prefixing dead key is used to determine which of the bytes from the deadable keys special table to output. The byte in the index+1 position is sent out. (The very first byte is the value to output if the key was not prefixed by a dead key.) Thus, if Alt-H is pressed (dead) and then Shift-A, an ‘a’ with a circumflex (^) accent will be output. This is because:
+
Before going further, an understanding of the structure of a descriptor data area wherein DPF_MOD is set for one (or more) of its members is necessary. Referring to the example, we see that DPF_MOD is set for the first and second pairs of bytes. According to its LoKeyMapTypes entry, and using table above (Dead Key Qualifier Bits) as a guide, these pairs represent the alone and SHIFTed values for the key. When DPF_MOD is set, the byte immediately following the flag must be the offset from the start of the key's descriptor data area to the start of a table of bytes describing the characters to output when this key combination is preceded by any dead keys. This is where the index mentioned above comes in. The value of the index from a prefixing dead key is used to determine which of the bytes from the deadable keys special table to output. The byte in the index+1 position is sent out. (The very first byte is the value to output if the key was not prefixed by a dead key.) Thus, if Alt-H is pressed (dead) and then Shift-A, an 'a' with a circumflex (^) accent will be output. This is because:
   
* The byte pair for the ALT position of the '''H''' key (key 25) is DPF_DEAD,3 so the index is 3.
+
* The byte pair for the ALT position of the "H" key (key 25) is DPF_DEAD,3 so the index is 3.
* The byte pair for the SHIFT position of the '''A''' key (key 20) is DPF_MOD, key20s-key20, so we refer to the ''table-of-bytes'' at key20s.
 
* The ''third+1'' byte of the ''table-of-bytes'' is $C2, an ‘a’ character.
 
   
  +
* The byte pair for the SHIFT position of the "A" key (key 20) is DPF_MOD, key20s-key20, so we refer to the table-of-bytes at key20s.
<sub>b</sub>oxA Note About Table Size.The number of bytes in the ''table-of-bytes'' for all deadable keys must be equal to the highest index value of all dead keys plus 1.
 
  +
  +
* The third+1 byte of the table-of-bytes is $C2, an 'a' character.
  +
  +
{{Note|title=A Note About Table Size|text=The number of bytes in the table-of-bytes for all deadable keys must be equal to the highest index value of all dead keys plus 1.}}
   
 
=== Double-Dead Keys ===
 
=== Double-Dead Keys ===
Line 879: Line 788:
 
Double-dead keys are an extension of the dead-class keys explained above. Unlike normal dead keys wherein one dead key of type DPF_DEAD can modify a second of type DPF_MOD, double-dead keys employ two consecutive keys of type DPF_DEAD to together modify a third of type DPF_MOD.
 
Double-dead keys are an extension of the dead-class keys explained above. Unlike normal dead keys wherein one dead key of type DPF_DEAD can modify a second of type DPF_MOD, double-dead keys employ two consecutive keys of type DPF_DEAD to together modify a third of type DPF_MOD.
   
For example, the key on the German keyboard labeled with single quotes (`') is a double-dead key. When this key is pressed alone and then pressed again shifted, there is no output. But when followed by an appropriate third key, for example the '''A''' key, the three keypresses combine to produce an ‘a’ with a circumflex (^) accent (character code $E2). Thus the double-dead pair qualify the output of the '''A''' key.
+
For example, the key on the German keyboard labeled with single quotes (<nowiki>''</nowiki>) is a double-dead key. When this key is pressed alone and then pressed again shifted, there is no output. But when followed by an appropriate third key, for example the A key, the three keypresses combine to produce an 'a' with a circumflex (^) accent (character code $E2). Thus the double-dead pair qualify the output of the A key.
   
The system always keeps the last two down key codes for possible further translation. If they are both of type DPF_DEAD and the key immediately following is DPF_MOD then the two are used to form an index into the (third) key’s translation table as follows:
+
The system always keeps the last two down key codes for possible further translation. If they are both of type DPF_DEAD and the key immediately following is DPF_MOD then the two are used to form an index into the (third) key's translation table as follows:
   
 
In addition to the index found after the DPF_DEAD qualifier in a normal dead key, a second factor is included in the high nibble of double-dead keys (it is shifted into place with DP_2DFACSHIFT). Its value equals the total number of dead key types + 1 in the keymap. This second index also serves as an identifying flag to the system that two dead keys can be significant.
 
In addition to the index found after the DPF_DEAD qualifier in a normal dead key, a second factor is included in the high nibble of double-dead keys (it is shifted into place with DP_2DFACSHIFT). Its value equals the total number of dead key types + 1 in the keymap. This second index also serves as an identifying flag to the system that two dead keys can be significant.
Line 889: Line 798:
 
Finally, this last value is used as an index into the translation table of the current, DPF_MOD, key.
 
Finally, this last value is used as an index into the translation table of the current, DPF_MOD, key.
   
The translation table of all deadable (DPF_MOD) keys has ''(number of dead key types + 1)''<math>\times</math>''(number of double dead key types + 1)'' entries, arranged in ''(number of double dead key types + 1)'' rows of ''(number of dead key types + 1)'' entries.
+
The translation table of all deadable (DPF_MOD) keys has [number of dead key types + 1] * [number of double dead key types + 1] entries, arranged in [number of double dead key types + 1] rows of [number of dead key types + 1] entries. This is because as indices are assigned for dead keys in the keymap, those that are double dead keys are assigned the lower numbers.
 
This is because as indices are assigned for dead keys in the keymap, those that are double dead keys are assigned the lower numbers.
 
   
 
Following is a code fragment from the German (d) keymap source:
 
Following is a code fragment from the German (d) keymap source:
   
<pre>key0C:
+
<pre>
  +
key0C:
DC.B DPF_DEAD,1+(6&lt;&lt;DP_2DFACSHIFT) ; dead '
 
DC.B DPF_DEAD,2+(6&lt;&lt;DP_2DFACSHIFT) ; dead `
+
DC.B DPF_DEAD,1+(6<<DP_2DFACSHIFT) ; dead '
  +
DC.B DPF_DEAD,2+(6<<DP_2DFACSHIFT) ; dead `
 
DC.B 0,'=',0,'+' ; =, +
 
DC.B 0,'=',0,'+' ; =, +
 
key20: ; a, A, ae, AE
 
key20: ; a, A, ae, AE
Line 910: Line 818:
 
DC.B 'A',$C1,$C0,$C2,$C3,$C4
 
DC.B 'A',$C1,$C0,$C2,$C3,$C4
 
DC.B $C1,$C1,$C2,$C1,$C1,$C1 ; most recent is '
 
DC.B $C1,$C1,$C2,$C1,$C1,$C1 ; most recent is '
DC.B $C0,$C2,$C0,$C0,$C0,$C0 ; most recent is `</pre>
+
DC.B $C0,$C2,$C0,$C0,$C0,$C0 ; most recent is `
  +
</pre>
Raw key0C, the German single quotes (`') key, is a double dead key. Pressing this key alone, then again while the shift key is down will produce no output but will form a double-dead qualifier. The output of key20 ('''A'''), a deadable key, will consequently be modified, producing an “a” with a circumflex (^) accent. The mechanics are as follows:
 
   
  +
Raw key0C, the German single quotes (<nowiki>''</nowiki>) key, is a double dead key. Pressing this key alone, then again while the shift key is down will produce no output but will form a double-dead qualifier. The output of key20 (A), a deadable key, will consequently be modified, producing an "a" with a circumflex (^) accent. The mechanics are as follows:
* When key0C is pressed alone the DPF_DEAD of the first byte pair in the key’s table indicates that the key as dead. The second byte is then held by the system.
 
* Next, when key0C is pressed again, this time with the Shift key down, the DPF_DEAD of the second byte pair (recall that the second pair is used because of the SHIFT qualifier) again indicates the key is a dead key. The second byte of this pair is also held by the system.
 
* Finally, when the '''A''' key is pressed the system recalls the latter of the two bytes it has saved. The upper nibble, $6, is multiplied by the lower nibble, $2. The result, $0C, is then added to the lower nibble of the earlier of the two saved bytes, $1. This new value, $0D, is used as an index into the (unshifted) translation table of key20. The character at position $0D is character $E2, an ‘a’ with a circumflex (^) accent.
 
   
  +
* When key0C is pressed alone the DPF_DEAD of the first byte pair in the key's table indicates that the key as dead. The second byte is then held by the system.
<sub>b</sub>oxNote About Double Dead Keys.If only one double-dead key is pressed before a deadable key then the output is the same as if the double-dead were a normal dead key. If shifted key0C is pressed on the German keyboard and then immediately followed by key20, the output produced is character $E0, ‘à’. As before, the upper nibble is multiplied with the lower, resulting in $0C. But because there was no second dead-key, this product is used as the final index.
 
   
  +
* Next, when key0C is pressed again, this time with the Shift key down, the DPF_DEAD of the second byte pair (recall that the second pair is used because of the SHIFT qualifier) again indicates the key is a dead key. The second byte of this pair is also held by the system.
== Keyboard Layout ==
 
   
  +
* Finally, when the A key is pressed the system recalls the latter of the two bytes it has saved. The upper nibble, $6, is multiplied by
The keys with key codes $2B and $30 in the following keyboard diagrams are keys which are present on some national Amiga keyboards.
 
  +
the lower nibble, $2. The result, $0C, is then added to the lower nibble of the earlier of the two saved bytes, $1. This new value, $0D, is used as an index into the (unshifted) translation table of key20. The character at position $0D is character $E2, an 'a' with a circumflex (^) accent.
   
  +
{{Note|title=Note About Double Dead Keys|text=If only one double-dead key is pressed before a deadable key then the output is the same as if the double-dead were a normal dead key. If shifted key0C is pressed on the German keyboard and then immediately followed by key20, the output produced is character $E0 'à'. As before, the upper nibble is multiplied with the lower, resulting in $0C. But because there was no second dead-key, this product is used as the final index.}}
[[File:LibFig34-1.png]]
 
   
  +
== Keyboard Layout ==
Figure 34-1: Amiga 1000 Keyboard Showing Key Codes in Hex
 
   
  +
The keys with key codes $2B and $30 in the following keyboard diagrams are keys which are present on some national Amiga keyboards.
[[File:LibFig34-2.png]]
 
   
Figure 34-2: Amiga 500/2000 Keyboard Showing Key Codes in Hex
+
[[File:LibFig34-1.png|800px|Amiga 1000 Keyboard Showing Key Codes in Hex]]
  +
  +
[[File:LibFig34-2.png|800px|Amiga 500/2000 Keyboard Showing Key Codes in Hex]]
   
 
The default values given above correspond to the values the console device will return when these keys are pressed with the keycaps as shipped with the standard American keyboard.
 
The default values given above correspond to the values the console device will return when these keys are pressed with the keycaps as shipped with the standard American keyboard.
   
  +
{| class="wikitable"
'''ROM Default (USA0) and USA1 Console Key Mapping'''
 
  +
|+ROM Default (USA0) and USA1 Console Key Mapping
  +
|-
  +
! Raw Key Number
  +
! Keycap Legend
  +
! Unshifted Default Value
  +
! Shifted Default Value
  +
|-
  +
| 00 || `~ || ` (Accent grave) || ~ (tilde)
  +
|-
  +
| 01 || 1 ! || 1 || !
  +
|-
  +
| 02 || 2 @ || 2 || @
  +
|-
  +
| 03 || 3 # || 3 || #
  +
|-
  +
| 04 || 4 $ || 4 || $
  +
|-
  +
| 05 || 5 % || 5 || %
  +
|-
  +
| 06 || 6 ^ || 6 || ^
  +
|-
  +
| 07 || 7 & || 7 || &
  +
|-
  +
| 08 || 8 * || 8 ||
  +
|-
  +
| 09 || 9 ( || 9 || (
  +
|-
  +
| 0A || 0 ) || 0 || )
  +
|-
  +
| 0B || - _ || - (Hyphen) || _ (Underscore)
  +
|-
  +
| 0C || = + || = || +
  +
|-
  +
| 0D || | | || || | |
  +
|-
  +
| 0E || (undefined) ||
  +
|-
  +
| 0F || 0 || 0 || 0 (Numeric pad)
  +
|-
  +
| 10 || Q || q || Q
  +
|-
  +
| 11 || W || w || W
  +
|-
  +
| 12 || E || e || E
  +
|-
  +
| 13 || R || r || R
  +
|-
  +
| 14 || T || t || T
  +
|-
  +
| 15 || Y || y || Y
  +
|-
  +
| 16 || U || u || U
  +
|-
  +
| 17 || I || i || I
  +
|-
  +
| 18 || O || o || O
  +
|-
  +
| 19 || P || p || P
  +
|-
  +
| 1A || [ { || [ || {
  +
|-
  +
| 1B || ] } || ] || }
  +
|-
  +
| 1C || || (undefined) ||
  +
|-
  +
| 1D || 1 || 1 || 1 (Numeric pad)
  +
|-
  +
| 1E || 2 || 2 || 2 (Numeric pad)
  +
|-
  +
| 1F || 3 || 3 || 3 (Numeric pad)
  +
|-
  +
| 20 || A || a || A
  +
|-
  +
| 21 || S || s || S
  +
|-
  +
| 22 || D || d || D
  +
|-
  +
| 23 || F || f || F
  +
|-
  +
| 24 || G || g || G
  +
|-
  +
| 25 || H || h || H
  +
|-
  +
| 26 || J || j || J
  +
|-
  +
| 27 || K || k || K
  +
|-
  +
| 28 || L || l || L
  +
|-
  +
| 29 || ; : || ; || :
  +
|-
  +
| 2A || ' " || ' (single quote) || "
  +
|-
  +
| 2B || || (not on most U.S. keyboards) ||
  +
|-
  +
| 2C || || (undefined) ||
  +
|-
  +
| 2D || 4 || 4 || 4 (Numeric pad)
  +
|-
  +
| 2E || 5 || 5 || 5 (Numeric pad)
  +
|-
  +
| 2F || 6 || 6 || 6 (Numeric pad)
  +
|-
  +
| 30 || || (not on most U.S. keyboards) ||
  +
|-
  +
| 31 || Z || z || Z
  +
|-
  +
| 32 || X || x || X
  +
|-
  +
| 33 || C || c || C
  +
|-
  +
| 34 || V || v || V
  +
|-
  +
| 35 || B || b || B
  +
|-
  +
| 36 || N || n || N
  +
|-
  +
| 37 || M || m || M
  +
|-
  +
| 38 || , < || , (comma) || <
  +
|-
  +
| 39 || . > || . (period) || >
  +
|-
  +
| 3A || / ? || / || ?
  +
|-
  +
| 3B || || (undefined) ||
  +
|-
  +
| 3C || . || . || . (Numeric pad)
  +
|-
  +
| 3D || 7 || 7 || 7 (Numeric pad)
  +
|-
  +
| 3E || 8 || 8 || 8 (Numeric pad)
  +
|-
  +
| 3F || 9 || 9 || 9 (Numeric pad)
  +
|-
  +
| 40 || Space bar || 0x20 || 0x20
  +
|-
  +
| 41 || Back Space || 0x08 || 0x08
  +
|-
  +
| 42 || Tab || 0x09 || 0x09
  +
|-
  +
| 43 || Enter || 0x0D || 0x0D
  +
|-
  +
| 44 || Return || 0x0D || 0x0D (Numeric pad)
  +
|-
  +
| 45 || Esc || 0x1B || 0x1B
  +
|-
  +
| 46 || Del || 0x7F || 0x7F
  +
|-
  +
| 47 || || (undefined) ||
  +
|-
  +
| 48 || || (undefined) ||
  +
|-
  +
| 49 || || (undefined) ||
  +
|-
  +
| 4A || - || - || - (Numeric Pad)
  +
|-
  +
| 4B || || (undefined) ||
  +
|-
  +
| 4C || Up arrow || <CSI>A || <CSI>T
  +
|-
  +
| 4D || Down arrow || <CSI>B || <CSI>S
  +
|-
  +
| 4E || Forward arrow || <CSI>C || <CSI> A (note blank space after <CSI>)
  +
|-
  +
| 4F || Backward arrow || <CSI>D || <CSI> @ (note blank space after <CSI>)
  +
|-
  +
| 50 || F1 || <CSI>0~ || <CSI>10~
  +
|-
  +
| 51 || F2 || <CSI>1~ || <CSI>11~
  +
|-
  +
| 52 || F3 || <CSI>2~ || <CSI>12~
  +
|-
  +
| 53 || F4 || <CSI>3~ || <CSI>13~
  +
|-
  +
| 54 || F5 || <CSI>4~ || <CSI>14~
  +
|-
  +
| 55 || F6 || <CSI>5~ || <CSI>15~
  +
|-
  +
| 56 || F7 || <CSI>6~ || <CSI>16~
  +
|-
  +
| 57 || F8 || <CSI>7~ || <CSI>17~
  +
|-
  +
| 58 || F9 || <CSI>8~ || <CSI>18~
  +
|-
  +
| 59 || F10 || <CSI>9~ || <CSI>19~
  +
|-
  +
| 5A || ( || ( || ( (usa1 Numeric pad)
  +
|-
  +
| 5B || ) || ) || ) (usa1 Numeric pad)
  +
|-
  +
| 5C || / || / || / (usa1 Numeric pad)
  +
|-
  +
| 5D || * || * || * (usa1 Numeric pad)
  +
|-
  +
| 5E || + || + || + (usa1 Numeric pad)
  +
|-
  +
| 5F || Help || <CSI>?~ || <CSI>?~
  +
|}
   
  +
{| class="wikitable"
|l|l|l|l|
 
  +
! Raw Key Number
 
  +
! Function or Keycap Legend
'''Raw''' &amp; &amp; '''Unshifted''' &amp; '''Shifted'''<br />
 
  +
|-
'''Key''' &amp; '''Keycap''' &amp; '''Default''' &amp; '''Default'''<br />
 
  +
| 60 || Shift (left of space bar)
'''Number''' &amp; '''Legend''' &amp; '''Value''' &amp; '''Value'''<br />
 
  +
|-
00 &amp; ` ~ &amp; ` (Accent grave) &amp; ~ (tilde)<br />
 
  +
| 61 || Shift (right of space bar)
01 &amp; 1 ! &amp; 1 &amp; !<br />
 
  +
|-
02 &amp; 2 @ &amp; 2 &amp; @<br />
 
  +
| 62 || Caps Lock
03 &amp; 3 # &amp; 3 &amp; #<br />
 
  +
|-
04 &amp; 4 $ &amp; 4 &amp; $<br />
 
  +
| 63 || Ctrl
05 &amp; 5 % &amp; 5 &amp; %<br />
 
  +
|-
06 &amp; 6 ^ &amp; 6 &amp; ^<br />
 
  +
| 64 || (Left) Alt
07 &amp; 7 &amp; &amp; 7 &amp; &amp;<br />
 
  +
|-
08 &amp; 8 * &amp; 8 &amp;<br />
 
  +
| 65 || (Right) Alt
09 &amp; 9 ( &amp; 9 &amp; (<br />
 
  +
|-
0A &amp; 0 ) &amp; 0 &amp; )<br />
 
  +
| 66 || Amiga (left of space bar)
0B &amp; - _ &amp; - (Hyphen) &amp; _ (Underscore)<br />
 
  +
|-
0C &amp; = + &amp; = &amp; +<br />
 
  +
| 67 || Amiga (right of space bar)
0D &amp; <math>\backslash</math> | &amp; <math>\backslash</math> &amp; |<br />
 
  +
|-
0E &amp; 3l''(undefined)''<br />
 
  +
| 68 || Left mouse button (not converted)
0F &amp; 0 &amp; 0 (Zero) &amp; 0 (Numeric pad)<br />
 
  +
|-
10 &amp; Q &amp; q &amp; Q<br />
 
  +
| 69 || Right mouse button (not converted)
11 &amp; W &amp; w &amp; W<br />
 
  +
|-
12 &amp; E &amp; e &amp; E<br />
 
  +
| 6A || Middle mouse button (not converted)
13 &amp; R &amp; r &amp; R<br />
 
  +
|-
14 &amp; T &amp; t &amp; T<br />
 
  +
| 6B || (undefined)
15 &amp; Y &amp; y &amp; Y<br />
 
  +
|-
16 &amp; U &amp; u &amp; U<br />
 
  +
| 6C || (undefined)
17 &amp; I &amp; i &amp; I<br />
 
  +
|-
18 &amp; O &amp; o &amp; O<br />
 
  +
| 6D || (undefined)
19 &amp; P &amp; p &amp; P<br />
 
  +
|-
1A &amp; [ { &amp; [ &amp; {<br />
 
  +
| 6E || (undefined)
1B &amp; ] } &amp; ] &amp; }<br />
 
  +
|-
1C &amp; 3l''(undefined)''<br />
 
  +
| 6F || (undefined)
1D &amp; 1 &amp; 1 &amp; 1 (Numeric pad)<br />
 
  +
|-
1E &amp; 2 &amp; 2 &amp; 2 (Numeric pad)<br />
 
  +
| 70-7F || (undefined)
1F &amp; 3 &amp; 3 &amp; 3 (Numeric pad)<br />
 
  +
|-
20 &amp; A &amp; a &amp; A<br />
 
  +
| 80-F8 || Up transition (release or unpress key of one of the above keys) (80 for 00, F8 for 7F)
21 &amp; S &amp; s &amp; S<br />
 
  +
|-
22 &amp; D &amp; d &amp; D<br />
 
  +
| F9 || Last key code was bad (was sent in order to resynchronize)
23 &amp; F &amp; f &amp; F<br />
 
  +
|-
24 &amp; G &amp; g &amp; G<br />
 
  +
| FA || Keyboard buffer overflow
25 &amp; H &amp; h &amp; H<br />
 
  +
|-
26 &amp; J &amp; j &amp; J<br />
 
  +
| FB || (undefined, reserved for keyboard processor catastrophe)
27 &amp; K &amp; k &amp; K<br />
 
  +
|-
28 &amp; L &amp; l &amp; L<br />
 
  +
| FC || Keyboard selftest failed
29 &amp; ; : &amp; ; &amp; :<br />
 
  +
|-
2A &amp; ' &quot; &amp; ' (single quote) &amp; &quot;<br />
 
  +
| FD || Power-up key stream start. Keys pressed or stuck at power-up will be sent between FD and FE.
2B &amp; 3l''(not on U.S. keyboards)''<br />
 
  +
|-
2C &amp; 3l''(undefined)''<br />
 
  +
| FE || Power-up key stream end
2D &amp; 4 &amp; 4 &amp; 4 (Numeric pad)<br />
 
  +
|-
2E &amp; 5 &amp; 5 &amp; 5 (Numeric pad)<br />
 
  +
| FF || (undefined, reserved)
2F &amp; 6 &amp; 6 &amp; 6 (Numeric pad)<br />
 
  +
|-
30 &amp; 3l''(not on U.S. keyboards)''<br />
 
  +
| FF || Mouse event, movement only, no button change (not converted)
 
  +
|}
 
'''ROM Default (USA0) and USA1 Console Key Mapping (continued)'''
 
 
|l|l|l|l|
 
 
'''Raw''' &amp; &amp; '''Unshifted''' &amp; '''Shifted'''<br />
 
'''Key''' &amp; '''Keycap''' &amp; '''Default''' &amp; '''Default'''<br />
 
'''Number''' &amp; '''Legend''' &amp; '''Value''' &amp; '''Value'''<br />
 
31 &amp; Z &amp; z &amp; Z<br />
 
32 &amp; X &amp; x &amp; X<br />
 
33 &amp; C &amp; c &amp; C<br />
 
34 &amp; V &amp; v &amp; V<br />
 
35 &amp; B &amp; b &amp; B<br />
 
36 &amp; N &amp; n &amp; N<br />
 
37 &amp; M &amp; m &amp; M<br />
 
38 &amp; , &lt; &amp; , (comma) &amp; &lt;<br />
 
39 &amp; . &gt; &amp; . (period) &amp; &gt;<br />
 
3A &amp; / ? &amp; / &amp; ?<br />
 
3B &amp; 3l''(undefined)''<br />
 
3C &amp; . &amp; . (period) &amp; . (Numeric pad)<br />
 
3D &amp; 7 &amp; 7 &amp; 7 (Numeric pad)<br />
 
3E &amp; 8 &amp; 8 &amp; 8 (Numeric pad)<br />
 
3F &amp; 9 &amp; 9 &amp; 9 (Numeric pad)<br />
 
40 &amp; Space bar &amp; (ASCII code 0x20) &amp; (ASCII code 0x20)<br />
 
41 &amp; Back Space &amp; (ASCII code 0x08) &amp; (ASCII code 0x08)<br />
 
42 &amp; Tab &amp; (ASCII code 0x09) &amp; (ASCII code 0x09)<br />
 
43 &amp; Enter &amp; (ASCII code 0x0D) &amp; (ASCII code 0x0D)<br />
 
44 &amp; Return &amp; (ASCII code 0x0D) &amp; (ASCII code 0x0D; Numeric pad)<br />
 
45 &amp; Esc &amp; (ASCII code 0x1B) &amp; (ASCII code 0x1B)<br />
 
46 &amp; Del &amp; (ASCII code 0x7F) &amp; (ASCII code 0x7F)<br />
 
47 &amp; 3l''(undefined)''<br />
 
48 &amp; 3l''(undefined)''<br />
 
49 &amp; 3l''(undefined)''<br />
 
4A &amp; - &amp; - (Hyphen) &amp; - (Numeric Pad)<br />
 
4B &amp; 3l''(undefined)''<br />
 
4C &amp; Up arrow &amp; &lt;CSI&gt;A &amp; &lt;CSI&gt;T<br />
 
4D &amp; Down arrow &amp; &lt;CSI&gt;B &amp; &lt;CSI&gt;S<br />
 
4E &amp; Forward arrow &amp; &lt;CSI&gt;C &amp; &lt;CSI&gt; A (note blank space after &lt;CSI&gt;)<br />
 
4F &amp; Backward arrow &amp; &lt;CSI&gt;D &amp; &lt;CSI&gt; @ (note blank space after &lt;CSI&gt;)<br />
 
50 &amp; F1 &amp; &lt;CSI&gt;0~ &amp; &lt;CSI&gt;10 <br />
 
51 &amp; F2 &amp; &lt;CSI&gt;1~ &amp; &lt;CSI&gt;11 <br />
 
52 &amp; F3 &amp; &lt;CSI&gt;2~ &amp; &lt;CSI&gt;12 <br />
 
53 &amp; F4 &amp; &lt;CSI&gt;3~ &amp; &lt;CSI&gt;13 <br />
 
54 &amp; F5 &amp; &lt;CSI&gt;4~ &amp; &lt;CSI&gt;14 <br />
 
55 &amp; F6 &amp; &lt;CSI&gt;5~ &amp; &lt;CSI&gt;15 <br />
 
56 &amp; F7 &amp; &lt;CSI&gt;6~ &amp; &lt;CSI&gt;16 <br />
 
57 &amp; F8 &amp; &lt;CSI&gt;7~ &amp; &lt;CSI&gt;17 <br />
 
58 &amp; F9 &amp; &lt;CSI&gt;8~ &amp; &lt;CSI&gt;18 <br />
 
59 &amp; F10 &amp; &lt;CSI&gt;9~ &amp; &lt;CSI&gt;19 <br />
 
5A &amp; ( &amp; ( &amp; ( (usa1 Numeric pad)<br />
 
5B &amp; ) &amp; ) &amp; ) (usa1 Numeric pad)<br />
 
5C &amp; / &amp; / &amp; / (usa1 Numeric pad)<br />
 
5D &amp; &amp; &amp; (usa1 Numeric pad)<br />
 
5E &amp; + &amp; + &amp; + (usa1 Numeric pad)<br />
 
5F &amp; Help &amp; &lt;CSI&gt;?  &amp; &lt;CSI&gt;? <br />
 
 
 
'''ROM Default (USA0) and USA1 Console Key Mapping (continued)'''
 
 
<table>
 
<tbody>
 
<tr class="odd">
 
<td align="left">'''Raw'''</td>
 
<td align="left">'''Function or'''</td>
 
</tr>
 
<tr class="even">
 
<td align="left">'''Key'''</td>
 
<td align="left">'''Keycap'''</td>
 
</tr>
 
<tr class="odd">
 
<td align="left">'''Number'''</td>
 
<td align="left">'''Legend'''</td>
 
</tr>
 
<tr class="even">
 
<td align="left">60</td>
 
<td align="left">Shift (left of space bar)</td>
 
</tr>
 
<tr class="odd">
 
<td align="left">61</td>
 
<td align="left">Shift (right of space bar)</td>
 
</tr>
 
<tr class="even">
 
<td align="left">62</td>
 
<td align="left">Caps Lock</td>
 
</tr>
 
<tr class="odd">
 
<td align="left">63</td>
 
<td align="left">Ctrl</td>
 
</tr>
 
<tr class="even">
 
<td align="left">64</td>
 
<td align="left">(Left) Alt</td>
 
</tr>
 
<tr class="odd">
 
<td align="left">65</td>
 
<td align="left">(Right) Alt</td>
 
</tr>
 
<tr class="even">
 
<td align="left">66</td>
 
<td align="left">Amiga (left of space bar; “Left Amiga”)</td>
 
</tr>
 
<tr class="odd">
 
<td align="left">67</td>
 
<td align="left">Amiga (right of space bar; “Right Amiga”)</td>
 
</tr>
 
<tr class="even">
 
<td align="left">68</td>
 
<td align="left">Left mouse button (''not converted''; inputs only for mouse connected to Intuition)</td>
 
</tr>
 
<tr class="odd">
 
<td align="left">69</td>
 
<td align="left">Right mouse button (''not converted''; inputs only for mouse connected to Intuition)</td>
 
</tr>
 
<tr class="even">
 
<td align="left">6A</td>
 
<td align="left">Middle mouse button (''not converted''; inputs only for mouse connected to Intuition)</td>
 
</tr>
 
<tr class="odd">
 
<td align="left">6B</td>
 
<td align="left">''(undefined)''</td>
 
</tr>
 
<tr class="even">
 
<td align="left">6C</td>
 
<td align="left">''(undefined)''</td>
 
</tr>
 
<tr class="odd">
 
<td align="left">6D</td>
 
<td align="left">''(undefined)''</td>
 
</tr>
 
<tr class="even">
 
<td align="left">6E</td>
 
<td align="left">''(undefined)''</td>
 
</tr>
 
<tr class="odd">
 
<td align="left">6F</td>
 
<td align="left">''(undefined)''</td>
 
</tr>
 
<tr class="even">
 
<td align="left">70-7F</td>
 
<td align="left">''(undefined)''</td>
 
</tr>
 
<tr class="odd">
 
<td align="left">80-F8</td>
 
<td align="left">Up transition (release or unpress key of one of the above keys;</td>
 
</tr>
 
<tr class="even">
 
<td align="left"></td>
 
<td align="left">80 for 00, F8 for 7F)</td>
 
</tr>
 
<tr class="odd">
 
<td align="left">F9</td>
 
<td align="left">Last key code was bad (was sent in order to resynchronize)</td>
 
</tr>
 
<tr class="even">
 
<td align="left">FA</td>
 
<td align="left">Keyboard buffer overflow</td>
 
</tr>
 
<tr class="odd">
 
<td align="left">FB</td>
 
<td align="left">''(undefined, reserved for keyboard processor catastrophe)''</td>
 
</tr>
 
<tr class="even">
 
<td align="left">FC</td>
 
<td align="left">Keyboard selftest failed</td>
 
</tr>
 
<tr class="odd">
 
<td align="left">FD</td>
 
<td align="left">Power-up key stream start. Keys pressed or stuck at power-up</td>
 
</tr>
 
<tr class="even">
 
<td align="left"></td>
 
<td align="left">will be sent between FD and FE.</td>
 
</tr>
 
<tr class="odd">
 
<td align="left">FE</td>
 
<td align="left">Power-up key stream end</td>
 
</tr>
 
<tr class="even">
 
<td align="left">FF</td>
 
<td align="left">''(undefined, reserved)''</td>
 
</tr>
 
<tr class="odd">
 
<td align="left">FF</td>
 
<td align="left">Mouse event, movement only, no button change (''not converted'')</td>
 
</tr>
 
</tbody>
 
</table>
 
   
 
Notes about the preceding table:
 
Notes about the preceding table:
   
  +
# "<CSI>" is the Control Sequence Introducer, value hex 9B.
<ol>
 
  +
# (undefined)" indicates that the current keyboard design should not generate this number. If you are using '''SetKeyMap()''' to change the key map, the entries for these numbers must still be included.
<li><p>''(undefined)''</p>
 
  +
# "(not converted)" refers to mouse button events. You must use the sequence "<CSI>2{" to inform the console driver that you wish to receive mouse events; otherwise these will not be transmitted.
<p>indicates that the current keyboard design should not generate this number. If you are using SetKeyMap() to change the key map, the entries for these numbers must still be included.</p></li>
 
  +
# "(RESERVED)" indicates that these key codes have been reserved for national keyboards. The $2B code key will be between the double-quote (") and Return keys. The $30 code key will be between the Shift and Z keys.
<li><p>''(not converted)''</p>
 
<p>refers to mouse button events. You must use the sequence &lt;CSI&gt;2{ to inform the console driver that you wish to receive mouse events; otherwise these will not be transmitted.</p></li>
 
<li><p>''(reserved)''</p>
 
<p>indicates that these key codes have been reserved for national keyboards. The $2B code key will be between the double-quote (&quot;) and Return keys. The $30 code key will be between the '''Shift''' and '''Z''' keys.</p></li></ol>
 
   
[[File:LibFig34-3.png]]
+
[[File:LibFig34-3.png|frame|center|ECMA-94 Latin 1 International 8-Bit Character Set]]
   
  +
== Raw Key Table ==
Figure 34-3: ECMA-94 Latin 1 International 8-Bit Character Set
 
   
  +
The following table defines all of the Amiga raw key codes and what they mean.
==== Complete Keymap Source Example ====
 
   
  +
{{Note|All values are in hexadecimal}}
The following example is the complete Amiga assembler source for the ''d'' (German) keymap. Comments in the source code illustrate the key layout of the German keyboard, and the standard U.S. keyboard layout for comparison.
 
   
  +
{| class="wikitable"
<pre>**********************************************************************
 
  +
! Raw Key
*
 
  +
! USB Page
* d (GERMAN) A2000 key map
 
  +
! USB Code
* Assemble and then link without startup code or linker libs
 
  +
! PS2 Set 1 Code
*
 
  +
! PS2 Set 2 Code
* Copyright (c) 1988 Commodore-Amiga, Inc. All Rights Reserved
 
  +
! Name
*
 
  +
! Classic Amiga Key
**********************************************************************
 
  +
|-
*------ Included Files -----------------------------------------------
 
  +
| 0000 || 0007 || 0035 || 0029 || 000E || || <nowiki>`~</nowiki>
INCLUDE &quot;exec/types.i&quot;
 
  +
|-
INCLUDE &quot;devices/keymap.i&quot;
 
  +
| 0001 || 0007 || 001E || 0002 || 0016 || || <nowiki>1!</nowiki>
*---------------------------------------------------------------------
 
  +
|-
DC.L 0,0 ; ln_Succ, ln_Pred
 
  +
| 0002 || 0007 || 001F || 0003 || 001E || || <nowiki>2@</nowiki>
DC.B 0,0 ; ln_Type, ln_Pri
 
  +
|-
DC.L KMName ; ln_Name
 
  +
| 0003 || 0007 || 0020 || 0004 || 0026 || || <nowiki>3#</nowiki>
DC.L KMLowMapType
 
  +
|-
DC.L KMLowMap
 
  +
| 0004 || 0007 || 0021 || 0005 || 0025 || || <nowiki>4$</nowiki>
DC.L KMLCapsable
 
  +
|-
DC.L KMLRepeatable
 
  +
| 0005 || 0007 || 0022 || 0006 || 002E || || <nowiki>5%</nowiki>
DC.L KMHighMapType
 
  +
|-
DC.L KMHighMap
 
  +
| 0006 || 0007 || 0023 || 0007 || 0036 || || <nowiki>6^</nowiki>
DC.L KMHCapsable
 
  +
|-
DC.L KMHRepeatable
 
  +
| 0007 || 0007 || 0024 || 0008 || 003D || || <nowiki>7&</nowiki>
*------ Key Translation Table ----------------------------------------
 
  +
|-
* Raw key codes
 
  +
| 0008 || 0007 || 0025 || 0009 || 003E || || <nowiki>8*</nowiki>
*
 
  +
|-
* 45 50 51 52 53 54 55 56 57 58 59
 
  +
| 0009 || 0007 || 0026 || 000A || 0046 || || <nowiki>9(</nowiki>
* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 41 46 5F 5A 5B 5C 5D
 
  +
|-
* 42 10 11 12 13 14 15 16 17 18 19 1A 1B 44 3D 3E 3F 4A
 
  +
| 000A || 0007 || 0027 || 000B || 0045 || || <nowiki>0)</nowiki>
* 63 62 20 21 22 23 24 25 26 27 28 29 2A 2B 4C 2D 2E 2F 5E
 
  +
|-
* 60 30 31 32 33 34 35 36 37 38 39 3A 61 4F 4D 4E 1D 1E 1F 43
 
  +
| 000B || 0007 || 002D || 000C || 004E || || <nowiki>-_</nowiki>
* 64 66 40 67 65 0F 3C
 
  +
|-
*
 
  +
| 000C || 0007 || 002E || 000D || 0055 || || <nowiki>=+</nowiki>
*---------------------------------------------------------------------
 
  +
|-
* German (D) mapping
 
  +
| 000D || 0007 || 0031 || || || || <nowiki>\|</nowiki> near Backspace
*
 
  +
|-
* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10
 
  +
| 000E || 0007 || 0089 || 007D || 006A || || Intl 3 Yen
* `~ 1! 2&quot; 3S 4$ 5% 6&amp; 7/ 8( 9) 0= B? '` \| BS DEL HELP [{ ]} / *
 
  +
|-
* TAB qQ wW eE rR tT zZ uU iI oO pP uU +* RET 7 8 9 -
 
  +
| 000F || 0007 || 0062 || 0052 || 0070 || || NP <nowiki>0</nowiki>
* CT CL aA sS dD fF gG hH jJ kK lL oO aA #^ UC 4 5 6 +
 
  +
|-
* SH &lt;&gt; yY xX cC vV bB nN mM ,; .: -_ SH LC DC RC 1 2 3 ENT
 
  +
| 0010 || 0007 || 0014 || 0010 || 0015 || || <nowiki>qQ</nowiki>
* ALT AM SPACE AM ALT 0 .
 
  +
|-
*
 
  +
| 0011 || 0007 || 001A || 0011 || 001D || || <nowiki>wW</nowiki>
*---------------------------------------------------------------------
 
  +
|-
* For comparison, here's the USA1 mapping
 
  +
| 0012 || 0007 || 0008 || 0012 || 0024 || || <nowiki>eE</nowiki>
*
 
  +
|-
* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10
 
  +
| 0013 || 0007 || 0015 || 0013 || 002D || || <nowiki>rR</nowiki>
* `~ 1! 2@ 3# 4$ 5% 6^ 7&amp; 8* 9( 0) -_ =+ \| BS DEL HELP (( )) // **
 
  +
|-
* TAB qQ wW eE rR tT yY uU iI oO pP [{ ]} RET 77 88 99 --
 
  +
| 0014 || 0007 || 0017 || 0014 || 002C || || <nowiki>tT</nowiki>
* CT CL aA sS dD fF gG hH jJ kK lL ;: '&quot; [2B] UC 44 55 66 ++
 
  +
|-
* SH [30] zZ xX cC vV bB nN mM ,&lt; .&gt; /? SH LC DC RC 11 22 33 ENT
 
  +
| 0015 || 0007 || 001C || 0015 || 0035 || || <nowiki>yY</nowiki>
* ALT AM SPACE AM ALT 00 ..
 
  +
|-
*
 
  +
| 0016 || 0007 || 0018 || 0016 || 003C || || <nowiki>uU</nowiki>
*--------------------------------------------------------------------------
 
  +
|-
*
 
  +
| 0017 || 0007 || 000C || 0017 || 0043 || || <nowiki>iI</nowiki>
* 40 Space
 
  +
|-
* 41 Backspace
 
  +
| 0018 || 0007 || 0012 || 0018 || 0044 || || <nowiki>oO</nowiki>
* 42 Tab
 
  +
|-
* 43 Enter
 
  +
| 0019 || 0007 || 0013 || 0019 || 004D || || <nowiki>pP</nowiki>
* 44 Return
 
  +
|-
* 45 Escape
 
  +
| 001A || 0007 || 002F || 001A || 0054 || || <nowiki>[{</nowiki>
* 46 Delete
 
  +
|-
* 4A Numeric Pad -
 
  +
| 001B || 0007 || 0030 || 001B || 005B || || <nowiki>]}</nowiki>
* 4C Cursor Up
 
  +
|-
* 4D Cursor Down
 
  +
| 001C || || || || || || undefined
* 4E Cursor Forward
 
  +
|-
* 4F Cursor Backward
 
  +
| 001D || 0007 || 0059 || 004F || 0069 || || NP <nowiki>1</nowiki>
*
 
  +
|-
* 50-59 Function keys F1-F10
 
  +
| 001E || 0007 || 005A || 0050 || 0072 || || NP <nowiki>2</nowiki>
* 5A Numeric Pad [{ (A2000)
 
  +
|-
* 5B Numeric Pad ]} (A2000)
 
  +
| 001F || 0007 || 005B || 0051 || 007A || || NP <nowiki>3</nowiki>
* 5C Numeric Pad / (A2000)
 
  +
|-
* 5D Numeric Pad * (A2000)
 
  +
| 0020 || 0007 || 0004 || 001E || 001C || || <nowiki>aA</nowiki>
* 5E Numeric Pad + (A2000)
 
  +
|-
* 5F Help
 
  +
| 0021 || 0007 || 0016 || 001F || 001B || || <nowiki>sS</nowiki>
*
 
  +
|-
* 60 Left Shift
 
  +
| 0022 || 0007 || 0007 || 0020 || 0023 || || <nowiki>dD</nowiki>
* 61 Right Shift
 
  +
|-
* 62 Caps Lock
 
  +
| 0023 || 0007 || 0009 || 0021 || 002B || || <nowiki>fF</nowiki>
* 63 Control
 
  +
|-
* 64 Left Alt
 
  +
| 0024 || 0007 || 000A || 0022 || 0034 || || <nowiki>gG</nowiki>
* 65 Right Alt
 
  +
|-
* 66 Left Amiga
 
  +
| 0025 || 0007 || 000B || 0023 || 0033 || || <nowiki>hH</nowiki>
* 67 Right Amiga
 
  +
|-
*
 
  +
| 0026 || 0007 || 000D || 0024 || 003B || || <nowiki>jJ</nowiki>
* 68 Left Mouse Button (not converted)
 
  +
|-
* 69 Right Mouse Button (not converted)
 
  +
| 0027 || 0007 || 000E || 0025 || 0042 || || <nowiki>kK</nowiki>
* 6A Middle Mouse Button (not converted)
 
  +
|-
*
 
  +
| 0028 || 0007 || 000F || 0026 || 004B || || <nowiki>lL</nowiki>
*---------------------------------------------------------------------
 
  +
|-
KMLCapsable: ; NL means NULL (undefined) and RE means RESERVED
 
  +
| 0029 || 0007 || 0033 || 0027 || 004C || || <nowiki>;:</nowiki>
DC.B %00000000 ; 7\ 6&amp; 5% 4$ 3s 2&quot; 1! [] 07 - 00
 
  +
|-
DC.B %00000000 ; 0N NL \| '` B? 0= 9) 8( 0F - 08
 
  +
| 002A || 0007 || 0034 || 0028 || 0052 || || <nowiki>'"</nowiki>
DC.B %11111111 ; iI uU zZ tT rR eE wW qQ 17 - 10
 
  +
|-
DC.B %00000111 ; 3N 2N 1N NL +* UU pP oO 1F - 18
 
  +
| 002B || 0007 || 0032 || 002B || 005D || || Intl 1 near Return
DC.B %11111111 ; kK jJ hH gG fF dD sS aA 27 - 20
 
  +
|-
DC.B %00000111 ; 6N 5N 4N NL #' AA OO lL 2F - 28
 
  +
| 002C || || || || || || undefined
DC.B %11111110 ; mM nN bB vV cC xX yY &lt;&gt; 37 - 30
 
  +
|-
DC.B %00000000 ; 9N 8N 7N .N NL -_ .: ,; 3F - 38
 
  +
| 002D || 0007 || 005C || 004B || 006B || || NP <nowiki>4</nowiki>
 
  +
|-
KMHCapsable:
 
  +
| 002E || 0007 || 005D || 004C || 0073 || || NP <nowiki>5</nowiki>
DC.B %00000000 ; 47 - 40
 
  +
|-
DC.B %00000000 ; 4F - 48
 
  +
| 002F || 0007 || 005E || 004D || 0074 || || NP <nowiki>6</nowiki>
DC.B %00000000 ; 57 - 50
 
  +
|-
DC.B %00000000 ; 5F - 58
 
  +
| 0030 || 0007 || 0064 || 0056 || 0061 || || Intl 2 near LShift
DC.B %00000000 ; 67 - 60
 
  +
|-
DC.B %00000000 ; 6F - 68
 
  +
| 0031 || 0007 || 001D || 002C || 001A || || <nowiki>zZ</nowiki>
DC.B %00000000 ; 77 - 70
 
  +
|-
KMLRepeatable:
 
  +
| 0032 || 0007 || 001B || 002D || 0022 || || <nowiki>xX</nowiki>
DC.B %11111111 ; 7\ 6&amp; 5% 4$ 3s 2&quot; 1! [] 07 - 00
 
  +
|-
DC.B %10111111 ; 0N NL \| '` B? 0= 9) 8( 0F - 08
 
  +
| 0033 || 0007 || 0006 || 002E || 0021 || || <nowiki>cC</nowiki>
DC.B %11111111 ; iI uU zZ tT rR eE wW qQ 17 - 10
 
  +
|-
DC.B %11101111 ; 3N 2N 1N NL +* UU pP oO 1F - 18
 
  +
| 0034 || 0007 || 0019 || 002F || 002A || || <nowiki>vV</nowiki>
DC.B %11111111 ; kK jJ hH gG fF dD sS aA 27 - 20
 
  +
|-
DC.B %11101111 ; 6N 5N 4N NL #' AA OO lL 2F - 28
 
  +
| 0035 || 0007 || 0005 || 0030 || 0032 || || <nowiki>bB</nowiki>
DC.B %11111111 ; mM nN bB vV cC xX yY &lt;&gt; 37 - 30
 
  +
|-
DC.B %11110111 ; 9N 8N 7N .N NL -_ .: ,; 3F - 38
 
  +
| 0036 || 0007 || 0011 || 0031 || 0031 || || <nowiki>nN</nowiki>
KMHRepeatable:
 
  +
|-
DC.B %01000111 ; 47 - 40
 
  +
| 0037 || 0007 || 0010 || 0032 || 003A || || <nowiki>mM</nowiki>
DC.B %11110100 ; 4F - 48
 
  +
|-
DC.B %11111111 ; 57 - 50
 
  +
| 0038 || 0007 || 0036 || 0033 || 0041 || || <nowiki>,<</nowiki>
DC.B %01111111 ; 5F - 58
 
  +
|-
DC.B %00000000 ; 67 - 60
 
  +
| 0039 || 0007 || 0037 || 0034 || 0049 || || <nowiki>.></nowiki>
DC.B %00000000 ; 6F - 68
 
  +
|-
DC.B %00000000 ; 77 - 70
 
  +
| 003A || 0007 || 0038 || 0035 || 004A || || <nowiki>/?</nowiki>
KMLowMapType:
 
  +
|-
DC.B KC_VANILLA ; [] $00
 
  +
| 003B || 0007 || 0087 || 0073 || 0051 || || <nowiki>/?</nowiki> Brazil (near RShift) and International 1 (Ro)
DC.B KCF_SHIFT+KCF_ALT ; 1!
 
  +
|-
DC.B KCF_SHIFT+KCF_ALT ; 2&quot;
 
  +
| 003C || 0007 || 0063 || 0053 || 0071 || || NP <nowiki>.</nowiki>
DC.B KCF_SHIFT+KCF_ALT ; 3s
 
  +
|-
DC.B KCF_SHIFT+KCF_ALT ; 4$
 
  +
| 003D || 0007 || 005F || 0047 || 006C || || NP <nowiki>7</nowiki>
DC.B KCF_SHIFT+KCF_ALT ; 5%
 
  +
|-
DC.B KC_VANILLA ; 6&amp;
 
  +
| 003E || 0007 || 0060 || 0048 || 0075 || || NP <nowiki>8</nowiki>
DC.B KCF_SHIFT+KCF_ALT ; 7/
 
  +
|-
DC.B KCF_SHIFT+KCF_ALT ; 8( $08
 
  +
| 003F || 0007 || 0061 || 0049 || 007D || || NP <nowiki>9</nowiki>
DC.B KCF_SHIFT+KCF_ALT ; 9)
 
  +
|-
DC.B KCF_SHIFT+KCF_ALT ; 0=
 
  +
| 0040 || 0007 || 002C || 0039 || 0029 || SPACE || Space
DC.B KC_VANILLA ; B?
 
  +
|-
DC.B KCF_DEAD+KCF_SHIFT+KCF_ALT ; '`
 
  +
| 0041 || 0007 || 002A || 000E || 0066 || BACKSPACE || Backspace
DC.B KC_VANILLA ; \|
 
  +
|-
DC.B KCF_NOP ;NL
 
  +
| 0042 || 0007 || 002B || 000F || 000D || TAB || Tab
DC.B KC_NOQUAL ; 0N
 
  +
|-
DC.B KC_VANILLA ; qQ $10
 
  +
| 0043 || 0007 || 0058 || 00E01C || 00E05A || ENTER || NP Enter
DC.B KC_VANILLA ; wW
 
  +
|-
DC.B KCF_DEAD+KC_VANILLA ; eE
 
  +
| 0044 || 0007 || 0028 || 001C || 005A || RETURN || Return
DC.B KC_VANILLA ; rR
 
  +
|-
DC.B KC_VANILLA ; tT
 
  +
| 0045 || 0007 || 0029 || 0001 || 0076 || ESC || Escape
DC.B KC_VANILLA ; zZ
 
  +
|-
DC.B KCF_DEAD+KC_VANILLA ; uU
 
  +
| 0046 || 0007 || 004C || 00E053 || 00E071 || DEL || Delete
DC.B KCF_DEAD+KC_VANILLA ; iI
 
  +
|-
DC.B KCF_DEAD+KC_VANILLA ; oO $18
 
  +
| 0047 || 0007 || 0049 || 00E052 || 00E070 || INSERT || Insert
DC.B KC_VANILLA ; pP
 
  +
|-
DC.B KC_VANILLA ; omlatuU
 
  +
| 0048 || 0007 || 004B || 00E049 || 00E07D || PAGE_UP || PageUp
DC.B KC_VANILLA ; +*
 
  +
|-
DC.B KCF_NOP ; NL
 
  +
| 0049 || 0007 || 004E || 00E051 || 00E07A || PAGE_DOWN || PageDown
DC.B KC_NOQUAL ; 1N
 
  +
|-
DC.B KC_NOQUAL ; 2N
 
  +
| 004A || 0007 || 0056 || 004A || 007B || || NP <nowiki>-</nowiki>
DC.B KC_NOQUAL ; 3N
 
  +
|-
DC.B KCF_DEAD+KC_VANILLA ; aA $20
 
  +
| 004B || 0007 || 0044 || 0057 || 0078 || F11 || F11
DC.B KC_VANILLA ; sS
 
  +
|-
DC.B KC_VANILLA ; dD
 
  +
| 004C || 0007 || 0052 || 00E048 || 00E075 || CURSOR_UP || CrsrUp
DC.B KCF_DEAD+KC_VANILLA ; fF
 
  +
|-
DC.B KCF_DEAD+KC_VANILLA ; gG
 
  +
| 004D || 0007 || 0051 || 00E050 || 00E072 || CURSOR_DOWN || CrsrDown
DC.B KCF_DEAD+KC_VANILLA ; hH
 
  +
|-
DC.B KCF_DEAD+KC_VANILLA ; jJ
 
  +
| 004E || 0007 || 004F || 00E04D || 00E074 || CURSOR_RIGHT || CrsrRight
DC.B KCF_DEAD+KC_VANILLA ; kK
 
  +
|-
DC.B KC_VANILLA ; lL $28
 
  +
| 004F || 0007 || 0050 || 00E04B || 00E06B || CURSOR_LEFT || CrsrLeft
DC.B KCF_SHIFT+KCF_ALT ; umlotoO
 
  +
|-
DC.B KCF_SHIFT+KCF_ALT ; umlotaA
 
  +
| 0050 || 0007 || 003A || 003B || 0005 || F1 || F1
DC.B KC_VANILLA ; #^
 
  +
|-
DC.B KCF_NOP ; NL
 
  +
| 0051 || 0007 || 003B || 003C || 0006 || F2 || F2
DC.B KC_NOQUAL ; 4N
 
  +
|-
DC.B KC_NOQUAL ; 5N
 
  +
| 0052 || 0007 || 003C || 003D || 0004 || F3 || F3
DC.B KC_NOQUAL ; 6N
 
  +
|-
DC.B KCF_SHIFT ; &lt;&gt; $30
 
  +
| 0053 || 0007 || 003D || 003E || 000C || F4 || F4
DC.B KCF_DEAD+KC_VANILLA ; yY
 
  +
|-
DC.B KC_VANILLA ; xX
 
  +
| 0054 || 0007 || 003E || 003F || 0003 || F5 || F5
DC.B KC_VANILLA ; cC
 
  +
|-
DC.B KC_VANILLA ; vV
 
  +
| 0055 || 0007 || 003F || 0040 || 000B || F6 || F6
DC.B KC_VANILLA ; bB
 
  +
|-
DC.B KCF_DEAD+KC_VANILLA ; nN
 
  +
| 0056 || 0007 || 0040 || 0041 || 0083 || F7 || F7
DC.B KC_VANILLA ; mM
 
  +
|-
DC.B KCF_SHIFT+KCF_ALT ; ,; $38
 
  +
| 0057 || 0007 || 0041 || 0042 || 000A || F8 || F8
DC.B KCF_SHIFT+KCF_ALT ; .:
 
  +
|-
DC.B KC_VANILLA ; -_
 
  +
| 0058 || 0007 || 0042 || 0043 || 0001 || F9 || F9
DC.B KCF_NOP ; NL
 
  +
|-
DC.B KC_NOQUAL ; .N
 
  +
| 0059 || 0007 || 0043 || 0044 || 0009 || F10 || F10
DC.B KC_NOQUAL ; 7N
 
  +
|-
DC.B KC_NOQUAL ; 8N
 
  +
| 005A || || || || || || NP <nowiki>(</nowiki>
DC.B KC_NOQUAL ; 9N
 
  +
|-
KMHighMapType:
 
  +
| 005B || || || || || || NP <nowiki>)</nowiki>
DC.B KCF_DEAD+KCF_ALT ; SPACE $40
 
  +
|-
DC.B KC_NOQUAL ; BACKSPACE
 
  +
| 005C || 0007 || 0054 || 00E035 || 00E04A || || NP <nowiki>/</nowiki>
DC.B KCF_STRING+KCF_SHIFT ; TAB
 
  +
|-
DC.B KC_NOQUAL ; ENTER
 
  +
| 005D || 0007 || 0055 || 0037 || 007C || || NP <nowiki>*</nowiki>
DC.B KCF_CONTROL ; RETURN
 
  +
|-
DC.B KCF_ALT ; ESCAPE
 
  +
| 005E || 0007 || 0057 || 004E || 0079 || || NP <nowiki>+</nowiki>
DC.B KC_NOQUAL ; DELETE
 
  +
|-
DC.B KCF_NOP
 
  +
| 005F || 0007 || 0075 || 0046 || 007E || HELP || Help (maps to ScrollLock on PS/2)
DC.B KCF_NOP ; $48
 
  +
|-
DC.B KCF_NOP
 
  +
| 0060 || 0007 || 00E1 || 002A || 0012 || LSHIFT || LShift
DC.B KC_NOQUAL ; -N
 
  +
|-
DC.B KCF_NOP
 
  +
| 0061 || 0007 || 00E5 || 0036 || 0059 || RSHIFT || RShift
DC.B KCF_STRING+KCF_SHIFT ; CURSOR UP
 
  +
|-
DC.B KCF_STRING+KCF_SHIFT ; CURSOR DOWN
 
  +
| 0062 || 0007 || 0039 || 003A || 0058 || CAPSLOCK || CapsLock
DC.B KCF_STRING+KCF_SHIFT ; CURSOR FORWARD
 
  +
|-
DC.B KCF_STRING+KCF_SHIFT ; CURSOR BACKWARD
 
  +
| 0063 || 0007 || 00E0 || 001D || 0014 || CONTROL || LControl
DC.B KCF_STRING+KCF_SHIFT ; FKEY 1 $50
 
  +
|-
DC.B KCF_STRING+KCF_SHIFT ; FKEY 2
 
  +
| 0064 || 0007 || 00E2 || 0038 || 0011 || LALT || LAlt
DC.B KCF_STRING+KCF_SHIFT ; FKEY 3
 
  +
|-
DC.B KCF_STRING+KCF_SHIFT ; FKEY 4
 
  +
| 0065 || 0007 || 00E6 || 00E038 || 00E011 || RALT || RAlt
DC.B KCF_STRING+KCF_SHIFT ; FKEY 5
 
  +
|-
DC.B KCF_STRING+KCF_SHIFT ; FKEY 6
 
  +
| 0066 || 0007 || 00E3 || 00E05B || 00E01F || LCOMMAND || LAmiga, LWin, LApple, LMeta
DC.B KCF_STRING+KCF_SHIFT ; FKEY 7
 
  +
|-
DC.B KCF_STRING+KCF_SHIFT ; FKEY 8
 
  +
| 0067 || 0007 || 00E7 || 00E05C || 00E027 || RCOMMAND || RAmiga, RWin, RApple, RMeta
DC.B KCF_STRING+KCF_SHIFT ; FKEY 9 $58
 
  +
|-
DC.B KCF_STRING+KCF_SHIFT ; FKEY 10
 
  +
| 0068 || || || || || LBUTTON || LMouse reserved
DC.B KCF_SHIFT+KCF_CONTROL ; Numeric Pad [{
 
  +
|-
DC.B KCF_SHIFT+KCF_CONTROL ; Numeric Pad ]}
 
  +
| 0069 || || || || || RBUTTON || RMouse reserved
DC.B KC_NOQUAL ; Numeric Pad /
 
  +
|-
DC.B KC_NOQUAL ; Numeric Pad *
 
  +
| 006A || || || || || MBUTTON || MMouse reserved
DC.B KC_NOQUAL ; Numeric Pad +
 
  +
|-
DC.B KCF_STRING ; Help
 
  +
| 006B || 0007 || 0065 || 00E05D || 00E02F || MENU || Menu, Windows, Compose (mappable to RAmiga in Firmware)
DC.B KCF_NOP ; Left Shift $60
 
  +
|-
DC.B KCF_NOP ; Right Shift
 
  +
| 006C || 0007 || 0085 || 007E || 006D || || Brazil NP <nowiki>.</nowiki> (named "Keypad <nowiki>,</nowiki>" in USB specs)
DC.B KCF_NOP ; Caps Lock
 
  +
|-
DC.B KCF_NOP ; Control
 
  +
| 006D || 0007 || 0046 || 00E037 || 00E07C || PRINTSCREEN || PrintScreen/SysReq (mappable to Help in Firmware)
DC.B KCF_NOP ; Left Alt
 
  +
|-
DC.B KCF_NOP ; Right Alt
 
  +
| 006E || 0007 || 0048 || 00E046 || 00E07E || BREAK || Break, Ctrl-Pause on PS/2
DC.B KCF_NOP ; Left Amiga
 
  +
|-
DC.B KCF_NOP ; Right Amiga
 
  +
| 006F || 0007 || 0045 || 0058 || 0007 || F12 || F12
DC.B KCF_NOP ; Left Mouse Button $68
 
  +
|-
DC.B KCF_NOP ; Right Mouse Button
 
  +
| 0070 || 0007 || 004A || 00E047 || 00E06C || HOME || Home
DC.B KCF_NOP ; Middle Mouse Button
 
  +
|-
DC.B KCF_NOP
 
DC.B KCF_NOP
+
| 0071 || 0007 || 004D || 00E04F || 00E069 || END || End
  +
|-
DC.B KCF_NOP
 
  +
| 0072 || 000C || 00B7 || 00E024 || 00E03B || AUD_STOP || Stop, CD32 Blue Stop, CDTV Stop, Port 0 Blue
DC.B KCF_NOP
 
  +
|-
DC.B KCF_NOP
 
  +
| 0073 || 000C || 00CD || 00E022 || E034 || AUD_PLAY_PAUSE || Play/Pause, CD32 Grey Play/Pause, CDTV Play/Pause, Port 0 Play
DC.B KCF_NOP ; $70
 
  +
|-
DC.B KCF_NOP
 
  +
| 0074 || 000C || 00B6 || 00E010 || E015 || AUD_PREV_TRACK || Prev Track, CD32 Charcoal Reverse, CDTV <nowiki><<</nowiki> REW, Port 0 Reverse
DC.B KCF_NOP
 
  +
|-
DC.B KCF_NOP
 
  +
| 0075 || 000C || 00B5 || 00E019 || E04D || AUD_NEXT_TRACK || Next Track, CD32 Charcoal Forward, CDTV <nowiki>>></nowiki> FF, Port 0 Forward
DC.B KCF_NOP
 
  +
|-
DC.B KCF_NOP
 
  +
| 0076 || 000C || 00B9 || || || AUD_SHUFFLE || Random Play, CD32 Green Shuffle, Port 0 Green
DC.B KCF_NOP
 
  +
|-
DC.B KCF_NOP
 
  +
| 0077 || 000C || 00BC || || || AUD_REPEAT || Repeat, CD32 Yellow Repeat, Port 0 Yellow
KMLowMap:
 
  +
|-
DC.B '~','`','~','`' ; `, ~, `, ~ $00
 
  +
| 0078 || || || || || || Port 0 Red
DC.B '!',$B9,'!','1' ; 1, !, super 1, !
 
  +
|-
DC.B $B2,'@','&quot;','2' ; 2, &quot;, @, super 2
 
  +
| 0079 || || || || || || Port 0 Joystick Up
DC.B '#',$B3,$A7,'3' ; 3, section, super 3, #
 
  +
|-
DC.B $A2,$B0,'$','4' ; 4, $, degree, cents
 
  +
| 007A || || || || || || Port 0 Joystick Down
DC.B '%',$BC,'%','5' ; 5, %, 1/4, %
 
  +
|-
DC.B '^',$BD,'&amp;','6' ; 6, &amp;, 1/2, ^
 
  +
| 007B || || || || || || Port 0 Joystick Right
DC.B '&amp;',$BE,'/','7' ; 7, /, 3/4, &amp;
 
  +
|-
DC.B '*',$B7,'(','8' ; 8, (, bullet, * $08
 
  +
| 007C || || || || || || Port 0 Joystick Left
DC.B '(',$AB,')','9' ; 9, ), &lt;&lt;, (
 
  +
|-
DC.B ')',$BB,'=','0' ; 0, =, &gt;&gt;, )
 
  +
| 007D || || || || || || undefined
DC.B '_','-','?',$DF ; sharp s, ?, -, _
 
  +
|-
DC.L key0C ; dead ', dead `, =, +
 
  +
| 007E || || || || || || undefined
DC.B '|','\','|','\' ; \, |, \, |
 
  +
|-
DC.L 0 ; NOP
 
  +
| 007F || || || || || || undefined
DC.B 0,0,0,'0' ; numeric pad 0 (0N)
 
  +
|-
DC.B $C5,$E5,'Q','q' ; q, Q, dot a, dot A $10
 
  +
| 0080 - 00F8 || || || || || || Up transition (release or unpress key) (0080 for 0000, 00F8 for 0078)
DC.B $B0,$B0,'W','w' ; w, W, dot, dot
 
  +
|-
DC.L key12 ; e, E, (c), (c)
 
  +
| 00F9 || || || || || || Last key code was bad (was sent in order to resynchronize)
DC.B $AE,$AE,'R','r' ; r, R, (r), (r)
 
  +
|-
DC.B $DE,$FE,'T','t' ; t, T, thorn, THORN
 
  +
| 00FA || || || || || || Keyboard buffer overflow
DC.B $A5,$A4,'Z','z' ; z, Z, IMS, Yen
 
  +
|-
DC.L key16 ; u, U, micro, micro
 
  +
| 00FB || || || || || || (undefined, reserved for keyboard processor catastrophe)
DC.L key17 ; i, I, inverted !, broken |
 
  +
|-
DC.L key18 ; o, O, slash o, slash O $18
 
  +
| 00FC || || || || || || Keyboard selftest failed
DC.B $B6,$B6,'P','p' ; p, P, paragraph, paragraph
 
  +
|-
DC.B '{','[',$DC,$FC ; umlaut u, umlaut U, [, {
 
  +
| 00FD || || || || || || Power-up key stream start. Keys pressed or stuck at power-up will be sent between 00FD and 00FE.
DC.B '}',']','*','+' ; +, *, ], }
 
  +
|-
DC.L 0 ; NOP
 
  +
| 00FE || || || || || || Power-up key stream end
DC.B 0,0,0,'1' ; numeric pad 1 (1N)
 
  +
|-
DC.B 0,0,0,'2' ; numeric pad 2 (2N)
 
  +
| 00FF || || || || || || No key code defined
DC.B 0,0,0,'3' ; numeric pad 3 (3N)
 
  +
|-
DC.L key20 ; a, A, ae, AE $20
 
  +
| 0100 || 0007 || 0088 || 0070 || 0013 || || Intl 2 Hiragana/Katakana
DC.B $A7,$DF,'S','s' ; s, S, sharp s, section
 
  +
|-
DC.B $D0,$F0,'D','d' ; d, D, bar d, bar D
 
  +
| 0101 || 0007 || 008A || 0079 || 0064 || || Intl 4 Henkan
DC.L key23 ; f, F, dead '
 
  +
|-
DC.L key24 ; g, G, dead `
 
  +
| 0102 || 0007 || 008B || 007B || 0067 || || Intl 5 Muhenkan
DC.L key25 ; h, H, dead ^
 
  +
|-
DC.L key26 ; j, J, dead ~
 
  +
| 0103 || 0007 || 0068 || 0064 || 0008 || F13 || F13
DC.L key27 ; k, K, dead &quot;
 
  +
|-
DC.B $A3,$A3,'L','l' ; l, L, pound, pound $28
 
  +
| 0104 || 0007 || 0069 || 0065 || 0010 || F14 || F14
DC.B ':',';',$D6,$F6 ; umlaut o, umlaut O, ;, :
 
  +
|-
DC.B '&quot;',$27,$C4,$E4 ; umlaut a, umlaut A, ', &quot;
 
  +
| 0105 || 0007 || 006A || 0066 || 0018 || F15 || F15
DC.B '^','#','^','#' ; #, ^, #, ^
 
  +
|-
DC.L 0 ; NOP
 
  +
| 0180 - 0185 || || || || || || Up transition (release or unpress key) (0180 for 0100)
DC.B 0,0,0,'4' ; numeric pad 4 (4N)
 
  +
|}
DC.B 0,0,0,'5' ; numeric pad 5 (5N)
 
DC.B 0,0,0,'6' ; numeric pad 6 (6N)
 
DC.B 0,0,'&gt;','&lt;' ; &lt;, &gt; $30
 
DC.L key31 ; y, Y, +/-, not
 
DC.B $F7,$D7,'X','x' ; x, X, times, divide
 
DC.B $C7,$E7,'C','c' ; c, C, c cedilla, C cedilla
 
DC.B $AA,$AA,'V','v' ; v, V, female ordinal
 
DC.B $BA,$BA,'B','b' ; b, B, male ordinal
 
DC.L key36 ; n, N, SHY, overbar
 
DC.B $BF,$B8,'M','m' ; m, M, cedilla, inverted ?
 
DC.B '&lt;',',',';',',' ; ,, ;, ,, &lt; $38
 
DC.B '&gt;','.',':','.' ; ., :, ., &gt;
 
DC.B '?','/','_','-' ; -, _, /, ?
 
DC.L 0 ; NOP
 
DC.B 0,0,0,'.' ; numeric pad . (.N)
 
DC.B 0,0,0,'7' ; numeric pad 7 (7N)
 
DC.B 0,0,0,'8' ; numeric pad 8 (8N)
 
DC.B 0,0,0,'9' ; numeric pad 9 (9N)
 
KMHighMap:
 
DC.L key40 $40
 
DC.B 0,0,0,$08
 
DC.L key42
 
DC.B 0,0,0,$0D
 
DC.B 0,0,$0A,$0D
 
DC.B 0,0,$9B,$1B
 
DC.B 0,0,0,$7F
 
DC.L 0
 
DC.L 0 $48
 
DC.L 0
 
DC.B 0,0,0,'-'
 
DC.L 0
 
DC.L key4C
 
DC.L key4D
 
DC.L key4E
 
DC.L key4F
 
DC.L key50 $50
 
DC.L key51
 
DC.L key52
 
DC.L key53
 
DC.L key54
 
DC.L key55
 
DC.L key56
 
DC.L key57
 
DC.L key58 $58
 
DC.L key59
 
DC.B $1B,$1B,'{','[' ; numeric pad [, {
 
DC.B $1D,$1D,'}',']' ; numeric pad ], }
 
DC.B 0,0,0,'/' ; numeric pad /
 
DC.B 0,0,0,'*' ; numeric pad *
 
DC.B 0,0,0,'+' ; numeric pad +
 
DC.L key5F
 
DC.L 0 $60
 
DC.L 0
 
DC.L 0
 
DC.L 0
 
DC.L 0
 
DC.L 0
 
DC.L 0
 
DC.L 0
 
DC.L 0 $68
 
DC.L 0
 
DC.L 0
 
DC.L 0
 
DC.L 0
 
DC.L 0
 
DC.L 0
 
DC.L 0
 
DC.L 0 $70
 
DC.L 0
 
DC.L 0
 
DC.L 0
 
DC.L 0
 
DC.L 0
 
DC.L 0
 
DC.L 0
 
;------ possible dead keys
 
key0C:
 
DC.B DPF_DEAD,1+(6&lt;&lt;DP_2DFACSHIFT) ; dead '
 
DC.B DPF_DEAD,2+(6&lt;&lt;DP_2DFACSHIFT) ; dead `
 
DC.B 0,'=',0,'+' ; =, +
 
key23:
 
DC.B 0,'f',0,'F' ; f, F
 
DC.B DPF_DEAD,1+(6&lt;&lt;DP_2DFACSHIFT) ; dead '
 
DC.B DPF_DEAD,1+(6&lt;&lt;DP_2DFACSHIFT) ; dead '
 
DC.B 0,$06,0,$06,0,$86,0,$86 ; control translation
 
key24:
 
DC.B 0,'g',0,'G' ; g, G
 
DC.B DPF_DEAD,2+(6&lt;&lt;DP_2DFACSHIFT) ; dead `
 
DC.B DPF_DEAD,2+(6&lt;&lt;DP_2DFACSHIFT) ; dead `
 
DC.B 0,$07,0,$07,0,$87,0,$87 ; control translation
 
key25:
 
DC.B 0,'h',0,'H' ; h, H
 
DC.B DPF_DEAD,3,DPF_DEAD,3 ; dead ^, dead ^
 
DC.B 0,$08,0,$08,0,$88,0,$88 ; control translation
 
key26:
 
DC.B 0,'j',0,'J' ; j, J
 
DC.B DPF_DEAD,4,DPF_DEAD,4 ; dead ~, dead ~
 
DC.B 0,$0A,0,$0A,0,$8A,0,$8A ; control translation
 
key27:
 
DC.B 0,'k',0,'K' ; k, K
 
DC.B DPF_DEAD,5,DPF_DEAD,5 ; dead &quot;, dead &quot;
 
DC.B 0,$0B,0,$0B,0,$8B,0,$8B ; control translation
 
;------ deadable keys (modified by dead keys)
 
key12: ; e, E, (c), (c)
 
DC.B DPF_MOD,key12u-key12,DPF_MOD,key12s-key12
 
DC.B 0,$A9,0,$A9
 
DC.B 0,$05,0,$05,0,$85,0,$85 ; control translation
 
key12u:
 
DC.B 'e',$E9,$E8,$EA,'e',$EB
 
DC.B $E9,$E9,$EA,$E9,$E9,$E9
 
DC.B $E8,$EA,$E8,$E8,$E8,$E8
 
key12s:
 
DC.B 'E',$C9,$C8,$CA,'E',$CB
 
DC.B $C9,$C9,$CA,$C9,$C9,$C9
 
DC.B $C8,$CA,$C8,$C8,$C8,$C8
 
key16: ; u, U, micro, micro
 
DC.B DPF_MOD,key16u-key16,DPF_MOD,key16s-key16
 
DC.B 0,$B5,0,$B5
 
DC.B 0,$15,0,$15,0,$95,0,$95 ; control translation
 
key16u:
 
DC.B 'u',$FA,$F9,$FB,'u',$FC
 
DC.B $FA,$FA,$FB,$FA,$FA,$FA
 
DC.B $F9,$FB,$F9,$F9,$F9,$F9
 
key16s:
 
DC.B 'U',$DA,$D9,$DB,'U',$DC
 
DC.B $DA,$DA,$DB,$DA,$DA,$DA
 
DC.B $D9,$DB,$D9,$D9,$D9,$D9
 
key17: ; i, I, inverted !, broken |
 
DC.B DPF_MOD,key17u-key17,DPF_MOD,key17s-key17
 
DC.B 0,$A1,0,$A6
 
DC.B 0,$09,0,$09,0,$89,0,$89 ; control translation
 
key17u:
 
DC.B 'i',$ED,$EC,$EE,'i',$EF
 
DC.B $ED,$ED,$EE,$ED,$ED,$ED
 
DC.B $EC,$EE,$EC,$EC,$EC,$EC
 
key17s:
 
DC.B 'I',$CD,$CC,$CE,'I',$CF
 
DC.B $CD,$CD,$CE,$CD,$CD,$CD
 
DC.B $CC,$CE,$CC,$CC,$CC,$CC
 
key18: ; o, O, bar o, bar O
 
DC.B DPF_MOD,key18u-key18,DPF_MOD,key18s-key18
 
DC.B 0,$F8,0,$D8
 
DC.B 0,$0F,0,$0F,0,$8F,0,$8F ; control translation
 
key18u:
 
DC.B 'o',$F3,$F2,$F4,$F5,$F6
 
DC.B $F3,$F3,$F4,$F3,$F3,$F3
 
DC.B $F2,$F4,$F2,$F2,$F2,$F2
 
key18s:
 
DC.B 'O',$D3,$D2,$D4,$D5,$D6
 
DC.B $D3,$D3,$D4,$D3,$D3,$D3
 
DC.B $D2,$D4,$D2,$D2,$D2,$D2
 
key20: ; a, A, ae, AE
 
DC.B DPF_MOD,key20u-key20,DPF_MOD,key20s-key20
 
DC.B 0,$E6,0,$C6
 
DC.B 0,$01,0,$01,0,$81,0,$81 ; control translation
 
key20u:
 
DC.B 'a',$E1,$E0,$E2,$E3,$E4
 
DC.B $E1,$E1,$E2,$E1,$E1,$E1 ; most recent is '
 
DC.B $E0,$E2,$E0,$E0,$E0,$E0 ; most recent is `
 
key20s:
 
DC.B 'A',$C1,$C0,$C2,$C3,$C4
 
DC.B $C1,$C1,$C2,$C1,$C1,$C1 ; most recent is '
 
DC.B $C0,$C2,$C0,$C0,$C0,$C0 ; most recent is `
 
key36: ; n, N, SHY, overbar
 
DC.B DPF_MOD,key36u-key36,DPF_MOD,key36s-key36
 
DC.B 0,$AD,0,$AF
 
DC.B 0,$0E,0,$0E,0,$8E,0,$8E ; control translation
 
key36u:
 
DC.B 'n','n','n','n',$F1,'n'
 
DC.B 'n','n','n','n','n','n'
 
DC.B 'n','n','n','n','n','n'
 
key36s:
 
DC.B 'N','N','N','N',$D1,'N'
 
DC.B 'N','N','N','N','N','N'
 
DC.B 'N','N','N','N','N','N'
 
key31: ; y, Y, +/-, not
 
DC.B DPF_MOD,key31u-key31,DPF_MOD,key31s-key31
 
DC.B 0,$B1,0,$AC
 
DC.B 0,$19,0,$19,0,$99,0,$99 ; control translation
 
key31u:
 
DC.B 'y',$FD,'y','y','y',$FF
 
DC.B $FD,$FD,$FD,$FD,$FD,$FD
 
DC.B 'y','y','y','y','y','y'
 
key31s:
 
DC.B 'Y',$DD,'Y','Y','Y','Y'
 
DC.B $DD,$DD,$DD,$DD,$DD,$DD
 
DC.B 'Y','Y','Y','Y','Y','Y'
 
key40: ; space,,NBSP, and accents
 
DC.B DPF_MOD,key40d-key40,0,$A0
 
key40d:
 
DC.B ' ',$B4,'`','^','~',$A8
 
DC.B $B4,'^',$B4,$B4,$B4,$B4
 
DC.B '`','`','^','`','`','`'
 
;------ string keys
 
key42:
 
DC.B key42ue-key42us,key42us-key42
 
DC.B key42se-key42ss,key42ss-key42
 
key42us:
 
DC.B $09
 
key42ue:
 
key42ss:
 
DC.B $9B,'Z'
 
key42se:
 
key4C:
 
DC.B key4Cue-key4Cus,key4Cus-key4C
 
DC.B key4Cse-key4Css,key4Css-key4C
 
key4Cus:
 
DC.B $9B,'A'
 
key4Cue:
 
key4Css:
 
DC.B $9B,'T'
 
key4Cse:
 
key4D:
 
DC.B key4Due-key4Dus,key4Dus-key4D
 
DC.B key4Dse-key4Dss,key4Dss-key4D
 
key4Dus:
 
DC.B $9B,'B'
 
key4Due:
 
key4Dss:
 
DC.B $9B,'S'
 
key4Dse:
 
key4E:
 
DC.B key4Eue-key4Eus,key4Eus-key4E
 
DC.B key4Ese-key4Ess,key4Ess-key4E
 
key4Eus:
 
DC.B $9B,'C'
 
key4Eue:
 
key4Ess:
 
DC.B $9B,' ','@'
 
key4Ese:
 
key4F:
 
DC.B key4Fue-key4Fus,key4Fus-key4F
 
DC.B key4Fse-key4Fss,key4Fss-key4F
 
key4Fus:
 
DC.B $9B,'D'
 
key4Fue:
 
key4Fss:
 
DC.B $9B,' ','A'
 
key4Fse:
 
key50:
 
DC.B key50ue-key50us,key50us-key50
 
DC.B key50se-key50ss,key50ss-key50
 
key50us:
 
DC.B $9B,'0~'
 
key50ue:
 
key50ss:
 
DC.B $9B,'10~'
 
key50se:
 
key51:
 
DC.B key51ue-key51us,key51us-key51
 
DC.B key51se-key51ss,key51ss-key51
 
key51us:
 
DC.B $9B,'1~'
 
key51ue:
 
key51ss:
 
DC.B $9B,'11~'
 
key51se:
 
key52:
 
DC.B key52ue-key52us,key52us-key52
 
DC.B key52se-key52ss,key52ss-key52
 
key52us:
 
DC.B $9B,'2~'
 
key52ue:
 
key52ss:
 
DC.B $9B,'12~'
 
key52se:
 
key53:
 
DC.B key53ue-key53us,key53us-key53
 
DC.B key53se-key53ss,key53ss-key53
 
key53us:
 
DC.B $9B,'3~'
 
key53ue:
 
key53ss:
 
DC.B $9B,'13~'
 
key53se:
 
key54:
 
DC.B key54ue-key54us,key54us-key54
 
DC.B key54se-key54ss,key54ss-key54
 
key54us:
 
DC.B $9B,'4~'
 
key54ue:
 
key54ss:
 
DC.B $9B,'14~'
 
key54se:
 
key55:
 
DC.B key55ue-key55us,key55us-key55
 
DC.B key55se-key55ss,key55ss-key55
 
key55us:
 
DC.B $9B,'5~'
 
key55ue:
 
key55ss:
 
DC.B $9B,'15~'
 
key55se:
 
key56:
 
DC.B key56ue-key56us,key56us-key56
 
DC.B key56se-key56ss,key56ss-key56
 
key56us:
 
DC.B $9B,'6~'
 
key56ue:
 
key56ss:
 
DC.B $9B,'16~'
 
key56se:
 
key57:
 
DC.B key57ue-key57us,key57us-key57
 
DC.B key57se-key57ss,key57ss-key57
 
key57us:
 
DC.B $9B,'7~'
 
key57ue:
 
key57ss:
 
DC.B $9B,'17~'
 
key57se:
 
key58:
 
DC.B key58ue-key58us,key58us-key58
 
DC.B key58se-key58ss,key58ss-key58
 
key58us:
 
DC.B $9B,'8~'
 
key58ue:
 
key58ss:
 
DC.B $9B,'18~'
 
key58se:
 
key59:
 
DC.B key59ue-key59us,key59us-key59
 
DC.B key59se-key59ss,key59ss-key59
 
key59us:
 
DC.B $9B,'9~'
 
key59ue:
 
key59ss:
 
DC.B $9B,'19~'
 
key59se:
 
key5F:
 
DC.B key5Fe-key5Fs,key5Fs-key5F
 
key5Fs:
 
DC.B $9B,'?~'
 
key5Fe:
 
KMName:
 
DC.B 'd',0
 
kmEnd
 
END</pre>
 
   
 
== Function Reference ==
 
== Function Reference ==
   
The following are brief descriptions of the functions covered in this chapter. See the ''Amiga ROM Kernel Reference Manual: Includes and Autodocs'' for details on each function call.
+
The following are brief descriptions of the functions covered in this article. See the SDK for details on each function call.
   
  +
{| class="wikitable"
[h] Keymap Library Functions
 
  +
! Function
 
  +
! Description
<table>
 
  +
|-
<thead>
 
  +
| AskKeyMapDefault()
<tr class="header">
 
  +
| Ask for a pointer to the current default keymap
<th align="left">'''Function'''</th>
 
  +
|-
<th align="left">'''Description'''</th>
 
  +
| CloseKeyMapHandle()
</tr>
 
  +
| Close a keymap handle (V50)
</thead>
 
  +
|-
<tbody>
 
  +
| MapANSI()
<tr class="odd">
 
  +
| Encode an ANSI string into key codes
<td align="left">AskKeyMapDefault()</td>
 
  +
|-
<td align="left">Ask for a pointer to the current default keymap</td>
 
  +
| MapRawKey()
</tr>
 
  +
| Decode a raw key input event to an ANSI string
<tr class="even">
 
  +
|-
<td align="left">MapANSI()</td>
 
  +
| ObtainKeyMapInfo()
<td align="left">Encode an ANSI string into key codes</td>
 
  +
| Obtain information about a raw key (V51.7)
</tr>
 
  +
|-
<tr class="odd">
 
  +
| OpenKeyMapHandle()
<td align="left">MapRawKey()</td>
 
  +
| Open a keymap handle (V50)
<td align="left">Decode a raw key input event to an ANSI string</td>
 
  +
|-
</tr>
 
  +
| ReleaseKeyMapInfo()
<tr class="even">
 
  +
| Release info obtained from a keymap handle (V50)
<td align="left">SetKeyMapDefault()</td>
 
  +
|-
<td align="left">Set the current default keymap</td>
 
  +
| SetKeyMapDefault()
</tr>
 
  +
| Set the current default keymap
</tbody>
 
  +
|}
</table>
 

Latest revision as of 16:54, 18 August 2019

WIP.png This page is currently being updated to AmigaOS 4.x. Some of the information contained here may not yet be applicable in part or totally.

Keymap Library

Amiga computers are sold internationally with a variety of local keyboards which match the standards of particular countries. All Amigas have keyboards which are physically similar, and keys which output the same low-level raw key code for any particular physical key. However, in different countries, the keycaps of the keys may contain different letters or symbols. Since the physical position of a key determines the raw key code that it generates, raw key codes are not internationally compatible. For instance, on the German keyboard, the Y and Z keys are swapped when compared to the USA keyboard. The second key on the fifth row will generate the same raw key code on all Amiga keyboards, but should be decoded as a Z on a US keyboard and as a Y on a German keyboard.

The Amiga uses the ECMA-94 Latin 1 International 8-bit character set, and can map raw key codes to any desired ANSI character value, string, or escape sequence. This allows national keyboards to be supported by using keymaps. A keymap is a file which describes what character or string is tied to what key code. Generally, the user's startup-sequence will set a system default keymap that is correct for the user's keyboard. The console.device translates the raw key codes into the correct characters based on the installed keymap. This includes the translation of special deadkey sequential key combinations to produce accented international characters.

Programs which perform keyboard input using the console.device, CON:, RAW:, or Intuition VANILLAKEY, will receive custom keymaps, or may need to perform their own translation between raw key codes and ANSI characters. In this article, the term ANSI refers to the standard 8-bit character definitions which include printable ASCII characters, special characters, and escape sequences.

Keymap.library offers some of the keymap commands of the console.device, enabling applications to inquire after the default keymap and map key codes to ANSI characters. It also provides the ability to map ANSI characters back into raw codes. Unlike the console.device however, it can not be used to select a keymap for only one application, i.e., one console window.

As a prelude to the following material, note that the Amiga keyboard transmits raw key information to the computer in the form of a key position and a transition. Raw key positions range from hexadecimal 00 to 7F. When a key is released, its raw key position, plus hexadecimal 80, is transmitted.

Keymap Functions

Keymap Library Functions
AskKeyMapDefault() Ask for a pointer to the current default keymap
MapANSI() Encode an ANSI string into key codes
MapRawKey() Decode a raw key input event to an ANSI string
SetKeyMapDefault() Set the current default keymap
Console Device Keymap Commands
CD_ASKKEYMAP Ask for the current console's keymap
CD_SETKEYMAP Set the current console's keymap
CD_ASKDEFAULTKEYMAP* Set the current default keymap
CD_SETDEFAULTKEYMAP** Ask for a pointer to the current default keymap
* Obsolete - use AskKeyMapDefault()
** Obsolete - use SetKeyMapDefault()

All of these commands deal with a set of pointers to key translation arrays, known as the KeyMap structure. The KeyMap structure is defined in <devices/keymap.h> and is shown below.

struct KeyMap
    {
    UBYTE *km_LoKeyMapTypes;
    ULONG *km_LoKeyMap;
    UBYTE *km_LoCapsable;
    UBYTE *km_LoRepeatable;
    UBYTE *km_HiKeyMapTypes;
    ULONG *km_HiKeyMap;
    UBYTE *km_HiCapsable;
    UBYTE *km_HiRepeatable;
    };

The KeyMap structure contains pointers to arrays which define the ANSI character or string that should be produced when a key or a combination of keys are pressed. For example, a keymap might specify that the key with raw value hex 20 should produce the ANSI character "a", and if the Shift key is being held it should produce the character "A".

Asking for the Default Keymap

The AskKeyMapDefault() returns a pointer to the current default keymap. To use the mapping functions in keymap.library it is normally not necessary to call this function. They accept NULL as equivalent to 'use default keymap' and will call this function for you. You can use this pointer for example to cache the system default in order to temporarily change the keymap your applications uses, or find the keymap in the keymap.resource list of loaded keymaps. You should never change the system wide default keymap unless the user asks you to do so; since the Amiga is a multitasking system, changing the keymap could interfere with the behaviour of other applications.

Setting the Default Keymap

The system default keymap can be set with the SetKeyMapDefault() function. This function takes a pointer to a loaded keymap. In general, this function should never be used by an application unless the application is a system Preferences editor, or an application that takes over the system. Normal applications should instead attach a console.device unit to their own Intuition window (see the Devices volume), and use the console.device command CD_SETKEYMAP to set a keymap only for their own console.

When making a keymap the system default, first check whether the keymap has been loaded previously by checking the keymap list of the keymap.resource. If it has not been loaded already, it can be loaded from DEVS:Keymaps, and added to the keymap list of keymap.resource. This will ensure that other applications which may want the keymap will not have to load a second instance. Once made the default, the keymap can never be safely removed from memory, even after if it is no longer the default, since other applications may still have and use a pointer to it.

Accessing the Keymap for the Current Console

The function AskKeyMap() shown below does not return a pointer to a table of pointers to currently assigned key mapping. Instead, it copies the current set of pointers to a user-designated area of memory. AskKeyMap() returns a TRUE or FALSE value that says whether or not the function succeeded.

The function SetKeyMap(), also shown below, copies the designated key map data structure to the console device. Thus this routine is complementary to AskKeymap() in that it can restore an original key mapping as well as establish a new one.

Ask/SetKeyMap()
These functions assume that you have already opened the console.device and that request is a valid IOStdReq structure for the newly opened console. These functions are not part of the keymap.library, nor of the console.device. These merely demonstrate CD_ASKKEYMAP and CD_SETKEYMAP which are console.device commands.
/* These functions require that you have created a port and an IO request,
 * and have opened the console device as shown in the "Console Device" section.
 */
#include <devices/keymap.h>
 
BOOL AskKeyMap(struct IOStdReq *request, struct KeyMap *keymap)
{
    request->io_Command = CD_ASKKEYMAP;
    request->io_Length = sizeof(struct KeyMap);
    request->io_Data = (APTR)keymap;  /* where to put it */
    IExec->DoIO(request);
    if(request->io_Error) return(FALSE);
    else  return(TRUE); /* if no error, it worked. */
}
 
BOOL SetKeyMap(struct IOStdReq *request, struct KeyMap *keymap)
{
    request->io_Command = CD_SETKEYMAP;
    request->io_Length = sizeof(struct KeyMap);
    request->io_Data = (APTR)keymap;      /* where to get it */
    IExec->DoIO(request);
    if(request->io_Error) return(FALSE);
    else  return(TRUE);     /* if no error, it worked. */
}

Mapping Key Codes to ANSI Strings

MapRawKey() converts raw key codes in ANSI characters based on a default or supplied keymap.

WORD MapRawKey(struct InputEvent *inputevent, STRPTR buffer, WORD bufferlength, struct Keymap *keymap);

MapRawKey() takes an IECLASS_RAWKEY inputevent, which may be chained, and converts the key codes to ANSI characters which are placed in the specified buffer. If the buffer would overflow, for example because a longer string is attached to a key, -1 will be returned. If no error occured, MapRawKey() will return the number of bytes written in the buffer. The keymap argument can be set to NULL if the default keymap is to be used for translation, or can be a pointer to a specific KeyMap structure.

The following example shows how to implement the MapRawKey() function.

/*
 * maprawkey.c - Map Intuition RAWKEY events to ANSI with MapRawKey();
 */
#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <intuition/intuition.h>
#include <devices/inputevent.h>
 
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/keymap.h>
#include <proto/intuition.h>
 
/* our function prototypes */
void openall(void);
void closeall(void);
void closeout(UBYTE *errstring, LONG rc);
 
struct Library *IntuitionBase = NULL;
struct IntuitionIFace *IIntuition = NULL;
 
struct Library *KeymapBase = NULL;
struct KeymapIFace *IKeymap = NULL;
 
struct Window *window = NULL;
 
int main(int argc, char **argv)
{
    struct IntuiMessage *imsg;
    APTR                *eventptr;
    struct InputEvent   inputevent = {0};
    LONG                windowsignal;
    UBYTE               buffer[8];
    COUNT               i;
    BOOL                Done = FALSE;
 
    openall();
 
    window = IIntuition->OpenWindowTags(NULL,
                            WA_Width,  500,
                            WA_Height, 60,
                            WA_Title, "MapRawKey - Press Keys",
                            WA_Flags, WFLG_CLOSEGADGET | WFLG_ACTIVATE,
                            WA_IDCMP, IDCMP_RAWKEY | IDCMP_CLOSEWINDOW,
                            TAG_END);
    if(window == NULL)   closeout("Can't open window",RETURN_FAIL);
 
    windowsignal = 1L << window->UserPort->mp_SigBit;
 
    /* Initialize InputEvent structure (already cleared to 0) */
    inputevent.ie_Class = IECLASS_RAWKEY;
 
    while(!Done)
       {
       IExec->Wait(windowsignal);
 
       while (imsg = (struct IntuiMessage *)IExec->GetMsg(window->UserPort))
           {
           switch(imsg->Class)
               {
                case IDCMP_CLOSEWINDOW:
                    Done = TRUE;
                    break;
 
                case IDCMP_RAWKEY:
                    inputevent.ie_Code = imsg->Code;
                    inputevent.ie_Qualifier = imsg->Qualifier;
 
                    IDOS->Printf("RAWKEY: Code=$%04lx  Qualifier=$%04lx\n",
                             imsg->Code, imsg->Qualifier); 
 
                    /* Make sure deadkeys and qualifiers are taken
                     * into account.
                     */
                    eventptr = imsg->IAddress;
                    inputevent.ie_EventAddress = *eventptr;
 
                    /* Map RAWKEY to ANSI */
                    i = IKeymap->MapRawKey(&inputevent, buffer, 8, NULL);
 
                    if (i == -1) IDOS->Write(IDOS->Output(),"*Overflow*",10);
                    else if (i)
                        {
                        /* This key or key combination mapped to something */
                        IDOS->Printf("MAPS TO: ");
                        IDOS->Write(IDOS->Output(),buffer,i);
                        IDOS->Printf("\en");
                        }
                    break;
                }
            IExec->ReplyMsg((struct Message *)imsg);
            }
        }
    IIntuition->CloseWindow(window);
    closeall();
    return RETURN_OK;
}
 
void openall(void)
{
    KeymapBase = IExec->OpenLibrary("keymap.library", 50);
    IKeymap = (struct KeymapIFace*)IExec->GetInterface(KeymapBase, "main", 1, NULL);
    if (IKeymap == NULL)    closeout("Can't get IKeymap",RETURN_FAIL);
 
    IntuitionBase = IExec->OpenLibrary("intuition.library", 50);
    IIntuition = (struct IntuitionIFace*)IExec->GetInterface(IntuitionBase, "main", 1, NULL);
    if (IIntuition == NULL) closeout("Can't get IIntuition",RETURN_FAIL);
}
 
void closeall(void)
{
    IExec->DropInterface((struct Interface*)IIntuition);
    IExec->CloseLibrary(IntuitionBase);
 
    IExec->DropInterface((struct Interface*)IKeymap);
    IExec->CloseLibrary(KeymapBase);
}
 
void closeout(UBYTE *errstring, LONG rc)
{
    if (*errstring)  IDOS->Printf("%s\en",errstring);
    closeall();
    exit(rc);
}

Mapping ANSI Strings to Key Codes

The MapANSI() function translates ANSI strings into raw key codes, complete with qualifiers and (double) dead keys, based on a default or supplied keymap.

LONG MapANSI(UBYTE *string, LONG stringlength, UBYTE *buffer, LONG bufferlength, struct KeyMap *keymap);

The string argument is a pointer to an ANSI string, of length stringlength. The buffer argument is a pointer to the memory block where the translated key codes will be placed. The length of this buffer must be indicated in WORDs since each translation will occupy one byte for the key code and one for the qualifier. Since one ANSI character can be translated to two dead keys and one key, the buffer must be at least 3 WORDs per character in the string to be translated. The keymap argument can be set to NULL if the default keymap is to be used, or can be a pointer to a KeyMap structure. Upon return, the function will indicate how many key code/qualifier combinations are placed in the buffer or a negative number in case an error occurred. If zero is returned, the character could not be translated.

The following example shows the usage of MapANSI() and demonstrates how returned key codes can be processed.

/*
mapansi.c - converts a string to input events using MapANSI() function.
 
            This example will also take the created input events
            and add them to the input stream using the simple
            commodities.library function AddIEvents().  Alternately,
            you could open the input.device and use the input device
            command IND_WRITEEVENT to add events to the input stream.
*/
 
#include       <exec/types.h>
#include       <exec/memory.h>
#include       <exec/io.h>
#include       <dos/dos.h>
#include       <devices/input.h>
#include       <devices/inputevent.h>
 
#include       <proto/exec.h>
#include       <proto/dos.h>
#include       <proto/keymap.h>
#include       <proto/commodities.h>
 
struct Library *KeymapBase = NULL;       /* MapAnsi() function    */
struct KeymapIFace *IKeymap = NULL;
 
struct Library *CxBase = NULL;           /* AddIEvents() function */
struct CommoditiesIFace *ICommodities = NULL;
 
struct InputEvent       *InputEvent = NULL;       /* we'll allocate this */
 
/* prototypes for our program functions */
 
void openall(void);
void closeall(void);
void closeout(UBYTE *errstring, LONG rc);
 
 
int main(int argc, char **argv)
{
    UBYTE               *string;
    UBYTE               *tmp1;
    UBYTE               *tmp2;
    UBYTE               iebuffer[6];            /* Space for two dead keys */
                                                /* + 1 key + qualifiers    */
    COUNT               i;
    LONG                rc = 0;
 
 
    openall();
 
    string = ";String converted to input events and sent to input device\n";
 
    InputEvent->ie_Class = IECLASS_RAWKEY;
 
    /* Turn each character into an InputEvent */
    tmp1 = string;
 
    while (*tmp1)
    {
        /* Convert one character, use default key map */
        i = IKeymap->MapANSI(tmp1, 1, iebuffer, 3, NULL);
 
        /* Make sure we start without deadkeys */
        InputEvent->ie_Prev1DownCode = InputEvent->ie_Prev1DownQual = 0;
        InputEvent->ie_Prev2DownCode = InputEvent->ie_Prev2DownQual = 0;
 
        tmp2 = iebuffer;
 
        switch (i)
        {
          case -2:
            IDOS->Printf("Internal error\n", NULL);
            rc = RETURN_FAIL;
            break;
 
          case -1:
            IDOS->Printf("Overflow\n", NULL);
            rc = RETURN_FAIL;
            break;
 
          case 0:
            IDOS->Printf("Can't generate code\n", NULL);
            break;
 
          case 3:
            InputEvent->ie_Prev2DownCode = *tmp2++;
            InputEvent->ie_Prev2DownQual = *tmp2++;
            /* FALL THROUGH */
 
          case 2:
            InputEvent->ie_Prev1DownCode = *tmp2++;
            InputEvent->ie_Prev1DownQual = *tmp2++;
            /* FALL THROUGH */
 
          case 1:
            InputEvent->ie_Code = *tmp2++;
            InputEvent->ie_Qualifier = *tmp2;
            break;
        }
 
        if (rc == RETURN_OK)
        {
            /* Send the key down event */
            ICommodities->AddIEvents(InputEvent);
 
            /* Create a key up event */
            InputEvent->ie_Code |= IECODE_UP_PREFIX;
 
            /* Send the key up event */
            ICommodities->AddIEvents(InputEvent);
         }
 
        if (rc != RETURN_OK)
            break;
 
        tmp1++;
    }
 
    closeall();
    return rc;
}
 
 
void openall(void)
{
    KeymapBase = IExec->OpenLibrary("keymap.library", 50);
    IKeymap = (struct KeymapIFace*)IExec->GetInterface(KeymapBase, "main", 1, NULL);
    if (IKeymap == NULL)  closeout("Can't get IKeymap", RETURN_FAIL);
 
    CxBase = IExec->OpenLibrary("commodities.library", 50);
    ICommodities = (struct CommoditiesIFace*)IExec->GetInterface(CxBase, "main", 1, NULL);
    if (ICommodities == NULL)  closeout("Can't get ICommodities", RETURN_FAIL);
 
    InputEvent = IExec->AllocMem(sizeof(struct InputEvent), MEMF_CLEAR);
    if (InputEvent == NULL)  closeout("Can't allocate input event",RETURN_FAIL);
}
 
 
void closeall()
{
    if (InputEvent)    IExec->FreeMem(InputEvent, sizeof(struct InputEvent));
 
    IExec->DropInterface((struct Interface*)ICommodities);
    IExec->CloseLibrary(CxBase);
 
    IExec->DropInterface((struct Interface*)IKeymap);
    IExec->CloseLibrary(KeymapBase);
}
 
 
void closeout(UBYTE *errstring, LONG rc)
{
    if(*errstring)     IDOS->Printf("%s\n",errstring);
    closeall();
    exit(rc);
}

Details of the Keymap Structure

A KeyMap structure contains pointers to arrays which determine the translation from raw key codes to ANSI characters.

struct KeyMap
    {
    UBYTE *km_LoKeyMapTypes;
    ULONG *km_LoKeyMap;
    UBYTE *km_LoCapsable;
    UBYTE *km_LoRepeatable;
    UBYTE *km_HiKeyMapTypes;
    ULONG *km_HiKeyMap;
    UBYTE *km_HiCapsable;
    UBYTE *km_HiRepeatable;
    };

LoKeyMap and HighKeyMap

The low key map provides translation of the key values from hex 00-3F; the high key map provides translation of key values from hex 40-7F. Key values from hex 68-7F are not used by the existing keyboards, but this may change in the future. A raw key value (hex 00-7F) plus hex 80 is the release of that key. If you need to check for raw key releases do it like this:

if (keyvalue & 0x80)     {  /* do key up processing   */  }
else                     {  /* do key down processing */  }

Raw output from the keyboard for the low key map does not include the space bar, Tab, Alt, Ctrl, arrow keys, and several other keys.

High Key Map Hex Values
Key Number Keycap Legend for Function
40 Space
41 Backspace
42 Tab
43 Enter
44 Return
45 Escape
46 Delete
4A Numeric Pad character
4C Cursor Up
4D Cursor Down
4E Cursor Right
4F Cursor Left
50-59 Function keys F1-F10
5A-5E Numeric Pad characters
5F Help
60 Left Shift
61 Right Shift
62 Caps Lock
63 Control
64 Left Alt
65 Right Alt
66 Left Amiga
67 Right Amiga

The keymap table for the low and high keymaps consists of 4-byte entries, one per hex key code. These entries are interpreted in one of two possible ways:

  • As four separate bytes, specifying how the key is to be interpreted when pressed alone, with one qualifier, with another qualifier, or with both qualifiers (where a qualifier is one of three possible keys: Ctrl, Alt, or Shift).
  • As a longword containing the address of a string descriptor, where a string of characters is to be output when this key is pressed. If a string is to be output, any combination of qualifiers can affect the string that may be transmitted.
  • As a longword containing the address of a dead-key descriptor, where additional data describe the character to be output when this key is pressed alone or with another dead key.
The keymap tables must be word aligned
The keymap tables must begin aligned on a word boundary. Each entry is four bytes long, thereby maintaining word alignment throughout the table. This is necessary because some of the entries may be longword addresses and must be aligned properly for the 68000.

LoKeyMapTypes and HiKeyMapTypes

The tables named km_LoKeyMapTypes and km_HiKeyMapTypes each contain one byte per raw key code. Each byte defines the type of entry that is found in the keymap table for that raw key code.

Possible key types are:

  • Any of the qualifier groupings noted above
  • KCF_STRING + any combination of KCF_SHIFT, KCF_ALT, KCF_CONTROL (or KC_NOQUAL) if the result of pressing the key is to be a stream of bytes (and key-with-one-or-more-qualifiers is to be one or more alternate streams of bytes). Any key can be made to output up to eight unique byte streams if KCF_STRING is set in its keytype. The only limitation is that the total length of all of the strings assigned to a key must be within the "jump range" of a single byte increment. See the "String Output Keys" section below for more information.
  • KCF_DEAD + any combination of KCF_SHIFT, KCF_ALT, KCF_CONTROL (or KC_NOQUAL) if the key is a dead-class key and can thus modify or be modified by another dead-class key. See the "Dead-Class Keys" section below for more information.

The low keytype table covers the raw key codes from hex 00-3F and contains one byte per key code. Therefore this table contains 64 (decimal) bytes. The high keytype table covers the raw key codes from hex 40-7F and contains 64 (decimal) bytes.

More About Qualifiers

For keys such as the Return key or Esc key, the qualifiers specified in the keytypes table (up to two) are the qualifiers used to establish the response to the key. This is done as follows. In the keytypes table, the values listed for the key types are those listed for the qualifiers in <devices/keymap.h> and <devices/keymap>. Specifically, these qualifier equates are:

KC_NOQUAL 0x00
KCF_SHIFT 0x01
KCF_ALT 0x02
KCF_CONTROL 0x04
KC_VANILLA 0x07
KCF_DOWNUP 0x08
KCF_STRING 0x40

As shown above, the qualifiers for the various types of keys occupy specific bit positions in the key types control byte. As you may have noticed, there are three possible qualifiers, but only a 4-byte space in the table for each key. This does not allow space to describe what the computer should output for all possible combinations of qualifiers. A solution exists, however, for "vanilla" keys, such as the alphabetic keys. Here is how that works.

Keys of type KC_VANILLA use the 4 bytes to represent the data output for the key alone, Shifted key, Alt'ed key, and Shifted-and-Alt'ed key. Then for the Ctrl-key-plus-vanilla-key, use the code for the key alone with bits 6 and 5 set to 0.

The Vanilla Qualifier Does Not Mean Plain
The qualifier KC_VANILLA is equivalent to KCF_SHIFT+KCF_ALT+KCF_CONTROL.

This table shows how to interpret the keymap for various combinations of the qualifier bits:

Keymap Qualifier Bits
If Keytype is: Then data at this position in the keytable is output when the key is pressed along with:
KC_NOQUAL - - - alone
KCF_SHIFT - - Shift alone
KCF_ALT - - Alt alone
KCF_CONTROL - - Ctrl alone
KCF_ALT+KCF_SHIFT Shift+Alt Alt Shift alone
KCF_CONTROL+KCF_ALT Ctrl+Alt Ctrl Alt alone
KCF_CONTROL+KCF_SHIFT Ctrl+Shift Ctrl Shift alone
KC_VANILLA Shift+Alt Alt Shift alone*
*Special case--Ctrl key, when pressed with one of the alphabet keys and certain others, is to output key-alone value with the bits 6 and 5 set to zero.

String Output Keys

When a key is to output a string, the keymap table contains the address of a string descriptor in place of a 4-byte mapping of a key as shown above. Here is a partial table for a new high keymap table that contains only three entries thus far. The first two are for the space bar and the backspace key; the third is for the tab key, which is to output a string that says "[TAB]". An alternate string, "[SHIFTED-TAB]", is also to be output when a shifted TAB key is pressed.

newHiMapTypes:
    DC.B        KCF_ALT,KC_NOQUAL,      ;key 41
    DC.B        KCF_STRING+KCF_SHIFT,   ;key 42
        ...     ;(more)
newHiMap:
    DC.B        0,0,$A0,$20     ;key 40: space bar, and Alt-space bar
    DC.B        0,0,0,$08       ;key 41: Back Space key only
    DC.L        newkey42        ;key 42: new definition for string to output for Tab key
        ...     ;(more)
newkey42:
    DC.B        new42ue - new42us       ;length of the unshifted string
    DC.B        new42us - newkey42      ;number of bytes from start of
                                        ;string descriptor to start of this string
    DC.B        new42se - new42ss       ;length of the shifted string
    DC.B        new42ss - newkey42      ;number of bytes from start of
                                        ;string descriptor to start of this string
new42us:  DC.B        '[TAB]'
new42ue:
new42ss:  DC.B        '[SHIFTED-TAB]'
new42se:

The new high map table points to the string descriptor at address newkey42. The new high map types table says that there is one qualifier, which means that there are two strings in the key string descriptor.

Each string in the descriptor takes two bytes in this part of the table: the first byte is the length of the string, and the second byte is the distance from the start of the descriptor to the start of the string. Therefore, a single string (KCF_STRING + KC_NOQUAL) takes 2 bytes of string descriptor. If there is one qualifier, 4 bytes of descriptor are used. If there are two qualifiers, 8 bytes of descriptor are used. If there are 3 qualifiers, 16 bytes of descriptor are used. All strings start immediately following the string descriptor in that they are accessed as single-byte offsets from the start of the descriptor itself. Therefore, the distance from the start of the descriptor to the last string in the set (the one that uses the entire set of specified qualifiers) must start within 255 bytes of the descriptor address.

Because the length of the string is contained in a single byte, the length of any single string must be 255 bytes or less while also meeting the "reach" requirement. However, the console input buffer size limits the string output from any individual key to 32 bytes maximum.

The length of a keymap containing string descriptors and strings is variable and depends on the number and size of the strings that you provide.

Capsable Bit Tables

The vectors km_LoCapsable and km_HiCapsable each point to an array of 8 bytes that contain more information about the keytable entries. Specifically, if the Caps Lock key has been pressed (the Caps Lock LED is on) and if there is a bit \fIon\fP in that position in the capsable map, then this key will be treated as though the Shift key is now currently pressed. For example, in the default key mapping, the alphabetic keys are "capsable" but the punctuation keys are not. This allows you to set the Caps Lock key, just as on a normal typewriter, and get all capital letters. However, unlike a normal typewriter, you need not go out of Caps Lock to correctly type the punctuation symbols or numeric keys.

In the byte array, the bits that control this feature are numbered from the lowest bit in the byte, and from the lowest memory byte address to the highest. For example, the bit representing capsable status for the key that transmits raw code 00 is bit 0 in byte 0; for the key that transmits raw code 08 it is bit 0 in byte 1, and so on.

There are 64 bits (8 bytes) in each of the two capsable tables.

Repeatable Bit Tables

The vectors km_LoRepeatable and km_HiRepeatable each point to an array of 8 bytes that contain additional information about the keytable entries. A bit for each key indicates whether or not the specified key should repeat at the rate set by the Input Preferences program.

The bit positions correspond to those specified in the capsable bit table. If there is a 1 in a specific position, the key can repeat. There are 64 bits (8 bytes) in each of the two repeatable tables.

Key Map Standards

Users and programs depend on certain predictable behaviors from all keyboards and keymaps. With the exception of dead-class keys (see "Dead-Class Keys" section), mapping of keys in the low key map should follow these general rules:

  • When pressed alone, keys should transmit the ASCII equivalent of the unshifted letter or lower symbol on the keycap.
  • When Shifted, keys should transmit the ASCII equivalent of the shifted letter or upper symbol printed on the keycap.
  • When Alt'ed, keys should generally transmit the same character (or act as the same deadkey) as the Alt'ed key in the usa1 keymap.
  • When pressed with CTRL alone, alphabetic keys should generally transmit their unshifted value but with bits 5 and 6 cleared. This allows keyboard typing of "control characters." For example, the C key (normally value $63) should transmit value $03 (Ctrl-C) when Ctrl and C are pressed together.

The keys in the high key map (keys with raw key values $40 and higher) are generally non-alphanumeric keys such as those used for editing (backspace, delete, cursor keys, etc.), and special Amiga keys such as the function and help keys. Keymaps should translate these keys to the same values or strings as those shown in ROM Default Key Mapping table.

In addition to their normal unshifted and shifted values, the following translations are standard for particular qualified high keymap keys:

Key Generates This Value If Used with Qualifier, Generates This Value
Space $20 $A0 with qualifier KCF_ALT
Return $0D $0A with qualifier KCF_CONTROL
Esc $1B $9B with qualifier KCF_ALT

Dead-Class Keys

All of the national keymaps, including USA, contain dead-class keys. This term refers to keys that either modify or can themselves be modified by other dead-class keys. There are two types of dead-class keys: dead and deadable. A dead key is one which can modify certain keys pressed immediately following. For example, on the German keyboard there is a dead key marked with the grave accent (`). The dead key produces no console output, but when followed by (for instance) the A key, the combination will produce the a-grave (à) character (National Character Code $E0). On the U.S. keyboard, Alt-G is the deadkey used to add the grave accent (`) to the next appropriate character typed.

A deadable key is one that can be prefixed by a dead key. The A key in the previous example is a deadable key. Thus, a dead key can only affect the output of a deadable key.

For any key that is to have a dead-class function, whether dead or deadable, the qualifier KCF_DEAD flag must be included in the entry for the key in the KeyMapTypes table. The KCF_DEAD type may also be used in conjunction with the other qualifiers. Furthermore, the key's keymap table entry must contain the longword address of the key's dead-key descriptor data area in place of the usual 4 ASCII character mapping.

Below is an excerpt from the Amiga 1000 German key map which is referred to in the following discussion.

KMLowMapType:
        DC.B    KCF_DEAD+KC_VANILLA     ; aA (Key 20)
                    ...                 ; (more...)
        DC.B    KCF_DEAD+KC_VANILLA     ; hH (Key 25)
                    ...                 ; (more...)
KMLowMap:
        DC.L    key20                   ; a, A, ae, AE
                    ...                 ; (more...)
        DC.L    key25                   ; h, H, dead ^
                    ...                 ; (more...)
;------ possible dead keys
key25:
        DC.B    0,'h',0,'H'             ; h, H
        DC.B    DPF_DEAD,3,DPF_DEAD,3   ; dead ^, dead ^
        DC.B    0,$08,0,$08,0,$88,0,$88 ; control translation
                    ...                 ; (more...)
;------ deadable keys (modified by dead keys)
key20:                  ; a, A, ae, AE
        DC.B    DPF_MOD,key20u-key20    ; deadable flag, number of
                                        ; bytes from start of key20
                                        ; descriptor to start of un-
                                        ; shifted data
        DC.B    DPF_MOD,key20s-key20    ; deadable flag, number of
                                        ; bytes from start of key20
                                        ; descriptor to start of shift-
                                        ; ed data
        DC.B    0,$E6,0,$C6             ; null flags followed by rest
        DC.B    0,$01,0,$01,0,$81,0,$81 ; of values (ALT, CTRL...)
key20u:
        DC.B    'a',$E1,$E0,$E2,$E3,$E4 ; 'a' alone and characters to
                                        ; output when key alone is
                                        ; prefixed by a dead key
        DC.B    $E1,$E1,$E2,$E1,$E1,$E1 ; most recent is '
        DC.B    $E0,$E2,$E0,$E0,$E0,$E0 ; most recent is `
key20s:
        DC.B    'A',$C1,$C0,$C2,$C3,$C4 ; SHIFTed 'a' and characters to
                                        ; output when SHIFTed key is
                                        ; prefixed by a dead key
        DC.B    $C1,$C1,$C2,$C1,$C1,$C1 ; most recent is '
        DC.B    $C0,$C2,$C0,$C0,$C0,$C0 ; most recent is `

In the example, key 25 (the H key) is a dead key and key 20 (the A key) is a deadable key. Both keys use the addresses of their descriptor data areas as entries in the LoKeyMap table. The LoKeyMapTypes table says that there are four qualifiers for both: the requisite KCF_DEAD, as well as KCF_SHIFT, KCF_ALT, and KCF_CONTROL. The number of qualifiers determine length and arrangement of the descriptor data areas for each key. The next table shows how to interpret the KeyMapTypes for various combinations of the qualifier bits. For each possible position a pair of bytes is needed. The first byte in each pair tells how to interpret the second byte (more about this below).

Dead Key Qualifier Bits
If type is: Then the pair of bytes in this position in the dead-class key descriptor data is output when the key is pressed along with:
NOQUAL alone - - - - - - -
A alone - - - - - - -
C alone C - - - - - -
S alone S - - - - - -
A+C alone A C A+C - - - -
A+S alone S A A+S - - - -
C+S alone S C C+S - - - -
S+A+C (VANILLA) alone S A S+A C C+S C+A C+S+A
The abbreviations A, C, S stand for KCF_ALT, KCF_CONTROL, and KCF_SHIFT, respectively. Also note that the ordering is reversed from that in the normal KeyMap table.

Because keys 20 and 25 each use three qualifier bits (not including KCF_DEAD), according to the table there must be 8 pairs of data, arranged as shown. Had only KCF_ALT been set, for instance, (not including KCF_DEAD), just two pairs would have been needed.

As mentioned earlier, the first byte of each data pair in the descriptor data area specifies how to interpret the second byte. There are three possible values: 0, DPF_DEAD and DPF_MOD. In the Amiga 1000 German keymap listed above, DPF_DEAD appears in the data for key 25, while DPF_MOD is used for key 20. It is the use of these flags that determines whether a dead-class key has dead or deadable function. A value of zero causes the unrestricted output of the following byte.

If the flag byte is DPF_DEAD, then that particular key combination (determined by the placement of the pair of bytes in the data table) is dead and will modify the output of the next key pressed (if deadable). How it modifies is controlled by the second byte of the pair which is used as an index into part(s) of the data area for ALL the deadable (DPF_MOD set) keys.

Before going further, an understanding of the structure of a descriptor data area wherein DPF_MOD is set for one (or more) of its members is necessary. Referring to the example, we see that DPF_MOD is set for the first and second pairs of bytes. According to its LoKeyMapTypes entry, and using table above (Dead Key Qualifier Bits) as a guide, these pairs represent the alone and SHIFTed values for the key. When DPF_MOD is set, the byte immediately following the flag must be the offset from the start of the key's descriptor data area to the start of a table of bytes describing the characters to output when this key combination is preceded by any dead keys. This is where the index mentioned above comes in. The value of the index from a prefixing dead key is used to determine which of the bytes from the deadable keys special table to output. The byte in the index+1 position is sent out. (The very first byte is the value to output if the key was not prefixed by a dead key.) Thus, if Alt-H is pressed (dead) and then Shift-A, an 'a' with a circumflex (^) accent will be output. This is because:

  • The byte pair for the ALT position of the "H" key (key 25) is DPF_DEAD,3 so the index is 3.
  • The byte pair for the SHIFT position of the "A" key (key 20) is DPF_MOD, key20s-key20, so we refer to the table-of-bytes at key20s.
  • The third+1 byte of the table-of-bytes is $C2, an 'a' character.
A Note About Table Size
The number of bytes in the table-of-bytes for all deadable keys must be equal to the highest index value of all dead keys plus 1.

Double-Dead Keys

Double-dead keys are an extension of the dead-class keys explained above. Unlike normal dead keys wherein one dead key of type DPF_DEAD can modify a second of type DPF_MOD, double-dead keys employ two consecutive keys of type DPF_DEAD to together modify a third of type DPF_MOD.

For example, the key on the German keyboard labeled with single quotes ('') is a double-dead key. When this key is pressed alone and then pressed again shifted, there is no output. But when followed by an appropriate third key, for example the A key, the three keypresses combine to produce an 'a' with a circumflex (^) accent (character code $E2). Thus the double-dead pair qualify the output of the A key.

The system always keeps the last two down key codes for possible further translation. If they are both of type DPF_DEAD and the key immediately following is DPF_MOD then the two are used to form an index into the (third) key's translation table as follows:

In addition to the index found after the DPF_DEAD qualifier in a normal dead key, a second factor is included in the high nibble of double-dead keys (it is shifted into place with DP_2DFACSHIFT). Its value equals the total number of dead key types + 1 in the keymap. This second index also serves as an identifying flag to the system that two dead keys can be significant.

When a key of type DPF_MOD is pressed, the system checks the two key codes which preceded the current one. If they were both DPF_DEAD then the most recent of the two is checked for the double-dead index/flag. If it is found then a new index is formed by multiplying the value in lower nibble with that in the upper. Then, the lower nibble of the least recent DPF_DEAD key is added in to form the final offset.

Finally, this last value is used as an index into the translation table of the current, DPF_MOD, key.

The translation table of all deadable (DPF_MOD) keys has [number of dead key types + 1] * [number of double dead key types + 1] entries, arranged in [number of double dead key types + 1] rows of [number of dead key types + 1] entries. This is because as indices are assigned for dead keys in the keymap, those that are double dead keys are assigned the lower numbers.

Following is a code fragment from the German (d) keymap source:

key0C:
        DC.B    DPF_DEAD,1+(6<<DP_2DFACSHIFT)   ; dead '
        DC.B    DPF_DEAD,2+(6<<DP_2DFACSHIFT)   ; dead `
        DC.B    0,'=',0,'+'                     ; =, +
key20:                  ; a, A, ae, AE
        DC.B    DPF_MOD,key20u-key20,DPF_MOD,key20s-key20
        DC.B    0,$E6,0,$C6
        DC.B    0,$01,0,$01,0,$81,0,$81 ; control translation
key20u:
        DC.B    'a',$E1,$E0,$E2,$E3,$E4
        DC.B    $E1,$E1,$E2,$E1,$E1,$E1 ; most recent is '
        DC.B    $E0,$E2,$E0,$E0,$E0,$E0 ; most recent is `
key20s:
        DC.B    'A',$C1,$C0,$C2,$C3,$C4
        DC.B    $C1,$C1,$C2,$C1,$C1,$C1 ; most recent is '
        DC.B    $C0,$C2,$C0,$C0,$C0,$C0 ; most recent is `

Raw key0C, the German single quotes ('') key, is a double dead key. Pressing this key alone, then again while the shift key is down will produce no output but will form a double-dead qualifier. The output of key20 (A), a deadable key, will consequently be modified, producing an "a" with a circumflex (^) accent. The mechanics are as follows:

  • When key0C is pressed alone the DPF_DEAD of the first byte pair in the key's table indicates that the key as dead. The second byte is then held by the system.
  • Next, when key0C is pressed again, this time with the Shift key down, the DPF_DEAD of the second byte pair (recall that the second pair is used because of the SHIFT qualifier) again indicates the key is a dead key. The second byte of this pair is also held by the system.
  • Finally, when the A key is pressed the system recalls the latter of the two bytes it has saved. The upper nibble, $6, is multiplied by

the lower nibble, $2. The result, $0C, is then added to the lower nibble of the earlier of the two saved bytes, $1. This new value, $0D, is used as an index into the (unshifted) translation table of key20. The character at position $0D is character $E2, an 'a' with a circumflex (^) accent.

Note About Double Dead Keys
If only one double-dead key is pressed before a deadable key then the output is the same as if the double-dead were a normal dead key. If shifted key0C is pressed on the German keyboard and then immediately followed by key20, the output produced is character $E0 'à'. As before, the upper nibble is multiplied with the lower, resulting in $0C. But because there was no second dead-key, this product is used as the final index.

Keyboard Layout

The keys with key codes $2B and $30 in the following keyboard diagrams are keys which are present on some national Amiga keyboards.

Amiga 1000 Keyboard Showing Key Codes in Hex

Amiga 500/2000 Keyboard Showing Key Codes in Hex

The default values given above correspond to the values the console device will return when these keys are pressed with the keycaps as shipped with the standard American keyboard.

ROM Default (USA0) and USA1 Console Key Mapping
Raw Key Number Keycap Legend Unshifted Default Value Shifted Default Value
00 `~ ` (Accent grave) ~ (tilde)
01 1 ! 1 !
02 2 @ 2 @
03 3 # 3 #
04 4 $ 4 $
05 5 % 5 %
06 6 ^ 6 ^
07 7 & 7 &
08 8 * 8
09 9 ( 9 (
0A 0 ) 0 )
0B - _ - (Hyphen) _ (Underscore)
0C = + = +
0D | |
0E (undefined)
0F 0 0 0 (Numeric pad)
10 Q q Q
11 W w W
12 E e E
13 R r R
14 T t T
15 Y y Y
16 U u U
17 I i I
18 O o O
19 P p P
1A [ { [ {
1B ] } ] }
1C (undefined)
1D 1 1 1 (Numeric pad)
1E 2 2 2 (Numeric pad)
1F 3 3 3 (Numeric pad)
20 A a A
21 S s S
22 D d D
23 F f F
24 G g G
25 H h H
26 J j J
27 K k K
28 L l L
29 ; : ; :
2A ' " ' (single quote) "
2B (not on most U.S. keyboards)
2C (undefined)
2D 4 4 4 (Numeric pad)
2E 5 5 5 (Numeric pad)
2F 6 6 6 (Numeric pad)
30 (not on most U.S. keyboards)
31 Z z Z
32 X x X
33 C c C
34 V v V
35 B b B
36 N n N
37 M m M
38 , < , (comma) <
39 . > . (period) >
3A / ? / ?
3B (undefined)
3C . . . (Numeric pad)
3D 7 7 7 (Numeric pad)
3E 8 8 8 (Numeric pad)
3F 9 9 9 (Numeric pad)
40 Space bar 0x20 0x20
41 Back Space 0x08 0x08
42 Tab 0x09 0x09
43 Enter 0x0D 0x0D
44 Return 0x0D 0x0D (Numeric pad)
45 Esc 0x1B 0x1B
46 Del 0x7F 0x7F
47 (undefined)
48 (undefined)
49 (undefined)
4A - - - (Numeric Pad)
4B (undefined)
4C Up arrow <CSI>A <CSI>T
4D Down arrow <CSI>B <CSI>S
4E Forward arrow <CSI>C <CSI> A (note blank space after <CSI>)
4F Backward arrow <CSI>D <CSI> @ (note blank space after <CSI>)
50 F1 <CSI>0~ <CSI>10~
51 F2 <CSI>1~ <CSI>11~
52 F3 <CSI>2~ <CSI>12~
53 F4 <CSI>3~ <CSI>13~
54 F5 <CSI>4~ <CSI>14~
55 F6 <CSI>5~ <CSI>15~
56 F7 <CSI>6~ <CSI>16~
57 F8 <CSI>7~ <CSI>17~
58 F9 <CSI>8~ <CSI>18~
59 F10 <CSI>9~ <CSI>19~
5A ( ( ( (usa1 Numeric pad)
5B ) ) ) (usa1 Numeric pad)
5C / / / (usa1 Numeric pad)
5D * * * (usa1 Numeric pad)
5E + + + (usa1 Numeric pad)
5F Help <CSI>?~ <CSI>?~
Raw Key Number Function or Keycap Legend
60 Shift (left of space bar)
61 Shift (right of space bar)
62 Caps Lock
63 Ctrl
64 (Left) Alt
65 (Right) Alt
66 Amiga (left of space bar)
67 Amiga (right of space bar)
68 Left mouse button (not converted)
69 Right mouse button (not converted)
6A Middle mouse button (not converted)
6B (undefined)
6C (undefined)
6D (undefined)
6E (undefined)
6F (undefined)
70-7F (undefined)
80-F8 Up transition (release or unpress key of one of the above keys) (80 for 00, F8 for 7F)
F9 Last key code was bad (was sent in order to resynchronize)
FA Keyboard buffer overflow
FB (undefined, reserved for keyboard processor catastrophe)
FC Keyboard selftest failed
FD Power-up key stream start. Keys pressed or stuck at power-up will be sent between FD and FE.
FE Power-up key stream end
FF (undefined, reserved)
FF Mouse event, movement only, no button change (not converted)

Notes about the preceding table:

  1. "<CSI>" is the Control Sequence Introducer, value hex 9B.
  2. (undefined)" indicates that the current keyboard design should not generate this number. If you are using SetKeyMap() to change the key map, the entries for these numbers must still be included.
  3. "(not converted)" refers to mouse button events. You must use the sequence "<CSI>2{" to inform the console driver that you wish to receive mouse events; otherwise these will not be transmitted.
  4. "(RESERVED)" indicates that these key codes have been reserved for national keyboards. The $2B code key will be between the double-quote (") and Return keys. The $30 code key will be between the Shift and Z keys.
ECMA-94 Latin 1 International 8-Bit Character Set

Raw Key Table

The following table defines all of the Amiga raw key codes and what they mean.

Note
All values are in hexadecimal
Raw Key USB Page USB Code PS2 Set 1 Code PS2 Set 2 Code Name Classic Amiga Key
0000 0007 0035 0029 000E `~
0001 0007 001E 0002 0016 1!
0002 0007 001F 0003 001E 2@
0003 0007 0020 0004 0026 3#
0004 0007 0021 0005 0025 4$
0005 0007 0022 0006 002E 5%
0006 0007 0023 0007 0036 6^
0007 0007 0024 0008 003D 7&
0008 0007 0025 0009 003E 8*
0009 0007 0026 000A 0046 9(
000A 0007 0027 000B 0045 0)
000B 0007 002D 000C 004E -_
000C 0007 002E 000D 0055 =+
000D 0007 0031 \| near Backspace
000E 0007 0089 007D 006A Intl 3 Yen
000F 0007 0062 0052 0070 NP 0
0010 0007 0014 0010 0015 qQ
0011 0007 001A 0011 001D wW
0012 0007 0008 0012 0024 eE
0013 0007 0015 0013 002D rR
0014 0007 0017 0014 002C tT
0015 0007 001C 0015 0035 yY
0016 0007 0018 0016 003C uU
0017 0007 000C 0017 0043 iI
0018 0007 0012 0018 0044 oO
0019 0007 0013 0019 004D pP
001A 0007 002F 001A 0054 [{
001B 0007 0030 001B 005B ]}
001C undefined
001D 0007 0059 004F 0069 NP 1
001E 0007 005A 0050 0072 NP 2
001F 0007 005B 0051 007A NP 3
0020 0007 0004 001E 001C aA
0021 0007 0016 001F 001B sS
0022 0007 0007 0020 0023 dD
0023 0007 0009 0021 002B fF
0024 0007 000A 0022 0034 gG
0025 0007 000B 0023 0033 hH
0026 0007 000D 0024 003B jJ
0027 0007 000E 0025 0042 kK
0028 0007 000F 0026 004B lL
0029 0007 0033 0027 004C ;:
002A 0007 0034 0028 0052 '"
002B 0007 0032 002B 005D Intl 1 near Return
002C undefined
002D 0007 005C 004B 006B NP 4
002E 0007 005D 004C 0073 NP 5
002F 0007 005E 004D 0074 NP 6
0030 0007 0064 0056 0061 Intl 2 near LShift
0031 0007 001D 002C 001A zZ
0032 0007 001B 002D 0022 xX
0033 0007 0006 002E 0021 cC
0034 0007 0019 002F 002A vV
0035 0007 0005 0030 0032 bB
0036 0007 0011 0031 0031 nN
0037 0007 0010 0032 003A mM
0038 0007 0036 0033 0041 ,<
0039 0007 0037 0034 0049 .>
003A 0007 0038 0035 004A /?
003B 0007 0087 0073 0051 /? Brazil (near RShift) and International 1 (Ro)
003C 0007 0063 0053 0071 NP .
003D 0007 005F 0047 006C NP 7
003E 0007 0060 0048 0075 NP 8
003F 0007 0061 0049 007D NP 9
0040 0007 002C 0039 0029 SPACE Space
0041 0007 002A 000E 0066 BACKSPACE Backspace
0042 0007 002B 000F 000D TAB Tab
0043 0007 0058 00E01C 00E05A ENTER NP Enter
0044 0007 0028 001C 005A RETURN Return
0045 0007 0029 0001 0076 ESC Escape
0046 0007 004C 00E053 00E071 DEL Delete
0047 0007 0049 00E052 00E070 INSERT Insert
0048 0007 004B 00E049 00E07D PAGE_UP PageUp
0049 0007 004E 00E051 00E07A PAGE_DOWN PageDown
004A 0007 0056 004A 007B NP -
004B 0007 0044 0057 0078 F11 F11
004C 0007 0052 00E048 00E075 CURSOR_UP CrsrUp
004D 0007 0051 00E050 00E072 CURSOR_DOWN CrsrDown
004E 0007 004F 00E04D 00E074 CURSOR_RIGHT CrsrRight
004F 0007 0050 00E04B 00E06B CURSOR_LEFT CrsrLeft
0050 0007 003A 003B 0005 F1 F1
0051 0007 003B 003C 0006 F2 F2
0052 0007 003C 003D 0004 F3 F3
0053 0007 003D 003E 000C F4 F4
0054 0007 003E 003F 0003 F5 F5
0055 0007 003F 0040 000B F6 F6
0056 0007 0040 0041 0083 F7 F7
0057 0007 0041 0042 000A F8 F8
0058 0007 0042 0043 0001 F9 F9
0059 0007 0043 0044 0009 F10 F10
005A NP (
005B NP )
005C 0007 0054 00E035 00E04A NP /
005D 0007 0055 0037 007C NP *
005E 0007 0057 004E 0079 NP +
005F 0007 0075 0046 007E HELP Help (maps to ScrollLock on PS/2)
0060 0007 00E1 002A 0012 LSHIFT LShift
0061 0007 00E5 0036 0059 RSHIFT RShift
0062 0007 0039 003A 0058 CAPSLOCK CapsLock
0063 0007 00E0 001D 0014 CONTROL LControl
0064 0007 00E2 0038 0011 LALT LAlt
0065 0007 00E6 00E038 00E011 RALT RAlt
0066 0007 00E3 00E05B 00E01F LCOMMAND LAmiga, LWin, LApple, LMeta
0067 0007 00E7 00E05C 00E027 RCOMMAND RAmiga, RWin, RApple, RMeta
0068 LBUTTON LMouse reserved
0069 RBUTTON RMouse reserved
006A MBUTTON MMouse reserved
006B 0007 0065 00E05D 00E02F MENU Menu, Windows, Compose (mappable to RAmiga in Firmware)
006C 0007 0085 007E 006D Brazil NP . (named "Keypad ," in USB specs)
006D 0007 0046 00E037 00E07C PRINTSCREEN PrintScreen/SysReq (mappable to Help in Firmware)
006E 0007 0048 00E046 00E07E BREAK Break, Ctrl-Pause on PS/2
006F 0007 0045 0058 0007 F12 F12
0070 0007 004A 00E047 00E06C HOME Home
0071 0007 004D 00E04F 00E069 END End
0072 000C 00B7 00E024 00E03B AUD_STOP Stop, CD32 Blue Stop, CDTV Stop, Port 0 Blue
0073 000C 00CD 00E022 E034 AUD_PLAY_PAUSE Play/Pause, CD32 Grey Play/Pause, CDTV Play/Pause, Port 0 Play
0074 000C 00B6 00E010 E015 AUD_PREV_TRACK Prev Track, CD32 Charcoal Reverse, CDTV << REW, Port 0 Reverse
0075 000C 00B5 00E019 E04D AUD_NEXT_TRACK Next Track, CD32 Charcoal Forward, CDTV >> FF, Port 0 Forward
0076 000C 00B9 AUD_SHUFFLE Random Play, CD32 Green Shuffle, Port 0 Green
0077 000C 00BC AUD_REPEAT Repeat, CD32 Yellow Repeat, Port 0 Yellow
0078 Port 0 Red
0079 Port 0 Joystick Up
007A Port 0 Joystick Down
007B Port 0 Joystick Right
007C Port 0 Joystick Left
007D undefined
007E undefined
007F undefined
0080 - 00F8 Up transition (release or unpress key) (0080 for 0000, 00F8 for 0078)
00F9 Last key code was bad (was sent in order to resynchronize)
00FA Keyboard buffer overflow
00FB (undefined, reserved for keyboard processor catastrophe)
00FC Keyboard selftest failed
00FD Power-up key stream start. Keys pressed or stuck at power-up will be sent between 00FD and 00FE.
00FE Power-up key stream end
00FF No key code defined
0100 0007 0088 0070 0013 Intl 2 Hiragana/Katakana
0101 0007 008A 0079 0064 Intl 4 Henkan
0102 0007 008B 007B 0067 Intl 5 Muhenkan
0103 0007 0068 0064 0008 F13 F13
0104 0007 0069 0065 0010 F14 F14
0105 0007 006A 0066 0018 F15 F15
0180 - 0185 Up transition (release or unpress key) (0180 for 0100)

Function Reference

The following are brief descriptions of the functions covered in this article. See the SDK for details on each function call.

Function Description
AskKeyMapDefault() Ask for a pointer to the current default keymap
CloseKeyMapHandle() Close a keymap handle (V50)
MapANSI() Encode an ANSI string into key codes
MapRawKey() Decode a raw key input event to an ANSI string
ObtainKeyMapInfo() Obtain information about a raw key (V51.7)
OpenKeyMapHandle() Open a keymap handle (V50)
ReleaseKeyMapInfo() Release info obtained from a keymap handle (V50)
SetKeyMapDefault() Set the current default keymap