diff --git a/stratosphere/ams_mitm/source/utils.cpp b/stratosphere/ams_mitm/source/utils.cpp index 637113fdc..e25b09408 100644 --- a/stratosphere/ams_mitm/source/utils.cpp +++ b/stratosphere/ams_mitm/source/utils.cpp @@ -35,10 +35,26 @@ static std::vector g_disable_mitm_flagged_tids; static std::atomic_bool g_has_initialized = false; static std::atomic_bool g_has_hid_session = false; -static u64 g_override_key_combination = KEY_R; -static u64 g_override_hbl_tid = 0x010000000000100DULL; -static bool g_override_any_app = false; -static bool g_override_by_default = true; +/* Content override support variables/types */ +static OverrideKey g_default_override_key = { + .key_combination = KEY_R, + .override_by_default = true +}; + +struct HblOverrideConfig { + OverrideKey override_key; + u64 title_id; + bool override_any_app; +}; + +static HblOverrideConfig g_hbl_override_config = { + .override_key = { + .key_combination = KEY_R, + .override_by_default = true + }, + .title_id = 0x010000000000100D, + .override_any_app = false +}; /* Static buffer for loader.ini contents at runtime. */ static char g_config_ini_data[0x800]; @@ -368,7 +384,7 @@ Result Utils::SaveSdFileForAtmosphere(u64 title_id, const char *fn, void *data, } bool Utils::IsHblTid(u64 tid) { - return (g_override_any_app && IsApplicationTid(tid)) || (!g_override_any_app && tid == g_override_hbl_tid); + return (g_hbl_override_config.override_any_app && IsApplicationTid(tid)) || (!g_hbl_override_config.override_any_app && tid == g_hbl_override_config.title_id); } bool Utils::HasTitleFlag(u64 tid, const char *flag) { @@ -446,6 +462,13 @@ Result Utils::GetKeysDown(u64 *keys) { return 0x0; } +static bool HasOverrideKey(OverrideKey *cfg) { + u64 kDown = 0; + bool keys_triggered = (R_SUCCEEDED(Utils::GetKeysDown(&kDown)) && ((kDown & cfg->key_combination) != 0)); + return Utils::IsSdInitialized() && (cfg->override_by_default ^ keys_triggered); +} + + bool Utils::HasOverrideButton(u64 tid) { if ((!IsApplicationTid(tid)) || (!IsSdInitialized())) { /* Disable button override disable for non-applications. */ @@ -455,71 +478,88 @@ bool Utils::HasOverrideButton(u64 tid) { /* Unconditionally refresh loader.ini contents. */ RefreshConfiguration(); - u64 kDown = 0; - bool keys_triggered = (R_SUCCEEDED(GetKeysDown(&kDown)) && ((kDown & g_override_key_combination) != 0)); - return IsSdInitialized() && (g_override_by_default ^ keys_triggered); + if (IsHblTid(tid) && HasOverrideKey(&g_hbl_override_config.override_key)) { + return true; + } + + OverrideKey title_cfg = GetTitleOverrideKey(tid); + return HasOverrideKey(&title_cfg); } -static int FsMitMIniHandler(void *user, const char *section, const char *name, const char *value) { +static OverrideKey ParseOverrideKey(const char *value) { + OverrideKey cfg; + + /* Parse on by default. */ + if (value[0] == '!') { + cfg.override_by_default = true; + value++; + } else { + cfg.override_by_default = false; + } + + /* Parse key combination. */ + if (strcasecmp(value, "A") == 0) { + cfg.key_combination = KEY_A; + } else if (strcasecmp(value, "B") == 0) { + cfg.key_combination = KEY_B; + } else if (strcasecmp(value, "X") == 0) { + cfg.key_combination = KEY_X; + } else if (strcasecmp(value, "Y") == 0) { + cfg.key_combination = KEY_Y; + } else if (strcasecmp(value, "LS") == 0) { + cfg.key_combination = KEY_LSTICK; + } else if (strcasecmp(value, "RS") == 0) { + cfg.key_combination = KEY_RSTICK; + } else if (strcasecmp(value, "L") == 0) { + cfg.key_combination = KEY_L; + } else if (strcasecmp(value, "R") == 0) { + cfg.key_combination = KEY_R; + } else if (strcasecmp(value, "ZL") == 0) { + cfg.key_combination = KEY_ZL; + } else if (strcasecmp(value, "ZR") == 0) { + cfg.key_combination = KEY_ZR; + } else if (strcasecmp(value, "PLUS") == 0) { + cfg.key_combination = KEY_PLUS; + } else if (strcasecmp(value, "MINUS") == 0) { + cfg.key_combination = KEY_MINUS; + } else if (strcasecmp(value, "DLEFT") == 0) { + cfg.key_combination = KEY_DLEFT; + } else if (strcasecmp(value, "DUP") == 0) { + cfg.key_combination = KEY_DUP; + } else if (strcasecmp(value, "DRIGHT") == 0) { + cfg.key_combination = KEY_DRIGHT; + } else if (strcasecmp(value, "DDOWN") == 0) { + cfg.key_combination = KEY_DDOWN; + } else if (strcasecmp(value, "SL") == 0) { + cfg.key_combination = KEY_SL; + } else if (strcasecmp(value, "SR") == 0) { + cfg.key_combination = KEY_SR; + } else { + cfg.key_combination = 0; + } + + return cfg; +} + +static int FsMitmIniHandler(void *user, const char *section, const char *name, const char *value) { /* Taken and modified, with love, from Rajkosto's implementation. */ - if (strcasecmp(section, "config") == 0) { - if (strcasecmp(name, "hbl_tid") == 0) { + if (strcasecmp(section, "hbl_config") == 0) { + if (strcasecmp(name, "title_id") == 0) { if (strcasecmp(value, "app") == 0) { - g_override_any_app = true; + g_hbl_override_config.override_any_app = true; } else { u64 override_tid = strtoul(value, NULL, 16); if (override_tid != 0) { - g_override_hbl_tid = override_tid; + g_hbl_override_config.title_id = override_tid; } } } else if (strcasecmp(name, "override_key") == 0) { - if (value[0] == '!') { - g_override_by_default = true; - value++; - } else { - g_override_by_default = false; - } - - if (strcasecmp(value, "A") == 0) { - g_override_key_combination = KEY_A; - } else if (strcasecmp(value, "B") == 0) { - g_override_key_combination = KEY_B; - } else if (strcasecmp(value, "X") == 0) { - g_override_key_combination = KEY_X; - } else if (strcasecmp(value, "Y") == 0) { - g_override_key_combination = KEY_Y; - } else if (strcasecmp(value, "LS") == 0) { - g_override_key_combination = KEY_LSTICK; - } else if (strcasecmp(value, "RS") == 0) { - g_override_key_combination = KEY_RSTICK; - } else if (strcasecmp(value, "L") == 0) { - g_override_key_combination = KEY_L; - } else if (strcasecmp(value, "R") == 0) { - g_override_key_combination = KEY_R; - } else if (strcasecmp(value, "ZL") == 0) { - g_override_key_combination = KEY_ZL; - } else if (strcasecmp(value, "ZR") == 0) { - g_override_key_combination = KEY_ZR; - } else if (strcasecmp(value, "PLUS") == 0) { - g_override_key_combination = KEY_PLUS; - } else if (strcasecmp(value, "MINUS") == 0) { - g_override_key_combination = KEY_MINUS; - } else if (strcasecmp(value, "DLEFT") == 0) { - g_override_key_combination = KEY_DLEFT; - } else if (strcasecmp(value, "DUP") == 0) { - g_override_key_combination = KEY_DUP; - } else if (strcasecmp(value, "DRIGHT") == 0) { - g_override_key_combination = KEY_DRIGHT; - } else if (strcasecmp(value, "DDOWN") == 0) { - g_override_key_combination = KEY_DDOWN; - } else if (strcasecmp(value, "SL") == 0) { - g_override_key_combination = KEY_SL; - } else if (strcasecmp(value, "SR") == 0) { - g_override_key_combination = KEY_SR; - } else { - g_override_key_combination = 0; - } + g_hbl_override_config.override_key = ParseOverrideKey(value); + } + } else if (strcasecmp(section, "default_config") == 0) { + if (strcasecmp(name, "override_key") == 0) { + g_default_override_key = ParseOverrideKey(value); } } else { return 0; @@ -527,6 +567,46 @@ static int FsMitMIniHandler(void *user, const char *section, const char *name, c return 1; } +static int FsMitmTitleSpecificIniHandler(void *user, const char *section, const char *name, const char *value) { + /* We'll output an override key when relevant. */ + OverrideKey *user_cfg = reinterpret_cast(user); + + if (strcasecmp(section, "override_config") == 0) { + if (strcasecmp(name, "override_key") == 0) { + *user_cfg = ParseOverrideKey(value); + } + } else { + return 0; + } + return 1; +} + +OverrideKey Utils::GetTitleOverrideKey(u64 tid) { + OverrideKey cfg = g_default_override_key; + char path[FS_MAX_PATH+1] = {0}; + snprintf(path, FS_MAX_PATH, "/atmosphere/titles/%016lx/config.ini", tid); + FsFile cfg_file; + + if (fsFsOpenFile(&g_sd_filesystem, path, FS_OPEN_READ, &cfg_file)) { + ON_SCOPE_EXIT { fsFileClose(&cfg_file); }; + + size_t config_file_size = 0x20000; + fsFileGetSize(&cfg_file, &config_file_size); + + char *config_buf = reinterpret_cast(calloc(1, config_file_size)); + if (config_buf != NULL) { + ON_SCOPE_EXIT { free(config_buf); }; + + /* Read title ini contents. */ + fsFileRead(&cfg_file, 0, config_buf, config_file_size, &config_file_size); + + /* Parse title ini. */ + ini_parse_string(config_buf, FsMitmTitleSpecificIniHandler, &cfg); + } + } + + return cfg; +} void Utils::RefreshConfiguration() { FsFile config_file; @@ -547,7 +627,7 @@ void Utils::RefreshConfiguration() { fsFileRead(&config_file, 0, g_config_ini_data, size, &r_s); fsFileClose(&config_file); - ini_parse_string(g_config_ini_data, FsMitMIniHandler, NULL); + ini_parse_string(g_config_ini_data, FsMitmIniHandler, NULL); } Result Utils::GetSettingsItemValueSize(const char *name, const char *key, u64 *out_size) { diff --git a/stratosphere/ams_mitm/source/utils.hpp b/stratosphere/ams_mitm/source/utils.hpp index 2c15ec13e..db9e84f6a 100644 --- a/stratosphere/ams_mitm/source/utils.hpp +++ b/stratosphere/ams_mitm/source/utils.hpp @@ -37,6 +37,11 @@ enum BisStorageId : u32 { BisStorageId_SystemProperPartition = 33, }; +struct OverrideKey { + u64 key_combination; + bool override_by_default; +}; + class Utils { public: static bool IsSdInitialized(); @@ -72,6 +77,8 @@ class Utils { static bool IsHidAvailable(); static Result GetKeysDown(u64 *keys); + + static OverrideKey GetTitleOverrideKey(u64 tid); static bool HasOverrideButton(u64 tid); /* Settings! */