RemoteControl Project
Note that this project also requires the TMsgSimulator component
which can be found at the web page below.
This component was downloaded from
Ben's Delphi Page
http://www.radix.net/~bziegler/Delphi
-Ben Ziegler
bziegler@radix.net
----------------------
main.dfm dosyası
----------------------
ÿ
TMAINFORM 0 TPF0 TMainFormMainFormLeftTopkWidthºHeightàCaptionMsgSimulator Component DemoFont.CharsetDEFAULT_CHARSET
Font.ColorclWindowTextFont.Heightõ Font.Name
MS Sans Serif
Font.Style PositionpoScreenCenter
PixelsPerInch`
TextHeight
TLabelLabel1Left Top´Width²Height
AlignalBottom AlignmenttaCenterCaptionJThis program demonstrates the capabilities of the TMsgSimulator component. TButtonSimClickButLeftTopWidthÑ HeightCaption&Simulate Button ClickTabOrder OnClickSimClickButClick TButtonBeepButLeftTop8WidthKHeightCaption&BeepTabOrderOnClickBeepButClick TButton SimKeyButLeftToppWidthÑ HeightCaptionSimulate &KeystrokesTabOrderOnClickSimKeyButClick TEditEdit1LeftTop˜ Width HeightTabOrderTextEdit1 TButtonButton1LeftTopÈ WidthÑ HeightCaptionType &Text into notepadTabOrderOnClickButton1Click TButton RecordButLeftTopğ WidthKHeightCaption&RecordTabOrderOnClickRecordButClick TButtonStopButLeftpTopğ WidthKHeightCaptionSto&pEnabledTabOrderOnClickStopButClick TButtonPlayButLeftĞ Topğ WidthKHeightCaption&PlayTabOrderOnClickPlayButClick TMemoMemo1LeftTopWidth¡Height‘ Font.CharsetANSI_CHARSET
Font.ColorclWindowTextFont.Heightõ Font.NameCourier New
Font.Style
ParentFont
ScrollBarsssBothTabOrderWordWrap
TMsgSimulator
MsgSimulator1Messages OnStopRecordMsgSimulator1StopRecordLeftÀ Top0
------------------------------------ main.dfm bitiş -----------------------------------
----------------------
main.pas dosyası
----------------------
unit Main;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, MsgSimulator, ShellAPI;
type
TMainForm = class(TForm)
Label1: TLabel;
SimClickBut: TButton;
BeepBut: TButton;
MsgSimulator1: TMsgSimulator;
SimKeyBut: TButton;
Edit1: TEdit;
Button1: TButton;
RecordBut: TButton;
StopBut: TButton;
PlayBut: TButton;
Memo1: TMemo;
procedure BeepButClick(Sender: TObject);
procedure SimClickButClick(Sender: TObject);
procedure SimKeyButClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure RecordButClick(Sender: TObject);
procedure PlayButClick(Sender: TObject);
procedure StopButClick(Sender: TObject);
procedure MsgSimulator1StopRecord(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
{$R *.DFM}
procedure TMainForm.BeepButClick(Sender: TObject);
begin
Beep;
end;
procedure TMainForm.SimClickButClick(Sender: TObject);
begin
with MsgSimulator1 do begin
Messages.Clear;
Add_Window_Click(BeepBut.Handle, 5, 5);
Play;
end;
SimClickBut.SetFocus;
end;
procedure TMainForm.SimKeyButClick(Sender: TObject);
begin
with MsgSimulator1 do begin
Messages.Clear;
Add_ASCII_Keys('This is a Test!');
Edit1.SetFocus;
Play;
end;
SimKeyBut.SetFocus;
end;
procedure TMainForm.Button1Click(Sender: TObject);
var
StartInfo : TStartupInfo;
ProcInfo : TProcessInformation;
begin
GetStartupInfo(StartInfo);
Win32Check(CreateProcess(nil, 'notepad.exe', nil, nil, True, 0, nil, nil, StartInfo, ProcInfo));
WaitForInputIdle(ProcInfo.hProcess, INFINITE);
with MsgSimulator1 do begin
Messages.Clear;
Add_ASCII_Keys('This is a Test!'#13);
Add_ASCII_Keys('Next I will simulate an "F5" keypress:'#13);
Add_VirtualKey(0, VK_F5, 1, mmKeyDown);
Add_VirtualKey(0, VK_F5, 1, mmKeyUp);
Play;
end;
end;
procedure TMainForm.RecordButClick(Sender: TObject);
begin
MsgSimulator1.Record_Input;
StopBut.Enabled := True;
end;
procedure TMainForm.PlayButClick(Sender: TObject);
begin
MsgSimulator1.Play;
end;
procedure TMainForm.StopButClick(Sender: TObject);
begin
MsgSimulator1.Stop_Record;
end;
procedure TMainForm.MsgSimulator1StopRecord(Sender: TObject);
var
i : integer;
mi : TMessageItem;
s : string;
begin
StopBut.Enabled := False;
for i := 0 to MsgSimulator1.Messages.Count-1 do begin
mi := MsgSimulator1.Messages[i];
s := Format('Msg: %3d X: %4d Y: %4d Key: %4.4x Delay: %4d', [integer(mi.Msg), mi.PosX, mi.PosY, mi.VkKey, mi.Delay]);
Memo1.Lines.Add(s);
end;
end;
end.
------------------------------------ main.pas bitiş -----------------------------------
----------------------
msgsimdemo.dpr dosyası
----------------------
program MsgSimDemo;
uses
Forms,
Main in 'Main.pas' {MainForm};
{$R *.RES}
begin
Application.Initialize;
Application.Title := 'MsgSimulator Component Demo';
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end.
------------------------------------ msgsimdemo.dpr bitiş -----------------------------------
----------------------
msgsimdemo.res dosyası
----------------------
ÿÿ ÿÿ è ÿÿ ÿÿ ( @ € € €€ € € € €€ €€€ ÀÀÀ ÿ ÿ ÿÿ ÿ ÿ ÿ ÿÿ ÿÿÿ wx ÌÌÌÌ ‡€ ÌÌÌÌÌÌ ‡øxÌLÌLÌLÌ ø‡€ÌÌÌÌÌÌÌÀ ‡øxLLLLLLL ø‡€ÌÌÌÌÌÌÌÀ ‡øxLLLLLLL Çø‡€ÌÌÌÌÌÌÌ L‡øxLLLLLL@ ÄÇø‡€ÄÄÄÄÄÄÀ LL‡÷wLLLLLL ÄÄÇøxwp ÄÄÄÄÄ LLL‡‡ HLL ÄÄÄÇ÷xpx €„„Ä LLLLxw‡yˆHL ÄÄÄć‡p‡¹™„Ä LLLLGw÷{û¹˜L ÄÄÄćxx÷¿¹™˜Ä DDDDHw{ûû¹™ğ ÄÄÄÄ„x÷»¿¿›™ğ DDDHxy¿»»™™Ÿ ÄÄÄ„÷™»ù›¹™˜ğ DDDHH™›¹™›™Ÿ DDD„ù™›»™™˜ğ DDDHH™™™¹™Ÿ DDD„øù™›™˜ğ DD@O›™ ø›™ğ ™Ÿ ù™ğ Ãÿÿÿğÿ€Àÿ€ ÿ€ À ?à ğ ğ ğ à à à à à à à à à ğ ğ ø ø ü ş ÿ ÿÀ ÿğHÿÿüÿÿşÿÿüÿÿş? 0 ÿÿ M A I N I C O N r è
------------------------------------ msgsimdemo.res bitiş -----------------------------------
----------------------
msgsimdemo.dcr dosyası
----------------------
ÿÿ ÿÿ ˆ 8 ÿÿ T M S G S I M U L A T O R ( € € €€ € € € €€ €€€ ÀÀÀ ÿ ÿ ÿÿ ÿ ÿ ÿ ÿÿ ÿÿÿ ˆˆˆˆˆˆˆˆˆˆ ˆˆˆˆˆİ؈ˆˆ€ÿˆˆˆİ݈€ˆ€ÿˆˆˆİ݈€ğˆˆˆˆİ݈€ğğˆˆˆˆˆİ؈€ÿÿˆˆˆˆˆˆˆˆ€ÿÿ ˆˆˆˆˆfh€ÿÿÿˆˆˆˆ†ff€ÿÿğˆˆˆ»¸†ff€ÿÿˆˆ‹»»†ff€ÿğˆˆˆ‹»»ˆfh€ÿˆˆˆ‹»»ˆˆˆ€ğˆ™˜ˆˆ»¸ˆˆˆ€‰™™ˆˆˆˆˆˆˆˆˆ‰™™ˆˆˆˆˆŒÌˆˆ‰™™ˆˆˆˆˆÌÌȈˆ™˜ˆˆˆˆˆÌÌȈˆˆˆˆŠªˆˆÌÌȈªª¨ˆŒÌˆˆîî航ª¨ˆˆˆˆˆîî航ª¨ˆˆˆˆˆîî舊ªˆˆˆˆˆˆîˆˆˆˆˆˆˆˆˆˆˆˆˆ
---------------------------- msgsimdemo.dcr bitiş -----------------------------------
----------------------
msgsimdemo.pas dosyası
----------------------
unit MsgSimulator;
{
June 23, 1998 by Ben Ziegler
6/30/98 - Added a Record Macro function
}
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
type
TWMMessage = (mmMouseDown, mmMouseUp, mmMouseMove, mmKeyDown, mmKeyUp);
TMessageItem = class(TCollectionItem)
protected
em : TEventMsg; // Structure required by JournalPlayback Proc
FMsg : TWMMessage;
FDelay : DWORD; // Delay in msec before next message is played
FX : integer; // This means nothing for keystrokes
FY : integer; // This means nothing for keystrokes
FKey : integer; // This means nothing for mouse clicks
FHWND : integer; // Window Handle (not used for keystrokes)
FButton : TMouseButton; // This means nothing for keystrokes
procedure Fill_EM_From_Props;
procedure Fill_Props_From_EM;
public
constructor Create(Collection: TCollection); override;
property HWND : integer read FHWND write FHWND; // No need to save it - it will be different after each run
published
property Msg : TWMMessage read FMsg write FMsg;
property PosX : integer read FX write FX;
property PosY : integer read FY write FY;
property VkKey : integer read FKey write FKey;
property Delay : DWORD read FDelay write FDelay;
property Button : TMouseButton read FButton write FButton;
end;
TMsgSimulator = class;
TMessageCollection = class(TCollection)
private
FOwner : TMsgSimulator;
function GetItem(Index: Integer): TMessageItem;
procedure SetItem(Index: Integer; Value: TMessageItem);
protected
function GetOwner: TPersistent; override;
procedure Update(Item: TCollectionItem); override;
public
constructor Create(AOwner: TMsgSimulator);
function Add: TMessageItem;
property Owner: TMsgSimulator read FOwner;
property Items[Index: Integer]: TMessageItem read GetItem write SetItem; default;
end;
TMsgSimulator = class(TComponent)
protected
FRunning : boolean; // Simulation is currently running
play_hk : THandle; // JournalPlayback Hook handle
rec_hk : THandle; // RecordPlayback Hook handle
PlayDone : boolean; // Flag to signal that all messages have been simulated
AbortSim : boolean; // Flag to signal aborting the playback of messages
StartTime : DWORD; // Time simulation started (msec)
StopTime : DWORD; // Time simulation stoped (msec)
FDelay : integer; // Default delay between messages
FMsgList : TMessageCollection; // Messages to playback
FTopWin : string;
FindText : string;
FindHandle : THandle;
StopRec : integer;
FRecording : boolean;
FOnStopRec : TNotifyEvent;
function GetElapTime: integer;
procedure SetMsgList(MsgList: TMessageCollection);
function Add_Raw_Message(Msg: TWMMessage; x, y, VkKey, Delay, HWND: integer; Button: TMouseButton): TMessageItem;
procedure Add_Shift(hwnd: THandle; Shift: TShiftState; UpDown: TWMMessage; Delay: integer);
procedure SimClientToScreen(hwnd: THandle; var x, y: integer);
procedure FixUp_Playback_Delays;
procedure FixUp_Record_Delays;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
// Low-level Message Creation Functions
procedure Add_ClickEx(hwnd: THandle; Button: TMouseButton; Shift: TShiftState;
x, y, Delay: integer);
procedure Add_DragEx(hwnd: THandle; Button: TMouseButton; Shift: TShiftState;
StartX, StartY, StopX, StopY, NumMoves, Delay: integer);
procedure Add_VirtualKey(hwnd: THandle; VkKey, Delay: integer; UpDown: TWMMessage);
// High-level Message Creation Functions
procedure Add_Window_Click(hwnd: THandle; x, y: integer);
procedure Add_Window_Drag(hwnd: THandle; StartX, StartY, StopX, StopY: integer);
procedure Add_Screen_Click(x, y: integer);
procedure Add_Screen_Drag(StartX, StartY, StopX, StopY: integer);
procedure Add_ASCII_Keys(const Keystrokes: string);
public
// Playback & Cancel Functions
procedure Play; // Plays messages, then returns
procedure Play_Async; // Returns immediately
procedure Abort;
procedure Record_Input;
procedure Stop_Record;
property Running: boolean read FRunning;
property Recording: boolean read FRecording;
property ElapTime: integer read GetElapTime; // Elapsed running time in msec
// Helper Functions
procedure FocusWin(hwnd: THandle);
function FindTopLevelWin(const FindText: string): THandle;
published
property Messages: TMessageCollection read FMsgList write SetMsgList;
property DefaultDelay: integer read FDelay write FDelay default 50;
property OnStopRecord: TNotifyEvent read FOnStopRec write FOnStopRec;
end;
procedure Register;
implementation
var
CurSim : TMsgSimulator; // Only one TMsgSimulator can play at a time
Cur : integer; // Current Message to play in the MsgList
NumCur : integer; // Number of times current message has been played
procedure Register;
begin
RegisterComponents('Samples', [TMsgSimulator]);
end;
// *********************************************************************
// TMessageItem
constructor TMessageItem.Create(Collection: TCollection);
begin
inherited;
Delay := TMessageCollection(Collection).Owner.DefaultDelay;
end;
procedure TMessageItem.Fill_EM_From_Props;
begin
em.hwnd := hwnd;
if (Msg = mmMouseDown) and (Button = mbLeft) then em.message := WM_LBUTTONDOWN;
if (Msg = mmMouseUp) and (Button = mbLeft) then em.message := WM_LBUTTONUP;
if (Msg = mmMouseDown) and (Button = mbRight) then em.message := WM_RBUTTONDOWN;
if (Msg = mmMouseUp) and (Button = mbRight) then em.message := WM_RBUTTONUP;
if (Msg = mmMouseDown) and (Button = mbMiddle) then em.message := WM_MBUTTONDOWN;
if (Msg = mmMouseUp) and (Button = mbMiddle) then em.message := WM_MBUTTONUP;
case Msg of
mmMouseMove : em.message := WM_MOUSEMOVE;
mmKeyDown : em.message := WM_KEYDOWN;
mmKeyUp : em.message := WM_KEYUP;
end;
if (Msg = mmKeyDown) or (Msg = mmKeyUp) then begin
// Keystroke Message
em.paramL := VkKey;
em.paramH := MapVirtualKey(VkKey, 0);
end else begin
// Mouse Message
em.paramL := PosX;
em.paramH := PosY;
end;
end;
procedure TMessageItem.Fill_Props_From_EM;
begin
hwnd := em.hwnd;
case em.message of
WM_LBUTTONDOWN : begin Msg := mmMouseDown; Button := mbLeft; end;
WM_LBUTTONUP : begin Msg := mmMouseUp; Button := mbLeft; end;
WM_RBUTTONDOWN : begin Msg := mmMouseDown; Button := mbRight; end;
WM_RBUTTONUP : begin Msg := mmMouseUp; Button := mbRight; end;
WM_MBUTTONDOWN : begin Msg := mmMouseDown; Button := mbMiddle; end;
WM_MBUTTONUP : begin Msg := mmMouseUp; Button := mbMiddle; end;
WM_MOUSEMOVE : Msg := mmMouseMove;
WM_KEYDOWN : Msg := mmKeyDown;
WM_KEYUP : Msg := mmKeyUp;
end;
if (Msg = mmKeyDown) or (Msg = mmKeyUp) then begin
// Keystroke Message
VkKey := em.paramL;
end else begin
// Mouse Message
PosX := em.paramL;
PosY := em.paramH;
end;
end;
// *********************************************************************
// TMessageCollection
constructor TMessageCollection.Create(AOwner: TMsgSimulator);
begin
inherited Create(TMessageItem);
FOwner := AOwner;
end;
function TMessageCollection.Add: TMessageItem;
begin
Result := TMessageItem(inherited Add);
end;
function TMessageCollection.GetItem(Index: Integer): TMessageItem;
begin
Result := TMessageItem(inherited GetItem(Index));
end;
function TMessageCollection.GetOwner: TPersistent;
begin
Result := FOwner;
end;
procedure TMessageCollection.SetItem(Index: Integer; Value: TMessageItem);
begin
inherited SetItem(Index, Value);
end;
procedure TMessageCollection.Update(Item: TCollectionItem);
begin
Assert(not FOwner.Running);
end;
// *********************************************************************
// TMsgSimulator
constructor TMsgSimulator.Create(AOwner: TComponent);
begin
inherited;
FDelay := 50;
FMsgList := TMessageCollection.Create(Self);
end;
destructor TMsgSimulator.Destroy;
begin
if Running then Abort;
FMsgList.Free;
FMsgList := nil;
inherited;
end;
procedure TMsgSimulator.SetMsgList(MsgList: TMessageCollection);
begin
FMsgList.Assign(MsgList);
end;
function TMsgSimulator.Add_Raw_Message(Msg: TWMMessage; x, y, VkKey, Delay, HWND: integer; Button: TMouseButton): TMessageItem;
begin
Result := Messages.Add;
Result.Msg := Msg;
Result.PosX := x;
Result.PosY := y;
Result.VkKey := VkKey;
Result.Delay := Delay;
Result.HWND := HWND;
Result.Button := Button;
end;
procedure TMsgSimulator.Add_Shift(hwnd: THandle; Shift: TShiftState; UpDown: TWMMessage; Delay: integer);
begin
// NOTE: Keystrokes do not require an hwnd, so use 0
if Shift = [] then exit;
if ssShift in Shift then Add_Raw_Message(UpDown, 0, 0, VK_SHIFT, Delay, 0, mbLeft);
if ssCtrl in Shift then Add_Raw_Message(UpDown, 0, 0, VK_CONTROL, Delay, 0, mbLeft);
if ssAlt in Shift then Add_Raw_Message(UpDown, 0, 0, VK_MENU, Delay, 0, mbLeft);
end;
// x, y are in Screen coordinates
procedure TMsgSimulator.Add_ClickEx(hwnd: THandle; Button: TMouseButton; Shift: TShiftState;
x, y, Delay: integer);
begin
Add_Shift(hwnd, Shift, mmKeyDown, Delay);
Add_Raw_Message(mmMouseDown, x, y, 0, Delay, hwnd, Button);
Add_Raw_Message(mmMouseUp, x, y, 0, Delay, hwnd, Button);
Add_Raw_Message(mmMouseMove, x, y, 0, Delay, hwnd, Button);
Add_Shift(hwnd, Shift, mmKeyUp, Delay);
end;
// x, y are in Screen coordinates
procedure TMsgSimulator.Add_DragEx(hwnd: THandle; Button: TMouseButton; Shift: TShiftState;
StartX, StartY, StopX, StopY, NumMoves, Delay: integer);
var
i, x, y : integer;
begin
Add_Shift(hwnd, Shift, mmKeyDown, Delay);
Add_Raw_Message(mmMouseDown, StartX, StartY, 0, Delay, hwnd, Button);
for i := 0 to NumMoves do begin
x := (StopX - StartX) * i div NumMoves + StartX;
y := (StopY - StartY) * i div NumMoves + StartY;
Add_Raw_Message(mmMouseMove, x, y, 0, Delay, hwnd, Button);
end;
Add_Raw_Message(mmMouseUp, StopX, StopY, 0, Delay, hwnd, Button);
Add_Shift(hwnd, Shift, mmKeyUp, Delay);
end;
procedure TMsgSimulator.Add_VirtualKey(hwnd: THandle; VkKey, Delay: integer; UpDown: TWMMessage);
begin
Add_Raw_Message(upDown, 0, 0, vkKey, Delay, hwnd, mbLeft);
end;
procedure TMsgSimulator.SimClientToScreen(hwnd: THandle; var x, y: integer);
var
p : TPoint;
begin
if hwnd = 0 then exit;
p := Point(x, y);
Windows.ClientToScreen(hwnd, p);
x := p.x;
y := p.y;
end;
// x, y are in the Window's coordinates
procedure TMsgSimulator.Add_Window_Click(hwnd: THandle; x, y: integer);
begin
SimClientToScreen(hwnd, x, y);
Add_ClickEx(hwnd, mbLeft, [], x, y, DefaultDelay);
end;
// StartXY & StopXY are in the Window's coordinates
procedure TMsgSimulator.Add_Window_Drag(hwnd: THandle; StartX, StartY, StopX, StopY: integer);
begin
SimClientToScreen(hwnd, StartX, StartY);
SimClientToScreen(hwnd, StopX, StopY);
Add_DragEx(hwnd, mbLeft, [], StartX, StartY, StopX, StopY, 10, DefaultDelay);
end;
// x, y are in Screen coordinates
procedure TMsgSimulator.Add_Screen_Click(x, y: integer);
var
hwnd : THandle;
begin
hwnd := Windows.WindowFromPoint(Point(x, y));
Add_ClickEx(hwnd, mbLeft, [], x, y, DefaultDelay);
end;
// x, y are in Screen coordinates
procedure TMsgSimulator.Add_Screen_Drag(StartX, StartY, StopX, StopY: integer);
var
hwnd : THandle;
begin
hwnd := Windows.WindowFromPoint(Point(StartX, StartY));
Add_DragEx(hwnd, mbLeft, [], StartX, StartY, StopX, StopY, 10, DefaultDelay);
end;
procedure TMsgSimulator.Add_ASCII_Keys(const Keystrokes: string);
var
i : integer;
c : byte;
Shift : boolean;
begin
for i := 1 to Length(Keystrokes) do begin
c := VkKeyScan(Keystrokes[i]) and 255;
Shift := (VkKeyScan(Keystrokes[i]) and 256) <> 0;
if Shift then Add_Raw_Message(mmKeyDown, 0, 0, VK_SHIFT, 1 {DefaultDelay}, 0, mbLeft);
Add_Raw_Message(mmKeyDown, 0, 0, c, DefaultDelay, 0, mbLeft);
Add_Raw_Message(mmKeyUp, 0, 0, c, 1 {DefaultDelay}, 0, mbLeft);
if Shift then Add_Raw_Message(mmKeyUp, 0, 0, VK_SHIFT, 1 {DefaultDelay}, 0, mbLeft);
end;
end;
procedure TMsgSimulator.Play;
begin
Play_Async;
Assert(Application <> nil, 'TMsgSimulator.Play: Application = nil');
while (not Application.Terminated) and (not AbortSim) and (not PlayDone) do begin
Application.ProcessMessages;
Sleep(1);
end;
end;
procedure UnHook;
begin
Win32Check(UnhookWindowsHookEx(CurSim.play_hk));
CurSim.play_hk := 0;
CurSim.PlayDone := True;
CurSim.StopTime := GetTickCount;
CurSim.FRunning := False;
CurSim := nil;
end;
function JournalPlaybackProc(code: integer; wp: WParam; lp: LPARAM): LResult; stdcall;
var
pe : PEventMsg;
begin
Assert(CurSim <> nil, 'CurSim = nil!');
Assert(CurSim.PlayDone = False, 'Still Playing?');
Result := CallNextHookEx(CurSim.play_hk, code, wp, lp);
if code < 0 then exit;
if CurSim.AbortSim then begin
UnHook;
exit;
end;
if code = HC_GETNEXT then begin
pe := @CurSim.Messages[Cur].em;
PEventMsg(lp)^ := pe^;
Result := 0;
if (NumCur = 0) and (Cur > 0) then begin
Result := CurSim.Messages[Cur].em.time - CurSim.Messages[Cur-1].em.time;
end;
NumCur := NumCur + 1;
exit;
end;
if code = HC_SKIP then begin
Cur := Cur + 1;
NumCur := 0;
if Cur = CurSim.Messages.Count then begin
UnHook;
end;
exit;
end;
end;
procedure TMsgSimulator.FixUp_Playback_Delays;
var
i : integer;
begin
for i := 0 to Messages.Count-1 do begin
Messages[i].Fill_EM_From_Props;
if i = 0 then Messages[i].em.time := 0
else Messages[i].em.time := Messages[i-1].em.time + Messages[i].Delay;
// TODO: Fix up HWNDs? -bpz
end;
end;
// This function returns immediately
procedure TMsgSimulator.Play_Async;
begin
StartTime := GetTickCount;
StopTime := StartTime;
if Messages.Count = 0 then exit;
FRunning := True;
AbortSim := False;
PlayDone := False;
Assert(CurSim = nil, 'A TMsgSimulator is already playing or recording!');
CurSim := Self;
FixUp_Playback_Delays;
// Set up the JournalPlayback Hook
Cur := 0;
NumCur := 0;
play_hk := SetWindowsHookEx(WH_JOURNALPLAYBACK, JournalPlaybackProc, HInstance, 0);
end;
function TMsgSimulator.GetElapTime: integer;
begin
if Running then
Result := GetTickCount - StartTime
else
Result := StopTime - StartTime;
end;
procedure TMsgSimulator.Abort;
begin
Assert(Running, 'Must be running to Abort!');
AbortSim := True;
end;
function JournalRecordProc(code: integer; wp: WParam; lp: LPARAM): LResult; stdcall;
var
pe : PEventMsg;
mi : TMessageItem;
begin
Result := 0;
case code of
HC_ACTION : if (CurSim.StopRec = 0) then begin
pe := PEventMsg(lp);
if (pe.message = WM_KEYDOWN) and ((pe.paramL and 255) = VK_CANCEL) then begin
CurSim.Stop_Record;
exit;
end;
mi := CurSim.Messages.Add;
mi.em := pe^;
mi.Fill_Props_From_EM;
end;
HC_SYSMODALON : Inc(CurSim.StopRec);
HC_SYSMODALOFF : Dec(CurSim.StopRec);
end;
end;
procedure TMsgSimulator.Record_Input;
begin
Assert(CurSim = nil, 'A TMsgSimulator is already playing or recording!');
CurSim := Self;
StopRec := 0;
Messages.Clear;
FRecording := True;
rec_hk := SetWindowsHookEx(WH_JOURNALRECORD, JournalRecordProc, HInstance, 0);
end;
procedure TMsgSimulator.FixUp_Record_Delays;
var
i : integer;
begin
for i := 0 to Messages.Count-1 do begin
if i = Messages.Count-1 then Messages[i].Delay := 0
else Messages[i].Delay := Messages[i+1].em.time - Messages[i].em.time;
end;
end;
procedure TMsgSimulator.Stop_Record;
begin
if Recording then begin
Win32Check(UnhookWindowsHookEx(CurSim.rec_hk));
rec_hk := 0;
CurSim := nil;
FRecording := False;
FixUp_Record_Delays;
if Assigned(OnStopRecord) then
OnStopRecord(Self); // This is useful when the user hits CTRL-BREAK to stop recording rather than pressing a "Stop" button
end;
end;
procedure TMsgSimulator.FocusWin(hwnd: THandle);
var
tmp : THandle;
begin
// Get the top-level window
tmp := hwnd;
while GetParent(tmp)<>0 do
tmp := GetParent(tmp);
SetForegroundWindow(tmp);
Windows.SetFocus(hwnd);
end;
function EnumWindowsProc(hwnd: THandle; lp: LParam): boolean; stdcall;
var
buf : array[0..MAX_PATH] of char;
ms : TMsgSimulator;
begin
Result := True;
ms := TMsgSimulator(lp);
Assert(ms<>nil);
GetWindowText(hwnd, buf, sizeof(buf));
if Pos(ms.FindText, buf)<>0 then ms.FindHandle := hwnd;
end;
function TMsgSimulator.FindTopLevelWin(const FindText: string): THandle;
begin
Self.FindText := FindText;
FindHandle := DWORD(-1);
EnumWindows(@EnumWindowsProc, LParam(Self));
Result := FindHandle;
end;
initialization
CurSim := nil;
end.
---------------------------- msgsimdemo.pas bitiş -----------------------------------