From f07d09aeb046ca7312e6c44bb4b443fd12ea23e2 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Mon, 26 Feb 2018 12:32:55 -0500 Subject: [PATCH] Added appletGetDesiredLanguage(). In set-serv('set'), added support for all language/region commands, etc. --- nx/include/switch/services/applet.h | 2 + nx/include/switch/services/set.h | 56 +++++- nx/source/services/applet.c | 39 ++++ nx/source/services/set.c | 283 +++++++++++++++++++++++++++- 4 files changed, 378 insertions(+), 2 deletions(-) diff --git a/nx/include/switch/services/applet.h b/nx/include/switch/services/applet.h index ef217b76..74d32f85 100644 --- a/nx/include/switch/services/applet.h +++ b/nx/include/switch/services/applet.h @@ -51,6 +51,8 @@ Result appletGetAppletResourceUserId(u64 *out); void appletNotifyRunning(u8 *out); Result appletCreateManagedDisplayLayer(u64 *out); +Result appletGetDesiredLanguage(u64 *LanguageCode); + /** * @brief Controls whether screenshot-capture is allowed. * @param val 0 = disable, 1 = enable. diff --git a/nx/include/switch/services/set.h b/nx/include/switch/services/set.h index 97c10697..b33b9196 100644 --- a/nx/include/switch/services/set.h +++ b/nx/include/switch/services/set.h @@ -1,4 +1,10 @@ -// Copyright 2018 plutoo +/** + * @file set.h + * @brief Settings services IPC wrapper. + * @author plutoo + * @author yellows8 + * @copyright libnx Authors + */ #include "../result.h" typedef enum { @@ -6,6 +12,54 @@ typedef enum { ColorSetId_Dark=1 } ColorSetId; +/// IDs for Language. +typedef enum +{ + SetLanguage_JA = 0, ///< Japanese + SetLanguage_ENUS = 1, ///< US English + SetLanguage_FR = 2, ///< French + SetLanguage_DE = 3, ///< German + SetLanguage_IT = 4, ///< Italian + SetLanguage_ES = 5, ///< Spanish + SetLanguage_ZHCN = 6, ///< Simplified Chinese + SetLanguage_KO = 7, ///< Korean + SetLanguage_NL = 8, ///< Dutch + SetLanguage_PT = 9, ///< Portugese + SetLanguage_RU = 10, ///< Russian + SetLanguage_ZHTW = 11, ///< Traditional Chinese + SetLanguage_ENGB = 12, ///< GB English + SetLanguage_FRCA = 13, ///< CA French + SetLanguage_ES419 = 14, ///< {?} Spanish +} SetLanguage; + +Result setInitialize(void); +void setExit(void); + +/// Converts LanguageCode to Language. +Result setMakeLanguage(u64 LanguageCode, s32 *Language); + +/// Converts Language to LanguageCode. +Result setMakeLanguageCode(s32 Language, u64 *LanguageCode); + +/// Gets the current system LanguageCode. +/// Normally this should be used instead of \ref setGetLanguageCode. +/// LanguageCode is a string, see here: http://switchbrew.org/index.php?title=Settings_services#LanguageCode +Result setGetSystemLanguage(u64 *LanguageCode); + +/// Gets the current LanguageCode, \ref setGetSystemLanguage should be used instead normally. +Result setGetLanguageCode(u64 *LanguageCode); + +/// Gets available LanguageCodes. +/// On system-version <4.0.0, max_entries is set to the output from \ref setGetAvailableLanguageCodeCount if max_entries is larger than that. +Result setGetAvailableLanguageCodes(s32 *total_entries, u64 *LanguageCodes, size_t max_entries); + +/// Gets total available LanguageCodes. +/// Output total is overridden with value 0 if the total is <0. +Result setGetAvailableLanguageCodeCount(s32 *total); + +/// Gets the RegionCode. +Result setGetRegionCode(s32 *RegionCode); + Result setsysInitialize(void); void setsysExit(void); diff --git a/nx/source/services/applet.c b/nx/source/services/applet.c index de8f972f..56d4fae3 100644 --- a/nx/source/services/applet.c +++ b/nx/source/services/applet.c @@ -503,6 +503,45 @@ Result appletGetAppletResourceUserId(u64 *out) { return 0; } +Result appletGetDesiredLanguage(u64 *LanguageCode) { + IpcCommand c; + ipcInitialize(&c); + + if (!serviceIsActive(&g_appletSrv) || __nx_applet_type!=AppletType_Application) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 21; + + Result rc = serviceIpcDispatch(&g_appletIFunctions); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + u64 LanguageCode; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && LanguageCode) { + *LanguageCode = resp->LanguageCode; + } + } + + return rc; +} + void appletNotifyRunning(u8 *out) { IpcCommand c; ipcInitialize(&c); diff --git a/nx/source/services/set.c b/nx/source/services/set.c index 3953b722..ff207aed 100644 --- a/nx/source/services/set.c +++ b/nx/source/services/set.c @@ -1,12 +1,42 @@ -// Copyright 2018 plutoo +/** + * @file set.h + * @brief Settings services IPC wrapper. + * @author plutoo + * @author yellows8 + * @copyright libnx Authors + */ #include "types.h" #include "result.h" #include "ipc.h" +#include "kernel/detect.h" #include "services/set.h" #include "services/sm.h" +#include "services/applet.h" +static Service g_setSrv; static Service g_setsysSrv; +static bool g_setLanguageCodesInitialized; +static u64 g_setLanguageCodes[0x40]; +static s32 g_setLanguageCodesTotal; + +static Result _setMakeLanguageCode(s32 Language, u64 *LanguageCode); + +Result setInitialize(void) +{ + if (serviceIsActive(&g_setSrv)) + return MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized); + + g_setLanguageCodesInitialized = 0; + + return smGetService(&g_setSrv, "set"); +} + +void setExit(void) +{ + serviceClose(&g_setSrv); +} + Result setsysInitialize(void) { if (serviceIsActive(&g_setsysSrv)) @@ -20,6 +50,257 @@ void setsysExit(void) serviceClose(&g_setsysSrv); } +static Result setInitializeLanguageCodesCache(void) { + if (g_setLanguageCodesInitialized) return 0; + Result rc = 0; + + rc = setGetAvailableLanguageCodes(&g_setLanguageCodesTotal, g_setLanguageCodes, sizeof(g_setLanguageCodes)/sizeof(u64)); + if (R_FAILED(rc)) return rc; + + if (g_setLanguageCodesTotal < 0) g_setLanguageCodesTotal = 0; + + g_setLanguageCodesInitialized = 1; + + return rc; +} + +Result setMakeLanguage(u64 LanguageCode, s32 *Language) { + Result rc = setInitializeLanguageCodesCache(); + if (R_FAILED(rc)) return rc; + + s32 i; + rc = MAKERESULT(Module_Libnx, LibnxError_BadInput); + for (i=0; i= g_setLanguageCodesTotal) { + if (!kernelAbove400()) return MAKERESULT(Module_Libnx, LibnxError_BadInput); + return _setMakeLanguageCode(Language, LanguageCode); + } + + *LanguageCode = g_setLanguageCodes[Language]; + + return rc; +} + +Result setGetSystemLanguage(u64 *LanguageCode) { + //This is disabled because the returned LanguageCode can differ from the system language, for example ja instead of {English}. + /*Result rc = appletGetDesiredLanguage(LanguageCode); + if (R_SUCCEEDED(rc)) return rc;*/ + + return setGetLanguageCode(LanguageCode); +} + +Result setGetLanguageCode(u64 *LanguageCode) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 0; + + Result rc = serviceIpcDispatch(&g_setSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + u64 LanguageCode; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && LanguageCode) *LanguageCode = resp->LanguageCode; + } + + return rc; +} + +Result setGetAvailableLanguageCodes(s32 *total_entries, u64 *LanguageCodes, size_t max_entries) { + IpcCommand c; + ipcInitialize(&c); + + Result rc=0; + bool new_cmd = kernelAbove400(); + + if (!new_cmd) {//On system-version <4.0.0 the sysmodule will close the session if max_entries is too large. + s32 tmptotal = 0; + + rc = setGetAvailableLanguageCodeCount(&tmptotal); + if (R_FAILED(rc)) return rc; + + if (max_entries > (size_t)tmptotal) max_entries = (size_t)tmptotal; + } + + size_t bufsize = max_entries*sizeof(u64); + + if (!new_cmd) { + ipcAddRecvStatic(&c, LanguageCodes, bufsize, 0); + } + else { + ipcAddRecvBuffer(&c, LanguageCodes, bufsize, 0); + } + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = new_cmd ? 5 : 1; + + rc = serviceIpcDispatch(&g_setSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + s32 total_entries; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && total_entries) *total_entries = resp->total_entries; + } + + return rc; +} + +static Result _setMakeLanguageCode(s32 Language, u64 *LanguageCode) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + s32 Language; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 2; + raw->Language = Language; + + Result rc = serviceIpcDispatch(&g_setSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + u64 LanguageCode; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && LanguageCode) *LanguageCode = resp->LanguageCode; + } + + return rc; +} + +Result setGetAvailableLanguageCodeCount(s32 *total) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = kernelAbove400() ? 6 : 3; + + Result rc = serviceIpcDispatch(&g_setSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + s32 total; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && total) { + *total = resp->total; + if (*total < 0) *total = 0; + } + } + + return rc; +} + +Result setGetRegionCode(s32 *RegionCode) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 4; + + Result rc = serviceIpcDispatch(&g_setSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + s32 RegionCode; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && RegionCode) *RegionCode = resp->RegionCode; + } + + return rc; +} + Result setsysGetColorSetId(ColorSetId* out) { IpcCommand c;