home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d500 / wiconify.lha / wIconify / wKeys.lzh / Source / wKeys-Handler.c < prev    next >
C/C++ Source or Header  |  1991-04-21  |  13KB  |  493 lines

  1. /*
  2.  *  wKeys-Handler.c   Input Handler for wKeyw, which moves and activates 
  3.  *                    windows and screensin response to keystrokes
  4.  *
  5.  *              Copyright (c) 1987,1988 by Davide P. Cervone
  6.  *  You may use this code provided this copyright notice is left intact.
  7.  */
  8.  
  9. #include <exec/types.h>
  10. #include <exec/memory.h>
  11. #include <devices/inputevent.h>
  12. #include <intuition/intuitionbase.h>
  13.  
  14. #include "wKeys.h"
  15.  
  16. static char *program = "wKeys-Handler";
  17. static int   version = 4;
  18. static char *date    = "April 1991";
  19. static char *author  = "Copyright (c) 1987,1988,1991 by Davide P. Cervone";
  20.  
  21. extern struct Layer *WhichLayer();
  22. extern struct IntuiMessage *GetMsg();
  23. extern struct IntuiMessage *AllocMem();
  24. extern void myHandlerStub();
  25.  
  26.  
  27. #define WINDOW(layer)   ((struct Window *)((layer)->Window))
  28.  
  29. #define SCREENTOP\
  30.    (theScreen->TopEdge << ((theScreen->ViewPort.Modes & LACE)? 0: 1))
  31.  
  32. #define IMSIZE          ((ULONG)sizeof(struct IntuiMessage))
  33. #define NEWMESSAGE(m)   (m = AllocMem(IMSIZE,MEMF_PUBLIC | MEMF_CLEAR))
  34. #define FREEMESSAGE(m)  FreeMem(m,IMSIZE);
  35.  
  36. struct IntuitionBase *IntuitionBase = NULL;
  37. struct LayersBase    *LayersBase    = NULL;
  38. struct SysBase       *SysBase       = NULL;
  39.  
  40. static struct HotKey *Key = NULL;
  41. static int KeyCount = 0;
  42. static struct MsgPort *ReplyPort = NULL;
  43.  
  44.  
  45. /*
  46.  *  Setup()
  47.  *
  48.  *  wKeys calls LoadSeg() to get this handler into memory.  The segment
  49.  *  that it gets points to this routine.  wKeys calls Setup() and 
  50.  *  passes the IntuitionBase, LayersBase and SysBase pointers that it
  51.  *  has initialized (with OpenLibrary()).  wKeys also passes the KeyArray
  52.  *  and KeyCount which hold the key bindings.  Setup returns a pointer to
  53.  *  the actual input handler, which wKeys installs, and sets the version
  54.  *  number so that hotKey can report the handler's version.
  55.  */
  56.  
  57. long Setup(Ibase,Lbase,Sbase,theKeys,Count,Port,VersionPtr)
  58. struct IntuitionBase *Ibase;
  59. struct LayersBase *Lbase;
  60. struct SysBase *Sbase;
  61. struct HotKey *theKeys;
  62. struct MsgPort *Port;
  63. int *VersionPtr;
  64. int Count;
  65. {
  66.    IntuitionBase = Ibase;
  67.    LayersBase = Lbase;
  68.    SysBase = Sbase;
  69.    Key = theKeys;
  70.    KeyCount = Count;
  71.    ReplyPort = Port;
  72.    *VersionPtr = version;
  73.    return((long) &myHandlerStub);
  74. }
  75.  
  76.  
  77. /*
  78.  *  TopWindow()
  79.  *
  80.  *  Find the top window of the specified screen.  Start at the top layer of
  81.  *  the screen and move backward as long as the layer exists and has no
  82.  *  window connected to it.  Return the window associated with the final 
  83.  *  layer, if any.
  84.  */
  85.  
  86. static struct Window *TopWindow(theScreen)
  87. struct Screen *theScreen;
  88. {
  89.    struct Window *theWindow = NULL;
  90.    struct Layer *theLayer;
  91.    
  92.    theLayer = theScreen->LayerInfo.top_layer;
  93.    while (theLayer && WINDOW(theLayer) == NULL) theLayer = theLayer->back;
  94.    if (theLayer) theWindow = WINDOW(theLayer);
  95.    return(theWindow);
  96. }
  97.  
  98.  
  99. /*
  100.  *  BottomWindow()
  101.  *
  102.  *  Find the bottom window of the specified screen.  Start at the top layer
  103.  *  and as long as the layer exists, go to the next layer back.  If the
  104.  *  layer has a window attached, consider that to be the bottom window until
  105.  *  a lower one is found.
  106.  */
  107.  
  108. static struct Window *BottomWindow(theScreen)
  109. struct Screen *theScreen;
  110. {
  111.    struct Window *theWindow = NULL;
  112.    struct Layer *theLayer = theScreen->LayerInfo.top_layer;
  113.    
  114.    while (theLayer)
  115.    {
  116.       if (WINDOW(theLayer) && wIsIconified(WINDOW(theLayer)) == FALSE)
  117.          theWindow = WINDOW(theLayer);
  118.       theLayer = theLayer->back;
  119.    }
  120.    return(theWindow);
  121. }
  122.  
  123.  
  124. /*
  125.  *  NextWindow()
  126.  *
  127.  *  Find the next window below the specified window (wrap arround to the top
  128.  *  if the window is the bottom one).  Start with the window's layer and go
  129.  *  back until a layer with a window is found, or no more layers exist.  If
  130.  *  a window was found, return it, otherwise, use the top window.
  131.  */
  132.  
  133. static struct Window *NextWindow(theWindow)
  134. struct Window *theWindow;
  135. {
  136.    struct Layer  *theLayer  = theWindow->WLayer;
  137.    
  138.    do
  139.       theLayer = theLayer->back;
  140.    while (theLayer && (WINDOW(theLayer) == NULL ||
  141.           wIsIconified(WINDOW(theLayer))));
  142.    if (theLayer)
  143.       theWindow = WINDOW(theLayer);
  144.      else
  145.       theWindow = TopWindow(theWindow->WScreen);
  146.    return(theWindow);
  147. }
  148.  
  149.  
  150. /*
  151.  *  PreviousWindow()
  152.  *
  153.  *  Find the window that is on top of the specified window (or NULL if there
  154.  *  are no windows above it).  Start with the window's layer, and move to
  155.  *  the layer in front until a layer with a (different) window is found, or
  156.  *  until no more layers exist.  If a window was found, return it, otherwise
  157.  *  return NULL.
  158.  */
  159.  
  160. static struct Window *PreviousWindow(theWindow)
  161. struct Window *theWindow;
  162. {
  163.    struct Layer  *theLayer  = theWindow->WLayer;
  164.    
  165.    do
  166.       theLayer = theLayer->front;
  167.    while (theLayer && (WINDOW(theLayer) == NULL ||
  168.                        WINDOW(theLayer) == theWindow));
  169.    if (theLayer)
  170.       theWindow = WINDOW(theLayer);
  171.      else
  172.       theWindow = NULL;
  173.    return(theWindow);
  174. }
  175.  
  176.  
  177. /*
  178.  *  BackScreenToFront()
  179.  *
  180.  *  Bring the bottom-most screen to the top, and activate its top window.
  181.  *  While there is a screen following the current one, move the the next screen.
  182.  *  Bring that screen to the front and find its top window.  If one was found,
  183.  *  activate the window.
  184.  */
  185.  
  186. static void BackScreenToFront()
  187. {
  188.    struct Screen *theScreen = IntuitionBase->FirstScreen;
  189.    struct Window *theWindow;
  190.    
  191.    if (theScreen)
  192.    {
  193.       while (theScreen->NextScreen) theScreen = theScreen->NextScreen;
  194.       ScreenToFront(theScreen);
  195.       theWindow = TopWindow(theScreen);
  196.       if (theWindow) ActivateWindow(theWindow);
  197.    }
  198. }
  199.  
  200.  
  201. /*
  202.  *  FrontScreenToBack()
  203.  *
  204.  *  Move the top screen to the back and activate the top window on the new
  205.  *  top screen.
  206.  */
  207.  
  208. static void FrontScreenToBack()
  209. {
  210.    struct Screen *theScreen = IntuitionBase->FirstScreen;
  211.    struct Window *theWindow;
  212.  
  213.    if (theScreen)
  214.    {
  215.       ScreenToBack(theScreen);
  216.       theScreen = IntuitionBase->FirstScreen;
  217.       if (theScreen)
  218.       {
  219.          theWindow = TopWindow(theScreen);
  220.          if (theWindow) ActivateWindow(theWindow);
  221.       }
  222.    }
  223. }
  224.  
  225.  
  226. /*
  227.  *  ActivatePreviousWindow()
  228.  *
  229.  *  Get the window previous to the current window (if none, then get the
  230.  *  bottom window in the active screen), and activate that window.
  231.  */
  232.  
  233. static void ActivatePreviousWindow()
  234. {
  235.    struct Window *theWindow = PreviousWindow(IntuitionBase->ActiveWindow);
  236.    
  237.    if (theWindow == NULL) theWindow = BottomWindow(IntuitionBase->ActiveScreen);
  238.    if (theWindow) ActivateWindow(theWindow);
  239. }
  240.  
  241.  
  242. /*
  243.  *  ActivateNextWindow()
  244.  *
  245.  *  Get the window below the current window and activate it.
  246.  */
  247.  
  248. static void ActivateNextWindow()
  249. {
  250.    struct Window *theWindow = NextWindow(IntuitionBase->ActiveWindow);
  251.    
  252.    if (theWindow) ActivateWindow(theWindow);
  253. }
  254.  
  255.  
  256. /*
  257.  *  CurrentWindowToBack()
  258.  *
  259.  *  Send the current window to the back of the list.
  260.  */
  261.  
  262. static void CurrentWindowToBack()
  263. {
  264.    struct Window *theWindow = IntuitionBase->ActiveWindow;
  265.    
  266.    if (theWindow && (theWindow->Flags & BACKDROP) == 0)
  267.       WindowToBack(theWindow);
  268. }
  269.  
  270.  
  271. /*
  272.  *  CurrentWindowToFront()
  273.  *
  274.  *  Send the current window to the top of the list.
  275.  */
  276.  
  277. static void CurrentWindowToFront()
  278. {
  279.    struct Window *theWindow = IntuitionBase->ActiveWindow;
  280.    
  281.    if (theWindow) WindowToFront(theWindow);
  282. }
  283.  
  284.  
  285. /*
  286.  *  BackWindowToFront()
  287.  *
  288.  *  Move the bottom window to the top and activate it.  Get the bottom window,
  289.  *  skipping over backdrop windows.  If one is found, bring it to the front,
  290.  *  and activate it.
  291.  */
  292.  
  293. static void BackWindowToFront()
  294. {
  295.    struct Window *theWindow = BottomWindow(IntuitionBase->ActiveScreen);
  296.    
  297.    if (theWindow)
  298.    {
  299.       while (theWindow && (theWindow->Flags & BACKDROP))
  300.          theWindow = PreviousWindow(theWindow);
  301.       if (theWindow)
  302.       {
  303.          WindowToFront(theWindow);
  304.          ActivateWindow(theWindow);
  305.       }
  306.    }
  307. }
  308.  
  309.  
  310. /*
  311.  *  FrontWindowToBack()
  312.  *
  313.  *  Move the top window to the back, and activate the new top window.
  314.  *  Get the top window, and then the window following it.  Send the top window
  315.  *  to the back, and activate the next window.
  316.  */
  317.  
  318. static void FrontWindowToBack()
  319. {
  320.    struct Window *theWindow  = TopWindow(IntuitionBase->ActiveScreen);
  321.    struct Window *nextWindow = NextWindow(theWindow);
  322.    
  323.    if (theWindow && (theWindow->Flags & BACKDROP) == 0)
  324.    {
  325.       WindowToBack(theWindow);
  326.       if (nextWindow) ActivateWindow(nextWindow);
  327.    }
  328. }
  329.  
  330.  
  331. /*
  332.  *  CloseCurrentWindow()
  333.  *
  334.  *  If the current window has the CLOSEWINDOW IDCMP flag, then 
  335.  *  send it a CLOSEWINDOW IDCMP message.  Unfortunately, the workbench
  336.  *  has the CLOSWINDOW flag set, and it crashes if you send it a close
  337.  *  message; therefore, CloseCurrentWindow will not sent a CLOSWINDOW
  338.  *  event to a BACKDROP window.  This seemed the easiest way to rule out
  339.  *  the workbench without too much overhead.
  340.  *
  341.  *  The message will be replied to the ReplyPort, which is checked in the 
  342.  *  input handler.  Any messages that get returned are freed.
  343.  */
  344.  
  345. static void CloseCurrentWindow()
  346. {
  347.    struct Window *theWindow = IntuitionBase->ActiveWindow;
  348.    struct IntuiMessage *theMessage;
  349.    
  350.    if (theWindow && (theWindow->IDCMPFlags & CLOSEWINDOW) && 
  351.       (theWindow->Flags & BACKDROP) == 0)
  352.    {
  353.       if (NEWMESSAGE(theMessage))
  354.       {
  355.          theMessage->Class = CLOSEWINDOW;
  356.          theMessage->IDCMPWindow = theWindow;
  357.          theMessage->ExecMessage.mn_ReplyPort = ReplyPort;
  358.          PutMsg(theWindow->UserPort,theMessage);
  359.       }
  360.    }
  361. }
  362.  
  363.  
  364. /*
  365.  *  WindowToIcon()
  366.  *
  367.  *  Iconify the current window if wIconify is running.
  368.  */
  369.  
  370. static void WindowToIcon()
  371. {
  372.    struct Window *theWindow = IntuitionBase->ActiveWindow;
  373.    
  374.    if (theWindow) wIconify(theWindow);
  375. }
  376.  
  377.  
  378. /*
  379.  *  IconToWindow()
  380.  *
  381.  *  Restore the selected wIconify icon to a window.  wIconify must be running,
  382.  *  and an icon must be selected.
  383.  */
  384.  
  385. static void IconToWindow()
  386. {
  387.    struct Screen *theScreen = IntuitionBase->ActiveScreen;
  388.  
  389.    if (theScreen) wOpenSelected(theScreen);
  390. }
  391.  
  392.  
  393. /*
  394.  *  SelectNextIcon()
  395.  *
  396.  *  Tells wIconify to select the next window icon on the screen.  If no
  397.  *  icon is selected, then select the first icon.
  398.  */
  399.  
  400. static void SelectNextIcon()
  401. {
  402.    struct Screen *theScreen = IntuitionBase->ActiveScreen;
  403.  
  404.    if (theScreen) wSelectNext(theScreen);
  405. }
  406.  
  407.  
  408. /*
  409.  *  Array of functions that perform the different actions associated with 
  410.  *  the hot-keys.  These are called by the handler routine.
  411.  */
  412.  
  413. typedef void (*FUNCTION)();
  414.  
  415. static FUNCTION Action[] =
  416. {
  417.    NULL,
  418.    &BackScreenToFront,
  419.    &FrontScreenToBack,
  420.    &ActivatePreviousWindow,
  421.    &ActivateNextWindow,
  422.    &CurrentWindowToBack,
  423.    &CurrentWindowToFront,
  424.    &BackWindowToFront,
  425.    &FrontWindowToBack,
  426.    &CloseCurrentWindow,
  427.    &WindowToIcon,
  428.    &IconToWindow,
  429.    &SelectNextIcon
  430. };
  431.  
  432.  
  433. /*
  434.  *  myHandler()
  435.  *
  436.  *  This is the input handler.  
  437.  *  First check if there are any returned CLOSEWINDOW events, then,
  438.  *  For each event in the event list:
  439.  *  If the event is a raw key event, then
  440.  *    make the KeyCode longword for that event's code and qualifier,
  441.  *    binary search the Key[] array for a matching entry (only consider
  442.  *      the qualifiers specified by the KeyMask).  Since most keys pressed
  443.  *      will NOT match a hot-key, we want the search to be as fast as 
  444.  *      possible, so we use a binary search rather than a linear search.
  445.  *    set NoHotKey if the key is not a hot key.
  446.  *  if the key was not a hot key,
  447.  *    go on to the next key
  448.  *   otherwise,
  449.  *    perform the function for the specified hot key,
  450.  *    remove the hot key from the event list.
  451.  *
  452.  *  When all the events have been checked, return the event list so that
  453.  *  Intuition can do its thing.
  454.  */
  455.  
  456. struct InputEvent *myHandler(EventList,data)
  457. struct InputEvent *EventList;
  458. APTR data;
  459. {
  460.    register struct InputEvent **EventPtr = &EventList;
  461.    register struct InputEvent *theEvent;
  462.    register long   theKey;
  463.    register short  Num,Min,Max;
  464.    register long   NoHotKey;
  465.    struct IntuiMessage *theMessage;
  466.  
  467.    while (theMessage = GetMsg(ReplyPort)) FREEMESSAGE(theMessage);
  468.  
  469.    Forbid();
  470.    while((theEvent = *EventPtr) != NULL)
  471.    {
  472.       NoHotKey = TRUE;
  473.       if (theEvent->ie_Class == IECLASS_RAWKEY)
  474.       {
  475.          theKey = KEY(theEvent);
  476.          Max = KeyCount; Min = -1;
  477.          while ((Num = (Min + Max) >> 1) != Min &&
  478.                 (NoHotKey = (theKey & Key[Num].hk_KeyMask) -
  479.                              Key[Num].hk_KeyCode) != 0)
  480.             if (NoHotKey > 0) Min = Num; else Max = Num;
  481.       }
  482.       if (NoHotKey)
  483.       {
  484.          EventPtr = &(theEvent->ie_NextEvent);
  485.       } else {
  486.          (*(Action[Key[Num].hk_Action]))();
  487.          *EventPtr = theEvent->ie_NextEvent;
  488.       }
  489.    }
  490.    Permit();
  491.    return(EventList);
  492. }
  493.