#include "KeyMacro.h" struct MXMBase *MXMBase; struct IntuitionBase *IntuitionBase; struct MSeg *MSeg; LONG MSignal = -1; struct KeyEquivalent *EquList; struct Process *ExecuteProc; struct MsgPort *ExecutePort; struct MsgPort *InputDevPort; struct IOStdReq *InputRequestBlock; struct Interrupt HandlerStuff; long ConsoleDevice = NULL; struct IOStdReq ConStdReq; /* FreeString(Byte): * * Frees the memory occupied by the contents of a BSTR. */ void FreeString(Byte) BPTR Byte; { long *Ptr = (long *)BADDR(Byte); FreeMem(Ptr - 1,Ptr[-1]); } /* CreateBSTR(s): * * Allocates enough memory to hold the contents of * a given string and makes it a BSTR. */ BPTR CreateBSTR(s) char *s; { long Length = strlen(s); long BlockLength = (Length + 8) & ~3; char *Byte; if(!(Byte = (char *)AllocMem(BlockLength,MEMF_PUBLIC | MEMF_CLEAR))) return(NULL); *(long *)Byte = BlockLength; Byte[4] = Length; strncpy(Byte + 5,s,Length); return((long)(Byte + 4) >> 2); } /* CopyPath(): * * Builds a fake pathlist inherited from any valid * CLI process or Workbench. */ BPTR CopyPath() { struct Process *Father; struct CommandLineInterface *CLI; BPTR *Next1,*Next2,*Last,NewPath = NULL; Last = &NewPath; /* If using ARP this will also give us a valid * pathlist. */ if(!(Father = (struct Process *)FindTask("Workbench"))) if(!(Father = (struct Process *)FindTask("ARP Shell Process"))) if(!(Father = (struct Process *)FindTask("New CLI"))) if(!(Father = (struct Process *)FindTask("Initial CLI"))) return(NULL); if(!(CLI = (struct CommandLineInterface *)BADDR(Father -> pr_CLI))) return(NULL); for(Next1 = (BPTR *)BADDR(CLI -> cli_CommandDir) ; Next1 ; Next1 = (BPTR *)BADDR(*Next1)) { if(!(Next2 = (BPTR *)AllocMem(2 * sizeof(BPTR),MEMF_PUBLIC | MEMF_CLEAR))) break; *Last = (long)Next2 >> 2; Last = Next2; Next2[1] = (BPTR)DupLock(Next1[1]); Next2[0] = NULL; } return(NewPath); } /* FakeCLI(): * * Creates a fake CLI structure for out process. This * includes pathlist, currentdir, prompt and stack. */ void FakeCLI() { struct CommandLineInterface *CLI; struct Process *MyProcess = (struct Process *)FindTask(NULL); if(!(CLI = (struct CommandLineInterface *)AllocMem(sizeof(struct CommandLineInterface),MEMF_PUBLIC | MEMF_CLEAR))) return; MyProcess -> pr_CLI = (long)CLI >> 2; CLI -> cli_SetName = CreateBSTR("SYS:"); CLI -> cli_Prompt = CreateBSTR("%N> "); CLI -> cli_DefaultStack = 4000; CurrentDir(Lock("SYS:",ACCESS_READ)); CLI -> cli_CommandDir = CopyPath(); } /* ClearPath(InitPath): * * Frees the contents of our fake pathlist. */ void ClearPath(InitPath) BPTR InitPath; { BPTR *Next,*Path; for(Path = (BPTR *)BADDR(InitPath) ; Path ; Path = Next) { Next = (BPTR *)BADDR(Path[0]); if(Path[1]) UnLock(Path[1]); FreeMem(Path,2 * sizeof(BPTR)); } } /* StopFakery(): * * Removes the contents of our fake CLI structure. */ void StopFakery() { BPTR MyCD = (BPTR)CurrentDir(NULL); struct Process *MyProcess = (struct Process *)FindTask(NULL); struct CommandLineInterface *CLI = (struct CommandLineInterface *)BADDR(MyProcess -> pr_CLI); if(!CLI) return; if(MyCD) UnLock(MyCD); FreeString(CLI -> cli_SetName); FreeString(CLI -> cli_Prompt); ClearPath(CLI -> cli_CommandDir); MyProcess -> pr_CLI = NULL; FreeMem(CLI,sizeof(struct CommandLineInterface)); } void * DeleteCustomMsg(scm_Msg) struct MacroMessage *scm_Msg; { if(scm_Msg && scm_Msg -> mm_Message . mn_Node . ln_Name == scm_Msg) FreeRem(scm_Msg); return(NULL); } void * SendCustomMsg(scm_Msg,scm_Port) struct MacroMessage *scm_Msg; struct MsgPort *scm_Port; { struct MacroMessage *scm_TempMsg = (struct MacroMessage *)AllocRem(sizeof(struct MacroMessage),MEMF_PUBLIC | MEMF_CLEAR); if(scm_TempMsg) { 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,scm_TempMsg); } return((void *)scm_TempMsg); } void Executor() { ULONG SignalSet,NilHandle; struct MacroMessage *ExecuteMsg; struct Window *TheWindow; geta4(); if(!(ExecutePort = (struct MsgPort *)CreatePort(NULL,0))) return; if(!(NilHandle = (ULONG)Open("NIL:",MODE_NEWFILE))) { DeletePort(ExecutePort); return; } FakeCLI(); FOREVER { SignalSet = Wait(SIG_CLOSE | (1 << ExecutePort -> mp_SigBit)); if(SignalSet & SIG_CLOSE) { StopFakery(); Close(NilHandle); DeletePort(ExecutePort); ExecuteProc = NULL; return; } while(ExecuteMsg = (struct MacroMessage *)GetMsg(ExecutePort)) { TheWindow = NULL; if(ExecuteMsg -> mm_WindowName) { ULONG IntuiLock; struct Screen *ExScreen; struct Window *ExWindow; IntuiLock = LockIBase(NULL); ExScreen = IntuitionBase -> FirstScreen; do { ExWindow = ExScreen -> FirstWindow; do { if(!UStrCmp(ExecuteMsg -> mm_WindowName,ExWindow -> Title)) { UnlockIBase(IntuiLock); TheWindow = ExWindow; goto SkipLoop; } } while(ExWindow = ExWindow -> NextWindow); } while(ExScreen = ExScreen -> NextScreen); UnlockIBase(IntuiLock); } Execute(ExecuteMsg -> mm_FileName,NULL,NilHandle); SkipLoop: DeleteCustomMsg(ExecuteMsg); if(TheWindow) { WindowToFront(TheWindow); ScreenToFront(TheWindow -> WScreen); ActivateWindow(TheWindow); } } } } struct MacroKey * FindMacroKey(Code,Qualifier) LONG Code,Qualifier; { long i; if(!MSeg -> MacroList) return(NULL); for(i = 0 ; i < MSeg -> NumMacros ; i++) { if(MSeg -> MacroList[i] . mk_Type == MK_UNUSED) continue; if(MSeg -> MacroList[i] . mk_CommandKey == Code && (Qualifier & MSeg -> MacroList[i] . mk_CommandQualifier) == MSeg -> MacroList[i] . mk_CommandQualifier) return(&MSeg -> MacroList[i]); } return(NULL); } #asm _Handler: MOVEM.L A4,-(A7) MOVEM.L A0/A1,-(A7) JSR _geta4# JSR _EventHandler ADDQ.L #8,A7 MOVEM.L (A7)+,A4 RTS #endasm struct InputEvent * EventHandler(Event) struct InputEvent *Event; { register struct MacroKey *HandlerKey; if(Event -> ie_Class != IECLASS_RAWKEY || Event -> ie_Code & IECODE_UP_PREFIX) return(Event); if(HandlerKey = (struct MacroKey *)FindMacroKey(Event -> ie_Code,Event -> ie_Qualifier)) { struct MacroMessage HandlerMsg; HandlerMsg . mm_Type = MM_INPUT; HandlerMsg . mm_MacroKey= HandlerKey; SendCustomMsg(&HandlerMsg,&MSeg -> Port); Event -> ie_Class = IECLASS_NULL; } return(Event); } BOOL InitHandler() { extern void Handler(); if(OpenDevice("console.device",-1,&ConStdReq,0)) return(FALSE); ConsoleDevice = (long)ConStdReq . io_Device; if(!(InputDevPort = (struct MsgPort *)CreatePort(NULL,0))) return(FALSE); if(!(InputRequestBlock = (struct IOStdReq *)CreateStdIO(InputDevPort))) return(FALSE); if(OpenDevice("input.device",0,InputRequestBlock,0)) return(FALSE); HandlerStuff . is_Code = Handler; HandlerStuff . is_Node . ln_Pri = 60; HandlerStuff . is_Node . ln_Name= "KeyMacro-Handler"; InputRequestBlock -> io_Command = IND_ADDHANDLER; InputRequestBlock -> io_Data = (APTR)&HandlerStuff; DoIO(InputRequestBlock); return(TRUE); } void FlushHandler() { if(ConsoleDevice) CloseDevice(&ConStdReq); if(InputRequestBlock -> io_Device) { InputRequestBlock -> io_Command = IND_REMHANDLER; InputRequestBlock -> io_Data = (APTR)&HandlerStuff; DoIO(InputRequestBlock); CloseDevice(InputRequestBlock); } if(InputRequestBlock) DeleteStdIO(InputRequestBlock); if(InputDevPort) DeletePort(InputDevPort); } void ShutDown() { FlushHandler(); if(ExecuteProc) { Signal(ExecuteProc,SIG_CLOSE); while(ExecuteProc) Delay(10); } if(MXMBase) CloseLibrary(MXMBase); if(MSignal != -1) FreeSignal(MSignal); Forbid(); if(MSeg -> Father) Signal(MSeg -> Father,SIG_CLOSE); if(!MSeg -> Father) { register BPTR Segment = MSeg -> Segment; RemPort(&MSeg -> Port); FreeMem(MSeg -> Port . mp_Node . ln_Name,sizeof(PORTNAME)); UnLoadSeg(Segment); Wait(NULL); } } long _main() { struct Process *ThatsMe = (struct Process *)FindTask(NULL); ULONG SignalSet; struct MacroMessage *MacroMsg; register long i; if(ThatsMe -> pr_CLI) return(10); if(!(MSeg = (struct MSeg *)FindPort(PORTNAME))) return(10); if(MSeg -> Port . mp_Flags == PA_SIGNAL) return(10); if(MSeg -> Revision < REVISION) { Signal(MSeg -> Father,MSeg -> RingBack); return(10); } if(!InitHandler()) { FlushHandler(); Signal(MSeg -> Father,MSeg -> RingBack); return(20); } if(!(MXMBase = (struct MXMBase *)OpenLibrary("mxm.library",0))) { FlushHandler(); Signal(MSeg -> Father,MSeg -> RingBack); return(20); } IntuitionBase = (struct IntuitionBase *)MXMBase -> IntuitionBase; if((MSignal = AllocSignal(-1)) == -1) { CloseLibrary(MXMBase); FlushHandler(); Signal(MSeg -> Father,MSeg -> RingBack); return(20); } if(!(ExecuteProc = (struct Process *)CreateFuncProc("KeyMacro.exec",10,Executor,4000))) { FreeSignal(MSignal); CloseLibrary(MXMBase); FlushHandler(); Signal(MSeg -> Father,MSeg -> RingBack); return(20); } MSeg -> Child = (struct Task *)ThatsMe; Signal(MSeg -> Father,MSeg -> RingBack); MSeg -> Father = NULL; MSeg -> Port . mp_Flags = PA_SIGNAL; MSeg -> Port . mp_SigBit = MSignal; MSeg -> Port . mp_SigTask = MSeg -> Child; FOREVER { SignalSet = Wait(SIG_CLOSE | SIG_PORT); if(SignalSet & SIG_CLOSE) { ShutDown(); return(0); } if(SignalSet & SIG_PORT) { while(MacroMsg = (struct MacroMessage *)GetMsg(&MSeg -> Port)) { if(MacroMsg -> mm_Type == MM_INPUT) { struct MacroKey *TempMacroKey = MacroMsg -> mm_MacroKey; if(TempMacroKey) { if(TempMacroKey -> mk_Type == MK_COMMAND) { struct MacroMessage CommandMsg; CommandMsg . mm_Type = MM_EXECUTE; CommandMsg . mm_FileName = TempMacroKey -> mk_String; CommandMsg . mm_WindowName = TempMacroKey -> mk_Window; SendCustomMsg(&CommandMsg,ExecutePort); } if(TempMacroKey -> mk_Type == MK_WORD) { struct InputEvent FakeInputEvent; InputRequestBlock -> io_Command = IND_WRITEEVENT; InputRequestBlock -> io_Data = (APTR)&FakeInputEvent; setmem(&FakeInputEvent,sizeof(struct InputEvent),0); FakeInputEvent . ie_Class = IECLASS_RAWKEY; for(i = 0 ; i < strlen(TempMacroKey -> mk_String) ; i++) if(InvertKey(TempMacroKey -> mk_String[i],&FakeInputEvent,IK_USEIKM,NULL)) DoIO(InputRequestBlock); } } } if(MacroMsg -> mm_Type == MM_UPDATE) { if(MSeg -> MacroList) { for(i = 0 ; i < MSeg -> NumMacros ; i++) { if(MSeg -> MacroList[i] . mk_Type == MK_UNUSED) continue; if(MSeg -> MacroList[i] . mk_String) FreeRem(MSeg -> MacroList[i] . mk_String); if(MSeg -> MacroList[i] . mk_Window) FreeRem(MSeg -> MacroList[i] . mk_Window); } FreeRem(MSeg -> MacroList); } MSeg -> NumMacros = MacroMsg -> mm_NumMacros; MSeg -> MacroList = MacroMsg -> mm_MacroList; } DeleteCustomMsg(MacroMsg); } } } }