* fix(windows,server): 提交键慢响应改为分片让出等待,不再丢字或冻结宿主 * fix(windows): 提交回复轮询不阻塞宿主,补齐标点顶候选路径并保持结算顺序 - 标点顶高亮候选(WM_AsyncPunctuationCommit 无预取文本)也在处理函数里分片取回复, edit session 不再在宿主 UI 线程上阻塞 300 ms - 轮询改为不阻塞:先查缓存、PeekNamedPipe,有帧才以零超时读,不再每片阻塞 16 ms - 定时器只重派已开始等待的请求,按请求 id 升序结算,较新的提交排在仍在等的旧提交之后 - 处理函数取到 TransportUnavailable 时直接按歧义丢键并重置,不再交给 edit session - 已在等回复的提交键在同一焦点下被组合纪元取代时按 DeliveryAmbiguous 处理,避免两端分叉 - 回复缓存淘汰不再淘汰刚写入的条目;CachePendingReply 与提交回复缓存共用一份逻辑 - 停用时显式 KillTimer(TIMER_COMMIT_REPLY_POLL);windows/AGENTS.md 同步新的提交预算 --------- Co-authored-by: fanlusky <1730976608@qq.com>
49 lines
2.4 KiB
C++
49 lines
2.4 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
|
|
namespace FanyImeIpc
|
|
{
|
|
// A digit/space selection settles against the live page_words, but the user is looking at the
|
|
// asynchronously painted CandidatePageSnapshot. Pin-frequency reorders a page after every commit, so
|
|
// a selection that runs ahead of the painted frame commits a candidate the user never saw.
|
|
//
|
|
// The wait bound is load-bearing: the TSF side waits for a committing reply within
|
|
// FANY_IME_COMMIT_REPLY_TIMEOUT_MS (1500ms, windows/src/IPC/Ipc.h) and at the end of that window
|
|
// tears the pipe down and makes the user choose again. The wait is woken by the render echo, so a
|
|
// condition variable timeout (rounded up to one timer tick, ~16ms) is the only slack on top of
|
|
// this bound; together with candidate resolution it must stay well inside that budget. The
|
|
// frequency write runs after the reply and no longer competes for it. On a slow machine (battery,
|
|
// WebView2 paint) a paint regularly takes longer than 30ms, and settling against the unpainted
|
|
// page is exactly the "committed something I did not see" bug, so the bound leaves room for a slow
|
|
// paint. On timeout the caller continues with the current data and the diagnostic log records the
|
|
// miss. Do not raise this without re-deriving the TSF budget.
|
|
constexpr int kCandidateSelectionRenderWaitMaxMs = 80;
|
|
|
|
// Header-only pure policy so tests can pin it without linking the Windows/server stack.
|
|
// Generation 0 means "never published/rendered". A host-drawn (UI-less) or invisible candidate
|
|
// window has no on-screen list to match either, so none of those cases waits.
|
|
constexpr bool ShouldWaitForCandidateRender(std::uint64_t rendered, std::uint64_t current, bool uiless,
|
|
bool visible) noexcept
|
|
{
|
|
if (uiless || !visible)
|
|
{
|
|
return false;
|
|
}
|
|
if (current == 0 || rendered == 0)
|
|
{
|
|
return false;
|
|
}
|
|
return rendered < current;
|
|
}
|
|
|
|
// The render echo only moves forward. WebView2 echoes from async DOM callbacks, so a content-only
|
|
// update's callback can land after a dedup of the same content already echoed the newer generation;
|
|
// storing the older one left rendered one behind published and every selection waited out the full
|
|
// bound.
|
|
constexpr std::uint64_t AdvanceRenderedCandidateGeneration(std::uint64_t rendered, std::uint64_t echoed) noexcept
|
|
{
|
|
return echoed > rendered ? echoed : rendered;
|
|
}
|
|
} // namespace FanyImeIpc
|