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