home *** CD-ROM | disk | FTP | other *** search
- /* 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;
- }
-