53 using std::make_shared;
54 using std::make_unique;
56 using std::string_view;
69 [[nodiscard]]
string help(
const vector<string>& tokens)
const override;
79 [[nodiscard]]
string help(
const vector<string>& tokens)
const override;
90 [[nodiscard]]
string help(
const vector<string>& tokens)
const override;
101 [[nodiscard]]
string help(
const vector<string>& tokens)
const override;
111 [[nodiscard]]
string help(
const vector<string>& tokens)
const override;
122 [[nodiscard]]
string help(
const vector<string>& tokens)
const override;
132 [[nodiscard]]
string help(
const vector<string>& tokens)
const override;
143 [[nodiscard]]
string help(
const vector<string>& tokens)
const override;
154 [[nodiscard]]
string help(
const vector<string>& tokens)
const override;
165 [[nodiscard]]
string help(
const vector<string>& tokens)
const override;
175 [[nodiscard]]
string help(
const vector<string>& tokens)
const override;
186 [[nodiscard]]
string help(
const vector<string>& tokens)
const override;
189 const string configName;
198 [[nodiscard]]
string help(
const vector<string>& tokens)
const override;
200 const uint64_t reference;
209 [[nodiscard]] std::string
help(
const std::vector<std::string>& tokens)
const override;
219 rtScheduler = make_unique<RTScheduler>();
220 eventDistributor = make_unique<EventDistributor>(*
this);
221 globalCliComm = make_unique<GlobalCliComm>();
222 globalCommandController = make_unique<GlobalCommandController>(
223 *eventDistributor, *globalCliComm, *
this);
224 globalSettings = make_unique<GlobalSettings>(
225 *globalCommandController);
226 inputEventGenerator = make_unique<InputEventGenerator>(
227 *globalCommandController, *eventDistributor, *globalSettings);
228 diskFactory = make_unique<DiskFactory>(
230 diskManipulator = make_unique<DiskManipulator>(
231 *globalCommandController, *
this);
232 virtualDrive = make_unique<DiskChanger>(
233 *
this,
"virtual_drive");
234 filePool = make_unique<FilePool>(*globalCommandController, *
this);
235 userSettings = make_unique<UserSettings>(
236 *globalCommandController);
237 afterCommand = make_unique<AfterCommand>(
238 *
this, *eventDistributor, *globalCommandController);
239 exitCommand = make_unique<ExitCommand>(
240 *globalCommandController, *eventDistributor);
241 messageCommand = make_unique<MessageCommand>(
242 *globalCommandController);
243 machineCommand = make_unique<MachineCommand>(
244 *globalCommandController, *
this);
245 testMachineCommand = make_unique<TestMachineCommand>(
246 *globalCommandController, *
this);
247 createMachineCommand = make_unique<CreateMachineCommand>(
248 *globalCommandController, *
this);
249 deleteMachineCommand = make_unique<DeleteMachineCommand>(
250 *globalCommandController, *
this);
251 listMachinesCommand = make_unique<ListMachinesCommand>(
252 *globalCommandController, *
this);
253 activateMachineCommand = make_unique<ActivateMachineCommand>(
254 *globalCommandController, *
this);
255 storeMachineCommand = make_unique<StoreMachineCommand>(
256 *globalCommandController, *
this);
257 restoreMachineCommand = make_unique<RestoreMachineCommand>(
258 *globalCommandController, *
this);
259 getClipboardCommand = make_unique<GetClipboardCommand>(
260 *globalCommandController, *
this);
261 setClipboardCommand = make_unique<SetClipboardCommand>(
262 *globalCommandController, *
this);
263 aviRecordCommand = make_unique<AviRecorder>(*
this);
264 extensionInfo = make_unique<ConfigInfo>(
266 machineInfo = make_unique<ConfigInfo>(
268 realTimeInfo = make_unique<RealTimeInfo>(
270 softwareInfoTopic = make_unique<SoftwareInfoTopic>(
272 tclCallbackMessages = make_unique<TclCallbackMessages>(
273 *globalCliComm, *globalCommandController);
275 createMachineSetting();
289 deleteBoard(activeBoard);
302 mixer = make_unique<Mixer>(*
this, *globalCommandController);
309 if (!softwareDatabase) {
310 softwareDatabase = make_unique<RomDatabase>(*globalCliComm);
312 return *softwareDatabase;
317 return *globalCliComm;
327 return *globalCommandController;
332 return globalCommandController->getOpenMSXInfoCommand();
337 vector<string> result;
339 auto fileAction = [&](
const std::string& , std::string_view name) {
341 name.remove_suffix(4);
342 result.emplace_back(name);
345 auto dirAction = [&](std::string& path, std::string_view name) {
346 auto size = path.size();
347 path +=
"/hardwareconfig.xml";
349 result.emplace_back(name);
361 void Reactor::createMachineSetting()
365 machines.reserve(names.size() + 1);
368 [&](
auto& name) {
return std::pair(std::move(name),
count++); }));
369 machines.emplace_back(
"C-BIOS_MSX2+", 0);
371 machineSetting = make_unique<EnumSetting<int>>(
372 *globalCommandController,
"default_machine",
373 "default machine (takes effect next time openMSX is started)",
374 0, std::move(machines));
380 return activeBoard.get();
385 return activeBoard ? activeBoard->getMachineID() : string_view{};
388 vector<string_view> Reactor::getMachineIDs()
const
391 boards, [](
auto& b) {
return b->getMachineID(); }));
396 for (
auto& b : boards) {
397 if (b->getMachineID() == machineID) {
401 throw CommandException(
"No machine with ID: ", machineID);
406 return make_shared<MSXMotherBoard>(*
this);
414 boards.push_back(newBoard);
418 [&](
auto& b) {
return b.get() == &oldBoard_; });
421 if (*it == activeBoard) {
422 switchBoard(newBoard);
432 display = make_unique<Display>(*
this);
436 display->createVideoSystem();
447 newBoard->loadMachine(machine);
448 boards.push_back(newBoard);
450 auto oldBoard = activeBoard;
451 switchBoard(newBoard);
452 deleteBoard(oldBoard);
455 void Reactor::switchBoard(Board newBoard)
458 assert(!newBoard ||
contains(boards, newBoard));
459 assert(!activeBoard ||
contains(boards, activeBoard));
461 activeBoard->activate(
false);
467 std::lock_guard<std::mutex> lock(mbMutex);
468 activeBoard = newBoard;
470 eventDistributor->distributeEvent(
474 activeBoard->activate(
true);
478 void Reactor::deleteBoard(Board board)
488 if (board == activeBoard) {
490 switchBoard(
nullptr);
502 activeBoard->exitCPULoopSync();
505 std::lock_guard<std::mutex> lock(mbMutex);
507 activeBoard->exitCPULoopAsync();
514 auto& commandController = *globalCommandController;
518 commandController.source(
535 commandController.executeCommand(cmd);
537 throw FatalError(
"Couldn't execute command: ", cmd,
555 activeBoard->powerUp();
559 while (doOneIteration()) {
564 bool Reactor::doOneIteration()
566 eventDistributor->deliverEvents();
567 bool blocked = (blockedCounter > 0) || !activeBoard;
571 auto copy = activeBoard;
572 blocked = !
copy->execute();
581 eventDistributor->sleep(20 * 1000);
586 void Reactor::unpause()
595 void Reactor::pause()
614 assert(blockedCounter >= 0);
620 void Reactor::update(
const Setting& setting) noexcept
622 auto& pauseSetting = getGlobalSettings().getPauseSetting();
623 if (&setting == &pauseSetting) {
624 if (pauseSetting.getBoolean()) {
633 int Reactor::signalEvent(
const std::shared_ptr<const Event>& event) noexcept
635 auto type =
event->getType();
650 auto& focusEvent = checked_cast<const FocusEvent&>(*event);
651 if (focusEvent.getGain()) {
668 :
Command(commandController_,
"exit")
669 , distributor(distributor_)
676 switch (tokens.
size()) {
689 return "Use this command to stop the emulator.\n"
690 "Optionally you can pass an exit-code.\n";
698 :
Command(commandController_,
"machine")
706 switch (tokens.
size()) {
725 return "Switch to a different MSX machine.";
738 :
Command(commandController_,
"test_machine")
757 return "Test the configuration for the given machine. "
758 "Returns an error message explaining why the configuration is "
759 "invalid or an empty string in case of success.";
772 :
Command(commandController_,
"create_machine")
781 result = newBoard->getMachineID();
782 reactor.boards.push_back(move(newBoard));
787 return "Creates a new (empty) MSX machine. Returns the ID for the new "
789 "Use 'load_machine' to actually load a machine configuration "
790 "into this new machine.\n"
791 "The main reason create_machine and load_machine are two "
792 "separate commands is that sometimes you already want to know "
793 "the ID of the machine before load_machine starts emitting "
794 "events for this machine.";
802 :
Command(commandController_,
"delete_machine")
811 reactor.deleteBoard(reactor.getMachine(tokens[1].getString()));
816 return "Deletes the given MSX machine.";
829 :
Command(commandController_,
"list_machines")
842 return "Returns a list of all machine IDs.";
850 :
Command(commandController_,
"activate_machine")
859 switch (tokens.
size()) {
863 reactor.switchBoard(reactor.getMachine(tokens[1].getString()));
871 return "Make another machine the active msx machine.\n"
872 "Or when invoked without arguments, query the ID of the "
873 "active msx machine.";
886 :
Command(commandController_,
"store_machine")
895 string_view machineID;
896 switch (tokens.
size()) {
902 machineID = tokens[1].getString();
906 machineID = tokens[1].getString();
911 auto& board = *reactor.getMachine(machineID);
922 "store_machine Save state of current machine to file \"openmsxNNNN.xml.gz\"\n"
923 "store_machine machineID Save state of machine \"machineID\" to file \"openmsxNNNN.xml.gz\"\n"
924 "store_machine machineID <filename> Save state of machine \"machineID\" to indicated file\n"
926 "This is a low-level command, the 'savestate' script is easier to use.";
939 :
Command(commandController_,
"restore_machine")
951 switch (tokens.
size()) {
959 time_t modTime = st.st_mtime;
960 if (modTime > lastTime) {
989 newBoard->getStateChangeDistributor().stopReplay(newBoard->getCurrentTime());
991 result = newBoard->getMachineID();
992 reactor.boards.push_back(move(newBoard));
997 return "restore_machine Load state from last saved state in default directory\n"
998 "restore_machine <filename> Load state from indicated file\n"
1000 "This is a low-level command, the 'loadstate' script is easier to use.";
1014 :
Command(commandController_,
"get_clipboard_text")
1029 return "Returns the (text) content of the clipboard as a string.";
1037 :
Command(commandController_,
"set_clipboard_text")
1050 return "Send the given string to the clipboard.";
1057 const string& configName_)
1058 :
InfoTopic(openMSXInfoCommand, configName_)
1059 , configName(configName_)
1066 switch (tokens.
size()) {
1074 configName, tokens[2].getString());
1075 if (
auto* info = config.findChild(
"info")) {
1076 for (
const auto& i : info->getChildren()) {
1082 "Couldn't get config info: ", e.
getMessage());
1093 return strCat(
"Shows a list of available ", configName,
", "
1094 "or get meta information about the selected item.\n");
1106 :
InfoTopic(openMSXInfoCommand,
"realtime")
1107 , reference(Timer::getTime())
1115 result = delta / 1000000.0;
1120 return "Returns the time in seconds since openMSX was started.";
1127 :
InfoTopic(openMSXInfoCommand,
"software")
1135 if (tokens.
size() != 3) {
1139 Sha1Sum sha1sum(tokens[2].getString());
1141 const RomInfo* romInfo = romDatabase.fetchRomInfo(sha1sum);
1145 "Software with sha1sum ", sha1sum.
toString(),
" not found");
1148 const char* bufStart = romDatabase.getBufferStart();
1150 "year", romInfo->
getYear(bufStart),
1162 return "Returns information about the software "
1163 "given its sha1sum, in a paired list.";
string help(const vector< string > &tokens) const override
Print help for this command.
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
ActivateMachineCommand(CommandController &commandController, Reactor &reactor)
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
Interpreter & getInterpreter() const final
const std::vector< std::string > & getStartupScripts() const
ParseStatus getParseStatus() const
const std::vector< std::string > & getStartupCommands() const
static void completeFileName(std::vector< std::string > &tokens, const FileContext &context, const RANGE &extra)
void checkNumArgs(span< const TclObject > tokens, unsigned exactly, const char *errMessage) const
static void completeString(std::vector< std::string > &tokens, ITER begin, ITER end, bool caseSensitive=true)
string help(const vector< string > &tokens) const override
Print help for this topic.
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this topic.
void execute(span< const TclObject > tokens, TclObject &result) const override
Show info on this topic.
ConfigInfo(InfoCommand &openMSXInfoCommand, const string &configName)
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
CreateMachineCommand(CommandController &commandController, Reactor &reactor)
string help(const vector< string > &tokens) const override
Print help for this command.
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
string help(const vector< string > &tokens) const override
Print help for this command.
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
DeleteMachineCommand(CommandController &commandController, Reactor &reactor)
VideoSystem & getVideoSystem()
std::vector< std::pair< std::string, T > > Map
void distributeEvent(const EventPtr &event)
Schedule the given event for delivery.
ExitCommand(CommandController &commandController, EventDistributor &distributor)
string help(const vector< string > &tokens) const override
Print help for this command.
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
string help(const vector< string > &tokens) const override
Print help for this command.
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
GetClipboardCommand(CommandController &commandController, Reactor &reactor)
void setAllowExternalCommands()
Interpreter & getInterpreter() override
BooleanSetting & getPauseSetting()
static XMLElement loadConfig(std::string_view type, std::string_view name)
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
ListMachinesCommand(CommandController &commandController, Reactor &reactor)
string help(const vector< string > &tokens) const override
Print help for this command.
const std::string & getMessage() const &
std::string loadMachine(const std::string &machine)
string help(const vector< string > &tokens) const override
Print help for this command.
MachineCommand(CommandController &commandController, Reactor &reactor)
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
void mute()
This methods (un)mute the sound.
Contains the main loop of openMSX.
MSXMotherBoard * getMotherBoard() const
std::shared_ptr< MSXMotherBoard > Board
CommandController & getCommandController()
InfoCommand & getOpenMSXInfoCommand()
void switchMachine(const std::string &machine)
GlobalSettings & getGlobalSettings()
GlobalCliComm & getGlobalCliComm()
void run(CommandLineParser &parser)
Main loop.
Board createEmptyMotherBoard()
Interpreter & getInterpreter()
GlobalCommandController & getGlobalCommandController()
void replaceBoard(MSXMotherBoard &oldBoard, Board newBoard)
std::string_view getMachineID() const
static std::vector< std::string > getHwConfigs(std::string_view type)
RomDatabase & getSoftwareDatabase()
void execute(span< const TclObject > tokens, TclObject &result) const override
Show info on this topic.
string help(const vector< string > &tokens) const override
Print help for this topic.
RealTimeInfo(InfoCommand &openMSXInfoCommand)
string help(const vector< string > &tokens) const override
Print help for this command.
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
RestoreMachineCommand(CommandController &commandController, Reactor &reactor)
std::string_view getYear(const char *buf) const
std::string_view getTitle(const char *buf) const
std::string_view getCompany(const char *buf) const
std::string_view getRemark(const char *buf) const
std::string_view getCountry(const char *buf) const
RomType getRomType() const
static std::string_view romTypeToName(RomType type)
std::string_view getOrigType(const char *buf) const
SetClipboardCommand(CommandController &commandController, Reactor &reactor)
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
string help(const vector< string > &tokens) const override
Print help for this command.
This class represents the result of a sha1 calculation (a 160-bit value).
std::string toString() const
void execute(span< const TclObject > tokens, TclObject &result) const override
Show info on this topic.
SoftwareInfoTopic(InfoCommand &openMSXInfoCommand, Reactor &reactor)
std::string help(const std::vector< std::string > &tokens) const override
Print help for this topic.
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
string help(const vector< string > &tokens) const override
Print help for this command.
StoreMachineCommand(CommandController &commandController, Reactor &reactor)
void detach(Observer< T > &observer)
void attach(Observer< T > &observer)
void addListElements(ITER first, ITER last)
void addDictKeyValue(const Key &key, const Value &value)
void addDictKeyValues(Args &&... args)
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
TestMachineCommand(CommandController &commandController, Reactor &reactor)
string help(const vector< string > &tokens) const override
Print help for this command.
virtual void setClipboardText(zstring_view text)=0
virtual std::string getClipboardText()=0
ALWAYS_INLINE void serialize(const char *tag, const T &t, Args &&...args)
constexpr index_type size() const noexcept
ALWAYS_INLINE unsigned count(const uint8_t *pIn, const uint8_t *pMatch, const uint8_t *pInLimit)
bool endsWith(string_view total, string_view part)
string expandTilde(string path)
Expand the '~' character to the users home directory.
bool isRegularFile(const Stat &st)
const string & getUserOpenMSXDir()
Get the openMSX dir in the user's home directory.
string getNextNumberedFileName(string_view directory, string_view prefix, string_view extension)
Gets the next numbered file name with the specified prefix in the specified directory,...
string join(string_view part1, string_view part2)
Join two paths.
bool isMainThread()
Returns true when called from the main thread.
uint64_t getTime()
Get current (real) time in us.
This file implemented 3 utility functions:
const FileContext & systemFileContext()
@ OPENMSX_MACHINE_LOADED_EVENT
Send when a (new) machine configuration is loaded.
constexpr const char *const filename
FileContext userFileContext(string_view savePath)
bool foreach_file(std::string path, FileAction fileAction)
const FileContext & preferSystemFileContext()
bool foreach_file_and_directory(std::string path, FileAction fileAction, DirAction dirAction)
auto unique(ForwardRange &&range)
auto copy(InputRange &&range, OutputIter out)
void sort(RandomAccessRange &&range)
size_t size(std::string_view utf8)
constexpr auto transform(Range &&range, UnaryOp op)
constexpr auto rfind_unguarded(RANGE &range, const VAL &val)
Similar to the find(_if)_unguarded functions above, but searches from the back to front.
constexpr ITER find_if_unguarded(ITER first, ITER last, PRED pred)
Faster alternative to 'find_if' when it's guaranteed that the predicate will be true for at least one...
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
auto to_vector(Range &&range) -> std::vector< detail::ToVectorType< T, decltype(std::begin(range))>>
std::string strCat(Ts &&...ts)
constexpr auto end(const zstring_view &x)