home *** CD-ROM | disk | FTP | other *** search
- /**************************************************************************
- *
- * 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);
- }
-