问题
I've been asked to develop a new application that will work along side the existing one. Both application will wait for a barcode reader input. I don't want our operator to scan a barcode twice: once for the existing application (16bit - clipper, no sources) and once for the new application. To solves this issue I've decided to use a low-level keyboard hook (written in Delphi). It looks perfect since 2 applications will need the barcode reader input and that my application will not be focused the most of the time.
My low-level keyboard hook is well working when my application is focused. For example, if I enter into a TEdit control and then if I scan my barcode :
- the awaited characters will be displayed in the TEdit control (#02;90BDIJ#).
- the low-level hook will get all characters (# , then 0, then 2 and so on).
Things are getting worse when my application is no more focused : if I open notepad and then if I scan my barcode :
- the awaited characters will be displayed in notepad (#02;90BDIJ#).
- the low-level hook will get wrongs characters : "àé;çàbdij"
It looks like the Keyboard state is no taken in account ! It looks like the Shift, Ctrl or even Alt keys are no more taken in account.On my french keyboard :
- '#' = CTRL = ALT + "
- '0' = SHIFT + à
- '2' = SHIFT + é
- ...
Does anyone now how to solve this problem ? Am I doing it the wrong way (should I use windows messages instead ?). Thank you in advance.
FWIW Here is my source code :
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.
回答1:
This is a local keyboard hook. You need to create a global hook for it to work everywhere. Global keyboard (and mouse) hooks need to be implemented in a separate .dll.
Update:
I have been corrected. Apparently this does not need to be implemented in a dll.
回答2:
i encountered this issue today and was resolved by adding these lines after 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);
来源:https://stackoverflow.com/questions/1590983/low-level-keyboard-hook-issue-keyboard-state-losed-when-application-is-not-foc