15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef BASE_EVENT_RECORDER_H_
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define BASE_EVENT_RECORDER_H_
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base_export.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class FilePath;
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A class for recording and playing back keyboard and mouse input events.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note - if you record events, and the playback with the windows in
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//        different sizes or positions, the playback will fail.  When
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//        recording and playing, you should move the relevant windows
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//        to constant sizes and locations.
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(mbelshe) For now this is a singleton.  I believe that this class
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//        could be easily modified to:
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//             support two simultaneous recorders
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//             be playing back events while already recording events.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//        Why?  Imagine if the product had a "record a macro" feature.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//        You might be recording globally, while recording or playing back
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//        a macro.  I don't think two playbacks make sense.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BASE_EXPORT EventRecorder {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the singleton EventRecorder.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We can only handle one recorder/player at a time.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static EventRecorder* current() {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!current_)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      current_ = new EventRecorder();
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return current_;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Starts recording events.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will clobber the file if it already exists.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true on success, or false if an error occurred.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool StartRecording(const FilePath& filename);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Stops recording.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void StopRecording();
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Is the EventRecorder currently recording.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_recording() const { return is_recording_; }
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Plays events previously recorded.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true on success, or false if an error occurred.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool StartPlayback(const FilePath& filename);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Stops playback.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void StopPlayback();
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Is the EventRecorder currently playing.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_playing() const { return is_playing_; }
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // C-style callbacks for the EventRecorder.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Used for internal purposes only.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LRESULT RecordWndProc(int nCode, WPARAM wParam, LPARAM lParam);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LRESULT PlaybackWndProc(int nCode, WPARAM wParam, LPARAM lParam);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a new EventRecorder.  Events are saved to the file filename.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the file already exists, it will be deleted before recording
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // starts.
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EventRecorder()
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : is_recording_(false),
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        is_playing_(false),
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        journal_hook_(NULL),
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        file_(NULL),
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        playback_first_msg_time_(0),
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        playback_start_time_(0) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(&playback_msg_, 0, sizeof(playback_msg_));
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~EventRecorder();
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static EventRecorder* current_;  // Our singleton.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_recording_;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_playing_;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HHOOK journal_hook_;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FILE* file_;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EVENTMSG playback_msg_;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int playback_first_msg_time_;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int playback_start_time_;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(EventRecorder);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // BASE_EVENT_RECORDER_H_
110