Files
msime-windows/engine/contracts/mid_sentence_helpcode.h
T
fanlusky 233ac9ef33 feat(engine,server,windows,ui-html,installer): 句中辅助码触发键可多选,新增分号
设置页「句中辅助码触发键」可勾选反引号和分号,至少保留一个。

- 分号只在 AcceptsMarkerAt 成立(这一节是偶数键)时才当触发键;微软/搜狗/紫光双拼的
  ing 韵母只跟在奇数键之后,两者不抢同一个位置,判断时分号先让给 ing 韵母
- 无论按哪个键,TSF 按键缓冲、Server raw 与引擎输入串里都记成反引号,引擎解析不变
- 新配置项 helpcode.shuangpin_mid_sentence_helpcode_backtick / _semicolon 同步写入出厂
  模板、工作配置与两个设置宿主
- opcode 28 保持「反引号是否触发」、载荷单个 "0"/"1"(TSF 会丢弃更长的帧);分号走新增
  的 opcode 29,旧 DLL 忽略它
2026-10-02 23:55:46 +08:00

80 lines
3.2 KiB
C++

#pragma once
#include <cstddef>
// 双拼句中辅助码的输入形状(规则见 engine/core/syllable_helpcode.h)。
//
// TSF 在同步吃键阶段要先判断反引号是不是编码键,Server 随后按同一条规则决定收不收、引擎按它
// 解析输入串。三处必须一致:TSF 吃了而 Server 不收,两边的输入串从此分叉。TSF 不链接引擎、
// 没有音节表,所以这里只看形状,不判断前面的键是不是合法音节。
//
// 一段是反引号加至多两个字母:第一码(大小写都算)和紧跟其后的大写第二码。
//
// 触发键可以是反引号,也可以是分号(设置里多选)。无论按的是哪个,输入串里记的都是反引号:TSF 的
// 按键缓冲、Server 的 raw 和引擎解析的都是同一种串,分号在微软/搜狗/紫光双拼里还是 ing 韵母,
// 不能让它在串里有两种意思。分号只在 AcceptsMarkerAt 成立时才是触发键,那时这一节是偶数键,
// 而 ing 韵母只跟在奇数键之后,两者不会抢同一个位置。
namespace FanyImeMidSentenceHelpcode
{
inline constexpr char kMarker = '`';
inline constexpr char kSemicolonTrigger = ';';
template <typename Char> constexpr bool IsAsciiLetter(Char ch)
{
return (ch >= Char('a') && ch <= Char('z')) || (ch >= Char('A') && ch <= Char('Z'));
}
template <typename Char> constexpr bool IsAsciiUpper(Char ch)
{
return ch >= Char('A') && ch <= Char('Z');
}
// text[marker] 是反引号,返回这一段结束的位置。
template <typename Char> constexpr std::size_t BlockEnd(const Char *text, std::size_t size, std::size_t marker)
{
std::size_t end = marker + 1;
if (end < size && IsAsciiLetter(text[end]))
{
++end;
if (end < size && IsAsciiUpper(text[end]))
{
++end;
}
}
return end;
}
// text[0, size) 末尾能否接一个反引号:当前这一节(最后一个 ' 或反引号段之后)是偶数个、
// 至少两个键,也就是光标前恰好是一个个完整的双拼两键音节。
template <typename Char> constexpr bool AcceptsMarker(const Char *text, std::size_t size)
{
std::size_t chunk_start = 0;
std::size_t index = 0;
while (index < size)
{
if (text[index] == Char('\''))
{
chunk_start = ++index;
}
else if (text[index] == Char(kMarker))
{
chunk_start = index = BlockEnd(text, size, index);
}
else
{
++index;
}
}
const std::size_t chunk_length = size - chunk_start;
return chunk_length >= 2 && chunk_length % 2 == 0;
}
// 光标停在 text[caret] 时能否插入一个反引号:光标前按 AcceptsMarker 判断,后面的部分不看——
// 光标移回句中补辅助码时,它后面还有没敲完的音节。光标后紧跟的已经是这个音节的段时不收,
// 一个音节上叠两段只会让后一段把前一段盖掉。
template <typename Char> constexpr bool AcceptsMarkerAt(const Char *text, std::size_t size, std::size_t caret)
{
return caret <= size && AcceptsMarker(text, caret) && (caret == size || text[caret] != Char(kMarker));
}
} // namespace FanyImeMidSentenceHelpcode