2010-07-01 165 views
6

我創建了一個GLOBAL鍵盤鉤子DLL,使用在互聯網上找到的源代碼。對於最好的部分來說,除了涉及到瀏覽器以外,它的功能非常出色。Windows全局鍵盤鉤子 - Delphi

它接收瀏覽器中的每個按鍵,但看起來,當瀏覽器獲得焦點時,它會丟失按下的第一個按鍵。在IE和Firefox中測試過它,兩者似乎都是一樣的。

例如,如果我打開IE並開始輸入www。 ,我只能回來ww。如果瀏覽器窗口始終處於焦點狀態,則不會再有密鑰丟失。一旦瀏覽器失去焦點並重新獲得焦點,第一個關鍵就會再次失蹤。

難道是因爲只使用WH_KEYDOWN而不是WH_KEYPRESS/WH_KEYUP?任何人都可以對此有所瞭解嗎?

謝謝

PS:鉤子函數本身就是下圖:DLL發送了一份備忘錄箱和應用程序句柄至極DLL將發送消息,以及一個usermessage。

function KeyHookFunc(Code, VirtualKey, KeyStroke: Integer): LRESULT; stdcall; 
var 
    KeyState1: TKeyBoardState; 
    AryChar: array[0..1] of Char; 
    Count: Integer; 
begin 
    Result := 0; 
    if Code = HC_NOREMOVE then Exit; 

    Result := CallNextHookEx(hKeyHook, Code, VirtualKey, KeyStroke); 
    {I moved the CallNextHookEx up here but if you want to block 
    or change any keys then move it back down} 
    if Code < 0 then 
    Exit; 
    if Code = HC_ACTION then 
    begin 
    if ((KeyStroke and (1 shl 30)) <> 0) then 
     if not IsWindow(hMemo) then 
     begin 
     {I moved the OpenFileMapping up here so it would not be opened 
     unless the app the DLL is attatched to gets some Key messages} 
     hMemFile := OpenFileMapping(FILE_MAP_WRITE, False, 'NetParentMAP');//Global7v9k 
     PHookRec1 := MapViewOfFile(hMemFile, FILE_MAP_WRITE, 0, 0, 0); 
     if PHookRec1 <> nil then 
     begin 
      hMemo := PHookRec1.MemoHnd; 
      hApp := PHookRec1.AppHnd; 
     end; 
     end; 
    if ((KeyStroke AND (1 shl 31)) = 0) then //if ((KeyStroke and (1 shl 30)) <> 0) then 
    begin 
     GetKeyboardState(KeyState1); 
     Count := ToAscii(VirtualKey, KeyStroke, KeyState1, AryChar, 0); 
     if Count = 1 then 
     begin 
     SendMessage(hMemo, WM_CHAR, Ord(AryChar[0]), 0); 
     {I included 2 ways to get the Charaters, a Memo Hnadle and 
     a WM_USER+1678 message to the program} 
     PostMessage(hApp, WM_USER + 1678, Ord(AryChar[0]), 0); 
     end; 
    end; 
    end; 
end; 
+2

您的代碼示例有助於很多人試圖回答您的代碼。 – 2010-07-01 10:37:47

+0

是的,我知道,問題是我不得不提出整個項目,因爲我不知道問題出在哪裏。我可以說的是,我使用以下設置鉤子: hKeyHook:= SetWindowsHookEx(WH_KEYBOARD,KeyHookFunc,hInstance,0); 但我見過一個似乎使用WH_KEYBOARD_LL的C#項目,這可能會有所作爲嗎? – Paul 2010-07-01 12:04:50

+0

至少您可以向我們展示您在互聯網上找到的來源。也許這個代碼是不正確的...... – bepe4711 2010-07-01 14:50:04

回答

8

你是不是你的分配和hMemohApp足夠早。您正在等待,直到通知的「先前狀態」標誌爲1,表示按鍵已按住至少1次重複計數,或正在釋放,以先發生者爲準。因此,hMemohApp在您的掛鉤檢測到第一次按下鍵通知時尚不可用。這就是你錯過角色的原因。試試這個:

function KeyHookFunc(Code, VirtualKey, KeyStroke: Integer): LRESULT; stdcall; 
var 
    KeyState1: TKeyBoardState; 
    AryChar: array[0..1] of Char; 
    Count: Integer; 
begin 
    Result := CallNextHookEx(hKeyHook, Code, VirtualKey, KeyStroke); 
    if Code <> HC_ACTION then Exit; 

    { a key notification had occured, prepare the HWNDs 
    before checking the actual key state } 
    if (hMemo = 0) or (hApp = 0) then 
    begin 
    if hMemFile = 0 then 
    begin 
     hMemFile := OpenFileMapping(FILE_MAP_WRITE, False, 'NetParentMAP'); 
     if hMemFile = 0 then Exit; 
    end; 
    if PHookRec1 = nil then 
    begin 
     PHookRec1 := MapViewOfFile(hMemFile, FILE_MAP_WRITE, 0, 0, 0); 
     if PHookRec1 = nil then Exit; 
    end; 
    hMemo := PHookRec1.MemoHnd; 
    hApp := PHookRec1.AppHnd; 
    if (hMemo = 0) and (hApp = 0) then Exit; 
    end; 

    if ((KeyStroke and (1 shl 31)) = 0) then // a key is down 
    begin 
    GetKeyboardState(KeyState1); 
    Count := ToAscii(VirtualKey, KeyStroke, KeyState1, AryChar, 0); 
    if Count = 1 then 
    begin 
     if hMemo <> 0 then SendMessage(hMemo, WM_CHAR, Ord(AryChar[0]), 0); 
     if hApp <> 0 then PostMessage(hApp, WM_USER + 1678, Ord(AryChar[0]), 0); 
    end; 
    end; 
end; 
+3

哥們你是明星。可能是愚蠢的錯誤,但沒有更多。謝謝 – Paul 2010-07-02 08:00:58