WM_AsyncServerCandidateKey 对所有候选键都用 300 ms 提交预算,回复缺失即按 「可能已上屏」处理:丢键并完整重置传输。可对 PageUp/PageDown/Up/Down/Tab(含 Shift+Tab)来说,Server 只翻页或移动高亮,回复本来就只是确认(处理函数原先的 注释也这么写),永远不会上屏。把一次慢确认升级成拆管道、清组合,代价完全不对等。 现在这几颗键走普通的 50 ms 软读取:超时只是软错过,不拆管道、不清队列,迟到 的回复按 request id 缓存;只有真正的读失败/坏帧(TransportUnavailable)才按传输 失败处理。回复内容一律不应用,因为 Server 对这些键从不提交文本。 逗号、句号、括号、减号/等号(可配置翻页,也可能以词定字或随标点上屏)、 Ctrl+Enter 译文上屏和选词键仍保留 300 ms 提交预算与「歧义即丢键 + 传输重置」。 判定放在 IsCandidateNavigationOnlyKey 里并补了单元测试。
82 lines
3.2 KiB
C++
82 lines
3.2 KiB
C++
#include "Key/DeferredKeyFailurePolicy.h"
|
|
|
|
namespace
|
|
{
|
|
using Kind = DeferredKeyFailureKind;
|
|
using Reason = DeferredKeyFailureReason;
|
|
|
|
bool Resolves(Reason reason, bool offline, Kind expected)
|
|
{
|
|
return ResolveDeferredKeyFailure(reason, offline) == expected;
|
|
}
|
|
} // namespace
|
|
|
|
int main()
|
|
{
|
|
// A superseded key never starts another reset, online or offline.
|
|
if (!Resolves(Reason::Superseded, false, Kind::Stale))
|
|
return 1;
|
|
if (!Resolves(Reason::Superseded, true, Kind::Stale))
|
|
return 2;
|
|
|
|
// Host quirks resync the composition over the healthy pipes.
|
|
if (!Resolves(Reason::HostEditRejected, false, Kind::Resync))
|
|
return 3;
|
|
if (!Resolves(Reason::EditSessionRequestFailed, false, Kind::Resync))
|
|
return 4;
|
|
if (!Resolves(Reason::AsyncPostFailed, false, Kind::Resync))
|
|
return 5;
|
|
|
|
// Offline, the local composition is the only authority: nothing to resync.
|
|
if (!Resolves(Reason::HostEditRejected, true, Kind::Offline))
|
|
return 6;
|
|
if (!Resolves(Reason::EditSessionRequestFailed, true, Kind::Offline))
|
|
return 7;
|
|
if (!Resolves(Reason::AsyncPostFailed, true, Kind::Offline))
|
|
return 8;
|
|
|
|
// A broken or ambiguous transport always takes the full reset.
|
|
if (!Resolves(Reason::TransportBroken, false, Kind::Transport))
|
|
return 9;
|
|
if (!Resolves(Reason::TransportBroken, true, Kind::Transport))
|
|
return 10;
|
|
if (!Resolves(Reason::DeliveryAmbiguous, false, Kind::Transport))
|
|
return 11;
|
|
if (!Resolves(Reason::DeliveryAmbiguous, true, Kind::Transport))
|
|
return 12;
|
|
|
|
// Edit-session outcomes: validation beats the HRESULT, ambiguity beats a
|
|
// plain transport error, and anything else is a host rejection.
|
|
if (ClassifyEditSessionFailure(true, true, true) != Reason::Superseded)
|
|
return 13;
|
|
if (ClassifyEditSessionFailure(false, true, true) != Reason::DeliveryAmbiguous)
|
|
return 14;
|
|
if (ClassifyEditSessionFailure(false, false, true) != Reason::TransportBroken)
|
|
return 15;
|
|
if (ClassifyEditSessionFailure(false, false, false) != Reason::HostEditRejected)
|
|
return 16;
|
|
|
|
// Paging and highlight moves are acknowledgement-only.
|
|
const unsigned int navigationKeys[] = {0x09 /*Tab*/, 0x21 /*PageUp*/, 0x22 /*PageDown*/, 0x26 /*Up*/,
|
|
0x28 /*Down*/};
|
|
for (const unsigned int key : navigationKeys)
|
|
{
|
|
if (!IsCandidateNavigationOnlyKey(key))
|
|
return 17;
|
|
}
|
|
// Keys the Server may turn into a commit keep the ambiguous-commit rule:
|
|
// configurable paging punctuation (, . [ ] - =), Enter (Ctrl+Enter
|
|
// translation), Space and the selection digits. Composition edit keys are
|
|
// not candidate keys at all.
|
|
const unsigned int commitCapableKeys[] = {0xBC /*,*/, 0xBE /*.*/, 0xDB /*[*/, 0xDD /*]*/, 0xBD /*-*/,
|
|
0xBB /*=*/, 0x0D /*Enter*/, 0x20 /*Space*/, '1', '9',
|
|
0x24 /*Home*/, 0x23 /*End*/, 0x25 /*Left*/, 0x27 /*Right*/};
|
|
for (const unsigned int key : commitCapableKeys)
|
|
{
|
|
if (IsCandidateNavigationOnlyKey(key))
|
|
return 18;
|
|
}
|
|
|
|
return 0;
|
|
}
|