ahh@j.cc.purdue.edu (Brent L. Woods) (02/09/88)
Program Name: wKeys Submitted By: Davide P. Cervone dpvc@tut.cc.rochester.edu dpvc@ur-tut.UUCP DPVC@UORDBV.BITNET Summary: A program to attach various window functions to the function keys. Poster Boy: Brent Woods (ahh@j.cc.purdue.edu) Tested. NOTES: Very much like the previous submission of wKeys, but with some functions added. They are: "The new functions added are: ability to close any window with a close gadget; iconify a window; uniconify a window; and select the next window icon on the workbench. The last three are available only if wIconify is running. See the documentation file for more information on wKeys. [currently in the binaries posting--Moderator] I have included .uu files for HandlerStub.o (in case anyone does not have an assembler), and wIconCalls.o (since I have not distributed source to this one yet). The rest is pretty much self-explanatory (I hope)." -Author Brent Woods, Co-Moderator, comp.{sources,binaries}.amiga USENET: ...!j.cc.purdue.edu!ahh ARPANET: ahh@j.cc.purdue.edu BITNET: PODUM@PURCCVM PHONE: +1 (317) 743-8421 USNAIL: 320 Brown St., #406 / West Lafayette, IN 47906 ================================================================ # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # wKeys.c # BindWKeys.c # mSort.c # wKeys-Handler.c # HandlerStub.a # wKeys.h # wKeys.lnk # wKeys-Handler.lnk # HandlerStub.o.uu # wIconCalls.o.uu # This archive created: Sun Jan 10 21:47:10 1988 # By: (Davide P. Cervone) cat << \SHAR_EOF > wKeys.c /* * wKeys.c Moves and activates windows and screens via keystrokes. * * Copyright (c) 1987,1988 by Davide P. Cervone * You may use this code provided this copyright notice is left intact. */ #include <exec/types.h> #include <libraries/dos.h> #include <exec/io.h> #include <exec/memory.h> #include <exec/interrupts.h> #include <devices/input.h> #include <devices/inputevent.h> #include "wKeys.h" static char *program = "wKeys"; static int version = 2; static char *date = "January 1988"; static char *author = "Copyright (c) 1987,1988 by Davide P. Cervone"; static int hversion = 0; static char *PortName = "wKeysPort"; static char *handler = "L:wKeys-Handler"; /* the handler file */ #define HANDLER &(handler[2]) /* without the "L:" */ /* * This is the structure that holds the handler information between calls * to wKeys. We create a named, public message-port that points to * an instance of this structure so that we can find this information * when we are asked to remove the handler. The PortName is stored here * (NamedPort->mp_Node.ln_Name uses this area for it's name). The other * data are what we need in order to remove the handler and clean up properly. */ struct HandlerBlock { char *PortName; /* name of the public, named message-port */ struct Interrupt Handler; /* the handler added to the handler chain */ struct IntuitionBase *Ibase; /* an error if the handler can't be found */ struct LayersBase *Lbase; /* library base used by the handler */ long Segment; /* pointer from LoadSeg() */ struct HotKey *Keys; /* pointer to Key array */ struct MsgPort *ReplyPort; /* the reply port for CLOSE-WINDOW */ int KeyCount; /* size of Key array */ }; #define HANDLERINFOSIZE sizeof(struct HandlerBlock) #define NAMESIZE (strlen(PortName)+1) /*extern struct MsgPort *CreatePort();*/ extern struct IOStdReq *CreateStdIO(); extern struct MsgPort *FindPort(), *CreatePort(); extern APTR AllocMem(); extern long LoadSeg(); #define INTUITION_REV 0L #define LAYERS_REV 0L struct IntuitionBase *IntuitionBase = NULL; struct LayersBase *LayersBase = NULL; extern struct SysBase *SysBase; struct MsgPort *InputPort = NULL; /* Port used to talk to Input.Device */ struct IOStdReq *InputBlock = NULL; /* request block used with Input.Device */ LONG InputDevice = 0; /* flag whether Input.Device is open */ struct MsgPort *NamedPort = NULL; /* holds info needed to remove handler */ struct MsgPort *ReplyPort = NULL; /* reply port for CLOSE-WINDOW */ struct HandlerBlock *HandlerInfo = NULL; /* holds info stored in NamedPort */ extern struct HotKeyItem *KeyList; extern struct HotKey *KeyArray; extern int KeyCount; #define KEYARRAYSIZE (KeyCount*sizeof(struct HotKey)) extern void GetKeyArray(); /* * DeleteNonSigPort() * * Deletes a message port with signal type PA_IGNORE. Based on * DeletePort() from the exec support functions documented in the RKM */ void DeleteNonSigPort(thePort) struct MsgPort *thePort; { if (thePort->mp_Node.ln_Name) RemPort(thePort); thePort->mp_Node.ln_Type = 0xFF; thePort->mp_MsgList.lh_Head = (struct Node *) -1; FreeMem(thePort,(ULONG)sizeof(struct MsgPort)); } /* * CreateNonSigPort() * * Creates a message port with signal type PA_IGNORE. Based on * CreatePort() from the exec support functions documented in the RKM. */ struct MsgPort *CreateNonSigPort(name,pri) char *name; BYTE pri; { struct MsgPort *thePort; thePort = (struct MsgPort *)AllocMem((ULONG)sizeof(struct MsgPort), MEMF_PUBLIC | MEMF_CLEAR); if (thePort) { thePort->mp_Node.ln_Name = name; thePort->mp_Node.ln_Pri = pri; thePort->mp_Node.ln_Type = NT_MSGPORT; thePort->mp_Flags = PA_IGNORE; thePort->mp_SigBit = 0; thePort->mp_SigTask = NULL; if (name) AddPort(thePort); else NewList(&(thePort->mp_MsgList)); } return(thePort); } /* * DoExit() * * General purpose exit routine. If 's' is not NULL, then print an * error message with up to three parameters. Free any memory, close * any open device, delete any ports, close any libraries, etc. */ void DoExit(s,x1,x2,x3) char *s, *x1, *x2, *x3; { long status = RETURN_OK; struct HotKeyItem *TempKey; if (s != NULL) { printf(s,x1,x2,x3); printf("\n"); status = RETURN_ERROR; } if (InputDevice) CloseDevice(InputBlock); if (InputBlock) DeleteStdIO(InputBlock); if (InputPort) DeletePort(InputPort); if (NamedPort) DeleteNonSigPort(NamedPort); if (ReplyPort) DeleteNonSigPort(ReplyPort); if (HandlerInfo) { if (HandlerInfo->PortName) FreeMem(HandlerInfo->PortName,NAMESIZE); FreeMem(HandlerInfo,HANDLERINFOSIZE); } if (KeyArray) FreeMem(KeyArray,KEYARRAYSIZE); while (KeyList) { TempKey = KeyList; KeyList = KeyList->Next; FreeMem(TempKey,sizeof(*TempKey)); } if (IntuitionBase) CloseLibrary(IntuitionBase); if (LayersBase) CloseLibrary(LayersBase); exit(status); } /* * CheckLibOpen() * * General library open routine. It opens a library and sets a pointer * to it. It checks that the library was openned successfully. */ static void CheckLibOpen(lib,name,rev) APTR *lib; char *name; int rev; { extern APTR OpenLibrary(); if ((*lib = OpenLibrary(name,(LONG)rev)) == NULL) DoExit("Can't open '%s'\n",name); } /* * Macros that make memory allocation easier. */ #define NEW(s,var) (var = (struct s *)New("var",sizeof(struct s))) #define NEWCHAR(var,s) (var = (char *)New("var",s)) /* * New() * * Allocate public memory of a given size and set it to all zeros. If there * is not enough memory, then exit with an error, otherwise return the * pointer to the newly allocated memory. */ APTR New(name,size) char *name; int size; { APTR ptr; if ((ptr = AllocMem(size,MEMF_PUBLIC | MEMF_CLEAR)) == NULL) DoExit("Can't Get Memory for '%s'",name); return(ptr); } /* * TellInputDevice() * * Create a port and I/O block, and open the input device. Set up the * I/O block to add or remove the input handler, and send the request * to the input device. Finally, close the device and delete the * I/O block and port. */ static void TellInputDevice(function) int function; { long status; if ((InputPort = CreatePort(0,0)) == NULL) DoExit("Can't Create Port"); if ((InputBlock = CreateStdIO(InputPort)) == NULL) DoExit("Can't Create Standard IO Block"); InputDevice = (OpenDevice("input.device",0,InputBlock,0) == 0); if (InputDevice == FALSE) DoExit("Can't Open 'input.device'"); InputBlock->io_Command = (long) function; InputBlock->io_Data = (APTR) &(HandlerInfo->Handler); if (status = DoIO(InputBlock)) DoExit("Error from DoIO: %ld",status); CloseDevice(InputBlock); DeleteStdIO(InputBlock); DeletePort(InputPort); } /* * CreateHandler() * * Open the libraries needed by the input handler and store their locations * in the HandlerInfo structure (so we can close them later). Try to * LoadSeg() the handler. If it is not in the current directory, try the * L: directory. Exit with an error if the handler can't be found. * Convert the segment pointer into a pointer to the Setup() routine (the * first routine in the handler executable). Call Setup() and pass it * the pointers to the libraries that it will need to use. Setup() returns * a pointer to the actual handler routine that should be added into the * input handler chain. Store this in the HandlerInfo structure so we * can use it to remove the handler later. Set the handler priority to * 51 so that it is ahead of Intuition. * * Finally, add the handler in the chain and tell the user that the * handler has been installed. */ static void CreateHandler() { long (*Setup)(); CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV); CheckLibOpen(&LayersBase,"layers.library",LAYERS_REV); HandlerInfo->Ibase = IntuitionBase; HandlerInfo->Lbase = LayersBase; if ((HandlerInfo->Segment = LoadSeg(HANDLER)) == NULL) if ((HandlerInfo->Segment = LoadSeg(handler)) == NULL) DoExit("Can't Load '%s'",handler); Setup = (long (*)()) ((HandlerInfo->Segment << 2) + 4); HandlerInfo->Handler.is_Code = (void (*)()) ((*Setup)(IntuitionBase,LayersBase,SysBase, KeyArray,KeyCount,ReplyPort,&hversion)); HandlerInfo->Handler.is_Node.ln_Pri = 51; HandlerInfo->Keys = KeyArray; HandlerInfo->KeyCount = KeyCount; HandlerInfo->ReplyPort = ReplyPort; TellInputDevice(IND_ADDHANDLER); printf("%s v%d.%d (%s) Installed\n",program,version,hversion,date); } /* * Delete Handler() * * Retreive the library pointers from the HandlerInfo structure, where * we stored them when we originally installed the handler, then remove * the handler from the input handler chain. Tell the user that the * handler is gone, and then close the libraries that are no longer needed. */ static void DeleteHandler() { IntuitionBase = HandlerInfo->Ibase; LayersBase = HandlerInfo->Lbase; KeyArray = HandlerInfo->Keys; KeyCount = HandlerInfo->KeyCount; ReplyPort = HandlerInfo->ReplyPort; TellInputDevice(IND_REMHANDLER); UnLoadSeg(HandlerInfo->Segment); printf("%s Removed\n",program); FreeMem(KeyArray,KEYARRAYSIZE); CloseLibrary(IntuitionBase); CloseLibrary(LayersBase); } /* * main() * * Check if a message port with our name already exists. * If not, then the handler is not already installed, so: * Allocate a new HandlerInfo structure and initialize the port name. * Create a public, named message-port (we will look for this the next * time wKeys is called). * Make the message port point to the HandlerInfo structure so we * can use it later when the user asks us to remove the handler. * Note that the port is not actually used for putting and getting * messages, so the Task field is never used, so we can take it for * our own uses. * Get a port to use as a reply port for CLOSE-WINDOW intuimessages. * Finally, add the input handler into the chain. * Otherwise, the port exists, so wKeys already is installed: * Retreive the HandlerInfo poiner from the port, and remove the * handler from the input handler chain. * Free the memory used by the HandlerInfo, and delete the message ports. */ void main(argc,argv) int argc; char **argv; { NamedPort = FindPort(PortName); if (NamedPort == NULL) { NEW(HandlerBlock,HandlerInfo); NEWCHAR(HandlerInfo->PortName,NAMESIZE); strcpy(HandlerInfo->PortName,PortName); if ((NamedPort = CreateNonSigPort(HandlerInfo->PortName,0)) == NULL) DoExit("Can't Create Message Port '%s'",PortName); if ((ReplyPort = CreateNonSigPort(NULL,0)) == NULL) DoExit("Can't Create Reply Port"); NamedPort->mp_SigTask = (struct Task *)HandlerInfo; GetKeyArray(argc,argv); CreateHandler(); } else { HandlerInfo = (struct HandlerBlock *)(NamedPort->mp_SigTask); DeleteHandler(); FreeMem(HandlerInfo->PortName,NAMESIZE); FreeMem(HandlerInfo,HANDLERINFOSIZE); DeleteNonSigPort(ReplyPort); DeleteNonSigPort(NamedPort); } } SHAR_EOF cat << \SHAR_EOF > BindWKeys.c /* * BindWKeys.c Reads a file and creates an array of key bindings * to be used by a hot-key handler to tell which keys * do what. * * Copyright (c) 1987,1988 by Davide P. Cervone * You may use this code provided this copyright notice is left intact. */ #include <exec/types.h> #include <exec/memory.h> #include <devices/inputevent.h> #ifndef NO_FILE #include <stdio.h> #endif #include "wKeys.h" #ifndef NO_FILE #define KEYMASK 0x00FF /* default qualifier key mask */ #define SHIFT IECODE_UP_PREFIX #define BADVALUE -1 /* error while parsing input line */ /* * Macros to tell whether a character is printable or not, and * whether it is not alphanumeric */ #define PRINTABLE(c) ((c)>=' '&&(c)<='~') #define NOTPRINTABLE(c) ((c)<' '||(c)>'~') #define NOTALPHANUM(c)\ ((c)<'0'||((c)>'9'&&(c)<'A')||((c)>'Z'&&(c)<'a')||(c)>'z') /* * Create a new instance of a given structure type */ #define NEW(s,var) (var = (struct s *)New("var",sizeof(struct s))) #define LINESIZE 132 static char InputLine[LINESIZE+1]; /* the line read from the file */ static char *CurPos; /* current character position in line */ static char *CurWord; /* pointer to begining of current word */ static char TerminationChar; /* character that ended the word */ static int LineCount = 0; /* number of lines read from the file */ #endif struct HotKeyItem *KeyList = NULL; /* the list of key definitions so far */ struct HotKey *KeyArray = NULL; /* the sorted array of key definitions */ int KeyCount = 0; /* the number of key definitions */ #define KEYARRAYSIZE (KeyCount*sizeof(struct HotKey)) #ifndef NO_FILE static FILE *InFile = NULL; /* the input file */ #define ERROR _OSERR /* the system's error variable */ extern int ERROR; /* * This structure maps a character string to a numeric value. It is used * for mapping key names to keyboard scan codes and key action names to * action numbers. */ struct Definition { char *Name; UBYTE Code; }; /* * Qualifier[] maps the names of the qualifier keys to their corresponding * bit positions within the ie_Qualifier field of an InputEvent. This List * is sorted by name. Note that LCOMMAND is equivalent to LAMIGA, etc. * Note also that there are some compound qualifier names, such as SHIFT. * These are expanded into more than one key definition. * * See devices/inputevent.h for more details on qualifier values. */ static struct Definition Qualifier[] = { {"ALT",20}, {"AMIGA",22}, {"CAPSLOCK",2}, {"CONTROL",3}, {"INTERRUPT",10}, {"KEYUP",31}, {"LALT",4}, {"LAMIGA",6}, {"LBUTTON",14}, {"LCOMMAND",6}, {"LSHIFT",0}, {"MBUTTON",12}, {"MULTIBROADCAST",11}, {"NUMERICPAD",8}, {"RALT",5}, {"RAMIGA",7}, {"RBUTTON",13}, {"RCOMMAND",7}, {"RELATIVEMOUSE",15}, {"REPEAT",9}, {"RSHIFT",1}, {"SHIFT",16}, }; #define MAXQUALIFIER (sizeof(Qualifier)/sizeof(struct Definition)) /* * AsciiToKeyCode[] maps ASCII characters to keyboard scan-codes. This array * is in ASCII order. SHIFT indicates that one of the shift keys must be * held down together with the correct key in order to produce that ASCII * character. Note, however, that upper- and lower-case letters both are * mapped to un-shifted keys. */ static UBYTE AsciiToKeyCode[] = { 0x01 | SHIFT, /* ! */ 0x2A | SHIFT, /* " */ 0x03 | SHIFT, /* # */ 0x04 | SHIFT, /* $ */ 0x05 | SHIFT, /* % */ 0x07 | SHIFT, /* & */ 0x2A, /* ' */ 0x09 | SHIFT, /* ( */ 0x0A | SHIFT, /* ) */ 0x08 | SHIFT, /* * */ 0x0C | SHIFT, /* + */ 0x38, /* , */ 0x0B, /* - */ 0x39, /* . */ 0x3A, /* / */ 0x0A, /* 0 */ 0x01, /* 1 */ 0x02, /* 2 */ 0x03, /* 3 */ 0x04, /* 4 */ 0x05, /* 5 */ 0x06, /* 6 */ 0x07, /* 7 */ 0x08, /* 8 */ 0x09, /* 9 */ 0x29 | SHIFT, /* : */ 0x29, /* ; */ 0x38 | SHIFT, /* < */ 0x0C, /* = */ 0x39 | SHIFT, /* > */ 0x3A | SHIFT, /* ? */ 0x02 | SHIFT, /* @ */ 0x20, /* A */ 0x35, /* B */ 0x33, /* C */ 0x22, /* D */ 0x12, /* E */ 0x23, /* F */ 0x24, /* G */ 0x25, /* H */ 0x17, /* I */ 0x26, /* J */ 0x27, /* K */ 0x28, /* L */ 0x37, /* M */ 0x36, /* N */ 0x18, /* O */ 0x19, /* P */ 0x10, /* Q */ 0x13, /* R */ 0x21, /* S */ 0x14, /* T */ 0x16, /* U */ 0x34, /* V */ 0x11, /* W */ 0x32, /* X */ 0x15, /* Y */ 0x31, /* Z */ 0x1A, /* [ */ 0x0D | SHIFT, /* \ */ 0x1B, /* ] */ 0x06 | SHIFT, /* ^ */ 0x0B | SHIFT, /* _ */ 0x00, /* ` */ 0x20, /* a */ 0x35, /* b */ 0x33, /* c */ 0x22, /* d */ 0x12, /* e */ 0x23, /* f */ 0x24, /* g */ 0x25, /* h */ 0x17, /* i */ 0x26, /* j */ 0x27, /* k */ 0x28, /* l */ 0x37, /* m */ 0x36, /* n */ 0x18, /* o */ 0x19, /* p */ 0x10, /* q */ 0x13, /* r */ 0x21, /* s */ 0x14, /* t */ 0x16, /* u */ 0x34, /* v */ 0x11, /* w */ 0x32, /* x */ 0x15, /* y */ 0x31, /* z */ 0x1A | SHIFT, /* { */ 0x0D | SHIFT, /* | */ 0x1B | SHIFT, /* } */ 0x00 | SHIFT, /* ~ */ }; #define MAXASCII sizeof(AsciiToKeyCode) /* * Key[] maps key names to their keyboard scan-codes. This array is sorted * by name. SHIFT means that a SHIFT key must be held down in addition to * the indicated key. Some keys have more than one name (e.g., ESCAPE is * equivalent to ESC). Note that pressing a qualifier key also can be * detected. */ static struct Definition Key[] = { {"BACKSPACE",0x41}, {"BS", 0x41}, {"CAPSLOCKKEY",0x62}, {"COLON",0x29 | SHIFT}, {"COMMA",0x38}, {"CONTROLKEY",0x63}, {"DASH",0x0B}, {"DEL",0x46}, {"DELETE",0x46}, {"DOT",0x3C}, {"DOWNARROW",0x4D}, {"ENTER",0x42}, {"ESC",0x45}, {"ESCAPE",0x45}, {"F1",0x50}, {"F10",0x59}, {"F2",0x51}, {"F3",0x52}, {"F4",0x53}, {"F5",0x54}, {"F6",0x55}, {"F7",0x56}, {"F8",0x57}, {"F9",0x58}, {"HELP",0x5F}, {"KP0",0x0F}, {"KP1",0x1D}, {"KP2",0x1E}, {"KP3",0x1F}, {"KP4",0x2D}, {"KP5",0x2E}, {"KP6",0x2F}, {"KP7",0x3D}, {"KP8",0x3E}, {"KP9",0x3F}, {"LALTKEY",0x64}, {"LAMIGAKEY",0x66}, {"LCOMMANDKEY",0x66}, {"LEFTARROW",0x4F}, {"LSHIFTKEY",0x60}, {"MINUS",0x4A}, {"RALTKEY",0x65}, {"RAMIGAKEY",0x67}, {"RCOMMANDKEY",0x67}, {"RETURN",0x44}, {"RIGHTARROW",0x4E}, {"RSHIFTKEY",0x61}, {"SPACE",0x40}, {"TAB",0x42}, {"UPARROW",0x4C}, }; #define MAXKEY (sizeof(Key)/sizeof(struct Definition)) /* * Action[] maps key action names to their action numbers (used by the * input handler to perform the action when the key is pressed). This array * is sorted by name. */ static struct Definition Action[] = { {"BACK-WINDOW-TO-FRONT", BACKTOFRONT}, {"CLOSE-WINDOW", CLOSETHEWINDOW}, {"FRONT-WINDOW-TO-BACK", FRONTTOBACK}, {"ICON-TO-WINDOW", ICONTOWINDOW}, {"NEXT-WINDOW", ACTIVATENEXT}, {"PREVIOUS-WINDOW", ACTIVATEPREVIOUS}, {"SCREEN-TO-BACK", SCREENTOBACK}, {"SCREEN-TO-FRONT", SCREENTOFRONT}, {"SELECT-NEXT-ICON", SELECTNEXTICON}, {"WINDOW-TO-BACK", WINDOWTOBACK}, {"WINDOW-TO-FRONT", WINDOWTOFRONT}, {"WINDOW-TO-ICON", WINDOWTOICON}, }; #define MAXACTION (sizeof(Action)/sizeof(struct Definition)) #endif /* * Some shorthand macros used to define the default key layout */ #define RAMIGA IEQUALIFIER_RCOMMAND #define RSHIFT IEQUALIFIER_RSHIFT #define UPARROW 0x4C #define DOWNARROW 0x4D #define RIGHTARROW 0x4E #define LEFTARROW 0x4F #define BSKEY 0x41 #define TABKEY 0x42 #define RETURNKEY 0x44 #define DELETEKEY 0x46 #define HOTKEY(q,c,a) {{c,0,q},{0xFF,a,RAMIGA|RSHIFT}} /* * DefaultKey[] maps the default key layout. This array is sorted by * KeyCode value. Change this array to change the default key bindings. */ static struct HotKey DefaultKey[] = { HOTKEY( RAMIGA, BSKEY, ICONTOWINDOW), HOTKEY( RAMIGA, TABKEY, SELECTNEXTICON), HOTKEY( RAMIGA, RETURNKEY, WINDOWTOICON), HOTKEY( RAMIGA, DELETEKEY, CLOSETHEWINDOW), HOTKEY( RAMIGA, UPARROW, WINDOWTOFRONT), HOTKEY( RSHIFT | RAMIGA, UPARROW, SCREENTOFRONT), HOTKEY( RAMIGA, DOWNARROW, WINDOWTOBACK), HOTKEY( RSHIFT | RAMIGA, DOWNARROW, SCREENTOBACK), HOTKEY( RAMIGA, RIGHTARROW, ACTIVATENEXT), HOTKEY( RSHIFT | RAMIGA, RIGHTARROW, FRONTTOBACK), HOTKEY( RAMIGA, LEFTARROW, ACTIVATEPREVIOUS), HOTKEY( RSHIFT | RAMIGA, LEFTARROW, BACKTOFRONT), }; #define DEFAULTSIZE (sizeof(DefaultKey)/sizeof(struct HotKey)) #ifndef NO_FILE /* * Error() * * Print an error message and the line number where the error occured. * Return the error value. */ static int Error(s,x1,x2,x3) char *s, *x1,*x2,*x3; { printf("Line %2d: ",LineCount); printf(s,x1,x2,x3); printf("\n"); return(BADVALUE); } /* * GetNextWord() * * Isolate the next word in the line read from the file. * If we are not at the end of the line, then * skip over leading spaces, * set CurWord to point to the beginning of the word, * while we are not at the end of the word, * check if the current character is a word delimiter: * if it is a space or a tab, * skip additional spaces or tabs, * set the terminator character, * and end the word. * (At this point, CurPos will be pointing to the "real" delimiter, * or to the beginning of the next word, if the delimiter really was * a space). * if it was a NULL, convert it to a new-line. * if it was a dash, comma, colon or new-line, * save the termination character for later, * replace the charactger with a NULL so that CurWord will end at * the end of the word, * and stop looking for more of the word. * otherwise * if we're still looking for the end of the word (i.e., we have not * ended, it by hitting a space), * if its unprintable or the current word is more than one character * long and the current character is not alphanumeric, * then record the bad character and end the word * go on to the next character (i.e., add the current one to the word) */ static void GetNextWord() { short NotDone = TRUE; char c; if (TerminationChar != '\n') { while (*CurPos == ' ' || *CurPos == '\t') CurPos++; CurWord = CurPos; while (NotDone) { if (*CurPos == ' ' || *CurPos == '\t') { *CurPos = '\0'; while (*(++CurPos) == ' ' || *CurPos == '\t'); TerminationChar = ' '; NotDone = FALSE; } switch(c = *CurPos) { case '\0': c = *CurPos = '\n'; case '-': case ',': case ':': case '\n': TerminationChar = c; *CurPos++ = '\0'; NotDone = FALSE; break; default: if (NotDone) { if (NOTPRINTABLE(c) || (CurPos != CurWord && NOTALPHANUM(c))) { TerminationChar = c; NotDone = FALSE; } CurPos++; } break; } } } } /* * FindWord() * * Search the KeyWord array (containing Count entries) for an entry with * Name equal to theWord. Return the corresponding Code value, or BADVALUE * if theWord does not appear in the KeyWord array. * * KeyWord[] must be sorted by name, since we use a binary search to find * theWord witin it. */ static int FindWord(theWord,KeyWord,Count) char *theWord; struct Definition KeyWord[]; int Count; { int value = BADVALUE; register short Min,Max, Num; register int comp; Max = Count; Min = -1; while ((Num = (Min + Max) >> 1) != Min && value == BADVALUE) { comp = stricmp(theWord,KeyWord[Num].Name); if (comp < 0) Max = Num; else if (comp > 0) Min = Num; else value = KeyWord[Num].Code; } return(value); } /* * FindQualifier() * * Find a qualifier name in the Qualifier[] array. */ #define FindQualifier(w) FindWord(w,Qualifier,MAXQUALIFIER) /* * FindKeyCode() * * Find the scan-code for the given key name. If the key name is a single * ASCII character, use the AsciiToKeyCode array to look up the scan-code * directly, otherwise use FindWord() to search the Key[] array. */ static int FindKeyCode(theWord) char *theWord; { int value = BADVALUE; if (strlen(theWord) == 1) { if (PRINTABLE(*theWord)) value = AsciiToKeyCode[*theWord-'!']; } else { value = FindWord(theWord,Key,MAXKEY); } return(value); } /* * GetKeyCode() * * Parse a set of qualifiers and a key name and return the KeyCode longword * that describes the designated key. SHIFT, AMIGA, and ALT flags are * used to indicate when more than one key is designated. Return BADVALUE * if there is an error parsing the line. * * Get the next word on the line, and check the termination character. * Qualifiers end with dashes, commas, or spaces; key-names end with a colon. * Try to find the qualifier or key-name in the proper list, and give an error * if it can not be found, or if the name is null. For a qualifier, set its * flag bit in the KeyCode longword. For key-names, set the scan-code and * the set the SHIFT bit in the qualifier flag bits if necessary. * If the end of the line is reached, display an error. If some other * delimiter was found, then display an error (making unprintable characters * printable). * * Once a key-name is found, stop looking for more words. */ static void GetKeyCode(theKey) long *theKey; { short NotDone = TRUE; int value; *theKey = 0; while (NotDone) { GetNextWord(); switch(TerminationChar) { case '-': case ',': case ' ': if (strlen(CurWord)) { value = FindQualifier(CurWord); if (value > BADVALUE) *theKey |= (1 << value); else *theKey = Error("Unrecognized key qualifier '%s'",CurWord); } else { *theKey = Error("Missing qualifier keyword"); } break; case ':': if (strlen(CurWord)) { value = FindKeyCode(CurWord); if (value > BADVALUE) { *theKey |= ((value & (~SHIFT)) << 24) | ((value & SHIFT) << 9); } else { *theKey = Error("Unrecognized key name '%s'",CurWord); } } else { *theKey = Error("Key name not specified"); } NotDone = FALSE; break; case '\n': *theKey = Error("Key name ends prematurely"); NotDone = FALSE; break; default: if ((TerminationChar & 0x7F) >= ' ') *theKey = Error("Illegal delimiter character '%c'", (char)TerminationChar); else *theKey = Error("Illegal delimiter character '^%c'", (char)((TerminationChar & 0x7F) + '@')); break; } } } /* * GetKeyAction() * * Parse the rest of the input line for a key-action keyword. First, remove * leading and training blanks, and replace the final new-line with a NULL. * Look up the remainder of the line (if any) in the Action[] array, and * if it is not found, report the error. */ static void GetKeyAction(theAction) short *theAction; { *theAction = BADVALUE; while (*CurPos == ' ' || *CurPos == '\t') CurPos++; CurWord = CurPos; CurPos = CurPos + strlen(CurWord) - 1; if (*CurPos == '\n') *CurPos-- = '\0'; while (*CurPos == ' ' || *CurPos == '\t') *CurPos-- = '\0'; if (*CurWord) { *theAction = FindWord(CurWord,Action,MAXACTION); if (*theAction == BADVALUE) Error("Unrecognized action '%s'",CurWord); } else { Error("No action specified"); } } /* * KeyCompare() * * Return a positive number if the first key is bigger than the second, * zero if they are equal, and a negative number if the second key is * bigger. This routine is used by mSort() to sort the keys. */ static int KeyCompare(key1,key2) struct HotKeyItem *key1, *key2; { return(key1->hki_KeyCode - key2->hki_KeyCode); } /* * * KeyDispose() * * Remove a duplicate key definition and report the fact that a key is * multiply defined (it takes a little work to get the qualifier and key * names back out of the arrays). This routine is called by mSort() when * it finds duplicate keys. */ static void KeyDispose(key) struct HotKeyItem *key; { short i; UBYTE code = key->hki_Code & 0x7F; int KeyNotFound = TRUE; long mask = 0xFFFFFFFF; printf("Key "); for (i=0; i<MAXQUALIFIER; i++) if (key->hki_KeyCode & (1 << Qualifier[i].Code) & mask) { printf("%s-",Qualifier[i].Name); mask &= ~(1 << Qualifier[i].Code); } for (i=0; i<MAXKEY && KeyNotFound; i++) if (code == Key[i].Code) { printf("%s",Key[i].Name); KeyNotFound = FALSE; } for (i=0; i<MAXASCII && KeyNotFound; i++) { if (code == AsciiToKeyCode[i]) { printf("%c",i+'!'); KeyNotFound = FALSE; } } printf(" multiply defined\n"); KeyCount--; key->Next = key->Prev = NULL; FreeMem(key,sizeof(*key)); } /* * GetKeyList() * * Read each line from the file (incrementing the line count as we go), * and skip leading spaces and blank lines. Get the key code and key action * specified on the line. If no error was found, add the key definition * to the linked list of keys defined. If SHIFT, AMIGA, or ALT were specified, * then add one key each for the left and right version of that qualifier. */ static void GetKeyList() { long theKey; short theAction; struct HotKeyItem *TempKey; UWORD mask,multikeys; extern char *fgets(); while (feof(InFile) == FALSE) { CurPos = fgets(InputLine,LINESIZE,InFile); TerminationChar = '\0'; LineCount++; while (*CurPos == ' ' || *CurPos == '\t') CurPos++; if (CurPos != NULL && *CurPos != '\0' && *CurPos != '\n') { GetKeyCode(&theKey); GetKeyAction(&theAction); if (theKey != BADVALUE && theAction != BADVALUE) { multikeys = (theKey >> 15) & 0xFE; multikeys |= multikeys << 1; if (multikeys == 0) multikeys = 1; for (mask=1; multikeys; mask<<=1,multikeys>>=1) { if (multikeys & 1) { NEW(HotKeyItem,TempKey); TempKey->hki_KeyCode = theKey; TempKey->hki_Flags = 0; TempKey->hki_Qual |= mask >> 1; TempKey->hki_KeyMask = 0xFFFFFFFF; TempKey->hki_Action = theAction; TempKey->Next = KeyList; KeyList = TempKey; KeyCount++; } } } } } } /* * SetKeyMasks() * * For each key scan-code, we OR together the qualifier masks for all the * definitions for that scan-code and set the key Mask value for each * key with that scan-code to the final ORed mask. That is, the Mask value * indicates what qualifiers are important for determining when a key has * been pressed (and distinguishing it from other definitions using the * same scan-code but different qualifiers). */ static void SetKeyMasks() { struct HotKeyItem *CurKey = KeyList; struct HotKeyItem *LastKey = CurKey; UWORD Mask; while (LastKey) { Mask = 0; while (CurKey && CurKey->hki_Code == LastKey->hki_Code) { Mask |= CurKey->hki_Qual; CurKey = CurKey->Next; } if (Mask == 0) Mask = KEYMASK; do { LastKey->hki_Mask = Mask; LastKey = LastKey->Next; } while (LastKey != CurKey); } } /* * MakeKeyArray() * * If there are any keys defined, allocate enough space for the KeyArray * that will contain the key definitions, then go through the list and * copy the definitions into the array. Free each item from the list once it * is copied. The array saves space (it does not need to contain pointers * to next and previous items), and allows for easy implementation of a * binary search on the array. */ static void MakeKeyArray() { struct HotKeyItem *TempKey; short i; if (KeyCount) { KeyArray = (struct HotKey *)New("KeyArray",KEYARRAYSIZE); for (i=0; i<KeyCount; i++) { KeyArray[i].hk_KeyCode = KeyList->hki_KeyCode; KeyArray[i].hk_KeyMask = KeyList->hki_KeyMask; TempKey = KeyList; KeyList = KeyList->Next; FreeMem(TempKey,sizeof(*TempKey)); } } } #endif /* * MakeDefaultArray() * * Copy the DefaultKey[] array into a dynamically allocated array that can * be passed to the input handler and still remain in memory even when the * original process is unloaded. */ static void MakeDefaultArray() { short i; KeyCount = DEFAULTSIZE; KeyArray = (struct HotKey *)New("KeyArray",KEYARRAYSIZE); for (i=0; i<KeyCount; i++) { KeyArray[i].hk_KeyCode = DefaultKey[i].hk_KeyCode; KeyArray[i].hk_KeyMask = DefaultKey[i].hk_KeyMask; } } /* * GetKeyArray() * * If there is a command-line argument, then * it must be a file name, so try to open it (error if there is a problem). * Create the key definition list from the lines in the file. * If there were no valid key definitions, * say so, * otherwise, * sort the key list, * set the key masks for each scan-code, * make the key array from the sorted list. * otherwise (there was no file name given, so) * make the key array from the default key list. */ void GetKeyArray(argc,argv) int argc; char *argv[]; { #ifndef NO_FILE extern struct HotKeyItem *mSort(); if (argc > 1) { InFile = fopen(argv[1],"r"); if (InFile == NULL) DoExit("Can't Open File '%s': Error %d",argv[1],ERROR); GetKeyList(); if (KeyCount == 0) { DoExit("No valid key definitions found in file '%s'",argv[1]); } else { KeyList = mSort(KeyList,KeyCompare,KeyDispose); SetKeyMasks(); MakeKeyArray(); } } else #endif { MakeDefaultArray(); } } SHAR_EOF cat << \SHAR_EOF > mSort.c /* * MSORT.C version 1.0 18-Nov-1986 * * A general-purpose implementation of a merge-sort for linked lists. * * Written for the Commodore Amiga 1000, version 1.1 * using Lattice C v3.03 by Davide P. Cervone * * The merge-sort algorithm takes advantage of the fact that it is * easy to combine two sorted lists into one sorted list: just keep * taking the smaller item off the top of the two lists and add it * to the bottom of the new list until the original lists are empty. * * The sort algorithm first places each item to be sorted in its * own list (one item long). Pairs of these singleton lists are merged * in the manner described above, and we are left with half as many lists * as before, each two items long. Pairs of these lists are combined to * form half as many lists again, each four items long. This process is * repeated until only one list remains. This is the final, sorted list. * * The merge-sort is ideal for linked lists, since it does not require * random access look-ups (which are difficult in linked-lists). It does * not require extra "work-space", so no memory is wasted. Finally, its * result is a simple, linked-list structure, ready to use (unlike some sort * methods that result in trees or other structures were it is dificult to * get from one item to the next). * * The merge-sort is fairly efficient. In it's worst case, it takes * n * (log(n) - 1) + 1 comparisons to sort n items (where the log() * function is the log to base 2). Thus, for 1024 items, the maximum * number of comparisons is 1024*(10-1)+1 = 9217, or approximately 9 * comparisons per item. And that's its worst case! Compare this to * a worst case of n*(n-1)/2 for some popular sorts (e.g., the tree sort). * The worst case for the tree sort for 1024 items is 523776 compares! * * In its best case, the merge-sort takes n * log(n) / 2 comparisons. * For our example of n=1024, that's 5120 comparisons. For the tree sort, * the minimum is approximately n * (log(n) - 2) comparisons, for a * minimum of 8192 comparisons for 1024 items. * * Note that the maximum comparisons that will ever occur with the merge-sort * is no more than n more than the minimum number possible with the tree * sort. * * While these numbers look impressive, there is one drawback: the merge- * sort is heavily weighted toward its worst case, since the merge sort skips * comparisons only when one list runs out of items more than one item before * the other. In practice, the average number of comparisons made by the * merge-sort is a consistant 96% of the maximum number. This gives you a very * acurate estimate of the number of comparisons (hence the time it takes) to * sort a list of a particular size. Since the maximum value is so close to * the most probable value, you don't have to worry about pathelogic cases * slowing down your sort routine (for a tree sort, the "pathelogic" case * is a pre-sorted list, which may not be an uncommon case). * * In a comparison against the tree sort using random data (the kind the * tree sort handles best), the merge-sort was found to take 96% of its * maximum number of sorts, while the tree sort averaged about 38% more than * it's minimum (there was considerably more variation with the tree sort). * Overall, the tree sort was found to take a consitant 25% more comparisons * than the merge-sort on lists of length 300 items to 10000 items. For * 100 items, the difference drops off to about 15%, and for 10 items, the two * sorts are about the same, with the merge-sort comming out a little bit * ahead (one or two comparisons out of an average of 23). * * All in all, the merge-sort is an effective, fast, and very useful sort * that compares favorably with other sort algorithms. */ #include <exec/types.h> #define ADD_TO_NEWLIST(l) (newlist = (newlist->Next = l)) /* * The linked list is a double-linked list (there are pointers to both * the previous and the following item). The end of the list is marked * by NULL pointers. * * The pointers should appear at the top of the structure you intend to * sort, so if you are sorting a linked list of people's names, you might * use a structure like the following in your main program: * * struct ListItem * { * struct ListItem *Next; * struct ListItem *Prev; * char FirstName[30]; * char MiddleInitial; * char LastName[50] * }; * * The pointers must be the first fields so that mSort() and Merge() can * find the pointers without having to know anything about the structure * of the data you are sorting. */ /* * The #ifndef is so that this module can be #included into the program * that calls mSort(), rather than requiring it to be linked in separately. * To avoid a conflicting definition error, #define NextList to be the * name of the pointer to the previous item as it is declared in your * program (for the example given above, user #define NextList Prev). * be sure that the #define and the struct ListItem declaration both * appear before the #include for this module */ #ifndef NextList struct ListItem { struct ListItem *Next; struct ListItem *NextList; }; #endif /* * These are the compare and dispose functions passed to mSort() (see * mSort() for more details), and are assigned to global variables so that * they don't have to be passed to mMerge() every time it is called. */ static int (*mCompare)() = NULL; static void (*mDispose)() = NULL; /* * mMerge() * * combines two sorted linked lists into one sorted linked list, using * the mCompare() function to determine the sorting, and the dispose() * function to remove duplicate values. * * list1 a pointer to the first linked list * list2 a pointer to the second linked list */ struct ListItem * mMerge(list1,list2) struct ListItem *list1, *list2; { static struct ListItem top_item; static struct ListItem *newlist, *temp; static int result; top_item.Next = top_item.NextList = NULL; newlist = &top_item; /* * While there are still items in each list, compare the top items in the * lists. Link the smaller one to the end of the new, combined list, and * pop the item off the top of the old list. If the top items are equal, * then add one of them to the new list, and if there is a dispose function, * get rid of the other one, otherwise add the second one into the list * as well. * * When one of the lists is exauseted, add any remaining items from * the other list onto the end of the result list, and return a pointer * to the final, sorted list. */ while (list1 != NULL && list2 != NULL) { result = (*mCompare)(list1,list2); if (result < 0) { ADD_TO_NEWLIST(list1); list1 = list1->Next; } else if (result > 0) { ADD_TO_NEWLIST(list2); list2 = list2->Next; } else { ADD_TO_NEWLIST(list1); list1 = list1->Next; if (mDispose == NULL) { ADD_TO_NEWLIST(list2); list2 = list2->Next; } else { temp = list2; list2 = list2->Next; temp->Next = temp->NextList = NULL; (*mDispose)(temp); } } } if (list1 != NULL) ADD_TO_NEWLIST(list1); else if (list2 != NULL) ADD_TO_NEWLIST(list2); return(top_item.Next); } /* * mSort() * * sorts a linked list of items of any sort, using a user-provided comparison * routine. Duplicate items will be removed if the dispose routine is * provided. The result list will be a doubly-linked list (pointers go both * forward and backward) that is sorted. mSort() returns a pointer to * the top of the result list. * * cur_item a pointer to the begining of the original, unsorted * list. * compare() a pointer to a function that compares two * ListItems and returns a negative number if * the first item is smaller, zero if they are * equal, and a positive number if the first * item is larger than the second. Compare() * should take two parameters, the pointers * to the ListItems that are to be compared. * dispose() disposes of a duplicate ListItem. Dispose() * should accept one parameter, the pointer to * the ListItem to be removed. Dispose() should * free any memory allocated to the ListItem. * This list item will not appear in the final * linked list. If dispose in NULL, then * duplicate items are retained in the list. */ struct ListItem * mSort(cur_item,compare,dispose) struct ListItem *cur_item; int (*compare)(); void (*dispose)(); { static struct ListItem *first_item, *next_item; /* * Put the compare and dispose routines where mMerge() can find them */ mCompare = compare; mDispose = dispose; first_item = NULL; if (cur_item != NULL) { /* * Put each item in the original list into a separate list. Use the * NextList field to link the individual lists into a list (a linked list * of linked lists). Link the end of the list to the begining so we get * a ring rather than a list. */ first_item = cur_item; do { next_item = cur_item->Next; cur_item->Next = NULL; cur_item->NextList = (next_item != NULL)? next_item : first_item; cur_item = next_item; } while (cur_item != NULL); /* * While there's more than one list left in the ring (i.e., the list * following the current one is not itself), then merge the current list * with the one following it (keep track of the first list after the ones * we're combining so we can link the result of the merge back into * the ring). Finally, if there were more than two lists in the ring * (i.e., if the current list is neither equal to the one preceding it nor * equal to the one after the list with which it was combined), then * link the result list into the ring, otherwise link the result list * to itself (since there were only two lists in the ring, their * merger should leave us with only one). Move down the ring, so we * can merge the next two lists in the ring. */ while ((cur_item = first_item->NextList) != first_item) { next_item = cur_item->NextList->NextList; cur_item = mMerge(cur_item,cur_item->NextList,compare,dispose); if (cur_item == first_item || cur_item == next_item) { cur_item->NextList = cur_item; } else { first_item->NextList = cur_item; cur_item->NextList = next_item; } first_item = cur_item; } /* * When there's only one list left, traverse the list, setting the * reverse pointers so that the list is properly linked both directions. */ first_item->NextList = NULL; while (cur_item->Next != NULL) { cur_item->Next->NextList = cur_item; cur_item = cur_item->Next; } } return(first_item); } SHAR_EOF cat << \SHAR_EOF > wKeys-Handler.c /* * wKeys-Handler.c Input Handler for wKeyw, which moves and activates * windows and screensin response to keystrokes * * Copyright (c) 1987,1988 by Davide P. Cervone * You may use this code provided this copyright notice is left intact. */ #include <exec/types.h> #include <exec/memory.h> #include <devices/inputevent.h> #include <intuition/intuitionbase.h> #include "wKeys.h" static char *program = "wKeys-Handler"; static int version = 3; static char *date = "January 1988"; static char *author = "Copyright (c) 1987,1988 by Davide P. Cervone"; extern struct Layer *WhichLayer(); extern struct IntuiMessage *GetMsg(); extern struct IntuiMessage *AllocMem(); extern void myHandlerStub(); #define WINDOW(layer) ((struct Window *)((layer)->Window)) #define SCREENTOP\ (theScreen->TopEdge << ((theScreen->ViewPort.Modes & LACE)? 0: 1)) #define IMSIZE ((ULONG)sizeof(struct IntuiMessage)) #define NEWMESSAGE(m) (m = AllocMem(IMSIZE,MEMF_PUBLIC | MEMF_CLEAR)) #define FREEMESSAGE(m) FreeMem(m,IMSIZE); struct IntuitionBase *IntuitionBase = NULL; struct LayersBase *LayersBase = NULL; struct SysBase *SysBase = NULL; static struct HotKey *Key = NULL; static int KeyCount = 0; static struct MsgPort *ReplyPort = NULL; /* * Setup() * * wKeys calls LoadSeg() to get this handler into memory. The segment * that it gets points to this routine. wKeys calls Setup() and * passes the IntuitionBase, LayersBase and SysBase pointers that it * has initialized (with OpenLibrary()). wKeys also passes the KeyArray * and KeyCount which hold the key bindings. Setup returns a pointer to * the actual input handler, which wKeys installs, and sets the version * number so that hotKey can report the handler's version. */ long Setup(Ibase,Lbase,Sbase,theKeys,Count,Port,VersionPtr) struct IntuitionBase *Ibase; struct LayersBase *Lbase; struct SysBase *Sbase; struct HotKey *theKeys; struct MsgPort *Port; int *VersionPtr; int Count; { IntuitionBase = Ibase; LayersBase = Lbase; SysBase = Sbase; Key = theKeys; KeyCount = Count; ReplyPort = Port; *VersionPtr = version; return((long) &myHandlerStub); } /* * TopWindow() * * Find the top window of the specified screen. Start at the top layer of * the screen and move backward as long as the layer exists and has no * window connected to it. Return the window associated with the final * layer, if any. */ static struct Window *TopWindow(theScreen) struct Screen *theScreen; { struct Window *theWindow = NULL; struct Layer *theLayer; theLayer = theScreen->LayerInfo.top_layer; while (theLayer && WINDOW(theLayer) == NULL) theLayer = theLayer->back; if (theLayer) theWindow = WINDOW(theLayer); return(theWindow); } /* * BottomWindow() * * Find the bottom window of the specified screen. Start at the top layer * and as long as the layer exists, go to the next layer back. If the * layer has a window attached, consider that to be the bottom window until * a lower one is found. */ static struct Window *BottomWindow(theScreen) struct Screen *theScreen; { struct Window *theWindow = NULL; struct Layer *theLayer = theScreen->LayerInfo.top_layer; while (theLayer) { if (WINDOW(theLayer) && isIconified(WINDOW(theLayer)) == FALSE) theWindow = WINDOW(theLayer); theLayer = theLayer->back; } return(theWindow); } /* * NextWindow() * * Find the next window below the specified window (wrap arround to the top * if the window is the bottom one). Start with the window's layer and go * back until a layer with a window is found, or no more layers exist. If * a window was found, return it, otherwise, use the top window. */ static struct Window *NextWindow(theWindow) struct Window *theWindow; { struct Layer *theLayer = theWindow->WLayer; do theLayer = theLayer->back; while (theLayer && (WINDOW(theLayer) == NULL || isIconified(WINDOW(theLayer)))); if (theLayer) theWindow = WINDOW(theLayer); else theWindow = TopWindow(theWindow->WScreen); return(theWindow); } /* * PreviousWindow() * * Find the window that is on top of the specified window (or NULL if there * are no windows above it). Start with the window's layer, and move to * the layer in front until a layer with a (different) window is found, or * until no more layers exist. If a window was found, return it, otherwise * return NULL. */ static struct Window *PreviousWindow(theWindow) struct Window *theWindow; { struct Layer *theLayer = theWindow->WLayer; do theLayer = theLayer->front; while (theLayer && (WINDOW(theLayer) == NULL || WINDOW(theLayer) == theWindow)); if (theLayer) theWindow = WINDOW(theLayer); else theWindow = NULL; return(theWindow); } /* * BackScreenToFront() * * Bring the bottom-most screen to the top, and activate its top window. * While there is a screen following the current one, move the the next screen. * Bring that screen to the front and find its top window. If one was found, * activate the window. */ static void BackScreenToFront() { struct Screen *theScreen = IntuitionBase->FirstScreen; struct Window *theWindow; if (theScreen) { while (theScreen->NextScreen) theScreen = theScreen->NextScreen; ScreenToFront(theScreen); theWindow = TopWindow(theScreen); if (theWindow) ActivateWindow(theWindow); } } /* * FrontScreenToBack() * * Move the top screen to the back and activate the top window on the new * top screen. */ static void FrontScreenToBack() { struct Screen *theScreen = IntuitionBase->FirstScreen; struct Window *theWindow; if (theScreen) { ScreenToBack(theScreen); theScreen = IntuitionBase->FirstScreen; if (theScreen) { theWindow = TopWindow(theScreen); if (theWindow) ActivateWindow(theWindow); } } } /* * ActivatePreviousWindow() * * Get the window previous to the current window (if none, then get the * bottom window in the active screen), and activate that window. */ static void ActivatePreviousWindow() { struct Window *theWindow = PreviousWindow(IntuitionBase->ActiveWindow); if (theWindow == NULL) theWindow = BottomWindow(IntuitionBase->ActiveScreen); if (theWindow) ActivateWindow(theWindow); } /* * ActivateNextWindow() * * Get the window below the current window and activate it. */ static void ActivateNextWindow() { struct Window *theWindow = NextWindow(IntuitionBase->ActiveWindow); if (theWindow) ActivateWindow(theWindow); } /* * CurrentWindowToBack() * * Send the current window to the back of the list. */ static void CurrentWindowToBack() { struct Window *theWindow = IntuitionBase->ActiveWindow; if (theWindow && (theWindow->Flags & BACKDROP) == 0) WindowToBack(theWindow); } /* * CurrentWindowToFront() * * Send the current window to the top of the list. */ static void CurrentWindowToFront() { struct Window *theWindow = IntuitionBase->ActiveWindow; if (theWindow) WindowToFront(theWindow); } /* * BackWindowToFront() * * Move the bottom window to the top and activate it. Get the bottom window, * skipping over backdrop windows. If one is found, bring it to the front, * and activate it. */ static void BackWindowToFront() { struct Window *theWindow = BottomWindow(IntuitionBase->ActiveScreen); if (theWindow) { while (theWindow && (theWindow->Flags & BACKDROP)) theWindow = PreviousWindow(theWindow); if (theWindow) { WindowToFront(theWindow); ActivateWindow(theWindow); } } } /* * FrontWindowToBack() * * Move the top window to the back, and activate the new top window. * Get the top window, and then the window following it. Send the top window * to the back, and activate the next window. */ static void FrontWindowToBack() { struct Window *theWindow = TopWindow(IntuitionBase->ActiveScreen); struct Window *nextWindow = NextWindow(theWindow); if (theWindow && (theWindow->Flags & BACKDROP) == 0) { WindowToBack(theWindow); if (nextWindow) ActivateWindow(nextWindow); } } /* * CloseCurrentWindow() * * If the current window has the CLOSEWINDOW IDCMP flag, then * send it a CLOSEWINDOW IDCMP message. Unfortunately, the workbench * has the CLOSWINDOW flag set, and it crashes if you send it a close * message; therefore, CloseCurrentWindow will not sent a CLOSWINDOW * event to a BACKDROP window. This seemed the easiest way to rule out * the workbench without too much overhead. * * The message will be replied to the ReplyPort, which is checked in the * input handler. Any messages that get returned are freed. */ static void CloseCurrentWindow() { struct Window *theWindow = IntuitionBase->ActiveWindow; struct IntuiMessage *theMessage; if (theWindow && (theWindow->IDCMPFlags & CLOSEWINDOW) && (theWindow->Flags & BACKDROP) == 0) { if (NEWMESSAGE(theMessage)) { theMessage->Class = CLOSEWINDOW; theMessage->IDCMPWindow = theWindow; theMessage->ExecMessage.mn_ReplyPort = ReplyPort; PutMsg(theWindow->UserPort,theMessage); } } } /* * WindowToIcon() * * Iconify the current window if wIconify is running. */ static void WindowToIcon() { struct Window *theWindow = IntuitionBase->ActiveWindow; if (theWindow) wIconifyWindow(theWindow); } /* * IconToWindow() * * Restore the selected wIconify icon to a window. The workbench must * be the active window, and wIconify must be running, and a window icon * must be selected. */ static void IconToWindow() { wRestoreWindow(NULL); } /* * SelectNextIcon() * * Tells wIconify to select the next window icon on the workbench. If no * icon is selected, then select the first icon. */ static void SelectNextIcon() { wNextIcon(); } /* * Array of functions that perform the different actions associated with * the hot-keys. These are called by the handler routine. */ typedef void (*FUNCTION)(); static FUNCTION Action[] = { NULL, &BackScreenToFront, &FrontScreenToBack, &ActivatePreviousWindow, &ActivateNextWindow, &CurrentWindowToBack, &CurrentWindowToFront, &BackWindowToFront, &FrontWindowToBack, &CloseCurrentWindow, &WindowToIcon, &IconToWindow, &SelectNextIcon }; /* * myHandler() * * This is the input handler. * First check if there are any returned CLOSEWINDOW events, then, * For each event in the event list: * If the event is a raw key event, then * make the KeyCode longword for that event's code and qualifier, * binary search the Key[] array for a matching entry (only consider * the qualifiers specified by the KeyMask). Since most keys pressed * will NOT match a hot-key, we want the search to be as fast as * possible, so we use a binary search rather than a linear search. * set NoHotKey if the key is not a hot key. * if the key was not a hot key, * go on to the next key * otherwise, * perform the function for the specified hot key, * remove the hot key from the event list. * * When all the events have been checked, return the event list so that * Intuition can do its thing. */ struct InputEvent *myHandler(EventList,data) struct InputEvent *EventList; APTR data; { register struct InputEvent **EventPtr = &EventList; register struct InputEvent *theEvent; register long theKey; register short Num,Min,Max; register long NoHotKey; struct IntuiMessage *theMessage; while (theMessage = GetMsg(ReplyPort)) FREEMESSAGE(theMessage); Forbid(); while((theEvent = *EventPtr) != NULL) { NoHotKey = TRUE; if (theEvent->ie_Class == IECLASS_RAWKEY) { theKey = KEY(theEvent); Max = KeyCount; Min = -1; while ((Num = (Min + Max) >> 1) != Min && (NoHotKey = (theKey & Key[Num].hk_KeyMask) - Key[Num].hk_KeyCode) != 0) if (NoHotKey > 0) Min = Num; else Max = Num; } if (NoHotKey) { EventPtr = &(theEvent->ie_NextEvent); } else { (*(Action[Key[Num].hk_Action]))(); *EventPtr = theEvent->ie_NextEvent; } } Permit(); return(EventList); } SHAR_EOF cat << \SHAR_EOF > HandlerStub.a CSECT text XREF _myHandler XDEF _myHandlerStub _myHandlerStub: MOVEM.L A0/A1,-(A7) JSR _myHandler ADDQ.L #8,A7 RTS END SHAR_EOF cat << \SHAR_EOF > wKeys.h /* * wKeys.h Structure definitions for wKeys program, which moves * and activates windows and screens via keystrokes. * * Copyright (c) 1987,1988 by Davide P. Cervone * You may use this code provided this copyright notice is left intact. */ /* * HotKey is the structure that holds the information needed to bind a * key to a function. Each HotKey is a pair of longwords, the first * represents a combination of the key-code and qualifier mask for the * key to be bound to a function. Using a single longword for this makes * it easy to compare against the currently pressed key. * * The second longword represents the qualifier mask that specifies the * qualifier flags that are important to distinguish this key binding from * other bindings with the same scan-code but different qualifiers. It is * the logical OR of all the qualifiers used by any key definition with * the same scan-code as this one. This longword contains 0xFF in the * same position where the first one has the scan-code, so ANDing this mask * against a KeyCode longword does not mask out the key code. * * The second longword also contains a byte that represents the action that * the key will perform when it is pressed. */ struct HotKey { union { struct { UBYTE Code; /* the InputEvent ie_Code field */ UBYTE Flags; /* SHIFT, AMIGA, and ALT (0 otherwise) */ UWORD Qualifiers; /* the InputEvent ie_Qualfiers field */ } PartCode; long FullCode; /* KeyCode longword */ } Key; union { struct { UBYTE FF; /* always 0xFF */ UBYTE Action; /* the action to be performed by this key */ UWORD Mask; /* the qualifier mask */ } PartMask; long FullMask; /* the KeyMask longword */ } Mask; }; #define hk_Code Key.PartCode.Code #define hk_Flags Key.PartCode.Flags #define hk_Qual Key.PartCode.Qualifiers #define hk_KeyCode Key.FullCode #define hk_FF Mask.PartMask.FF #define hk_Action Mask.PartMask.Action #define hk_Mask Mask.PartMask.Mask #define hk_KeyMask Mask.FullMask /* * This is the structure used in the linked list when building the key * definition array. It is the same as a HotKey except it contains pointers * to the next and previous items so that it can be sorted by mSort(). */ struct HotKeyItem { struct HotKeyItem *Next; struct HotKeyItem *Prev; struct HotKey HotKey; }; #define hki_Code HotKey.hk_Code #define hki_Flags HotKey.hk_Flags #define hki_Qual HotKey.hk_Qual #define hki_KeyCode HotKey.hk_KeyCode #define hki_FF HotKey.hk_FF #define hki_Action HotKey.hk_Action #define hki_Mask HotKey.hk_Mask #define hki_KeyMask HotKey.hk_KeyMask /* * These are the actions that can be perfomed. They must correspond to the * Action[] array in the input handler. You can add functions to the end * of this list provided you add them into the Action[] array in * wKeys-Handler.c, and the Action[] array in BindWKeys.c. */ #define SCREENTOFRONT 1 #define SCREENTOBACK 2 #define ACTIVATEPREVIOUS 3 #define ACTIVATENEXT 4 #define WINDOWTOBACK 5 #define WINDOWTOFRONT 6 #define BACKTOFRONT 7 #define FRONTTOBACK 8 #define CLOSETHEWINDOW 9 #define WINDOWTOICON 10 #define ICONTOWINDOW 11 #define SELECTNEXTICON 12 #define KEYCODE(qual,key) (((key)<<24)|(qual)) #define KEY(e) KEYCODE((e)->ie_Qualifier,(e)->ie_Code) SHAR_EOF cat << \SHAR_EOF > wKeys.lnk FROM LIB:c.o+wKeys.o+BindWKeys.o+mSort.o TO wKeys LIB LIB:lc.lib+LIB:amiga.lib NODEBUG SMALLDATA SMALLCODE SHAR_EOF cat << \SHAR_EOF > wKeys-Handler.lnk FROM wKeys-Handler.o+HandlerStub.o+wIconCalls.o TO wKeys-Handler LIB LIB:amiga.lib+LIB:lc.lib NODEBUG SMALLDATA SMALLCODE SHAR_EOF cat << \SHAR_EOF > HandlerStub.o.uu begin 17 HandlerStub.o M```#YP````1H86YD;&5R<W1U8BYO```````#Z`````%T97AT```#Z0````1(0 MYP#`3KD`````4(].=0`````#[X$```-?;7E(86YD;&5R```````!````!@$`1 >``1?;7E(86YD;&5R4W1U8@````````````````/R: `` end SHAR_EOF cat << \SHAR_EOF > wIconCalls.o.uu begin 17 wIconCalls.o M```#YP````-W:6-O;F-A;&QS+F\```/I````,DY5__1(>0````!.N0````!8- MCT*M__0K0/_X2H!G0"\\``$``7`:+P!.N0````!0CRM`__Q*@&<F($`Q;0`*5 M`!@A;0`,`!1"J``.+P`O+?_X3KD`````4(]P`2M`__0@+?_T3EU.=4Y5```OU M+0`(<`$O`&&,4(].74YU3E4``"\M``AP`B\`80#_>%"/3EU.=4*G<`4O`&$`* M_VA0CTYU3E7__$*M__Q*K0`(9Q(@;0`(""@`!P`99P9P`2M`__P@+?_\3EU.S M=0`````#[`````$````!````!@````````/O@0```U]&:6YD4&]R=```````G M``$````,@0```U]!;&QO8TUE;0````````$````J@0```E]0=71-<V<`````G M`0```%(!```$7W=)8V]N:69Y5VEN9&]W`````&8!```$7W=297-T;W)E5VEN* M9&]W`````'H!```#7W=.97AT26-O;@``````D`$```-?:7-)8V]N:69I960`? M``">`````````_(```/J````!'=)8V]N:69Y4&]R=`````````/R```#ZP``4 &``````/RU `` end SHAR_EOF # End of shell archive exit 0 ------- End of Forwarded Message