From: <m97...@us...> - 2010-02-09 22:04:01
|
Revision: 11254 http://openmsx.svn.sourceforge.net/openmsx/?rev=11254&view=rev Author: m9710797 Date: 2010-02-09 22:03:52 +0000 (Tue, 09 Feb 2010) Log Message: ----------- Implemented better msx/host keyboard resync on reverse-stop-replay. See comments in Keyboard::transferHostKeyMatrix() for more details. Modified Paths: -------------- openmsx/trunk/src/ReverseManager.cc openmsx/trunk/src/ReverseManager.hh openmsx/trunk/src/input/Keyboard.cc openmsx/trunk/src/input/Keyboard.hh Modified: openmsx/trunk/src/ReverseManager.cc =================================================================== --- openmsx/trunk/src/ReverseManager.cc 2010-02-09 19:20:23 UTC (rev 11253) +++ openmsx/trunk/src/ReverseManager.cc 2010-02-09 22:03:52 UTC (rev 11254) @@ -4,6 +4,7 @@ #include "MSXMotherBoard.hh" #include "EventDistributor.hh" #include "StateChangeDistributor.hh" +#include "Keyboard.hh" #include "XMLException.hh" #include "XMLElement.hh" #include "TclObject.hh" @@ -100,6 +101,7 @@ , motherBoard(motherBoard_) , eventDistributor(motherBoard.getReactor().getEventDistributor()) , reverseCmd(new ReverseCmd(*this, motherBoard.getCommandController())) + , keyboard(0) , collectCount(0) , replayIndex(0) , pendingTakeSnapshot(false) @@ -117,6 +119,11 @@ eventDistributor.unregisterEventListener(OPENMSX_TAKE_REVERSE_SNAPSHOT, *this); } +void ReverseManager::registerKeyboard(Keyboard& keyboard_) +{ + keyboard = &keyboard_; +} + bool ReverseManager::collecting() const { return collectCount != 0; @@ -303,8 +310,12 @@ // MSXMotherBoard. Also we should stop collecting in this ReverseManager, // and start collecting in the new one. assert(collecting()); - newBoard->getReverseManager().transferHistory( - history, it->first, it->second.eventCount); + ReverseManager& newManager = newBoard->getReverseManager(); + newManager.transferHistory(history, it->first, it->second.eventCount); + if (newManager.keyboard && keyboard) { + newManager.keyboard->transferHostKeyMatrix(*keyboard); + } + stop(); // fast forward to the required time Modified: openmsx/trunk/src/ReverseManager.hh =================================================================== --- openmsx/trunk/src/ReverseManager.hh 2010-02-09 19:20:23 UTC (rev 11253) +++ openmsx/trunk/src/ReverseManager.hh 2010-02-09 22:03:52 UTC (rev 11254) @@ -15,6 +15,7 @@ namespace openmsx { class MSXMotherBoard; +class Keyboard; class EventDistributor; class ReverseCmd; class MemBuffer; @@ -27,6 +28,11 @@ ReverseManager(MSXMotherBoard& motherBoard); ~ReverseManager(); + // Keyboard is special because we need to transfer the host keyboard + // state on 'reverse goto' to be able to resynchronize when replay + // stops. See Keyboard::transferHostKeyMatrix() for more info. + void registerKeyboard(Keyboard& keyboard); + private: struct ReverseChunk { ReverseChunk() : time(EmuTime::zero) {} @@ -89,6 +95,7 @@ MSXMotherBoard& motherBoard; EventDistributor& eventDistributor; const std::auto_ptr<ReverseCmd> reverseCmd; + Keyboard* keyboard; ReverseHistory history; unsigned collectCount; // nb taken snapshots (0 = not collecting) unsigned replayIndex; Modified: openmsx/trunk/src/input/Keyboard.cc =================================================================== --- openmsx/trunk/src/input/Keyboard.cc 2010-02-09 19:20:23 UTC (rev 11253) +++ openmsx/trunk/src/input/Keyboard.cc 2010-02-09 22:03:52 UTC (rev 11254) @@ -9,6 +9,8 @@ #include "InputEventFactory.hh" #include "MSXEventDistributor.hh" #include "StateChangeDistributor.hh" +#include "MSXMotherBoard.hh" +#include "ReverseManager.hh" #include "MSXException.hh" #include "RecordedCommand.hh" #include "CommandException.hh" @@ -210,6 +212,7 @@ , keyGhostingSGCprotected(keyGhostSGCprotected) , codeKanaLocks(codeKanaLocks_) , graphLocks(graphLocks_) + , replaying(true) { keysChanged = false; msxCapsLockOn = false; @@ -219,12 +222,15 @@ memset(keyMatrix, 255, sizeof(keyMatrix)); memset(cmdKeyMatrix, 255, sizeof(cmdKeyMatrix)); memset(userKeyMatrix, 255, sizeof(userKeyMatrix)); + memset(hostKeyMatrix, 255, sizeof(hostKeyMatrix)); memset(dynKeymap, 0, sizeof(dynKeymap)); msxEventDistributor.registerEventListener(*this); stateChangeDistributor.registerListener(*this); // We do not listen for CONSOLE_OFF_EVENTS because rescanning the // keyboard can have unwanted side effects + + motherBoard.getReverseManager().registerKeyboard(*this); } Keyboard::~Keyboard() @@ -248,7 +254,33 @@ return keyMatrix; } -/* Received an MSX event (through EventTranslator class) +void Keyboard::transferHostKeyMatrix(const Keyboard& source) +{ + // This mechanism exists to solve the following problem: + // - play a game where the spacebar is constantly pressed (e.g. + // Road Fighter) + // - go back in time (press the reverse hotkey) while keeping the + // spacebar pressed + // - interrupt replay by pressing the cursor keys, still while + // keeping spacebar pressed + // At the moment replay is interrupted, we need to resynchronize the + // msx keyboard with the host keyboard. In the past we assumed the host + // keyboard had no keys pressed. But this is wrong in the above + // scenario. Now we remember the state of the host keyboard and + // transfer that to the new keyboard(s) that get created for reverese. + // When replay is stopped we restore this host keyboard state, see + // stopReplay(). + + assert(replaying); // we must still be in replay state + + const byte* src = source.replaying ? source.hostKeyMatrix + : source.userKeyMatrix; + for (unsigned row = 0; row < NR_KEYROWS; ++row) { + hostKeyMatrix[row] = src[row]; + } +} + +/* Received an MSX event * Following events get processed: * OPENMSX_KEY_DOWN_EVENT * OPENMSX_KEY_UP_EVENT @@ -279,11 +311,11 @@ void Keyboard::stopReplay(EmuTime::param time) { - // TODO Read actual state from keyboard, currently we just clear all - // pressed keys. Might be hard to implement correctly, is it worth - // the effort? + assert(replaying); + replaying = false; + for (unsigned row = 0; row < NR_KEYROWS; ++row) { - changeKeyMatrixEvent(time, row, 0xff); + changeKeyMatrixEvent(time, row, hostKeyMatrix[row]); } msxmodifiers = 0xff; msxKeyEventQueue->clear(); @@ -1228,6 +1260,7 @@ ar.serialize("msxmodifiers", msxmodifiers); ar.serialize("msxKeyEventQueue", *msxKeyEventQueue); } + // don't serialize hostKeyMatrix if (ar.isLoader()) { // force recalculation of keyMatrix Modified: openmsx/trunk/src/input/Keyboard.hh =================================================================== --- openmsx/trunk/src/input/Keyboard.hh 2010-02-09 19:20:23 UTC (rev 11253) +++ openmsx/trunk/src/input/Keyboard.hh 2010-02-09 22:03:52 UTC (rev 11254) @@ -66,6 +66,8 @@ */ const byte* getKeys(); + void transferHostKeyMatrix(const Keyboard& source); + template<typename Archive> void serialize(Archive& ar, unsigned version); @@ -121,9 +123,10 @@ const std::auto_ptr<KeybDebuggable> keybDebuggable; const std::auto_ptr<UnicodeKeymap> unicodeKeymap; - byte cmdKeyMatrix[NR_KEYROWS]; + byte cmdKeyMatrix [NR_KEYROWS]; byte userKeyMatrix[NR_KEYROWS]; - byte keyMatrix[NR_KEYROWS]; + byte hostKeyMatrix[NR_KEYROWS]; + byte keyMatrix [NR_KEYROWS]; byte msxmodifiers; const bool hasKeypad; const bool keyGhosting; @@ -134,6 +137,7 @@ bool msxCapsLockOn; bool msxCodeKanaLockOn; bool msxGraphLockOn; + bool replaying; static const int MAX_KEYSYM = 0x150; static const byte keyTab[MAX_KEYSYM][2]; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |