24 using std::ostringstream;
27 using std::unique_ptr;
37 const string&
getId()
const;
38 virtual string getType()
const = 0;
62 virtual void schedulerDeleted();
104 virtual string getType()
const;
116 virtual string getType()
const;
120 virtual bool alarm();
129 :
Command(commandController,
"after")
131 , eventDistributor(eventDistributor_)
203 if (tokens.size() < 2) {
208 if (subCmd ==
"time") {
209 afterTime(tokens, result);
210 }
else if (subCmd ==
"realtime") {
211 afterRealTime(tokens, result);
212 }
else if (subCmd ==
"idle") {
213 afterIdle(tokens, result);
214 }
else if (subCmd ==
"frame") {
215 afterEvent<OPENMSX_FINISH_FRAME_EVENT>(tokens, result);
216 }
else if (subCmd ==
"break") {
217 afterEvent<OPENMSX_BREAK_EVENT>(tokens, result);
218 }
else if (subCmd ==
"quit") {
219 afterEvent<OPENMSX_QUIT_EVENT>(tokens, result);
220 }
else if (subCmd ==
"boot") {
221 afterEvent<OPENMSX_BOOT_EVENT>(tokens, result);
222 }
else if (subCmd ==
"machine_switch") {
223 afterEvent<OPENMSX_MACHINE_LOADED_EVENT>(tokens, result);
224 }
else if (subCmd ==
"info") {
225 afterInfo(tokens, result);
226 }
else if (subCmd ==
"cancel") {
227 afterCancel(tokens, result);
229 afterTclTime(time, tokens, result);
242 static double getTime(
const TclObject& obj)
251 void AfterCommand::afterTime(
const vector<TclObject>& tokens, TclObject& result)
253 if (tokens.size() != 4) {
257 if (!motherBoard)
return;
258 double time = getTime(tokens[2]);
259 auto cmd = make_unique<AfterTimeCmd>(
260 motherBoard->getScheduler(), *
this, tokens[3], time);
261 result.setString(cmd->getId());
262 afterCmds.push_back(move(cmd));
265 void AfterCommand::afterRealTime(
const vector<TclObject>& tokens, TclObject& result)
267 if (tokens.size() != 4) {
270 double time = getTime(tokens[2]);
271 auto cmd = make_unique<AfterRealTimeCmd>(
272 *
this, tokens[3], time);
273 result.setString(cmd->getId());
274 afterCmds.push_back(move(cmd));
277 void AfterCommand::afterTclTime(
278 int ms,
const vector<TclObject>& tokens, TclObject& result)
280 TclObject command(tokens.front().getInterpreter());
281 command.addListElements(tokens.begin() + 2, tokens.end());
282 auto cmd = make_unique<AfterRealTimeCmd>(
283 *
this, command, ms / 1000.0);
284 result.setString(cmd->getId());
285 afterCmds.push_back(move(cmd));
288 template<EventType T>
289 void AfterCommand::afterEvent(
const vector<TclObject>& tokens, TclObject& result)
291 if (tokens.size() != 3) {
294 auto cmd = make_unique<AfterEventCmd<T>>(
295 *
this, tokens[1], tokens[2]);
296 result.setString(cmd->getId());
297 afterCmds.push_back(move(cmd));
300 void AfterCommand::afterInputEvent(
301 const EventPtr& event,
const vector<TclObject>& tokens, TclObject& result)
303 if (tokens.size() != 3) {
306 auto cmd = make_unique<AfterInputEventCmd>(
307 *
this, event, tokens[2]);
308 result.setString(cmd->getId());
309 afterCmds.push_back(move(cmd));
312 void AfterCommand::afterIdle(
const vector<TclObject>& tokens, TclObject& result)
314 if (tokens.size() != 4) {
318 if (!motherBoard)
return;
319 double time = getTime(tokens[2]);
320 auto cmd = make_unique<AfterIdleCmd>(
321 motherBoard->getScheduler(), *
this, tokens[3], time);
322 result.setString(cmd->getId());
323 afterCmds.push_back(move(cmd));
326 void AfterCommand::afterInfo(
const vector<TclObject>& , TclObject& result)
329 for (
auto& cmd : afterCmds) {
330 str << cmd->getId() <<
": ";
331 str << cmd->getType() <<
' ';
332 if (
auto cmd2 = dynamic_cast<const AfterTimedCmd*>(cmd.get())) {
334 str << std::fixed << std::showpoint << cmd2->getTime() <<
' ';
336 str << cmd->getCommand()
339 result.setString(str.str());
342 void AfterCommand::afterCancel(
const vector<TclObject>& tokens, TclObject& )
344 if (tokens.size() != 3) {
347 if (tokens.size() == 3) {
348 for (
auto it = afterCmds.begin(); it != afterCmds.end(); ++it) {
349 if ((*it)->getId() == tokens[2].getString()) {
356 command.addListElements(tokens.begin() + 2, tokens.end());
358 for (
auto it = afterCmds.begin(); it != afterCmds.end(); ++it) {
359 if ((*it)->getCommand() == cmdStr) {
373 return "after time <seconds> <command> execute a command after some time (MSX time)\n"
374 "after realtime <seconds> <command> execute a command after some time (realtime)\n"
375 "after idle <seconds> <command> execute a command after some time being idle\n"
376 "after frame <command> execute a command after a new frame is drawn\n"
377 "after break <command> execute a command after a breakpoint is reached\n"
378 "after boot <command> execute a command after a (re)boot\n"
379 "after machine_switch <command> execute a command after a switch to a new machine\n"
380 "after info list all postponed commands\n"
381 "after cancel <id> cancel the postponed command with given id\n";
386 if (tokens.size() == 2) {
387 static const char*
const cmds[] = {
388 "time",
"realtime",
"idle",
"frame",
"break",
"boot",
389 "machine_switch",
"info",
"cancel",
396 template<
typename PRED>
void AfterCommand::executeMatches(PRED pred)
399 auto it =
partition(afterCmds.begin(), afterCmds.end(), pred);
400 AfterCmds tmp(std::make_move_iterator(it),
401 std::make_move_iterator(afterCmds.end()));
402 afterCmds.erase(it, afterCmds.end());
403 for (
auto& c : tmp) {
413 template<EventType T>
void AfterCommand::executeEvents()
415 executeMatches(AfterEventPred<T>());
420 if (
auto* cmd = dynamic_cast<AfterRealTimeCmd*>(x.get())) {
421 if (cmd->hasExpired()) {
431 if (
auto* cmd = dynamic_cast<AfterTimedCmd*>(x.get())) {
432 if (cmd->getTime() == 0.0) {
444 if (
auto* cmd = dynamic_cast<AfterInputEventCmd*>(x.get())) {
445 if (cmd->getEvent()->matches(*event))
return false;
452 int AfterCommand::signalEvent(
const std::shared_ptr<const Event>& event)
455 executeEvents<OPENMSX_FINISH_FRAME_EVENT>();
457 executeEvents<OPENMSX_BREAK_EVENT>();
459 executeEvents<OPENMSX_BOOT_EVENT>();
461 executeEvents<OPENMSX_QUIT_EVENT>();
463 executeEvents<OPENMSX_MACHINE_LOADED_EVENT>();
465 executeMatches(AfterTimePred());
467 executeMatches(AfterEmuTimePred());
469 executeMatches(AfterInputEventPred(event));
470 for (
auto& c : afterCmds) {
471 if (
auto* cmd = dynamic_cast<AfterIdleCmd*>(c.get())) {
485 : afterCommand(afterCommand_), command(command_)
498 return command.getString();
509 command.executeCommand();
512 "Error executing delayed command: " + e.
getMessage());
520 if (it->get() ==
this) {
521 auto result = move(*it);
563 void AfterTimedCmd::schedulerDeleted()
603 template<EventType T>
607 :
AfterCmd(afterCommand, command), type(type_.getString().str())
611 template<EventType T>
631 return event->toString();
655 bool AfterRealTimeCmd::alarm()