線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:3040
推到 Plurk!
推到 Facebook!

通過Delphi建立鍵盤滑鼠動作紀錄與重播

 
jackkcg
站務副站長


發表:891
回覆:1050
積分:848
註冊:2002-03-23

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-10-26 02:59:59 IP:210.65.xxx.xxx 未訂閱
此為轉貼資料 通過Delphi建立鍵盤滑鼠動作紀錄與重播 TechnoFantasy(原作) www.applevb.com 很多的教學軟體或系統監視軟體可以自動記錄重播用戶的輸入文字或點擊按鈕等操作操作,這個功能的實現是使用 了Windows的Hook函數。 Windows提供API函數SetwindowsHookEx來建立一個Hook,通過這個函數可以將一個程式添加到Hook鏈中監視Windows 消息,函數語法?: SetWindowsHookEx(idHook: Integer; lpfn: TFNHookProc; hmod: HINST; dwThreadId: DWORD) 其中參數idHook指定建立的監視函數類型。通過Windows MSDN幫助可以看到,SetwindowsHookEx函數提供15種不同 的消息監視類型,在這裏我們將使用WH_JOURNALRECORD和WH_JOURNALPLAYBACK來監視鍵盤和滑鼠操作。參數lpfn指定消 息函數,在相應的消息?生後,系統會調用該函數並將消息值傳遞給該函數供處理。函數的一般形式?: Hookproc (code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT stdcall; 其中code?系統指示標記,wParam和lParam?附加參數,根據不同的消息監視類型而不同。只要在程式中建立這樣 一個函數再通過SetwindowsHookEx函數將它加入到消息監視鏈中就可以處理消息了。 在不需要監視系統消息時需要調用提供UnHookWindowsHookEx來解除對消息的監視。 WH_JOURNALRECORD和WH_JOURNALPLAYBACK類型是兩種相反的Hook類型,前者獲得滑鼠、鍵盤動作消息,後者重播鼠 標鍵盤消息。所以在程式中我們需要建立兩個消息函數,一個用於紀錄滑鼠鍵盤操作並保存到一個陣列中,另一個用於 將保存的操作返給系統重播。 下面來建立程式,在Delphi中建立一個工程,在Form1上添加3個按鈕用於程式操作。另外再添加一個按鈕控制項和一 個Edit控制項用於驗證操作。 下面是Form1的全部代碼 unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; Button3: TButton; Edit1: TEdit; Button4: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; EventArr:array[0..1000]of EVENTMSG; EventLog:Integer; PlayLog:Integer; hHook,hPlay:Integer; recOK:Integer; canPlay:Integer; bDelay:Bool; implementation {$R *.DFM} Function PlayProc(iCode:Integer;wParam:wParam;lParam:lParam):LRESULT;stdcall; begin canPlay:=1; Result:=0; if iCode < 0 then //必須將消息傳遞到消息鏈的下一個接受單元 Result := CallNextHookEx(hPlay,iCode,wParam,lParam) else if iCode = HC_SYSMODALON then canPlay:=0 else if iCode = HC_SYSMODALOFF then canPlay:=1 else if ((canPlay =1 )and(iCode=HC_GETNEXT)) then begin if bDelay then begin bDelay:=False; Result:=50; end; pEventMSG(lParam)^:=EventArr[PlayLog]; end else if ((canPlay = 1)and(iCode = HC_SKIP))then begin bDelay := True; PlayLog:=PlayLog 1; end; if PlayLog>=EventLog then begin UNHookWindowsHookEx(hPlay); end; end; function HookProc(iCode:Integer;wParam:wParam;lParam:lParam):LRESULT;stdcall; begin recOK:=1; Result:=0; if iCode < 0 then Result := CallNextHookEx(hHook,iCode,wParam,lParam) else if iCode = HC_SYSMODALON then recOK:=0 else if iCode = HC_SYSMODALOFF then recOK:=1 else if ((recOK>0) and (iCode = HC_ACTION)) then begin EventArr[EventLog]:=pEventMSG(lParam)^; EventLog:=EventLog 1; if EventLog>=1000 then begin UnHookWindowsHookEx(hHook); end; end; end; procedure TForm1.FormCreate(Sender: TObject); begin Button1.Caption:='紀錄'; Button2.Caption:='停止'; Button3.Caption:='重播'; Button4.Caption:='範例'; Button2.Enabled:=False; Button3.Enabled:=False; end; procedure TForm1.Button1Click(Sender: TObject); begin EventLog:=0; //建立鍵盤滑鼠操作消息紀錄鏈 hHook:=SetwindowsHookEx(WH_JOURNALRECORD,HookProc,HInstance,0); Button2.Enabled:=True; Button1.Enabled:=False; end; procedure TForm1.Button2Click(Sender: TObject); begin UnHookWindowsHookEx(hHook); hHook:=0; Button1.Enabled:=True; Button2.Enabled:=False; Button3.Enabled:=True; end; procedure TForm1.Button3Click(Sender: TObject); begin PlayLog:=0; //建立鍵盤滑鼠操作消息紀錄重播鏈 hPlay:=SetwindowsHookEx(WH_JOURNALPLAYBACK,PlayProc, HInstance,0); Button3.Enabled:=False; end; end. 代碼添加完畢後,運行程式,點擊"紀錄"按鈕開始紀錄操作,這時你可以在文本控制項中輸入一些文字或者點擊 "範例"按鈕,然後點擊"停止"按鈕停止紀錄,再點擊"重播"按鈕就可以講先前所做的操作重播。 在上面的程式中,HookProc是紀錄操作的消息函數,每當有滑鼠鍵盤消息發生時,系統都會調用該函數,消息信 息就保存在位址lParam中,我們可以講消息保存在一個陣列中。PlayProc是消息重播函數,當系統可以執行消息重播 時調用該函數,程式就將先前紀錄的消息值返回到lParam指向的區域中,系統就會執行該消息,從而實現了消息重播。
------
**********************************************************
哈哈&兵燹
最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好

Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知
K.表Knowlege 知識,就是本站的標語:Open our mind
hido
一般會員


發表:2
回覆:14
積分:3
註冊:2003-03-18

發送簡訊給我
#2 引用回覆 回覆 發表時間:2003-04-02 12:31:56 IP:140.135.xxx.xxx 未訂閱
請問各位大大 有人將本篇DELPHI的程式碼轉成BCB程式碼嗎? 我對DELPHI不熟!!有很多地方都無法轉為BCB格式 不知道說有哪位大大已經做過相同的事情可以轉貼上來嗎?? 例如:pEventMSG(lParam)^:=EventArr[PlayLog]; 或 EventArr[EventLog]:=pEventMSG(lParam)^; 等等的! 感激不盡
KFC
一般會員


發表:43
回覆:73
積分:23
註冊:2003-03-27

發送簡訊給我
#3 引用回覆 回覆 發表時間:2003-05-19 19:47:52 IP:211.156.xxx.xxx 未訂閱
太棒了!!! 我想问有没有方法可以加快播放动作?实现太慢了,将bDelay设为False还是很慢。为什么许多软件的macro播放可以这么快? 能不能不显示鼠标的移动路径而只显示开始和结束时的鼠标位置? 万分感谢! 發表人 - KFC 於 2003/05/19 19:53:56
jackkcg
站務副站長


發表:891
回覆:1050
積分:848
註冊:2002-03-23

發送簡訊給我
#4 引用回覆 回覆 發表時間:2003-05-19 21:57:16 IP:61.64.xxx.xxx 未訂閱
KFC 我沒有能力幫助你 你去問問 hagar 版主 看看他是否知道你說的 bcb 請找雙修RaynorPao版主 看看 KFC 謝謝你的贊美 不過我比較希望你的分享 這篇是轉貼的 以你的能力可以幫助別人解惑 希望你能多多幫助別人 就相你希望別人幫你一般 這個的讚美 是原著應該擁有的 希望有人能po上原著網址 因為我忘記了 ********************************************************* 哈哈&兵燹 最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好 Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知 K.表Knowlege 知識,就是本站的標語:Open our mind to make knowledge together! 希望能大家敞開心胸,將知識寶庫結合一起
------
**********************************************************
哈哈&兵燹
最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好

Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知
K.表Knowlege 知識,就是本站的標語:Open our mind
Justmade
版主


發表:94
回覆:1934
積分:2030
註冊:2003-03-12

發送簡訊給我
#5 引用回覆 回覆 發表時間:2003-05-19 22:18:58 IP:218.16.xxx.xxx 未訂閱
只是猜猜,作參考: 要加速甚至不要移動過程應可以在記錄或播放時跳過部份或全部(只留最後一個)連續的 WM_MOUSEMOVE 也可找找有沒其他不必要的事件可以跳過。
jumo
一般會員


發表:33
回覆:65
積分:24
註冊:2002-04-17

發送簡訊給我
#6 引用回覆 回覆 發表時間:2003-05-21 16:26:12 IP:61.221.xxx.xxx 未訂閱
請問一下幾個問題: 1. 這個動作的資料是否可以存檔, 以後可以讀出記錄檔, 然後讓他執行之前的動作. 2. 範例程式中是可以重複執行一次, 如果想讓他重複執行 N 次, 有什麼方法可以實現? 請各位大大提供一下意見吧 !!
st
一般會員


發表:11
回覆:21
積分:11
註冊:2004-07-02

發送簡訊給我
#7 引用回覆 回覆 發表時間:2004-09-30 15:50:43 IP:211.22.xxx.xxx 未訂閱
請問有BCB版了嗎?
Zard
尊榮會員


發表:24
回覆:396
積分:539
註冊:2003-11-26

發送簡訊給我
#8 引用回覆 回覆 發表時間:2004-10-19 21:56:55 IP:61.64.xxx.xxx 未訂閱
引言: 太棒了!!! 我想问有没有方法可以加快播放动作?实现太慢了,将bDelay设为False还是很慢。为什么许多软件的macro播放可以这么快? 能不能不显示鼠标的移动路径而只显示开始和结束时的鼠标位置? 万分感谢! 發表人 - KFC 於 2003/05/19 19:53:56
查一下MSDN就有答案了, 引用MSDN原文如下 To have the system wait before processing the message, the return value must be the amount of time, in clock ticks, that the system should wait. (This value can be computed by calculating the difference between the time members in the current and previous input messages.) To process the message immediately, the return value should be zero. The return value is used only if the hook code is HC_GETNEXT; otherwise, it is ignored. 所以程式修改處(標為紅字)如下所示: Function PlayProc(iCode:Integer;wParam:wParam;lParam:lParam):LRESULT;stdcall; begin canPlay:=1; Result:=0; if iCode < 0 then //必須將消息傳遞到消息鏈的下一個接受單元 Result := CallNextHookEx(hPlay,iCode,wParam,lParam) else if iCode = HC_SYSMODALON then canPlay:=0 else if iCode = HC_SYSMODALOFF then canPlay:=1 else if ((canPlay =1 )and(iCode=HC_GETNEXT)) then begin if bDelay then begin bDelay:=False; //原速播放 Result := EventArr[PlayLog].time - EventArr[PlayLog - 1].time; end; pEventMSG(lParam)^ := EventArr[PlayLog]; pEventMSG(lParam)^.time := pEventMSG(lParam)^.time dwBeginTime; end else if ((canPlay = 1)and(iCode = HC_SKIP))then begin bDelay := True; PlayLog:=PlayLog 1; end; if PlayLog>=EventLog then begin UNHookWindowsHookEx(hPlay); end; end; 若要在加快只要在遞減紅字的Result值即可.
Zard
尊榮會員


發表:24
回覆:396
積分:539
註冊:2003-11-26

發送簡訊給我
#9 引用回覆 回覆 發表時間:2004-10-19 22:48:19 IP:61.64.xxx.xxx 未訂閱
引言: 請問有BCB版了嗎? 做善事, 幫翻

<textarea class="cpp" rows="10" cols="60" name="code"> #include #pragma hdrstop #include "Unit1.h" #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; EVENTMSG EventArr[1000]; int EventLog; int PlayLog; HHOOK hHook, hPlay; int recOK; int canPlay; BOOL bDelay; DWORD dwBeginTime; LRESULT WINAPI PlayProc(int iCode, WPARAM wParam, LPARAM lParam) { canPlay=1; int Result=0; if (iCode < 0) //必須將消息傳遞到消息鏈的下一個接受單元 Result = CallNextHookEx(hPlay, iCode, wParam, lParam); else if (iCode == HC_SYSMODALON) canPlay=0; else if (iCode == HC_SYSMODALOFF) canPlay=1; else if ((canPlay ==1 )&&(iCode==HC_GETNEXT)) { if (bDelay) { bDelay=FALSE; Result = EventArr[PlayLog].time - EventArr[PlayLog - 1].time; if (Result < 0) Result = 0; } (*(PEVENTMSGMSG)lParam) = EventArr[PlayLog]; } else if ((canPlay == 1)&&(iCode == HC_SKIP)) { bDelay = TRUE; PlayLog ; } if (PlayLog>=EventLog) { UnhookWindowsHookEx(hPlay); } return Result; } LRESULT WINAPI HookProc(int iCode, WPARAM wParam, LPARAM lParam) { recOK=1; int Result=0; if (iCode < 0) Result = CallNextHookEx(hHook,iCode,wParam,lParam); else if (iCode == HC_SYSMODALON) recOK=0; else if (iCode == HC_SYSMODALOFF) recOK=1; else if ((recOK>0) && (iCode == HC_ACTION)) { EventArr[EventLog]=(*(PEVENTMSGMSG)lParam); EventLog ; if (EventLog>=1000) { UnhookWindowsHookEx(hHook); } } return Result; } __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } void __fastcall TForm1::FormCreate(TObject *Sender) { Button1->Caption="紀錄"; Button2->Caption="停止"; Button3->Caption="重播"; Button4->Caption="範例"; Button2->Enabled=False; Button3->Enabled=False; } void __fastcall TForm1::Button1Click(TObject *Sender) { EventLog=0; //建立鍵盤滑鼠操作消息紀錄鏈 hHook=SetWindowsHookEx(WH_JOURNALRECORD, (HOOKPROC)HookProc, GetModuleHandle(NULL), 0); Button2->Enabled=TRUE; Button1->Enabled=FALSE; } void __fastcall TForm1::Button2Click(TObject *Sender) { UnhookWindowsHookEx(hHook); hHook=NULL; Button1->Enabled=TRUE; Button2->Enabled=FALSE; Button3->Enabled=TRUE; } void __fastcall TForm1::Button3Click(TObject *Sender) { PlayLog=0; dwBeginTime = GetTickCount(); //建立鍵盤滑鼠操作消息紀錄重播鏈 hPlay=SetWindowsHookEx(WH_JOURNALPLAYBACK, (HOOKPROC)PlayProc, GetModuleHandle(NULL), 0); Button3->Enabled=FALSE; } </textarea>
編輯記錄
yckuo 重新編輯於 2007-04-27 10:45:46, 註解 套用程式碼編輯‧
系統時間:2024-04-27 10:28:11
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!