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