home *** CD-ROM | disk | FTP | other *** search
- /*
- ** AltMenu - the keyboard menu replacement doohicky
- **
- ** Version 1.0 10/14/89
- ** Authors: E. A. Hutchins and L. J. Rittle
- **
- ** Credits: Many basic input event handling routines and ideas blatantly
- ** lifted from:
- **
- ** NewPOP which is based upon POPCLI,
- **
- ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- ** |_o_o|\\ Copyright (c) 1986 The Software Distillery. All Rights Reserved *
- ** |. o.| || This program may not be distributed without the permission of *
- ** | . | || the authors. *
- ** | o | || Dave Baker Ed Burnette Stan Chow Jay Denebeim *
- ** | . |// Gordon Keener Jack Rouse John Toebes Doug Walker *
- ** ====== BBS:(919)-471-6436 VOICE:(919)-469-4210 *
- ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- **
- ** which is VERY loosely based on the input.device example by Rob Peck, 12/1/85
- **
- ** NewPOP additions and modifications Copyright © 1989 Loren J. Rittle.
- **
- ** As stated in the original POPCLI documentation file about POPCLI:
- **
- ** Permission is hereby granted to distribute this program provided
- ** both the documentation accompanies the executable and that no
- ** charge is made for its distribution.
- **
- **
- **
- ** History:
- ** EAH&LJR 10/14 While chatting about Amiga problems, Ed points out that
- ** it would sure be nice if one could navigate through
- ** menus with out picking up the mouse. I finally see the
- ** light and agree, thus AltMenu is born!
- ** EAH&LJR 10/14 Started version 1.0 with the intent of getting it done
- ** in one flurry of Amiga hacking.
- ** EAH 10/14 Finished version 1.0!
- ** (Loren sleeping at the great momment)
- ** LJR 10/14 Changed the priority to run us at from -20 to 19 in
- ** order to clean up the order in which output is displayed
- ** on the screen. (No more prompt then our output!)
- ** LJR 10/14 Added nice HELLO and START messages.
- ** LJR 10/14 Fixed problem with DMouse by just making sure that
- ** DMouse's input handler has a higher priority than
- ** ours.
- ** EAH 10/21 Added direct key jumps.
- */
-
- /*
- ** Includes
- */
-
- #include <exec/types.h>
- #include <exec/exec.h>
- #include <devices/input.h>
- #include <devices/inputevent.h>
- #include <intuition/intuition.h>
- #include <intuition/intuitionbase.h>
- #include <proto/dos.h>
- #include <proto/exec.h>
- #include <proto/intuition.h>
- #include <proto/console.h>
- #include <string.h>
-
- /*
- ** Defines
- */
-
- #define ALTMENU_PRIORITY 55
-
- #define PORTNAME "AltMenu.port"
- #define HELLOMSG "\x9B" "0;33mAltMenu\x9B" "0m by E. A. Hutchins and L. J. Rittle\n" \
- "Version 1.0 Copyright \xA9 1989 All Rights Reserved.\n"
- #define STARTMSG "AltMenu is starting.\n"
- #define KILLMSG "AltMenu is leaving.\n"
-
- #define LAST_KEY (0x4a)
-
- #define UP(x) ((x) | 0x80)
- #define RAW_ESC (0x45)
- #define RAW_RETURN (0x44)
- #define RAW_SPACE (0x40)
- #define RAW_UP (0x4c)
- #define RAW_DOWN (0x4d)
- #define RAW_RIGHT (0x4e)
- #define RAW_LEFT (0x4f)
- #define RAW_LALT (0x64)
- #define RAW_RALT (0x65)
- #define EXTQUAL (0x70cf)
-
- #define SCRN (gptr->Scrn)
- #define ROOT (gptr->Root)
- #define MENU (gptr->Menu)
- #define menu (gptr->_menu)
- #define MID (gptr->MidItem)
- #define SUB (gptr->SubItem)
- #define item (gptr->_item)
- #define mtmp ((struct Menu *)(gptr->_mtmp))
- #define itmp ((struct MenuItem *)(gptr->_mtmp))
- #define WHERE (gptr->where)
- #define MENUX (gptr->MenuX)
- #define MENUY (gptr->MenuY)
- #define EVT (gptr->Evt)
- #define GETKEY(x) ((gptr->Key)=((gptr->RawKeyMap)[(UBYTE)(x)]))
- #define KEY (gptr->Key)
- #define NAME (gptr->Name)
- #define UPPER(x) (((x) >= 'a' && (x) <= '~')?((x)-'a'+'A'):(x))
- #define MX (ep->ie_X)
- #define MY (ep->ie_Y)
- #define GLOBALMOUSE ((gptr->MouseX=MX),(gptr->MouseY=MY),(MX=((MX*gptr->XMul)-(gptr->IBase->MouseX))),(MY=((MY*gptr->YMul)-(gptr->IBase->MouseY))))
- #define ITEXT_OF(x) (((struct IntuiText *)((x)->ItemFill))->IText)
-
- /*
- ** Type definitions
- */
-
- typedef enum { Idle, AltDown, InMenu } States;
- typedef enum { Top, Mid, Sub } MenuPos;
-
- typedef struct
- {
- struct Task *buddy;
- struct IntuitionBase *IBase;
- States state;
- WORD OldMouseX, OldMouseY;
- WORD MouseX, MouseY;
- struct Screen *Scrn;
- int XMul, YMul;
- MenuPos where;
- struct Menu *Root, *Menu, *_menu;
- struct MenuItem *MidItem, *SubItem, *_item;
- void *_mtmp;
- int MenuX, MenuY;
- struct InputEvent Evt;
- BYTE *Name;
- BYTE Key;
- BYTE RawKeyMap[LAST_KEY];
- } GLOBAL_DATA;
-
- /*
- ** Global variables
- */
-
- struct IntuitionBase *IntuitionBase = NULL;
- struct Library *ConsoleDevice = NULL;
-
- extern BPTR _Backstdout; /* standard output when run in background */
- long _BackGroundIO = 1; /* Flag to tell it we want to do I/O */
- long _stack = 4000; /* Amount of stack space our task needs */
- char *_procname = "AltMenu"; /* The name of the task to create */
- long _priority = 19; /* The priority to run us at */
-
- /*
- ** Prototypes
- */
-
- struct MsgPort *FindPort();
- struct MsgPort *CreatePort();
- void DeletePort();
- struct IOStdReq *CreateIOReq(struct MsgPort *, int);
- void DeleteIOReq(struct IOStdReq *);
-
- /*
- ** myhandler - our awesome input event handler
- */
-
- __regargs struct InputEvent *myhandler( struct InputEvent *ev, register GLOBAL_DATA *gptr )
- {
- register struct InputEvent *ep;
-
- for (ep = ev; ep != NULL; ep = ep->ie_NextEvent)
- {
- if (ep->ie_Class == IECLASS_TIMER ||
- ep->ie_Class == IECLASS_NULL)
- continue;
-
- if (gptr->state == InMenu)
- {
- if (ep->ie_Class == IECLASS_RAWKEY)
- {
- switch (ep->ie_Code)
- {
- case UP(RAW_ESC):
- case RAW_LALT:
- case RAW_RALT:
- gptr->MouseX = SCRN->LeftEdge;
- gptr->MouseY = SCRN->TopEdge;
- /* fall through */
- case UP(RAW_RETURN):
- MX = gptr->MouseX;
- MY = gptr->MouseY;
- ep->ie_Class = IECLASS_RAWMOUSE;
- ep->ie_Code = UP(IECODE_RBUTTON);
- ep->ie_Qualifier = 0x8000; /* relmouse */
- GLOBALMOUSE;
- gptr->state = Idle;
- continue;
- case RAW_SPACE:
- MX = gptr->MouseX;
- MY = gptr->MouseY;
- ep->ie_Class = IECLASS_RAWMOUSE;
- ep->ie_Code = IECODE_LBUTTON;
- ep->ie_Qualifier = 0xc000; /* relmouse | lbutton */
- GLOBALMOUSE;
- continue;
- case UP(RAW_SPACE):
- MX = gptr->MouseX;
- MY = gptr->MouseY;
- ep->ie_Class = IECLASS_RAWMOUSE;
- ep->ie_Code = UP(IECODE_LBUTTON);
- ep->ie_Qualifier = 0x8000; /* relmouse */
- GLOBALMOUSE;
- continue;
- case RAW_UP:
- switch (WHERE)
- {
- case Top:
- if ((MID = MENU->FirstItem) == NULL) goto EatMe;
- WHERE = Mid;
- while (MID->NextItem != NULL)
- MID = MID->NextItem;
- break;
- case Mid:
- if ((item = MENU->FirstItem) == MID)
- {
- WHERE = Top;
- break;
- }
- while (item->NextItem != NULL && item->NextItem != MID)
- item = item->NextItem;
- MID = item;
- break;
- case Sub:
- if ((item = MID->SubItem) == SUB)
- {
- while (SUB->NextItem != NULL)
- SUB = SUB->NextItem;
- break;
- }
- while (item->NextItem != NULL && item->NextItem != SUB)
- item = item->NextItem;
- SUB = item;
- break;
- }
- break;
- case RAW_DOWN:
- switch (WHERE)
- {
- case Top:
- if ((MID = MENU->FirstItem) == NULL) goto EatMe;
- WHERE = Mid;
- break;
- case Mid:
- if (MID->NextItem != NULL)
- MID = MID->NextItem;
- else
- MID = MENU->FirstItem;
- break;
- case Sub:
- if (SUB->NextItem != NULL)
- SUB = SUB->NextItem;
- else
- SUB = MID->SubItem;
- break;
- }
- break;
- case RAW_LEFT:
- switch (WHERE)
- {
- case Mid:
- WHERE = Top;
- /* fall through */
- case Top:
- if (MENU == (menu = ROOT))
- while (MENU->NextMenu != NULL) MENU = MENU->NextMenu;
- else
- {
- while (menu->NextMenu != NULL && menu->NextMenu != MENU) menu = menu->NextMenu;
- MENU = menu;
- }
- break;
- case Sub:
- WHERE = Mid;
- break;
- }
- break;
- case RAW_RIGHT:
- switch (WHERE)
- {
- case Mid:
- if (MID->SubItem != NULL)
- {
- WHERE = Sub;
- SUB = MID->SubItem;
- break;
- }
- /* fall through */
- case Sub:
- WHERE = Top;
- /* fall through */
- case Top:
- if (MENU->NextMenu != NULL)
- MENU = MENU->NextMenu;
- else
- MENU = ROOT;
- break;
- }
- break;
- default:
- if (((UBYTE)(ep->ie_Code)) > LAST_KEY) goto EatMe;
- GETKEY( ep->ie_Code );
- if (KEY == 0) goto EatMe;
- /* find the menu name */
- switch (WHERE)
- {
- case Top:
- mtmp = NULL;
- menu = MENU;
- do {
- NAME = menu->MenuName;
- while (*NAME == ' ') ++NAME;
- if (KEY == UPPER( *NAME ))
- {
- if (mtmp != NULL)
- {
- if (mtmp == MENU) mtmp = menu;
- break;
- }
- mtmp = menu;
- }
- menu = menu->NextMenu;
- if (menu == NULL) menu = ROOT;
- } while (menu != MENU);
- /* no matches? */
- if (mtmp == NULL) goto EatMe;
- /* only one match? */
- if (menu == MENU)
- {
- MID = mtmp->FirstItem;
- if (MENU == mtmp && MID != NULL)
- WHERE = Mid;
- }
- MENU = mtmp;
- break;
- case Mid:
- itmp = NULL;
- item = MID;
- do {
- if (item->Flags & ITEMTEXT)
- {
- NAME = ITEXT_OF(item);
- while (*NAME == ' ') ++NAME;
- if (KEY == UPPER( *NAME ))
- {
- if (itmp != NULL)
- {
- if (itmp == MID) itmp = item;
- break;
- }
- itmp = item;
- }
- }
- item = item->NextItem;
- if (item == NULL) item = MENU->FirstItem;
- } while (item != MID);
- /* no matches? */
- if (itmp == NULL) goto EatMe;
- /* only one match? */
- if (item == MID)
- {
- SUB = itmp->SubItem;
- if (MID == itmp)
- {
- if (SUB != NULL)
- WHERE = Sub;
- else
- {
- EVT.ie_NextEvent = ep->ie_NextEvent;
- EVT.ie_Class = IECLASS_RAWKEY;
- EVT.ie_SubClass = 0;
- EVT.ie_Qualifier = 0;
- EVT.ie_Code = UP(RAW_RETURN);
- ep->ie_NextEvent = &EVT;
- }
- }
- }
- MID = itmp;
- break;
- case Sub:
- itmp = NULL;
- item = SUB;
- do {
- if (item->Flags & ITEMTEXT)
- {
- NAME = ITEXT_OF(item);
- while (*NAME == ' ') ++NAME;
- if (KEY == UPPER( *NAME ))
- {
- if (itmp != NULL)
- {
- if (itmp == SUB) itmp = item;
- break;
- }
- itmp = item;
- }
- }
- item = item->NextItem;
- if (item == NULL) item = MID->SubItem;
- } while (item != SUB);
- /* no matches? */
- if (itmp == NULL) goto EatMe;
- /* only one match? */
- if (item == SUB && SUB == itmp)
- {
- EVT.ie_NextEvent = ep->ie_NextEvent;
- EVT.ie_Class = IECLASS_RAWKEY;
- EVT.ie_SubClass = 0;
- EVT.ie_Qualifier = 0;
- EVT.ie_Code = UP(RAW_RETURN);
- ep->ie_NextEvent = &EVT;
- }
- SUB = itmp;
- break;
- }
- break;
- EatMe:
- ep->ie_Class = IECLASS_NULL;
- continue;
- }
-
- /* move the mouse cursor on top of the item */
-
- switch (WHERE)
- {
- case Top:
- MX = SCRN->LeftEdge + MENU->LeftEdge + MENU->Width - 2;
- MY = SCRN->TopEdge + MENU->Height/2;
- break;
- case Mid:
- MX = MENUX + MENU->LeftEdge + MID->LeftEdge + 2;
- MY = MENUY + MENU->Height + MID->TopEdge + MID->Height/2;
- break;
- case Sub:
- MX = MENUX + MENU->LeftEdge + MID->LeftEdge + SUB->LeftEdge + SUB->Width - 8;
- MY = MENUY + MENU->Height + MID->TopEdge + SUB->TopEdge + SUB->Height/2;
- break;
- }
- ep->ie_Class = IECLASS_RAWMOUSE;
- ep->ie_Code = IECODE_NOBUTTON;
- ep->ie_Qualifier = 0x8000; /* relmouse */
- GLOBALMOUSE;
- }
- else if (ep->ie_Class == IECLASS_RAWMOUSE)
- {
- /* if this is a button up, quit */
- if (ep->ie_Code != IECODE_NOBUTTON)
- gptr->state = Idle;
- else /* otherwise eat 'em for now */
- ep->ie_Class = IECLASS_NULL;
- }
- }
- else if ((ep->ie_Class == IECLASS_RAWKEY) &&
- (gptr->state == Idle) &&
- ((ep->ie_Code == RAW_LALT) || (ep->ie_Code == RAW_RALT)) &&
- ((ep->ie_Qualifier & EXTQUAL) == 0))
- {
- gptr->state = AltDown;
- }
- else if ((ep->ie_Class == IECLASS_RAWKEY) &&
- (gptr->state == AltDown) &&
- ((ep->ie_Code == UP(RAW_LALT)) || (ep->ie_Code == UP(RAW_RALT))) &&
- ((ep->ie_Qualifier & EXTQUAL) == 0))
- {
- /* point at the menu */
- gptr->state = InMenu;
- ROOT = MENU = gptr->IBase->ActiveWindow->MenuStrip;
- SCRN = gptr->IBase->ActiveWindow->WScreen;
- if (ROOT == NULL || SCRN == NULL)
- {
- gptr->state = Idle;
- continue;
- }
- gptr->OldMouseX = gptr->IBase->MouseX;
- gptr->OldMouseY = gptr->IBase->MouseY;
- gptr->XMul = (gptr->Scrn->ViewPort.Modes & HIRES) ? 1 : 2;
- gptr->YMul = (gptr->Scrn->ViewPort.Modes & LACE) ? 1 : 2;
- MENUX = SCRN->LeftEdge + SCRN->MenuHBorder;
- MENUY = SCRN->TopEdge + SCRN->MenuVBorder;
- /* fix for non-standard menus */
- if (MENU->Height == 0) MENUY += SCRN->BarHeight;
- WHERE = Top;
- MX = SCRN->LeftEdge + MENU->LeftEdge + MENU->Width - 2;
- MY = SCRN->TopEdge + MENU->Height/2;
- ep->ie_Class = IECLASS_RAWMOUSE;
- ep->ie_Code = IECODE_RBUTTON;
- ep->ie_Qualifier = 0xa000; /* relmouse | rbutton */
- GLOBALMOUSE;
- }
- else gptr->state = Idle;
- }
- return(ev);
- }
-
- /*
- ** GetRawKeyMap - get the raw key conversion lookup table
- */
-
- void GetRawKeyMap( GLOBAL_DATA *gptr )
- {
- BYTE key;
- BYTE Ascii[16];
- struct InputEvent ev;
-
- for (key = 0; key <= LAST_KEY; ++key)
- {
- ev.ie_NextEvent = NULL;
- ev.ie_Class = IECLASS_RAWKEY;
- ev.ie_SubClass = 0;
- ev.ie_Qualifier = 0;
-
- ev.ie_Code = key;
- RawKeyConvert( &ev, Ascii, sizeof( Ascii ), NULL );
- (gptr->RawKeyMap)[key] = UPPER( Ascii[0] );
- }
- }
-
- /*
- ** Main entry point
- */
-
- void _main( char *cmd )
- {
- int stay = 0;
- struct MsgPort *port;
- struct MsgPort *DevPort = NULL;
- struct Message *msg = NULL;
- struct IOStdReq *inputRequestBlock = NULL;
- struct IOStdReq *conRequestBlock = NULL;
- struct Interrupt handlerStuff;
- GLOBAL_DATA global;
-
- if (_Backstdout) Write( _Backstdout, HELLOMSG, sizeof(HELLOMSG) );
-
- /* now see if we are already installed */
- if ((port = FindPort( PORTNAME )) == NULL)
- {
- /* remember to hang around when we are done */
- stay = 1;
- /* not installed, we need to install our own port */
- if ((port = CreatePort( PORTNAME, 0 )) == NULL) goto abort;
- if (_Backstdout)
- Write( _Backstdout, STARTMSG, sizeof(STARTMSG) );
- }
-
- /* if we were run from CLI then process parameters */
- if (cmd && *cmd)
- {
- /* skip over any leading spaces in the command line */
- while (*cmd && *cmd != '-') cmd++;
-
- /* see if they are trying to kill us. */
- if (*cmd == '-' && cmd[1] == 'q')
- {
- if ((msg = (struct Message *)
- AllocMem( sizeof(struct Message), MEMF_CLEAR|MEMF_PUBLIC)) == NULL )
- goto abort;
- msg->mn_Length = sizeof(struct Message);
- PutMsg( port, msg );
- msg = NULL;
-
- if (_Backstdout)
- Write( _Backstdout, KILLMSG, sizeof(KILLMSG) );
- }
- }
-
- if (!stay) goto abort;
-
- /* Let the original window go away */
- if (_Backstdout) Close( _Backstdout );
- _Backstdout = NULL;
-
- if (((DevPort = CreatePort( NULL, 0 )) == NULL) ||
- ((inputRequestBlock = CreateIOReq( DevPort, sizeof(struct IOStdReq) )) == NULL) ||
- ((conRequestBlock = CreateIOReq( DevPort, sizeof(struct IOStdReq) )) == NULL) ||
- ((IntuitionBase = (struct IntuitionBase *)OpenLibrary( "intuition.library", 0 )) == NULL) ||
- OpenDevice( "input.device", 0, (struct IORequest *)inputRequestBlock, 0 ) ||
- OpenDevice( "console.device", -1, (struct IORequest *)conRequestBlock, 0 ))
- goto abort;
-
- /* for using RawKeyConvert */
- ConsoleDevice = (struct Library *)conRequestBlock->io_Device;
- if (ConsoleDevice == NULL) goto abort;
-
- GetRawKeyMap( &global );
- global.buddy = FindTask( NULL );
- global.IBase = IntuitionBase;
- global.state = Idle;
-
- handlerStuff.is_Data = (APTR)&global;
- handlerStuff.is_Code = (VOID (*)()) myhandler;
- handlerStuff.is_Node.ln_Pri = ALTMENU_PRIORITY;
-
- inputRequestBlock->io_Command = IND_ADDHANDLER;
- inputRequestBlock->io_Data = (APTR)&handlerStuff;
- DoIO( inputRequestBlock );
-
- WaitPort( port );
- msg = GetMsg( port );
-
- abort:
- if (msg != NULL) FreeMem( (char *)msg, msg->mn_Length );
-
- if (conRequestBlock != NULL)
- {
- if (conRequestBlock->io_Device != NULL)
- CloseDevice( (struct IORequest *)conRequestBlock );
- DeleteIOReq( conRequestBlock );
- }
-
- if (inputRequestBlock != NULL)
- {
- if (inputRequestBlock->io_Device != NULL)
- {
- inputRequestBlock->io_Command = IND_REMHANDLER;
- inputRequestBlock->io_Data = (APTR)&handlerStuff;
- DoIO( (struct IORequest *)inputRequestBlock );
- CloseDevice( (struct IORequest *)inputRequestBlock );
- }
- DeleteIOReq( inputRequestBlock );
- }
-
- if (IntuitionBase != NULL) CloseLibrary( (struct Library *)IntuitionBase );
- if (DevPort != NULL) DeletePort( DevPort );
- if (_Backstdout) Close( _Backstdout );
- if (stay && (port != NULL)) DeletePort( port );
- }
-
- /*
- ** No nutty memory cleanup needed!
- */
-
- void MemCleanup( void )
- {
- }
-
- /*
- ** CreatePort - create a message port
- */
-
- struct MsgPort *CreatePort( name, pri )
- char *name;
- int pri;
- {
- UBYTE sigbit;
- register struct MsgPort *port;
-
- if ((sigbit = AllocSignal(-1)) == -1) return( NULL );
- if ((port = (struct MsgPort *)AllocMem( sizeof( struct MsgPort ), MEMF_CLEAR|MEMF_PUBLIC)) == NULL)
- {
- FreeSignal( sigbit );
- return( NULL );
- }
-
- port->mp_Node.ln_Name = name;
- port->mp_Node.ln_Pri = pri;
- port->mp_Node.ln_Type = NT_MSGPORT;
- port->mp_Flags = PA_SIGNAL;
- port->mp_SigBit = sigbit;
- port->mp_SigTask = (struct Task *)FindTask( NULL );
- AddPort( port );
- return( port );
- }
-
- /*
- ** DeletePort - delete an allocated message port
- */
-
- void DeletePort( struct MsgPort *port )
- {
- RemPort( port );
- FreeSignal( port->mp_SigBit );
- FreeMem( (char *)port,sizeof(struct MsgPort) );
- }
-
- /*
- ** CreateIOReq - create an i/o request block
- */
-
- struct IOStdReq *CreateIOReq( struct MsgPort *port, int size )
- {
- struct IOStdReq *ioReq;
-
- if ((ioReq = (struct IOStdReq *)AllocMem( size, MEMF_CLEAR | MEMF_PUBLIC )) != NULL)
- {
- ioReq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
- ioReq->io_Message.mn_Node.ln_Pri = 0;
- ioReq->io_Message.mn_Length = size;
- ioReq->io_Message.mn_ReplyPort = port;
- }
- return( ioReq );
- }
-
- /*
- ** DeleteIOReq - delete an allocated i/o block
- */
-
- void DeleteIOReq( struct IOStdReq *ioReq )
- {
- ioReq->io_Message.mn_Node.ln_Type = 0xff;
- ioReq->io_Device = (struct Device *) -1;
- ioReq->io_Unit = (struct Unit *) -1;
- FreeMem( (char *)ioReq, ioReq->io_Message.mn_Length );
- }
-