* fix(windows): 支持标点切换快捷键改绑与取消绑定 * fix(shortcut): 对齐虚拟键并处理语音与窗口快捷键冲突 * fix(ui-html): 绑定标点快捷键前提示应用快捷键占用 * fix(ui-html): 仅对已知快捷键冲突提示确认 * feat(shortcuts): 支持自定义输入状态切换快捷键 * fix: keep shortcut editor buttons on one row * fix(shortcuts): 限定输入状态快捷键为 Ctrl 组合 * fix: clarify shortcut override and punctuation lock behavior * perf(server,windows): 提前筛选输入状态快捷键 * fix(windows,server,ui-html): 修正输入状态快捷键的兼容与保存问题 - windows: 未协商 InputStateShortcuts 时回退到旧的 Ctrl+Shift+E KeyEvent, 新 DLL 配旧 Server 时英文候选快捷键不再失效 - windows: 全角快捷键与标点快捷键一样可在待处理按键后排队,不再漏给应用 - windows: Server 不可用时排队的英文候选切换按 FUNCTION_CANCEL 离线回放, 不再丢弃其后的按键 - server: 非字符串配置值不再以 "!invalid" 作为 binding 发给设置页 - server: 仅三个输入状态快捷键路径强制回传配置快照;去掉 worker 中与 reader 重复的协商检查;抽出 InputStateShortcutViews 去除重复转换 - ui-html: 保存后 5 秒未收到快照则恢复编辑器并提示重试 --------- Co-authored-by: fanlusky <1730976608@qq.com>
75 lines
2.7 KiB
C++
75 lines
2.7 KiB
C++
#pragma once
|
|
#include <string_view>
|
|
|
|
namespace FanyImeKeyChord
|
|
{
|
|
constexpr unsigned Shift = 1, Control = 2, Alt = 4, Win = 8;
|
|
struct Binding
|
|
{
|
|
unsigned key = 0, modifiers = 0;
|
|
constexpr bool Matches(unsigned code, unsigned pressed) const
|
|
{
|
|
return key != 0 && key == code && modifiers == pressed;
|
|
}
|
|
};
|
|
struct KeyName
|
|
{
|
|
std::string_view name;
|
|
unsigned key;
|
|
std::string_view label;
|
|
};
|
|
constexpr KeyName NamedKeys[] = {{"Space", 0x20, "Space"}, {"Semicolon", 0xba, ";"}, {"Equal", 0xbb, "="},
|
|
{"Comma", 0xbc, ","}, {"Minus", 0xbd, "-"}, {"Period", 0xbe, "."},
|
|
{"Slash", 0xbf, "/"}, {"Backquote", 0xc0, "`"}, {"BracketLeft", 0xdb, "["},
|
|
{"Backslash", 0xdc, "\\"}, {"BracketRight", 0xdd, "]"}, {"Quote", 0xde, "'"}};
|
|
inline constexpr unsigned KeyCode(std::string_view code)
|
|
{
|
|
if (code.size() == 4 && code.substr(0, 3) == "Key" && code[3] >= 'A' && code[3] <= 'Z')
|
|
return code[3];
|
|
if (code.size() == 6 && code.substr(0, 5) == "Digit" && code[5] >= '0' && code[5] <= '9')
|
|
return code[5];
|
|
if (code.size() == 2 && code[0] == 'F' && code[1] >= '1' && code[1] <= '9')
|
|
return 0x70 + code[1] - '1';
|
|
if (code == "F10" || code == "F11" || code == "F12")
|
|
return 0x79 + code[2] - '0';
|
|
for (const auto &entry : NamedKeys)
|
|
if (entry.name == code)
|
|
return entry.key;
|
|
return 0;
|
|
}
|
|
// Canonical Ctrl [+Shift] + one Windows virtual key. Empty disables.
|
|
inline constexpr bool Parse(std::string_view value, Binding &result)
|
|
{
|
|
result = {};
|
|
if (value.empty())
|
|
return true;
|
|
if (value.substr(0, 5) != "Ctrl+")
|
|
return false;
|
|
unsigned modifiers = Control;
|
|
value.remove_prefix(5);
|
|
if (value.substr(0, 6) == "Shift+")
|
|
{
|
|
modifiers |= Shift;
|
|
value.remove_prefix(6);
|
|
}
|
|
const unsigned key = KeyCode(value);
|
|
if (!key)
|
|
return false;
|
|
result = {key, modifiers};
|
|
return true;
|
|
}
|
|
// Stands in for a configured value that is not a string; Parse rejects it.
|
|
constexpr std::string_view InvalidValue = "!invalid";
|
|
// Used by the DLL's existing small TOML reader; invalid types stay invalid.
|
|
inline std::string_view TomlString(std::string_view value)
|
|
{
|
|
const auto begin = value.find_first_not_of(" \t\r");
|
|
if (begin == std::string_view::npos)
|
|
return InvalidValue;
|
|
value = value.substr(begin, value.find_last_not_of(" \t\r") - begin + 1);
|
|
if (value.size() >= 2 && (value.front() == '"' || value.front() == '\'') && value.back() == value.front())
|
|
return value.substr(1, value.size() - 2);
|
|
return InvalidValue;
|
|
}
|
|
} // namespace FanyImeKeyChord
|