feat(engine): 直接辅助码句中四码可用第二位辅码大写结束 (#630)

直接辅助码的四码在句中原来只能补 / 结束(uiab/),现在也可以把第二位辅码敲成大写(uiaB)。
设置页「直接辅助码句中四码标记」两个勾选框可多选、至少留一个,默认只勾 /。

- 引擎:拼写图新增 Aux2Upper(非缩写)。开着大写标记时大写字母只能当第二位辅码,
  走不通再退回不分大小写的旧规则,第一位辅码敲大写(uiAuiQ)照常可用。/ 的收键受勾选控制。
- 协议:DirectHelpcodeChanged 载荷改为 "0"/"1"/"2"(2 = 开着但 / 不是编码键),
  TSF 据此决定吃不吃 /。
- 配置:新增 helpcode.shuangpin_direct_helpcode_slash / _uppercase,同步写入出厂模板、
  工作配置和两个设置宿主的读写映射。
This commit is contained in:
Lu Fan(SonnyCalcr) authored and GitHub committed 2026-10-05 20:43:02 +08:00
1 parent 3c79876205
commit 53ee180ec3
29 files changed
+347 -45

No files matched your search

+24 -12
View File
@@ -13,6 +13,11 @@ bool is_letter(char ch)
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
}
bool is_upper(char ch)
{
return ch >= 'A' && ch <= 'Z';
}
char to_lower(char ch)
{
return ch >= 'A' && ch <= 'Z' ? static_cast<char>(ch + ('a' - 'A')) : ch;
@@ -60,29 +65,32 @@ std::vector<bool> forward_reach(const SpellingGraph &graph, bool normal_only)
}
SpellingGraph build_attempt(const std::string &typed, const ShuangpinProfile &profile, const AuxPredicate &has_aux,
bool symbols_as_delimiters)
const SpellingOptions &options, bool lenient)
{
SpellingGraph graph;
const std::size_t n = typed.size();
graph.size = n;
graph.edges.resize(n);
graph.skip.resize(n, false);
// 大写标记开着、又不是兜底那一遍时,大写字母只能当四码的第二位辅码。
const bool strict_case = options.uppercase_marker && !lenient;
const auto usable = [&](std::size_t index) { return !strict_case || !is_upper(typed[index]); };
for (std::size_t pos = 0; pos < n; ++pos)
{
const char ch = typed[pos];
graph.skip[pos] = ch == '\'' || (symbols_as_delimiters && (ch == '/' || ch == ';'));
if (!is_letter(ch))
graph.skip[pos] = ch == '\'' || (lenient && (ch == '/' || ch == ';'));
if (!is_letter(ch) || !usable(pos))
continue;
auto &out = graph.edges[pos];
if (pos + 1 < n && (is_letter(typed[pos + 1]) || typed[pos + 1] == ';'))
if (pos + 1 < n && ((is_letter(typed[pos + 1]) && usable(pos + 1)) || typed[pos + 1] == ';'))
{
std::string code{to_lower(ch), to_lower(typed[pos + 1])};
std::string quanpin = syllable_quanpin(code, profile);
if (!quanpin.empty())
{
out.push_back(make_spelling(pos, pos + 2, code, quanpin, SpellingKind::Plain));
if (pos + 2 < n && is_letter(typed[pos + 2]))
if (pos + 2 < n && is_letter(typed[pos + 2]) && usable(pos + 2))
{
const char first = to_lower(typed[pos + 2]);
if (has_aux && has_aux(quanpin, first, 0))
@@ -92,11 +100,15 @@ SpellingGraph build_attempt(const std::string &typed, const ShuangpinProfile &pr
const char second = to_lower(typed[pos + 3]);
if (has_aux && has_aux(quanpin, first, second))
{
if (pos + 4 < n && typed[pos + 4] == '/')
if (options.slash_marker && pos + 4 < n && typed[pos + 4] == '/')
out.push_back(
make_spelling(pos, pos + 5, code, quanpin, SpellingKind::Aux2Slash, first, second));
out.push_back(
make_spelling(pos, pos + 4, code, quanpin, SpellingKind::Aux2Abbrev, first, second));
if (options.uppercase_marker && is_upper(typed[pos + 3]))
out.push_back(
make_spelling(pos, pos + 4, code, quanpin, SpellingKind::Aux2Upper, first, second));
else
out.push_back(make_spelling(pos, pos + 4, code, quanpin, SpellingKind::Aux2Abbrev,
first, second));
}
}
}
@@ -149,15 +161,15 @@ SpellingGraph build_attempt(const std::string &typed, const ShuangpinProfile &pr
} // namespace
SpellingGraph build_spelling_graph(const std::string &typed, const ShuangpinProfile &profile,
const AuxPredicate &has_aux)
const AuxPredicate &has_aux, const SpellingOptions &options)
{
if (typed.empty())
return {};
SpellingGraph graph = build_attempt(typed, profile, has_aux, false);
SpellingGraph graph = build_attempt(typed, profile, has_aux, options, false);
if (graph.empty())
{
// 用不上的 / 和 ; 退回成分隔符,候选照常出,不至于整串作废。
graph = build_attempt(typed, profile, has_aux, true);
// 用不上的 / 和 ; 退回成分隔符、大写字母不再只当第二位辅码,候选照常出,不至于整串作废。
graph = build_attempt(typed, profile, has_aux, options, true);
}
return graph;
}