/* ikm.c -- invert keymaps */ /** NOTICE: * The contents of this file are copyright 1987, Jim Mackraz. All rights * reserved. No use of the contents of this file or the compilation * of them may be used apart from the entire Commodities Exchange * without written permission. */ #define CONTROLBITS ( (1 << 5) | (1 << 6) ) /* return >= 0 if ok (no error checking now) */ ULONG InvertKeyMap(ansicode, ie, km) ULONG ansicode; register struct InputEvent *ie; struct KeyMap *km; { ULONG kindex; UBYTE code = 0; extern struct KeyMap keymap; if (km == NULL) { km = &keymap; } ie->ie_Class = IECLASS_RAWKEY; ie->ie_EventAddress = 0; /* check for codes in (default) high map first */ switch(ansicode) { case ' ': code = 0x40; /* space */ break; case 0x08: /* backspace */ code = 0x41; break; case '\t': /* tab */ code = 0x42; break; case 0x0D: /* return */ code = 0x44; break; case 0x1B: /* esc */ code = 0x45; break; case 0x7F: /* del */ code = 0x46; break; } if (code) { ie->ie_Code = code; ie->ie_Qualifier = 0; return (1); } if (LowKeyInvert((UBYTE) ansicode, km, &ie->ie_Code, &ie->ie_Qualifier, &kindex) >= 0) { if (kindex) { /* was dead key, need "preceding" keystroke. */ IndexKey(kindex, km, (ULONG *)&ie->ie_EventAddress); } } return (1); } #define KEYMAPSIZE 64 /* LowKeyInvert returns good code else <0 if no find * * regarding keymap as many-to-one mapping: * -entries for a given key are scanned so that * the minimum number of qualifiers are associated * with the keystroke. * -passing a character value of zero corresponds, in * the default keymap, to CTRL-`, which is probably a bug. * -numerals are matched with numeric pad keystrokes (no * qualifiers) on standard keymap. The way to specify * a key on the number row is via its shifted value; * specify explicitly that the qualifier is to be unshifted, * or a "don't care." */ UWORD LowKeyInvert(value, km, codep, qualp, indexp) register UBYTE value; /* translation value from low keymap */ struct KeyMap *km; UWORD *codep; /* pointers where answers are to be put */ UWORD *qualp; ULONG *indexp; /* dead-key index information (put into ie?) */ { register UWORD code = 0; register WORD type; register LONG *p; /* points to four-byte lokeymap entry */ WORD found_it = 0; *indexp = *qualp = 0; p = (LONG *) km->km_LoKeyMap; do { /* determine type of key */ if ((type = km->km_LoKeyMapTypes[code] ) == KC_VANILLA) { found_it = checkVanilla((UBYTE *)p, value, qualp); } else if (type & KCF_DEAD) { found_it = checkDead((UBYTE **)p, value, qualp, indexp); } /** else if (type & KCF_STRING) { } **/ else if (!(type & KCF_NOP)) { found_it = checkNormal((LONG)p, value, (UWORD)type, qualp); } ++p; } while (!found_it && ++code < KEYMAPSIZE); *codep = code; return (code); } /* * packs code|qual of previous key (should be keys) in *dead_vudup * returns code, <0 if failure */ VOID IndexKey(inx, km, dead_vudup) ULONG inx; struct KeyMap *km; ULONG *dead_vudup; { /* find keystroke which generates index */ register WORD code = 0; UWORD **p; /* points to four-byte lokeymap entry */ register UWORD *deadthing; WORD i; WORD qual = 0; LONG vudu; p = (UWORD **) km->km_LoKeyMap; do { /* check each deadkey in the table */ if (km->km_LoKeyMapTypes[code] & KCF_DEAD) { /* keymap entry is pointer to eight prefix:byte pairs */ deadthing = *p; for (i = 0; i < 8; ++i, ++deadthing) { /* check for index prefix and correct index */ if (*deadthing == ((DPF_DEAD << 8) | inx)) { deadQual((WORD)i, &qual); goto FOUND_IT; } } } ++p; } while (++code < KEYMAPSIZE); FOUND_IT: /* pack as follows: [pred(-1)|qual(-1)|pred(-2)|qual(-2)] */ /* for now, 2nd previous deadkey ignored */ if (code < 0) { *dead_vudup = 0; } else { vudu = code << 8; vudu |= (0xFF & qual); vudu <<= 16; *dead_vudup = vudu; } } WORD checkNormal(four_bytesp, val, type, qualp) LONG four_bytesp; UBYTE val; UWORD type; UWORD *qualp; { register UBYTE *p = (UBYTE *) four_bytesp; /* codes held in long word */ register WORD position; /* start with last of four bytes, "more vanilla" */ p += 3; for (position = 3; position >= 0; --position, --p) { if (*p == val) { switch (type) { case KC_NOQUAL: if (position != 3) goto NOT_THIS; break; case KCF_SHIFT: if (!(position & 2)) goto NOT_THIS; if (position == 2) *qualp |= IEQUALIFIER_LSHIFT; break; case KCF_ALT: if (!(position & 2)) goto NOT_THIS; if (position == 2) *qualp |= IEQUALIFIER_LALT; break; case KCF_CONTROL: if (!(position & 2)) goto NOT_THIS; if (position == 2) *qualp |= IEQUALIFIER_CONTROL; break; case KCF_ALT | KCF_CONTROL: if (!(position & 1)) *qualp |= IEQUALIFIER_LALT; if (!(position & 2)) *qualp |= IEQUALIFIER_CONTROL; break; case KCF_SHIFT | KCF_CONTROL: if (!(position & 1)) *qualp |= IEQUALIFIER_LSHIFT; if (!(position & 2)) *qualp |= IEQUALIFIER_CONTROL; break; case KCF_SHIFT | KCF_ALT: if (!(position & 1)) *qualp |= IEQUALIFIER_LSHIFT; if (!(position & 2)) *qualp |= IEQUALIFIER_LALT; break; default: break; } return (1); } NOT_THIS: ; } return (0); } WORD checkVanilla(p, val, qualp) UBYTE *p; /* note: byte pointer */ UBYTE val; UWORD *qualp; { register WORD i; /* only one way to match a vanilla control key */ if (!(val & CONTROLBITS)) { /* is a control code */ if ((p[3] & ~CONTROLBITS) == val) { *qualp |= IEQUALIFIER_CONTROL; return (1); } } else { /* not a control */ for (i = 3; i >= 0; --i) { if (p[i] == val) { if (!(i & 1)) *qualp |= IEQUALIFIER_LSHIFT; if (!(i & 2)) *qualp |= IEQUALIFIER_LALT; return (1); } } } return (0); } WORD checkDead(keybase, val, qualp, indexp) UBYTE **keybase; /* note: byte pointer */ UBYTE val; UWORD *qualp; ULONG *indexp; { WORD i; WORD j; register UWORD *p = (UWORD *) *keybase; /* need to remember keybase for offsets */ UBYTE *deadp; WORD found_it = 0; /* walk through eight two-byte entries, one for each qual. combo. */ for (i = 0; i < 8; ++i, ++p) { switch (*p >> 8) { case DPF_DEAD: /* dead keys do not themselves map to anything */ break; case DPF_MOD: /* dead key modifiable */ deadp = *keybase + (*p & 0xFF); /* look down the string indexed by dead-key index */ for (j = 0; j < 6; ++j) { if (deadp[j] == val) { found_it = 1; *indexp = j; break; } } break; case 0: /* normal stroke for this key */ if ((*p & 0xFF) == val) { found_it = 1; } } if (found_it) { deadQual((WORD)i, qualp); return (1); } } return (0); } /* figure out qualifier from position */ WORD deadQual(wordpos, qualp) WORD wordpos; /* which word in dead-key string? */ UWORD *qualp; { if (wordpos & 1) *qualp |= IEQUALIFIER_LSHIFT; if (wordpos & 2) *qualp |= IEQUALIFIER_LALT; if (wordpos & 4) *qualp |= IEQUALIFIER_CONTROL; return (0); }