arash_ebrahimi_nk
سه شنبه 10 مرداد 1385, 15:56 عصر
سلام دوست عزیز
من یه کم تحقیق کردم و فهمیدم که باید از PeekMessage یا GetMessage استفاده کنم.
یه کد آماده به اینصورت دیدم:
This function should work with all Delphi versions:
function KeyPressed(aHandle: THandle): boolean;
var
Msg: TMsg;
begin
if PeekMessage(Msg, aHandle, WM_KEYFIRST,WM_KEYLAST,
PM_REMOVE) then
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
Result := true;
end
else Result := false;
end;
Before useing this function you must empty the keyboard buffer. This works in one line:
while KeyPressed(Handle) do ;
As aHandle you have to use the form-handle. For the actual form it's 0.
یه چیزایی در مورد این کد میدونم امّا هیچ استفاده ای نتونستم ازش بکنم.
شاید برنامه WinSight32 که همراه مجموعه دلفی هست رو دیده باشی.
تمام رویدادهای برنامه های دیگه رو لیست میکنه و تمام اعمال در حال اجرا رو نشون میده.
من میخوام رویدادهای یه برنامه رو بفهمم و بتونم اونها رو مدیریت کنم.
اگه براتون مقدوره یه مرجع ای معرفی ای کنین که بشه ازش یه مثال عملی در آورد.
خدا خیرتون بده.
arash_ebrahimi_nk
چهارشنبه 11 مرداد 1385, 10:53 صبح
یه مثال پیدا کردم:
A lot of people ask me about the possibility that our application Delphi captures the user's keystrokes, although the user doesn't make them our active application being.
Of course... the first thing that we make is to give a turn for the event OnKeyPress of the form, and of course, without obtaining positive results, even putting the property KeyPreview from the form to true...
This happens because our application will only receive messages of the keystrokes when is it who has the focus.
The following step to solve this question is fighting with the keyboard hooks.
A Hook it is not more than a mechanism that will allow us to spy the traffic of messages between Windows and the applications.
To install a hook in our application is something relatively simple, but of course, if we install it in our application, we will only spy the messages that Windows sent to our application, so neither we will have solved the problem.
Then... Which is the solution?. The solution is to install a Hook but at system level, that is to say, a hook that captures all the messages that circulate toward Windows.
Installing a hook at system level has a great added complication that is the fact that the function to the one that calls the hook it must be contained in a DLL, not in our Delphi application.
This condition, will force us, in the first place to build us a DLL, and in second place to to build us some invention to communicate the DLL with our application.
In this trick you have an example of keyboard capture by means of a keyboard Hook to system level.
The example consists of two projects, one for the DLL and another for the example application.
The operation is the following one:
<li>We make DLL with two functions that we will export, one to install the hook and another for ununstall it.
<li>There is a third function that is the one that will execute the hook once installed (CallBack). In her, that will make it is to send the data of the message captured to our application.
The DLL should know in all moment the handle of the receiver application, so we will make him to read it of a memory mapped file that we will create from the own application.
Well, let's go with the example:
DLL that installs the Hook:
Make the skeleton of a DLL (File - New - DLL)
Change the code of the project for this another:
library Project1;
{
Demo de Hook de teclado a nivel de sistema, Radikal.
Como lo que queremos es capturar las teclas pulsadas en cualquier parte
de Windows, necesitamos instalar la funcion CallBack a la que llamará
el Hook en una DLL, que es ésta misma.
}
uses Windows,
Messages;
const
CM_MANDA_TECLA = WM_USER + $1000;
var
HookDeTeclado : HHook;
FicheroM : THandle;
PReceptor : ^Integer;
function CallBackDelHook( Code : Integer;
wParam : WPARAM;
lParam : LPARAM
) : LRESULT; stdcall;
{Esta es la funcion CallBack a la cual llamará el hook.}
{This is the CallBack function called by he Hook}
begin
{Si una tecla fue pulsada o liberada}
{if a key was pressed/released}
if code=HC_ACTION then
begin
{Miramos si existe el fichero}
{if the mapfile exists}
FicheroM:=OpenFileMapping(FILE_MAP_READ,False,'ElR eceptor');
{Si no existe, no enviamos nada a la aplicacion receptora}
{If dont, send nothing to receiver application}
if FicheroM<>0 then
begin
PReceptor:=MapViewOfFile(FicheroM,FILE_MAP_READ,0, 0,0);
PostMessage(PReceptor^,CM_MANDA_TECLA,wParam,lPara m);
UnmapViewOfFile(PReceptor);
CloseHandle(FicheroM);
end;
end;
{Llamamos al siguiente hook de teclado de la cadena}
{call to next hook of the chain}
Result := CallNextHookEx(HookDeTeclado, Code, wParam, lParam)
end;
procedure HookOn; stdcall;
{Procedure que instala el hook}
{procedure for install the hook}
begin
HookDeTeclado:=SetWindowsHookEx(WH_KEYBOARD, @CallBackDelHook, HInstance , 0);
end;
procedure HookOff; stdcall;
begin
{procedure para desinstalar el hook}
{procedure to uninstall the hook}
UnhookWindowsHookEx(HookDeTeclado);
end;
exports
{Exportamos las procedures...}
{Export the procedures}
HookOn,
HookOff;
begin
end.
Now record the project with the name: ' HookTeclado.dpr' and compile it (Project - Build All), and you will have generated the DLL of the project.
Receiver application
<li>Make a new empty application
<li>Put a TMemo (Memo1) in the form
<li>Change the form's unit code by this other:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
const
NombreDLL = 'HookTeclado.dll';
CM_MANDA_TECLA = WM_USER + $1000;
type
THookTeclado=procedure; stdcall;
type
TForm1 = class(TForm)
Label1: TLabel;
Memo1: TMemo;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
FicheroM : THandle;
PReceptor : ^Integer;
HandleDLL : THandle;
HookOn,
HookOff : THookTeclado;
procedure LlegaDelHook(var message: TMessage); message CM_MANDA_TECLA;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
{No queremos que el Memo maneje el teclado...}
{We dont want that the memo read the keyboard...}
Memo1.ReadOnly:=TRUE;
HandleDLL:=LoadLibrary( PChar(ExtractFilePath(Application.Exename)+
NombreDLL ) );
if HandleDLL = 0 then raise Exception.Create('No se pudo cargar la DLL');
@HookOn :=GetProcAddress(HandleDLL, 'HookOn');
@HookOff:=GetProcAddress(HandleDLL, 'HookOff');
IF not assigned(HookOn) or
not assigned(HookOff) then
raise Exception.Create('No se encontraron las funciones en la DLL'+#13+
'Cannot find the required DLL functions');
{Creamos el fichero de memoria}
FicheroM:=CreateFileMapping( $FFFFFFFF,
nil,
PAGE_READWRITE,
0,
SizeOf(Integer),
'ElReceptor');
{Si no se creó el fichero, error}
if FicheroM=0 then
raise Exception.Create( 'Error al crear el fichero'+
'/Error while create file');
{Direccionamos nuestra estructura al fichero de memoria}
PReceptor:=MapViewOfFile(FicheroM,FILE_MAP_WRITE,0 ,0,0);
{Escribimos datos en el fichero de memoria}
PReceptor^:=Handle;
HookOn;
end;
procedure TForm1.LlegaDelHook(var message: TMessage);
var
NombreTecla : array[0..100] of char;
Accion : string;
begin
{Traducimos de Virtual key Code a TEXTO}
{Virtual key code to Key Name}
GetKeyNameText(Message.LParam,@NombreTecla,100);
{Miramos si la tecla fué pulsada, soltada o repetida}
{Look if the key was pressed, released o re-pressed}
if ((Message.lParam shr 31) and 1)=1
then Accion:='Soltada' {Released}
else
if ((Message.lParam shr 30) and 1)=1
then Accion:='Repetida' {repressed}
else Accion:='Pulsada'; {pressed}
Memo1.Lines.Append( Accion+
' tecla: '+
String(NombreTecla) );
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
{Desactivamos el Hook}
{Uninstall the Hook}
if Assigned(HookOff) then HookOff;
{Liberamos la DLL}
{Free the DLL}
if HandleDLL<>0 then
FreeLibrary(HandleDLL);
{Cerramos la vista del fichero y el fichero}
{Close the memfile and the View}
if FicheroM<>0 then
begin
UnmapViewOfFile(PReceptor);
CloseHandle(FicheroM);
end;
end;
end.
<li>Record the project in the same directory of the project of the DLL and compile the application.
If you have followed the steps until here, you will have in the directory of the two projects a DLL (HookTeclado.DLL) and the executable of the receiver application.
Execute it, and you will see in the Memo1 all the keys pressed in Windows.
If you only wanted an example that works, it is not necessary that you continue reading. If you want to know a little more than like the invention works... so... here you have it, step to step:
We go starting from the event OnCreate of the application:
First, we put the Memo1 to readonly. Imagine for what reason, or better, it proves to not putting it, to see that it happens...:)
procedure TForm1.FormCreate(Sender: TObject);
begin
{No queremos que el Memo maneje el teclado...}
{We dont want that the memo read the keyboard...}
Memo1.ReadOnly:=TRUE;
Now we load the DLL that we will suppose that it will be in the same directory that our executable one. If there was some problem when loading it, we generate an exception, in such a way that the following code would not be executed.
HandleDLL:=LoadLibrary( PChar(ExtractFilePath(Application.Exename)+
NombreDLL ) );
if HandleDLL = 0 then raise Exception.Create('No se pudo cargar la DLL');
<li>Once loaded the DLL, we look for the two functions that they should be in it. If they are not... we generate an exception.
@HookOn :=GetProcAddress(HandleDLL, 'HookOn');
@HookOff:=GetProcAddress(HandleDLL, 'HookOff');
IF not assigned(HookOn) or
not assigned(HookOff) then
raise Exception.Create('No se encontraron las funciones en la DLL'+#13+
'Cannot find the required DLL functions');
<li>Now, we make a memory mapped file, which will use to keep the handle of our form, the DLL will taste this way like who must send him the message with the key that has been pressed just reading this file.
{Creamos el fichero de memoria}
FicheroM:=CreateFileMapping( $FFFFFFFF,
nil,
PAGE_READWRITE,
0,
SizeOf(Integer),
'ElReceptor');
{Si no se creó el fichero, error}
if FicheroM=0 then
raise Exception.Create( 'Error al crear el fichero'+
'/Error while create file');
{Direccionamos nuestra estructura al fichero de memoria}
PReceptor:=MapViewOfFile(FicheroM,FILE_MAP_WRITE,0 ,0,0);
<li>Once we have the memory mapped file, and a view pointing to it, we record the handle of the form in it, and we activate the Hook, calling to the procedure HookOn of the DLL:
{Escribimos datos en el fichero de memoria}
PReceptor^:=Handle;
HookOn;
end;
<li>Well, now see that it happens in our DLL when calling to the function HookOn:
procedure HookOn; stdcall;
{Procedure que instala el hook}
{procedure for install the hook}
begin
HookDeTeclado:=SetWindowsHookEx(WH_KEYBOARD, @CallBackDelHook, HInstance , 0);
end;
As you see, there is not more than a call to SetWindowsHookEx, to install a hook at system level (0 in the last parameter) that will execute the function CallBackDelHook with each message that it captures.
<li>Let us see that it makes the function CallBackDelHook when it is executed by the hook:
First, it checks that the function has been called by a new keyboard event, by means of the if code=HC_ACTION.
function CallBackDelHook( Code : Integer;
wParam : WPARAM;
lParam : LPARAM
) : LRESULT; stdcall;
{Esta es la funcion CallBack a la cual llamará el hook.}
{This is the CallBack function called by he Hook}
begin
{Si una tecla fue pulsada o liberada}
{if a key was pressed/released}
if code=HC_ACTION then
begin
If it is this way, that is to say that is a new keyboard event that it is necessary to assist... the first thing that we should make is so to look for the handle from the application to which should send the message with the data of the pressed/released key, which have kept by heart in a file from the application, we try to open the file, and to read this handle, and if everything goes well, we send the message by means of a PostMessage:
{Miramos si existe el fichero}
{if the mapfile exists}
FicheroM:=OpenFileMapping(FILE_MAP_READ,False,'ElR eceptor');
{Si no existe, no enviamos nada a la aplicacion receptora}
{If dont, send nothing to receiver application}
if FicheroM<>0 then
begin
PReceptor:=MapViewOfFile(FicheroM,FILE_MAP_READ,0, 0,0);
PostMessage(PReceptor^,CM_MANDA_TECLA,wParam,lPara m);
once sent the message, we free the file:
UnmapViewOfFile(PReceptor);
CloseHandle(FicheroM);
end;
end;
later, should call to next hook:
{Llamamos al siguiente hook de teclado de la cadena}
{call to next hook of the chain}
Result := CallNextHookEx(HookDeTeclado, Code, wParam, lParam)
end;
Well, do we have installed a hook that captures the keyboard events and does it forward them to our application... which the following step is?, of course... to make something to receive it...
We will have to capture user's message that we have been defined:
const
CM_MANDA_TECLA = WM_USER + $1000;
that which we will get adding this line in the private part of the form:
procedure LlegaDelHook(var message: TMessage); message CM_MANDA_TECLA;
and of course, the corresponding procedure in the implementation part:
procedure TForm1.LlegaDelHook(var message: TMessage);
var
NombreTecla : array[0..100] of char;
Accion : string;
begin
{Traducimos de Virtual key Code a TEXTO}
{Virtual key code to Key Name}
GetKeyNameText(Message.LParam,@NombreTecla,100);
{Miramos si la tecla fué pulsada, soltada o repetida}
{Look if the key was pressed, released o re-pressed}
if ((Message.lParam shr 31) and 1)=1
then Accion:='Soltada' {Released}
else
if ((Message.lParam shr 30) and 1)=1
then Accion:='Repetida' {repressed}
else Accion:='Pulsada'; {pressed}
Memo1.Lines.Append( Accion+
' tecla: '+
String(NombreTecla) );
end;
In this example, I simply translate the data of the pressed/released key, translating it to its key name and adding it to the TMemo.
If you want more information on the parameters than the function will receive, revise the help file Win32.hlp looking for the topic ' KeyboardProc'.
There you will see the meaning of the parameters wParam and lParam that you will receive in the function.
For I finish, we have left to undo this whole invention when we leave the application. The OnDestroy event of the application:
First, uninstall the hook, calling to the HookOff function of the DLL. Care, is to use the if Assigned, because if there has been some problem when loading the DLL in the OnCreate... now we would try to execute something that was not initialized.
procedure TForm1.FormDestroy(Sender: TObject);
begin
{Desactivamos el Hook}
{Uninstall the Hook}
if Assigned(HookOff) then HookOff;
Now, free the DLL:
{Liberamos la DLL}
{Free the DLL}
if HandleDLL<>0 then
FreeLibrary(HandleDLL);
And the file:
{Cerramos la vista del fichero y el fichero}
{Close the memfile and the View}
if FicheroM<>0 then
begin
UnmapViewOfFile(PReceptor);
CloseHandle(FicheroM);
end;
end;
اگه ازش سر در آوردم مزاحم شما نمی شم.
بازم ممنون.
مرد مباح
چهارشنبه 11 مرداد 1385, 15:58 عصر
[ hamacro.zip (http://delphi.icm.edu.pl/ftp/d20share/hamacro.zip) ] [ 121,035 bytes ][ Shareware ] [ No Source ]
[ D2 | D3 | D4 | D5 | D6 | D7 ]Happy Arts Macrorecorder is a Component for Delphi 32 it records/plays Key- and Mouse-Events to play it again. It uses Windows-wide Systemhooks to realize macros. A useful Demo-App is included with sources. Registered users will get Full Sources!
Registered users get FULL SOURCES new versions on my homedir at http://www.uni-jena.de/~i7lema/program.htm required files to compile all included condition of usage shareware - hint on running programs
ببین این به درد میخوره؟ طبق این مشخصات؟
از یک سایت ÷یدا کردم
البته اونی که شما گفتی نیست.
arash_ebrahimi_nk
چهارشنبه 11 مرداد 1385, 17:13 عصر
اون سایت هم مجموعه خودش رو بصورت رایگان برای دانلود گذاشته
http://madshi.net/madCollection.exe
من گرفتم و نصب کردم - به نظر میرسه مشکلی نداره!!
فقط یه کمپوننت نصب میکنه - اما از طریق کد میشه از VCL ها و Dll هاش استفاده کرد.
مثال هم داره.
فکر میکنم از طریق این ابزار سریع تر به نتیجه مطلوب برسم.
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.