From 4078de1eff2c68e1f297ad902b9a1e09489ff91d Mon Sep 17 00:00:00 2001 From: yellows8 Date: Sun, 1 Dec 2019 18:34:14 -0500 Subject: [PATCH] psel: Various improvements, including proper version handling. Updated names. Renamed/added modes, with sysver docs. Don't use ptrs for input AccountUids. Added pselShowUserCreatorForStarter and pselShowNintendoAccountNnidLinker. Directly return the Result from PselUiReturnArg. Removed the output user param from pselShowUserCreator. --- nx/include/switch/applets/psel.h | 115 ++++++++++++++++++------------- nx/source/applets/psel.c | 82 ++++++++++++++-------- 2 files changed, 119 insertions(+), 78 deletions(-) diff --git a/nx/include/switch/applets/psel.h b/nx/include/switch/applets/psel.h index 497a62a5..e0c8ee59 100644 --- a/nx/include/switch/applets/psel.h +++ b/nx/include/switch/applets/psel.h @@ -1,71 +1,79 @@ /** * @file psel.h * @brief Wrapper for using playerSelect (user selection applet). - * @author XorTroll + * @author XorTroll, yellows8 * @copyright libnx Authors */ #pragma once #include "../types.h" -#include "../services/applet.h" #include "../services/acc.h" /// playerSelect UI modes. typedef enum { - PselUiMode_SelectUser = 0, ///< Simple user selection (new users cannot be created). - PselUiMode_UserCreation = 1, ///< Only user creation (the user is later returned). - PselUiMode_EnsureNsaAvailable = 2, ///< EnsureNsaAvailable - PselUiMode_IconEditor = 3, ///< IconEditor - PselUiMode_NicknameEditor = 4, ///< NicknameEditor - PselUiMode_ForStarter = 5, ///< Mode "starter" uses to register the console's first user on the initial setup - PselUiMode_NetworkServiceAccountRegistration = 8, ///< NetworkServiceAccountRegistration - PselUiMode_NintendoAccountNnidLinker = 9, ///< NintendoAccountNnidLinker - PselUiMode_LicenseRequirementsForNetworkService = 10, ///< LicenseRequirementsForNetworkService - PselUiMode_NaLoginTest = 12, ///< NaLoginTest + PselUiMode_UserSelector = 0, ///< Simple user selection (new users cannot be created). + PselUiMode_UserCreator = 1, ///< User creation. + PselUiMode_EnsureNetworkServiceAccountAvailable = 2, ///< EnsureNetworkServiceAccountAvailable + PselUiMode_UserIconEditor = 3, ///< UserIconEditor + PselUiMode_UserNicknameEditor = 4, ///< UserNicknameEditor + PselUiMode_UserCreatorForStarter = 5, ///< Mode "starter" uses to register the console's first user on the initial setup. +// TODO: Add mode 6. + PselUiMode_IntroduceExternalNetworkServiceAccount = 7, ///< IntroduceExternalNetworkServiceAccount + PselUiMode_IntroduceExternalNetworkServiceAccountForRegistration = 8, ///< [6.0.0+] IntroduceExternalNetworkServiceAccountForRegistration + PselUiMode_NintendoAccountNnidLinker = 9, ///< [6.0.0+] NintendoAccountNnidLinker + PselUiMode_LicenseRequirementsForNetworkService = 10, ///< [6.0.0+] LicenseRequirementsForNetworkService + PselUiMode_LicenseRequirementsForNetworkServiceWithUserContextImpl = 11, ///< [7.0.0+] LicenseRequirementsForNetworkServiceWithUserContextImpl + PselUiMode_UserCreatorForImmediateNaLoginTest = 12, ///< [7.0.0+] UserCreatorForImmediateNaLoginTest } PselUiMode; -/// UI settings for playerSelect. +/// Base UI settings for playerSelect. typedef struct { - u32 mode; ///< UI mode, see \ref PselUiMode. - u32 dialogType; ///< Dialog type - AccountUid invalidUserList[ACC_USER_LIST_SIZE]; ///< List of \ref AccountUid user IDs which will be disabled. - u8 unk_x88[0x8]; ///< Unknown. - u8 networkServiceRequired; ///< Whether the user needs to be linked to a Nintendo account. - u8 unk_x91[0x2]; ///< Unknown. - u8 allowUserCreation; ///< (With ::PselUiMode_SelectUser) enables the option to create a new user. - u8 skipEnabled; ///< Enables the option to skip user selection (a new button is shown) - u8 unk_x95[0xb]; ///< Unknown. + u32 mode; ///< \ref PselUiMode + u32 dialog_type; ///< Dialog type. + AccountUid user_list[ACC_USER_LIST_SIZE]; ///< List of \ref AccountUid. + u8 unk_x88[0x8]; ///< Unknown. + u8 network_service_required; ///< Whether the user needs to be linked to a Nintendo account. + u8 unk_x91[0x2]; ///< Unknown. + u8 allow_user_creation; ///< (With ::PselUiMode_SelectUser) enables the option to create a new user. + u8 skip_enabled; ///< Enables the option to skip user selection (a new button is shown) + u8 unk_x95[0x3]; ///< Unknown. +} PselUiSettingsV1; + +/// UI settings for versions starting with 0x10000. +typedef struct { + PselUiSettingsV1 settings; ///< \ref PselUiSettingsV1 + u8 unk_x98[0x8]; ///< Unknown. } PselUiSettings; -/// Result data sent after execution. +/// Return data sent after execution. typedef struct { - u32 result; ///< Result code. - AccountUid userId; ///< Selected \ref AccountUid. -} PselResult; + Result res; ///< Result. + AccountUid user_id; ///< Selected \ref AccountUid. +} PselUiReturnArg; /** - * @brief Creates a new UI config for playerSelect applet with the specified mode. + * @brief Creates a new UI config for the playerSelect applet with the specified mode. * @param ui PseluiSettings struct. * @param mode playerSelect UI mode. */ Result pselUiCreate(PselUiSettings *ui, PselUiMode mode); /** - * @brief Adds a user to the user list of the applet. + * @brief Adds an user to the user list of the applet. * @param ui PselUiSettings struct. - * @param user_id user ID. + * @param[in] user_id user ID. * @note The users will be treated as invalid users for user selection mode, and as the input user for other modes. */ -void pselUiAddUser(PselUiSettings *ui, AccountUid *user_id); +void pselUiAddUser(PselUiSettings *ui, AccountUid user_id); /** - * @brief Sets whether users can be created in the applet + * @brief Sets whether users can be created in the applet. * @param ui PselUiSettings struct. * @param flag Flag value. * @note Only used for ::PselUiMode_SelectUser */ NX_CONSTEXPR void pselUiSetAllowUserCreation(PselUiSettings *ui, bool flag) { - if(ui->mode == PselUiMode_SelectUser) { - ui->allowUserCreation = flag; + if(ui->settings.mode == PselUiMode_UserSelector) { + ui->settings.allow_user_creation = flag; } } @@ -75,20 +83,20 @@ NX_CONSTEXPR void pselUiSetAllowUserCreation(PselUiSettings *ui, bool flag) { * @param flag Flag value. */ NX_CONSTEXPR void pselUiSetNetworkServiceRequired(PselUiSettings *ui, bool flag) { - ui->networkServiceRequired = flag; + ui->settings.network_service_required = flag; } /** - * @brief Sets whether selection can be skipped (with a new button) + * @brief Sets whether selection can be skipped (with a new button). * @param ui PselUiSettings struct. * @param flag Flag value. */ NX_CONSTEXPR void pselUiSetSkipEnabled(PselUiSettings *ui, bool flag) { - ui->skipEnabled = flag; + ui->settings.skip_enabled = flag; } /** - * @brief Shows playerSelect applet with the specified UI settings. + * @brief Shows the applet with the specified UI settings. * @param ui PselUiSettings struct. * @param out_user Selected user ID. * @note If user skips (see \ref pselUiSetSkipEnabled) this will return successfully but the output ID will be 0. @@ -96,25 +104,36 @@ NX_CONSTEXPR void pselUiSetSkipEnabled(PselUiSettings *ui, bool flag) { Result pselUiShow(PselUiSettings *ui, AccountUid *out_user); /** - * @brief Shows playerSelect applet to select a user. - * @param out_user Returned selected user ID. + * @brief Shows the applet to select a user. + * @param[out] out_user Returned selected user ID. */ Result pselShowUserSelector(AccountUid *out_user); /** - * @brief Shows playerSelect applet to create a user. - * @param out_user Returned created user ID. + * @brief Shows the applet to create a user. */ -Result pselShowUserCreator(AccountUid *out_user); +Result pselShowUserCreator(void); /** - * @brief Shows playerSelect applet to change a user's icon. - * @param user Input user ID. + * @brief Shows the applet to change a user's icon. + * @param[in] user Input user ID. */ -Result pselShowIconEditor(AccountUid *user); +Result pselShowUserIconEditor(AccountUid user); /** - * @brief Shows playerSelect applet to change a user's nickname. - * @param user Input user ID. + * @brief Shows the applet to change a user's nickname. + * @param[in] user Input user ID. */ -Result pselShowNicknameEditor(AccountUid *user); \ No newline at end of file +Result pselShowUserNicknameEditor(AccountUid user); + +/** + * @brief Shows the applet to create a user. Used by the starter applet during system setup. + */ +Result pselShowUserCreatorForStarter(void); + +/** + * @brief Shows the applet for Nintendo Account Nnid linking. + * @note Only available on [6.0.0+]. + * @param[in] user Input user ID. + */ +Result pselShowNintendoAccountNnidLinker(AccountUid user); diff --git a/nx/source/applets/psel.c b/nx/source/applets/psel.c index 278348bb..b7164029 100644 --- a/nx/source/applets/psel.c +++ b/nx/source/applets/psel.c @@ -1,35 +1,29 @@ #include -#include "types.h" -#include "result.h" -#include "services/applet.h" -#include "services/acc.h" -#include "applets/libapplet.h" +#include "libapplet_internal.h" #include "applets/psel.h" #include "runtime/hosversion.h" Result pselUiCreate(PselUiSettings *ui, PselUiMode mode) { memset(ui, 0, sizeof(PselUiSettings)); - ui->mode = mode; + ui->settings.mode = mode; return 0; } -void pselUiAddUser(PselUiSettings *ui, AccountUid *user_id) { - int i; - for(i = 0; i < ACC_USER_LIST_SIZE; i++) { - - if(!accountUidIsValid(&ui->invalidUserList[i])) { - __builtin_memcpy(&ui->invalidUserList[i], user_id, sizeof(AccountUid)); +void pselUiAddUser(PselUiSettings *ui, AccountUid user_id) { + for(u32 i=0; isettings.user_list[i])) { + ui->settings.user_list[i] = user_id; break; } } } static u32 _pselGetLaVersion() { - u32 ver = 0; - u32 hosver = hosversionGet(); - if(hosver >= MAKEHOSVERSION(9,0,0)) { + u32 ver = 0x1; // [1.0.0] + if (hosversionAtLeast(6,0,0)) ver = 0x20000; - } + else if (hosversionAtLeast(2,0,0)) + ver = 0x10000; return ver; } @@ -38,16 +32,21 @@ Result pselUiShow(PselUiSettings *ui, AccountUid *out_user) { LibAppletArgs args; u32 la_ver = _pselGetLaVersion(); libappletArgsCreate(&args, la_ver); - PselResult res; + PselUiReturnArg ret; size_t reply_size; + const void* arg_ptr = ui; + size_t arg_size = sizeof(*ui); - rc = libappletLaunch(AppletId_playerSelect, &args, ui, sizeof(PselUiSettings), &res, sizeof(res), &reply_size); + if (la_ver == 0x1) { // [1.0.0] + arg_ptr = &ui->settings; + arg_size = sizeof(ui->settings); + } + + rc = libappletLaunch(AppletId_playerSelect, &args, arg_ptr, arg_size, &ret, sizeof(ret), &reply_size); if (R_SUCCEEDED(rc)) { - if (res.result != 0) rc = MAKERESULT(Module_Libnx, LibnxError_LibAppletBadExit); - if (R_SUCCEEDED(rc)) { - if(out_user) *out_user = res.userId; - } + rc = ret.res; // Official sw returns this directly. + if (R_SUCCEEDED(rc) && out_user) *out_user = ret.user_id; } return rc; @@ -55,25 +54,26 @@ Result pselUiShow(PselUiSettings *ui, AccountUid *out_user) { Result pselShowUserSelector(AccountUid *out_user) { PselUiSettings ui; - Result rc = pselUiCreate(&ui, PselUiMode_SelectUser); + Result rc = pselUiCreate(&ui, PselUiMode_UserSelector); + // TODO: This is missing the rest of the UiSettings setup done by official sw. if(R_SUCCEEDED(rc)) { rc = pselUiShow(&ui, out_user); } return rc; } -Result pselShowUserCreator(AccountUid *out_user) { +Result pselShowUserCreator(void) { PselUiSettings ui; - Result rc = pselUiCreate(&ui, PselUiMode_UserCreation); + Result rc = pselUiCreate(&ui, PselUiMode_UserCreator); if(R_SUCCEEDED(rc)) { - rc = pselUiShow(&ui, out_user); + rc = pselUiShow(&ui, NULL); } return rc; } -Result pselShowIconEditor(AccountUid *user) { +Result pselShowUserIconEditor(AccountUid user) { PselUiSettings ui; - Result rc = pselUiCreate(&ui, PselUiMode_IconEditor); + Result rc = pselUiCreate(&ui, PselUiMode_UserIconEditor); if(R_SUCCEEDED(rc)) { pselUiAddUser(&ui, user); rc = pselUiShow(&ui, NULL); @@ -81,9 +81,31 @@ Result pselShowIconEditor(AccountUid *user) { return rc; } -Result pselShowNicknameEditor(AccountUid *user) { +Result pselShowUserNicknameEditor(AccountUid user) { PselUiSettings ui; - Result rc = pselUiCreate(&ui, PselUiMode_NicknameEditor); + Result rc = pselUiCreate(&ui, PselUiMode_UserNicknameEditor); + if(R_SUCCEEDED(rc)) { + pselUiAddUser(&ui, user); + rc = pselUiShow(&ui, NULL); + } + return rc; +} + +Result pselShowUserCreatorForStarter(void) { + PselUiSettings ui; + Result rc = pselUiCreate(&ui, PselUiMode_UserCreatorForStarter); + if(R_SUCCEEDED(rc)) { + rc = pselUiShow(&ui, NULL); + } + return rc; +} + +Result pselShowNintendoAccountNnidLinker(AccountUid user) { + if (hosversionBefore(6,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + PselUiSettings ui; + Result rc = pselUiCreate(&ui, PselUiMode_NintendoAccountNnidLinker); if(R_SUCCEEDED(rc)) { pselUiAddUser(&ui, user); rc = pselUiShow(&ui, NULL);