Link to home
Start Free TrialLog in
Avatar of hush021299
hush021299

asked on

Translate Key Code (message.lparam)

With a keyHook I receive messages.
With:
    GetKeyNameText(Message.LParam, @Character, 100);
I receive the Name of the key from the message. e.g. J, L, SHIFT, ENTER, F1

So far so good, but the problem is, I can display only the "first set" of chars, not considering the status of the shift key. (e.g. I press :, but GetKeyNameText returns first "SHIFT" and then ";"

At another place I receive and store the status of the shift key. With SHIFT and message.lparam I should be able to get the real key, the user pressed!?

So I tried this
 .. which should normaly produce the same text like the memo which the user have entered originally.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
AddKey(Message.WParam,STRING(CHARACTER));
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Procedure TSpyKeyForm.AddKey(key:word;STR:STRING);
VAR ch:STRING;
CONST
    AddAscii: integer = 32;
begin
        IF shift THEN AddAscii := 0 ELSE AddAscii := 32;
        case KEY of
        16: SHIFT:= true; //set shift private var,
        13: S:= S + #10#13;
        32: begin ch:= ' '; S:= S + CH ; end;
        186 .. 230: s:=s+STR;
        65 .. 90: s:=s+char(KEY + addAscii);
        else
        s:=s+' ['+STR+'] ';//char(KEY + addAscii);
        END;
end;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This procedure is far away from being finished, but I think there must be a API funktion to perform this kind of translation?!

Question:
Maybe a kind of GetKeyNameText which also take the shift key in order to give me the real character the user pressed, or a function like the one above using the message or ascii code and the SHIFT status.

.................................................
Here the unit:

UNIT KeyHook_DLL_U2;

INTERFACE

USES
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
    StdCtrls;

CONST
    My_Hook_DLL = 'KHD.dll';
    MY_HOOK_MSSG = WM_USER + $1000;

TYPE
    THookTeclado = PROCEDURE; stdcall;

TYPE
    TSpyKeyForm = CLASS(TForm)
        Memo1: TMemo;
        Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
        PROCEDURE FormCreate(Sender: TObject);
        PROCEDURE FormDestroy(Sender: TObject);
        PROCEDURE FormClick(Sender: TObject);
    Private
        { Private declarations }
        shift: boolean;
        File_in_Mem: THandle;
        PReceiver: ^Integer;
        HandleDLL: THandle;
        HookOn,
            HookOff: THookTeclado;
        s: STRING;
        PROCEDURE Sys_Hook(VAR message: TMessage); Message MY_HOOK_MSSG;
    procedure AddKey(key: word;STR:STRING);
    Public
        { Public declarations }
    END;

VAR
    SpyKeyForm: TSpyKeyForm;

IMPLEMENTATION

{$R *.DFM}

PROCEDURE TSpyKeyForm.FormCreate(Sender: TObject);
BEGIN

    {We dont want that the memo read the keyboard...}
    Memo1.ReadOnly := TRUE;
    //Find DLL
    HandleDLL := LoadLibrary(PChar(ExtractFilePath(Application.Exename) + My_Hook_DLL));
    IF HandleDLL = 0 THEN
        RAISE Exception.Create('DLL not found');
    //get address of dll functions
    @HookOn := GetProcAddress(HandleDLL, 'HookOn');
    @HookOff := GetProcAddress(HandleDLL, 'HookOff');

    IF NOT assigned(HookOn) OR
        NOT assigned(HookOff) THEN
        RAISE Exception.Create('Cannot find the required DLL functions');

    File_in_Mem := CreateFileMapping($FFFFFFFF,
        NIL,
        PAGE_READWRITE,
        0,
        SizeOf(Integer),
        'MyMappedFile'); //in dll

    IF File_in_Mem = 0 THEN
        RAISE Exception.Create('Error while create file');

    PReceiver := MapViewOfFile(File_in_Mem, FILE_MAP_WRITE, 0, 0, 0);

    PReceiver^ := Handle;
    HookOn;
END;

PROCEDURE TSpyKeyForm.Sys_Hook(VAR message: TMessage);
VAR
    Character: ARRAY[0..100] OF char;
    Key_Action: STRING; ch:string;
    ScanCode:word;
BEGIN
    {Virtual key code to Key Name}
    GetKeyNameText(Message.LParam, @Character, 100);
    ch:=string(character);
    //message from dll
   
    ScanCode:= MapVirtualKey(Message.wParam,0);
    label2.caption:=inttostr(scancode);
    label3.caption:=char(scancode);
    {Look if the key was pressed, released o re-pressed}
    IF ((Message.lParam SHR 31) AND 1) = 1 THEN
        BEGIN
            Key_Action := 'Released'; {Released}
            IF message.wparam = 16 THEN shift := false;
        END
    ELSE
        IF ((Message.lParam SHR 30) AND 1) = 1 THEN Key_Action := 'Repressed' {repressed}
    ELSE
        BEGIN Key_Action := 'pressed'; {pressed}
          AddKey(Message.WParam,STRING(CHARACTER));

       // s := s + ch;//STRING(Character);
        //        end;
        END;
    //if message.wparam = 16 then shift:= true else shift := false;

    //IF shift THEN showmessage('shift');
END;

Procedure TSpyKeyForm.AddKey(key:word;STR:STRING);
VAR ch:STRING;
CONST
    AddAscii: integer = 32;
begin
        IF shift THEN AddAscii := 0 ELSE AddAscii := 32;
        case KEY of
        16: shift := true;
        13: S:= S + #10#13;
        32: begin ch:= ' '; S:= S + CH ; end;
        186 .. 230: s:=s+STR;
        65 .. 90: s:=s+char(KEY + addAscii);
        else
        s:=s+' ['+STR+'] ';//char(KEY + addAscii);
        END;


    label1.caption :=
        inttostr(KEY) + '  '
        + STR + '  '
        + char(KEY + addAscii);


end;

PROCEDURE TSpyKeyForm.FormDestroy(Sender: TObject);
BEGIN
    {Uninstall the Hook}
    IF Assigned(HookOff) THEN
        HookOff;

    {Free the DLL}
    IF HandleDLL <> 0 THEN
        FreeLibrary(HandleDLL);

    {Close the memfile and the View}
    IF File_in_Mem <> 0 THEN
        BEGIN
            UnmapViewOfFile(PReceiver);
            CloseHandle(File_in_Mem);
        END;

END;

PROCEDURE TSpyKeyForm.FormClick(Sender: TObject);
var sl:TStringlist;
BEGIN
sl:=tstringlist.create;
    //memo1.text:=s;
    //memo1.text:=s;// := s;
    //showmessage(s);
    sl.text:=s;
    sl.SaveToFile(extractfilepath(application.exename)+'test1.txt');
    memo1.Lines.LoadFromFile('test1.txt');
    //memo1.Lines.SaveToFile('test2.txt');
END;

END.
Avatar of Member_2_248744
Member_2_248744
Flag of United States of America image

hello hush, I remember trying to get the Char out of the KeyHook, and then trying to figure out how to use ToAscii( ) the following code might save you alot of time.


var
CharString: String;
{CharString will have all the ASCII charaters typed, keys like
the Ctrl and Alt and F1 will not be added}

function KeyHookFunc(Code, VirtualKey{wParam}, KeyStroke{lParam}: 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);
if Code < 0 then
Exit;
if Code = HC_ACTION then
  begin
  if ((KeyStroke and (1 shl 30)) = 0) then
    begin
    GetKeyboardState(KeyState1);
    Count := ToAscii(VirtualKey,KeyStroke, KeyState1, AryChar, 0);
    if Count = 1 then
    CharString := CharString+ AryChar[0];
    //SendMessage(hMemo,WM_CHAR, Ord(AryChar[0]), 0);
    end;
  end;

end;


- - - - - - - - - - - - - - - - - - - -

hope this helps you, ask questions if you need more.
Avatar of robert_marquardt
robert_marquardt

Your problem is one of understanding. GetKeyNameText returns the name of the "physical" key. There "Shift" is just a normal key.

BTW GetKeyNameText is unreliable. It is implemented in a language specific DLL. The Windows 2000 version of the DLL is inferior to the Windows 98 version.
Avatar of hush021299

ASKER

Hello Slick812

Thanks a lot. I think this is the right clue, but I do not understand completely this part:

IF ((Message.lParam AND (1 SHL 30)) = 0) THEN
                    BEGIN ...

Does this show a keypress?
                         
I should have explained that, the First Bit in the KeyStroke (lparam) will be on if the key is down and off if the key is up so you test to see if it's down and do the charater, otherwise you'll get 2 Chars (one for key down and one for Key up) and you get double charaters, That one was hard to figure.
I hope I dont confuse u know.
The first code above is based on my first attempt using a dll. No I am at another place and try to understand your example code.
I just found a code (DLL, HookComponent and Unit) which I found on EExch. This code works fine so far. But then I tried to enter a part of your snippet in the keyHook eventhandler:

procedure TForm1.HookLib1KeyEvent(Sender: TObject; wParam,
  lParam: Integer);
VAR
     KeyState1: TKeyBoardState;
     AryChar: ARRAY[0..1] OF Char;
     Count: Integer;
BEGIN
     IF ((lParam AND (1 SHL 30)) = 0) THEN
     BEGIN
          GetKeyboardState(KeyState1);
          Count := ToAscii(wParam, lParam, KeyState1, AnyChar, 0);
          IF Count = 1 THEN
               CharString := CharString + AryChar[0];
   //SendMessage(hMemo,WM_CHAR, Ord(AryChar[0]), 0);
     END;
    memo2.text:=charstring;
   Inc(KeyboardCount);
   Label2.Caption:=Format('%d',[KeyboardCount]);
end;

The result is: It works fine as long I focus the memo, but when I key my text in another object,
I get the ascii-keystrokes,
but again only the non capital and first row of the keyboard.
(Test in internal Memo
this is when writing into notepad ,.-,.-)<=  

Why is that so?

...forgot something
basically I seems to get any keys, e.g. the shift key (16) and then the 1 (49) key. The system translates toASCII.
So when I figure out that a shift key is pressed then a "1" becomes a "!"

So I know that 1 = 16, but when I press ! it becomes to something else (I can not simply add 32). This is the part I do not understand.

Now the toASCII or getKeyNameText functions dont take shift as a parameter.

How can I know figure out what key really is shown in the originating document?
ASKER CERTIFIED SOLUTION
Avatar of Member_2_248744
Member_2_248744
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I got the same exactly problem with HUSH.
That spanish code has something wrong with SHIFT+key.
But it's look like a good code.



Alright...

When ever someone in my computer presses a key stroke ..is your DLL will work.

BM
good job!
however you should correct the hlib2 and hlib mistake.