home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d5xx
/
d535
/
keymacro.lha
/
KeyMacro
/
ikm.c
next >
Wrap
Text File
|
1991-08-26
|
10KB
|
371 lines
/**************************************************************************
*
* ikm.c - Olsen's magical key inversion routines.
*
* You may use this piece of code in any application
* without requesting permission of the original author.
*
* It is strongly recommended to use cx.lib/InvertString
* instead of the following set of routines when running
* under v37 or higher.
*
* Basically, the following code is derived from the
* keymap inversion routines employed by KeyMacro 1.9,
* strange enough the german keymap would never be
* read correctly to generate the letter `f'. This and
* a lot of other problems have been fixed (keep your
* fingers crossed!) and single-depth-dead-key
* conversion was added on the fly (i.e. accented
* characters can be generated with keyboard layouts
* which do not contain accent keys).
*
* Jimm Mackraz' original ikm.c code, Bill Hawes'
* cmap.asm example keymap, and the `International
* Keyboard Input' article by Eric Cotton and Carolyn
* Scheppner published in Amiga-Mail provided enough
* help to create the current release of this package
* (which also is significantly shorter than Jimm's
* original ikm.c code).
*
* A potential problem still exists: what happens if
* a dead-key-modifiable key sports less than three
* qualifiers (shift, alternate, control)? The
* `International Keyboard Input' article states that
* the number of qualifiers determines the format and the
* length of the corresponding mk_Hi/LowKeyMap entry.
* Unfortunately, no word is lost on how a keymap entry
* of such kind would look like. For now my code
* determines the number of table entries to look up
* by counting the qualifiers listed in
* km_Hi/LowKeyMapTypes which will probably find the
* approriate key but will fail to generate a matching
* qualifier (do YOU know of a fix?).
*
* Anyway, keymap inversion is a weird topic which
* had better been covered in the early days of
* the Amiga.
*
* A note to code hackers:
*
* Sometimes InvertKeyMap() will not return the
* proper raw key value for a character but
* rather the raw key value of the base character
* (example: character = á, base character = a).
* To avoid unpleasant sideeffects, just remove
* the dead key conversion in lines 214-225
* (delete the loop, only check the first character
* of the array).
*/
/* PackQualifiers(BYTE Bits):
*
* Piece together a valid pack of qualifiers from
* a bitmapped key position.
*/
STATIC UWORD
PackQualifiers(BYTE Bits)
{
UWORD Qualifier = 0;
if(Bits & KCF_SHIFT)
Qualifier |= IEQUALIFIER_LSHIFT;
if(Bits & KCF_ALT)
Qualifier |= IEQUALIFIER_LALT;
if(Bits & KCF_CONTROL)
Qualifier |= IEQUALIFIER_CONTROL;
return(Qualifier);
}
/* CountPairs(BYTE Qualifiers):
*
* Count the number (not the one from Sesame Street) of
* qualifiers given in a KeyMapTypes entry.
*/
STATIC BYTE
CountPairs(BYTE Qualifiers)
{
BYTE Bits = 1;
if(Qualifiers & KCF_SHIFT)
Bits++;
if(Qualifiers & KCF_ALT)
Bits++;
if(Qualifiers & KCF_CONTROL)
Bits++;
return(Bits);
}
/* FindIndexKey():
*
* Find the key which if `preceding' the inverted base key
* will generate the accented character (example: character
* to be inverted = á, inverted base key = a, the preceding
* key we are trying to find in this routine will put the
* accent ´ on top of the vowel).
*/
STATIC APTR
FindIndexKey(UBYTE Hi,UBYTE Offset,UBYTE *KeyTable,UBYTE *KeyTypes,APTR Index)
{
UBYTE *String;
SHORT i,j;
for(i = 0 ; i < Hi ; i++)
{
/* Examine only the dead key entries. */
if(KeyTypes[i] & KCF_DEAD)
{
String = (UBYTE *)(((ULONG *)KeyTable)[i]);
/* Look for a dead-key index. */
for(j = 0 ; j < CountPairs(KeyTypes[i]) ; j++)
{
/* This comes close to real magic:
*
* if the corresponding InputEvent
* is of type RAWKEY, the EventAddress
* pointer contains the packed
* codes and qualifiers of the
* previous key(s). The v37 header
* files reflect this, but alas,
* some guys will want to recompile
* this code using v34 (and below)
* header files.
*/
if(String[2 * j] == DPF_DEAD && (String[2 * j + 1] & 0x1F) == ((ULONG)Index & BYTEMASK))
return((APTR)(((ULONG)(Offset + i) << 24) | (ULONG)PackQualifiers(j) << 16));
}
}
}
return(NULL);
}
/* ScanKeyMap():
*
* Scan a given keymap for an ANSI key and try to generate
* an InputEvent which will -- if processed -- create the
* given character.
*/
STATIC BYTE
ScanKeyMap(UBYTE Hi,UBYTE Offset,UBYTE *KeyTable,UBYTE *KeyTypes,UBYTE AnsiKey,struct InputEvent *Event,BYTE Depth)
{
/* A bunch of qualifiers associated with KeyMapType bits. */
STATIC struct {
UBYTE QualBits;
UWORD Qualifiers[4];
} QualType[8] = {
KC_NOQUAL, 0, 0, 0, 0,
KCF_SHIFT, 0, 0, IEQUALIFIER_LSHIFT, 0,
KCF_ALT, 0, 0, IEQUALIFIER_LALT, 0,
KCF_CONTROL, 0, 0, IEQUALIFIER_CONTROL, 0,
KCF_ALT|KCF_SHIFT, IEQUALIFIER_LSHIFT|IEQUALIFIER_LALT, IEQUALIFIER_LALT, IEQUALIFIER_LSHIFT, 0,
KCF_CONTROL|KCF_ALT, IEQUALIFIER_CONTROL|IEQUALIFIER_LALT, IEQUALIFIER_CONTROL, IEQUALIFIER_LALT, 0,
KCF_CONTROL|KCF_SHIFT, IEQUALIFIER_CONTROL|IEQUALIFIER_LSHIFT, IEQUALIFIER_CONTROL, IEQUALIFIER_LSHIFT, 0,
KC_VANILLA, IEQUALIFIER_LSHIFT|IEQUALIFIER_LALT, IEQUALIFIER_LALT, IEQUALIFIER_LSHIFT, 0
};
BYTE *String;
SHORT i,j,k;
/* Scan the whole area. */
for(i = 0 ; i < Hi ; i++)
{
/* This looks like a dead key. */
if(KeyTypes[i] & KCF_DEAD)
{
String = (BYTE *)(((ULONG *)KeyTable)[i]);
/* Check all table entries. */
for(j = 0 ; j < CountPairs(KeyTypes[i]) ; j++)
{
switch(String[2 * j])
{
/* A simple dead key. */
case 0: if((UBYTE)String[2 * j + 1] == AnsiKey)
{
Event -> ie_Qualifier = PackQualifiers(j);
Event -> ie_Code = Offset + i;
return(TRUE);
}
break;
/* A dead-key-modifiable key. */
case DPF_MOD: for(k = 0 ; k < Depth ; k++)
{
if((UBYTE)String[String[2 * j + 1] + k] == AnsiKey)
{
Event -> ie_Qualifier = PackQualifiers(j);
Event -> ie_Code = Offset + i;
Event -> ie_EventAddress = (APTR)k;
return(TRUE);
}
}
break;
default: break;
}
}
}
/* This looks like a string. */
if(KeyTypes[i] & KCF_STRING)
{
String = (BYTE *)(((ULONG *)KeyTable)[i]);
/* Only single character strings are
* accepted, check the `no qualifier'
* entry first.
*/
if(String[0] == 1)
{
if((UBYTE)String[String[1]] == AnsiKey)
{
/* Try to find the approriate
* qualifier.
*/
for(k = 0 ; k < 8 ; k++)
{
if(QualType[k] . QualBits == (KeyTypes[i] & KC_VANILLA))
{
Event -> ie_Qualifier = QualType[k] . Qualifiers[j];
Event -> ie_Code = Offset + i;
return(TRUE);
}
}
}
}
/* Are there any strings left which
* require a qualifier key to be
* pressed?
*/
for(j = 0 ; j < 3 ; j++)
{
if(KeyTypes[i] & (1 << j))
{
if(String[2 + (2 * j)] == 1)
{
if((UBYTE)String[String[3 + (2 * j)]] == AnsiKey)
{
for(k = 0 ; k < 8 ; k++)
{
if(QualType[k] . QualBits == (KeyTypes[i] & KC_VANILLA))
{
Event -> ie_Qualifier = QualType[k] . Qualifiers[j];
Event -> ie_Code = Offset + i;
return(TRUE);
}
}
}
}
}
}
}
else
{
/* At last, something sensible, check
* the remaining vanilla type keys.
*/
for(j = 3 ; j >= 0 ; j--)
{
if(AnsiKey == KeyTable[4 * i + j])
{
for(k = 0 ; k < 8 ; k++)
{
if(QualType[k] . QualBits == KeyTypes[i])
{
Event -> ie_Code = Offset + i;
if(QualType[k] . QualBits == KC_VANILLA)
{
if(AnsiKey & 96)
Event -> ie_Qualifier = QualType[k] . Qualifiers[j];
else
Event -> ie_Qualifier = IEQUALIFIER_CONTROL;
}
else
Event -> ie_Qualifier = QualType[k] . Qualifiers[j];
return(TRUE);
}
}
}
}
}
}
return(FALSE);
}
/* InvertKeyMap():
*
* Invert a given character.
*/
BYTE
KeyInvert(UBYTE AnsiKey,struct InputEvent *Event,struct KeyMap *KeyMap,BYTE Depth)
{
BYTE Result;
Event -> ie_Class = IECLASS_RAWKEY;
Event -> ie_EventAddress = NULL;
/* Check the high keymap types first to include control keys
* such as backspace, return, delete, etc. instead of the
* control+? combination given in the low keymap entries.
*/
if(!(Result = ScanKeyMap(0x28,0x40,(UBYTE *)KeyMap -> km_HiKeyMap,(UBYTE *)KeyMap -> km_HiKeyMapTypes,AnsiKey & BYTEMASK,Event,Depth)))
Result = ScanKeyMap(0x40,0x00,(UBYTE *)KeyMap -> km_LoKeyMap,(UBYTE *)KeyMap -> km_LoKeyMapTypes,AnsiKey & BYTEMASK,Event,Depth);
/* See if we are to generate a preceding keystroke. */
if(Result && Event -> ie_EventAddress)
{
APTR Address;
/* Find the preceding keystroke. */
if(!(Address = FindIndexKey(0x28,0x40,(UBYTE *)KeyMap -> km_HiKeyMap,(UBYTE *)KeyMap -> km_HiKeyMapTypes,Event -> ie_EventAddress)))
Address = FindIndexKey(0x40,0x00,(UBYTE *)KeyMap -> km_LoKeyMap,(UBYTE *)KeyMap -> km_LoKeyMapTypes,Event -> ie_EventAddress);
/* Heavy magic, don't touch! */
if(!(Event -> ie_EventAddress = Address))
return(FALSE);
}
return(Result);
}