设置页「句中辅助码触发键」可勾选反引号和分号,至少保留一个。 - 分号只在 AcceptsMarkerAt 成立(这一节是偶数键)时才当触发键;微软/搜狗/紫光双拼的 ing 韵母只跟在奇数键之后,两者不抢同一个位置,判断时分号先让给 ing 韵母 - 无论按哪个键,TSF 按键缓冲、Server raw 与引擎输入串里都记成反引号,引擎解析不变 - 新配置项 helpcode.shuangpin_mid_sentence_helpcode_backtick / _semicolon 同步写入出厂 模板、工作配置与两个设置宿主 - opcode 28 保持「反引号是否触发」、载荷单个 "0"/"1"(TSF 会丢弃更长的帧);分号走新增 的 opcode 29,旧 DLL 忽略它
80 lines
3.2 KiB
C++
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
|