Mega Code Archive

 
Categories / Delphi / Games
 

Fare hareketlerini kaydetmek [trecorder]

// TRecorder //Kendi projenizin uses kısmına Recorder yazmanız yeterlidir. // cyamon software // place de l'Hôtel-de-Ville 8 // 1040 Echallens // Switzerland // www.cyamon.com // 11/99 // This unit is a freeware. You may change it, use it in your applications // at your own risks. // The recorder is an object that allows to record and play back mouse and // keyboard events. The recorder is not a component, it is instead a singleton // that is created and destroyed automatically in the initialization and // finalization parts of this unit. The recorded information is saved into a // memory stream. // The recorder exports the following properties and methods: // property State (Read only) is the recorder's state (idle, recording or playing). // property SpeedFactor is the factor (in %) by which the playback speed is modified. // Values < 100 accelerate, and values > 100 slowdown. // property OnStateChange is an event that is fired when the state changes. // procedure DoRecord(Append : boolean); // Starts recording. When "Append" is true the new recorded information is appended // to information already stored in the local stream. Otherwise, the local stream is // clared before recording. // procedure DoPlay; // Plays the recorded information // procedure DoStop; // Stops recording and/or to playing unit Recorder; interface uses Classes, Windows; type TRecorderState = (rsIdle, rsRecording, rsPlaying); TStateChangeEvent = procedure(NewState : TRecorderState) of object; TRecorder = class(TObject) private EventMsg : TEVENTMSG; FState : TRecorderState; FStream : TStream; HookHandle : THandle; BaseTime : integer; FSpeedFactor : integer; FOnStateChange : TStateChangeEvent; procedure SetSpeedFactor(const Value: integer); constructor Create; destructor Destroy; override; procedure SetState(const Value: TRecorderState); public procedure DoPlay; procedure DoRecord(Append : boolean); procedure DoStop; property SpeedFactor : integer read FSpeedFactor write SetSpeedFactor; property OnStateChange : TStateChangeEvent read FOnStateChange write FOnStateChange; property State : TRecorderState read FState; property Stream : TStream read FStream; end; var TheRecorder : TRecorder; implementation uses SysUtils, Messages; {~t} (************) (* PlayProc *) (************) function PlayProc(Code : integer; Undefined : WPARAM; P : LPARAM) : LRESULT; stdcall; begin if Code < 0 then Result := CallNextHookEx(TheRecorder.HookHandle, Code, Undefined, P) else begin case Code of HC_SKIP: begin if TheRecorder.FStream.Position < TheRecorder.FStream.Size then begin TheRecorder.FStream.Read(TheRecorder.EventMsg, SizeOf(EventMsg)); TheRecorder.EventMsg.Time := TheRecorder.SpeedFactor*(TheRecorder.EventMsg.Time div 100); TheRecorder.EventMsg.Time := TheRecorder.EventMsg.Time + TheRecorder.BaseTime; end else TheRecorder.SetState(rsIdle); end; HC_GETNEXT: begin Result := TheRecorder.EventMsg.Time - GetTickCount(); if Result < 0 then Result := 0; PEVENTMSG(P)^ := TheRecorder.EventMsg; end; else PEVENTMSG(P)^ := TheRecorder.EventMsg; Result := CallNextHookEx(TheRecorder.HookHandle, Code, Undefined, P) end {case}; end {if}; end {PlayProc}; (**************) (* RecordProc *) (**************) function RecordProc(Code : integer; Undefined : WPARAM; P : LPARAM) : LRESULT; stdcall; begin if Code < 0 then Result := CallNextHookEx(TheRecorder.HookHandle, Code, Undefined, P) else begin case Code of HC_ACTION: begin TheRecorder.EventMsg := PEVENTMSG(P)^; TheRecorder.EventMsg.Time := TheRecorder.EventMsg.Time-TheRecorder.BaseTime; if (TheRecorder.EventMsg.Message >= WM_KEYFIRST) and (TheRecorder.EventMsg.Message <= WM_KEYLAST) and (LoByte(TheRecorder.EventMsg.ParamL) = VK_CANCEL) then begin // Recording aborted by ctrl-Break TheRecorder.SetState(rsIdle); end {if}; TheRecorder.FStream.Write(TheRecorder.EventMsg, sizeOf(TheRecorder.EventMsg)); end; HC_SYSMODALON:; HC_SYSMODALOFF: end {case}; end {if}; end {RecordProc}; (********************) (* TRecorder.Create *) (********************) constructor TRecorder.Create; begin if TheRecorder = nil then begin FStream := TMemoryStream.Create; FSpeedFactor := 100; end else Fail; end {TRecorder.Create}; (*********************) (* TRecorder.Destroy *) (*********************) destructor TRecorder.Destroy; begin DoStop; FStream.Free; inherited; end {TRecorder.Destroy}; (********************) (* TRecorder.DoPlay *) (********************) procedure TRecorder.DoPlay; begin if State <> rsIdle then raise Exception.Create('Recorder: Not ready to play.') else if FStream.Size = 0 then raise Exception.Create('Recorder: Nothing to play') else begin FStream.Seek(0,0); FStream.Read(EventMsg, SizeOf(EventMsg)); HookHandle := SetWindowsHookEx(WH_JOURNALPLAYBACK, @PlayProc, hInstance, 0); if HookHandle = 0 then raise Exception.Create('Playback hook cannot be created') else begin BaseTime := GetTickCount(); SetState(rsPlaying); end {if}; end {if}; end {TRecorder.DoPlay}; (**********************) (* TRecorder.DoRecord *) (**********************) procedure TRecorder.DoRecord(Append : boolean); begin if State <> rsIdle then raise Exception.Create('Recorder: NotReady to record.') else begin if not Append then begin FStream.Size := 0; BaseTime := GetTickCount(); end else begin EventMsg.Time := 0; if FStream.Size > 0 then begin FStream.Seek(-SizeOf(EventMsg),soFromCurrent); FStream.Read(TheRecorder.EventMsg, SizeOf(EventMsg)); end {if}; BaseTime := GetTickCount() - EventMsg.Time; end {if}; HookHandle := SetWindowsHookEx(WH_JOURNALRECORD, @RecordProc, hInstance, 0); if HookHandle = 0 then raise Exception.Create('JournalHook cannot be created') else begin SetState(rsRecording); end {if}; end {if}; end {TRecorder.DoRecord}; (********************) (* TRecorder.DoStop *) (********************) procedure TRecorder.DoStop; begin SetState(rsIdle); end {TRecorder.DoStop}; (****************************) (* TRecorder.SetSpeedFactor *) (****************************) procedure TRecorder.SetSpeedFactor(const Value: integer); begin if Value > 0 then FSpeedFactor := Value; end {TRecorder.SetSpeedFactor}; (**********************) (* TRecorder.SetState *) (**********************) procedure TRecorder.SetState(const Value: TRecorderState); begin if (Value = rsIdle) and (HookHandle <> THandle(0)) then begin UnhookWindowsHookEx(HookHandle); HookHandle := THandle(0); end {if}; if Value <> FState then begin FState := Value; if Assigned(FOnStateChange) then FOnStateChange(FState) end {if}; end {TRecorder.SetState}; {~b} initialization TheRecorder := nil; TheRecorder := TRecorder.Create; finalization TheRecorder.Free; end.