/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkInteractorEventRecorder.cxx,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkInteractorEventRecorder.h" #include "vtkCallbackCommand.h" #include "vtkObjectFactory.h" #include "vtkRenderWindowInteractor.h" vtkCxxRevisionMacro(vtkInteractorEventRecorder, "$Revision: 1.8 $"); vtkStandardNewMacro(vtkInteractorEventRecorder); float vtkInteractorEventRecorder::StreamVersion = 1.0; vtkInteractorEventRecorder::vtkInteractorEventRecorder() { //take over the processing of delete and keypress events from the superclass this->KeyPressCallbackCommand->SetCallback( vtkInteractorEventRecorder::ProcessCharEvent); this->Priority = VTK_LARGE_FLOAT; //get events first this->EventCallbackCommand->SetCallback( vtkInteractorEventRecorder::ProcessEvents); this->FileName = NULL; this->State = vtkInteractorEventRecorder::Start; this->InputStream = NULL; this->OutputStream = NULL; this->ReadFromInputString = 0; this->InputString = NULL; } vtkInteractorEventRecorder::~vtkInteractorEventRecorder() { this->SetInteractor(0); if ( this->FileName ) { delete [] this->FileName; } if ( this->InputStream ) { delete this->InputStream; this->InputStream = NULL; } if ( this->OutputStream ) { delete this->OutputStream; this->OutputStream = NULL; } if ( this->InputString ) { delete [] this->InputString; this->InputString = NULL; } } void vtkInteractorEventRecorder::SetEnabled(int enabling) { if ( ! this->Interactor ) { vtkErrorMacro(<<"The interactor must be set prior to enabling/disabling widget"); return; } if ( enabling ) //---------------------------------------------------------- { vtkDebugMacro(<<"Enabling widget"); if ( this->Enabled ) //already enabled, just return { return; } this->Enabled = 1; // listen to any event vtkRenderWindowInteractor *i = this->Interactor; i->AddObserver(vtkCommand::AnyEvent, this->EventCallbackCommand, this->Priority); this->InvokeEvent(vtkCommand::EnableEvent,NULL); } else //disabling----------------------------------------------------------- { vtkDebugMacro(<<"Disabling widget"); if ( ! this->Enabled ) //already disabled, just return { return; } this->Enabled = 0; // don't listen for events any more this->Interactor->RemoveObserver(this->EventCallbackCommand); this->InvokeEvent(vtkCommand::DisableEvent,NULL); } } void vtkInteractorEventRecorder::Record() { if ( this->State == vtkInteractorEventRecorder::Start ) { if ( ! this->OutputStream ) //need to open file { this->OutputStream = new ofstream(this->FileName, ios::out); if (this->OutputStream->fail()) { vtkErrorMacro(<< "Unable to open file: "<< this->FileName); delete this->OutputStream; return; } *this->OutputStream << "# StreamVersion " << vtkInteractorEventRecorder::StreamVersion << "\n"; } vtkDebugMacro(<<"Recording"); this->State = vtkInteractorEventRecorder::Recording; } } void vtkInteractorEventRecorder::Play() { if ( this->State == vtkInteractorEventRecorder::Start ) { if ( this->ReadFromInputString ) { vtkDebugMacro(<< "Reading from InputString"); int len; if ( this->InputString == NULL || (len = strlen(this->InputString) <= 0) ) { vtkErrorMacro(<< "No input string specified"); return; } this->InputStream = new istrstream(this->InputString, len); if (this->InputStream->fail()) { vtkErrorMacro(<< "Unable to read from string"); delete this->InputStream; return; } } else { if ( ! this->InputStream ) //need to open file { this->InputStream = new ifstream(this->FileName, ios::in); if (this->InputStream->fail()) { vtkErrorMacro(<< "Unable to open file: "<< this->FileName); delete this->InputStream; return; } } } vtkDebugMacro(<<"Playing"); this->State = vtkInteractorEventRecorder::Playing; // Read events and invoke them on the object in question char event[128], keySym[64], buffer[512]; int pos[2], ctrlKey, shiftKey, keyCode, repeatCount; float stream_version = 0.0, tempf; while ( ! this->InputStream->eof() ) { this->InputStream->width(256); *this->InputStream >> event; // Quick skip comment if (*event == '#') { this->InputStream->getline(buffer, 512); // Parse the StreamVersion (not using >> since comment could be empty) // Expecting: # StreamVersion x.y if (strlen(buffer) > 15 && !strncmp(buffer, " StreamVersion ", 15)) { int res = sscanf(buffer + 15, "%f", &tempf); if (res && res != EOF) { stream_version = tempf; } } } else { unsigned long ievent = vtkCommand::GetEventIdFromString(event); if (ievent == vtkCommand::NoEvent) { this->InputStream->ignore(512, '\n'); } else { if (stream_version >= 1.1) { // We could grab the time info here } *this->InputStream >> pos[0]; *this->InputStream >> pos[1]; *this->InputStream >> ctrlKey; *this->InputStream >> shiftKey; *this->InputStream >> keyCode; *this->InputStream >> repeatCount; *this->InputStream >> keySym; this->Interactor->SetEventPosition(pos); this->Interactor->SetControlKey(ctrlKey); this->Interactor->SetShiftKey(shiftKey); this->Interactor->SetKeyCode(keyCode); this->Interactor->SetRepeatCount(repeatCount); this->Interactor->SetKeySym(keySym); this->Interactor->InvokeEvent(ievent, NULL); } } } } this->State = vtkInteractorEventRecorder::Start; } void vtkInteractorEventRecorder::Stop() { this->State = vtkInteractorEventRecorder::Start; this->Modified(); } void vtkInteractorEventRecorder::Rewind() { if ( ! this->InputStream ) //need to already have an open file { vtkGenericWarningMacro(<<"No input file opened to rewind..."); } this->InputStream->clear(); this->InputStream->seekg(0); } // This adds the keypress event observer and the delete event observer void vtkInteractorEventRecorder::SetInteractor(vtkRenderWindowInteractor* i) { if (i == this->Interactor) { return; } // if we already have an Interactor then stop observing it if (this->Interactor) { this->SetEnabled(0); //disable the old interactor this->Interactor->RemoveObserver(this->KeyPressCallbackCommand); } this->Interactor = i; // add observers for each of the events handled in ProcessEvents if (i) { i->AddObserver(vtkCommand::CharEvent, this->KeyPressCallbackCommand, this->Priority); i->AddObserver(vtkCommand::DeleteEvent, this->KeyPressCallbackCommand, this->Priority); } this->Modified(); } void vtkInteractorEventRecorder::ProcessCharEvent(vtkObject* object, unsigned long event, void* clientData, void* vtkNotUsed(callData)) { vtkInteractorEventRecorder* self = reinterpret_cast( clientData ); vtkRenderWindowInteractor* rwi = static_cast( object ); switch(event) { case vtkCommand::DeleteEvent: // if the interactor is being deleted then remove the event handlers self->SetInteractor(0); break; case vtkCommand::CharEvent: if ( self->KeyPressActivation ) { if (rwi->GetKeyCode() == self->KeyPressActivationValue ) { if ( !self->Enabled ) { self->On(); } else { self->Off(); } }//event not aborted }//if activation enabled } } void vtkInteractorEventRecorder::ProcessEvents(vtkObject* object, unsigned long event, void* clientData, void* vtkNotUsed(callData)) { vtkInteractorEventRecorder* self = reinterpret_cast( clientData ); vtkRenderWindowInteractor* rwi = static_cast( object ); // all events are processed if ( self->State == vtkInteractorEventRecorder::Recording ) { switch(event) { case vtkCommand::ModifiedEvent: //dont want these break; default: self->WriteEvent(vtkCommand::GetStringFromEventId(event), rwi->GetEventPosition(), rwi->GetControlKey(), rwi->GetShiftKey(), rwi->GetKeyCode(), rwi->GetRepeatCount(), rwi->GetKeySym()); } self->OutputStream->flush(); } } void vtkInteractorEventRecorder::WriteEvent(const char* event, int pos[2], int ctrlKey, int shiftKey, int keyCode, int repeatCount, char* keySym) { *this->OutputStream << event << " " << pos[0] << " " << pos[1] << " " << ctrlKey << " " << shiftKey << " " << keyCode << " " << repeatCount << " " << keySym << "\n"; } void vtkInteractorEventRecorder::ReadEvent() { } void vtkInteractorEventRecorder::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); if (this->FileName) { os << indent << "File Name: " << this->FileName << "\n"; } os << indent << "ReadFromInputString: " << (this->ReadFromInputString ? "On\n" : "Off\n"); if ( this->InputString ) { os << indent << "Input String: " << this->InputString << "\n"; } else { os << indent << "Input String: (None)\n"; } }