/**************************************************************************** * * KeySupport.c ---------- Keymacro support routines. * * Author ---------------- Olaf Barthel, MXM * Brabeckstrasse 35 * D-3000 Hannover 71 * * KeyMacro © Copyright 1990 by MXM; Executable program, * documentation and source code are shareware. If you like * this program a small donation will entitle you to receive * updates and new programs from MXM. * ****************************************************************************/ /* AllocRem(): * * Allocate public memory and keep track of its size. */ VOID * AllocRem(LONG ByteSize,LONG Requirements) { LONG *MemoryBlock = NULL; LONG RemSize = ByteSize + sizeof(LONG); if(ByteSize > 0) MemoryBlock = (LONG *)AllocMem(RemSize,Requirements); if(MemoryBlock) *MemoryBlock++ = RemSize; return((VOID *)MemoryBlock); } /* FreeRem(): * * Free a tracked portion of memory. */ VOID * FreeRem(LONG *MemoryBlock) { if(MemoryBlock--) FreeMem(MemoryBlock,*MemoryBlock); return(NULL); } /* SendMacroMsg(scm_Msg,scm_Port): * * Post a cloned macro message to a MsgPort. */ VOID * SendMacroMsg(struct MacroMessage *scm_Msg,struct MsgPort *scm_Port) { struct MacroMessage *scm_TempMsg; if(scm_TempMsg = (struct MacroMessage *)AllocRem(sizeof(struct MacroMessage),MEMF_PUBLIC | MEMF_CLEAR)) { CopyMem(scm_Msg,scm_TempMsg,sizeof(struct MacroMessage)); scm_TempMsg -> mm_Message . mn_Node . ln_Name = (char *)scm_TempMsg; scm_TempMsg -> mm_Message . mn_ReplyPort = NULL; scm_TempMsg -> mm_Message . mn_Length = sizeof(struct MacroMessage); PutMsg(scm_Port,(struct Message *)scm_TempMsg); } return((VOID *)scm_TempMsg); } /* The following piece of code was written by Jim Mackraz; * I do not claim any publishing rights for it, the code * is still his property. I will try to remove it as soon * as Kick 2.x has left the beta phase (read the docs, * there will probably be no further KeyMacro revisions * for pre-2.x systems). */ #define CONTROLBITS ( (1 << 5) | (1 << 6) ) STATIC BYTE CheckNormal(four_bytesp, val, type, qualp) LONG four_bytesp; UBYTE val; UWORD type; UWORD *qualp; { UBYTE *p = (UBYTE *)four_bytesp; /* codes held in long word */ long 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(TRUE); } NOT_THIS: ; } return(FALSE); } STATIC BYTE CheckVanilla(p,val,qualp) UBYTE *p; /* note: byte pointer */ UBYTE val; UWORD *qualp; { int 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(TRUE); } } 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(TRUE); } } } return(FALSE); } #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." */ STATIC UWORD LowKeyInvert(value,km,codep,qualp,indexp) 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?) */ { UWORD code = KEYMAPSIZE - 1; /* last entry */ unsigned int type; LONG *p; /* points to four-byte lokeymap entry */ int found_it = 0; *indexp = *qualp = 0; p = (LONG *)km -> km_LoKeyMap + code; do { /* determine type of key */ if((type = km -> km_LoKeyMapTypes[code]) == KC_VANILLA) found_it = CheckVanilla(p,value,qualp); else if(!(type & KCF_NOP)) found_it = CheckNormal(p,value,type,qualp); --p; } while(!found_it && code--); *codep = code; return(code); } ULONG InvertKeyMap(ULONG ansicode,struct InputEvent *ie,struct KeyMap *km) { LONG kindex; UBYTE code = 0; 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: code = 0x41; /* backspace */ break; case '\t': code = 0x42; /* tab */ break; case 0x0A: case 0x0D: code = 0x44; /* return */ break; case 0x1B: code = 0x45; /* esc */ break; case 0x7F: code = 0x46; /* del */ break; case '0': code = 0x0a; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': code = ansicode - '0'; break; } if(ansicode >= '1' && ansicode <= '0') code = ie -> ie_Code = 0; ie -> ie_Qualifier = 0; if(code) { ie -> ie_Code = code; ie -> ie_Qualifier = 0; return(TRUE); } LowKeyInvert((UBYTE)ansicode,km,&ie -> ie_Code,&ie -> ie_Qualifier,(ULONG *)&kindex); if(!ie -> ie_Code && !ie -> ie_Qualifier) return(FALSE); return(TRUE); }