home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kolekce / d123456 / DFS.ZIP / DFSKbMon.dpr < prev    next >
Text File  |  1998-11-25  |  6KB  |  219 lines

  1. {.$DEFINE DFS_DEBUG}
  2.  
  3. { The DFSKbMon.DLL library. }
  4.  
  5. { Intended for use with the TDFSStatusBar component (DFSStatusBar.pas), and
  6.   intended to be accessed by the DFSKb unit. }
  7.  
  8. { This DLL provides a notification mechanism for system wide monitoring of the
  9.   Caps, Num & Scroll lock keys.  Interested parties are notified via a custom
  10.   windows message as returned by the RegisterKeyboardHook function. }
  11.   
  12. library DFSKbMon;
  13.  
  14. uses
  15.   {$IFDEF DFS_DEBUG}
  16.   Debug, SysUtils,
  17.   {$ENDIF}
  18.   Windows;
  19.  
  20. const
  21.   MAX_CLIENTS = 256;
  22.  
  23. type
  24.   PHookData = ^THookData;
  25.   THookData = record
  26.     KeyboardHookHandle: HHOOK;
  27.     UsageCount: integer;
  28.     ClientIndex: integer;
  29.     Clients: array[0..MAX_CLIENTS-1] of HWND;
  30.   end;
  31.  
  32. var
  33.   MapFile: THandle;
  34.   WM_INDICATORKEY: UINT;
  35.   HookData: PHookData;
  36.  
  37.  
  38. procedure MapFileMemory;
  39. var
  40.   ZeroMem: boolean;
  41. begin
  42.   MapFile := CreateFileMapping($FFFFFFFF, NIL, PAGE_READWRITE, 0,
  43.      SizeOf(THookData), 'DFSKbMon Client List');
  44.   if (MapFile = 0) then
  45.   begin
  46.     MessageBox(0, 'DFSKbMon DLL', 'Could not create file map object', MB_OK);
  47.   end else begin
  48.     ZeroMem := GetLastError <> ERROR_ALREADY_EXISTS;
  49.     HookData := MapViewOfFile(MapFile, FILE_MAP_ALL_ACCESS, 0, 0,
  50.        SizeOf(THookData));
  51.     if (HookData = NIL) then
  52.     begin
  53.       CloseHandle(MapFile);
  54.       MessageBox(0, 'DFSKbMon DLL', 'Could not map file', MB_OK);
  55.     end else
  56.       if ZeroMem then
  57.         FillChar(HookData^, SizeOf(THookData), #0);
  58.   end;
  59. end;
  60.  
  61. procedure UnmapFileMemory;
  62. begin
  63.   if (HookData <> NIL) then
  64.   begin
  65.     UnMapViewOfFile(HookData);
  66.     HookData := NIL;
  67.   end;
  68.   if (MapFile <> 0) then
  69.   begin
  70.     CloseHandle(MapFile);
  71.     MapFile := 0;
  72.   end;
  73. end;
  74.  
  75. procedure AddClient(Wnd: HWND);
  76. begin
  77.   if (HookData <> NIL) then
  78.   begin
  79.     {$IFDEF DFS_DEBUG}
  80.     Debug.Log(TRUE, 'DFSKbMon: Added ' + IntToHex(Wnd, 8) + ' at index ' +
  81.        IntToStr(HookData^.ClientIndex));
  82.     {$ENDIF}
  83.     HookData^.Clients[HookData^.ClientIndex] := Wnd;
  84.     inc(HookData^.ClientIndex);
  85.   end;
  86. end;
  87.  
  88. procedure RemoveClient(Wnd: HWND);
  89. var
  90.   x: integer;
  91. begin
  92.   if (HookData <> NIL) then
  93.   begin
  94.     {$IFDEF DFS_DEBUG}
  95.     Debug.Log(TRUE, 'DFSKbMon: Trying to remove ' + IntToHex(Wnd, 8));
  96.     {$ENDIF}
  97.     for x := 0 to HookData^.ClientIndex-1 do
  98.     begin
  99.       if HookData^.Clients[x] = Wnd then
  100.       begin
  101.         {$IFDEF DFS_DEBUG}
  102.         Debug.Log(TRUE, '   Found at index ' + IntToStr(HookData^.ClientIndex));
  103.         {$ENDIF}
  104.         if x < HookData^.ClientIndex-1 then
  105.           Move(HookData^.Clients[x+1], HookData^.Clients[x],
  106.              (HookData^.ClientIndex - x - 1) * SizeOf(HWND));
  107.         dec(HookData^.ClientIndex);
  108.         break;
  109.       end;
  110.     end;
  111.   end;
  112. end;
  113.  
  114.  
  115.  
  116. // Keyboard hook callback
  117. function KeyboardHookCallBack(Code: integer; KeyCode: WPARAM;
  118.    KeyInfo: LPARAM): LRESULT; stdcall;
  119. var
  120.   x: integer;
  121.   State: ShortInt;
  122. begin
  123.   if (Code >= 0) and (HookData <> NIL) then
  124.   begin
  125.     // Is it one of the indicator keys, and is it not a repeat
  126.     if ((KeyCode = VK_CAPITAL) or (KeyCode = VK_NUMLOCK) or
  127.        (KeyCode = VK_SCROLL)) and
  128.        // This checks to see if the key is being pressed (bit 31) and if it was
  129.        // up before (bit 30).  We don't care about key releases or keys that
  130.        // were already down.  That just makes us flicker...
  131.        (((KeyInfo SHR 31) and 1) = 0) {and (((KeyInfo SHR 30) and 1) = 0)} then
  132.     begin
  133.       State := GetKeyState(KeyCode);
  134.       for x := 0 to HookData^.ClientIndex-1 do
  135.         PostMessage(HookData^.Clients[x], WM_INDICATORKEY, KeyCode, State);
  136.     end;
  137.   end;
  138.  
  139.   Result := CallNextHookEx(HookData^.KeyboardHookHandle, Code, KeyCode, KeyInfo);
  140. end;
  141.  
  142. // Utility routins for installing the windows hook for keypresses
  143. function RegisterKeyboardHook(Handle: HWND): UINT; stdcall;
  144.   { This is really silly, but that's the way it goes.  The only way to get the }
  145.   { module handle, *not* instance, is from the filename.  The Microsoft example}
  146.   { just hard-codes the DLL filename.  I think this is a little bit better.    }
  147.   function GetModuleHandleFromInstance: THandle;
  148.   var
  149.     s: array[0..512] of char;
  150.   begin
  151.     { Find the DLL filename from the instance value. }
  152.     GetModuleFileName(hInstance, s, sizeof(s)-1);
  153.     { Find the handle from the filename. }
  154.     Result := GetModuleHandle(s);
  155.   end;
  156. begin
  157.   if (HookData <> NIL) then
  158.   begin
  159.     if HookData^.KeyboardHookHandle = 0 then
  160.       { See the Microsoft KnowledgeBase, PSS ID Number: Q92659, for a }
  161.       { discussion of the Windows bug that requires GetModuleHandle to be used.}
  162.       HookData^.KeyboardHookHandle := SetWindowsHookEx(WH_KEYBOARD,
  163.          KeyboardHookCallBack, GetModuleHandleFromInstance, 0);
  164.  
  165.     inc(HookData^.UsageCount);
  166.     AddClient(Handle);
  167.  
  168.     Result := WM_INDICATORKEY;
  169.   end else
  170.     Result := 0;
  171. end;
  172.  
  173. procedure DeregisterKeyboardHook(Handle: HWND); stdcall;
  174. begin
  175.   if (HookData <> NIL) then
  176.   begin
  177.     dec(HookData^.UsageCount);
  178.     RemoveClient(Handle);
  179.     if HookData^.UsageCount < 1 then
  180.     begin
  181.       UnhookWindowsHookEx(HookData^.KeyboardHookHandle);
  182.       HookData^.KeyboardHookHandle := 0;
  183.     end;
  184.   end;
  185. end;
  186.  
  187. procedure LibraryProc(Reason: Integer);
  188. begin
  189.   case Reason of
  190.     DLL_PROCESS_ATTACH:
  191.     begin
  192.       {$IFDEF DFS_DEBUG}
  193.       Debug.Log(TRUE, 'DFSKbMon: loaded.');
  194.       {$ENDIF}
  195.       MapFile := 0;
  196.       HookData := NIL;
  197.       MapFileMemory;
  198.     end;
  199.     DLL_PROCESS_DETACH:
  200.     begin
  201.       UnmapFileMemory;
  202.       {$IFDEF DFS_DEBUG}
  203.       Debug.Log(TRUE, 'DFSKbMon: unloaded.');
  204.       {$ENDIF}
  205.     end;
  206.   end;
  207. end;
  208.  
  209. exports
  210.   RegisterKeyboardHook,
  211.   DeregisterKeyboardHook;
  212.  
  213.  
  214. begin
  215.   WM_INDICATORKEY := RegisterWindowMessage('DFSKbMon.WM_INDICATORKEY');
  216.   DLLProc := @LibraryProc;
  217.   LibraryProc(DLL_PROCESS_ATTACH);
  218. end.
  219.