55using std::make_unique;
57using std::string_view;
70 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
80 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
91 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
101 void execute(std::span<const TclObject> tokens,
TclObject& result)
override;
102 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
111 void execute(std::span<const TclObject> tokens,
TclObject& result)
override;
112 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
122 void execute(std::span<const TclObject> tokens,
TclObject& result)
override;
123 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
132 void execute(std::span<const TclObject> tokens,
TclObject& result)
override;
133 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
143 void execute(std::span<const TclObject> tokens,
TclObject& result)
override;
144 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
154 void execute(std::span<const TclObject> tokens,
TclObject& result)
override;
155 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
165 void execute(std::span<const TclObject> tokens,
TclObject& result)
override;
166 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
175 void execute(std::span<const TclObject> tokens,
TclObject& result)
override;
176 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
185 void execute(std::span<const TclObject> tokens,
187 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
190 const string configName;
197 void execute(std::span<const TclObject> tokens,
199 [[nodiscard]]
string help(std::span<const TclObject> tokens)
const override;
201 const uint64_t reference;
208 void execute(std::span<const TclObject> tokens,
210 [[nodiscard]] std::string
help(std::span<const TclObject> tokens)
const override;
220 rtScheduler = make_unique<RTScheduler>();
221 eventDistributor = make_unique<EventDistributor>(*
this);
222 globalCliComm = make_unique<GlobalCliComm>();
223 globalCommandController = make_unique<GlobalCommandController>(
224 *eventDistributor, *globalCliComm, *
this);
225 globalSettings = make_unique<GlobalSettings>(
226 *globalCommandController);
227 inputEventGenerator = make_unique<InputEventGenerator>(
228 *globalCommandController, *eventDistributor, *globalSettings);
229 symbolManager = make_unique<SymbolManager>(
230 *globalCommandController);
231 imGuiManager = make_unique<ImGuiManager>(*
this);
232 diskFactory = make_unique<DiskFactory>(
234 diskManipulator = make_unique<DiskManipulator>(
235 *globalCommandController, *
this);
236 virtualDrive = make_unique<DiskChanger>(
237 *
this,
"virtual_drive");
238 filePool = make_unique<FilePool>(*globalCommandController, *
this);
239 userSettings = make_unique<UserSettings>(
240 *globalCommandController);
241 afterCommand = make_unique<AfterCommand>(
242 *
this, *eventDistributor, *globalCommandController);
243 exitCommand = make_unique<ExitCommand>(
244 *globalCommandController, *eventDistributor);
245 messageCommand = make_unique<MessageCommand>(
246 *globalCommandController);
247 machineCommand = make_unique<MachineCommand>(
248 *globalCommandController, *
this);
249 testMachineCommand = make_unique<TestMachineCommand>(
250 *globalCommandController, *
this);
251 createMachineCommand = make_unique<CreateMachineCommand>(
252 *globalCommandController, *
this);
253 deleteMachineCommand = make_unique<DeleteMachineCommand>(
254 *globalCommandController, *
this);
255 listMachinesCommand = make_unique<ListMachinesCommand>(
256 *globalCommandController, *
this);
257 activateMachineCommand = make_unique<ActivateMachineCommand>(
258 *globalCommandController, *
this);
259 storeMachineCommand = make_unique<StoreMachineCommand>(
260 *globalCommandController, *
this);
261 restoreMachineCommand = make_unique<RestoreMachineCommand>(
262 *globalCommandController, *
this);
263 getClipboardCommand = make_unique<GetClipboardCommand>(
264 *globalCommandController, *
this);
265 setClipboardCommand = make_unique<SetClipboardCommand>(
266 *globalCommandController, *
this);
267 aviRecordCommand = make_unique<AviRecorder>(*
this);
268 extensionInfo = make_unique<ConfigInfo>(
270 machineInfo = make_unique<ConfigInfo>(
272 realTimeInfo = make_unique<RealTimeInfo>(
274 softwareInfoTopic = make_unique<SoftwareInfoTopic>(
276 tclCallbackMessages = make_unique<TclCallbackMessages>(
277 *globalCliComm, *globalCommandController);
279 createMachineSetting();
293 deleteBoard(activeBoard);
306 mixer = make_unique<Mixer>(*
this, *globalCommandController);
313 if (!softwareDatabase) {
314 softwareDatabase = make_unique<RomDatabase>(*globalCliComm);
316 return *softwareDatabase;
321 return *globalCliComm;
331 return *globalCommandController;
336 return globalCommandController->getOpenMSXInfoCommand();
341 return globalCommandController->getHotKey();
346 vector<string> result;
348 auto fileAction = [&](
const std::string& , std::string_view name) {
349 if (name.ends_with(
".xml")) {
350 name.remove_suffix(4);
351 result.emplace_back(name);
354 auto dirAction = [&](std::string& path, std::string_view name) {
355 auto size = path.size();
356 path +=
"/hardwareconfig.xml";
358 result.emplace_back(name);
377 if (
MSXPPI* ppi =
dynamic_cast<MSXPPI*
>(board->findDevice(
"ppi"))) {
378 return ppi->getKeyboard().getMsxChar2Unicode();
384 return defaultMsxChars;
388void Reactor::createMachineSetting()
392 machines.reserve(names.size() + 1);
396 machines.emplace_back(
"C-BIOS_MSX2+", 0);
398 machineSetting = make_unique<EnumSetting<int>>(
399 *globalCommandController,
"default_machine",
400 "default machine (takes effect next time openMSX is started)",
401 0, std::move(machines));
407 return activeBoard.get();
412 return activeBoard ? activeBoard->getMachineID() : string_view{};
418 it != boards.end()) {
426 return std::make_shared<MSXMotherBoard>(*
this);
434 boards.push_back(newBoard);
438 [](
auto& b) {
return b.get(); });
441 if (*it == activeBoard) {
442 switchBoard(newBoard);
452 display = make_unique<Display>(*
this);
456 display->createVideoSystem();
467 newBoard->loadMachine(machine);
468 boards.push_back(newBoard);
470 auto oldBoard = activeBoard;
471 switchBoard(newBoard);
472 deleteBoard(oldBoard);
475void Reactor::switchBoard(Board newBoard)
478 assert(!newBoard ||
contains(boards, newBoard));
479 assert(!activeBoard ||
contains(boards, activeBoard));
481 activeBoard->activate(
false);
487 std::lock_guard<std::mutex> lock(mbMutex);
488 activeBoard = newBoard;
490 eventDistributor->distributeEvent(MachineLoadedEvent());
493 activeBoard->activate(
true);
497void Reactor::deleteBoard(Board board)
507 if (board == activeBoard) {
509 switchBoard(
nullptr);
521 activeBoard->exitCPULoopSync();
524 std::lock_guard<std::mutex> lock(mbMutex);
526 activeBoard->exitCPULoopAsync();
533 auto& commandController = *globalCommandController;
537 commandController.source(
554 commandController.executeCommand(cmd);
556 throw FatalError(
"Couldn't execute command: ", cmd,
557 '\n',
e.getMessage());
569 tclCallbackMessages->redoPostponedCallbacks();
580 activeBoard->powerUp();
584 while (doOneIteration()) {
589bool Reactor::doOneIteration()
591 eventDistributor->deliverEvents();
592 bool blocked = (blockedCounter > 0) || !activeBoard;
596 auto copy = activeBoard;
597 blocked = !
copy->execute();
606 eventDistributor->sleep(20 * 1000);
611void Reactor::unpause()
639 assert(blockedCounter >= 0);
647 auto& pauseSetting = getGlobalSettings().getPauseSetting();
648 if (&
setting == &pauseSetting) {
649 if (pauseSetting.getBoolean()) {
658int Reactor::signalEvent(
const Event& event)
661 [&](
const QuitEvent& ) {
665 [&](
const WindowEvent&
e) {
668 if (
e.isMainWindow()) {
678 if (
e.getSdlWindowEvent().type == SDL_WINDOWEVENT_FOCUS_GAINED) {
680 }
else if (
e.getSdlWindowEvent().type == SDL_WINDOWEVENT_FOCUS_LOST) {
686 [](
const EventBase ) {
698 :
Command(commandController_,
"exit")
699 , distributor(distributor_)
706 switch (tokens.size()) {
719 return "Use this command to stop the emulator.\n"
720 "Optionally you can pass an exit-code.\n";
728 :
Command(commandController_,
"machine")
736 switch (tokens.size()) {
755 return "Switch to a different MSX machine.";
768 :
Command(commandController_,
"test_machine")
781 result =
e.getMessage();
787 return "Test the configuration for the given machine. "
788 "Returns an error message explaining why the configuration is "
789 "invalid or an empty string in case of success.";
802 :
Command(commandController_,
"create_machine")
811 result = newBoard->getMachineID();
812 reactor.boards.push_back(std::move(newBoard));
817 return "Creates a new (empty) MSX machine. Returns the ID for the new "
819 "Use 'load_machine' to actually load a machine configuration "
820 "into this new machine.\n"
821 "The main reason create_machine and load_machine are two "
822 "separate commands is that sometimes you already want to know "
823 "the ID of the machine before load_machine starts emitting "
824 "events for this machine.";
832 :
Command(commandController_,
"delete_machine")
841 reactor.deleteBoard(reactor.
getMachine(tokens[1].getString()));
846 return "Deletes the given MSX machine.";
859 :
Command(commandController_,
"list_machines")
872 return "Returns a list of all machine IDs.";
880 :
Command(commandController_,
"activate_machine")
889 switch (tokens.size()) {
893 reactor.switchBoard(reactor.
getMachine(tokens[1].getString()));
901 return "Make another machine the active msx machine.\n"
902 "Or when invoked without arguments, query the ID of the "
903 "active msx machine.";
916 :
Command(commandController_,
"store_machine")
925 string_view machineID;
926 switch (tokens.size()) {
932 machineID = tokens[1].getString();
936 machineID = tokens[1].getString();
937 filename = tokens[2].getString();
952 "store_machine Save state of current machine to file \"openmsxNNNN.xml.gz\"\n"
953 "store_machine machineID Save state of machine \"machineID\" to file \"openmsxNNNN.xml.gz\"\n"
954 "store_machine machineID <filename> Save state of machine \"machineID\" to indicated file\n"
956 "This is a low-level command, the 'savestate' script is easier to use.";
969 :
Command(commandController_,
"restore_machine")
981 switch (tokens.size()) {
989 time_t modTime = st.st_mtime;
990 if (modTime > lastTime) {
995 if (filename.empty()) {
1019 newBoard->getStateChangeDistributor().stopReplay(newBoard->getCurrentTime());
1021 result = newBoard->getMachineID();
1022 reactor.boards.push_back(std::move(newBoard));
1027 return "restore_machine Load state from last saved state in default directory\n"
1028 "restore_machine <filename> Load state from indicated file\n"
1030 "This is a low-level command, the 'loadstate' script is easier to use.";
1044 :
Command(commandController_,
"get_clipboard_text")
1059 return "Returns the (text) content of the clipboard as a string.";
1067 :
Command(commandController_,
"set_clipboard_text")
1080 return "Send the given string to the clipboard.";
1087 const string& configName_)
1088 :
InfoTopic(openMSXInfoCommand, configName_)
1089 , configName(configName_)
1096 switch (tokens.size()) {
1103 std::array<char, 8192> allocBuffer;
1104 XMLDocument doc{allocBuffer.data(),
sizeof(allocBuffer)};
1106 doc, configName, tokens[2].getString());
1107 if (
const auto* info = doc.getRoot()->findChild(
"info")) {
1108 for (
const auto& c : info->getChildren()) {
1114 "Couldn't get config info: ",
e.getMessage());
1125 return strCat(
"Shows a list of available ", configName,
", "
1126 "or get meta information about the selected item.\n");
1138 :
InfoTopic(openMSXInfoCommand,
"realtime")
1139 , reference(Timer::getTime())
1147 result = narrow_cast<double>(delta) * (1.0 / 1000000.0);
1152 return "Returns the time in seconds since openMSX was started.";
1159 :
InfoTopic(openMSXInfoCommand,
"software")
1165 std::span<const TclObject> tokens,
TclObject& result)
const
1167 if (tokens.size() != 3) {
1171 Sha1Sum sha1sum(tokens[2].getString());
1173 const RomInfo* romInfo = romDatabase.fetchRomInfo(sha1sum);
1177 "Software with sha1sum ", sha1sum.
toString(),
" not found");
1180 const char* bufStart = romDatabase.getBufferStart();
1182 "year", romInfo->
getYear(bufStart),
1194 return "Returns information about the software "
1195 "given its sha1sum, in a paired list.";
void execute(std::span< const TclObject > tokens, TclObject &result) override
Execute this command.
string help(std::span< const TclObject > tokens) const override
Print help for 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 auto & getStartupScripts() const
ParseStatus getParseStatus() const
const auto & getStartupCommands() const
static void completeFileName(std::vector< std::string > &tokens, const FileContext &context, const RANGE &extra)
static void completeString(std::vector< std::string > &tokens, ITER begin, ITER end, bool caseSensitive=true)
void checkNumArgs(std::span< const TclObject > tokens, unsigned exactly, const char *errMessage) const
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this topic.
string help(std::span< const TclObject > tokens) const override
Print help for this topic.
ConfigInfo(InfoCommand &openMSXInfoCommand, const string &configName)
void execute(std::span< const TclObject > tokens, TclObject &result) const override
Show info on this topic.
string help(std::span< const TclObject > tokens) const override
Print help for this command.
void execute(std::span< const TclObject > tokens, TclObject &result) override
Execute this command.
CreateMachineCommand(CommandController &commandController, Reactor &reactor)
void execute(std::span< const TclObject > tokens, TclObject &result) override
Execute this command.
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
DeleteMachineCommand(CommandController &commandController, Reactor &reactor)
string help(std::span< const TclObject > tokens) const override
Print help for this command.
VideoSystem & getVideoSystem()
void distributeEvent(Event &&event)
Schedule the given event for delivery.
string help(std::span< const TclObject > tokens) const override
Print help for this command.
ExitCommand(CommandController &commandController, EventDistributor &distributor)
void execute(std::span< const TclObject > tokens, TclObject &result) override
Execute this command.
void execute(std::span< const TclObject > tokens, TclObject &result) override
Execute this command.
string help(std::span< const TclObject > tokens) const override
Print help for this command.
GetClipboardCommand(CommandController &commandController, Reactor &reactor)
void setAllowExternalCommands()
Interpreter & getInterpreter() override
BooleanSetting & getPauseSetting()
static void loadConfig(XMLDocument &doc, std::string_view type, std::string_view name)
void execute(std::span< const TclObject > tokens, TclObject &result) override
Execute this command.
ListMachinesCommand(CommandController &commandController, Reactor &reactor)
string help(std::span< const TclObject > tokens) const override
Print help for this command.
std::string loadMachine(const std::string &machine)
std::string_view getMachineID() const
MachineCommand(CommandController &commandController, Reactor &reactor)
void execute(std::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(std::span< const TclObject > tokens) const override
Print help for this command.
void mute()
This methods (un)mute the sound.
Contains the main loop of openMSX.
GlobalSettings & getGlobalSettings()
MSXMotherBoard * getMotherBoard() const
std::shared_ptr< MSXMotherBoard > Board
CommandController & getCommandController()
GlobalCommandController & getGlobalCommandController()
InfoCommand & getOpenMSXInfoCommand()
void switchMachine(const std::string &machine)
void run(CommandLineParser &parser)
Main loop.
GlobalCliComm & getGlobalCliComm()
Board createEmptyMotherBoard()
Interpreter & getInterpreter()
const HotKey & getHotKey() const
void replaceBoard(MSXMotherBoard &oldBoard, Board newBoard)
std::string_view getMachineID() const
const MsxChar2Unicode & getMsxChar2Unicode() const
static std::vector< std::string > getHwConfigs(std::string_view type)
RomDatabase & getSoftwareDatabase()
Board getMachine(std::string_view machineID) const
auto getMachineIDs() const
RealTimeInfo(InfoCommand &openMSXInfoCommand)
string help(std::span< const TclObject > tokens) const override
Print help for this topic.
void execute(std::span< const TclObject > tokens, TclObject &result) const override
Show info on this topic.
string help(std::span< const TclObject > tokens) const override
Print help for this command.
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
RestoreMachineCommand(CommandController &commandController, Reactor &reactor)
void execute(std::span< const TclObject > tokens, TclObject &result) override
Execute this command.
std::string_view getYear(const char *buf) const
unsigned getGenMSXid() 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
static std::string_view romTypeToName(RomType type)
std::string_view getCountry(const char *buf) const
RomType getRomType() const
std::string_view getOrigType(const char *buf) const
void execute(std::span< const TclObject > tokens, TclObject &result) override
Execute this command.
SetClipboardCommand(CommandController &commandController, Reactor &reactor)
string help(std::span< const TclObject > 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
std::string help(std::span< const TclObject > tokens) const override
Print help for this topic.
void execute(std::span< const TclObject > tokens, TclObject &result) const override
Show info on this topic.
SoftwareInfoTopic(InfoCommand &openMSXInfoCommand, Reactor &reactor)
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
StoreMachineCommand(CommandController &commandController, Reactor &reactor)
string help(std::span< const TclObject > tokens) const override
Print help for this command.
void execute(std::span< const TclObject > tokens, TclObject &result) override
Execute this command.
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.
TestMachineCommand(CommandController &commandController, Reactor &reactor)
void execute(std::span< const TclObject > tokens, TclObject &result) override
Execute this command.
string help(std::span< const TclObject > 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)
string expandTilde(string path)
Expand the '~' character to the users home directory.
string getNextNumberedFileName(string_view directory, string_view prefix, string_view extension, bool addSeparator)
Gets the next numbered file name with the specified prefix in the specified directory,...
bool isRegularFile(const Stat &st)
const string & getUserOpenMSXDir()
Get the openMSX dir in the user's home 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()
std::variant< KeyUpEvent, KeyDownEvent, MouseMotionEvent, MouseButtonUpEvent, MouseButtonDownEvent, MouseWheelEvent, JoystickAxisMotionEvent, JoystickHatEvent, JoystickButtonUpEvent, JoystickButtonDownEvent, OsdControlReleaseEvent, OsdControlPressEvent, WindowEvent, TextEvent, FileDropEvent, QuitEvent, FinishFrameEvent, CliCommandEvent, GroupEvent, BootEvent, FrameDrawnEvent, BreakEvent, SwitchRendererEvent, TakeReverseSnapshotEvent, AfterTimedEvent, MachineLoadedEvent, MachineActivatedEvent, MachineDeactivatedEvent, MidiInReaderEvent, MidiInWindowsEvent, MidiInCoreMidiEvent, MidiInCoreMidiVirtualEvent, MidiInALSAEvent, Rs232TesterEvent, ImGuiDelayedActionEvent, ImGuiActiveEvent > Event
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)
auto find(InputRange &&range, const T &value)
constexpr void sort(RandomAccessRange &&range)
size_t size(std::string_view utf8)
constexpr auto transform(Range &&range, UnaryOp op)
ITER find_unguarded(ITER first, ITER last, const VAL &val, Proj proj={})
Faster alternative to 'find' when it's guaranteed that the value will be found (if not the behavior i...
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
auto rfind_unguarded(RANGE &range, const VAL &val, Proj proj={})
Similar to the find(_if)_unguarded functions above, but searches from the back to front.
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
std::string strCat(Ts &&...ts)
constexpr auto end(const zstring_view &x)