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 >
C/C++ Source or Header  |  1991-03-07  |  14KB  |  501 lines

  1. /* mod_idcmp.c
  2.  * Copyright (C) 1990 Commodore-Amiga, Inc.
  3.  * written by David N. Junod
  4.  *
  5.  * IDCMP gadget/menu/keyboard message handling routines
  6.  *
  7.  */
  8.  
  9. #include "mod.h"
  10.  
  11. /* normal low-overhead IDCMP messages */
  12. #define    IDCMP_flagF (CLOSEWINDOW | RAWKEY | MOUSEBUTTONS | GADGETDOWN \
  13.              | GADGETUP | MENUPICK)
  14.  
  15. /* IDCMP messages used when a hold or drag gadget is active */
  16. #define    IDCMP_flagS (RAWKEY | MOUSEMOVE | MOUSEBUTTONS | INTUITICKS \
  17.              | GADGETUP)
  18.  
  19. /* variables required for IDCMP message handling */
  20. struct IDCMPInfo
  21. {
  22.     struct MsgPort *msgport;    /* Message port */
  23.     struct NewWindow *nw;    /* NewWindow pointer */
  24.     struct Menu *menu;        /* Menu strip pointer */
  25.     WORD *KeyFunctions;        /* Keyboard function map */
  26.     struct Window *win;        /* Window */
  27.     struct EGadget *ActiveGad;    /* Currrently active gadget */
  28.     struct IOStdReq ioreq;    /* Rawkey conversion IO request */
  29. };
  30.  
  31. /* IDCMP message handler function prototypes */
  32. BOOL open_idcmp (struct AppInfo *, struct MsgHandler *);
  33. BOOL handle_idcmp (struct AppInfo *, struct MsgHandler *);
  34. BOOL close_idcmp (struct AppInfo *, struct MsgHandler *);
  35. BOOL shutdown_idcmp (struct AppInfo *, struct MsgHandler *);
  36. BOOL setup_key_array (struct IDCMPInfo * mh, struct KeyboardCMD * KeyArray);
  37. VOID shutdown_key_array (struct IDCMPInfo *);
  38. LONG DeadKeyConvert(struct IntuiMessage * msg, UBYTE * kbuffer, LONG kbsize, struct KeyMap * kmap);
  39. VOID CloseWindowSafely (struct Window * win);
  40. VOID HandleKeyEvent(struct AppInfo *,struct MsgHandler *,struct IntuiMessage * msg);
  41. VOID HandleGadgEvent(struct AppInfo *,struct MsgHandler *,struct IntuiMessage * msg);
  42. VOID HandleMenuEvent(struct AppInfo *,struct MsgHandler *,struct IntuiMessage * msg);
  43.  
  44. /* Required for DeadKeyConvert processing */
  45. struct ConsoleDevice *ConsoleDevice = NULL;
  46.  
  47. /* setup the resources required for IDCMP processing */
  48. struct MsgHandler *setup_idcmp (struct AppInfo * ai,
  49.                 struct NewWindow * nw,
  50.                 struct KeyboardCMD * kba,
  51.                 struct Menu * menu, BOOL immed)
  52. {
  53.     struct MsgHandler *mh = NULL;
  54.     struct IDCMPInfo *md = NULL;
  55.  
  56.     if (md = (struct IDCMPInfo *)
  57.     AllocMem (sizeof (struct IDCMPInfo), MEMF_CLEAR|MEMF_PUBLIC))
  58.     {
  59.     md->nw = nw;
  60.     md->menu = menu;
  61.     if (setup_key_array (md, kba))
  62.     {
  63.         if (md->msgport = CreatePort (NULL, 0))
  64.         {
  65.         if (mh = (struct MsgHandler *)
  66.             AllocMem (sizeof (struct MsgHandler), MEMF_CLEAR|MEMF_PUBLIC))
  67.         {
  68.             mh->mh_Node.ln_Type = MH_HANDLER_T;
  69.             mh->mh_Node.ln_Pri  = MH_HANDLER_P;
  70.             mh->mh_Node.ln_Name = "IDCMP";
  71.             mh->mh_SigBits = (1L << md->msgport->mp_SigBit);
  72.             mh->mh_Func[MH_OPEN]     = open_idcmp;
  73.             mh->mh_Func[MH_HANDLE]   = handle_idcmp;
  74.             mh->mh_Func[MH_CLOSE]    = close_idcmp;
  75.             mh->mh_Func[MH_SHUTDOWN] = shutdown_idcmp;
  76.             mh->mh_Data = md;
  77.  
  78.             if (immed)
  79.             {
  80.             if (open_idcmp (ai, mh))
  81.                 return (mh);
  82.             }
  83.             else
  84.             return (mh);
  85.  
  86.             FreeMem (mh, sizeof (struct MsgHandler));
  87.         }
  88.         else
  89.             NotifyUser (NULL, "Not enough memory");
  90.         }
  91.         else
  92.         NotifyUser (NULL, "Could not create IDCMP port");
  93.  
  94.     }
  95.     FreeMem (md, sizeof (struct IDCMPInfo));
  96.     }
  97.  
  98.     return (mh);
  99. }
  100.  
  101. /* activate IDCMP handler */
  102. BOOL open_idcmp (struct AppInfo * ai, struct MsgHandler * mh)
  103. {
  104.     struct IDCMPInfo *md = mh->mh_Data;
  105.  
  106.     if (!(md->win))
  107.     {
  108.     /* Open an Intuition window */
  109.     md->nw->IDCMPFlags = NULL;
  110.     if (md->win = OpenWindow (md->nw))
  111.     {
  112.         /* Attach the menu strip. You should pass it thru the AdjustMenu
  113.          * function that is shown in the 1.3 RKM Libraries & Devices menu
  114.          * example. */
  115.         SetMenuStrip (md->win, md->menu);
  116.  
  117.         /* set up the message port information */
  118.         md->win->UserPort = md->msgport;
  119.         ModifyIDCMP (md->win, IDCMP_flagF);
  120.  
  121.         return (TRUE);
  122.     }
  123.     else
  124.         NotifyUser (NULL, "Could not open window");
  125.     }
  126.     return (FALSE);
  127. }
  128.  
  129. /* Intuition message processing */
  130. BOOL handle_idcmp (struct AppInfo * ai, struct MsgHandler * mh)
  131. {
  132.     struct IDCMPInfo *md = mh->mh_Data;
  133.     struct IntuiMessage *imsg;    /* incoming Intuition messages */
  134.     struct IntuiMessage *fmsg, *tmsg; /* for filtering messages */
  135.     struct Window * win; /* only used for filtering messages */
  136.     struct IntuiMessage nmsg;    /* copy of the message */
  137.  
  138.     while (imsg = (struct IntuiMessage *) GetMsg (md->msgport))
  139.     {
  140.     /* Filter out excessive mouse-moves (oldest first) */
  141.     if (imsg->Class == MOUSEMOVE)
  142.     {
  143.         win = imsg->IDCMPWindow;
  144.         Forbid ();
  145.         fmsg = (struct IntuiMessage *)
  146.           (md->msgport->mp_MsgList.lh_Head);
  147.         while (tmsg = (struct IntuiMessage *)
  148.            (fmsg->ExecMessage.mn_Node.ln_Succ))
  149.         {
  150.         if (fmsg->IDCMPWindow == win &&
  151.             fmsg->Class == MOUSEMOVE)
  152.         {
  153.             Remove ((struct Node *) fmsg);
  154.             ReplyMsg ((struct Message *) imsg);
  155.             imsg = fmsg;
  156.         }
  157.         fmsg = tmsg;
  158.         }
  159.         Permit ();
  160.     }
  161.     /* Filter out excessive key repeats here. Amiga Mail article by
  162.      * Michael Sinz IV-37 Paced Repeat Key */
  163.  
  164.     /* copy the message so that we can reply to it */
  165.     CopyMem ( (APTR)imsg, (APTR)&nmsg, sizeof (struct IntuiMessage) );
  166.  
  167.     /* Reply to the message now that we're done with it */
  168.     ReplyMsg ((struct Message *) imsg);
  169.  
  170.     /* Process Intuition events */
  171.     switch (nmsg.Class)
  172.     {
  173.         /* Handle the close window gadget */
  174.         case CLOSEWINDOW:
  175.         if (nmsg.Qualifier & SHIFTED)
  176.             /* hide Intuition interface */
  177.             close_idcmp (ai, mh);
  178.         else
  179.             /* close down the application */
  180.             QuitFunc (ai, (struct Message *) &nmsg, NULL);
  181.         break;
  182.  
  183.         /* Handle keyboard events */
  184.         case RAWKEY:
  185.         HandleKeyEvent (ai, mh, &nmsg);
  186.         break;
  187.  
  188.         /* Handle events that pertain to gadgets */
  189.         case INTUITICKS:
  190.         case MOUSEMOVE:
  191.         case MOUSEBUTTONS:
  192.         case GADGETDOWN:
  193.         case GADGETUP:
  194.         HandleGadgEvent (ai, mh, &nmsg);
  195.         break;
  196.  
  197.         /* Handle menu events */
  198.         case MENUPICK:
  199.         HandleMenuEvent (ai, mh, &nmsg);
  200.         break;
  201.     }
  202.     }
  203.     return (TRUE);
  204. }
  205.  
  206. /* hide IDCMP message handler */
  207. BOOL close_idcmp (struct AppInfo * ai, struct MsgHandler * mh)
  208. {
  209.     struct IDCMPInfo *md = mh->mh_Data;
  210.  
  211.     if (mh)
  212.     {
  213.     if (md->win)
  214.     {
  215.         /* save current settings */
  216.         md->nw->Width = md->win->Width;
  217.         md->nw->Height = md->win->Height;
  218.         md->nw->LeftEdge = md->win->LeftEdge;
  219.         md->nw->TopEdge = md->win->TopEdge;
  220.  
  221.         /* clear the menu strip if there is one */
  222.         if (md->win->MenuStrip)
  223.         ClearMenuStrip (md->win);
  224.  
  225.         /* close the window */
  226.         CloseWindowSafely (md->win);
  227.         md->win = NULL;
  228.     }
  229.     }
  230.     return (TRUE);
  231. }
  232.  
  233. /* free resources for IDCMP message handler */
  234. BOOL shutdown_idcmp (struct AppInfo * ai, struct MsgHandler * mh)
  235. {
  236.     struct IDCMPInfo *md = mh->mh_Data;
  237.  
  238.     if (mh)
  239.     {
  240.     close_idcmp (ai, mh);        /* close window */
  241.     shutdown_key_array (md);    /* free keyboard array */
  242.  
  243.     DeletePort (md->msgport);    /* delete IDCMP port */
  244.     md->msgport = NULL;
  245.     }
  246.     return (TRUE);
  247. }
  248.  
  249. /* safely close a window that shares a message port with another window */
  250. VOID CloseWindowSafely (struct Window * win)
  251. {
  252.     struct IntuiMessage * msg, * succ;
  253.  
  254.     Forbid ();
  255.  
  256.     msg = (struct IntuiMessage *)win->UserPort->mp_MsgList.lh_Head;
  257.     while (succ = (struct IntuiMessage *)msg->ExecMessage.mn_Node.ln_Succ)
  258.     {
  259.     if (msg->IDCMPWindow == win)
  260.     {
  261.         Remove ((struct Node *)msg);
  262.         ReplyMsg ((struct Message *)msg);
  263.     }
  264.     msg = succ;
  265.     }
  266.     win->UserPort = NULL;
  267.     ModifyIDCMP (win, NULL);
  268.  
  269.     Permit ();
  270.     CloseWindow (win);
  271. }
  272.  
  273. /* Allocate resources for handling keyboard input */
  274. BOOL setup_key_array (struct IDCMPInfo * md, struct KeyboardCMD * KeyArray)
  275. {
  276.     register WORD cntr;
  277.  
  278.     /* Allow for NULL specification of a keyboard command array */
  279.     if (!KeyArray)
  280.     return (TRUE);
  281.  
  282.     /* Prepare for DeadKeyConvert */
  283.     if (!(OpenDevice ("console.device", -1L,
  284.               (struct IORequest *) & (md->ioreq), 0L)))
  285.     {
  286.     ConsoleDevice = (struct ConsoleDevice *) md->ioreq.io_Device;
  287.  
  288.     /* Allocate memory for the keyboard function map */
  289.     if (md->KeyFunctions =
  290.         AllocMem ((sizeof (WORD) * MAXKEYS), MEMF_CLEAR|MEMF_PUBLIC))
  291.     {
  292.         /* read in the key assignments */
  293.         for (cntr = 0; KeyArray[cntr].key != NULL; cntr++)
  294.         md->KeyFunctions[KeyArray[cntr].key] = KeyArray[cntr].funcID;
  295.         return (TRUE);
  296.     }
  297.     else
  298.         NotifyUser (NULL, "Not enough memory");
  299.  
  300.     CloseDevice ((struct IORequest *) & (md->ioreq));
  301.     }
  302.     else
  303.     NotifyUser (NULL, "Could not open console.device");
  304.  
  305.     return (FALSE);
  306. }
  307.  
  308. /* Release resources for handling keyboard input */
  309. VOID shutdown_key_array (struct IDCMPInfo * md)
  310. {
  311.     if (md)
  312.     {
  313.     if (md->KeyFunctions)
  314.         FreeMem (md->KeyFunctions, (sizeof (WORD) * MAXKEYS));
  315.     md->KeyFunctions = NULL;
  316.  
  317.     if (ConsoleDevice)
  318.         CloseDevice ((struct IORequest *) & (md->ioreq));
  319.     }
  320. }
  321.  
  322. /* Keyboard handling routines */
  323. VOID HandleKeyEvent (struct AppInfo * ai, struct MsgHandler * mh,
  324.              struct IntuiMessage * msg)
  325. {
  326.     struct IDCMPInfo *md = mh->mh_Data;
  327.     WORD FuncID = NO_FUNCTION;
  328.     WORD key, cur;
  329.     UBYTE buffer[17];
  330.  
  331.     strcpy (buffer, "               ");
  332.     key = (WORD) DeadKeyConvert (msg, buffer, 15L, 0L);
  333.     if (key > 0)
  334.     {
  335.     /* Get the ASCII value of the key that was pressed */
  336.     cur = buffer[0];
  337.  
  338.     /* Check to see if it was a special key; like a Function key,
  339.      * Help, or the Arrow keys.  Could also do additional checking for
  340.      * ALT, AMIGA and CTRL qualifiers by adding in a proportional
  341.      *weight for each one. */
  342.     if (key > 1 && cur == 155)
  343.         cur = SPECIAL + buffer[1];
  344.  
  345.     /* Get the function number assigned to this key */
  346.     FuncID = md->KeyFunctions[cur];
  347.  
  348.     if (FuncID != NO_FUNCTION)
  349.         /* Perform the function assigned to this key. */
  350.         PerfFunc (ai, (struct Message *)msg, ai->FuncTable[FuncID].name);
  351.     }
  352. }
  353.  
  354. /* Convert Raw keys to Vanilla keys */
  355. LONG DeadKeyConvert (msg, kbuffer, kbsize, kmap)
  356.     struct IntuiMessage *msg;
  357.     UBYTE *kbuffer;
  358.     LONG kbsize;
  359.     struct KeyMap *kmap;
  360. {
  361.     static struct InputEvent ievent =
  362.     {NULL, IECLASS_RAWKEY, 0, 0, 0};
  363.  
  364.     if (msg->Class != RAWKEY)
  365.     return (-2);
  366.     ievent.ie_Code = msg->Code;
  367.     ievent.ie_Qualifier = msg->Qualifier;
  368.     ievent.ie_position.ie_addr = *((APTR *) msg->IAddress);
  369.  
  370.     return (RawKeyConvert (&ievent, kbuffer, kbsize, kmap));
  371. }
  372.  
  373. /* Gadget handling routine */
  374. VOID HandleGadgEvent (struct AppInfo * ai, struct MsgHandler * mh,
  375.               struct IntuiMessage * msg)
  376. {
  377.     struct IDCMPInfo *md = mh->mh_Data;
  378.     struct EGadget *egad = (struct EGadget *) msg->IAddress;
  379.     WORD FuncID = NO_FUNCTION;
  380.     static ULONG glsecs = 0L, glmics = 0L;    /* For Gadget DoubleClick */
  381.  
  382.     switch (msg->Class)
  383.     {
  384.     /* Check to see if gadget is being held down and if there is a
  385.      * function to perform while it is being held. */
  386.     case MOUSEMOVE:
  387.     case INTUITICKS:
  388.         if (md->ActiveGad &&
  389.         md->ActiveGad->eg_Gadget.Flags & SELECTED)
  390.         {
  391.         /* gadget being held or dragged */
  392.         FuncID = md->ActiveGad->eg_Funcs[EG_HOLD];
  393.         }
  394.  
  395.         if (msg->Qualifier & IEQUALIFIER_RBUTTON)
  396.         {
  397.         /* Right mouse button pressed, abort operation */
  398.         FuncID = md->ActiveGad->eg_Funcs[EG_ABORT];
  399.  
  400.         /* clear the active gadget */
  401.         md->ActiveGad = NULL;
  402.  
  403.         /* only watch for necessary messages */
  404.         ModifyIDCMP (md->win, IDCMP_flagF);
  405.         }
  406.         break;
  407.  
  408.     /* Indicate that there is no active gadget now. */
  409.     case MOUSEBUTTONS:
  410.         if (msg->Code == SELECTUP)
  411.         {
  412.         /* clear the active gadget */
  413.         md->ActiveGad = NULL;
  414.  
  415.         /* only watch for necessary messages */
  416.         ModifyIDCMP (md->win, IDCMP_flagF);
  417.         }
  418.         break;
  419.  
  420.     /* Check to see if there is a function to perform on downpress or
  421.      * double-click of the gadget. */
  422.     case GADGETDOWN:
  423.  
  424.         /* Set the active gadget.  Only one gadget can EVER be active
  425.          * at a time (Intuition rule). */
  426.         md->ActiveGad = egad;
  427.  
  428.         /* tell the system that we need to watch for INTUITICKS
  429.          * and MOUSEMOVES if there is a hold function for this gadget */
  430.         if (egad->eg_Funcs[EG_HOLD] != NO_FUNCTION)
  431.         ModifyIDCMP (md->win, IDCMP_flagS);
  432.  
  433.         FuncID = egad->eg_Funcs[EG_DOWNPRESS];
  434.         if (egad->eg_Funcs[EG_DBLCLICK] != NO_FUNCTION)
  435.         {
  436.         /* If the gadget has a double-click function, then check to
  437.          * see if it has been double-clicked.  Notice that if there
  438.          * is a double-click function, then it over-rules the
  439.          *downpress function. */
  440.         if (DoubleClick (glsecs, glmics, msg->Seconds, msg->Micros))
  441.             FuncID = egad->eg_Funcs[EG_DBLCLICK];
  442.         else
  443.         {
  444.             glsecs = msg->Seconds;
  445.             glmics = msg->Micros;
  446.         }
  447.         }
  448.         break;
  449.  
  450.     /* Check to see if there is a function to perform on release of the
  451.      * gadget. */
  452.     case GADGETUP:
  453.         /* Clear the active gadget variable */
  454.         md->ActiveGad = NULL;
  455.  
  456.         /* only watch for necessary messages */
  457.         ModifyIDCMP (md->win, IDCMP_flagF);
  458.  
  459.         FuncID = egad->eg_Funcs[EG_RELEASE];
  460.         break;
  461.  
  462.     }
  463.  
  464.     /* Perform the function if there is one. */
  465.     if (FuncID != NO_FUNCTION)
  466.     PerfFunc (ai, (struct Message *) msg, ai->FuncTable[FuncID].name);
  467. }
  468.  
  469. /* Menu handling routine */
  470. VOID HandleMenuEvent (struct AppInfo * ai, struct MsgHandler * mh,
  471.               struct IntuiMessage * msg)
  472. {
  473.     struct EMenuItem *item;
  474.     UWORD selection = msg->Code;
  475.  
  476.     /* Shut down menu events while we're processing these. Any function that
  477.      * opens its own window and ignores events from the main window, should
  478.      * also set a busy pointer in the main window. */
  479.     msg->IDCMPWindow->Flags |= RMBTRAP;
  480.  
  481.     /* Process all menu events */
  482.     while ((selection != MENUNULL) && (!ai->Done))
  483.     {
  484.     /* Get the Extended MenuItem structure address */
  485.     item = (struct EMenuItem *)
  486.       ItemAddress (msg->IDCMPWindow->MenuStrip, (LONG) selection);
  487.  
  488.     /* Mutual Excluded items should all call the same function.  And that
  489.      * function should do any processing based on the currently selected
  490.      * item. */
  491.     PerfFunc (ai, (struct Message *)msg,
  492.           ai->FuncTable[item->emi_MenuID].name);
  493.  
  494.     /* Get the next selection */
  495.     selection = item->emi_Item.NextSelect;
  496.     }
  497.  
  498.     /* Turn menu events back on. */
  499.     msg->IDCMPWindow->Flags &= ~RMBTRAP;
  500. }
  501.