perf(windows): 换语言热键不再每次按键重读 config.toml
_MatchChordInputHotkey 和 _MatchModifierReleaseHotkey 在 OnTestKeyDown、 OnKeyDown、OnTestKeyUp、OnKeyUp 里都要调 ReadConfiguredSwitchLanguageHotkeys, 每次都查注册表 DataDir、再逐行解析整个 config.toml,一次按键最多四遍, 全在宿主 UI 线程上,不在组合里的按键也照付。 配置路径每个进程只解析一次(环境变量固定,DataDir 只在重装时变);解析 结果按文件修改时间和大小缓存,最多每秒检查一次时间戳,设置页改了热键一秒 内生效。缓存全部常量初始化,路径对象按需分配且不释放,不引入全局构造器。
This commit is contained in:
1 parent
e3b4f432fe
commit
f87809cf59
1 file changed
+84
-7
@@ -322,15 +322,11 @@ BOOL ReadConfiguredJapaneseInputMode()
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SwitchLanguageHotkeys ReadConfiguredSwitchLanguageHotkeys()
|
||||
namespace
|
||||
{
|
||||
SwitchLanguageHotkeys ParseSwitchLanguageHotkeys(const std::filesystem::path &configPath)
|
||||
{
|
||||
SwitchLanguageHotkeys result;
|
||||
const std::filesystem::path configPath = SharedConfigPath();
|
||||
if (configPath.empty())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
std::ifstream input(configPath);
|
||||
if (!input)
|
||||
{
|
||||
@@ -401,6 +397,87 @@ SwitchLanguageHotkeys ReadConfiguredSwitchLanguageHotkeys()
|
||||
return result;
|
||||
}
|
||||
|
||||
// The key sink asks for these hotkeys on every key down and key up, on the host's UI thread.
|
||||
// Resolving the path (environment + registry) and parsing the whole config.toml each time cost
|
||||
// up to four file reads per keystroke. The path cannot change for the life of the host process
|
||||
// (the environment is fixed and DataDir only changes on reinstall), so it is resolved once; the
|
||||
// file is re-parsed only when its timestamp or size changes, checked at most once per interval
|
||||
// so a settings change still lands within a second. Everything here is constant-initialized:
|
||||
// this DLL avoids global constructors and is built with /Zc:threadSafeInit-.
|
||||
constexpr ULONGLONG kHotkeyConfigRecheckMs = 1000;
|
||||
|
||||
struct HotkeyConfigCache
|
||||
{
|
||||
bool pathResolved = false;
|
||||
bool haveStamp = false;
|
||||
ULONGLONG checkedTick = 0;
|
||||
FILETIME lastWrite = {};
|
||||
DWORD sizeLow = 0;
|
||||
DWORD sizeHigh = 0;
|
||||
SwitchLanguageHotkeys value;
|
||||
};
|
||||
|
||||
SRWLOCK g_hotkeyConfigLock = SRWLOCK_INIT;
|
||||
HotkeyConfigCache g_hotkeyConfig;
|
||||
// Heap-allocated on first use and intentionally never freed, so it needs no global destructor.
|
||||
std::filesystem::path *g_hotkeyConfigPath = nullptr;
|
||||
} // namespace
|
||||
|
||||
SwitchLanguageHotkeys ReadConfiguredSwitchLanguageHotkeys()
|
||||
{
|
||||
AcquireSRWLockExclusive(&g_hotkeyConfigLock);
|
||||
SwitchLanguageHotkeys result = g_hotkeyConfig.value;
|
||||
try
|
||||
{
|
||||
if (!g_hotkeyConfig.pathResolved)
|
||||
{
|
||||
g_hotkeyConfig.pathResolved = true;
|
||||
const std::filesystem::path configPath = SharedConfigPath();
|
||||
if (!configPath.empty())
|
||||
{
|
||||
g_hotkeyConfigPath = new std::filesystem::path(configPath);
|
||||
}
|
||||
}
|
||||
|
||||
const ULONGLONG now = GetTickCount64();
|
||||
const bool due = !g_hotkeyConfig.haveStamp || now - g_hotkeyConfig.checkedTick >= kHotkeyConfigRecheckMs;
|
||||
if (g_hotkeyConfigPath != nullptr && due)
|
||||
{
|
||||
g_hotkeyConfig.checkedTick = now;
|
||||
WIN32_FILE_ATTRIBUTE_DATA attributes{};
|
||||
if (GetFileAttributesExW(g_hotkeyConfigPath->c_str(), GetFileExInfoStandard, &attributes))
|
||||
{
|
||||
const bool changed = !g_hotkeyConfig.haveStamp ||
|
||||
CompareFileTime(&attributes.ftLastWriteTime, &g_hotkeyConfig.lastWrite) != 0 ||
|
||||
attributes.nFileSizeLow != g_hotkeyConfig.sizeLow ||
|
||||
attributes.nFileSizeHigh != g_hotkeyConfig.sizeHigh;
|
||||
if (changed)
|
||||
{
|
||||
g_hotkeyConfig.value = ParseSwitchLanguageHotkeys(*g_hotkeyConfigPath);
|
||||
g_hotkeyConfig.lastWrite = attributes.ftLastWriteTime;
|
||||
g_hotkeyConfig.sizeLow = attributes.nFileSizeLow;
|
||||
g_hotkeyConfig.sizeHigh = attributes.nFileSizeHigh;
|
||||
g_hotkeyConfig.haveStamp = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// A missing config means defaults, as the uncached read returned; the stamp
|
||||
// stays unset so the file is picked up as soon as the Server writes it.
|
||||
g_hotkeyConfig.value = SwitchLanguageHotkeys{};
|
||||
g_hotkeyConfig.haveStamp = false;
|
||||
}
|
||||
}
|
||||
result = g_hotkeyConfig.value;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Keep the last known hotkeys; a read failure must not take the key path down.
|
||||
}
|
||||
ReleaseSRWLockExclusive(&g_hotkeyConfigLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
void SendKeys(std::wstring pinyin)
|
||||
{
|
||||
for (wchar_t ch : pinyin)
|
||||
|
||||
Reference in new issue
Block a user