hush021299
asked on
Translate Key Code (message.lparam)
With a keyHook I receive messages.
With:
GetKeyNameText(Message.LPa ram, @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,STRI NG(CHARACT ER));
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~
Procedure TSpyKeyForm.AddKey(key:wor d;STR:STRI NG);
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(Sen der: TObject);
BEGIN
{We dont want that the memo read the keyboard...}
Memo1.ReadOnly := TRUE;
//Find DLL
HandleDLL := LoadLibrary(PChar(ExtractF ilePath(Ap plication. 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($FFFFFFF F,
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.LPa ram, @Character, 100);
ch:=string(character);
//message from dll
ScanCode:= MapVirtualKey(Message.wPar am,0);
label2.caption:=inttostr(s cancode);
label3.caption:=char(scanc ode);
{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,STRI NG(CHARACT ER));
// 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:wor d;STR:STRI NG);
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(Se nder: 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(Send er: TObject);
var sl:TStringlist;
BEGIN
sl:=tstringlist.create;
//memo1.text:=s;
//memo1.text:=s;// := s;
//showmessage(s);
sl.text:=s;
sl.SaveToFile(extractfilep ath(applic ation.exen ame)+'test 1.txt');
memo1.Lines.LoadFromFile(' test1.txt' );
//memo1.Lines.SaveToFile(' test2.txt' );
END;
END.
With:
GetKeyNameText(Message.LPa
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,STRI
~~~~~~~~~~~~~~~~~~~~~~~~~~
Procedure TSpyKeyForm.AddKey(key:wor
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(Sen
BEGIN
{We dont want that the memo read the keyboard...}
Memo1.ReadOnly := TRUE;
//Find DLL
HandleDLL := LoadLibrary(PChar(ExtractF
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($FFFFFFF
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,
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.LPa
ch:=string(character);
//message from dll
ScanCode:= MapVirtualKey(Message.wPar
label2.caption:=inttostr(s
label3.caption:=char(scanc
{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,STRI
// 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:wor
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(Se
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(Send
var sl:TStringlist;
BEGIN
sl:=tstringlist.create;
//memo1.text:=s;
//memo1.text:=s;// := s;
//showmessage(s);
sl.text:=s;
sl.SaveToFile(extractfilep
memo1.Lines.LoadFromFile('
//memo1.Lines.SaveToFile('
END;
END.
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.
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.
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?
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.
ASKER
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(Se nder: 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_CHA R, Ord(AryChar[0]), 0);
END;
memo2.text:=charstring;
Inc(KeyboardCount);
Label2.Caption:=Format('%d ',[Keyboar dCount]);
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?
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(Se
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_CHA
END;
memo2.text:=charstring;
Inc(KeyboardCount);
Label2.Caption:=Format('%d
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?
ASKER
...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?
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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.
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
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.
however you should correct the hlib2 and hlib mistake.
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,KeyStro
if Count = 1 then
CharString := CharString+ AryChar[0];
//SendMessage(hMemo,WM_CHA
end;
end;
end;
- - - - - - - - - - - - - - - - - - - -
hope this helps you, ask questions if you need more.