Skip to content

Commit 1dfc972

Browse files
committed
fix(tsf): _HandleServiceResponse 不再吃掉 StatusUpdate, 修 Shift 后 IPC 断连
bug 现象: 用户在某 app 内按 Shift (模式切换 hotkey) → 后续 Ctrl+Space 完全失效, 任务栏图标也卡死。日志显示 Shift 发出后 200ms timeout 断连。 根因: _HandleServiceResponse 里有一个历史 loop —— 早期 state push 借 bridge pipe 道, 所以同步操作要扫掉中间夹的 push 才能拿到真响应。该 loop 对 ResponseType::StatusUpdate 的处理是 "调 UpdateFullStatus + continue read"。 push pipe 独立成专用 connection 后这个 loop 已经过时, 但 StatusUpdate 新近又成为 lshift/SystemModeSwitch/OnClick 的正式响应类型 ——loop 把 正式响应当 push 吞掉, 紧接着 ReceiveResponse 等不到下一条而 200ms timeout, bridge pipe 断连。之后 Ctrl+Space 走 OPENCLOSE compartment 路径调 SendSystemModeSwitch 时 _pIPCClient->IsConnected() == false, 整段 if 跳过, 只做 local toggle, _SetConversionMode + UpdateFullStatus 全都没执行。 修复: 删除 loop, 改成单次 ReceiveResponse。StatusUpdate 现在落到外层 switch 的 case ResponseType::StatusUpdate, 走完整 UpdateFullStatus (同时同步 mirror + TSF compartments + LangBar UI)。
1 parent cd2ef05 commit 1dfc972

1 file changed

Lines changed: 15 additions & 50 deletions

File tree

wind_tsf/src/KeyEventSink.cpp

Lines changed: 15 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,7 +1110,7 @@ STDAPI CKeyEventSink::OnKeyUp(ITfContext* pContext, WPARAM wParam, LPARAM lParam
11101110

11111111
// For Shift/Ctrl toggle: Send KeyUp event to Go service
11121112
// Go side will check config (e.g., only LShift vs both L/R Shift)
1113-
// and return ModeChanged response if the key is configured as toggle key
1113+
// and return StatusUpdate response if the key is configured as toggle key
11141114
if (pendingKey != VK_CAPITAL)
11151115
{
11161116
WIND_LOG_DEBUG_FMT(L"Sending toggle key KeyUp to Go: vk=0x%02X\n", pendingKey);
@@ -1140,7 +1140,7 @@ STDAPI CKeyEventSink::OnKeyUp(ITfContext* pContext, WPARAM wParam, LPARAM lParam
11401140
_pTextService->SendCaretPositionUpdate();
11411141

11421142
// Send KeyUp event to Go service (SYNC mode, wait for response)
1143-
// Go will check config and return ModeChanged if key is configured as toggle
1143+
// Go will check config and return StatusUpdate if key is configured as toggle
11441144
// All state changes go through Go service - no local fallback
11451145
if (_SendKeyToService(pendingKey, mods, KEY_EVENT_UP))
11461146
{
@@ -1526,44 +1526,17 @@ BOOL CKeyEventSink::_HandleServiceResponse()
15261526

15271527
ServiceResponse response;
15281528

1529-
// Loop to handle any StatusUpdate (state push) messages that may precede the actual response
1530-
// This is necessary because Go service may push state updates before the operation response
1531-
while (true)
1529+
// Bridge pipe 上的响应直接读一次即可。state push 已迁到独立 push pipe (由 async
1530+
// reader 处理), 不会再夹在 bridge response 之前; 而 StatusUpdate 现在是 lshift/
1531+
// OnClick/SystemModeSwitch 等同步操作的正式响应类型, 必须返回给外层 switch 走
1532+
// case StatusUpdate 分支 (UpdateFullStatus + 同步 TSF compartments)。
1533+
// 旧版本这里有一个吃掉 StatusUpdate 并 continue 的 loop, 是历史遗留: 早期
1534+
// state push 借 bridge pipe 道, 现在已废弃。继续保留会导致 lshift 响应被吃掉,
1535+
// 后续 ReceiveResponse 等不到下一条而 200ms timeout 断连 (Ctrl+Space 失效根因)。
1536+
if (!pIPCClient->ReceiveResponse(response))
15321537
{
1533-
if (!pIPCClient->ReceiveResponse(response))
1534-
{
1535-
WIND_LOG_ERROR(L"Failed to receive response from service");
1536-
return TRUE; // Default to eating the key on error
1537-
}
1538-
1539-
// If this is a StatusUpdate (state push), process it and continue reading
1540-
if (response.type == ResponseType::StatusUpdate)
1541-
{
1542-
WIND_LOG_DEBUG(L"Received StatusUpdate (state push), processing and reading next response\n");
1543-
1544-
// Update input mode from state push (with icon label from Go service)
1545-
_pTextService->UpdateFullStatus(
1546-
response.IsChineseMode(),
1547-
response.IsFullWidth(),
1548-
response.IsChinesePunct(),
1549-
response.IsToolbarVisible(),
1550-
response.IsCapsLock(),
1551-
response.iconLabel.empty() ? nullptr : response.iconLabel.c_str()
1552-
);
1553-
1554-
// Update hotkey whitelist if present
1555-
CHotkeyManager* pHotkeyMgr = _pTextService->GetHotkeyManager();
1556-
if (pHotkeyMgr != nullptr && response.HasHotkeys())
1557-
{
1558-
pHotkeyMgr->UpdateHotkeys(response.keyDownHotkeys, response.keyUpHotkeys);
1559-
}
1560-
1561-
// Continue reading to get the actual operation response
1562-
continue;
1563-
}
1564-
1565-
// Got a non-StatusUpdate response, break out of loop to process it
1566-
break;
1538+
WIND_LOG_ERROR(L"Failed to receive response from service");
1539+
return TRUE; // Default to eating the key on error
15671540
}
15681541

15691542
QueryPerformanceCounter(&midTime);
@@ -1659,18 +1632,10 @@ BOOL CKeyEventSink::_HandleServiceResponse()
16591632
_pTextService->EndComposition();
16601633
return TRUE;
16611634

1662-
case ResponseType::ModeChanged:
1663-
WIND_LOG_DEBUG(L"Received ModeChanged from service\n");
1664-
_isComposing = FALSE;
1665-
_hasCandidates = FALSE;
1666-
_pTextService->NotifyCandidatesVisibilityChanged(FALSE);
1667-
_pTextService->EndComposition();
1668-
_pTextService->SetInputMode(response.chineseMode);
1669-
return TRUE;
1670-
16711635
case ResponseType::StatusUpdate:
1672-
// StatusUpdate is normally handled in the loop above, but if we get here
1673-
// it means we received a StatusUpdate as the final response (e.g., from FocusGained)
1636+
// StatusUpdate 是 lshift/SystemModeSwitch/FocusGained/IMEActivated 等同步操作
1637+
// 的标准响应类型 (自包含 mode + iconLabel + hotkeys), 走 UpdateFullStatus 一并
1638+
// 同步 _bChineseMode mirror + TSF compartments + LangBar UI。
16741639
WIND_LOG_DEBUG(L"Received StatusUpdate as final response\n");
16751640
_pTextService->UpdateFullStatus(
16761641
response.IsChineseMode(),

0 commit comments

Comments
 (0)