低级键盘挂钩问题:应用程序未聚焦时键盘状态丢失(Delphi)

时间:2009-10-19 20:35:32

标签: delphi keyboard hook low-level

我被要求开发一个新的应用程序,它将与现有应用程序一起工作。两个应用程序都将等待条形码阅读器输入。我不希望我们的操作员扫描条形码两次:一次用于现有应用程序(16位 - 限幅器,无源),一次用于新应用程序。为了解决这个问题,我决定使用一个低级键盘钩子(用Delphi编写)。它看起来很完美,因为2个应用程序需要条形码阅读器输入,而且我的应用程序在大多数时间都不会聚焦。

当我的应用程序集中时,我的低级键盘钩子工作正常。例如,如果我进入TEdit控件然后我扫描条形码:

  • 等待的人物将是 显示在TEdit控件中 (#02; 90BDIJ#)。
  • 低级别的钩子将获得所有字符(#,然后是0,然后是2等等 上)。

当我的应用程序不再集中时,事情变得越来越糟:如果我打开记事本然后我扫描条形码:

  • 等待的人物将是 显示在记事本中(#02; 90BDIJ#)。
  • 低级别的钩子会出现错误字符:“àé;çàbdij”

看起来键盘状态没有考虑在内!看起来我不再考虑Shift,Ctrl或甚至Alt键。在我的法语键盘上:

  • '#'= CTRL = ALT +“
  • '0'= SHIFT +à
  • '2'= SHIFT +é
  • ...

现在有人如何解决这个问题? 我是以错误的方式做的(我应该使用Windows消息吗?)。提前谢谢。

FWIW这是我的源代码:

unit Unit5;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Math;

const
  LLKHF_UP             =  $0080;

type
  tagKBDLLHOOKSTRUCT =  packed record
    vkCode :            DWORD;
    scanCode :          DWORD;
    flags :             DWORD;
    time :              DWORD;
    dwExtraInfo :       Integer;
  end;
  KBDLLHOOKSTRUCT      =  tagKBDLLHOOKSTRUCT;
  PKBDLLHOOKSTRUCT     =  ^KBDLLHOOKSTRUCT;

var
  hkHook : HHook;
  function LowLevelKeyboardProc(Code, wParam, lParam: Integer): Integer; stdcall;
  procedure HookIt;
  procedure UnHookIt;

implementation

uses Unit1;

procedure HookIt;
begin
  hkHook := SetWindowsHookEx(WH_KEYBOARD_LL,@LowLevelKeyboardProc,hInstance,0);
end;

procedure UnHookIt;
begin
  UnHookWindowsHookEx(hkHook);
end;

function LowLevelKeyboardProc(Code, wParam, lParam: Integer): Integer;
var
  KeyState : TKeyboardState;
  NewChar: array[0..1] of Char;
  Hook : PKBDLLHOOKSTRUCT;
  bControlKeyDown : Boolean;
begin
  Try
    Hook := Pointer(lParam);
    Case Code Of
      HC_ACTION:
        begin
            If (Hook^.flags And LLKHF_UP) <> 0 Then
            begin
              FillChar(NewChar,2,#0);
              GetKeyboardState(KeyState);
              If ToAscii(Hook^.vkCode,Hook^.scanCode,KeyState,NewChar,0) = 1 Then
                    Form1.ListBox1.Items.Add(NewChar[0]);
            end;
        end;boar
      end;
  Finally
     Result := CallNextHookEx(hkHook,Code,wParam,lParam);
  end;
end;

end.

2 个答案:

答案 0 :(得分:3)

我今天遇到了这个问题,并通过在GetKeyboardState(KeyState)之后添加这些行来解决;

KeyState[VK_CAPITAL] := GetKeyState(VK_CAPITAL);
KeyState[VK_SHIFT] := GetKeyState(VK_SHIFT);
KeyState[VK_CONTROL] := GetKeyState(VK_CONTROL);
KeyState[VK_MENU] := GetKeyState(VK_MENU);

答案 1 :(得分:2)

这是一个本地键盘钩子。您需要创建global hook才能在任何地方使用它。全局键盘(和鼠标)挂钩需要在单独的.dll中实现。

<强>更新

我被纠正了。显然,这不需要在dll中实现。