| 676 | } |
| 677 | |
| 678 | void MainScreen::startScriptPicker(void) |
| 679 | { |
| 680 | if (TitleCatalog::get().progress().active || TransferJob::get().active() || ScriptRunner::get().active()) { |
| 681 | return; |
| 682 | } |
| 683 | |
| 684 | const bool hasTitle = selected.valid; |
| 685 | const u64 titleId = selected.id; |
| 686 | // Bundled (romfs) scripts first, then SD: an SD file of the same name wins. |
| 687 | std::vector<ScriptCatalog::Root> universalRoots = { |
| 688 | {Paths::bundledUniversalScriptsDir(), ScriptCatalog::Source::Bundled}, |
| 689 | {Paths::universalScriptsDir(), ScriptCatalog::Source::Sd}, |
| 690 | }; |
| 691 | std::vector<ScriptCatalog::Root> specificRoots; |
| 692 | if (hasTitle) { |
| 693 | specificRoots = { |
| 694 | {Paths::bundledScriptsDirFor(titleId), ScriptCatalog::Source::Bundled}, |
| 695 | {Paths::scriptsDirFor(titleId), ScriptCatalog::Source::Sd}, |
| 696 | }; |
| 697 | } |
| 698 | auto entries = ScriptCatalog::scan(universalRoots, specificRoots); |
| 699 | currentOverlay = std::make_shared<ScriptPickerOverlay>( |
| 700 | *this, std::move(entries), hasTitle ? selected.name : "", [this, hasTitle, titleId](const ScriptCatalog::Entry& entry) { |
| 701 | currentOverlay = std::make_shared<YesNoOverlay>( |
| 702 | *this, i18n::t("scripts.confirm_run", {entry.name}), |
| 703 | [this, entry, hasTitle, titleId]() { |
| 704 | this->removeOverlay(); |
| 705 | std::string idHex = hasTitle ? StringUtils::format("%016llX", titleId) : ""; |
| 706 | // HOME stays blocked for the whole run (PKSM precedent): picoc |
| 707 | // cannot be preempted, so a buggy script requires a reboot. |
| 708 | aptSetHomeAllowed(false); |
| 709 | if (ScriptRunner::get().start(entry.path, entry.name, std::move(idHex))) { |
| 710 | // The run owns both screens from here: ScriptScreen holds |
| 711 | // this one alive and hands control back when it is closed. |
| 712 | g_pendingScreen = std::make_shared<ScriptScreen>(g_screen, entry.name); |
| 713 | } |
| 714 | else { |
| 715 | aptSetHomeAllowed(true); |
| 716 | currentOverlay = std::make_shared<ErrorOverlay>(*this, -1, i18n::t("scripts.start_failed")); |
| 717 | } |
| 718 | }, |
| 719 | [this]() { this->removeOverlay(); }); |
| 720 | }); |
| 721 | } |
| 722 | |
| 723 | void MainScreen::handleEvents(const InputState& input) |
| 724 | { |