1

我被要求开发一个可以与现有应用程序一起工作的新应用程序。两个应用程序都将等待条形码阅读器输入。我不希望我们的操作员扫描条形码两次:一次用于现有应用程序(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.
4

2 回答 2

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);
于 2012-05-07T10:35:38.563 回答
2

这是一个本地键盘挂钩。您需要创建一个全局挂钩以使其在任何地方都可以工作。全局键盘(和鼠标)挂钩需要在单独的 .dll 中实现。

更新:

我已得到纠正。显然这不需要在 dll 中实现。

于 2009-10-19T22:13:01.840 回答