原「智能标点」是小狼毫 digit_separators 的语义:字母或数字后的 , . : 直出英文, 2 秒内再按同一标点转回中文——后半段靠 SendInput 往应用里补一个 Backspace 再打 字符,落点全靠光标当时在哪。这次换掉主路径:输入中文标点后按空格,用 TSF 编辑 会话就地把它改写成对应英文(。,!?;:、 → . , ! ? ; : /),2 秒内再按同一标点 键撤回中文;原来的直出降为子开关,整个家族默认全关、改为显式开启。 - 按键与会话:转换/撤回是本地文档改写,不进 IPC、不进延迟队列;判据落在 _IsKeyEaten,OnTestKeyDown 的预判与 _DispatchKeyDown 的第二遍预判共用同一份, 声称吃掉的键不交还宿主。改写走编辑会话,请求不上时另起一个最小会话把键本身 的字符写回去,避免已吃掉的键静默丢失。 - 状态:原来散落的九个成员收成一个 SmartPunctuationAction(None / ChineseCommitted / AsciiConverted),带焦点令牌、前台窗口和 beforeChar 指纹;清理以分类结果为准, 丢焦点与上下文栈变化一并清掉。 - 转换范围:。,!?;:、 与单独出现的 “”‘’【】《》() 都是映射表里的单字符 条目,路径完全一致;成对补全产生的一对(autoClosedPair)不 arm,按空格只落空格, 不会留下 <》 这类孤儿。 - 开关:总开关 + 中文标点后按空格转换 + 同键转回中文 + 数字后直出 + 字母后直出, 五键全部默认关;直出拆成数字/字母两个独立子开关(IPC 24 收窄为数字、25 追加为 字母),TSF 按前字符类型分别查键。 - 命名:子开关「独立符号」改名「中文标点后按空格转换」,配置键 smart_punctuation_standalone → smart_punctuation_space_convert,IPC 22 只改常量名 (SmartPunctuationSpaceConvertChanged),编号与语义不变、新旧测试包互通;设置页 文案同步重写,五处配置链路与死宿主一并跟改。 - 兼容:旧键未出厂、不迁移(升级合并按模板缺键丢弃、取默认 false);编号 23 随 「按空格整体转换一对」的设计退役并留空不复用。 - 验证:TSF x86/x64 与 Server Release 编译、Server 335 单测、windows_ipc_contract x64/x86、设置页 build + 27 测试、clang-format 18.1.8 全绿。真机未跑。 Signed-off-by: Jia Sui <jsfaint@gmail.com>
Product contracts
These headers are independently consumable C++17 contracts. Including them does not link the input engine, start threads, access dictionaries, or require any third-party code. The TSF text service consumes only these headers; the server consumes the same source by linking the engine. Both live in this repository — windows/ and server/ — and so does the engine, so one commit covers all three and there is no pin to keep in step.
windows_ipc.h owns the wire layouts, pipe names and opcodes. voice_composition_pipe.h owns voice framing. Consumers may wrap these headers but must not duplicate their definitions.
punctuation/policy.json is the source of truth for the ASCII punctuation keys and their Chinese
translations. Its generated policy.h is consumed by the engine and included directly by the hosts
that route punctuation keys. Stateful quote alternation and nested book-title marks remain
part of the same contract, rather than being re-created in each host.
product_lock.py contains the shared product-lock primitives used by the three platform locks.
See product_lock.md for the vendoring and byte-equality rule.
Main handshake
Reverse endpoints retain their 16-byte hello and PipeReady acknowledgement. Once both endpoints are registered, the new client sends the existing 304-byte ClientHello with:
| Field | Meaning |
|---|---|
| keycode | MSIP magic |
| wch | Major wire protocol version |
| point[0] | Minor additive version |
| modifiers_down | Supported capability bits |
| point[1] | Required capability bits |
| request_id | Nonzero registration correlation ID |
The Server sends ProtocolReady or ProtocolMismatch on the registered reply endpoint before activating the main route. The reply echoes the correlation ID and contains major/minor, negotiated capabilities and magic in the first six UTF-16 units. These packets are consumed only during registration and are never text commits.
Existing DLLs with unversioned hello remain accepted by the new Server using the established v1 semantics; they receive no new opcode. New DLLs require an acknowledgement from the new Server within the existing bounded handshake budget. Against an old or incompatible Server they remain disconnected and use the existing raw-input fallback, rather than interpreting unnegotiated frames. A late acknowledgement from an old registration cannot authorize another one.
Append opcodes; never change released values or reuse them. An incompatible layout needs a new major protocol and an explicit migration, not another copy of a header. Minor additions must be optional capabilities.
CharacterSetShortcut is optional and is not included in the default capability set.
Windows implementations that support it pass Capabilities | CharacterSetShortcut
to Hello / Negotiate. Only after negotiating this bit may a Chinese-mode client
consume Ctrl+Shift+F (no Alt or Windows modifier) and send the existing KeyEvent
with keycode F and Shift/Control modifier bits. The server toggles the persisted
character set without clearing composition, and refreshes the current candidate
page and toolbar. It sends no key reply. Clients suppress auto-repeat and must not
replay an ambiguously delivered toggle; older peers simply omit the optional bit.
tests/windows_ipc_contract.cpp executes wire-layout/upgrade/framing cases on all Engine CI platforms and both Windows TSF architectures.
backend/protocol.json 定义 MSIME-Backend 的可选共通 HTTP 服务 API,详见后端协议与兼容性。