/**************************************************************************** * * KeyMacro-Handler.c ---- KeyMacro handler. * * 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. * ****************************************************************************/ /* Function prototypes. */ struct Process * CreateFuncProc(char *Name,LONG Priority,APTR InitCode,ULONG StackSize); VOID FreeString(BPTR Byte); BPTR CreateBSTR(char *s); BPTR CopyPath(VOID); VOID FakeCLI(VOID); VOID ClearPath(BPTR InitPath); VOID StopFakery(VOID); VOID * DeleteMacroMsg(struct MacroMessage *scm_Msg); VOID Executor(VOID); struct MacroKey * FindMacroKey(LONG Code,LONG Qualifier); struct InputEvent * EventHandler(struct InputEvent *Event); BYTE OpenAll(VOID); VOID CloseAll(VOID); BYTE UStrCmp(UBYTE *a,UBYTE *b); VOID * AllocRem(LONG ByteSize,LONG Requirements); VOID * FreeRem(LONG *MemoryBlock); VOID * SendMacroMsg(struct MacroMessage *scm_Msg,struct MsgPort *scm_Port); ULONG InvertKeyMap(ULONG ansicode,struct InputEvent *ie,struct KeyMap *km); LONG _main(VOID); /* The magic stuff. */ #pragma regcall(EventHandler(a0)) /* Shared library identifiers. */ extern struct ExecBase *SysBase; struct IntuitionBase *IntuitionBase; struct Library *LayersBase; /* Global handshake data. */ struct MSeg *MSeg; /* Process<->Process communication data. */ struct Process *ExecuteProc; struct MsgPort *ExecutePort; /* Input device data. */ struct MsgPort *InputDevPort; struct IOStdReq *InputRequestBlock; struct Interrupt *InputHandler; struct InputEvent *FakeInputEvent; /* Console device data. */ struct IOStdReq *ConsoleRequest; struct MsgPort *ConsolePort; /* Timer device data. */ struct timerequest *TimeRequest; struct MsgPort *TimePort; BYTE SigBit = -1; /* Our current version tag. */ const char *VersionTag = "$VER: KeyMacro-Handler 1.6 (09 Sep 1990)\n\r"; /* _main(): * * This is the entry point to the handler process. */ LONG _main() { struct Process *ThatsMe; ULONG SignalSet; struct MacroMessage *MacroMsg; LONG i; /* Do I know myself? */ ThatsMe = (struct Process *)SysBase -> ThisTask; /* Don't let anybody call us from CLI. */ if(ThatsMe -> pr_CLI) goto Quit; /* Can we find the global MsgPort? */ if(!(MSeg = (struct MSeg *)FindPort(PORTNAME))) { Forbid(); Signal(MSeg -> Father,MSeg -> RingBack); goto Quit; } /* This older revision probably doesn't support * some newer structure tags -> exit. */ if(MSeg -> Revision < REVISION) { Forbid(); Signal(MSeg -> Father,MSeg -> RingBack); goto Quit; } /* The MsgPort is already owned by someone * else. */ if(MSeg -> Port . mp_Flags & PA_SIGNAL) { Forbid(); Signal(MSeg -> Father,MSeg -> RingBack); goto Quit; } /* Open the libraries. */ if(!OpenAll()) { CloseAll(); Forbid(); Signal(MSeg -> Father,MSeg -> RingBack); goto Quit; } /* Start the executing process. */ MSeg -> Child = (struct Task *)ThatsMe; if(!(ExecuteProc = (struct Process *)CreateFuncProc("KeyMacro CLI",10,Executor,4000))) { CloseAll(); Forbid(); MSeg -> Child = NULL; Signal(MSeg -> Father,MSeg -> RingBack); goto Quit; } /* Wait for handshake signal. */ Wait(SIG_SHAKE); /* Process creation failed. */ if(!ExecuteProc) { CloseAll(); Forbid(); MSeg -> Child = NULL; Signal(MSeg -> Father,MSeg -> RingBack); goto Quit; } /* Now we are truly running. */ Signal(MSeg -> Father,MSeg -> RingBack); MSeg -> Father = NULL; /* Re-init the MsgPort flags. */ MSeg -> Port . mp_Flags = PA_SIGNAL; MSeg -> Port . mp_SigBit = SigBit; MSeg -> Port . mp_SigTask = MSeg -> Child; /* Wait until somebody kicks us out. */ FOREVER { SignalSet = Wait(SIG_CLOSE | SIG_PORT); /* We are to shut down. */ if(SignalSet & SIG_CLOSE) { if(ExecuteProc) { Signal((struct Task *)ExecuteProc,SIG_CLOSE); Wait(SIG_SHAKE); } CloseAll(); Forbid(); Signal(MSeg -> Father,SIG_CLOSE); goto Quit; } /* A message arrived at our home port. */ if(SignalSet & SIG_PORT) { /* Walk through the list of messages. */ while(MacroMsg = (struct MacroMessage *)GetMsg(&MSeg -> Port)) { /* Execute a keyboard macro. */ if(MacroMsg -> mm_Type == MM_INPUT) { struct MacroKey *TempMacroKey = MacroMsg -> mm_MacroKey; if(TempMacroKey) { /* Let the execute process run the command. */ 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; SendMacroMsg(&CommandMsg,ExecutePort); } /* Build a keyboard macro. */ if(TempMacroKey -> mk_Type == MK_WORD) { InputRequestBlock -> io_Command = IND_WRITEEVENT; InputRequestBlock -> io_Data = (APTR)FakeInputEvent; memset(FakeInputEvent,0,sizeof(struct InputEvent)); FakeInputEvent -> ie_Class = IECLASS_RAWKEY; FakeInputEvent -> ie_SubClass = KM_SUBCLASS; for(i = 0 ; i < strlen(TempMacroKey -> mk_String) ; i++) { if(InvertKeyMap(TempMacroKey -> mk_String[i],FakeInputEvent,MSeg -> DefaultKeyMap)) { FakeInputEvent -> ie_Qualifier |= IEQUALIFIER_RELATIVEMOUSE; DoIO(TimeRequest); FakeInputEvent -> ie_TimeStamp = TimeRequest -> tr_time; DoIO(InputRequestBlock); FakeInputEvent -> ie_Code |= IECODE_UP_PREFIX; DoIO(TimeRequest); FakeInputEvent -> ie_TimeStamp = TimeRequest -> tr_time; DoIO(InputRequestBlock); } } } } } /* This is a request to update the * macro keys. */ 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; } /* Remove the message. */ DeleteMacroMsg(MacroMsg); } } } Quit: ; } /* UStrCmp(): * * strcmp function which ignores case and allows to * abbreviate the name of the source string to match * against the destination string. */ BYTE UStrCmp(UBYTE *a,UBYTE *b) { SHORT i; for(i = 0 ; i < strlen(a) ; i++) if(ToUpper(a[i]) != ToUpper(b[i])) return(1); return(0); } /* CreateFuncProc(): * * Create an independent process from a 'C' routine. */ struct Process * CreateFuncProc(char *Name,LONG Priority,APTR InitCode,ULONG StackSize) { struct Process *ChildProc = NULL; struct FakeSeg { BPTR NextSeg; WORD FirstCode; APTR RealCode; } *FakeSeg; if(FakeSeg = (struct FakeSeg *)AllocMem(sizeof(struct FakeSeg),MEMF_PUBLIC | MEMF_CLEAR)) { struct MsgPort *ChildPort; FakeSeg -> FirstCode = 0x4EF9; FakeSeg -> RealCode = InitCode; if(ChildPort = (struct MsgPort *)CreateProc(Name,Priority,MKBADDR(FakeSeg),StackSize)) ChildProc = (struct Process *)ChildPort -> mp_SigTask; Delay(TICKS_PER_SECOND); FreeMem(FakeSeg,sizeof(struct FakeSeg)); } return(ChildProc); } /* FreeString(Byte): * * Frees the memory occupied by the contents of a BSTR. */ VOID FreeString(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(char *s) { LONG BlockLength; SHORT Length; char *Byte; Length = strlen(s); BlockLength = (Length + 8) & ~3; if(!(Byte = (char *)AllocMem(BlockLength,MEMF_PUBLIC | MEMF_CLEAR))) return(NULL); *(LONG *)Byte = BlockLength; Byte[4] = Length; strncpy(Byte + 5,s,Length); return(MKBADDR(Byte + 4)); } /* CopyPath(): * * Builds a fake pathlist inherited from any valid * CLI process or Workbench. */ BPTR CopyPath() { BPTR *Next1,*Next2,*Last,NewPath = NULL; struct Process *Father; struct CommandLineInterface *CLI; 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)) { 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 = MKBADDR(Next2); Last = Next2; Next2[1] = (BPTR)DupLock(Next1[1]); Next2[0] = NULL; } } return(NewPath); } /* FakeCLI(): * * Creates a fake CLI structure for our process. This * includes pathlist, currentdir, prompt and stack. */ VOID FakeCLI() { struct Process *MyProcess = (struct Process *)SysBase -> ThisTask; struct CommandLineInterface *CLI; if(CLI = (struct CommandLineInterface *)AllocMem(sizeof(struct CommandLineInterface),MEMF_PUBLIC | MEMF_CLEAR)) { MyProcess -> pr_CLI = MKBADDR(CLI); 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(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() { struct CommandLineInterface *CLI; struct Process *MyProcess; BPTR MyCD; MyProcess = (struct Process *)SysBase -> ThisTask; if(CLI = (struct CommandLineInterface *)BADDR(MyProcess -> pr_CLI)) { if(MyCD = (BPTR)CurrentDir(NULL)) UnLock(MyCD); FreeString(CLI -> cli_SetName); FreeString(CLI -> cli_Prompt); ClearPath(CLI -> cli_CommandDir); MyProcess -> pr_CLI = NULL; FreeMem(CLI,sizeof(struct CommandLineInterface)); } } /* DeleteMacroMsg(scm_Msg): * * Remove a message from memory. */ VOID * DeleteMacroMsg(struct MacroMessage *scm_Msg) { if(scm_Msg && scm_Msg -> mm_Message . mn_Node . ln_Name == (char *)scm_Msg) FreeRem(scm_Msg); return(NULL); } /* Executor(): * * This is the dummy process to execute programs. */ VOID Executor() { ULONG SignalSet; BPTR NIL; struct MacroMessage *ExecuteMsg; struct Window *TheWindow; char TempLine[300]; struct Process *ThatsMe; BYTE Activate; geta4(); ThatsMe = (struct Process *)SysBase -> ThisTask; /* These are inherited from the father process, * we had better cleared them out. */ ThatsMe -> pr_WindowPtr = (APTR)-1; /* Try to allocate a port (we can't use our builtin * DOS port since we are actually calling DOS * routines which may mix up the messages coming * in). */ if(!(ExecutePort = (struct MsgPort *)CreatePort(NULL,0))) { Forbid(); ExecuteProc = NULL; Signal(MSeg -> Child,SIG_SHAKE); goto Quit; } /* Open the NULL-Handler. */ if(!(NIL = Open("NULL:",MODE_NEWFILE))) { Forbid(); ExecuteProc = NULL; Signal(MSeg -> Child,SIG_SHAKE); DeletePort(ExecutePort); goto Quit; } /* Pretend to be a CLI. */ FakeCLI(); /* This path leads nowhere. */ ThatsMe -> pr_CIS = NIL; ThatsMe -> pr_COS = NIL; ThatsMe -> pr_ConsoleTask = (APTR)DeviceProc("NULL:"); /* We're on the scene now. */ Signal(MSeg -> Child,SIG_SHAKE); FOREVER { SignalSet = Wait(SIG_CLOSE | (1 << ExecutePort -> mp_SigBit)); /* Shut down? */ if(SignalSet & SIG_CLOSE) { StopFakery(); Close(NIL); DeletePort(ExecutePort); ExecuteProc = NULL; Forbid(); Signal(MSeg -> Child,SIG_SHAKE); goto Quit; } /* Execute a command? */ while(ExecuteMsg = (struct MacroMessage *)GetMsg(ExecutePort)) { TheWindow = NULL; Activate = TRUE; /* Try to find a matching window title. */ if(ExecuteMsg -> mm_WindowName) { ULONG IntuiLock; struct Screen *ExScreen; struct Window *ExWindow; IntuiLock = LockIBase(NULL); if(UStrCmp(ExecuteMsg -> mm_WindowName,IntuitionBase -> ActiveWindow -> Title)) { ExScreen = IntuitionBase -> FirstScreen; do { ExWindow = ExScreen -> FirstWindow; do { if(!UStrCmp(ExecuteMsg -> mm_WindowName,ExWindow -> Title)) { TheWindow = ExWindow; break; } } while((ExWindow = ExWindow -> NextWindow) && !TheWindow); } while((ExScreen = ExScreen -> NextScreen) && !TheWindow); } else { TheWindow = IntuitionBase -> ActiveWindow; Activate = FALSE; } UnlockIBase(IntuiLock); } if(!TheWindow) { /* No chance, execute the command. */ strcpy(TempLine,"C:Run NULL: "); strcat(TempLine,ExecuteMsg -> mm_FileName); Execute(TempLine,NULL,NIL); } DeleteMacroMsg(ExecuteMsg); /* Found a window? Bring it to the front. */ if(TheWindow) { LockLayers(TheWindow -> RPort -> Layer -> LayerInfo); WindowToFront(TheWindow); UnlockLayers(TheWindow -> RPort -> Layer -> LayerInfo); ScreenToFront(TheWindow -> WScreen); if(Activate) ActivateWindow(TheWindow); } } } /* Finished, fall through. */ Quit: ; } /* FindMacroKey(Code,Qualifier): * * Find a macro key entry in the linked list of * macro key structures. */ struct MacroKey * FindMacroKey(LONG Code,LONG Qualifier) { SHORT i; if(MSeg -> MacroList) { 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); } /* EventHandler(Event): * * The input event handler. */ struct InputEvent * EventHandler(struct InputEvent *Event) { struct MacroKey *HandlerKey; struct InputEvent *ChainEvent; /* This is an interrupt, let's start with the register * saving. */ int_start(); for(ChainEvent = Event ; ChainEvent ; ChainEvent = ChainEvent -> ie_NextEvent) { if(ChainEvent -> ie_Class == IECLASS_RAWKEY && !(ChainEvent -> ie_Code & IECODE_UP_PREFIX) && ChainEvent -> ie_SubClass != KM_SUBCLASS) { if(HandlerKey = (struct MacroKey *)FindMacroKey(ChainEvent -> ie_Code,ChainEvent -> ie_Qualifier)) { struct MacroMessage HandlerMsg; HandlerMsg . mm_Type = MM_INPUT; HandlerMsg . mm_MacroKey = HandlerKey; SendMacroMsg(&HandlerMsg,&MSeg -> Port); ChainEvent -> ie_Class = IECLASS_NULL; } } } /* Restore the registers. */ int_end(); return(Event); } /* OpenAll(): * * Initialize the input event handler. */ BYTE OpenAll() { if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",33))) return(FALSE); if(!(LayersBase = (struct Library *)OpenLibrary("layers.library",33))) return(FALSE); if(!(InputDevPort = (struct MsgPort *)CreatePort(NULL,0))) return(FALSE); if(!(InputRequestBlock = (struct IOStdReq *)CreateStdIO(InputDevPort))) return(FALSE); if(OpenDevice("input.device",0,(struct IORequest *)InputRequestBlock,0)) return(FALSE); if(!(InputHandler = (struct Interrupt *)AllocMem(sizeof(struct Interrupt),MEMF_PUBLIC | MEMF_CLEAR))) return(FALSE); if(!(ConsolePort = (struct MsgPort *)CreatePort(NULL,0))) return(FALSE); if(!(ConsoleRequest = (struct IOStdReq *)CreateStdIO(ConsolePort))) return(FALSE); if(OpenDevice("console.device",CONU_LIBRARY,ConsoleRequest,0)) return(FALSE); if(!(TimePort = (struct MsgPort *)CreatePort(NULL,0))) return(FALSE); if(!(TimeRequest = (struct timerequest *)CreateExtIO(TimePort,sizeof(struct timerequest)))) return(FALSE); if(OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,0)) return(FALSE); TimeRequest -> tr_node . io_Command = TR_GETSYSTIME; if(!(FakeInputEvent = (struct InputEvent *)AllocMem(sizeof(struct InputEvent),MEMF_PUBLIC | MEMF_CLEAR))) return(FALSE); if((SigBit = AllocSignal(-1)) == -1) return(FALSE); InputHandler -> is_Code = (APTR)EventHandler; InputHandler -> is_Node . ln_Pri = 51; InputHandler -> is_Node . ln_Name = "KeyMacro-Handler"; InputRequestBlock -> io_Command = IND_ADDHANDLER; InputRequestBlock -> io_Data = (APTR)InputHandler; if(DoIO(InputRequestBlock)) return(FALSE); ConsoleRequest -> io_Command = CD_ASKDEFAULTKEYMAP; ConsoleRequest -> io_Length = sizeof(struct KeyMap); ConsoleRequest -> io_Data = (APTR)MSeg -> DefaultKeyMap; ConsoleRequest -> io_Flags = IOF_QUICK; if(DoIO(ConsoleRequest)) return(FALSE); return(TRUE); } /* CloseAll(): * * Remove the input event handler. */ VOID CloseAll() { if(InputRequestBlock) { if(InputRequestBlock -> io_Device) { if(InputHandler) { InputRequestBlock -> io_Command = IND_REMHANDLER; InputRequestBlock -> io_Data = (APTR)InputHandler; DoIO(InputRequestBlock); } CloseDevice(InputRequestBlock); } DeleteStdIO(InputRequestBlock); } if(TimeRequest) { if(TimeRequest -> tr_node . io_Device) CloseDevice(TimeRequest); DeleteExtIO(TimeRequest); } if(TimePort) DeletePort(TimePort); if(ConsoleRequest) { if(ConsoleRequest -> io_Device) CloseDevice(ConsoleRequest); DeleteStdIO(ConsoleRequest); } if(FakeInputEvent) FreeMem(FakeInputEvent,sizeof(struct InputEvent)); if(InputHandler) FreeMem(InputHandler,sizeof(struct Interrupt)); if(InputDevPort) DeletePort(InputDevPort); if(ConsolePort) DeletePort(ConsolePort); if(SigBit != -1) FreeSignal(SigBit); if(LayersBase) CloseLibrary(LayersBase); if(IntuitionBase) CloseLibrary(IntuitionBase); }