2010-07-01 3 views
6

Я создал GLOBAL DLL с клавиатурой, используя исходный код, найденный в Интернете. В лучшем случае он работает блестяще, за исключением случаев, когда дело касается браузеров.Windows Global Keyboard Hook - 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

Образец вашего кода помогает людям, которые пытаются ответить на ваш код. –

+0

Да, я знаю, проблема в том, что мне придется поставить весь проект, поскольку я не знаю, где проблема. Я могу сказать, что я использую следующее, чтобы установить hook: hKeyHook: = SetWindowsHookEx (WH_KEYBOARD, KeyHookFunc, hInstance, 0); Но я видел проект C#, который, кажется, использует WH_KEYBOARD_LL, может ли это изменить ситуацию? – Paul

+0

По крайней мере, вы могли бы показать нам источник, который вы нашли в Интернете. Возможно, этот код неправильный ... – bepe4711

ответ

8

Вы не назначая свои hMemo и hApp значения достаточно рано. Вы ожидаете, пока уведомление с флагом «предыдущего состояния» равным 1, что указывает на то, что ключ удерживается в течение, по меньшей мере, 1 повторения или высвобождается, в зависимости от того, что произойдет раньше. Таким образом, hMemo и hApp пока недоступны, когда ваш крючок обнаруживает свое первое уведомление о нажатии клавиши. Вот почему вы пропускаете персонажей. Попробуйте это вместо:

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