Merge pull request #13701 from MarcZX10/feat/psn-unavailable-dialogs

feat(libSceIme): show a notice when PSN-only system dialogs open
This commit is contained in:
Adrià authored and GitHub committed 2026-10-31 21:05:21 +01:00
commit 0836dfdf4f
36 files changed
+575 -15

No files matched your search

+16 -1
View File
@@ -1,4 +1,4 @@
add_library(libSceIme SHARED EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/ModalDialog.cpp)
add_library(libSceIme SHARED EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/ModalDialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/PsnDialogNotice.cpp)
target_include_directories(libSceIme PRIVATE ${LIBS_INCLUDE_DIR})
configure_windows_unwind(libSceIme)
@@ -53,6 +53,21 @@ if(BUILD_TESTING)
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceIme>")
endif()
add_test_executable(psn_dialog_notice_mode_tests ${LIBS_INCLUDE_DIR}/tests/PsnDialogNoticeMode.cpp)
target_include_directories(psn_dialog_notice_mode_tests PRIVATE ${LIBS_INCLUDE_DIR})
configure_host_test_executable(psn_dialog_notice_mode_tests)
add_test(NAME psn_dialog_notice_mode COMMAND psn_dialog_notice_mode_tests)
add_test_executable(psn_dialog_notice_tests ${LIBS_INCLUDE_DIR}/tests/PsnDialogNotice.cpp)
target_include_directories(psn_dialog_notice_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(psn_dialog_notice_tests PRIVATE libSceIme libc)
configure_windows_unwind(psn_dialog_notice_tests)
add_test(NAME psn_dialog_notice COMMAND psn_dialog_notice_tests)
if(WIN32)
set_tests_properties(psn_dialog_notice PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceIme>")
endif()
add_test_executable(guest_ime_open_tests ${LIBS_INCLUDE_DIR}/tests/GuestImeOpen.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../libSceVideoOut/src/ImeTextInput.cpp)
target_include_directories(guest_ime_open_tests PRIVATE ${LIBS_INCLUDE_DIR} ${ANYPS5_SDL2_INCLUDE_DIR})
@@ -14,6 +14,7 @@ inline constexpr std::size_t ModalDialogMaxButtons = 3;
inline constexpr std::uint32_t ModalDialogAnyOwner = 0;
inline constexpr std::uint32_t ModalDialogOwnerMsgDialog = 1;
inline constexpr std::uint32_t ModalDialogOwnerErrorDialog = 2;
inline constexpr std::uint32_t ModalDialogOwnerPsnNotice = 3;
struct ModalDialogRequest {
std::uint32_t owner = ModalDialogAnyOwner;
@@ -0,0 +1,42 @@
#ifndef CORE_LIBS_PRX_LIBSCEIME_INCLUDE_PSNDIALOGNOTICE_HPP
#define CORE_LIBS_PRX_LIBSCEIME_INCLUDE_PSNDIALOGNOTICE_HPP
#include <cstdint>
#include <stdexcept>
#include <string>
#include "prx/libSceIme/include/ModalDialog.hpp"
enum class PsnDialogNoticeMode : std::uint8_t { Silent, Show };
enum class PsnDialogNoticeKind : std::uint8_t { PsnFeature, GenericFeature };
inline constexpr std::uint64_t PsnDialogNoticeIntervalMilliseconds = 2000;
inline PsnDialogNoticeMode ParsePsnDialogNoticeMode(const char* text) {
if (text == nullptr || *text == '\0') return PsnDialogNoticeMode::Silent;
const std::string value(text);
if (value == "silent") return PsnDialogNoticeMode::Silent;
if (value == "show") return PsnDialogNoticeMode::Show;
throw std::runtime_error("ANYPS5_PSN_DIALOGS must be show or silent, not '" + value + "'");
}
inline ModalDialogRequest PsnDialogNoticeRequest(PsnDialogNoticeKind kind) {
ModalDialogRequest request;
request.owner = ModalDialogOwnerPsnNotice;
if (kind == PsnDialogNoticeKind::PsnFeature) {
request.message = u"This feature needs PlayStation Network, which AnyPS5 does not provide, so it is not available.";
} else {
request.message = u"This system feature is not available in AnyPS5.";
}
request.buttons = {u"OK"};
request.focus = 0;
request.cancel = 0;
return request;
}
extern "C" void PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode mode);
extern "C" bool PsnDialogNoticeOffer_nid_postfix(PsnDialogNoticeKind kind);
extern "C" bool PsnDialogNoticeOfferAt_nid_postfix(PsnDialogNoticeKind kind, std::uint64_t nowMilliseconds);
#endif
@@ -0,0 +1,49 @@
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
#include <chrono>
#include <cstdlib>
#include <mutex>
#include <optional>
namespace {
std::mutex g_mutex;
std::optional<PsnDialogNoticeMode> g_mode;
bool g_shown = false;
std::uint64_t g_lastShown = 0;
PsnDialogNoticeMode Mode() {
if (!g_mode) g_mode = ParsePsnDialogNoticeMode(std::getenv("ANYPS5_PSN_DIALOGS"));
return *g_mode;
}
std::uint64_t NowMilliseconds() {
return static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count());
}
}
extern "C" {
void PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode mode) {
std::lock_guard lock(g_mutex);
g_mode = mode;
g_shown = false;
g_lastShown = 0;
}
bool PsnDialogNoticeOfferAt_nid_postfix(PsnDialogNoticeKind kind, std::uint64_t nowMilliseconds) {
std::lock_guard lock(g_mutex);
if (Mode() != PsnDialogNoticeMode::Show) return false;
if (g_shown && nowMilliseconds >= g_lastShown && nowMilliseconds - g_lastShown < PsnDialogNoticeIntervalMilliseconds) return false;
if (!ModalDialogOpen_nid_postfix(PsnDialogNoticeRequest(kind))) return false;
g_shown = true;
g_lastShown = nowMilliseconds;
return true;
}
bool PsnDialogNoticeOffer_nid_postfix(PsnDialogNoticeKind kind) {
return PsnDialogNoticeOfferAt_nid_postfix(kind, NowMilliseconds());
}
}
@@ -1,4 +1,5 @@
add_library(libSceInvitationDialog SHARED EXCLUDE_FROM_ALL Export.cpp)
target_link_libraries(libSceInvitationDialog PRIVATE libSceIme)
target_include_directories(libSceInvitationDialog PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(libSceInvitationDialog PRIVATE libSceCommonDialog libc)
configure_windows_unwind(libSceInvitationDialog)
@@ -6,11 +7,11 @@ configure_windows_unwind(libSceInvitationDialog)
if(BUILD_TESTING)
add_test_executable(guest_invitation_dialog_tests ${LIBS_INCLUDE_DIR}/tests/GuestInvitationDialog.cpp)
target_include_directories(guest_invitation_dialog_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_invitation_dialog_tests PRIVATE libSceInvitationDialog libSceCommonDialog libc)
target_link_libraries(guest_invitation_dialog_tests PRIVATE libSceInvitationDialog libSceCommonDialog libSceIme libc)
configure_windows_unwind(guest_invitation_dialog_tests)
add_test(NAME guest_invitation_dialog COMMAND guest_invitation_dialog_tests)
if(WIN32)
set_tests_properties(guest_invitation_dialog PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceInvitationDialog>")
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceInvitationDialog>;PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceIme>")
endif()
endif()
@@ -2,6 +2,7 @@
#include "prx/libSceCommonDialog/include/DialogUse.hpp"
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
#include <algorithm>
#include <cstdint>
#include <iterator>
@@ -85,6 +86,7 @@ int APS5_VABI sceInvitationDialogOpen(const InvitationDialogParam* param) {
}
dialog.callbackArg = param->callbackArg;
dialog.status = COMMON_DIALOG_STATUS_FINISHED;
PsnDialogNoticeOffer_nid_postfix(PsnDialogNoticeKind::PsnFeature);
return COMMON_DIALOG_OK;
}
@@ -1,4 +1,5 @@
add_library(libSceNpAuthAuthorizedAppDialog SHARED EXCLUDE_FROM_ALL Export.cpp)
target_link_libraries(libSceNpAuthAuthorizedAppDialog PRIVATE libSceIme)
target_include_directories(libSceNpAuthAuthorizedAppDialog PRIVATE ${LIBS_INCLUDE_DIR})
configure_windows_unwind(libSceNpAuthAuthorizedAppDialog)
@@ -7,10 +8,10 @@ target_link_libraries(libSceNpAuthAuthorizedAppDialog PRIVATE libSceUserService)
if(BUILD_TESTING)
add_test_executable(guest_np_auth_authorized_app_dialog_tests ${LIBS_INCLUDE_DIR}/tests/GuestNpAuthAuthorizedAppDialog.cpp)
target_include_directories(guest_np_auth_authorized_app_dialog_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_np_auth_authorized_app_dialog_tests PRIVATE libSceNpAuthAuthorizedAppDialog libSceUserService)
target_link_libraries(guest_np_auth_authorized_app_dialog_tests PRIVATE libSceNpAuthAuthorizedAppDialog libSceIme libSceUserService)
add_test(NAME guest_np_auth_authorized_app_dialog COMMAND guest_np_auth_authorized_app_dialog_tests)
if(WIN32)
set_tests_properties(guest_np_auth_authorized_app_dialog PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpAuthAuthorizedAppDialog>")
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpAuthAuthorizedAppDialog>;PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceIme>")
endif()
endif()
@@ -7,6 +7,7 @@
#include "SceTypes.hpp"
#include "prx/libSceCommonDialog/CommonDialog.hpp"
#include "prx/libc/include/General.hpp"
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
namespace {
@@ -46,6 +47,7 @@ int APS5_VABI sceNpAuthAuthorizedAppDialogOpen(const NpAuthAuthorizedAppDialogPa
if (status == COMMON_DIALOG_STATUS_NONE) return COMMON_DIALOG_ERROR_NOT_INITIALIZED;
if (status == COMMON_DIALOG_STATUS_RUNNING) return COMMON_DIALOG_ERROR_BUSY;
g_status = COMMON_DIALOG_STATUS_FINISHED;
PsnDialogNoticeOffer_nid_postfix(PsnDialogNoticeKind::PsnFeature);
return 0;
}
@@ -1,4 +1,5 @@
add_library(libSceNpCommerce SHARED EXCLUDE_FROM_ALL Export.cpp)
target_link_libraries(libSceNpCommerce PRIVATE libSceIme)
target_include_directories(libSceNpCommerce PRIVATE ${LIBS_INCLUDE_DIR})
configure_windows_unwind(libSceNpCommerce)
target_link_libraries(libSceNpCommerce PRIVATE libc libSceUserService)
@@ -6,11 +7,11 @@ target_link_libraries(libSceNpCommerce PRIVATE libc libSceUserService)
if(BUILD_TESTING)
add_test_executable(guest_np_commerce_dialog_tests ${LIBS_INCLUDE_DIR}/tests/GuestNpCommerceDialog.cpp)
target_include_directories(guest_np_commerce_dialog_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_np_commerce_dialog_tests PRIVATE libSceNpCommerce libc libSceUserService)
target_link_libraries(guest_np_commerce_dialog_tests PRIVATE libSceNpCommerce libSceIme libc libSceUserService)
configure_windows_unwind(guest_np_commerce_dialog_tests)
add_test(NAME guest_np_commerce_dialog COMMAND guest_np_commerce_dialog_tests)
if(WIN32)
set_tests_properties(guest_np_commerce_dialog PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpCommerce>")
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpCommerce>;PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceIme>")
endif()
endif()
@@ -8,6 +8,7 @@
#include "SceTypes.hpp"
#include "prx/libSceCommonDialog/CommonDialog.hpp"
#include "prx/libc/include/General.hpp"
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
namespace {
@@ -109,6 +110,7 @@ int APS5_VABI sceNpCommerceDialogOpen(const NpCommerceDialogParam* param) {
if (!validateParam(*param)) return COMMON_DIALOG_ERROR_INVALID_ARGUMENT;
g_userData = param->userData;
g_status = COMMON_DIALOG_STATUS_FINISHED;
PsnDialogNoticeOffer_nid_postfix(PsnDialogNoticeKind::PsnFeature);
return 0;
}
@@ -166,6 +168,7 @@ int APS5_VABI sceNpCommerceDialogOpen2(const NpCommerceDialogParam2* param) {
if (!validateParam2(*param)) return COMMON_DIALOG_ERROR_INVALID_ARGUMENT;
g_userData = param->userData;
g_status = COMMON_DIALOG_STATUS_FINISHED;
PsnDialogNoticeOffer_nid_postfix(PsnDialogNoticeKind::PsnFeature);
return 0;
}
@@ -1,14 +1,15 @@
add_library(libSceNpFriendListDialog SHARED EXCLUDE_FROM_ALL Export.cpp)
target_link_libraries(libSceNpFriendListDialog PRIVATE libSceIme)
target_include_directories(libSceNpFriendListDialog PRIVATE ${LIBS_INCLUDE_DIR})
configure_windows_unwind(libSceNpFriendListDialog)
if(BUILD_TESTING)
add_test_executable(guest_np_friend_list_dialog_tests ${LIBS_INCLUDE_DIR}/tests/GuestNpFriendListDialog.cpp)
target_include_directories(guest_np_friend_list_dialog_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_np_friend_list_dialog_tests PRIVATE libSceNpFriendListDialog)
target_link_libraries(guest_np_friend_list_dialog_tests PRIVATE libSceNpFriendListDialog libSceIme)
add_test(NAME guest_np_friend_list_dialog COMMAND guest_np_friend_list_dialog_tests)
if(WIN32)
set_tests_properties(guest_np_friend_list_dialog PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpFriendListDialog>")
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpFriendListDialog>;PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceIme>")
endif()
endif()
@@ -5,6 +5,7 @@
#include <cstring>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
namespace {
@@ -37,6 +38,7 @@ int APS5_VABI sceNpFriendListDialogOpenA(const void* param) {
if (status == COMMON_DIALOG_STATUS_RUNNING) return COMMON_DIALOG_ERROR_BUSY;
if (param == nullptr) return COMMON_DIALOG_ERROR_ARG_NULL;
g_status = COMMON_DIALOG_STATUS_FINISHED;
PsnDialogNoticeOffer_nid_postfix(PsnDialogNoticeKind::PsnFeature);
return 0;
}
@@ -1,4 +1,5 @@
add_library(libSceNpProfileDialog SHARED EXCLUDE_FROM_ALL Export.cpp)
target_link_libraries(libSceNpProfileDialog PRIVATE libSceIme)
target_include_directories(libSceNpProfileDialog PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(libSceNpProfileDialog PRIVATE libc)
configure_windows_unwind(libSceNpProfileDialog)
@@ -6,11 +7,11 @@ configure_windows_unwind(libSceNpProfileDialog)
if(BUILD_TESTING)
add_test_executable(guest_np_profile_dialog_tests ${LIBS_INCLUDE_DIR}/tests/GuestNpProfileDialog.cpp)
target_include_directories(guest_np_profile_dialog_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_np_profile_dialog_tests PRIVATE libSceNpProfileDialog libc)
target_link_libraries(guest_np_profile_dialog_tests PRIVATE libSceNpProfileDialog libSceIme libc)
configure_windows_unwind(guest_np_profile_dialog_tests)
add_test(NAME guest_np_profile_dialog COMMAND guest_np_profile_dialog_tests)
if(WIN32)
set_tests_properties(guest_np_profile_dialog PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpProfileDialog>")
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpProfileDialog>;PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceIme>")
endif()
endif()
@@ -7,6 +7,7 @@
#include "SceTypes.hpp"
#include "prx/libSceCommonDialog/CommonDialog.hpp"
#include "prx/libc/include/General.hpp"
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
namespace {
@@ -74,6 +75,7 @@ int OpenDialog(const TParam* param, const char* function) {
}
dialog.userData = param->userData;
dialog.status = COMMON_DIALOG_STATUS_FINISHED;
PsnDialogNoticeOffer_nid_postfix(PsnDialogNoticeKind::PsnFeature);
return COMMON_DIALOG_OK;
}
@@ -1,14 +1,15 @@
add_library(libSceNpSnsFacebookDialog SHARED EXCLUDE_FROM_ALL Export.cpp)
target_link_libraries(libSceNpSnsFacebookDialog PRIVATE libSceIme)
target_include_directories(libSceNpSnsFacebookDialog PRIVATE ${LIBS_INCLUDE_DIR})
configure_windows_unwind(libSceNpSnsFacebookDialog)
if(BUILD_TESTING)
add_test_executable(guest_np_sns_facebook_dialog_tests ${LIBS_INCLUDE_DIR}/tests/GuestNpSnsFacebookDialog.cpp)
target_include_directories(guest_np_sns_facebook_dialog_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_np_sns_facebook_dialog_tests PRIVATE libSceNpSnsFacebookDialog)
target_link_libraries(guest_np_sns_facebook_dialog_tests PRIVATE libSceNpSnsFacebookDialog libSceIme)
add_test(NAME guest_np_sns_facebook_dialog COMMAND guest_np_sns_facebook_dialog_tests)
if(WIN32)
set_tests_properties(guest_np_sns_facebook_dialog PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpSnsFacebookDialog>")
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpSnsFacebookDialog>;PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceIme>")
endif()
endif()
@@ -5,6 +5,7 @@
#include <cstring>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
namespace {
@@ -37,6 +38,7 @@ int APS5_VABI sceNpSnsFacebookDialogOpen(const void* param) {
if (status == COMMON_DIALOG_STATUS_RUNNING) return COMMON_DIALOG_ERROR_BUSY;
if (param == nullptr) return COMMON_DIALOG_ERROR_ARG_NULL;
g_status = COMMON_DIALOG_STATUS_FINISHED;
PsnDialogNoticeOffer_nid_postfix(PsnDialogNoticeKind::PsnFeature);
return 0;
}
@@ -1,15 +1,16 @@
add_library(libSceWebBrowserDialog SHARED EXCLUDE_FROM_ALL Export.cpp)
target_link_libraries(libSceWebBrowserDialog PRIVATE libSceIme)
target_include_directories(libSceWebBrowserDialog PRIVATE ${LIBS_INCLUDE_DIR})
configure_windows_unwind(libSceWebBrowserDialog)
if(BUILD_TESTING)
add_test_executable(guest_web_browser_dialog_tests ${LIBS_INCLUDE_DIR}/tests/GuestWebBrowserDialog.cpp)
target_include_directories(guest_web_browser_dialog_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_web_browser_dialog_tests PRIVATE libSceWebBrowserDialog)
target_link_libraries(guest_web_browser_dialog_tests PRIVATE libSceWebBrowserDialog libSceIme)
add_test(NAME guest_web_browser_dialog COMMAND guest_web_browser_dialog_tests)
if(WIN32)
set_tests_properties(guest_web_browser_dialog PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceWebBrowserDialog>")
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceWebBrowserDialog>;PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceIme>")
endif()
endif()
@@ -8,6 +8,7 @@
#include "SceTypes.hpp"
#include "prx/libSceCommonDialog/CommonDialog.hpp"
#include "prx/libc/include/General.hpp"
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
static_assert(sizeof(WebBrowserDialogCookieParam) == 280);
static_assert(offsetof(WebBrowserDialogCookieParam, address) == 8);
@@ -102,6 +103,7 @@ int APS5_VABI sceWebBrowserDialogOpen(const void* param) {
if (param == nullptr) return COMMON_DIALOG_ERROR_ARG_NULL;
g_status = COMMON_DIALOG_STATUS_FINISHED;
g_open = true;
PsnDialogNoticeOffer_nid_postfix(PsnDialogNoticeKind::GenericFeature);
return 0;
}
@@ -139,6 +141,7 @@ int APS5_VABI sceWebBrowserDialogOpenForPredeterminedContent(const void* param,
if (status == COMMON_DIALOG_STATUS_RUNNING) return COMMON_DIALOG_ERROR_BUSY;
g_status = COMMON_DIALOG_STATUS_FINISHED;
g_open = true;
PsnDialogNoticeOffer_nid_postfix(PsnDialogNoticeKind::GenericFeature);
return 0;
}
+33
View File
@@ -1,4 +1,6 @@
#include "prx/libSceInvitationDialog/include/Api.hpp"
#include "prx/libSceIme/include/ModalDialog.hpp"
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
#include "prx/libSceCommonDialog/include/Api.hpp"
#include "prx/libSceCommonDialog/include/DialogUse.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
@@ -173,6 +175,36 @@ void TestStatusAndPending() {
Require(sceInvitationDialogGetStatus_nid_postfix() == StatusNone, "status after terminate");
}
bool PsnNoticeShown() {
ModalDialogView view;
if (!ModalDialogReadView_nid_postfix(view)) return false;
return view.message == PsnDialogNoticeRequest(PsnDialogNoticeKind::PsnFeature).message;
}
void RequireNotices() {
const InvitationDialogParam send = MakeParam(ModeSend, nullptr);
ModalDialogSetPresenter_nid_postfix(true);
Require(sceInvitationDialogInitialize() == 0, "initialize for the notice check");
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceInvitationDialogOpen(&send) == 0, "silent open");
Require(!PsnNoticeShown() && !ModalDialogCapturesInput_nid_postfix(), "silent mode showed a notice");
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceInvitationDialogOpen(nullptr) == ArgNull, "null open");
Require(!PsnNoticeShown(), "a refused open showed the notice");
Require(sceInvitationDialogOpen(&send) == 0, "show open");
Require(PsnNoticeShown(), "open did not show the PSN notice");
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
ModalDialogSetPresenter_nid_postfix(false);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
Require(sceInvitationDialogTerminate() == 0, "terminate after the notice check");
}
}
int main() {
@@ -181,5 +213,6 @@ int main() {
TestOpenChecks();
TestCanceled();
TestStatusAndPending();
RequireNotices();
return 0;
}
@@ -1,4 +1,6 @@
#include "prx/libSceNpAuthAuthorizedAppDialog/include/Api.hpp"
#include "prx/libSceIme/include/ModalDialog.hpp"
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstdint>
#include <cstdlib>
@@ -19,6 +21,45 @@ constexpr int kErrNotFinished = static_cast<int>(0x80B80005);
constexpr int kErrArgNull = static_cast<int>(0x80B8000D);
constexpr int kResultUserCanceled = 1;
bool PsnNoticeShown() {
ModalDialogView view;
if (!ModalDialogReadView_nid_postfix(view)) return false;
return view.message == PsnDialogNoticeRequest(PsnDialogNoticeKind::PsnFeature).message;
}
void RequireNotices() {
NpAuthAuthorizedAppDialogParam param{};
param.base.size = sizeof(param.base);
param.base.magic = static_cast<std::uint32_t>(reinterpret_cast<std::uintptr_t>(&param)) - 1060003575u;
param.size = sizeof(param);
param.userId = USER_SERVICE_INITIAL_USER_ID;
char application[136] = "test";
std::string text(16, 'a');
param.application = application;
param.text = text.c_str();
ModalDialogSetPresenter_nid_postfix(true);
Require(sceNpAuthAuthorizedAppDialogInitialize() == 0);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpAuthAuthorizedAppDialogOpen(&param) == 0);
Require(!PsnNoticeShown() && !ModalDialogCapturesInput_nid_postfix());
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpAuthAuthorizedAppDialogOpen(nullptr) == static_cast<int>(0x80B8000Du));
Require(!PsnNoticeShown());
Require(sceNpAuthAuthorizedAppDialogOpen(&param) == 0);
Require(PsnNoticeShown());
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
ModalDialogSetPresenter_nid_postfix(false);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
Require(sceNpAuthAuthorizedAppDialogTerminate() == 0);
}
}
int main() {
@@ -138,6 +179,7 @@ int main() {
Require(sceNpAuthAuthorizedAppDialogGetResult(result) == kErrNotFinished);
Require(sceNpAuthAuthorizedAppDialogTerminate() == 0);
Require(sceNpAuthAuthorizedAppDialogTerminate() == kErrNotInitialized);
RequireNotices();
Require(sceUserServiceTerminate() == 0);
return 0;
}
+55
View File
@@ -1,6 +1,8 @@
#include "prx/libSceNpCommerce/include/Api.hpp"
#include "ProcessParametersFixture.hpp"
#include "prx/libSceUserService/UserService.hpp"
#include "prx/libSceIme/include/ModalDialog.hpp"
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
#include <array>
#include <stdexcept>
#include "SceTypes.hpp"
@@ -33,6 +35,58 @@ void RequireCanceledResult(std::uint64_t userData, bool clearsReserved) {
for (const auto value : result.reserved) Require(value == (clearsReserved ? 0 : 0x33));
}
bool PsnNoticeShown() {
ModalDialogView view;
if (!ModalDialogReadView_nid_postfix(view)) return false;
return view.message == PsnDialogNoticeRequest(PsnDialogNoticeKind::PsnFeature).message;
}
void RequireNotices() {
std::uint32_t sdkVersion = 0x03500000;
std::memcpy(process.data() + 16, &sdkVersion, sizeof(sdkVersion));
NpCommerceDialogParam param{};
param.base.size = sizeof(param.base);
param.base.magic = static_cast<std::uint32_t>(reinterpret_cast<std::uintptr_t>(&param)) - 1060003575u;
param.size = sizeof(param);
param.userId = USER_SERVICE_INITIAL_USER_ID;
param.mode = 5;
param.argument = 1;
NpCommerceDialogParam2 param2{};
param2.base.size = sizeof(param2.base);
param2.base.magic = static_cast<std::uint32_t>(reinterpret_cast<std::uintptr_t>(&param2)) - 1060003575u;
param2.size = sizeof(param2);
param2.userId = USER_SERVICE_INITIAL_USER_ID;
param2.mode = 5;
param2.argument = 1;
ModalDialogSetPresenter_nid_postfix(true);
sceNpCommerceDialogTerminate();
Require(sceNpCommerceDialogInitialize() == 0);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpCommerceDialogOpen(&param) == 0);
Require(!PsnNoticeShown() && !ModalDialogCapturesInput_nid_postfix());
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpCommerceDialogOpen(nullptr) == static_cast<int>(0x80B8000Du));
Require(!PsnNoticeShown());
Require(sceNpCommerceDialogOpen(&param) == 0);
Require(PsnNoticeShown());
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpCommerceDialogOpen2(&param2) == 0);
Require(PsnNoticeShown());
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
ModalDialogSetPresenter_nid_postfix(false);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
Require(sceNpCommerceDialogTerminate() == 0);
}
}
int main() {
@@ -204,6 +258,7 @@ int main() {
Require(sceNpCommerceDialogGetResult(&result) == static_cast<int>(0x80B80003u));
Require(sceNpCommerceDialogGetStatus() == statusNone);
Require(sceNpCommerceDialogUpdateStatus() == statusNone);
RequireNotices();
Require(sceUserServiceTerminate() == 0);
return 0;
}
@@ -1,5 +1,7 @@
#include "prx/libSceNpFriendListDialog/include/Api.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include "prx/libSceIme/include/ModalDialog.hpp"
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
#include <cstdint>
#include <cstdlib>
@@ -16,6 +18,35 @@ constexpr int kErrNotFinished = static_cast<int>(0x80B80005);
constexpr int kErrArgNull = static_cast<int>(0x80B8000D);
constexpr int kResultUserCanceled = 1;
bool PsnNoticeShown() {
ModalDialogView view;
if (!ModalDialogReadView_nid_postfix(view)) return false;
return view.message == PsnDialogNoticeRequest(PsnDialogNoticeKind::PsnFeature).message;
}
void RequireNotices() {
std::uint64_t param = 0;
ModalDialogSetPresenter_nid_postfix(true);
Require(sceNpFriendListDialogInitialize() == 0);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpFriendListDialogOpenA(&param) == 0);
Require(!PsnNoticeShown() && !ModalDialogCapturesInput_nid_postfix());
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpFriendListDialogOpenA(nullptr) == kErrArgNull);
Require(!PsnNoticeShown());
Require(sceNpFriendListDialogOpenA(&param) == 0);
Require(PsnNoticeShown());
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
ModalDialogSetPresenter_nid_postfix(false);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
Require(sceNpFriendListDialogTerminate() == 0);
}
}
int main() {
@@ -75,4 +106,5 @@ int main() {
Require(sceNpFriendListDialogGetResultA(result) == kErrNotInitialized);
Require(sceNpFriendListDialogGetStatus() == kStatusNone);
Require(sceNpFriendListDialogUpdateStatus() == kStatusNone);
RequireNotices();
}
+53
View File
@@ -1,4 +1,6 @@
#include "prx/libSceNpProfileDialog/include/Api.hpp"
#include "prx/libSceIme/include/ModalDialog.hpp"
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstddef>
#include <cstdint>
@@ -67,6 +69,56 @@ void RequireCanceled(const std::uint8_t* result, void* userData) {
for (std::size_t i = kResultSize; i < kResultSize + 16; ++i) Require(result[i] == kSentinel);
}
bool PsnNoticeShown() {
ModalDialogView view;
if (!ModalDialogReadView_nid_postfix(view)) return false;
return view.message == PsnDialogNoticeRequest(PsnDialogNoticeKind::PsnFeature).message;
}
void RequireNotices(std::uint8_t* param, std::uint8_t* paramA) {
ModalDialogSetPresenter_nid_postfix(true);
Require(sceNpProfileDialogInitialize() == 0);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpProfileDialogOpen(reinterpret_cast<const SceNpProfileDialogParam*>(param)) == 0);
Require(!PsnNoticeShown() && !ModalDialogCapturesInput_nid_postfix());
Require(sceNpProfileDialogGetStatus() == kStatusFinished);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpProfileDialogOpen(reinterpret_cast<const SceNpProfileDialogParam*>(param)) == 0);
Require(PsnNoticeShown());
Require(sceNpProfileDialogGetStatus() == kStatusFinished);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpProfileDialogOpenA(reinterpret_cast<const SceNpProfileDialogParamA*>(paramA)) == 0);
Require(PsnNoticeShown());
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpProfileDialogOpen(nullptr) == kErrArgNull);
Require(!PsnNoticeShown());
Store<std::uint32_t>(param, 56, 9);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
RequireThrows([&] { sceNpProfileDialogOpen(reinterpret_cast<const SceNpProfileDialogParam*>(param)); });
Require(!PsnNoticeShown());
Store<std::uint32_t>(param, 56, 1);
ModalDialogSetPresenter_nid_postfix(false);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpProfileDialogOpen(reinterpret_cast<const SceNpProfileDialogParam*>(param)) == 0);
Require(!PsnNoticeShown() && !ModalDialogCapturesInput_nid_postfix());
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpProfileDialogTerminate() == 0);
}
}
int main() {
@@ -164,5 +216,6 @@ int main() {
Require(sceNpProfileDialogGetResult(nullptr) == kErrNotInitialized);
Require(sceNpProfileDialogGetStatus() == kStatusNone);
Require(sceNpProfileDialogUpdateStatus() == kStatusNone);
RequireNotices(param, paramA);
return 0;
}
@@ -1,5 +1,7 @@
#include "prx/libSceNpSnsFacebookDialog/include/Api.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include "prx/libSceIme/include/ModalDialog.hpp"
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
#include <cstdint>
#include <cstdlib>
@@ -16,6 +18,36 @@ constexpr int kErrNotFinished = static_cast<int>(0x80B80005);
constexpr int kErrArgNull = static_cast<int>(0x80B8000D);
constexpr int kResultUserCanceled = 1;
bool PsnNoticeShown() {
ModalDialogView view;
if (!ModalDialogReadView_nid_postfix(view)) return false;
return view.message == PsnDialogNoticeRequest(PsnDialogNoticeKind::PsnFeature).message;
}
void RequireNotices() {
std::uint64_t param = 0;
ModalDialogSetPresenter_nid_postfix(true);
Require(sceNpSnsFacebookDialogInitialize() == 0);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpSnsFacebookDialogOpen(&param) == 0);
Require(!PsnNoticeShown() && !ModalDialogCapturesInput_nid_postfix());
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpSnsFacebookDialogOpen(nullptr) == kErrArgNull);
Require(!PsnNoticeShown());
Require(sceNpSnsFacebookDialogOpen(&param) == 0);
Require(PsnNoticeShown());
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
ModalDialogSetPresenter_nid_postfix(false);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
Require(sceNpSnsFacebookDialogTerminate() == 0);
}
}
int main() {
@@ -75,4 +107,5 @@ int main() {
Require(sceNpSnsFacebookDialogGetResult(result) == kErrNotInitialized);
Require(sceNpSnsFacebookDialogGetStatus() == kStatusNone);
Require(sceNpSnsFacebookDialogUpdateStatus() == kStatusNone);
RequireNotices();
}
+40
View File
@@ -1,4 +1,6 @@
#include "prx/libSceWebBrowserDialog/include/Api.hpp"
#include "prx/libSceIme/include/ModalDialog.hpp"
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include "prx/libSceCommonDialog/CommonDialog.hpp"
#include <cstdint>
@@ -18,6 +20,43 @@ constexpr int COMMON_DIALOG_ERROR_ARG_NULL = static_cast<int>(0x80B8000Du);
void Require(bool value) { if (!value) std::abort(); }
bool GenericNoticeShown() {
ModalDialogView view;
if (!ModalDialogReadView_nid_postfix(view)) return false;
return view.message == PsnDialogNoticeRequest(PsnDialogNoticeKind::GenericFeature).message;
}
void RequireNotices(const void* param) {
WebBrowserDialogAllowList allowList{};
allowList.size = sizeof(allowList);
allowList.addresses[0] = "test.invalid";
ModalDialogSetPresenter_nid_postfix(true);
Require(sceWebBrowserDialogInitialize() == 0);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceWebBrowserDialogOpen(param) == 0);
Require(!GenericNoticeShown() && !ModalDialogCapturesInput_nid_postfix());
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceWebBrowserDialogOpen(nullptr) == COMMON_DIALOG_ERROR_ARG_NULL);
Require(!GenericNoticeShown());
Require(sceWebBrowserDialogOpen(param) == 0);
Require(GenericNoticeShown());
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceWebBrowserDialogOpenForPredeterminedContent(param, &allowList) == 0);
Require(GenericNoticeShown());
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
ModalDialogSetPresenter_nid_postfix(false);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
Require(sceWebBrowserDialogTerminate() == 0);
}
}
int main() {
@@ -149,5 +188,6 @@ int main() {
Require(sceWebBrowserDialogGetResult(nullptr) == COMMON_DIALOG_ERROR_ARG_NULL);
Require(sceWebBrowserDialogGetStatus() == COMMON_DIALOG_STATUS_NONE);
Require(sceWebBrowserDialogUpdateStatus() == COMMON_DIALOG_STATUS_NONE);
RequireNotices(param);
return 0;
}
+80
View File
@@ -0,0 +1,80 @@
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
#include <cstdio>
#include <cstdlib>
namespace {
void Require(bool value, const char* what) {
if (!value) {
std::fprintf(stderr, "psn_dialog_notice: %s\n", what);
std::abort();
}
}
const char16_t* const kPsnText = u"This feature needs PlayStation Network, which AnyPS5 does not provide, so it is not available.";
const char16_t* const kGenericText = u"This system feature is not available in AnyPS5.";
ModalDialogState StateFor(std::uint32_t owner, std::size_t& chosen) {
chosen = 7;
return ModalDialogPoll_nid_postfix(chosen, owner);
}
bool ShownMessageIs(const char16_t* text) {
ModalDialogView view;
if (!ModalDialogReadView_nid_postfix(view)) return false;
return view.message == text && view.buttons.size() == 1 && view.buttons[0].label == u"OK" && view.buttons[0].selected;
}
void Clear() {
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
}
}
int main() {
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
std::size_t chosen = 0;
Require(!PsnDialogNoticeOfferAt_nid_postfix(PsnDialogNoticeKind::PsnFeature, 0), "an offer was shown without a presenter");
Require(StateFor(ModalDialogAnyOwner, chosen) == ModalDialogState::Idle, "a refused offer left a modal dialog open");
ModalDialogSetPresenter_nid_postfix(true);
Require(PsnDialogNoticeOfferAt_nid_postfix(PsnDialogNoticeKind::PsnFeature, 0), "the first offer with a presenter was refused");
Require(ModalDialogCapturesInput_nid_postfix(), "the notice does not capture input while it shows");
Require(ShownMessageIs(kPsnText), "the PSN notice text or its OK button is wrong");
Require(StateFor(ModalDialogOwnerPsnNotice, chosen) == ModalDialogState::Showing, "the notice is not owned by its library");
Require(StateFor(ModalDialogOwnerErrorDialog, chosen) == ModalDialogState::Idle, "another owner sees the notice");
Require(!PsnDialogNoticeOfferAt_nid_postfix(PsnDialogNoticeKind::GenericFeature, 2500), "an offer replaced a notice that is still showing");
Require(ShownMessageIs(kPsnText), "a refused offer changed the notice that is showing");
ModalDialogPublishInput_nid_postfix(ModalDialogInputKind::Confirm);
Require(StateFor(ModalDialogOwnerPsnNotice, chosen) == ModalDialogState::Answered, "OK does not end the notice");
Clear();
Require(!PsnDialogNoticeOfferAt_nid_postfix(PsnDialogNoticeKind::PsnFeature, 1000), "a second notice came inside the two-second interval");
Require(!PsnDialogNoticeOfferAt_nid_postfix(PsnDialogNoticeKind::GenericFeature, 1999), "a notice came one millisecond inside the interval");
Require(PsnDialogNoticeOfferAt_nid_postfix(PsnDialogNoticeKind::GenericFeature, 2000), "a notice was refused at exactly the interval");
Require(ShownMessageIs(kGenericText), "the generic notice text is wrong");
Clear();
Require(!PsnDialogNoticeOfferAt_nid_postfix(PsnDialogNoticeKind::PsnFeature, 2001), "the interval does not count from the last shown notice");
Clear();
ModalDialogSetPresenter_nid_postfix(false);
Require(!PsnDialogNoticeOfferAt_nid_postfix(PsnDialogNoticeKind::PsnFeature, 9000), "an offer was shown without a presenter after a reset");
ModalDialogSetPresenter_nid_postfix(true);
Require(PsnDialogNoticeOfferAt_nid_postfix(PsnDialogNoticeKind::PsnFeature, 9001), "a refused offer started the interval");
Clear();
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
Require(!PsnDialogNoticeOfferAt_nid_postfix(PsnDialogNoticeKind::PsnFeature, 20000), "silent mode showed a notice");
Require(StateFor(ModalDialogAnyOwner, chosen) == ModalDialogState::Idle, "silent mode opened a modal dialog");
Require(!ModalDialogCapturesInput_nid_postfix(), "silent mode captures input");
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
Require(PsnDialogNoticeOfferAt_nid_postfix(PsnDialogNoticeKind::PsnFeature, 20000), "show mode is not restored after silent");
Clear();
ModalDialogSetPresenter_nid_postfix(false);
return 0;
}
+43
View File
@@ -0,0 +1,43 @@
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
#include <cstdio>
#include <cstdlib>
#include <stdexcept>
#include <string>
namespace {
void Require(bool value, const char* what) {
if (!value) {
std::fprintf(stderr, "psn_dialog_notice_mode: %s\n", what);
std::abort();
}
}
void RefusesNamingVariable(const char* text) {
try {
ParsePsnDialogNoticeMode(text);
} catch (const std::runtime_error& error) {
const std::string message = error.what();
Require(message.find("ANYPS5_PSN_DIALOGS") != std::string::npos, "the refusal does not name the variable");
Require(message.find(std::string("'") + text + "'") != std::string::npos, "the refusal does not name the value");
return;
}
Require(false, "an invalid value was accepted");
}
}
int main() {
Require(ParsePsnDialogNoticeMode(nullptr) == PsnDialogNoticeMode::Silent, "an unset variable is not silent");
Require(ParsePsnDialogNoticeMode("") == PsnDialogNoticeMode::Silent, "an empty value is not the same as unset");
Require(ParsePsnDialogNoticeMode("silent") == PsnDialogNoticeMode::Silent, "silent is not silent");
Require(ParsePsnDialogNoticeMode("show") == PsnDialogNoticeMode::Show, "show is not show");
RefusesNamingVariable("Show");
RefusesNamingVariable("SHOW");
RefusesNamingVariable("show ");
RefusesNamingVariable("1");
RefusesNamingVariable("0");
RefusesNamingVariable("on");
RefusesNamingVariable("yes");
return 0;
}
+6
View File
@@ -529,6 +529,12 @@ The code reads environment names through `getenv`, `IsEnvironmentSet`, `kibSetti
|------|------|--------|---------|-------------|
| `ANYPS5_SYSTEM_FONTS` | string | `core/libs/prx/libSceFont/src/SystemFont.cpp` | | directory holding the system fonts, defaulting to anyps5-fonts beside the executable |
### libSceIme
| Name | Kind | Source | Default | Description |
|------|------|--------|---------|-------------|
| `ANYPS5_PSN_DIALOGS` | string | `core/libs/prx/libSceIme/src/PsnDialogNotice.cpp` | silent | when a dialog that needs PlayStation Network opens (profile, friend list, store, invitations, Facebook link, authorized apps), `show` displays a host notice that the feature is not available; `silent`, unset or empty shows nothing, as before; any other value stops the title at its first such dialog with an error naming the variable |
### libSceNpEntitlementAccess
| Name | Kind | Source | Default | Description |
+1
View File
@@ -2,6 +2,7 @@
### Silent stubs
- [sceInvitationDialogOpen](../../../core/libs/prx/libSceInvitationDialog/Export.cpp) (libSceInvitationDialog) - with `ANYPS5_PSN_DIALOGS=show`, a successful open shows AnyPS5's notice that the feature needs PlayStation Network; the console's own display without PlayStation Network is not measured, and the notice wording is AnyPS5's.
- [sceInvitationDialogOpen, sceInvitationDialogGetResult](../../../core/libs/prx/libSceInvitationDialog/Export.cpp) (libSceInvitationDialog, PS4) - no dialog is shown and no invitation is sent: `Open` moves the dialog straight to `FINISHED`, and `GetResult` returns 0 with `errorCode` 0, `result` `USER_CANCELED` (1), the `callbackArg` of the last `Open` and a recipient count of 0, as [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/2cdefaa1298c6e4ece6c74bd84e90f3906282d51/src/core/libraries/invitation_dialog/invitation_dialog.cpp) reports when its window is dismissed and as [libSceNpProfileDialog](libSceNpProfileDialog.md) does. Not measured on a console.
### Unknown function info
@@ -2,6 +2,7 @@
### Silent stubs
- [sceNpAuthAuthorizedAppDialogOpen](../../../core/libs/prx/libSceNpAuthAuthorizedAppDialog/Export.cpp) (libSceNpAuthAuthorizedAppDialog) - with `ANYPS5_PSN_DIALOGS=show`, a successful open shows AnyPS5's notice that the feature needs PlayStation Network; the console's own display without PlayStation Network is not measured, and the notice wording is AnyPS5's.
- [libSceNpAuthAuthorizedAppDialog](../../../core/libs/prx/libSceNpAuthAuthorizedAppDialog/Export.cpp) - the authorized-app dialog runs the common-dialog state machine but shows nothing and reports the user as having cancelled, as there is no PSN sign-in to authorize an app against. Parameter fields at offsets 64 and 72 feed a 136-byte application record and a text value of at most 1024 bytes; their service-side meaning remains incomplete.
### Unknown function info
+1
View File
@@ -2,6 +2,7 @@
### Silent stubs
- [sceNpCommerceDialogOpen, sceNpCommerceDialogOpen2](../../../core/libs/prx/libSceNpCommerce/Export.cpp) (libSceNpCommerce) - with `ANYPS5_PSN_DIALOGS=show`, a successful open shows AnyPS5's notice that the feature needs PlayStation Network; the console's own display without PlayStation Network is not measured, and the notice wording is AnyPS5's.
- [libSceNpCommerce](../../../core/libs/prx/libSceNpCommerce/Export.cpp) - the PS Store icon show/hide calls and `sceNpCommerceSetPsStoreIconLayout` do nothing
### Unknown function info
@@ -2,6 +2,7 @@
### Silent stubs
- [sceNpFriendListDialogOpenA](../../../core/libs/prx/libSceNpFriendListDialog/Export.cpp) (libSceNpFriendListDialog) - with `ANYPS5_PSN_DIALOGS=show`, a successful open shows AnyPS5's notice that the feature needs PlayStation Network; the console's own display without PlayStation Network is not measured, and the notice wording is AnyPS5's.
- [libSceNpFriendListDialog](../../../core/libs/prx/libSceNpFriendListDialog/Export.cpp) - the friend list dialog (`sceNpFriendListDialogOpenA` and `sceNpFriendListDialogGetResultA`) runs the common-dialog state machine but shows nothing and reports the user as having cancelled, as there is no PSN friend list. The signatures are from [Orbital's type database](https://github.com/AlexAltea/orbital/blob/b321fcdbd700cc02da1cb1ad25412781d5ec73c6/tools/ida/db_types.json); the result layout beyond the leading `int32_t` result code is not known, so nothing else is written.
### Unknown function info
+1
View File
@@ -2,6 +2,7 @@
### Silent stubs
- [sceNpProfileDialogOpen, sceNpProfileDialogOpenA](../../../core/libs/prx/libSceNpProfileDialog/Export.cpp) (libSceNpProfileDialog) - with `ANYPS5_PSN_DIALOGS=show`, a successful open shows AnyPS5's notice that the feature needs PlayStation Network; the console's own display for this call without PlayStation Network is not measured, and the notice wording is AnyPS5's.
- [sceNpProfileDialogOpen, sceNpProfileDialogOpenA, sceNpProfileDialogGetResult](../../../core/libs/prx/libSceNpProfileDialog/Export.cpp) (libSceNpProfileDialog) - no profile is shown: `Open` and `OpenA` move the dialog straight to `FINISHED`, and `GetResult` reports `result` 0, `userAction` `USER_CANCELED` (1) and the caller's `userData`, as [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/c2814041e546bf75c12756dbec9da911c721ce1c/src/core/libraries/np/np_profile_dialog/np_profile_dialog.cpp#L21-L180) does when its window is dismissed. Not measured on a console.
### Unknown function info
@@ -2,4 +2,5 @@
### Silent stubs
- [sceNpSnsFacebookDialogOpen](../../../core/libs/prx/libSceNpSnsFacebookDialog/Export.cpp) (libSceNpSnsFacebookDialog) - with `ANYPS5_PSN_DIALOGS=show`, a successful open shows AnyPS5's notice that the feature needs PlayStation Network; the console's own display without PlayStation Network is not measured, and the notice wording is AnyPS5's.
- [libSceNpSnsFacebookDialog](../../../core/libs/prx/libSceNpSnsFacebookDialog/Export.cpp) - the Facebook dialog runs the common-dialog state machine but shows nothing and reports the user as having cancelled, as there is no Facebook account link. The signatures are from [Orbital's type database](https://github.com/AlexAltea/orbital/blob/b321fcdbd700cc02da1cb1ad25412781d5ec73c6/tools/ida/db_types.json); the result layout beyond the leading `int32_t` result code is not known, so nothing else is written.
+1
View File
@@ -2,6 +2,7 @@
### Silent stubs
- [sceWebBrowserDialogOpen, sceWebBrowserDialogOpenForPredeterminedContent](../../../core/libs/prx/libSceWebBrowserDialog/Export.cpp) (libSceWebBrowserDialog) - with `ANYPS5_PSN_DIALOGS=show`, a successful open shows AnyPS5's generic notice that the system feature is not available; no PlayStation Network link is claimed, since no source ties this dialog to it, and the console's own display is not measured.
- [libSceWebBrowserDialog](../../../core/libs/prx/libSceWebBrowserDialog/Export.cpp) - `sceWebBrowserDialogOpen` and `sceWebBrowserDialogOpenForPredeterminedContent` run the common-dialog state machine without displaying an interactive browser, and `sceWebBrowserDialogGetResult` reports that the user cancelled. Minecraft Bedrock (PPSA17221) imports `sceWebBrowserDialogOpenForPredeterminedContent` (#5744). The 424-byte allow-list parameter and its twenty optional address pointers are validated, but address filtering is not modelled without an interactive browser. Main open-parameter validation remains incomplete.
- [sceWebBrowserDialogSetCookie, sceWebBrowserDialogResetCookie](../../../core/libs/prx/libSceWebBrowserDialog/Export.cpp) (libSceWebBrowserDialog) - there is no browser cookie store. Both calls check their parameters in the same order and with the same codes as the PS5 13.60 module, then return 0 without storing or clearing anything. On the console they then forward the request to the browser service. While an opened dialog has not been updated to finished, closed or terminated, they return `0x80B80006` (the console's open-dialog flag).
### Unknown function info
+6
View File
@@ -560,6 +560,12 @@ A line is the player number (the controller's slot: a controller that reconnects
The panel uses the font and scale of the [performance overlay](#performance-overlay) and sits in the corner mirrored horizontally from `ANYPS5_OVERLAY_POS`, the top right by default, so it never covers that overlay. While the system on-screen keyboard is shown the panel is not drawn, and its 4 seconds keep running. Screenshots do not include it. While it is hidden, which is always so unless F9 or `ANYPS5_PAD_STATUS=1` shows it, nothing is drawn, no render pass or memory is allocated for it and the presented image is unchanged. What still runs is a lock and a clock read in each present and in each video-out loop pass, to see whether the panel is wanted. With `ANYPS5_PAD_STATUS` unset or 0 and no F9 press, no controller name is copied and no battery level is read for it; they are read on every loop pass with `ANYPS5_PAD_STATUS=1`, and while the panel is shown after F9.
### PSN-only dialogs
Some system dialogs need PlayStation Network: the profile, the friend list, the store, the invitation dialog, the Facebook link and the authorized-apps dialog. AnyPS5 does not provide PlayStation Network, so these dialogs finish at once with the same answer as a cancel, and nothing is shown. The web browser dialog is not known to need PlayStation Network, so its notice only says that the system feature is not available.
Set `ANYPS5_PSN_DIALOGS=show` to show a notice on the game's screen when one of these dialogs opens. The notice has one OK button and takes the controller until it is answered. It is not shown again within two seconds of the previous one, and it is not shown while another dialog or notice is showing. The game's result is the same either way. `silent`, an unset variable and an empty one show nothing. Any other value stops the game at its first such dialog with an error that names `ANYPS5_PSN_DIALOGS`.
### Windows crash diagnostics
When a register points at readable memory that starts with at least four printable ASCII characters, either as UTF-16LE or as single bytes, the crash report prints that text after the register memory dump, as `[r13] u"..."` for UTF-16LE or `[rdi] "..."` for single bytes. The text ends at a NUL, at the first character that is not printable ASCII, a tab, a line feed or a carriage return, after 512 characters or at the end of readable memory. Tabs, line breaks, quotes and backslashes are escaped, and `...` after the closing quote means that no NUL ended the text within those limits.