diff --git a/Redcraft.FocusIME/Source/Private/Main.cpp b/Redcraft.FocusIME/Source/Private/Main.cpp index 1bc7f64..13b189c 100644 --- a/Redcraft.FocusIME/Source/Private/Main.cpp +++ b/Redcraft.FocusIME/Source/Private/Main.cpp @@ -21,7 +21,11 @@ // ReSharper disable CppDeprecatedEntity // ReSharper disable CppClangTidyCertErr33C -std::ofstream GLogFile; +const std::string LogFilename = "FocusIME.log"; + +const std::string CachedModeFilename = "FocusIME.json"; + +std::ofstream GLogStream; bool GShouldExit = false; @@ -48,7 +52,153 @@ void Tick() Chinese, }; - static std::map CachedIMEMode; + static std::map CachedIMEMode = [] + { + std::map Result; + + std::ifstream File(CachedModeFilename); + + if (!File.is_open()) + { + PrintLog("Cached conversion mode configuration file not found"); + + return Result; + } + + do + { + std::string Buffer; + + Buffer.assign(std::istreambuf_iterator(File), std::istreambuf_iterator()); + + std::string_view View = Buffer; + + // { "ItemA": "ValueA", "ItemB": "ValueB" } + + while (!View.empty() && std::isspace(View.front())) View.remove_prefix(1); + while (!View.empty() && std::isspace(View.back ())) View.remove_suffix(1); + + if (!View.starts_with('{') || !View.ends_with('}')) break; + + View.remove_prefix(1); + View.remove_suffix(1); + + // "ItemA": "ValueA", "ItemB": "ValueB" + + const bool bSuccessful = [&Result, &View] + { + std::string_view::size_type Index = std::string_view::npos; + + while (true) + { + while (!View.empty() && std::isspace(View.front())) View.remove_prefix(1); + + if (!View.starts_with('"')) return false; + + View.remove_prefix(1); + + // ItemA": "ValueA", "ItemB": "ValueB" + + Index = View.find('"'); + + if (Index == std::string_view::npos) return false; + + std::string_view Process = View.substr(0, Index); + + View.remove_prefix(Process.size() + 1); + + // : "ValueA", "ItemB": "ValueB" + + while (!View.empty() && std::isspace(View.front())) View.remove_prefix(1); + + if (!View.starts_with(':')) return false; + + View.remove_prefix(1); + + // "ValueA", "ItemB": "ValueB" + + while (!View.empty() && std::isspace(View.front())) View.remove_prefix(1); + + if (!View.starts_with('"')) return false; + + View.remove_prefix(1); + + // ValueA", "ItemB": "ValueB" + + Index = View.find('"'); + + if (Index == std::string_view::npos) return false; + + std::string_view Mode = View.substr(0, Index); + + View.remove_prefix(Mode.size() + 1); + + // , "ItemB": "ValueB" + + while (!View.empty() && std::isspace(View.front())) View.remove_prefix(1); + + if (View.empty()) return true; + + if (!View.starts_with(',')) return false; + + View.remove_prefix(1); + + if (Mode != "English" && Mode != "Chinese" && Mode != "Default") return false; + + Result[std::string(Process)] = + Mode == "English" ? EIMEConversionMode::English : + Mode == "Chinese" ? EIMEConversionMode::Chinese : EIMEConversionMode::Default; + + } + + return true; + + } (); + + if (!bSuccessful) break; + + PrintLog("Successfully loaded " + std::to_string(Result.size()) + " cached conversion mode items"); + + return Result; + } + while (false); + + PrintLog("Invalid format detected in cached conversion mode configuration file"); + + return Result; + + } (); + + auto SaveCachedIMEMode = [] + { + std::ofstream File(CachedModeFilename); + + if (!File.is_open()) + { + PrintLog("Error: Failed to save cached conversion mode configuration"); + + return; + } + + File << "{"; + + bool bFirstItem = true; + + for (const auto& [Name, Mode] : CachedIMEMode) + { + if (!bFirstItem) File << ","; + + File << "\n\t\"" << Name << "\": \"" << + (Mode == EIMEConversionMode::English ? "English" : + Mode == EIMEConversionMode::Chinese ? "Chinese" : "Default") << "\""; + + bFirstItem = false; + } + + File << "\n}\n"; + + File.close(); + }; static HWND LastWindow = nullptr; @@ -83,9 +233,11 @@ void Tick() { CachedIMEMode[CachedProcess] = CurrentMode; - PrintLog("Update the conversion mode cached for process '" + CachedProcess + "' to " + + PrintLog("Updated cached conversion mode for process '" + CachedProcess + "' to " + (CurrentMode == EIMEConversionMode::English ? "English" : - CurrentMode == EIMEConversionMode::Chinese ? "Chinese" : "Default")); + CurrentMode == EIMEConversionMode::Chinese ? "Chinese" : "Default")); + + SaveCachedIMEMode(); } } } @@ -145,11 +297,11 @@ void Tick() { if (SendMessage(IMEWindow, WM_IME_CONTROL, IMC_SETCONVERSIONMODE, TargetMode) == 0) { - PrintLog("Successfully set conversion mode for process '" + CachedProcess + "'"); + PrintLog("Successfully applied conversion mode for process '" + CachedProcess + "'"); } else { - PrintLog("Failed to set conversion mode for process '" + CachedProcess + "'"); + PrintLog("Error: Failed to apply conversion mode for process '" + CachedProcess + "'"); } } } @@ -265,9 +417,9 @@ int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int) } # endif - GLogFile.open("Log.txt", std::ios::out | std::ios::app); + GLogStream.open(LogFilename, std::ios::out | std::ios::app); - if (!GLogFile.is_open()) + if (!GLogStream.is_open()) { MessageBox(nullptr, "Failed to open log file.", "FocusIME", MB_OK | MB_ICONERROR); @@ -276,7 +428,7 @@ int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int) return 1; } - PrintLog("FocusIME started successfully"); + PrintLog("FocusIME application started successfully"); MSG Message = { }; @@ -318,9 +470,9 @@ int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int) } } - PrintLog("FocusIME is shutting down..."); + PrintLog("FocusIME application is shutting down"); - GLogFile.close(); + GLogStream.close(); # if BUILD_DEBUG || BUILD_DEVELOPMENT { @@ -407,7 +559,7 @@ LRESULT CALLBACK MainWindowProc(const HWND Window, const UINT Message, const WPA if (LOWORD(WParam) == ID_TRAY_EXIT) { - PrintLog("Exit command received from tray menu"); + PrintLog("Exit command received from system tray menu"); GShouldExit = true; @@ -451,7 +603,7 @@ void PrintLog(const std::string& Text) Buffer[22] = Digits[Milliseconds / 10 % 10]; Buffer[23] = Digits[Milliseconds / 1 % 10]; - GLogFile << Buffer << Text << std::endl; + GLogStream << Buffer << Text << std::endl; #if BUILD_DEBUG || BUILD_DEVELOPMENT {