home *** CD-ROM | disk | FTP | other *** search
/ PC Open 19 / pcopen19.iso / Zipped / CALMIR21.ZIP / SOURCE.ZIP / SRC / WNDHOOKS.DPR < prev    next >
Encoding:
Text File  |  1998-02-20  |  9.9 KB  |  345 lines

  1. {**************************************************************************}
  2. {                                                                          }
  3. {    Calmira shell for Microsoft« Windows(TM) 3.1                          }
  4. {    Source Release 2.1                                                    }
  5. {    Copyright (C) 1997-1998  Li-Hsin Huang                                }
  6. {                                                                          }
  7. {    This program is free software; you can redistribute it and/or modify  }
  8. {    it under the terms of the GNU General Public License as published by  }
  9. {    the Free Software Foundation; either version 2 of the License, or     }
  10. {    (at your option) any later version.                                   }
  11. {                                                                          }
  12. {    This program is distributed in the hope that it will be useful,       }
  13. {    but WITHOUT ANY WARRANTY; without even the implied warranty of        }
  14. {    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         }
  15. {    GNU General Public License for more details.                          }
  16. {                                                                          }
  17. {    You should have received a copy of the GNU General Public License     }
  18. {    along with this program; if not, write to the Free Software           }
  19. {    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             }
  20. {                                                                          }
  21. {**************************************************************************}
  22.  
  23. library WndHooks;
  24.  
  25. {$C FIXED}
  26.  
  27. { Calmira's Windows hooks and other low level stuff.
  28.  
  29.   This DLL implements:
  30.  
  31.   Shell hook - detects and reports top-level windows being created or
  32.     destroyed (perfect for a taskbar)
  33.  
  34.   WndProc hook - detects and reports WM_ACTIVATE messages sent to
  35.     any window.  Detects user maximizing a window, and can adjust its
  36.     size so as not to overlap with the taskbar.
  37.  
  38.   Mouse hook - detects and reports WM_MOUSEMOVE messages sent to
  39.     any window (used by taskbar to hide after the cursor has moved off).
  40.     Also detects WM_NCRBUTTONDOWN so that right clicks on minimize or
  41.     maximize boxes can be used to close a window.
  42.  
  43.   Desktop WndProc - detects and reports the user right clicking on
  44.     the desktop, so that host program can display a popup menu.
  45.  
  46.   Thanks to Ralf Scheiner for the code to constrain maximized windows.
  47. }
  48.  
  49. uses WinProcs, WinTypes, Messages, CalMsgs;
  50.  
  51. type
  52.   LongRec = record
  53.     Lo, Hi: Word;
  54.   end;
  55.  
  56. const
  57.   MaxEnabled : Boolean = False;
  58.   MouseEnabled : Boolean = False;
  59.   RCloseEnabled : Boolean = False;
  60.   RButtonUpClose : Boolean = True;
  61.  
  62. var
  63.   CallBackWnd : HWND;
  64.  
  65.   TaskHook  : HHook;
  66.   WndHook   : HHook;
  67.   MouseHook : HHook;
  68.  
  69.   ScreenWidth, ScreenHeight, YLimit: Integer;
  70.  
  71.  
  72.   DeskWndProc : TFarProc;
  73.   DeskCallBack: HWND;
  74.  
  75.   KeyHook     : HHook;
  76.   KeyCallBack : HWND;
  77.  
  78.  
  79. { shell hook }
  80.  
  81. function ShellProc(Code : Integer; wParam: Word; lParam: Longint): Longint; export;
  82. begin
  83.   case Code of
  84.   HSHELL_WINDOWCREATED   : PostMessage(CallbackWnd, WM_SHELLWNDCREATE, wParam, lParam);
  85.   HSHELL_WINDOWDESTROYED : PostMessage(CallBackWnd, WM_SHELLWNDDESTROY, wParam, lParam);
  86.   end;
  87.   Result := CallNextHookEx(TaskHook, Code, wParam, lParam);
  88. end;
  89.  
  90.  
  91. procedure StopTaskMonitor; export;
  92. begin
  93.   if TaskHook > 0 then UnhookWindowsHookEx(TaskHook);
  94.   TaskHook := 0;
  95. end;
  96.  
  97. procedure StartTaskMonitor; export;
  98. begin
  99.   StopTaskMonitor;
  100.   TaskHook := SetWindowsHookEx(WH_SHELL, ShellProc, HInstance, 0);
  101. end;
  102.  
  103.  
  104. { WndProc hook }
  105.  
  106. function WndProcHook(code: integer; wParam:word; lParam:Longint):LongInt; export;
  107. type
  108.   PHookMsg=^THookMsg;
  109.  
  110.   THookMsg=record
  111.    lParam: Longint;
  112.    wParam: Word;
  113.    uMsg: Word;
  114.    hWnd: THandle;
  115.   end;
  116. var
  117.   Wnd: HWnd;
  118. begin
  119.   if code >= 0 then with PHookMsg(lParam)^ do
  120.  
  121.     if MaxEnabled and (uMsg = WM_WINDOWPOSCHANGING) then begin
  122.       { Adjust size of maximized window }
  123.       with pWindowPos(lParam)^ do
  124.         if (Y+cY>ScreenHeight+2) and (X+cX>ScreenWidth+2) then begin
  125.           cY := YLimit - Y;
  126.           if GetWindowLong(HWnd, GWL_STYLE) and WS_THICKFRAME > 0 then
  127.             Inc(cY, GetSystemMetrics(SM_CYFRAME))
  128.           else
  129.             Inc(cY);
  130.         end;
  131.     end
  132.     else if MaxEnabled and (uMsg = WM_SYSCOMMAND) and (wParam = SC_MOVE + 2) and
  133.       IsZoomed(HWnd) then begin
  134.       wParam := 0;
  135.       lParam := 0;
  136.     end
  137.  
  138.     else if (uMsg = WM_ACTIVATE) and (CallBackWnd > 0) then
  139.       { inform host program about activation message }
  140.       case wParam of
  141.         WA_INACTIVE    : if Bool(LongRec(lParam).Hi) then
  142.                          SendMessage(CallBackWnd, WM_HIDEQUERY, hWnd, 0);
  143.         WA_ACTIVE      : SendMessage(CallBackWnd, WM_WINACTIVE, hWnd, 1);
  144.         WA_CLICKACTIVE : SendMessage(CallBackWnd, WM_WINACTIVE, hWnd, 1);
  145.       end;
  146.  
  147.   Result := CallNextHookEx(WndHook,Code,wParam,lParam);
  148. end;
  149.  
  150. procedure SetYLimit(y: Integer); export;
  151. begin
  152.    YLimit := y;
  153. end;
  154.  
  155. procedure UnhookWndHook; export;
  156. begin
  157.   if WndHook> 0 then UnHookWindowsHookEx(WndHook);
  158.   WndHook:= 0;
  159. end;
  160.  
  161. procedure SetWndHook; export;
  162. begin
  163.   UnhookWndHook;
  164.   WndHook := SetWindowsHookEx(WH_CallWndProc,WndProcHook,hInstance,0);
  165. end;
  166.  
  167. { Mouse hook }
  168.  
  169. function MouseProc(Code : Integer; wParam: Word; lParam: Longint): Longint; export;
  170. const
  171.   ButtonUp : array[Boolean] of Word = (WM_NCRBUTTONDOWN, WM_NCRBUTTONUP);
  172. var
  173.   y: Integer;
  174. begin
  175.   if MouseEnabled and (wParam = WM_MOUSEMOVE) then begin
  176.     { inform host about mouse movement }
  177.     y := TMouseHookStruct(Pointer(lParam)^).Pt.y;
  178.     if y < YLimit then SendMessage(CallbackWnd, WM_MOUSEHOOK, y, 0);
  179.     { PostMessage() crashes Alt-Tab }
  180.   end
  181.  
  182.   else if RCloseEnabled and (wParam = ButtonUp[RButtonUpClose]) then begin
  183.     { close the window if right click on minimize/maximize boxes }
  184.     with TMouseHookStruct(Pointer(lParam)^) do
  185.       if (wHitTestCode = HTMAXBUTTON) or (wHitTestCode = HTMINBUTTON) then begin
  186.         Result := 1;
  187.         PostMessage(hWnd, WM_CLOSE, 0, 0);
  188.         Exit;
  189.       end;
  190.   end;
  191.  
  192.   Result := CallNextHookEx(MouseHook, Code, wParam, lParam);
  193. end;
  194.  
  195.  
  196. procedure StopMouseMonitor; export;
  197. begin
  198.   if MouseHook > 0 then UnhookWindowsHookEx(MouseHook);
  199.   MouseHook := 0;
  200. end;
  201.  
  202. procedure StartMouseMonitor; export;
  203. begin
  204.   StopMouseMonitor;
  205.   MouseHook := SetWindowsHookEx(WH_MOUSE, MouseProc, HInstance, 0);
  206. end;
  207.  
  208. procedure EnableMouseMonitor; export;
  209. begin
  210.   MouseEnabled := True;
  211. end;
  212.  
  213. procedure DisableMouseMonitor; export;
  214. begin
  215.   MouseEnabled := False;
  216. end;
  217.  
  218. procedure SetRButtonUpClose(value: Boolean); export;
  219. begin
  220.   RButtonUpClose := value;
  221. end;
  222.  
  223.  
  224. procedure SetCallBackWnd(Wnd: HWND); export;
  225. begin
  226.   CallBackWnd := Wnd;
  227. end;
  228.  
  229. procedure SetMaxEnabled(value : Boolean); export;
  230. begin
  231.   MaxEnabled := value;
  232. end;
  233.  
  234. { Desktop window procedure to catch right clicks }
  235.  
  236. function NewDeskWndProc(Handle: HWND; Msg: Word; wParam: Word;
  237.   lParam: Longint): Longint; export;
  238. const
  239.   MouseButtons : array[Boolean] of Word = (VK_LBUTTON, VK_RBUTTON);
  240. begin
  241.   if (Msg = WM_RBUTTONDOWN) then
  242.     if GetAsyncKeyState(
  243.       MouseButtons[Bool(GetSystemMetrics(SM_SWAPBUTTON))]) < 0 then
  244.  
  245.       PostMessage(DeskCallBack, WM_DESKACTIVATE, wParam, lParam)
  246.     else
  247.       PostMessage(DeskCallBack, WM_DESKMENU, wParam, lParam);
  248.  
  249.   Result := CallWindowProc(DeskWndProc, Handle, Msg, wParam, lParam);
  250. end;
  251.  
  252. procedure ReleaseDesktopHook; export;
  253. begin
  254.   { restore Windows's wndproc }
  255.   if DeskWndProc <> nil then begin
  256.     SetWindowLong(GetDesktopWindow, GWL_WNDPROC, Longint(DeskWndProc));
  257.     DeskWndProc := nil;
  258.   end;
  259. end;
  260.  
  261. procedure SetDesktopHook(CallBack : HWND); export;
  262. begin
  263.   { replace desktop wndproc with our one }
  264.   ReleaseDesktopHook;
  265.   DeskCallback := CallBack;
  266.   DeskWndProc := Pointer(SetWindowLong(GetDesktopWindow, GWL_WNDPROC,
  267.     Longint(@NewDeskWndProc)));
  268. end;
  269.  
  270.  
  271. { Right click on min/max buttons to close }
  272.  
  273. procedure SetRCloseEnabled(value : Boolean); export;
  274. begin
  275.   RCloseEnabled := value;
  276. end;
  277.  
  278. function IsHotKey(wParam : Word; lParam: Longint): Boolean; export;
  279. const
  280.   AltMask = $20000000; { forms.pas }
  281. begin
  282.   {
  283.     The key is not Ctrl, Alt or Shift
  284.     The key is being pressed, not released
  285.     This is not typematic key repeat
  286.     Two or more keys out of [Ctrl, Alt, Shift] are pressed
  287.   }
  288.   Result := (LoWord(lParam) = 1) and (lParam >= 0) and
  289.    (wParam <> VK_CONTROL) and (wParam <> VK_MENU) and (wParam <> VK_SHIFT) and
  290.    (Ord(lParam and AltMask <> 0) + Ord(GetKeyState(VK_CONTROL) < 0) +
  291.     Ord(GetKeyState(VK_SHIFT) < 0) >= 2)
  292. end;
  293.  
  294. { Keyboard hook }
  295.  
  296. function KeyboardProc(code : Integer; wParam : Word; lParam: Longint): Longint; export;
  297. begin
  298.   Result := 0;
  299.  
  300.   if (code >= 0) and IsHotKey(wParam, lParam)then
  301.     Result := SendMessage(KeyCallBack, WM_KEYBOARDHOOK, wParam, lParam);
  302.  
  303.   if CallNextHookEx(KeyHook, code, wParam, lParam) > 0 then Result := 1;
  304. end;
  305.  
  306. procedure StopKeyboardHook; export;
  307. begin
  308.   if KeyHook > 0 then UnhookWindowsHookEx(KeyHook);
  309.   KeyHook := 0;
  310. end;
  311.  
  312. procedure StartKeyboardHook(CallBack: HWND); export;
  313. begin
  314.   StopKeyboardHook;
  315.   KeyCallBack := CallBack;
  316.   KeyHook := SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, HInstance, 0);
  317. end;
  318.  
  319.  
  320. exports
  321.   StartTaskMonitor index 1,
  322.   StopTaskMonitor index 2,
  323.   SetWndHook index 3,
  324.   UnhookWndHook index 4,
  325.   SetYLimit index 5,
  326.   StartMouseMonitor index 6,
  327.   StopMouseMonitor index 7,
  328.   EnableMouseMonitor index 8,
  329.   DisableMouseMonitor index 9,
  330.   SetCallBackWnd index 10,
  331.   SetMaxEnabled index 11,
  332.   SetRCloseEnabled index 12,
  333.   SetDesktopHook index 13,
  334.   ReleaseDesktopHook index 14,
  335.   StartKeyboardHook index 15,
  336.   StopKeyboardHook index 16,
  337.   SetRButtonUpClose index 17,
  338.   IsHotKey index 18;
  339.  
  340. begin
  341.   ScreenWidth := GetSystemMetrics(SM_CXSCREEN);
  342.   ScreenHeight := GetSystemMetrics(SM_CYSCREEN);
  343.   YLimit := ScreenHeight - 32;
  344. end.
  345.