home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1995 November / PCWK1195.iso / inne / podstawy / os2 / nakladki / pc2v190.exe / SOURCE.ZIP / Source / PC2Hook.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-01  |  40.4 KB  |  615 lines

  1. /***********************************************************************\
  2.  *                                PC2.c                                *
  3.  *           Copyright (C) by Stangl Roman, 1993, 1994, 1995           *
  4.  * This Code may be freely distributed, provided the Copyright isn't   *
  5.  * removed.                                                            *
  6.  *                                                                     *
  7.  * Pc2Hook.c    Hook the input queue to filter certain messages.       *
  8.  *                                                                     *
  9. \***********************************************************************/
  10.  
  11. static char RCSID[]="@(#) $Header: Pc2Hook.c Version 1.90 05,1995 $ (LBL)";
  12.  
  13. #define         _FILE_  "PC/2 - PC2Hook.c V1.90"
  14.  
  15. #include        "PC2.h"                 /* User include files */
  16. #include        "Error.h"
  17.  
  18.                                         /* Reroute message from original desktionation 
  19.                                            to NULLHANDLE and return TRUE no to pass message
  20.                                            to next hook in chain */
  21. #define         REROUTEMSGTONULL()  pqmsg->hwnd=NULLHANDLE; \
  22.                                     return(TRUE);
  23.  
  24. /*--------------------------------------------------------------------------------------*\
  25.  * The following functions are exported in PC2Hook.def                                  *
  26. \*--------------------------------------------------------------------------------------*/
  27. void EXPENTRY   PC2DLL_SetParameters(void);
  28. BOOL EXPENTRY   PC2DLL_Hook(HAB hab, PQMSG pqmsg, ULONG option);
  29.  
  30. /*--------------------------------------------------------------------------------------*\
  31.  * The following datastructures are exported in PC2Hook.def                             *
  32. \*--------------------------------------------------------------------------------------*/
  33. HOOKPARAMETERS  HookParameters;         /* Central control structure for PC/2 */
  34. KEYDATA         KeyData[KEYDATACOUNT]={ /* Hotkeys defined within PC/2 */
  35.                     {KC_CTRL, '0', 0x0B, FALSE, NULL}, {KC_CTRL, '1', 0x02, FALSE, NULL}, {KC_CTRL, '2', 0x03, FALSE, NULL},
  36.                     {KC_CTRL, '3', 0x04, FALSE, NULL}, {KC_CTRL, '4', 0x05, FALSE, NULL}, {KC_CTRL, '5', 0x06, FALSE, NULL},
  37.                     {KC_CTRL, '6', 0x07, FALSE, NULL}, {KC_CTRL, '7', 0x08, FALSE, NULL}, {KC_CTRL, '8', 0x09, FALSE, NULL},
  38.                     {KC_CTRL, '9', 0x0A, FALSE, NULL},
  39.                     {KC_CTRL, 'A', 0x1E, FALSE, NULL}, {KC_CTRL, 'B', 0x30, FALSE, NULL}, {KC_CTRL, 'C', 0x2E, FALSE, NULL},
  40.                     {KC_CTRL, 'D', 0x20, FALSE, NULL}, {KC_CTRL, 'E', 0x12, FALSE, NULL}, {KC_CTRL, 'F', 0x21, FALSE, NULL},
  41.                     {KC_CTRL, 'G', 0x22, FALSE, NULL}, {KC_CTRL, 'H', 0x23, FALSE, NULL}, {KC_CTRL, 'I', 0x17, FALSE, NULL},
  42.                     {KC_CTRL, 'J', 0x24, FALSE, NULL}, {KC_CTRL, 'K', 0x25, FALSE, NULL}, {KC_CTRL, 'L', 0x26, FALSE, NULL},
  43.                     {KC_CTRL, 'M', 0x32, FALSE, NULL}, {KC_CTRL, 'N', 0x31, FALSE, NULL}, {KC_CTRL, 'O', 0x18, FALSE, NULL},
  44.                     {KC_CTRL, 'P', 0x19, FALSE, NULL}, {KC_CTRL, 'Q', 0x10, FALSE, NULL}, {KC_CTRL, 'R', 0x13, FALSE, NULL},
  45.                     {KC_CTRL, 'S', 0x1F, FALSE, NULL}, {KC_CTRL, 'T', 0x14, FALSE, NULL}, {KC_CTRL, 'U', 0x16, FALSE, NULL},
  46.                     {KC_CTRL, 'V', 0x2F, FALSE, NULL}, {KC_CTRL, 'W', 0x11, FALSE, NULL}, {KC_CTRL, 'X', 0x2D, FALSE, NULL},
  47.                     {KC_CTRL, 'Y', 0x15, FALSE, NULL}, {KC_CTRL, 'Z', 0x2C, FALSE, NULL},
  48.                     {KC_ALT, '0', 0x0B, FALSE, NULL}, {KC_ALT, '1', 0x02, FALSE, NULL}, {KC_ALT, '2', 0x03, FALSE, NULL},
  49.                     {KC_ALT, '3', 0x04, FALSE, NULL}, {KC_ALT, '4', 0x05, FALSE, NULL}, {KC_ALT, '5', 0x06, FALSE, NULL},
  50.                     {KC_ALT, '6', 0x07, FALSE, NULL}, {KC_ALT, '7', 0x08, FALSE, NULL}, {KC_ALT, '8', 0x09, FALSE, NULL},
  51.                     {KC_ALT, '9', 0x0A, FALSE, NULL},
  52.                     {KC_ALT, 'A', 0x1E, FALSE, NULL}, {KC_ALT, 'B', 0x30, FALSE, NULL}, {KC_ALT, 'C', 0x2E, FALSE, NULL},
  53.                     {KC_ALT, 'D', 0x20, FALSE, NULL}, {KC_ALT, 'E', 0x12, FALSE, NULL}, {KC_ALT, 'F', 0x21, FALSE, NULL},
  54.                     {KC_ALT, 'G', 0x22, FALSE, NULL}, {KC_ALT, 'H', 0x23, FALSE, NULL}, {KC_ALT, 'I', 0x17, FALSE, NULL},
  55.                     {KC_ALT, 'J', 0x24, FALSE, NULL}, {KC_ALT, 'K', 0x25, FALSE, NULL}, {KC_ALT, 'L', 0x26, FALSE, NULL},
  56.                     {KC_ALT, 'M', 0x32, FALSE, NULL}, {KC_ALT, 'N', 0x31, FALSE, NULL}, {KC_ALT, 'O', 0x18, FALSE, NULL},
  57.                     {KC_ALT, 'P', 0x19, FALSE, NULL}, {KC_ALT, 'Q', 0x10, FALSE, NULL}, {KC_ALT, 'R', 0x13, FALSE, NULL},
  58.                     {KC_ALT, 'S', 0x1F, FALSE, NULL}, {KC_ALT, 'T', 0x14, FALSE, NULL}, {KC_ALT, 'U', 0x16, FALSE, NULL},
  59.                     {KC_ALT, 'V', 0x2F, FALSE, NULL}, {KC_ALT, 'W', 0x11, FALSE, NULL}, {KC_ALT, 'X', 0x2D, FALSE, NULL},
  60.                     {KC_ALT, 'Y', 0x15, FALSE, NULL}, {KC_ALT, 'Z', 0x2C, FALSE, NULL} };
  61.  
  62. /*--------------------------------------------------------------------------------------*\
  63.  * The following datastructures are local for in PC2Hook.dll but shared for all         *
  64.  * processes in whose context this hook gets called.                                    *
  65. \*--------------------------------------------------------------------------------------*/
  66. ULONG                   ulMoveFlag;     /* xxxxxxxx (<-Bit 0)
  67.                                                   | Move all windows in x direction
  68.                                                  |  Move in -x direction
  69.                                                 |   Move in y direction
  70.                                                |    Move in -y direction
  71.                                               |     Click required to move */
  72. QUERYRECFROMRECT        QueryRect;      /* Rectangle to query underlaying containers */
  73. ULONG   ulButtonDown;                   /* Last button down on PM, either WM_BUTTON1DOWN
  74.                                            or WM_BUTTON2DOWN or 0 if pointer is not over
  75.                                            PM */
  76. UCHAR   ucClassname[32];                /* Window class e.g. #1 for WC_FRAME */
  77. UCHAR   ucWindowText[64];               /* Window name e.g. OS/2 2.0 Desktop */
  78. HWND    hwndActiveWindow;               /* Window handle of active frame class window on Desktop */
  79. HWND    hwndLastActiveWindow;           /* Window handle of last frame class window set active */
  80. HWND    hwndApplication;                /* Window handle of application under mouse pointer */
  81.                                         /* Window handle of application's parent window */
  82. HWND    hwndApplicationParent;  
  83. HWND    hwndTitlebar;                   /* Window handle of application's titlebar */
  84. HWND    hwndLastControl;                /* Window handle of last window set active  by moving
  85.                                            mouse pointer onto it */
  86. HWND    hwndActiveControl;              /* Window handle of window below mouse pointer */
  87. HWND    hwndFrameClick;                 /* Parent window handle of the window we clicked on */
  88. HWND    hwndWindow;                     /* The window that wants to top op z-order */
  89. HWND    hwndOwner;                      /* Its owner */
  90. USHORT  usFlags;                        /* KC_* flags */
  91. UCHAR   ucScanCode;                     /* Keyboard scan code of character pressed */
  92. KEYDATA *pKeyDataIndex;                 /* Pointer to KEYDATA structure in array */
  93. ULONG   ulKeyDataIndex;                 /* Array index */
  94.  
  95. /*--------------------------------------------------------------------------------------*\
  96.  * This procedure saves the data used in the PC/2 main procedure for use within the     *
  97.  * DLL.                                                                                 *
  98.  * Req:                                                                                 *
  99.  *      none                                                                            *
  100.  * Returns:                                                                             *
  101.  *      none                                                                            *
  102. \*--------------------------------------------------------------------------------------*/
  103. void EXPENTRY   PC2DLL_SetParameters(void)
  104. {
  105.                                         /* Initialize to query the topmost underlaying
  106.                                            container, that is partially hit by a rectangle
  107.                                            around the pointer */
  108. QueryRect.cb=sizeof(QUERYRECFROMRECT);
  109. QueryRect.fsSearch=CMA_PARTIAL | CMA_ZORDER;
  110. ulButtonDown=0;
  111. }
  112.  
  113. /*--------------------------------------------------------------------------------------*\
  114.  * This procedure implements the hook of the input queue into the system queue.         *
  115.  * Req:                                                                                 *
  116.  *      hab ........... Anchor block handle                                             *
  117.  *      pqmsg ......... Pointer to system QMSG structure                                *
  118.  *      option ........ PM_REMOVE ..... message is being removed                        *
  119.  *                      PM_NOREMOVE ... message is not being removed                    *
  120.  * Returns:                                                                             *
  121.  *      FALSE ......... OS/2 should process QMSG in the normal way passing to next hook *
  122.  *                      or to the application                                           *
  123.  *      TRUE .......... OS/2 doesn't pass the message to next hook or the application   *
  124. \*--------------------------------------------------------------------------------------*/
  125. BOOL EXPENTRY   PC2DLL_InputHook(HAB hab, PQMSG pqmsg, ULONG option)
  126. {
  127.  
  128.                                         /* Return if mouse is captured */
  129. if(WinQueryCapture(HWND_DESKTOP)!=NULLHANDLE) return(FALSE);
  130. /*                                                                                      *\
  131.  * Here we catch mouse button clicks on the PM to be able to send PC/2 a message when   *
  132.  * it should display the window list, because the window list is only displayed if the  *
  133.  * mouse is clicked on the WPS (not displaying the window list on PM).                  *
  134.  * The window list is invoked (like on the WPS) when one mouse button is down, and the  *
  135.  * other mouse button is pressed down too, but only if we are over PM.                  *
  136. \*                                                                                      */
  137. switch(pqmsg->msg)
  138. {
  139. case WM_BUTTON1DOWN:
  140.                                         /* If user clicked on the Desktop switch focus to Desktop */
  141.     if(pqmsg->hwnd==HookParameters.hwndDesktop)
  142.         {
  143.                                         /* Get the currently active top level window, so that
  144.                                            PC/2 can switch back to this window, when the session
  145.                                            started needed only be started in background. Be sure
  146.                                            that the top level window gets saved, but not the WPS,
  147.                                            because when the Popup-Menu gets activated with a double
  148.                                            click, the first click switches the focus to the WPS,
  149.                                            and the active window for the second click would then
  150.                                            be the WPS (and activated afterwards which we want to
  151.                                            avoid)  */
  152.         hwndActiveWindow=WinQueryActiveWindow(HWND_DESKTOP);
  153.         if(hwndActiveWindow!=HookParameters.hwndDesktop)
  154.             HookParameters.hwndActiveWindow=hwndActiveWindow;
  155.         WinFocusChange(HWND_DESKTOP, pqmsg->hwnd, 0);
  156.         }
  157.                                         /* If user clicked on the WPS, ensure we keep the top level
  158.                                            window stored, that had the focus before the WPS */
  159.     if(pqmsg->hwnd==HookParameters.hwndWPS)
  160.         {
  161.         hwndActiveWindow=WinQueryActiveWindow(HWND_DESKTOP);
  162.         if(hwndActiveWindow!=WinQueryWindow(HookParameters.hwndDesktop, QW_PARENT))
  163.             HookParameters.hwndActiveWindow=hwndActiveWindow;
  164.         }
  165.                                         /* If one button is down and other button was down before
  166.                                            save it because window list requires second button
  167.                                            down too */
  168.     if(ulButtonDown!=WM_BUTTON2DOWN)
  169.         ulButtonDown=WM_BUTTON1DOWN;
  170.     else
  171.         {
  172.         ulButtonDown=WM_WINDOWLIST;
  173.                                         /* If the user holds down both mouse buttons on PM display Window List */
  174.         if(pqmsg->hwnd==HookParameters.hwndDesktop)
  175.             {
  176.             WinPostMsg(HookParameters.hwndClient, WM_WINDOWLIST, MPFROMLONG(pqmsg->mp1), NULL);
  177.             REROUTEMSGTONULL()
  178.             }
  179.         }
  180.     break;
  181.  
  182. case WM_BUTTON2DOWN:
  183.     if(pqmsg->hwnd==HookParameters.hwndDesktop)
  184.         WinFocusChange(HWND_DESKTOP, pqmsg->hwnd, 0);
  185.     if(ulButtonDown!=WM_BUTTON1DOWN)
  186.         ulButtonDown=WM_BUTTON2DOWN;
  187.     else
  188.         {
  189.         ulButtonDown=WM_WINDOWLIST;
  190.         if(pqmsg->hwnd==HookParameters.hwndDesktop)
  191.             {
  192.             WinPostMsg(HookParameters.hwndClient, WM_WINDOWLIST, MPFROMLONG(pqmsg->mp1), NULL);
  193.             REROUTEMSGTONULL()
  194.             }
  195.         }
  196.     break;
  197.  
  198. case WM_MOUSEMOVE:
  199.                                         /* If the mouse is not over PM reset window list flag */
  200.     if(pqmsg->hwnd!=HookParameters.hwndDesktop)
  201.         ulButtonDown=0;
  202.     break;
  203.  
  204. case WM_BUTTON1UP:
  205. case WM_BUTTON2UP:
  206.                                         /* If the mouse is released reset window list flag */
  207.     ulButtonDown=0;
  208.     break;
  209. }
  210. /*                                                                                      *\
  211.  * Here we catch all WM_BUTTON2DOWN messages. If it was clicked on any window's         *
  212.  * titlebar then set this window to the bottom of the Desktop. WM_BUTTON2DOWN is used   *
  213.  * to prevent the moving frame to be drawn (which is the default action of a            *
  214.  * WM_BUTTON2DOWN message on a window's titlebar.                                       *
  215.  * This function using WM_BUTTON2DBLCLK was first implemented by Robert Mahoney's       *
  216.  * utiltiy WinBack, modified by Rolf Knebel to add this functionality to PC/2. However  *
  217.  * using a doubleclick with mouse button 2 has the drawback that the window is brought  *
  218.  * into the foreground first (because clicking on the titlebar activates a window) and  *
  219.  * then moved to the bottom (causing many unnecessary drawings).                        *
  220. \*                                                                                      */
  221. if((pqmsg->msg==WM_BUTTON2DOWN) && (HookParameters.ulStatusFlag & BUTTON2ZORDER))
  222.     {
  223.                                         /* Parent window handle of the window we clicked on */
  224.     hwndFrameClick=WinQueryWindow(pqmsg->hwnd, QW_PARENT);
  225.  
  226.                                         /* If we click on a titlebar the current window handle
  227.                                            equals the parent's titlebar window handle. If the
  228.                                            ALT key is pressed we pass this message to the titlebar
  229.                                            instead of processing to change its z-order */
  230.     if((pqmsg->hwnd==WinWindowFromID(hwndFrameClick, FID_TITLEBAR)) &&
  231.         (!(WinGetKeyState(HWND_DESKTOP, VK_ALT) & 0x8000)))
  232.         {                               /* Set it to the bottom of all windows */
  233.         WinSetWindowPos(hwndFrameClick, HWND_BOTTOM, 0, 0, 0, 0, SWP_ZORDER|SWP_DEACTIVATE);
  234.                                         /* Only activate window immediately under mouse if
  235.                                            the CTRL key is not pressed */
  236.         if(!(WinGetKeyState(HWND_DESKTOP, VK_CTRL) & 0x8000))
  237.             {
  238.                                         /* For some unknown reasons querying and activating the
  239.                                            new window immediately under the mouse pointer does not
  240.                                            work here. The same code in PC/2's client window procedure
  241.                                            works, I assume it has something to with that the hook
  242.                                            blocks the message queue until it returns. */
  243.             WinPostMsg(HookParameters.hwndClient, WM_ZORDER, MPFROMLONG(pqmsg->mp1), MPFROMHWND(pqmsg->hwnd));
  244.             }
  245.         REROUTEMSGTONULL()
  246.         }
  247.     }
  248. /*                                                                                      *\
  249.  * Here we catch all WM_CHAR messages filtering them for hotkeys. Found hotkeys are     *
  250.  * sent to PC/2.                                                                        *
  251. \*                                                                                      */
  252. if(pqmsg->msg == WM_CHAR)
  253.     {
  254.                                         /* KC_* flags */
  255.     usFlags=SHORT1FROMMP(pqmsg->mp1);
  256.                                         /* Keyboard scan code of character pressed */
  257.     ucScanCode=CHAR4FROMMP(pqmsg->mp1);
  258.  
  259.                                         /* If the key was depressed, ignore */
  260.     if(usFlags&KC_KEYUP) return(FALSE);
  261.                                         /* If no scan code is available for key, ignore. We
  262.                                            need to have the scan code, because this is the
  263.                                            only common part of WM_CHAR between PM and
  264.                                            WINDOWCOMPAT sessions. To be able to use the Hotkey
  265.                                            feature in WINDOWCOMPAT sessions too, we test for
  266.                                            the scan code (which is NLS-dependent, sorry) instead
  267.                                            of the ASCII value as we did in versions 1.80 and
  268.                                            before (which was NLS-independent) */
  269.     if(!(usFlags&KC_SCANCODE)) return(FALSE);
  270.                                         /* We now have a pressed key's scan code, now we are
  271.                                            only interested if a ALT or CTRL key was pressed
  272.                                            and hold before and if SHIFT was pressed too. */
  273.     usFlags&=(KC_ALT|KC_CTRL|KC_SHIFT);
  274.                                         /* It can only be a Hotkey when either a ALT or
  275.                                            CTRL key was pressed, but SHIFT was not pressed. */
  276.     if((usFlags==KC_CTRL) || (usFlags==KC_ALT))
  277.         {
  278.                                         /* If the user wants the Hotkeys detected only when
  279.                                            either PC/2, the Window List or the WPS is active
  280.                                            determine the active window */
  281.         if(HookParameters.ulStatusFlag & HOTKEY4PC2ONLY)
  282.             {
  283.                                         /* Query the currently active window, where HWND_DESKTOP
  284.                                            is the parent window. It will be a WC_FRAME class
  285.                                            window */
  286.             hwndActiveWindow=WinQueryActiveWindow(HWND_DESKTOP);
  287.             WinQueryWindowText(hwndActiveWindow, sizeof(ucWindowText), ucWindowText);
  288.             while(TRUE)
  289.                 {
  290.                                         /* We can accept the WPS having the focus */
  291.                 if(strstr(ucWindowText, HookParameters.ucDesktopName))
  292.                     break;
  293.                                         /* We can accept PM having the focus */
  294.                 if(hwndActiveWindow==HookParameters.hwndDesktop)
  295.                     break;
  296.                                         /* We can accept the Window List having the focus */
  297.                 if(strstr(ucWindowText, HookParameters.ucWindowListName))
  298.                     break;
  299.                                         /* We can accept any PC/2 Window having the focus */
  300.                 if(strstr(ucWindowText, "PC/2"))
  301.                     break;
  302.                                         /* We can accept no window having the focus */
  303.                 if(hwndActiveWindow==NULLHANDLE)
  304.                     break;
  305.                                         /* The active window is not one of the required ones,
  306.                                            so don't handle this message further, but pass it
  307.                                            on to the next hook in the chain */
  308.                 return(FALSE);
  309.                 }
  310.             }
  311.         pKeyDataIndex=KeyData;
  312.         ulKeyDataIndex=0;
  313.                                         /* Now try to find the key */
  314.         for( ;ulKeyDataIndex<=KEYDATACOUNT; ulKeyDataIndex++, pKeyDataIndex++)
  315.             if((pKeyDataIndex->usFlags==usFlags) && (pKeyDataIndex->ucScanCode==ucScanCode))
  316.                 {
  317.                 if(pKeyDataIndex->bUsed==TRUE)
  318.                     {
  319.                     WinPostMsg(HookParameters.hwndClient, WM_HOTKEY,
  320.                         MPFROM2SHORT(usFlags, pKeyDataIndex->usCh), MPFROMLONG(ulKeyDataIndex));
  321.                     REROUTEMSGTONULL()
  322.                     }
  323.                 else break;             /* If our key is not used we don't need any
  324.                                            further search */
  325.                 }
  326.         }
  327.     }
  328. /*                                                                                      *\
  329.  * Here we catch mouse button 1 clicks, either the move the Desktop or to display the   *
  330.  * Popup-Menu.                                                                          *
  331. \*                                                                                      */
  332. while(pqmsg->msg==HookParameters.ulClickFlag)
  333.     {
  334. /*                                                                                      *\
  335.  * If the user clicked on at least one of the surrounding rows or columns of the        *
  336.  * display, we shift the physical Desktop on the virtual Desktop. The flag MOVED4CLICK  *
  337.  * is set, if the user click on the display borders.                                    *
  338. \*                                                                                      */
  339.     if(ulMoveFlag & MOVED4CLICK)
  340.         {
  341.         WinPostMsg(HookParameters.hwndClient, WM_MOVEREQUEST,
  342.             MPFROM2SHORT(pqmsg->ptl.x, pqmsg->ptl.y), MPFROMLONG(ulMoveFlag));
  343.         ulMoveFlag&=~MOVED4CLICK;       /* Reset flag, because only a move before
  344.                                            a click may set it */
  345.         REROUTEMSGTONULL()
  346.         }
  347. /*                                                                                      *\
  348.  * If the user clicked on the WPS or PM window, send PC/2 a message to display the      *
  349.  * Popup-Menu, however not if stroke was part of the Window List activation.            *
  350. \*                                                                                      */
  351.     if((pqmsg->hwnd==HookParameters.hwndWPS) &&
  352.         (ulButtonDown!=WM_WINDOWLIST))
  353.         {                               /* The user clicked on WPS "Desktop" window.
  354.                                            We construct a small rectangle around the
  355.                                            current position of the pointer, relative to
  356.                                            the WPS window (not the screen) */
  357.         QueryRect.rect.xLeft=(ULONG)SHORT1FROMMP(pqmsg->mp1);
  358.         QueryRect.rect.xRight=QueryRect.rect.xLeft+1;
  359.         QueryRect.rect.yBottom=(ULONG)SHORT2FROMMP(pqmsg->mp1);
  360.         QueryRect.rect.yTop=QueryRect.rect.yBottom+1;
  361.         if(WinSendMsg(HookParameters.hwndWPS, CM_QUERYRECORDFROMRECT,
  362.             MPFROMLONG(CMA_FIRST), &QueryRect)==NULL)
  363.                                         /* If no container is under the rectangle of the
  364.                                            mouse pointer, we can display our Popup-Menu.
  365.                                            The type of container is unknown, but because
  366.                                            we test only on the WPS, they should usually
  367.                                            be the icons (but not the minimized programs,
  368.                                            which are windows with a different window handle). */
  369.                                         /* Pass the pointer position in coordinates relative
  370.                                            to the screen (not WPS window) and the handle of
  371.                                            that window. */
  372.             {
  373.             WinPostMsg(HookParameters.hwndClient, WM_POPUPMENU,
  374.                 MPFROM2SHORT((USHORT)pqmsg->ptl.x, (USHORT)pqmsg->ptl.y), MPFROMHWND(pqmsg->hwnd));
  375.             REROUTEMSGTONULL()
  376.             }
  377.         break;                          /* If clicked on an container, pass message to WPS */
  378.         }
  379.     if((pqmsg->hwnd==HookParameters.hwndDesktop) &&
  380.         (ulButtonDown!=WM_WINDOWLIST))
  381.         {                               /* The user clicked on the PM "Desktop" window.
  382.                                            If the WPS isn't installed we only get the PM
  383.                                            windows. We can now display our Popup-Menu.
  384.                                            Pass the pointer position in coordinates relative
  385.                                            to the screen (not WPS window) and the handle of
  386.                                            that window. */
  387.         WinPostMsg(HookParameters.hwndClient, WM_POPUPMENU,
  388.             MPFROM2SHORT((USHORT)pqmsg->ptl.x, (USHORT)pqmsg->ptl.y), MPFROMHWND(pqmsg->hwnd));
  389.         REROUTEMSGTONULL()
  390.         }
  391.     break;                              /* Break out of while loop */
  392.     }
  393. /*                                                                                      *\
  394.  * If enabled, here we catch all mouse movements, to set the window under the mouse     *
  395.  * pointer as the active one, if it isn't currently active or the window list or        *
  396.  * optionally the Desktop window.                                                       *
  397. \*                                                                                      */
  398. while((pqmsg->msg==WM_MOUSEMOVE) && (HookParameters.ulStatusFlag & SLIDINGFOCUS))
  399.     {                                   /* If enabled, use sliding focus to activate window
  400.                                            under the mouse pointer (with some exceptions).
  401.                                            Caution! Menus have a class WC_MENU, but their
  402.                                            parent is not the frame window WC_FRAME but the
  403.                                            Desktop itself. */
  404.                                         /* Don't process message as possible focus change for PC/2,
  405.                                            if SHIFT is pressed */
  406.     if((WinGetKeyState(HWND_DESKTOP, VK_SHIFT) & 0x8000))
  407.         return(FALSE);
  408.                                         /* If the mouse pointer is moving over the same window
  409.                                            as for the last move, we don't need to do anything */
  410.     if(hwndLastControl==(hwndActiveControl=pqmsg->hwnd))
  411.         break;
  412.                                         /* Query the currently active window, where HWND_DESKTOP
  413.                                            is the parent window. It will be a WC_FRAME class
  414.                                            window */
  415.     hwndActiveWindow=WinQueryActiveWindow(HWND_DESKTOP);
  416.                                         /* Don't switch away from Window List */
  417.     if(hwndActiveWindow==HookParameters.hwndWindowList) break;
  418.     hwndApplication=pqmsg->hwnd;        /* Get message target window */
  419.     if((hwndApplication==HookParameters.hwndDesktop) || (hwndApplication==HookParameters.hwndWPS))
  420.         break;                          /* If the window under the mouse pointer is one of the
  421.                                            Desktops, don't do any changes */
  422.                                         /* Get parent window of current window */
  423.     hwndApplicationParent=WinQueryWindow(hwndApplication, QW_PARENT);
  424.     while(hwndApplicationParent!=HookParameters.hwndDesktop)
  425.         {                               /* Loop until we get the Desktop window handle. The
  426.                                            previous child window of the Desktop is then the
  427.                                            WC_FRAME class window of the point under the mouse
  428.                                            pointer which is not the Desktop. */
  429.         hwndApplication=hwndApplicationParent;
  430.         hwndApplicationParent=WinQueryWindow(hwndApplication, QW_PARENT);
  431.         }
  432.                                         /* Sort with expected descending probability, to avoid
  433.                                            unnecessary cpu load */
  434.                                         /* Query the class of the frame window of the
  435.                                            designated target of WM_MOUSEMOVE */
  436.     WinQueryClassName(hwndApplication, sizeof(ucClassname), ucClassname);
  437.                                         /* Don't switch to a menu class windows */
  438.     if(!strcmp(ucClassname, "#4")) return(FALSE);
  439.                                         /* Don't switch to a combobox's listbox windows */
  440.     if(!strcmp(ucClassname, "#7")) return(FALSE);
  441.                                         /* Don't switch between frame windows if previous frame window
  442.                                            equals the current one */
  443.                                         /* Query the frame window name of the designated
  444.                                            target of WM_MOUSEMOVE */
  445.     WinQueryWindowText(hwndApplication, sizeof(ucWindowText), ucWindowText);
  446.                                         /* Don't switch to seamless WIN-OS2 menus */
  447.     if(strstr(ucWindowText, "Seamless")) return(FALSE);
  448.                                         /* If current frame is not equal than last frame we have
  449.                                            to activate current frame window */
  450.                                         /* Don't switch to the WC_FRAME class window of PC/2 */
  451.     if(strstr(ucWindowText, "PC/2")) return(FALSE);
  452.     if(hwndLastActiveWindow!=hwndApplication)
  453.         {
  454.         hwndLastActiveWindow=hwndApplication;
  455.         if(HookParameters.ulStatusFlag & PRESERVEZORDER)
  456.             {                           /* Change focus, but preserve Z-order */
  457.                                         /* Don't send WM_ACTIVATE to window with new focus */
  458.             WinFocusChange(HWND_DESKTOP, WinWindowFromID(hwndApplication, FID_CLIENT), FC_NOSETACTIVE);
  459.                                         /* Activate new window */
  460.             if((hwndTitlebar=WinWindowFromID(hwndApplication, FID_TITLEBAR))!=NULLHANDLE)
  461.                 WinPostMsg(hwndApplication, WM_ACTIVATE, MPFROMSHORT(TRUE), MPFROMHWND(hwndTitlebar));
  462.             }
  463.         else                            /* Now switch to the new frame window, causing
  464.                                            a new Z-order. It will generate all messages
  465.                                            of deactivating old and activating the
  466.                                            new window. */
  467.             WinSetFocus(HWND_DESKTOP, WinWindowFromID(hwndApplication, FID_CLIENT));
  468.         }
  469.                                         /* If current window below mouse pointer is not the one
  470.                                            being the last, deactivate last one and activate
  471.                                            current one, but only if the ALT key is not pressed */
  472.         if((WinGetKeyState(HWND_DESKTOP, VK_ALT) & 0x8000)==(LONG)FALSE)
  473.             {
  474.             WinFocusChange(HWND_DESKTOP, hwndActiveControl, FC_NOSETACTIVE);
  475.             hwndLastControl=hwndActiveControl;
  476.             }
  477.         REROUTEMSGTONULL()
  478.     }
  479. /*                                                                                      *\
  480.  * If enabled, here we catch all mouse movements that are on the surrounding rows and   *
  481.  * columns of the physical Desktop, to adjust the position of the physical Desktop      *
  482.  * within the virtual Desktop.                                                          *
  483. \*                                                                                      */
  484. while((pqmsg->msg==WM_MOUSEMOVE) && (HookParameters.ulStatusFlag & VIRTUALDESKTOP))
  485.     {
  486.     ulMoveFlag=0;
  487.     if(pqmsg->ptl.x<=0)
  488.         {                               /* If we are on the left border of our physical
  489.                                            Desktop, move all windows right as we shift
  490.                                            it leftwards on the virtual Desktop */
  491.         ulMoveFlag|=MOVEXR;
  492.                                         /* If we're in the lower left corner, also move
  493.                                            all windows up and shift downwards on the
  494.                                            virtual Desktop */
  495.         if(pqmsg->ptl.y<=HookParameters.LLHotBorder.y) ulMoveFlag|=MOVEYU;
  496.                                         /* If we're in the upper left corner, also move
  497.                                            all windows down and shift upwards on the
  498.                                            virtual Desktop */
  499.         if(pqmsg->ptl.y>=HookParameters.URHotBorder.y) ulMoveFlag|=MOVEYD;
  500.         }
  501.     if(pqmsg->ptl.x>=HookParameters.DesktopSize.x-1)
  502.         {                               /* If we are on the right border of our physical
  503.                                            Desktop, move all windows left as we shift
  504.                                            it rightwards on the virtual Desktop */
  505.         ulMoveFlag|=MOVEXL;
  506.         if(pqmsg->ptl.y<=HookParameters.LLHotBorder.y) ulMoveFlag|=MOVEYU;
  507.         if(pqmsg->ptl.y>=HookParameters.URHotBorder.y) ulMoveFlag|=MOVEYD;
  508.         }
  509.     if(pqmsg->ptl.y<=0)
  510.         {                               /* If we are on the bottom border of our physical
  511.                                            Desktop, move all windows up as we shift
  512.                                            it downwards on the virtual Desktop */
  513.         ulMoveFlag|=MOVEYU;
  514.         if(pqmsg->ptl.x<=HookParameters.LLHotBorder.x) ulMoveFlag|=MOVEXR;
  515.         if(pqmsg->ptl.x>=HookParameters.URHotBorder.x) ulMoveFlag|=MOVEXL;
  516.         }
  517.     if(pqmsg->ptl.y>=HookParameters.DesktopSize.y-1)
  518.         {                               /* If we are on the top border of our physical
  519.                                            Desktop, move all windows down as we shift
  520.                                            it upwards on the virtual Desktop */
  521.         ulMoveFlag|=MOVEYD;
  522.         if(pqmsg->ptl.x<=HookParameters.LLHotBorder.x) ulMoveFlag|=MOVEXR;
  523.         if(pqmsg->ptl.x>=HookParameters.URHotBorder.x) ulMoveFlag|=MOVEXL;
  524.         }
  525.     if(ulMoveFlag==0) break;            /* If there is no window to move, don't do any
  526.                                            further processing and exit loop. As no flags
  527.                                            are set, the click loop will not find 
  528.                                            the necessity to move */
  529.     ulMoveFlag|=MOVED4CLICK;            /* We're now about to move, but if the user
  530.                                            selected to click before move, we exit this
  531.                                            loop with the flags set. The click loop
  532.                                            will then use these flags */
  533.     if(HookParameters.ulStatusFlag & CLICK2MOVE) break;
  534.     WinPostMsg(HookParameters.hwndClient, WM_MOVEREQUEST,
  535.         MPFROM2SHORT(pqmsg->ptl.x, pqmsg->ptl.y), MPFROMLONG(ulMoveFlag));
  536.     REROUTEMSGTONULL()
  537.     }
  538. return(FALSE);                          /* Process the message in the normal way */
  539. }
  540.  
  541.  
  542. /*--------------------------------------------------------------------------------------*\
  543.  * This procedure implements the hook of WinSendMsg() calls in the system message       *
  544.  * queue.                                                                               *
  545.  * Req:                                                                                 *
  546.  *      hab ........... Anchor block handle                                             *
  547.  *      pSmh .......... Pointer to send message hook structure                          *
  548.  *      bInterTask .... TRUE .... Message is sent between tasks (intertask)             *
  549.  *                      FALSE ... Message is sent within task (intratask)               *
  550.  * Returns:                                                                             *
  551. \*--------------------------------------------------------------------------------------*/
  552. void EXPENTRY   PC2DLL_WinSendMsgHook(HAB hab, PSMHSTRUCT pSmh, BOOL bInterTask)
  553. {
  554. /*                                                                                      *\
  555.  * Tracking frame window creation, moving, sizing. If PC/2 should be on top of Z-order  *
  556.  * ensure this too.                                                                     *
  557. \*                                                                                      */
  558. if((pSmh->msg==WM_ADJUSTWINDOWPOS) && (WinQueryWindow(pSmh->hwnd, QW_PARENT)==HookParameters.hwndDesktop))
  559.     {
  560.                                         /* Don't change Z-order of (Popup) menus otherwise
  561.                                            e.g. the Window List's menu gets wrong Z-order */
  562.     WinQueryClassName(pSmh->hwnd, sizeof(ucClassname), ucClassname);
  563.     if(!strcmp(ucClassname, "#4")) return;
  564.                                         /* If PC/2 should be on Z-order top, we need some
  565.                                            rearranging */
  566.     if(HookParameters.ulStatusFlag & KEEPONTOP)
  567.         {
  568.         if((pSmh->hwnd!=HookParameters.hwndFrame) && (pSmh->hwnd!=HookParameters.hwndWindowList))
  569.             {                           /* If this is a frame not being PC/2 or the Window List
  570.                                            set it behind PC/2 instead of HWND_TOP */
  571.             if(((SWP *)(pSmh->mp1))->hwndInsertBehind==HWND_TOP)
  572.                 {                       /* But only when HWND_TOP is requested */
  573.                                         /* Get the window's owner window, until either PC/2
  574.                                            is the owner, or the Desktop */
  575.                 hwndOwner=WinQueryWindow(pSmh->hwnd, QW_OWNER);
  576.                 while(hwndOwner!=NULLHANDLE)
  577.                     {
  578.                                         /* If PC/2 is the owner, we don't change the z-order,
  579.                                            because a window is top of z-order to its owner,
  580.                                            and PC/2's overview window can't be on top of
  581.                                            z-order relative to its owned windows.
  582.                                            Ignoring this eats up CPU in 2.11 and traps or
  583.                                            causes IPE's in Warp */
  584.                     if(hwndOwner==HookParameters.hwndFrame)
  585.                         {
  586.                         return;
  587.                         }
  588.                     hwndWindow=hwndOwner;
  589.                     hwndOwner=WinQueryWindow(hwndWindow, QW_OWNER);
  590.                     }
  591.                                         /* Is PC/2 on top of Z-order */
  592.                 if(WinQueryWindow(HWND_DESKTOP, QW_TOP)!=HookParameters.hwndFrame)
  593.                     {                   /* If not set PC/2 to top */
  594.                     WinSetWindowPos(HookParameters.hwndFrame, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER);
  595.                     }
  596.                                         /* Set window immediately behind PC/2 */
  597.                 ((SWP *)(pSmh->mp1))->hwndInsertBehind=HookParameters.hwndFrame;
  598.                 ((SWP *)(pSmh->mp1))->fl|=SWP_ZORDER;
  599.                 }
  600.             }
  601.         else
  602.             {                           /* If it is PC/2 itself or the Window List, set
  603.                                            it to top of Z-order */
  604.             ((SWP *)(pSmh->mp1))->hwndInsertBehind=HWND_TOP;
  605.             ((SWP *)(pSmh->mp1))->fl|=SWP_ZORDER;
  606.             }
  607.         }
  608.                                         /* Post this message to PC/2 because to reflect
  609.                                            a window's creation, resizing, moving or destruction */
  610.     WinPostMsg(HookParameters.hwndClient, WM_SETUPSIZEPOSITION,
  611.         MPFROMLONG(WM_MOVE), MPFROMHWND(pSmh->hwnd));
  612.     }
  613. }
  614.  
  615.