Compare commits

...

2 Commits

Author SHA1 Message Date
7e6be53e8b fix(json): fix IME mode incomplete loading 2025-06-24 21:28:35 +08:00
9a83aea6a2 feat(master): add polling tick mode 2025-06-22 18:42:55 +08:00

View File

@ -21,9 +21,17 @@
// ReSharper disable CppDeprecatedEntity // ReSharper disable CppDeprecatedEntity
// ReSharper disable CppClangTidyCertErr33C // ReSharper disable CppClangTidyCertErr33C
const std::string LogFilename = "FocusIME.log"; using namespace std::chrono_literals;
const std::string CachedModeFilename = "FocusIME.json"; constexpr bool bEnableCallback = true;
constexpr bool bEnablePolling = true;
constexpr auto TickInterval = 250ms;
constexpr auto IMEMessageDelay = 50ms;
const std::string LogFilename = "FocusIME.log";
const std::string IMEModeFilename = "FocusIME.json";
static_assert(bEnableCallback || bEnablePolling);
std::ofstream GLogStream; std::ofstream GLogStream;
@ -33,8 +41,6 @@ void PrintLog(const std::string& Text);
void Tick() void Tick()
{ {
using namespace std::chrono_literals;
// ReSharper disable CppInconsistentNaming // ReSharper disable CppInconsistentNaming
// ReSharper disable CppClangTidyPerformanceEnumSize // ReSharper disable CppClangTidyPerformanceEnumSize
@ -52,15 +58,17 @@ void Tick()
Chinese, Chinese,
}; };
static std::map<std::string, EIMEConversionMode> CachedIMEMode = [] using FIMEMode = std::map<std::string, EIMEConversionMode>;
auto LoadIMEMode = []() -> FIMEMode
{ {
std::map<std::string, EIMEConversionMode> Result; std::map<std::string, EIMEConversionMode> Result;
std::ifstream File(CachedModeFilename); std::ifstream File(IMEModeFilename);
if (!File.is_open()) if (!File.is_open())
{ {
PrintLog("Cached conversion mode configuration file not found"); PrintLog("Conversion mode configuration file not found");
return Result; return Result;
} }
@ -137,18 +145,17 @@ void Tick()
while (!View.empty() && std::isspace(View.front())) View.remove_prefix(1); while (!View.empty() && std::isspace(View.front())) View.remove_prefix(1);
if (View.empty()) return true; if (Mode != "English" && Mode != "Chinese" && Mode != "Default") return false;
Result.emplace(Process,
Mode == "English" ? EIMEConversionMode::English :
Mode == "Chinese" ? EIMEConversionMode::Chinese : EIMEConversionMode::Default);
if (View.empty()) break;
if (!View.starts_with(',')) return false; if (!View.starts_with(',')) return false;
View.remove_prefix(1); 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; return true;
@ -157,25 +164,24 @@ void Tick()
if (!bSuccessful) break; if (!bSuccessful) break;
PrintLog("Successfully loaded " + std::to_string(Result.size()) + " cached conversion mode items"); PrintLog("Successfully loaded " + std::to_string(Result.size()) + " conversion mode items");
return Result; return Result;
} }
while (false); while (false);
PrintLog("Invalid format detected in cached conversion mode configuration file"); PrintLog("Invalid format detected in conversion mode configuration file");
return Result; return Result;
};
} (); auto SaveIMEMode = [](const FIMEMode& IMEMode)
auto SaveCachedIMEMode = []
{ {
std::ofstream File(CachedModeFilename); std::ofstream File(IMEModeFilename);
if (!File.is_open()) if (!File.is_open())
{ {
PrintLog("Error: Failed to save cached conversion mode configuration"); PrintLog("Error: Failed to save conversion mode configuration");
return; return;
} }
@ -184,7 +190,7 @@ void Tick()
bool bFirstItem = true; bool bFirstItem = true;
for (const auto& [Name, Mode] : CachedIMEMode) for (const auto& [Name, Mode] : IMEMode)
{ {
if (!bFirstItem) File << ","; if (!bFirstItem) File << ",";
@ -200,6 +206,8 @@ void Tick()
File.close(); File.close();
}; };
static FIMEMode IMEMode = LoadIMEMode();
static HWND LastWindow = nullptr; static HWND LastWindow = nullptr;
static std::string CachedProcess; static std::string CachedProcess;
@ -208,7 +216,7 @@ void Tick()
{ {
do do
{ {
if (CachedIMEMode.contains(CachedProcess) && CachedIMEMode[CachedProcess] == EIMEConversionMode::Default) break; if (IMEMode.contains(CachedProcess) && IMEMode[CachedProcess] == EIMEConversionMode::Default) break;
HKL KeyboardLayout = GetKeyboardLayout(GetWindowThreadProcessId(LastWindow, nullptr)); HKL KeyboardLayout = GetKeyboardLayout(GetWindowThreadProcessId(LastWindow, nullptr));
@ -229,15 +237,15 @@ void Tick()
if (CurrentMode == EIMEConversionMode::Default) break; if (CurrentMode == EIMEConversionMode::Default) break;
if (!CachedIMEMode.contains(CachedProcess) || CachedIMEMode[CachedProcess] != CurrentMode) if (!IMEMode.contains(CachedProcess) || IMEMode[CachedProcess] != CurrentMode)
{ {
CachedIMEMode[CachedProcess] = CurrentMode; IMEMode[CachedProcess] = CurrentMode;
PrintLog("Updated cached conversion mode for process '" + CachedProcess + "' to " + PrintLog("Updated conversion mode for process '" + CachedProcess + "' to " +
(CurrentMode == EIMEConversionMode::English ? "English" : (CurrentMode == EIMEConversionMode::English ? "English" :
CurrentMode == EIMEConversionMode::Chinese ? "Chinese" : "Default")); CurrentMode == EIMEConversionMode::Chinese ? "Chinese" : "Default"));
SaveCachedIMEMode(); SaveIMEMode(IMEMode);
} }
} }
} }
@ -280,9 +288,10 @@ void Tick()
CachedProcess = Buffer; CachedProcess = Buffer;
if (!CachedIMEMode.contains(CachedProcess) || CachedIMEMode[CachedProcess] == EIMEConversionMode::Default) break; if (!IMEMode.contains(CachedProcess) || IMEMode[CachedProcess] == EIMEConversionMode::Default) break;
std::this_thread::sleep_for(50ms); // Sometimes the message will miss if we don't sleep for a little while.
std::this_thread::sleep_for(IMEMessageDelay);
if (const HWND IMEWindow = ImmGetDefaultIMEWnd(LastWindow)) if (const HWND IMEWindow = ImmGetDefaultIMEWnd(LastWindow))
{ {
@ -291,7 +300,7 @@ void Tick()
if (!OpenStatus) break; if (!OpenStatus) break;
LPARAM TargetMode = CachedIMEMode[CachedProcess] == EIMEConversionMode::Chinese ? 0x0401 : 0x0000; LPARAM TargetMode = IMEMode[CachedProcess] == EIMEConversionMode::Chinese ? 0x0401 : 0x0000;
if (ConversionMode != TargetMode) if (ConversionMode != TargetMode)
{ {
@ -369,7 +378,11 @@ int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int)
ShowWindow(MainWindow, SW_HIDE); ShowWindow(MainWindow, SW_HIDE);
const HWINEVENTHOOK FocusEventHook = SetWinEventHook( HWINEVENTHOOK FocusEventHook;
if constexpr (bEnableCallback)
{
FocusEventHook = SetWinEventHook(
EVENT_OBJECT_FOCUS, EVENT_OBJECT_FOCUS, EVENT_OBJECT_FOCUS, EVENT_OBJECT_FOCUS,
nullptr, nullptr,
FocusEventHookProc, FocusEventHookProc,
@ -386,6 +399,7 @@ int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int)
return 1; return 1;
} }
}
# if BUILD_DEBUG || BUILD_DEVELOPMENT # if BUILD_DEBUG || BUILD_DEVELOPMENT
{ {
@ -432,6 +446,27 @@ int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int)
MSG Message = { }; MSG Message = { };
if constexpr (bEnablePolling)
{
while (!GShouldExit)
{
if (PeekMessage(&Message, nullptr, 0, 0, PM_REMOVE)) {
if (Message.message == WM_QUIT) break;
TranslateMessage(&Message);
DispatchMessage (&Message);
continue;
}
Tick();
std::this_thread::sleep_for(TickInterval);
}
}
else
{
while (!GShouldExit) while (!GShouldExit)
{ {
const BOOL bResult = GetMessage(&Message, nullptr, 0, 0); const BOOL bResult = GetMessage(&Message, nullptr, 0, 0);
@ -469,6 +504,7 @@ int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int)
break; break;
} }
} }
}
PrintLog("FocusIME application is shutting down"); PrintLog("FocusIME application is shutting down");
@ -480,7 +516,10 @@ int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int)
} }
# endif # endif
if constexpr (bEnableCallback)
{
UnhookWinEvent(FocusEventHook); UnhookWinEvent(FocusEventHook);
}
DestroyWindow(MainWindow); DestroyWindow(MainWindow);