/***********************************************************************\ * PC2.c * * Copyright (C) by Stangl Roman, 1993 * * This Code may be freely distributed, provided the Copyright isn't * * removed. * * * * Pc2Hook.c Hook the input queue to filter certain messages. * * * \***********************************************************************/ static char RCSID[]="@(#) $Header: Pc2Hook.c Version 1.60 06,1993 $ (LBL)"; #define _FILE_ "PC/2 - PC2Hook.c V1.60" #include "PC2.h" /* User include files */ #include "Error.h" void EXPENTRY PC2DLL_SetParameters(HOOKPARAMETERS *pHP); void EXPENTRY PC2DLL_QueryParameters(HOOKPARAMETERS *pHP); BOOL EXPENTRY PC2DLL_Hook(HAB hab, PQMSG pqmsg, ULONG option); BOOL PC2DLL_MoveWindows(PQMSG pqmsg); HOOKPARAMETERS HookParameters; /* Copy of PC2HOOK.DLL control structure, because DLL can't access original data in PC2.EXE */ POINTL LLHotBorder; /* Lower left coordinates that force sliding in x & y direction */ POINTL URHotBorder; /* Upper right coordinates that force sliding in -x & -y direction */ ULONG ulMoveFlag; /* xxxxxxxx (<-Bit 0) | Move all windows in x direction | Move in -x direction | Move in y direction | Move in -y direction | Click required to move */ LONG SlidingXFactor; /* Slide in x direction in pixels */ LONG SlidingYFactor; /* Slide in y direction in pixels */ QUERYRECFROMRECT QueryRect; /* Rectangle to query underlaying containers */ /*--------------------------------------------------------------------------------------*\ * This procedure saves the data used in the PC/2 main procedure for use within the * * DLL. * * Req: * * pHP............ Pointer to DLL initialization data * * Returns: * * none * \*--------------------------------------------------------------------------------------*/ void EXPENTRY PC2DLL_SetParameters(HOOKPARAMETERS *pHP) { /* Copy the passed parameters to a DLL local copy */ memcpy(&HookParameters, pHP, sizeof(HOOKPARAMETERS)); LLHotBorder.x=HookParameters.DesktopSize.x*0.15; LLHotBorder.y=HookParameters.DesktopSize.y*0.15; URHotBorder.x=HookParameters.DesktopSize.x*0.85; URHotBorder.y=HookParameters.DesktopSize.y*0.85; /* Initialize to query the topmost underlaying container, that is partially hit by a rectangle around the pointer */ QueryRect.cb=sizeof(QUERYRECFROMRECT); QueryRect.fsSearch=CMA_PARTIAL | CMA_ZORDER; } /*--------------------------------------------------------------------------------------*\ * This procedure queries the data used within the DLL for use in the PC/2 main * * procedure. * * Req: * * pHP............ Pointer to return DLL data * * Returns: * * none * \*--------------------------------------------------------------------------------------*/ void EXPENTRY PC2DLL_QueryParameters(HOOKPARAMETERS *pHP) { /* Copy from the DLL local copy to the passed parameters */ memcpy(pHP, &HookParameters, sizeof(HOOKPARAMETERS)); } /*--------------------------------------------------------------------------------------*\ * This procedure implements the hook of the input queue. . * * Req: * * PQMSG ......... Pointer to system QMSG structure * * Returns: * * FALSE ......... OS/2 should process QMSG in the normal way * \*--------------------------------------------------------------------------------------*/ BOOL EXPENTRY PC2DLL_Hook(HAB hab, PQMSG pqmsg, ULONG option) { /* Return if mouse is captured */ if(WinQueryCapture(HWND_DESKTOP)!=NULLHANDLE) return(FALSE); /* *\ * Here we catch mouse button 1 clicks, either the move the Desktop or to display the * * Popup-Menu. * \* */ while(pqmsg->msg==HookParameters.ulClickFlag) { /* *\ * If the user clicked on at least one of the surrounding rows or columns of the * * display, we shift the physical Desktop on the virtual Desktop. The flag MOVED4CLICK * * is set, if the user click on the display borders. * \* */ if(ulMoveFlag & MOVED4CLICK) { PC2DLL_MoveWindows(pqmsg); /* Now move the windows */ ulMoveFlag&=~MOVED4CLICK; /* Reset flag, because only a move before a click may set it */ return(TRUE); /* Don't pass this message to next hook in chain. */ } /* *\ * If the user clicked on the WPS or PM window, send PC/2 a message to display the * * Popup-Menu. * \* */ if(pqmsg->hwnd==HookParameters.hwndWPS) { /* The user clicked on WPS "Desktop" window. We construct a small rectangle around the current position of the pointer */ QueryRect.rect.xLeft=pqmsg->ptl.x; QueryRect.rect.xRight=pqmsg->ptl.x+1; QueryRect.rect.yBottom=pqmsg->ptl.y; QueryRect.rect.yTop=pqmsg->ptl.y+1; if(WinSendMsg(HookParameters.hwndWPS, CM_QUERYRECORDFROMRECT, MPFROMLONG(CMA_FIRST), &QueryRect)==NULL) /* If no container is under the rectangle of the mouse pointer, we can display our Popup-Menu. The type of container is unknown, but because we test only on the WPS, they should usually be the icons (but not the minimized programs, which are windows with a different window handle). */ /* Pass the pointer position in coordinates relative to the window and the handle of that window. The coordinates must be translated from that window to the display */ { WinSendMsg(HookParameters.hwndPC2, WM_POPUPMENU, MPFROMLONG(pqmsg->mp1), MPFROMHWND(pqmsg->hwnd)); return(TRUE); /* Don't pass this message to next hook in chain. */ } break; /* If clicked on an container, pass message to WPS */ } if(pqmsg->hwnd==HookParameters.hwndDesktop) { /* The user clicked on the PM "Desktop" window. If the WPS isn't installed we only get the PM windows. We can now display our Popup-Menu. Pass the pointer position in coordinates relative to the window and the handle of that window. The coordinates must be translated from that window to the display */ WinSendMsg(HookParameters.hwndPC2, WM_POPUPMENU, MPFROMLONG(pqmsg->mp1), MPFROMHWND(pqmsg->hwnd)); return(TRUE); /* Don't pass this message to next hook in chain. */ } break; /* Break out of while loop */ } /* *\ * If enabled, here we catch all mouse movements, to set the window under the mouse * * pointer as the active one, if it isn't currently active or the window list or * * optionally the Desktop window. * \* */ while((pqmsg->msg==WM_MOUSEMOVE) && (HookParameters.ulStatusFlag & SLIDINGFOCUS)) { /* If enabled, use sliding focus to activate window under the mouse pointer (with some exceptions). Caution! Menus have a class WC_MENU, but their parent is not the frame window WC_FRAME but the Desktop itself. */ static UCHAR ucClassname[7]; /* Window class f.e. #1 for WC_FRAME */ static UCHAR ucWindowText[33]; /* Window name f.e. OS/2 2.0 Desktop */ static HWND hwndActive; /* Window handle of active frame class window on Desktop */ static HWND hwndApplication; /* Window handle of application under mouse pointer */ /* Window handle of applications parent window */ static HWND hwndApplicationParent; /* Query the currently active window, where HWND_DESKTOP is the parent window. It will be a WC_FRAME class window */ hwndActive=WinQueryActiveWindow(HWND_DESKTOP); WinQueryWindowText(hwndActive, sizeof(ucWindowText), ucWindowText); /* Don't switch away from the WC_FRAME class tasklist */ if(!strcmp(ucWindowText, "Window List")) break; hwndApplication=pqmsg->hwnd; /* Get message target window */ if((hwndApplication==HookParameters.hwndDesktop) || (hwndApplication==HookParameters.hwndWPS)) break; /* If the window under the mouse pointer is one of the Desktops, don't do any changes */ /* Get parent window of current window */ hwndApplicationParent=WinQueryWindow(hwndApplication, QW_PARENT); while(hwndApplicationParent!=HookParameters.hwndDesktop) { /* Loop until we get the Desktop window handle. The previous child window of the Desktop is then the WC_FRAME class window of the point under the mouse pointer which is not the Desktop. */ hwndApplication=hwndApplicationParent; hwndApplicationParent=WinQueryWindow(hwndApplication, QW_PARENT); } /* Query the class of the frame window of the designated target of WM_MOUSEMOVE */ WinQueryClassName(hwndApplication, sizeof(ucClassname), ucClassname); /* Query the frame window name of the designated target of WM_MOUSEMOVE */ WinQueryWindowText(hwndApplication, sizeof(ucWindowText), ucWindowText); while(TRUE) { /* Sort with expected descending probability, to avoid unnecessary cpu load */ /* Don't switch if previous windows equals current one */ if(hwndActive==hwndApplication) break; /* Only switch to WC_FRAME class windows */ if(strcmp(ucClassname, "#1")) break; /* Don't switch to the WC_FRAME class window of PC/2 */ if(!strcmp(ucWindowText, "PC/2")) break; if(HookParameters.ulStatusFlag & PRESERVEZORDER) { /* Change focus, but preserve Z-order */ /* Don't send WM_ACTIVATE to window with new focus */ WinFocusChange(HWND_DESKTOP, pqmsg->hwnd, FC_NOSETACTIVE); /* Activate new window */ WinPostMsg(hwndApplication, WM_ACTIVATE, MPFROMSHORT(TRUE), MPFROMHWND(pqmsg->hwnd)); } else /* Now switch to the new frame window, causing a new Z-order. It will generate all messages of deactivating old and activating the new window. */ WinFocusChange(HWND_DESKTOP, pqmsg->hwnd, 0); return(TRUE); /* We changed the focus, don't pass this message to the next hook in the chain */ } break; /* Exit loop now */ } /* *\ * If enabled, here we catch all mouse movements that are on the surrounding rows and * * columns of the physical Desktop, to adjust the position of the physical Desktop * * within the virtual Desktop. * \* */ while((pqmsg->msg==WM_MOUSEMOVE) && (HookParameters.ulStatusFlag & VIRTUALDESKTOP)) { ulMoveFlag=0; if(pqmsg->ptl.x<=0) { /* If we are on the left border of our physical Desktop, move all windows right as we shift it leftwards on the virtual Desktop */ ulMoveFlag|=MOVEXR; /* If we're in the lower left corner, also move all windows up and shift downwards on the virtual Desktop */ if(pqmsg->ptl.y<=LLHotBorder.y) ulMoveFlag|=MOVEYU; /* If we're in the upper left corner, also move all windows down and shift upwards on the virtual Desktop */ if(pqmsg->ptl.y>=URHotBorder.y) ulMoveFlag|=MOVEYD; } if(pqmsg->ptl.x>=HookParameters.DesktopSize.x-1) { /* If we are on the right border of our physical Desktop, move all windows left as we shift it rightwards on the virtual Desktop */ ulMoveFlag|=MOVEXL; if(pqmsg->ptl.y<=LLHotBorder.y) ulMoveFlag|=MOVEYU; if(pqmsg->ptl.y>=URHotBorder.y) ulMoveFlag|=MOVEYD; } if(pqmsg->ptl.y<=0) { /* If we are on the bottom border of our physical Desktop, move all windows up as we shift it downwards on the virtual Desktop */ ulMoveFlag|=MOVEYU; if(pqmsg->ptl.x<=LLHotBorder.x) ulMoveFlag|=MOVEXR; if(pqmsg->ptl.x>=URHotBorder.x) ulMoveFlag|=MOVEXL; } if(pqmsg->ptl.y>=HookParameters.DesktopSize.y-1) { /* If we are on the top border of our physical Desktop, move all windows down as we shift it upwards on the virtual Desktop */ ulMoveFlag|=MOVEYD; if(pqmsg->ptl.x<=LLHotBorder.x) ulMoveFlag|=MOVEXR; if(pqmsg->ptl.x>=URHotBorder.x) ulMoveFlag|=MOVEXL; } if(ulMoveFlag==0) break; /* If there is no window to move, don't do any further processing and exit loop. As no flags are set, the click loop will not find the necessity to move */ ulMoveFlag|=MOVED4CLICK; /* We're now about to move, but if the user selected to click before move, we exit this loop with the flags set. The click loop will then use these flags */ if(HookParameters.ulStatusFlag & CLICK2MOVE) break; PC2DLL_MoveWindows(pqmsg); /* Now move the windows */ return(TRUE); /* Exit from loop */ } return(FALSE); /* Process the message in the normal way */ } /*--------------------------------------------------------------------------------------*\ * This local procedure is called from the PC2DLL_Hook procedure to move the windows * * within the virtual Desktop on its behalf. * * Req: * * pqmsg.......... Pointer to QMSG passed to Hook procedure by OS/2 * * Ref: * * ulMoveFlag..... Bitmapped flag to control move * * SlidingXFactor. Offset to move horizontal which is passed to PC/2's window * * procedure * * SlidingYFactor. Offset to move vertical * * HookParameters. DLL control structure * * Returns: * * none * \*--------------------------------------------------------------------------------------*/ BOOL PC2DLL_MoveWindows(PQMSG pqmsg) { LONG lDiff; SlidingXFactor=0; SlidingYFactor=0; if((ulMoveFlag&MOVEXR)) { /* Move physical Desktop left, but not over the left border of the virtual Desktop */ SlidingXFactor=HookParameters.SlidingXFactor; HookParameters.VirtualDesktopPos.x-=HookParameters.SlidingXFactor; lDiff=HookParameters.VirtualDesktopPos.x-HookParameters.VirtualDesktopMin.x; if(lDiff<0) { HookParameters.VirtualDesktopPos.x-=lDiff; SlidingXFactor+=lDiff; } } if((ulMoveFlag&MOVEXL)) { /* Move physical Desktop right, but not over the right border of the virtual Desktop */ SlidingXFactor=-HookParameters.SlidingXFactor; HookParameters.VirtualDesktopPos.x+=HookParameters.SlidingXFactor; lDiff=HookParameters.VirtualDesktopPos.x-HookParameters.VirtualDesktopMax.x; if(lDiff>0) { HookParameters.VirtualDesktopPos.x-=lDiff; SlidingXFactor+=lDiff; } } if((ulMoveFlag&MOVEYU)) { /* Move physical Desktop down, but not under the bottom border of the virtual Desktop */ SlidingYFactor=HookParameters.SlidingYFactor; HookParameters.VirtualDesktopPos.y-=HookParameters.SlidingYFactor; lDiff=HookParameters.VirtualDesktopPos.y-HookParameters.VirtualDesktopMin.y; if(lDiff<0) { HookParameters.VirtualDesktopPos.y-=lDiff; SlidingYFactor+=lDiff; } } if((ulMoveFlag&MOVEYD)) { /* Move physical Desktop up, but not over the top border of the virtual Desktop */ SlidingYFactor=-HookParameters.SlidingYFactor; HookParameters.VirtualDesktopPos.y+=HookParameters.SlidingYFactor; lDiff=HookParameters.VirtualDesktopPos.y-HookParameters.VirtualDesktopMax.y; if(lDiff>0) { HookParameters.VirtualDesktopPos.y-=lDiff; SlidingYFactor+=lDiff; } } /* If there is nothing to move, because we are on a border position, don't do further processing but return */ if(!SlidingXFactor && !SlidingYFactor) return(FALSE); /* Move pointer so that it is on that pixel it would be, if we hadn't moved the windows. Also change the pixel which gets the message. */ if(HookParameters.ulScrollPercentage==100) WinSetPointerPos(HWND_DESKTOP, (pqmsg->ptl.x+=SlidingXFactor*0.5), (pqmsg->ptl.y+=SlidingYFactor*0.5)); else WinSetPointerPos(HWND_DESKTOP, (pqmsg->ptl.x+=SlidingXFactor), (pqmsg->ptl.y+=SlidingYFactor)); /* Inform PC/2 to move windows */ WinSendMsg(HookParameters.hwndPC2, WM_DESKTOPMOVE, MPFROMLONG(SlidingXFactor), MPFROMLONG(SlidingYFactor)); return(TRUE); }