views:

697

answers:

1

Hello,

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  A: 

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.

Bruce McGee
Thank you for your answer Bruce but I wasn't able to make it works under Windows 7 ).
Stephane Wierzbicki
I've done this in Delphi 2007 in Vista with great success - but yes unicode might get in your way. I think Bruce is correct and a global hook is your only option.
Alister
Alister, I'm trying to adapt this code into a DLL... So far no luck, I can't even get a key stroke :(Would you mind to help me on this ?
Stephane Wierzbicki