From 3062a35eb1297067446156c43e9d0df2f684edff Mon Sep 17 00:00:00 2001 From: boludoz Date: Sun, 15 Oct 2023 02:02:22 -0300 Subject: Improved shortcut: add games in applist for Windows, question for start game at fullscreen & better unicode support for some Windows path funcs. --- src/common/fs/fs_util.cpp | 59 ++++++++++++++++++++++++++++++ src/common/fs/fs_util.h | 22 +++++++++++- src/common/fs/path_util.cpp | 87 ++++++++++++++++++++++++++++++++++++++------- src/common/fs/path_util.h | 15 +++++++- 4 files changed, 168 insertions(+), 15 deletions(-) (limited to 'src/common') diff --git a/src/common/fs/fs_util.cpp b/src/common/fs/fs_util.cpp index 813a713c3..442f63728 100644 --- a/src/common/fs/fs_util.cpp +++ b/src/common/fs/fs_util.cpp @@ -36,4 +36,63 @@ std::string PathToUTF8String(const std::filesystem::path& path) { return ToUTF8String(path.u8string()); } +std::u8string U8FilenameSantizer(const std::u8string_view u8filename) { + std::u8string u8path_santized{u8filename.begin(), u8filename.end()}; + size_t eSizeSanitized = u8path_santized.size(); + + // Special case for ":", for example: 'Pepe: La secuela' --> 'Pepe - La + // secuela' or 'Pepe : La secuela' --> 'Pepe - La secuela' + for (size_t i = 0; i < eSizeSanitized; i++) { + switch (u8path_santized[i]) { + case u8':': + if (i == 0 || i == eSizeSanitized - 1) { + u8path_santized.replace(i, 1, u8"_"); + } else if (u8path_santized[i - 1] == u8' ') { + u8path_santized.replace(i, 1, u8"-"); + } else { + u8path_santized.replace(i, 1, u8" -"); + eSizeSanitized++; + } + break; + case u8'\\': + case u8'/': + case u8'*': + case u8'?': + case u8'\"': + case u8'<': + case u8'>': + case u8'|': + case u8'\0': + u8path_santized.replace(i, 1, u8"_"); + break; + default: + break; + } + } + + // Delete duplicated spaces || Delete duplicated dots (MacOS i think) + for (size_t i = 0; i < eSizeSanitized - 1; i++) { + if ((u8path_santized[i] == u8' ' && u8path_santized[i + 1] == u8' ') || + (u8path_santized[i] == u8'.' && u8path_santized[i + 1] == u8'.')) { + u8path_santized.erase(i, 1); + i--; + } + } + + // Delete all spaces and dots at the end (Windows almost) + while (u8path_santized.back() == u8' ' || u8path_santized.back() == u8'.') { + u8path_santized.pop_back(); + } + + if (u8path_santized.empty()) { + return u8""; + } + + return u8path_santized; +} + +std::string UTF8FilenameSantizer(const std::string_view filename) { + return ToUTF8String(U8FilenameSantizer(ToU8String(filename))); +} + } // namespace Common::FS diff --git a/src/common/fs/fs_util.h b/src/common/fs/fs_util.h index 2492a9f94..dbb4f5a9a 100644 --- a/src/common/fs/fs_util.h +++ b/src/common/fs/fs_util.h @@ -82,4 +82,24 @@ concept IsChar = std::same_as; */ [[nodiscard]] std::string PathToUTF8String(const std::filesystem::path& path); -} // namespace Common::FS +/** + * Fix filename (remove invalid characters) + * + * @param u8_string dirty encoded filename string + * + * @returns utf8_string santized filename string + * + */ +[[nodiscard]] std::u8string U8FilenameSantizer(const std::u8string_view u8filename); + +/** + * Fix filename (remove invalid characters) + * + * @param utf8_string dirty encoded filename string + * + * @returns utf8_string santized filename string + * + */ +[[nodiscard]] std::string UTF8FilenameSantizer(const std::string_view filename); + +} // namespace Common::FS \ No newline at end of file diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index 0abd81a45..a461161ed 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -6,6 +6,7 @@ #include #include "common/fs/fs.h" +#include "common/string_util.h" #ifdef ANDROID #include "common/fs/fs_android.h" #endif @@ -14,7 +15,7 @@ #include "common/logging/log.h" #ifdef _WIN32 -#include // Used in GetExeDirectory() +#include // Used in GetExeDirectory() and GetWindowsDesktop() #else #include // Used in Get(Home/Data)Directory() #include // Used in GetHomeDirectory() @@ -250,30 +251,39 @@ void SetYuzuPath(YuzuPath yuzu_path, const fs::path& new_path) { #ifdef _WIN32 fs::path GetExeDirectory() { - wchar_t exe_path[MAX_PATH]; + WCHAR exe_path[MAX_PATH]; - if (GetModuleFileNameW(nullptr, exe_path, MAX_PATH) == 0) { + if (SUCCEEDED(GetModuleFileNameW(nullptr, exe_path, MAX_PATH))) { + std::wstring wideExePath(exe_path); + + // UTF-16 filesystem lib to UTF-8 is broken, so we need to convert to UTF-8 with the with + // the Windows library (Filesystem converts the strings literally). + return fs::path{Common::UTF16ToUTF8(wideExePath)}.parent_path(); + } else { LOG_ERROR(Common_Filesystem, - "Failed to get the path to the executable of the current process"); + "[GetExeDirectory] Failed to get the path to the executable of the current " + "process"); } - return fs::path{exe_path}.parent_path(); + return fs::path{}; } fs::path GetAppDataRoamingDirectory() { PWSTR appdata_roaming_path = nullptr; - SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &appdata_roaming_path); - - auto fs_appdata_roaming_path = fs::path{appdata_roaming_path}; - - CoTaskMemFree(appdata_roaming_path); + if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &appdata_roaming_path))) { + std::wstring wideAppdataRoamingPath(appdata_roaming_path); + CoTaskMemFree(appdata_roaming_path); - if (fs_appdata_roaming_path.empty()) { - LOG_ERROR(Common_Filesystem, "Failed to get the path to the %APPDATA% directory"); + // UTF-16 filesystem lib to UTF-8 is broken, so we need to convert to UTF-8 with the with + // the Windows library (Filesystem converts the strings literally). + return fs::path{Common::UTF16ToUTF8(wideAppdataRoamingPath)}; + } else { + LOG_ERROR(Common_Filesystem, + "[GetAppDataRoamingDirectory] Failed to get the path to the %APPDATA% directory"); } - return fs_appdata_roaming_path; + return fs::path{}; } #else @@ -338,6 +348,57 @@ fs::path GetBundleDirectory() { #endif +fs::path GetDesktopPath() { +#if defined(_WIN32) + PWSTR DesktopPath = nullptr; + + if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Desktop, 0, NULL, &DesktopPath))) { + std::wstring wideDesktopPath(DesktopPath); + CoTaskMemFree(DesktopPath); + + // UTF-16 filesystem lib to UTF-8 is broken, so we need to convert to UTF-8 with the with + // the Windows library (Filesystem converts the strings literally). + return fs::path{Common::UTF16ToUTF8(wideDesktopPath)}; + } else { + LOG_ERROR(Common_Filesystem, + "[GetDesktopPath] Failed to get the path to the desktop directory"); + } +#else + fs::path shortcut_path = GetHomeDirectory() / "Desktop"; + if (fs::exists(shortcut_path)) { + return shortcut_path; + } +#endif + return fs::path{}; +} + +fs::path GetAppsShortcutsPath() { +#if defined(_WIN32) + PWSTR AppShortcutsPath = nullptr; + + if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_CommonPrograms, 0, NULL, &AppShortcutsPath))) { + std::wstring wideAppShortcutsPath(AppShortcutsPath); + CoTaskMemFree(AppShortcutsPath); + + // UTF-16 filesystem lib to UTF-8 is broken, so we need to convert to UTF-8 with the with + // the Windows library (Filesystem converts the strings literally). + return fs::path{Common::UTF16ToUTF8(wideAppShortcutsPath)}; + } else { + LOG_ERROR(Common_Filesystem, + "[GetAppsShortcutsPath] Failed to get the path to the App Shortcuts directory"); + } +#else + fs::path shortcut_path = GetHomeDirectory() / ".local/share/applications"; + if (!fs::exists(shortcut_path)) { + shortcut_path = std::filesystem::path("/usr/share/applications"); + return shortcut_path; + } else { + return shortcut_path; + } +#endif + return fs::path{}; +} + // vvvvvvvvvv Deprecated vvvvvvvvvv // std::string_view RemoveTrailingSlash(std::string_view path) { diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h index 63801c924..b88a388d1 100644 --- a/src/common/fs/path_util.h +++ b/src/common/fs/path_util.h @@ -244,7 +244,6 @@ void SetYuzuPath(YuzuPath yuzu_path, const Path& new_path) { * @returns The path of the current user's %APPDATA% directory. */ [[nodiscard]] std::filesystem::path GetAppDataRoamingDirectory(); - #else /** @@ -275,6 +274,20 @@ void SetYuzuPath(YuzuPath yuzu_path, const Path& new_path) { #endif +/** + * Gets the path of the current user's desktop directory. + * + * @returns The path of the current user's desktop directory. + */ +[[nodiscard]] std::filesystem::path GetDesktopPath(); + +/** + * Gets the path of the current user's apps directory. + * + * @returns The path of the current user's apps directory. + */ +[[nodiscard]] std::filesystem::path GetAppsShortcutsPath(); + // vvvvvvvvvv Deprecated vvvvvvvvvv // // Removes the final '/' or '\' if one exists -- cgit v1.2.3