Skip to content

Commit 2b48486

Browse files
committed
fix(bridge): push 投递三阶段 lookup 防止 activeToken 卡死时投错进程
bug 现象: 用户在 Notepad 内按 Ctrl+Shift+E 切换方案, 任务栏图标不更新; 菜单切换模式 / 全半角 等情况同理。Go 日志能看到投递目标 PID 错位: Push enqueued kind=state processID=76636 (意图: Notepad) Push pipe write completed clientID=17 processID=66896 (实际: EverEdit) 根因: server_handler.go 故意只在 CMD_IME_ACTIVATED 时更新 activeToken (兼容 EverEdit 双进程: A 进程发 FOCUS_GAINED 没 push pipe, B 进程持 push pipe 通过 IMEActivated 注册 token)。但 IMEActivated 不会随每次 焦点切换重发, 当焦点在 Notepad ↔ EverEdit 来回切时, activeProcessID 跟着更新, 但 activeToken 卡在最后一次 IMEActivated 设置的值。 pushToActiveClient / PushCommitTextToActiveClient 用 token-first 查表 直接命中错的 push handle。 修复 (pushToActiveClient + PushCommitTextToActiveClient 同步改造): - Phase 1: token != 0 且 pushHandleToPID[h] == activeProcessID 才用 → 单进程多 DLL 实例场景的精确路由 - Phase 2: pushClientsByPID[activeProcessID] 兜底 → 正常单进程场景, 即使 activeToken 卡死也能正确投递 - Phase 3: token != 0 兜底 (不校验 PID) → 兼容 EverEdit 双进程: activeProcessID 是 A, token 指向 B 的 push 测试覆盖: 现有 8 个 push_pipe 回归测试全部通过。
1 parent 1dfc972 commit 2b48486

1 file changed

Lines changed: 30 additions & 5 deletions

File tree

wind_input/internal/bridge/server_push.go

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -274,16 +274,29 @@ func (s *Server) pushToActiveClient(encoded []byte, kind string) {
274274

275275
s.pushMu.RLock()
276276
var writer *pushClient
277+
// Phase 1: token 精确匹配且 PID 一致 — 单进程多 DLL 实例场景下走这里。
278+
// 注意要校验 PID, 否则 activeToken 可能是上一次 IMEActivated 残留的(FOCUS_GAINED
279+
// 不更新 token 是为兼容 EverEdit 双进程, 见 server_handler.go), 导致 push 误投。
277280
if activeToken != 0 {
278281
if h, ok := s.tokenToPushHandle[activeToken]; ok {
279-
writer = s.pushClients[h]
282+
if s.pushHandleToPID[h] == activeProcessID {
283+
writer = s.pushClients[h]
284+
}
280285
}
281286
}
287+
// Phase 2: PID 查表 — 正常单进程场景, 覆盖 activeToken 卡死的情况。
282288
if writer == nil && activeProcessID != 0 {
283289
if h, ok := s.pushClientsByPID[activeProcessID]; ok {
284290
writer = s.pushClients[h]
285291
}
286292
}
293+
// Phase 3: token 兜底 — EverEdit 双进程场景, A 进程 (activeProcessID) 没 push pipe,
294+
// B 进程持 push pipe, 通过 IMEActivated 注册了 token, 必须走 token 才能找到 B。
295+
if writer == nil && activeToken != 0 {
296+
if h, ok := s.tokenToPushHandle[activeToken]; ok {
297+
writer = s.pushClients[h]
298+
}
299+
}
287300
s.pushMu.RUnlock()
288301

289302
if writer == nil {
@@ -356,22 +369,34 @@ func (s *Server) PushCommitTextToActiveClient(text string) {
356369
s.pushMu.RLock()
357370
var handle windows.Handle
358371
var writer *pushClient
359-
// Primary: token-based exact targeting
372+
// Phase 1: token 精确匹配且 PID 一致 (单进程多实例); activeToken 不更新于
373+
// FOCUS_GAINED, 因此 PID 校验必须的 —— 否则 token 可能指向另一个进程的
374+
// push handle (见 pushToActiveClient 注释)。
360375
if activeToken != 0 {
361376
if h, ok := s.tokenToPushHandle[activeToken]; ok {
362-
if w := s.pushClients[h]; w != nil {
363-
handle, writer = h, w
377+
if s.pushHandleToPID[h] == activeProcessID {
378+
if w := s.pushClients[h]; w != nil {
379+
handle, writer = h, w
380+
}
364381
}
365382
}
366383
}
367-
// Fallback: PID-based (token not yet registered or handle already cleaned)
384+
// Phase 2: PID 查表 (正常单进程, 覆盖 activeToken 卡死)
368385
if writer == nil && activeProcessID != 0 {
369386
if h, ok := s.pushClientsByPID[activeProcessID]; ok {
370387
if w := s.pushClients[h]; w != nil {
371388
handle, writer = h, w
372389
}
373390
}
374391
}
392+
// Phase 3: token 兜底 (EverEdit 双进程)
393+
if writer == nil && activeToken != 0 {
394+
if h, ok := s.tokenToPushHandle[activeToken]; ok {
395+
if w := s.pushClients[h]; w != nil {
396+
handle, writer = h, w
397+
}
398+
}
399+
}
375400
s.pushMu.RUnlock()
376401

377402
// Encode the commit text message using CMD_COMMIT_TEXT

0 commit comments

Comments
 (0)