Windows全球键盘钩 - Delphi [英] Windows Global Keyboard Hook - Delphi

查看:293
本文介绍了Windows全球键盘钩 - Delphi的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经使用互联网上的源代码创建了一个GLOBAL键盘挂钩DLL。除了浏览器之外,除了浏览器之外,它最好的部分是非常出色的。除非浏览器重点关注,否则浏览器中的每个键都会被选中。失去按下的第一个键。在IE和Firefox中测试过,并且似乎都是一样的。



例如,如果我打开IE并开始输入www。 ,我只能回来了。如果浏览器窗口保持焦点,则不会再丢失任何键。一旦浏览器失去了重点并重新获得关注,第一个键就会再次出现。



可能是因为仅使用WH_KEYDOWN而不是WH_KEYPRESS / WH_KEYUP?任何人都可以这样做吗?



谢谢



PS:钩子功能本身如下:该DLL发送了一个备忘录框和应用程序句柄,DLL将发送消息以及一个usermessage。

  function KeyHookFunc Code,VirtualKey,KeyStroke:Integer):LRESULT;标准
var
KeyState1:​​TKeyBoardState;
AryChar:数组[0..1]的Char;
计数:整数;
begin
结果:= 0;
如果Code = HC_NOREMOVE然后退出;

结果:= CallNextHookEx(hKeyHook,Code,VirtualKey,KeyStroke);
{我把CallNextHookEx移到这里,但如果你想阻止
或更改任何键,然后将其移回}
如果Code< 0然后
退出;
如果代码= HC_ACTION然后
开始
如果((KeyStroke和(1 shl 30)))0然后
如果不是IsWindow(hMemo)然后
开始
{我把OpenFileMapping移到这里,所以它不会被打开
,除非应用程序的DLL被附加到获取一些关键消息}
hMemFile:= OpenFileMapping(FILE_MAP_WRITE,False, NetParentMAP'); // Global7v9k
PHookRec1:= MapViewOfFile(hMemFile,FILE_MAP_WRITE,0,0,0);
如果PHookRec1<>然后
开始
hMemo:= PHookRec1.MemoHnd;
hApp:= PHookRec1.AppHnd;
结束
结束
if((KeyStroke AND(1 shl 31))= 0)then // if((KeyStroke and(1 shl 30))<> 0)then
begin
GetKeyboardState KeyState1);
计数:= ToAscii(VirtualKey,KeyStroke,KeyState1,AryChar,0);
如果Count = 1然后
begin
SendMessage(hMemo,WM_CHAR,Ord(AryChar [0]),0);
{我包括2种方式获得Charaters,一个Memo Hnadle和
a WM_USER + 1678消息给程序}
PostMessage(hApp,WM_USER + 1678,Ord(AryChar [0]), 0);
结束
结束
结束
结束


解决方案

您没有分配您的 hMemo hApp 值早。您正在等待,直到具有1的先前状态标志的通知,这表示一个键已被按下至少1次重复计数,或正在被释放,以先到者为准。因此,当您的钩子检测到第一个按键通知时, hMemo hApp 不可用。这就是为什么你错过角色。尝试这样做:

  function KeyHookFunc(Code,VirtualKey,KeyStroke:Integer):LRESULT;标准
var
KeyState1:​​TKeyBoardState;
AryChar:数组[0..1]的Char;
计数:整数;
begin
结果:= CallNextHookEx(hKeyHook,Code,VirtualKey,KeyStroke);
如果Code<> HC_ACTION然后退出;

{一个密钥通知发生,在检查实际的密钥状态之前准备HWNDs
}
if(hMemo = 0)或(hApp = 0)然后
开始
如果hMemFile = 0然后
开始
hMemFile:= OpenFileMapping(FILE_MAP_WRITE,False,'NetParentMAP');
如果hMemFile = 0然后退出;
结束
如果PHookRec1 = nil然后
begin
PHookRec1:= MapViewOfFile(hMemFile,FILE_MAP_WRITE,0,0,0);
如果PHookRec1 = nil然后退出;
结束
hMemo:= PHookRec1.MemoHnd;
hApp:= PHookRec1.AppHnd;
如果(hMemo = 0)和(hApp = 0)则退出;
结束

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


I've created a GLOBAL keyboard hook DLL, using source code found on the internet. For the best part it works brilliant, except when it comes to browsers.

It picks up every key in the browser except, it seems, when the browser gets focus, it looses the first key that is pressed. Tested this in IE and Firefox and it seems to be the same for both.

For instance, if I open IE and start typing www. , I only get back ww. If the browser window stays in focus no further keys are lost. As soon as the browser looses focus and regains focus, the first key is again missing.

Could it be because of using only WH_KEYDOWN instead of WH_KEYPRESS / WH_KEYUP ? Can anyone shed some light on this please?

Thank you

PS: The hook function itself is below: The DLL is sent a memo box and app handle to wich the DLL will send messages as well as a 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; 

解决方案

You are not assigning your hMemo and hApp values early enough. You are waiting until a notification with a "previous state" flag of 1, which indicates a key has been held down for at least 1 repeat count, or is being released, whichever occurs first. Thus, hMemo and hApp are not available yet when your hook detects its first key down notification. That is why you miss characters. Try this instead:

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;

这篇关于Windows全球键盘钩 - Delphi的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆