aboutsummaryrefslogtreecommitdiff
path: root/backends/events/default
diff options
context:
space:
mode:
authorEugene Sandulenko2007-09-19 13:55:05 +0000
committerEugene Sandulenko2007-09-19 13:55:05 +0000
commit77eea722afe175003baba3ed5341bfbf8cf988f6 (patch)
treeff95cd001b8929308468d69466623f0c28be476b /backends/events/default
parent2254028365cf5f162bd41cf0011b4475ec608f4c (diff)
downloadscummvm-rg350-77eea722afe175003baba3ed5341bfbf8cf988f6.tar.gz
scummvm-rg350-77eea722afe175003baba3ed5341bfbf8cf988f6.tar.bz2
scummvm-rg350-77eea722afe175003baba3ed5341bfbf8cf988f6.zip
Modified patch #1738058: "Action recorder".
svn-id: r28968
Diffstat (limited to 'backends/events/default')
-rw-r--r--backends/events/default/default-events.cpp321
-rw-r--r--backends/events/default/default-events.h44
2 files changed, 365 insertions, 0 deletions
diff --git a/backends/events/default/default-events.cpp b/backends/events/default/default-events.cpp
index 7730cb7df1..7f484a73d4 100644
--- a/backends/events/default/default-events.cpp
+++ b/backends/events/default/default-events.cpp
@@ -27,11 +27,69 @@
#include "common/config-manager.h"
#include "common/system.h"
+#include "common/config-manager.h"
#include "backends/events/default/default-events.h"
#include "engines/engine.h"
#include "gui/message.h"
+#define RECORD_SIGNATURE 0x54455354
+#define RECORD_VERSION 1
+
+void readRecord(Common::InSaveFile *inFile, uint32 &diff, Common::Event &event) {
+ diff = inFile->readUint32LE();
+
+ event.type = (Common::EventType)inFile->readUint32LE();
+
+ switch(event.type) {
+ case Common::EVENT_KEYDOWN:
+ case Common::EVENT_KEYUP:
+ event.kbd.keycode = (Common::KeyCode)inFile->readSint32LE();
+ event.kbd.ascii = inFile->readUint16LE();
+ event.kbd.flags = inFile->readByte();
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ case Common::EVENT_LBUTTONDOWN:
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_RBUTTONDOWN:
+ case Common::EVENT_RBUTTONUP:
+ case Common::EVENT_WHEELUP:
+ case Common::EVENT_WHEELDOWN:
+ event.mouse.x = inFile->readSint16LE();
+ event.mouse.y = inFile->readSint16LE();
+ break;
+ default:
+ break;
+ }
+}
+
+void writeRecord(Common::OutSaveFile *outFile, uint32 diff, Common::Event &event) {
+ outFile->writeUint32LE(diff);
+
+ outFile->writeUint32LE((uint32)event.type);
+
+ switch(event.type) {
+ case Common::EVENT_KEYDOWN:
+ case Common::EVENT_KEYUP:
+ outFile->writeSint32LE(event.kbd.keycode);
+ outFile->writeUint16LE(event.kbd.ascii);
+ outFile->writeByte(event.kbd.flags);
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ case Common::EVENT_LBUTTONDOWN:
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_RBUTTONDOWN:
+ case Common::EVENT_RBUTTONUP:
+ case Common::EVENT_WHEELUP:
+ case Common::EVENT_WHEELDOWN:
+ outFile->writeSint16LE(event.mouse.x);
+ outFile->writeSint16LE(event.mouse.y);
+ break;
+ default:
+ break;
+ }
+}
+
DefaultEventManager::DefaultEventManager(OSystem *boss) :
_boss(boss),
_buttonState(0),
@@ -40,8 +98,252 @@ DefaultEventManager::DefaultEventManager(OSystem *boss) :
assert(_boss);
+ _recordFile = NULL;
+ _recordTimeFile = NULL;
+ _playbackFile = NULL;
+ _playbackTimeFile = NULL;
+ _timeMutex = _boss->createMutex();
+ _recorderMutex = _boss->createMutex();
+
+ _eventCount = 0;
+ _lastEventCount = 0;
+ _lastMillis = 0;
+
+ Common::String recordModeString = ConfMan.get("record_mode");
+ if (recordModeString.compareToIgnoreCase("record") == 0) {
+ _recordMode = kRecorderRecord;
+ } else {
+ if (recordModeString.compareToIgnoreCase("playback") == 0) {
+ _recordMode = kRecorderPlayback;
+ } else {
+ _recordMode = kPassthrough;
+ }
+ }
+
+ _recordFileName = ConfMan.get("record_file_name");
+ if (_recordFileName.empty()) {
+ _recordFileName = "record.bin";
+ }
+ _recordTempFileName = ConfMan.get("record_temp_file_name");
+ if (_recordTempFileName.empty()) {
+ _recordTempFileName = "record.tmp";
+ }
+ _recordTimeFileName = ConfMan.get("record_time_file_name");
+ if (_recordTimeFileName.empty()) {
+ _recordTimeFileName = "record.time";
+ }
+
// Reset key repeat
_currentKeyDown.keycode = 0;
+
+ // recorder stuff
+ if (_recordMode == kRecorderRecord) {
+ _recordCount = 0;
+ _recordTimeCount = 0;
+ _recordFile = _boss->getSavefileManager()->openForSaving(_recordTempFileName.c_str());
+ _recordTimeFile = _boss->getSavefileManager()->openForSaving(_recordTimeFileName.c_str());
+ _recordSubtitles = ConfMan.getBool("subtitles");
+ }
+
+ uint32 sign;
+ uint32 version;
+ uint32 randomSourceCount;
+ if (_recordMode == kRecorderPlayback) {
+ _playbackCount = 0;
+ _playbackTimeCount = 0;
+ _playbackFile = _boss->getSavefileManager()->openForLoading(_recordFileName.c_str());
+ _playbackTimeFile = _boss->getSavefileManager()->openForLoading(_recordTimeFileName.c_str());
+
+ if (!_playbackFile) {
+ warning("Cannot open playback file %s. Playback was switched off", _recordFileName.c_str());
+ _recordMode = kPassthrough;
+ }
+
+ if (!_playbackTimeFile) {
+ warning("Cannot open playback time file %s. Playback was switched off", _recordTimeFileName.c_str());
+ _recordMode = kPassthrough;
+ }
+ }
+
+ if (_recordMode == kRecorderPlayback) {
+ sign = _playbackFile->readUint32LE();
+ if (sign != RECORD_SIGNATURE) {
+ error("Unknown record file signature");
+ }
+ version = _playbackFile->readUint32LE();
+
+ // conf vars
+ ConfMan.setBool("subtitles", _playbackFile->readByte() != 0);
+
+ _recordCount = _playbackFile->readUint32LE();
+ _recordTimeCount = _playbackFile->readUint32LE();
+ randomSourceCount = _playbackFile->readUint32LE();
+ for (uint i = 0; i < randomSourceCount; ++i) {
+ RandomSourceRecord rec;
+ rec.name = "";
+ uint32 sLen = _playbackFile->readUint32LE();
+ for (uint j = 0; j < sLen; ++j) {
+ char c = _playbackFile->readSByte();
+ rec.name += c;
+ }
+ rec.seed = _playbackFile->readUint32LE();
+ _randomSourceRecords.push_back(rec);
+ }
+
+ _hasPlaybackEvent = false;
+ }
+}
+
+DefaultEventManager::~DefaultEventManager() {
+ _boss->lockMutex(_timeMutex);
+ _boss->lockMutex(_recorderMutex);
+ _recordMode = kPassthrough;
+ _boss->unlockMutex(_timeMutex);
+ _boss->unlockMutex(_recorderMutex);
+
+ if (_playbackFile != NULL) {
+ delete _playbackFile;
+ }
+ if (_playbackTimeFile != NULL) {
+ delete _playbackTimeFile;
+ }
+
+ if (_recordFile != NULL) {
+ _recordFile->finalize();
+ delete _recordFile;
+ _recordTimeFile->finalize();
+ delete _recordTimeFile;
+
+ _playbackFile = _boss->getSavefileManager()->openForLoading(_recordTempFileName.c_str());
+
+ _recordFile = _boss->getSavefileManager()->openForSaving(_recordFileName.c_str());
+ _recordFile->writeUint32LE(RECORD_SIGNATURE);
+ _recordFile->writeUint32LE(RECORD_VERSION);
+
+ // conf vars
+ _recordFile->writeByte(_recordSubtitles ? 1 : 0);
+
+ _recordFile->writeUint32LE(_recordCount);
+ _recordFile->writeUint32LE(_recordTimeCount);
+
+ _recordFile->writeUint32LE(_randomSourceRecords.size());
+ for (uint i = 0; i < _randomSourceRecords.size(); ++i) {
+ _recordFile->writeUint32LE(_randomSourceRecords[i].name.size());
+ _recordFile->writeString(_randomSourceRecords[i].name);
+ _recordFile->writeUint32LE(_randomSourceRecords[i].seed);
+ }
+
+ for (uint i = 0; i < _recordCount; ++i) {
+ uint32 tempDiff;
+ Common::Event tempEvent;
+ readRecord(_playbackFile, tempDiff, tempEvent);
+ writeRecord(_recordFile, tempDiff, tempEvent);
+ }
+
+ _recordFile->finalize();
+ delete _recordFile;
+ delete _playbackFile;
+
+ //TODO: remove recordTempFileName'ed file
+ }
+ _boss->deleteMutex(_timeMutex);
+ _boss->deleteMutex(_recorderMutex);
+}
+
+bool DefaultEventManager::playback(Common::Event &event) {
+
+ if (!_hasPlaybackEvent) {
+ if (_recordCount > _playbackCount) {
+ readRecord(_playbackFile, (uint32&)_playbackDiff, _playbackEvent);
+ _playbackCount++;
+ _hasPlaybackEvent = true;
+ }
+ }
+
+ if (_hasPlaybackEvent) {
+ if (_playbackDiff <= (_eventCount - _lastEventCount)) {
+ switch(_playbackEvent.type) {
+ case Common::EVENT_MOUSEMOVE:
+ case Common::EVENT_LBUTTONDOWN:
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_RBUTTONDOWN:
+ case Common::EVENT_RBUTTONUP:
+ case Common::EVENT_WHEELUP:
+ case Common::EVENT_WHEELDOWN:
+ _boss->warpMouse(_playbackEvent.mouse.x, _playbackEvent.mouse.y);
+ break;
+ default:
+ break;
+ }
+ event = _playbackEvent;
+ _hasPlaybackEvent = false;
+ _lastEventCount = _eventCount;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void DefaultEventManager::record(Common::Event &event) {
+ writeRecord(_recordFile, _eventCount - _lastEventCount, event);
+
+ _recordCount++;
+ _lastEventCount = _eventCount;
+}
+
+void DefaultEventManager::registerRandomSource(Common::RandomSource &rnd, const char *name) {
+
+ if (_recordMode == kRecorderRecord) {
+ RandomSourceRecord rec;
+ rec.name = name;
+ rec.seed = rnd.getSeed();
+ _randomSourceRecords.push_back(rec);
+ }
+
+ if (_recordMode == kRecorderPlayback) {
+ for (uint i = 0; i < _randomSourceRecords.size(); ++i) {
+ if (_randomSourceRecords[i].name == name) {
+ rnd.setSeed(_randomSourceRecords[i].seed);
+ _randomSourceRecords.remove_at(i);
+ break;
+ }
+ }
+ }
+}
+
+void DefaultEventManager::processMillis(uint32 &millis) {
+ uint32 d;
+ if (_recordMode == kPassthrough) {
+ return;
+ }
+
+ _boss->lockMutex(_timeMutex);
+ if (_recordMode == kRecorderRecord) {
+ //Simple RLE compression
+ d = millis - _lastMillis;
+ if (d >= 0xff) {
+ _recordTimeFile->writeByte(0xff);
+ _recordTimeFile->writeUint32LE(d);
+ } else {
+ _recordTimeFile->writeByte(d);
+ }
+ _recordTimeCount++;
+ }
+
+ if (_recordMode == kRecorderPlayback) {
+ if (_recordTimeCount > _playbackTimeCount) {
+ d = _playbackTimeFile->readByte();
+ if (d == 0xff) {
+ d = _playbackTimeFile->readUint32LE();
+ }
+ millis = _lastMillis + d;
+ _playbackTimeCount++;
+ }
+ }
+
+ _lastMillis = millis;
+ _boss->unlockMutex(_timeMutex);
}
bool DefaultEventManager::pollEvent(Common::Event &event) {
@@ -50,6 +352,25 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
result = _boss->pollEvent(event);
+ if (_recordMode != kPassthrough) {
+
+ _boss->lockMutex(_recorderMutex);
+ _eventCount++;
+
+ if (_recordMode == kRecorderPlayback) {
+ if (event.type != Common::EVENT_QUIT) {
+ result = playback(event);
+ }
+ } else {
+ if (_recordMode == kRecorderRecord) {
+ if (result) {
+ record(event);
+ }
+ }
+ }
+ _boss->unlockMutex(_recorderMutex);
+ }
+
if (result) {
event.synthetic = false;
switch (event.type) {
diff --git a/backends/events/default/default-events.h b/backends/events/default/default-events.h
index e7d70cb152..14fe775d73 100644
--- a/backends/events/default/default-events.h
+++ b/backends/events/default/default-events.h
@@ -27,6 +27,7 @@
#define BACKEND_EVENTS_DEFAULT_H
#include "common/events.h"
+#include "common/savefile.h"
/*
At some point we will remove pollEvent from OSystem and change
@@ -47,7 +48,45 @@ class DefaultEventManager : public Common::EventManager {
int _buttonState;
int _modifierState;
bool _shouldQuit;
+
+ class RandomSourceRecord {
+ public:
+ Common::String name;
+ uint32 seed;
+ };
+ Common::Array<RandomSourceRecord> _randomSourceRecords;
+
+ bool _recordSubtitles;
+ volatile uint32 _recordCount;
+ volatile uint32 _lastRecordEvent;
+ volatile uint32 _recordTimeCount;
+ Common::OutSaveFile *_recordFile;
+ Common::OutSaveFile *_recordTimeFile;
+ Common::MutexRef _timeMutex;
+ Common::MutexRef _recorderMutex;
+ volatile uint32 _lastMillis;
+
+ volatile uint32 _playbackCount;
+ volatile uint32 _playbackDiff;
+ volatile bool _hasPlaybackEvent;
+ volatile uint32 _playbackTimeCount;
+ Common::Event _playbackEvent;
+ Common::InSaveFile *_playbackFile;
+ Common::InSaveFile *_playbackTimeFile;
+ volatile uint32 _eventCount;
+ volatile uint32 _lastEventCount;
+
+ enum RecordMode {
+ kPassthrough = 0,
+ kRecorderRecord = 1,
+ kRecorderPlayback = 2
+ };
+ volatile RecordMode _recordMode;
+ Common::String _recordFileName;
+ Common::String _recordTempFileName;
+ Common::String _recordTimeFileName;
+
// for continuous events (keyDown)
enum {
kKeyRepeatInitialDelay = 400,
@@ -61,10 +100,15 @@ class DefaultEventManager : public Common::EventManager {
} _currentKeyDown;
uint32 _keyRepeatTime;
+ void record(Common::Event &event);
+ bool playback(Common::Event &event);
public:
DefaultEventManager(OSystem *boss);
+ ~DefaultEventManager();
virtual bool pollEvent(Common::Event &event);
+ virtual void registerRandomSource(Common::RandomSource &rnd, const char *name);
+ virtual void processMillis(uint32 &millis);
virtual Common::Point getMousePos() const { return _mousePos; }
virtual int getButtonState() const { return _buttonState; }