📄 msgsimulator.pas
字号:
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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -