| 724 | } |
| 725 | |
| 726 | void MainScreen::startScriptPicker(void) |
| 727 | { |
| 728 | if (TitleCatalog::get().progress().active || TransferJob::get().active() || ScriptRunner::get().active()) { |
| 729 | return; |
| 730 | } |
| 731 | |
| 732 | const bool hasTitle = selected.valid; |
| 733 | const u64 titleId = selected.id; |
| 734 | // Bundled (romfs) scripts first, then SD: an SD file of the same name wins. |
| 735 | std::vector<ScriptCatalog::Root> universalRoots = { |
| 736 | {Paths::bundledUniversalScriptsDir(), ScriptCatalog::Source::Bundled}, |
| 737 | {Paths::universalScriptsDir(), ScriptCatalog::Source::Sd}, |
| 738 | }; |
| 739 | std::vector<ScriptCatalog::Root> specificRoots; |
| 740 | if (hasTitle) { |
| 741 | specificRoots = { |
| 742 | {Paths::bundledScriptsDirFor(titleId), ScriptCatalog::Source::Bundled}, |
| 743 | {Paths::scriptsDirFor(titleId), ScriptCatalog::Source::Sd}, |
| 744 | }; |
| 745 | } |
| 746 | auto entries = ScriptCatalog::scan(universalRoots, specificRoots); |
| 747 | currentOverlay = std::make_shared<ScriptPickerOverlay>( |
| 748 | *this, std::move(entries), hasTitle ? selected.name : "", [this, hasTitle, titleId](const ScriptCatalog::Entry& entry) { |
| 749 | currentOverlay = std::make_shared<YesNoOverlay>( |
| 750 | *this, i18n::t("scripts.confirm_run", {entry.name}), |
| 751 | [this, entry, hasTitle, titleId]() { |
| 752 | this->removeOverlay(); |
| 753 | std::string idHex = hasTitle ? StringUtils::format("%016llX", titleId) : ""; |
| 754 | // HOME stays blocked for the whole run (PKSM precedent): picoc |
| 755 | // cannot be preempted, so a buggy script requires a reboot. |
| 756 | aptSetHomeAllowed(false); |
| 757 | if (ScriptRunner::get().start(entry.path, entry.name, std::move(idHex))) { |
| 758 | // The run owns both screens from here: ScriptScreen holds |
| 759 | // this one alive and hands control back when it is closed. |
| 760 | g_pendingScreen = std::make_shared<ScriptScreen>(g_screen, entry.name); |
| 761 | } |
| 762 | else { |
| 763 | aptSetHomeAllowed(true); |
| 764 | currentOverlay = std::make_shared<ErrorOverlay>(*this, -1, i18n::t("scripts.start_failed")); |
| 765 | } |
| 766 | }, |
| 767 | [this]() { this->removeOverlay(); }); |
| 768 | }); |
| 769 | } |
| 770 | |
| 771 | void MainScreen::handleEvents(const InputState& input) |
| 772 | { |