| Index: base/event_recorder_win.cc
|
| diff --git a/base/event_recorder_win.cc b/base/event_recorder_win.cc
|
| deleted file mode 100644
|
| index b3076a11318c57744c7256e71987d6688d468d9c..0000000000000000000000000000000000000000
|
| --- a/base/event_recorder_win.cc
|
| +++ /dev/null
|
| @@ -1,258 +0,0 @@
|
| -// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include <stddef.h>
|
| -#include <windows.h>
|
| -#include <mmsystem.h>
|
| -
|
| -#include "base/event_recorder.h"
|
| -#include "base/files/file_util.h"
|
| -#include "base/logging.h"
|
| -
|
| -// A note about time.
|
| -// For perfect playback of events, you'd like a very accurate timer
|
| -// so that events are played back at exactly the same time that
|
| -// they were recorded. However, windows has a clock which is only
|
| -// granular to ~15ms. We see more consistent event playback when
|
| -// using a higher resolution timer. To do this, we use the
|
| -// timeGetTime API instead of the default GetTickCount() API.
|
| -
|
| -namespace base {
|
| -
|
| -EventRecorder* EventRecorder::current_ = NULL;
|
| -
|
| -LRESULT CALLBACK StaticRecordWndProc(int nCode, WPARAM wParam,
|
| - LPARAM lParam) {
|
| - DCHECK(EventRecorder::current());
|
| - return EventRecorder::current()->RecordWndProc(nCode, wParam, lParam);
|
| -}
|
| -
|
| -LRESULT CALLBACK StaticPlaybackWndProc(int nCode, WPARAM wParam,
|
| - LPARAM lParam) {
|
| - DCHECK(EventRecorder::current());
|
| - return EventRecorder::current()->PlaybackWndProc(nCode, wParam, lParam);
|
| -}
|
| -
|
| -EventRecorder::~EventRecorder() {
|
| - // Try to assert early if the caller deletes the recorder
|
| - // while it is still in use.
|
| - DCHECK(!journal_hook_);
|
| - DCHECK(!is_recording_ && !is_playing_);
|
| -}
|
| -
|
| -bool EventRecorder::StartRecording(const FilePath& filename) {
|
| - if (journal_hook_ != NULL)
|
| - return false;
|
| - if (is_recording_ || is_playing_)
|
| - return false;
|
| -
|
| - // Open the recording file.
|
| - DCHECK(!file_);
|
| - file_ = OpenFile(filename, "wb+");
|
| - if (!file_) {
|
| - DLOG(ERROR) << "EventRecorder could not open log file";
|
| - return false;
|
| - }
|
| -
|
| - // Set the faster clock, if possible.
|
| - ::timeBeginPeriod(1);
|
| -
|
| - // Set the recording hook. JOURNALRECORD can only be used as a global hook.
|
| - journal_hook_ = ::SetWindowsHookEx(WH_JOURNALRECORD, StaticRecordWndProc,
|
| - GetModuleHandle(NULL), 0);
|
| - if (!journal_hook_) {
|
| - DLOG(ERROR) << "EventRecorder Record Hook failed";
|
| - CloseFile(file_);
|
| - return false;
|
| - }
|
| -
|
| - is_recording_ = true;
|
| - return true;
|
| -}
|
| -
|
| -void EventRecorder::StopRecording() {
|
| - if (is_recording_) {
|
| - DCHECK(journal_hook_ != NULL);
|
| -
|
| - if (!::UnhookWindowsHookEx(journal_hook_)) {
|
| - DLOG(ERROR) << "EventRecorder Unhook failed";
|
| - // Nothing else we can really do here.
|
| - return;
|
| - }
|
| -
|
| - ::timeEndPeriod(1);
|
| -
|
| - DCHECK(file_ != NULL);
|
| - CloseFile(file_);
|
| - file_ = NULL;
|
| -
|
| - journal_hook_ = NULL;
|
| - is_recording_ = false;
|
| - }
|
| -}
|
| -
|
| -bool EventRecorder::StartPlayback(const FilePath& filename) {
|
| - if (journal_hook_ != NULL)
|
| - return false;
|
| - if (is_recording_ || is_playing_)
|
| - return false;
|
| -
|
| - // Open the recording file.
|
| - DCHECK(!file_);
|
| - file_ = OpenFile(filename, "rb");
|
| - if (!file_) {
|
| - DLOG(ERROR) << "EventRecorder Playback could not open log file";
|
| - return false;
|
| - }
|
| - // Read the first event from the record.
|
| - if (fread(&playback_msg_, sizeof(EVENTMSG), 1, file_) != 1) {
|
| - DLOG(ERROR) << "EventRecorder Playback has no records!";
|
| - CloseFile(file_);
|
| - return false;
|
| - }
|
| -
|
| - // Set the faster clock, if possible.
|
| - ::timeBeginPeriod(1);
|
| -
|
| - // Playback time is tricky. When playing back, we read a series of events,
|
| - // each with timeouts. Simply subtracting the delta between two timers will
|
| - // lead to fast playback (about 2x speed). The API has two events, one
|
| - // which advances to the next event (HC_SKIP), and another that requests the
|
| - // event (HC_GETNEXT). The same event will be requested multiple times.
|
| - // Each time the event is requested, we must calculate the new delay.
|
| - // To do this, we track the start time of the playback, and constantly
|
| - // re-compute the delay. I mention this only because I saw two examples
|
| - // of how to use this code on the net, and both were broken :-)
|
| - playback_start_time_ = timeGetTime();
|
| - playback_first_msg_time_ = playback_msg_.time;
|
| -
|
| - // Set the hook. JOURNALPLAYBACK can only be used as a global hook.
|
| - journal_hook_ = ::SetWindowsHookEx(WH_JOURNALPLAYBACK, StaticPlaybackWndProc,
|
| - GetModuleHandle(NULL), 0);
|
| - if (!journal_hook_) {
|
| - DLOG(ERROR) << "EventRecorder Playback Hook failed";
|
| - return false;
|
| - }
|
| -
|
| - is_playing_ = true;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -void EventRecorder::StopPlayback() {
|
| - if (is_playing_) {
|
| - DCHECK(journal_hook_ != NULL);
|
| -
|
| - if (!::UnhookWindowsHookEx(journal_hook_)) {
|
| - DLOG(ERROR) << "EventRecorder Unhook failed";
|
| - // Nothing else we can really do here.
|
| - }
|
| -
|
| - DCHECK(file_ != NULL);
|
| - CloseFile(file_);
|
| - file_ = NULL;
|
| -
|
| - ::timeEndPeriod(1);
|
| -
|
| - journal_hook_ = NULL;
|
| - is_playing_ = false;
|
| - }
|
| -}
|
| -
|
| -// Windows callback hook for the recorder.
|
| -LRESULT EventRecorder::RecordWndProc(int nCode, WPARAM wParam, LPARAM lParam) {
|
| - static bool recording_enabled = true;
|
| - EVENTMSG* msg_ptr = NULL;
|
| -
|
| - // The API says we have to do this.
|
| - // See http://msdn2.microsoft.com/en-us/library/ms644983(VS.85).aspx
|
| - if (nCode < 0)
|
| - return ::CallNextHookEx(journal_hook_, nCode, wParam, lParam);
|
| -
|
| - // Check for the break key being pressed and stop recording.
|
| - if (::GetKeyState(VK_CANCEL) & 0x8000) {
|
| - StopRecording();
|
| - return ::CallNextHookEx(journal_hook_, nCode, wParam, lParam);
|
| - }
|
| -
|
| - // The Journal Recorder must stop recording events when system modal
|
| - // dialogs are present. (see msdn link above)
|
| - switch (nCode) {
|
| - case HC_SYSMODALON:
|
| - recording_enabled = false;
|
| - break;
|
| - case HC_SYSMODALOFF:
|
| - recording_enabled = true;
|
| - break;
|
| - }
|
| -
|
| - if (nCode == HC_ACTION && recording_enabled) {
|
| - // Aha - we have an event to record.
|
| - msg_ptr = reinterpret_cast<EVENTMSG*>(lParam);
|
| - msg_ptr->time = timeGetTime();
|
| - fwrite(msg_ptr, sizeof(EVENTMSG), 1, file_);
|
| - fflush(file_);
|
| - }
|
| -
|
| - return CallNextHookEx(journal_hook_, nCode, wParam, lParam);
|
| -}
|
| -
|
| -// Windows callback for the playback mode.
|
| -LRESULT EventRecorder::PlaybackWndProc(int nCode, WPARAM wParam,
|
| - LPARAM lParam) {
|
| - static bool playback_enabled = true;
|
| - int delay = 0;
|
| -
|
| - switch (nCode) {
|
| - // A system modal dialog box is being displayed. Stop playing back
|
| - // messages.
|
| - case HC_SYSMODALON:
|
| - playback_enabled = false;
|
| - break;
|
| -
|
| - // A system modal dialog box is destroyed. We can start playing back
|
| - // messages again.
|
| - case HC_SYSMODALOFF:
|
| - playback_enabled = true;
|
| - break;
|
| -
|
| - // Prepare to copy the next mouse or keyboard event to playback.
|
| - case HC_SKIP:
|
| - if (!playback_enabled)
|
| - break;
|
| -
|
| - // Read the next event from the record.
|
| - if (fread(&playback_msg_, sizeof(EVENTMSG), 1, file_) != 1)
|
| - this->StopPlayback();
|
| - break;
|
| -
|
| - // Copy the mouse or keyboard event to the EVENTMSG structure in lParam.
|
| - case HC_GETNEXT:
|
| - if (!playback_enabled)
|
| - break;
|
| -
|
| - memcpy(reinterpret_cast<void*>(lParam), &playback_msg_,
|
| - sizeof(playback_msg_));
|
| -
|
| - // The return value is the amount of time (in milliseconds) to wait
|
| - // before playing back the next message in the playback queue. Each
|
| - // time this is called, we recalculate the delay relative to our current
|
| - // wall clock.
|
| - delay = (playback_msg_.time - playback_first_msg_time_) -
|
| - (timeGetTime() - playback_start_time_);
|
| - if (delay < 0)
|
| - delay = 0;
|
| - return delay;
|
| -
|
| - // An application has called PeekMessage with wRemoveMsg set to PM_NOREMOVE
|
| - // indicating that the message is not removed from the message queue after
|
| - // PeekMessage processing.
|
| - case HC_NOREMOVE:
|
| - break;
|
| - }
|
| -
|
| - return CallNextHookEx(journal_hook_, nCode, wParam, lParam);
|
| -}
|
| -
|
| -} // namespace base
|
|
|