home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
488.lha
/
modengine_v1.0
/
mod_idcmp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-03-07
|
14KB
|
501 lines
/* mod_idcmp.c
* Copyright (C) 1990 Commodore-Amiga, Inc.
* written by David N. Junod
*
* IDCMP gadget/menu/keyboard message handling routines
*
*/
#include "mod.h"
/* normal low-overhead IDCMP messages */
#define IDCMP_flagF (CLOSEWINDOW | RAWKEY | MOUSEBUTTONS | GADGETDOWN \
| GADGETUP | MENUPICK)
/* IDCMP messages used when a hold or drag gadget is active */
#define IDCMP_flagS (RAWKEY | MOUSEMOVE | MOUSEBUTTONS | INTUITICKS \
| GADGETUP)
/* variables required for IDCMP message handling */
struct IDCMPInfo
{
struct MsgPort *msgport; /* Message port */
struct NewWindow *nw; /* NewWindow pointer */
struct Menu *menu; /* Menu strip pointer */
WORD *KeyFunctions; /* Keyboard function map */
struct Window *win; /* Window */
struct EGadget *ActiveGad; /* Currrently active gadget */
struct IOStdReq ioreq; /* Rawkey conversion IO request */
};
/* IDCMP message handler function prototypes */
BOOL open_idcmp (struct AppInfo *, struct MsgHandler *);
BOOL handle_idcmp (struct AppInfo *, struct MsgHandler *);
BOOL close_idcmp (struct AppInfo *, struct MsgHandler *);
BOOL shutdown_idcmp (struct AppInfo *, struct MsgHandler *);
BOOL setup_key_array (struct IDCMPInfo * mh, struct KeyboardCMD * KeyArray);
VOID shutdown_key_array (struct IDCMPInfo *);
LONG DeadKeyConvert(struct IntuiMessage * msg, UBYTE * kbuffer, LONG kbsize, struct KeyMap * kmap);
VOID CloseWindowSafely (struct Window * win);
VOID HandleKeyEvent(struct AppInfo *,struct MsgHandler *,struct IntuiMessage * msg);
VOID HandleGadgEvent(struct AppInfo *,struct MsgHandler *,struct IntuiMessage * msg);
VOID HandleMenuEvent(struct AppInfo *,struct MsgHandler *,struct IntuiMessage * msg);
/* Required for DeadKeyConvert processing */
struct ConsoleDevice *ConsoleDevice = NULL;
/* setup the resources required for IDCMP processing */
struct MsgHandler *setup_idcmp (struct AppInfo * ai,
struct NewWindow * nw,
struct KeyboardCMD * kba,
struct Menu * menu, BOOL immed)
{
struct MsgHandler *mh = NULL;
struct IDCMPInfo *md = NULL;
if (md = (struct IDCMPInfo *)
AllocMem (sizeof (struct IDCMPInfo), MEMF_CLEAR|MEMF_PUBLIC))
{
md->nw = nw;
md->menu = menu;
if (setup_key_array (md, kba))
{
if (md->msgport = CreatePort (NULL, 0))
{
if (mh = (struct MsgHandler *)
AllocMem (sizeof (struct MsgHandler), MEMF_CLEAR|MEMF_PUBLIC))
{
mh->mh_Node.ln_Type = MH_HANDLER_T;
mh->mh_Node.ln_Pri = MH_HANDLER_P;
mh->mh_Node.ln_Name = "IDCMP";
mh->mh_SigBits = (1L << md->msgport->mp_SigBit);
mh->mh_Func[MH_OPEN] = open_idcmp;
mh->mh_Func[MH_HANDLE] = handle_idcmp;
mh->mh_Func[MH_CLOSE] = close_idcmp;
mh->mh_Func[MH_SHUTDOWN] = shutdown_idcmp;
mh->mh_Data = md;
if (immed)
{
if (open_idcmp (ai, mh))
return (mh);
}
else
return (mh);
FreeMem (mh, sizeof (struct MsgHandler));
}
else
NotifyUser (NULL, "Not enough memory");
}
else
NotifyUser (NULL, "Could not create IDCMP port");
}
FreeMem (md, sizeof (struct IDCMPInfo));
}
return (mh);
}
/* activate IDCMP handler */
BOOL open_idcmp (struct AppInfo * ai, struct MsgHandler * mh)
{
struct IDCMPInfo *md = mh->mh_Data;
if (!(md->win))
{
/* Open an Intuition window */
md->nw->IDCMPFlags = NULL;
if (md->win = OpenWindow (md->nw))
{
/* Attach the menu strip. You should pass it thru the AdjustMenu
* function that is shown in the 1.3 RKM Libraries & Devices menu
* example. */
SetMenuStrip (md->win, md->menu);
/* set up the message port information */
md->win->UserPort = md->msgport;
ModifyIDCMP (md->win, IDCMP_flagF);
return (TRUE);
}
else
NotifyUser (NULL, "Could not open window");
}
return (FALSE);
}
/* Intuition message processing */
BOOL handle_idcmp (struct AppInfo * ai, struct MsgHandler * mh)
{
struct IDCMPInfo *md = mh->mh_Data;
struct IntuiMessage *imsg; /* incoming Intuition messages */
struct IntuiMessage *fmsg, *tmsg; /* for filtering messages */
struct Window * win; /* only used for filtering messages */
struct IntuiMessage nmsg; /* copy of the message */
while (imsg = (struct IntuiMessage *) GetMsg (md->msgport))
{
/* Filter out excessive mouse-moves (oldest first) */
if (imsg->Class == MOUSEMOVE)
{
win = imsg->IDCMPWindow;
Forbid ();
fmsg = (struct IntuiMessage *)
(md->msgport->mp_MsgList.lh_Head);
while (tmsg = (struct IntuiMessage *)
(fmsg->ExecMessage.mn_Node.ln_Succ))
{
if (fmsg->IDCMPWindow == win &&
fmsg->Class == MOUSEMOVE)
{
Remove ((struct Node *) fmsg);
ReplyMsg ((struct Message *) imsg);
imsg = fmsg;
}
fmsg = tmsg;
}
Permit ();
}
/* Filter out excessive key repeats here. Amiga Mail article by
* Michael Sinz IV-37 Paced Repeat Key */
/* copy the message so that we can reply to it */
CopyMem ( (APTR)imsg, (APTR)&nmsg, sizeof (struct IntuiMessage) );
/* Reply to the message now that we're done with it */
ReplyMsg ((struct Message *) imsg);
/* Process Intuition events */
switch (nmsg.Class)
{
/* Handle the close window gadget */
case CLOSEWINDOW:
if (nmsg.Qualifier & SHIFTED)
/* hide Intuition interface */
close_idcmp (ai, mh);
else
/* close down the application */
QuitFunc (ai, (struct Message *) &nmsg, NULL);
break;
/* Handle keyboard events */
case RAWKEY:
HandleKeyEvent (ai, mh, &nmsg);
break;
/* Handle events that pertain to gadgets */
case INTUITICKS:
case MOUSEMOVE:
case MOUSEBUTTONS:
case GADGETDOWN:
case GADGETUP:
HandleGadgEvent (ai, mh, &nmsg);
break;
/* Handle menu events */
case MENUPICK:
HandleMenuEvent (ai, mh, &nmsg);
break;
}
}
return (TRUE);
}
/* hide IDCMP message handler */
BOOL close_idcmp (struct AppInfo * ai, struct MsgHandler * mh)
{
struct IDCMPInfo *md = mh->mh_Data;
if (mh)
{
if (md->win)
{
/* save current settings */
md->nw->Width = md->win->Width;
md->nw->Height = md->win->Height;
md->nw->LeftEdge = md->win->LeftEdge;
md->nw->TopEdge = md->win->TopEdge;
/* clear the menu strip if there is one */
if (md->win->MenuStrip)
ClearMenuStrip (md->win);
/* close the window */
CloseWindowSafely (md->win);
md->win = NULL;
}
}
return (TRUE);
}
/* free resources for IDCMP message handler */
BOOL shutdown_idcmp (struct AppInfo * ai, struct MsgHandler * mh)
{
struct IDCMPInfo *md = mh->mh_Data;
if (mh)
{
close_idcmp (ai, mh); /* close window */
shutdown_key_array (md); /* free keyboard array */
DeletePort (md->msgport); /* delete IDCMP port */
md->msgport = NULL;
}
return (TRUE);
}
/* safely close a window that shares a message port with another window */
VOID CloseWindowSafely (struct Window * win)
{
struct IntuiMessage * msg, * succ;
Forbid ();
msg = (struct IntuiMessage *)win->UserPort->mp_MsgList.lh_Head;
while (succ = (struct IntuiMessage *)msg->ExecMessage.mn_Node.ln_Succ)
{
if (msg->IDCMPWindow == win)
{
Remove ((struct Node *)msg);
ReplyMsg ((struct Message *)msg);
}
msg = succ;
}
win->UserPort = NULL;
ModifyIDCMP (win, NULL);
Permit ();
CloseWindow (win);
}
/* Allocate resources for handling keyboard input */
BOOL setup_key_array (struct IDCMPInfo * md, struct KeyboardCMD * KeyArray)
{
register WORD cntr;
/* Allow for NULL specification of a keyboard command array */
if (!KeyArray)
return (TRUE);
/* Prepare for DeadKeyConvert */
if (!(OpenDevice ("console.device", -1L,
(struct IORequest *) & (md->ioreq), 0L)))
{
ConsoleDevice = (struct ConsoleDevice *) md->ioreq.io_Device;
/* Allocate memory for the keyboard function map */
if (md->KeyFunctions =
AllocMem ((sizeof (WORD) * MAXKEYS), MEMF_CLEAR|MEMF_PUBLIC))
{
/* read in the key assignments */
for (cntr = 0; KeyArray[cntr].key != NULL; cntr++)
md->KeyFunctions[KeyArray[cntr].key] = KeyArray[cntr].funcID;
return (TRUE);
}
else
NotifyUser (NULL, "Not enough memory");
CloseDevice ((struct IORequest *) & (md->ioreq));
}
else
NotifyUser (NULL, "Could not open console.device");
return (FALSE);
}
/* Release resources for handling keyboard input */
VOID shutdown_key_array (struct IDCMPInfo * md)
{
if (md)
{
if (md->KeyFunctions)
FreeMem (md->KeyFunctions, (sizeof (WORD) * MAXKEYS));
md->KeyFunctions = NULL;
if (ConsoleDevice)
CloseDevice ((struct IORequest *) & (md->ioreq));
}
}
/* Keyboard handling routines */
VOID HandleKeyEvent (struct AppInfo * ai, struct MsgHandler * mh,
struct IntuiMessage * msg)
{
struct IDCMPInfo *md = mh->mh_Data;
WORD FuncID = NO_FUNCTION;
WORD key, cur;
UBYTE buffer[17];
strcpy (buffer, " ");
key = (WORD) DeadKeyConvert (msg, buffer, 15L, 0L);
if (key > 0)
{
/* Get the ASCII value of the key that was pressed */
cur = buffer[0];
/* Check to see if it was a special key; like a Function key,
* Help, or the Arrow keys. Could also do additional checking for
* ALT, AMIGA and CTRL qualifiers by adding in a proportional
*weight for each one. */
if (key > 1 && cur == 155)
cur = SPECIAL + buffer[1];
/* Get the function number assigned to this key */
FuncID = md->KeyFunctions[cur];
if (FuncID != NO_FUNCTION)
/* Perform the function assigned to this key. */
PerfFunc (ai, (struct Message *)msg, ai->FuncTable[FuncID].name);
}
}
/* Convert Raw keys to Vanilla keys */
LONG DeadKeyConvert (msg, kbuffer, kbsize, kmap)
struct IntuiMessage *msg;
UBYTE *kbuffer;
LONG kbsize;
struct KeyMap *kmap;
{
static struct InputEvent ievent =
{NULL, IECLASS_RAWKEY, 0, 0, 0};
if (msg->Class != RAWKEY)
return (-2);
ievent.ie_Code = msg->Code;
ievent.ie_Qualifier = msg->Qualifier;
ievent.ie_position.ie_addr = *((APTR *) msg->IAddress);
return (RawKeyConvert (&ievent, kbuffer, kbsize, kmap));
}
/* Gadget handling routine */
VOID HandleGadgEvent (struct AppInfo * ai, struct MsgHandler * mh,
struct IntuiMessage * msg)
{
struct IDCMPInfo *md = mh->mh_Data;
struct EGadget *egad = (struct EGadget *) msg->IAddress;
WORD FuncID = NO_FUNCTION;
static ULONG glsecs = 0L, glmics = 0L; /* For Gadget DoubleClick */
switch (msg->Class)
{
/* Check to see if gadget is being held down and if there is a
* function to perform while it is being held. */
case MOUSEMOVE:
case INTUITICKS:
if (md->ActiveGad &&
md->ActiveGad->eg_Gadget.Flags & SELECTED)
{
/* gadget being held or dragged */
FuncID = md->ActiveGad->eg_Funcs[EG_HOLD];
}
if (msg->Qualifier & IEQUALIFIER_RBUTTON)
{
/* Right mouse button pressed, abort operation */
FuncID = md->ActiveGad->eg_Funcs[EG_ABORT];
/* clear the active gadget */
md->ActiveGad = NULL;
/* only watch for necessary messages */
ModifyIDCMP (md->win, IDCMP_flagF);
}
break;
/* Indicate that there is no active gadget now. */
case MOUSEBUTTONS:
if (msg->Code == SELECTUP)
{
/* clear the active gadget */
md->ActiveGad = NULL;
/* only watch for necessary messages */
ModifyIDCMP (md->win, IDCMP_flagF);
}
break;
/* Check to see if there is a function to perform on downpress or
* double-click of the gadget. */
case GADGETDOWN:
/* Set the active gadget. Only one gadget can EVER be active
* at a time (Intuition rule). */
md->ActiveGad = egad;
/* tell the system that we need to watch for INTUITICKS
* and MOUSEMOVES if there is a hold function for this gadget */
if (egad->eg_Funcs[EG_HOLD] != NO_FUNCTION)
ModifyIDCMP (md->win, IDCMP_flagS);
FuncID = egad->eg_Funcs[EG_DOWNPRESS];
if (egad->eg_Funcs[EG_DBLCLICK] != NO_FUNCTION)
{
/* If the gadget has a double-click function, then check to
* see if it has been double-clicked. Notice that if there
* is a double-click function, then it over-rules the
*downpress function. */
if (DoubleClick (glsecs, glmics, msg->Seconds, msg->Micros))
FuncID = egad->eg_Funcs[EG_DBLCLICK];
else
{
glsecs = msg->Seconds;
glmics = msg->Micros;
}
}
break;
/* Check to see if there is a function to perform on release of the
* gadget. */
case GADGETUP:
/* Clear the active gadget variable */
md->ActiveGad = NULL;
/* only watch for necessary messages */
ModifyIDCMP (md->win, IDCMP_flagF);
FuncID = egad->eg_Funcs[EG_RELEASE];
break;
}
/* Perform the function if there is one. */
if (FuncID != NO_FUNCTION)
PerfFunc (ai, (struct Message *) msg, ai->FuncTable[FuncID].name);
}
/* Menu handling routine */
VOID HandleMenuEvent (struct AppInfo * ai, struct MsgHandler * mh,
struct IntuiMessage * msg)
{
struct EMenuItem *item;
UWORD selection = msg->Code;
/* Shut down menu events while we're processing these. Any function that
* opens its own window and ignores events from the main window, should
* also set a busy pointer in the main window. */
msg->IDCMPWindow->Flags |= RMBTRAP;
/* Process all menu events */
while ((selection != MENUNULL) && (!ai->Done))
{
/* Get the Extended MenuItem structure address */
item = (struct EMenuItem *)
ItemAddress (msg->IDCMPWindow->MenuStrip, (LONG) selection);
/* Mutual Excluded items should all call the same function. And that
* function should do any processing based on the currently selected
* item. */
PerfFunc (ai, (struct Message *)msg,
ai->FuncTable[item->emi_MenuID].name);
/* Get the next selection */
selection = item->emi_Item.NextSelect;
}
/* Turn menu events back on. */
msg->IDCMPWindow->Flags &= ~RMBTRAP;
}