diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/src/org/dolphinemu/dolphinemu/NativeLibrary.java index 027d476095..91b29e4410 100644 --- a/Source/Android/src/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/src/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -169,6 +169,12 @@ public final class NativeLibrary */ public static native void CreateUserFolders(); + /** + * Sets the current working user directory + * If not set, it auto-detects a location + */ + public static native void SetUserDirectory(String directory); + /** * Begins emulation. * diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index a20543e3ec..e4fc2bb5c7 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -21,7 +21,6 @@ #include <direct.h> // getcwd #include <io.h> #include <shellapi.h> -#include <shlobj.h> // for SHGetFolderPath #include <windows.h> #else #include <dirent.h> @@ -743,66 +742,6 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new // Set up all paths and files on the first run if (paths[D_USER_IDX].empty()) { -#ifdef _WIN32 - // Detect where the User directory is. There are five different cases (on top of the - // command line flag, which overrides all this): - // 1. GetExeDirectory()\portable.txt exists - // -> Use GetExeDirectory()\User - // 2. HKCU\Software\Dolphin Emulator\LocalUserConfig exists and is true - // -> Use GetExeDirectory()\User - // 3. HKCU\Software\Dolphin Emulator\UserConfigPath exists - // -> Use this as the user directory path - // 4. My Documents exists - // -> Use My Documents\Dolphin Emulator as the User directory path - // 5. Default - // -> Use GetExeDirectory()\User - - // Check our registry keys - HKEY hkey; - DWORD local = 0; - TCHAR configPath[MAX_PATH] = {0}; - if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Dolphin Emulator"), 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS) - { - DWORD size = 4; - if (RegQueryValueEx(hkey, TEXT("LocalUserConfig"), nullptr, nullptr, reinterpret_cast<LPBYTE>(&local), &size) != ERROR_SUCCESS) - local = 0; - - size = MAX_PATH; - if (RegQueryValueEx(hkey, TEXT("UserConfigPath"), nullptr, nullptr, (LPBYTE)configPath, &size) != ERROR_SUCCESS) - configPath[0] = 0; - RegCloseKey(hkey); - } - - local = local || File::Exists(GetExeDirectory() + DIR_SEP "portable.txt"); - - // Get Program Files path in case we need it. - TCHAR my_documents[MAX_PATH]; - bool my_documents_found = SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_MYDOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, my_documents)); - - if (local) // Case 1-2 - paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; - else if (configPath[0]) // Case 3 - paths[D_USER_IDX] = TStrToUTF8(configPath); - else if (my_documents_found) // Case 4 - paths[D_USER_IDX] = TStrToUTF8(my_documents) + DIR_SEP "Dolphin Emulator" DIR_SEP; - else // Case 5 - paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; - - // Prettify the path: it will be displayed in some places, we don't want a mix of \ and /. - paths[D_USER_IDX] = ReplaceAll(paths[D_USER_IDX], "\\", DIR_SEP); - - // Make sure it ends in DIR_SEP. - if (*paths[D_USER_IDX].rbegin() != DIR_SEP_CHR) - paths[D_USER_IDX] += DIR_SEP; -#else - if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) - paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; - else - paths[D_USER_IDX] = std::string(getenv("HOME") ? - getenv("HOME") : getenv("PWD") ? - getenv("PWD") : "") + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP; -#endif - paths[D_GCUSER_IDX] = paths[D_USER_IDX] + GC_USER_DIR DIR_SEP; paths[D_WIIROOT_IDX] = paths[D_USER_IDX] + WII_USER_DIR; paths[D_WIIUSER_IDX] = paths[D_WIIROOT_IDX] + DIR_SEP; diff --git a/Source/Core/DolphinQt/Main.cpp b/Source/Core/DolphinQt/Main.cpp index dd622a5290..65baf122da 100644 --- a/Source/Core/DolphinQt/Main.cpp +++ b/Source/Core/DolphinQt/Main.cpp @@ -42,6 +42,7 @@ int main(int argc, char* argv[]) app.setAttribute(Qt::AA_UseHighDpiPixmaps); // TODO: Add command line options + UICommon::SetUserDirectory(""); // Auto-detect user folder UICommon::CreateDirectories(); UICommon::Init(); diff --git a/Source/Core/DolphinWX/Main.cpp b/Source/Core/DolphinWX/Main.cpp index e0a36c023b..ecc7ca6e57 100644 --- a/Source/Core/DolphinWX/Main.cpp +++ b/Source/Core/DolphinWX/Main.cpp @@ -229,12 +229,7 @@ bool DolphinApp::OnInit() selectAudioEmulation = parser.Found("audio_emulation", &audioEmulationName); selectPerfDir = parser.Found("perf_dir", &perfDir); playMovie = parser.Found("movie", &movieFile); - - if (parser.Found("user", &userPath)) - { - File::CreateFullPath(WxStrToStr(userPath) + DIR_SEP); - File::GetUserPath(D_USER_IDX, userPath.ToStdString() + DIR_SEP); - } + parser.Found("user", &userPath); #endif // wxUSE_CMDLINE_PARSER // Register message box and translation handlers @@ -249,6 +244,7 @@ bool DolphinApp::OnInit() wxHandleFatalExceptions(true); #endif + UICommon::SetUserDirectory(userPath.ToStdString()); UICommon::CreateDirectories(); UICommon::Init(); @@ -421,7 +417,6 @@ void DolphinApp::OnFatalException() WiimoteReal::Shutdown(); } - // ------------ // Talk to GUI diff --git a/Source/Core/DolphinWX/MainAndroid.cpp b/Source/Core/DolphinWX/MainAndroid.cpp index 527e76f17a..78960533cd 100644 --- a/Source/Core/DolphinWX/MainAndroid.cpp +++ b/Source/Core/DolphinWX/MainAndroid.cpp @@ -49,6 +49,7 @@ ANativeWindow* surf; std::string g_filename; +std::string g_set_userpath = ""; #define DOLPHIN_TAG "Dolphinemu" @@ -231,6 +232,7 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetFilename( JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveState(JNIEnv *env, jobject obj, jint slot); JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadState(JNIEnv *env, jobject obj, jint slot); JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_CreateUserFolders(JNIEnv *env, jobject obj); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirectory(JNIEnv *env, jobject obj, jstring jDirectory); JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv *env, jobject obj, jobject _surf); JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_UnPauseEmulation(JNIEnv *env, jobject obj) @@ -361,6 +363,13 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_CreateUserFo File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + JAP_DIR DIR_SEP); } +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirectory(JNIEnv *env, jobject obj, jstring jDirectory) +{ + std::string directory = GetJString(env, jDirectory); + g_set_userpath = directory; + UICommon::SetUserDirectory(directory); +} + JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv *env, jobject obj, jobject _surf) { surf = ANativeWindow_fromSurface(env, _surf); @@ -371,6 +380,7 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv * RegisterMsgAlertHandler(&MsgAlert); + UICommon::SetUserDirectory(g_set_userpath); UICommon::Init(); // No use running the loop when booting fails diff --git a/Source/Core/DolphinWX/MainNoGUI.cpp b/Source/Core/DolphinWX/MainNoGUI.cpp index 8d6d0282a6..bd82c8b4f5 100644 --- a/Source/Core/DolphinWX/MainNoGUI.cpp +++ b/Source/Core/DolphinWX/MainNoGUI.cpp @@ -324,6 +324,7 @@ int main(int argc, char* argv[]) return 1; } + UICommon::SetUserDirectory(""); // Auto-detect user folder UICommon::Init(); platform->Init(); diff --git a/Source/Core/UICommon/UICommon.cpp b/Source/Core/UICommon/UICommon.cpp index 735487306a..2c4b9b4a87 100644 --- a/Source/Core/UICommon/UICommon.cpp +++ b/Source/Core/UICommon/UICommon.cpp @@ -2,6 +2,10 @@ // Licensed under GPLv2 // Refer to the license.txt file included. +#ifdef _WIN32 +#include <shlobj.h> // for SHGetFolderPath +#endif + #include "Common/CommonPaths.h" #include "Common/FileUtil.h" #include "Common/Logging/LogManager.h" @@ -70,4 +74,77 @@ void CreateDirectories() File::CreateFullPath(File::GetUserPath(D_THEMES_IDX)); } +void SetUserDirectory(const std::string& custom_path) +{ + if (custom_path.size() != 0) + { + File::CreateFullPath(custom_path + DIR_SEP); + File::GetUserPath(D_USER_IDX, custom_path + DIR_SEP); + return; + } + + std::string user_path = ""; +#ifdef _WIN32 + // Detect where the User directory is. There are five different cases (on top of the + // command line flag, which overrides all this): + // 1. GetExeDirectory()\portable.txt exists + // -> Use GetExeDirectory()\User + // 2. HKCU\Software\Dolphin Emulator\LocalUserConfig exists and is true + // -> Use GetExeDirectory()\User + // 3. HKCU\Software\Dolphin Emulator\UserConfigPath exists + // -> Use this as the user directory path + // 4. My Documents exists + // -> Use My Documents\Dolphin Emulator as the User directory path + // 5. Default + // -> Use GetExeDirectory()\User + + // Check our registry keys + HKEY hkey; + DWORD local = 0; + TCHAR configPath[MAX_PATH] = {0}; + if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Dolphin Emulator"), 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS) + { + DWORD size = 4; + if (RegQueryValueEx(hkey, TEXT("LocalUserConfig"), nullptr, nullptr, reinterpret_cast<LPBYTE>(&local), &size) != ERROR_SUCCESS) + local = 0; + + size = MAX_PATH; + if (RegQueryValueEx(hkey, TEXT("UserConfigPath"), nullptr, nullptr, (LPBYTE)configPath, &size) != ERROR_SUCCESS) + configPath[0] = 0; + RegCloseKey(hkey); + } + + local = local || File::Exists(File::GetExeDirectory() + DIR_SEP "portable.txt"); + + // Get Program Files path in case we need it. + TCHAR my_documents[MAX_PATH]; + bool my_documents_found = SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_MYDOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, my_documents)); + + if (local) // Case 1-2 + user_path = File::GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; + else if (configPath[0]) // Case 3 + user_path = TStrToUTF8(configPath); + else if (my_documents_found) // Case 4 + user_path = TStrToUTF8(my_documents) + DIR_SEP "Dolphin Emulator" DIR_SEP; + else // Case 5 + user_path = File::GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; + + // Prettify the path: it will be displayed in some places, we don't want a mix of \ and /. + user_path = ReplaceAll(user_path, "\\", DIR_SEP); + + // Make sure it ends in DIR_SEP. + if (*user_path.rbegin() != DIR_SEP_CHR) + user_path += DIR_SEP; +#else + if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) + user_path = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; + else + user_path = std::string(getenv("HOME") ? + getenv("HOME") : getenv("PWD") ? + getenv("PWD") : "") + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP; +#endif + + File::GetUserPath(D_USER_IDX, user_path); +} + } // namespace UICommon diff --git a/Source/Core/UICommon/UICommon.h b/Source/Core/UICommon/UICommon.h index d177727986..6a5e05fbaf 100644 --- a/Source/Core/UICommon/UICommon.h +++ b/Source/Core/UICommon/UICommon.h @@ -11,5 +11,6 @@ void Init(); void Shutdown(); void CreateDirectories(); +void SetUserDirectory(const std::string& custom_path); } // namespace UICommon