Add logs.
This commit is contained in:
1 parent
e42cc92b8e
commit
2e44cc4e24
11 files changed
+280
-8
No files matched your search
@@ -124,6 +124,8 @@ set(SRC_FILES
|
||||
"./src/kaomoji/kaomoji_ime.h"
|
||||
"./src/log/fanylog.cpp"
|
||||
"./src/log/fanylog.h"
|
||||
"./src/log/candidate_diag_log.cpp"
|
||||
"./src/log/candidate_diag_log.h"
|
||||
"./src/log/ftb_diag_log.cpp"
|
||||
"./src/log/ftb_diag_log.h"
|
||||
"./src/quick-phrases/quick_phrase_query.cpp"
|
||||
|
||||
@@ -10,6 +10,8 @@ theme = "dark"
|
||||
# 通用
|
||||
#
|
||||
[general]
|
||||
# 候选框诊断日志(默认关闭;不记录输入内容或候选文本)
|
||||
candidate_window_diagnostic_log = false
|
||||
# 悬浮工具栏
|
||||
floating_toolbar = true
|
||||
# 悬浮工具栏组件(中英文切换始终显示)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "ime_config.h"
|
||||
#include <fmt/xchar.h>
|
||||
#include <Windows.h>
|
||||
#include <atomic>
|
||||
#include <dwrite.h>
|
||||
#include <wrl/client.h>
|
||||
#include <winreg.h>
|
||||
@@ -53,6 +54,7 @@ std::string g_candidate_english_font = "Segoe UI";
|
||||
std::string g_candidate_default_font = "Microsoft YaHei";
|
||||
int g_candidate_font_size = 16;
|
||||
int g_candidate_window_preedit_font_size = 16;
|
||||
std::atomic_bool g_candidate_window_diagnostic_log_enabled{false};
|
||||
std::string g_candidate_text_color = "auto";
|
||||
std::string g_shuangpin_schema = "xiaohe";
|
||||
std::string g_wubi_schema = "wubi86";
|
||||
@@ -648,6 +650,8 @@ bool LoadImeConfig()
|
||||
g_show_quanpin_helpcode_in_candidate_window =
|
||||
tbl["helpcode"]["show_qp_helpcode_in_candidate_window"].value_or(true);
|
||||
g_floating_toolbar_enabled = tbl["general"]["floating_toolbar"].value_or(true);
|
||||
g_candidate_window_diagnostic_log_enabled.store(
|
||||
tbl["general"]["candidate_window_diagnostic_log"].value_or(false), std::memory_order_relaxed);
|
||||
g_floating_toolbar_items.fullwidth = tbl["general"]["floating_toolbar_fullwidth"].value_or(true);
|
||||
g_floating_toolbar_items.punctuation = tbl["general"]["floating_toolbar_punctuation"].value_or(true);
|
||||
g_floating_toolbar_items.character_set = tbl["general"]["floating_toolbar_character_set"].value_or(true);
|
||||
@@ -1266,6 +1270,19 @@ bool SetConfiguredCandidateWindowPreeditFontSize(int font_size)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetConfiguredCandidateWindowDiagnosticLogEnabled()
|
||||
{
|
||||
return g_candidate_window_diagnostic_log_enabled.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
bool SetConfiguredCandidateWindowDiagnosticLogEnabled(bool enabled)
|
||||
{
|
||||
if (!WriteConfiguredValue("general", "candidate_window_diagnostic_log", enabled ? "true" : "false"))
|
||||
return false;
|
||||
g_candidate_window_diagnostic_log_enabled.store(enabled, std::memory_order_relaxed);
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool IsValidCandidateTextColor(const std::string &color)
|
||||
|
||||
@@ -130,6 +130,8 @@ int GetConfiguredCandidateFontSize();
|
||||
bool SetConfiguredCandidateFontSize(int font_size);
|
||||
int GetConfiguredCandidateWindowPreeditFontSize();
|
||||
bool SetConfiguredCandidateWindowPreeditFontSize(int font_size);
|
||||
bool GetConfiguredCandidateWindowDiagnosticLogEnabled();
|
||||
bool SetConfiguredCandidateWindowDiagnosticLogEnabled(bool enabled);
|
||||
const std::string &GetConfiguredCandidateTextColor();
|
||||
bool SetConfiguredCandidateTextColor(const std::string &color);
|
||||
// Installed font family names for settings dropdowns (cached after first call).
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "kaomoji/kaomoji_query.h"
|
||||
#include "kaomoji/kaomoji_ime.h"
|
||||
#include "jianpin/jianpin_query.h"
|
||||
#include "log/candidate_diag_log.h"
|
||||
#include "log/ftb_diag_log.h"
|
||||
#include "voice-input/voice_input_service.h"
|
||||
#include <cwchar>
|
||||
@@ -208,8 +209,11 @@ void RequestShowCandidateWindow()
|
||||
{
|
||||
if (IsUiLessMode() || !::global_hwnd)
|
||||
{
|
||||
CAND_DIAG_LOGF(L"show request skipped uiless={} hwnd_present={}", IsUiLessMode(), ::global_hwnd != nullptr);
|
||||
return;
|
||||
}
|
||||
CAND_DIAG_LOGF(L"show request posted raw_units={} candidate_count={}",
|
||||
GlobalIme::composition.raw_input_with_cases.size(), Global::candidate_ui.items.size());
|
||||
PostMessage(::global_hwnd, WM_SHOW_MAIN_WINDOW, 0, 0);
|
||||
}
|
||||
|
||||
@@ -1021,6 +1025,11 @@ void RefreshCandidatePageUi(bool show_window)
|
||||
{
|
||||
::WriteDataToSharedMemory(string_to_wstring(candidate_string), true);
|
||||
}
|
||||
CAND_DIAG_LOGF(L"candidate UI refreshed show={} uiless={} items={} page_words={} selected={} page={} "
|
||||
L"serialized_units={}",
|
||||
show_window, IsUiLessMode(), Global::candidate_ui.items.size(),
|
||||
Global::candidate_ui.page_words.size(), Global::candidate_ui.selected_index_in_page,
|
||||
Global::candidate_ui.page_index, candidate_string.size());
|
||||
if (show_window)
|
||||
{
|
||||
RequestShowCandidateWindow();
|
||||
@@ -1030,6 +1039,7 @@ void RefreshCandidatePageUi(bool show_window)
|
||||
void LogPipeConnectResult(const wchar_t *pipe_name, BOOL connected)
|
||||
{
|
||||
const DWORD gle = connected ? ERROR_SUCCESS : GetLastError();
|
||||
CAND_DIAG_LOGF(L"pipe connect name={} connected={} gle={}", pipe_name, connected != FALSE, gle);
|
||||
if (connected)
|
||||
{
|
||||
FANY_IPC_LOGF(L"[msime]: [ipc] {} connected", pipe_name);
|
||||
@@ -1042,13 +1052,16 @@ void LogPipeConnectResult(const wchar_t *pipe_name, BOOL connected)
|
||||
|
||||
void LogPipeReadFailure(const wchar_t *pipe_name, DWORD bytes_read)
|
||||
{
|
||||
const DWORD gle = GetLastError();
|
||||
FANY_IPC_LOGF(L"[msime]: [ipc] {} ReadFile failed or returned empty: gle={}, bytes_read={}", pipe_name,
|
||||
GetLastError(), bytes_read);
|
||||
gle, bytes_read);
|
||||
CAND_DIAG_LOGF(L"pipe read failure name={} gle={} bytes={}", pipe_name, gle, bytes_read);
|
||||
}
|
||||
|
||||
void LogPipeDisconnect(const wchar_t *pipe_name)
|
||||
{
|
||||
FANY_IPC_LOGF(L"[msime]: [ipc] {} disconnected", pipe_name);
|
||||
CAND_DIAG_LOGF(L"pipe disconnected name={}", pipe_name);
|
||||
}
|
||||
|
||||
void LogPipeEvent(const wchar_t *pipe_name, UINT event_type, UINT keycode, WCHAR wch, UINT modifiers_down)
|
||||
@@ -1391,6 +1404,9 @@ void WorkerThread()
|
||||
FTB_DIAG_LOGF(L"task {} epoch={} rejected as stale",
|
||||
task.type == TaskType::ClientDeactivated ? L"ClientDeactivated" : L"ClientSuspended",
|
||||
task.activation_epoch);
|
||||
CAND_DIAG_LOGF(L"candidate lifecycle task rejected stale type={} epoch={}",
|
||||
task.type == TaskType::ClientDeactivated ? L"deactivated" : L"suspended",
|
||||
task.activation_epoch);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -1428,6 +1444,9 @@ void WorkerThread()
|
||||
// refreshes (creating-word progress and candidate context-menu
|
||||
// actions), whose current packet does not carry a valid point.
|
||||
::ReadDataFromNamedPipe(0b111111);
|
||||
CAND_DIAG_LOGF(L"task ShowCandidate client={} epoch={} request={} caret=({},{}) input_units={}",
|
||||
task.client_id, task.activation_epoch, task.pipe_data.request_id, Global::Point[0],
|
||||
Global::Point[1], GlobalIme::composition.raw_input_with_cases.size());
|
||||
PrepareCandidateList(task.client_id, task.activation_epoch);
|
||||
RequestShowCandidateWindow();
|
||||
break;
|
||||
@@ -1435,6 +1454,8 @@ void WorkerThread()
|
||||
|
||||
case TaskType::HideCandidate: {
|
||||
::ReadDataFromNamedPipe(0b100000);
|
||||
CAND_DIAG_LOGF(L"task HideCandidate client={} epoch={} request={}", task.client_id,
|
||||
task.activation_epoch, task.pipe_data.request_id);
|
||||
PostMessage(::global_hwnd, WM_HIDE_MAIN_WINDOW, 0, 0);
|
||||
/* 清理状态 */
|
||||
ClearState();
|
||||
@@ -1444,6 +1465,8 @@ void WorkerThread()
|
||||
case TaskType::MoveCandidate: {
|
||||
static int cnt = 0;
|
||||
::ReadDataFromNamedPipe(0b001000);
|
||||
CAND_DIAG_LOGF(L"task MoveCandidate client={} epoch={} caret=({},{})", task.client_id,
|
||||
task.activation_epoch, Global::Point[0], Global::Point[1]);
|
||||
PostMessage(::global_hwnd, WM_MOVE_CANDIDATE_WINDOW, 0, 0);
|
||||
break;
|
||||
}
|
||||
@@ -1527,6 +1550,8 @@ void WorkerThread()
|
||||
}
|
||||
|
||||
case TaskType::ClientActivated: {
|
||||
CAND_DIAG_LOGF(L"client activated client={} epoch={} hwnd_present={}", task.client_id,
|
||||
task.activation_epoch, ::global_hwnd != nullptr);
|
||||
VoiceInput::SetImeActive(true);
|
||||
// Activation replaces all composition/candidate state from the
|
||||
// previous focus session. A terminal TIP activation also makes
|
||||
@@ -1564,6 +1589,7 @@ void WorkerThread()
|
||||
}
|
||||
|
||||
case TaskType::ClientDeactivated: {
|
||||
CAND_DIAG_LOGF(L"client deactivated client={} epoch={}", task.client_id, task.activation_epoch);
|
||||
VoiceInput::SetImeActive(false);
|
||||
// Unlike a route-only suspension, terminal TIP deactivation means
|
||||
// the user switched to another input method.
|
||||
@@ -1583,6 +1609,7 @@ void WorkerThread()
|
||||
}
|
||||
|
||||
case TaskType::ClientSuspended: {
|
||||
CAND_DIAG_LOGF(L"client suspended client={} epoch={}", task.client_id, task.activation_epoch);
|
||||
// A suspension rotates the IPC focus session while the TIP may
|
||||
// still own thread focus. It clears candidates just like terminal
|
||||
// deactivation, but never changes floating-toolbar visibility.
|
||||
@@ -2390,6 +2417,8 @@ void MainPipeClientThread(HANDLE clientPipe, uint64_t handlerId)
|
||||
{
|
||||
FANY_IPC_LOGF(L"[msime]: [ipc] ignored inactive main-pipe event: client_id={}, type={}", clientId,
|
||||
pipeData.event_type);
|
||||
CAND_DIAG_LOGF(L"main-pipe event ignored inactive client={} type={} request={}", clientId,
|
||||
pipeData.event_type, pipeData.request_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
#include "candidate_diag_log.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include "config/ime_config.h"
|
||||
#include "global/globals.h"
|
||||
#include "utils/common_utils.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr unsigned long long kMaxLogBytes = 4ull * 1024ull * 1024ull;
|
||||
|
||||
std::mutex g_log_mutex;
|
||||
bool g_path_resolved = false;
|
||||
std::wstring g_log_path;
|
||||
|
||||
const std::wstring &ResolveLogPathUnlocked()
|
||||
{
|
||||
if (g_path_resolved)
|
||||
return g_log_path;
|
||||
g_path_resolved = true;
|
||||
|
||||
const std::string local_appdata = CommonUtils::get_local_appdata_path();
|
||||
if (local_appdata.empty())
|
||||
return g_log_path;
|
||||
|
||||
const std::wstring app_directory = string_to_wstring(local_appdata) + L"\\" + GlobalIme::AppName;
|
||||
const std::wstring log_directory = app_directory + L"\\logs";
|
||||
CreateDirectoryW(app_directory.c_str(), nullptr);
|
||||
if (!CreateDirectoryW(log_directory.c_str(), nullptr) && GetLastError() != ERROR_ALREADY_EXISTS)
|
||||
return g_log_path;
|
||||
|
||||
g_log_path = log_directory + L"\\candidate-window-diagnostic.log";
|
||||
return g_log_path;
|
||||
}
|
||||
|
||||
void RotateIfOversizedUnlocked(const std::wstring &path)
|
||||
{
|
||||
WIN32_FILE_ATTRIBUTE_DATA attributes{};
|
||||
if (!GetFileAttributesExW(path.c_str(), GetFileExInfoStandard, &attributes))
|
||||
return;
|
||||
const unsigned long long size =
|
||||
(static_cast<unsigned long long>(attributes.nFileSizeHigh) << 32) | attributes.nFileSizeLow;
|
||||
if (size < kMaxLogBytes)
|
||||
return;
|
||||
|
||||
const std::wstring previous = path + L".1";
|
||||
DeleteFileW(previous.c_str());
|
||||
MoveFileW(path.c_str(), previous.c_str());
|
||||
}
|
||||
|
||||
std::wstring Timestamp()
|
||||
{
|
||||
SYSTEMTIME now{};
|
||||
GetLocalTime(&now);
|
||||
wchar_t buffer[40]{};
|
||||
swprintf_s(buffer, L"%04u-%02u-%02u %02u:%02u:%02u.%03u", static_cast<unsigned>(now.wYear),
|
||||
static_cast<unsigned>(now.wMonth), static_cast<unsigned>(now.wDay), static_cast<unsigned>(now.wHour),
|
||||
static_cast<unsigned>(now.wMinute), static_cast<unsigned>(now.wSecond),
|
||||
static_cast<unsigned>(now.wMilliseconds));
|
||||
return buffer;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace CandidateDiag
|
||||
{
|
||||
bool IsEnabled()
|
||||
{
|
||||
return GetConfiguredCandidateWindowDiagnosticLogEnabled();
|
||||
}
|
||||
|
||||
void Write(const std::wstring &line)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_log_mutex);
|
||||
const std::wstring &path = ResolveLogPathUnlocked();
|
||||
if (path.empty())
|
||||
return;
|
||||
RotateIfOversizedUnlocked(path);
|
||||
|
||||
const std::wstring record = Timestamp() + L" [p" + std::to_wstring(GetCurrentProcessId()) + L":t" +
|
||||
std::to_wstring(GetCurrentThreadId()) + L"] " + line + L"\r\n";
|
||||
const std::string utf8 = wstring_to_string(record);
|
||||
|
||||
HANDLE file = CreateFileW(path.c_str(), FILE_APPEND_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (file == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
if (GetLastError() != ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
const char bom[] = "\xEF\xBB\xBF";
|
||||
DWORD written = 0;
|
||||
WriteFile(file, bom, 3, &written, nullptr);
|
||||
}
|
||||
|
||||
DWORD written = 0;
|
||||
WriteFile(file, utf8.data(), static_cast<DWORD>(utf8.size()), &written, nullptr);
|
||||
CloseHandle(file);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Diagnostics must never affect the input path.
|
||||
}
|
||||
}
|
||||
} // namespace CandidateDiag
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "fmt/xchar.h"
|
||||
|
||||
// Diagnostic trace for candidate-window disappearance investigations. The
|
||||
// trace deliberately records only state, counts, identifiers, coordinates and
|
||||
// error codes; user input and candidate text must never be written here.
|
||||
namespace CandidateDiag
|
||||
{
|
||||
// When disabled, call sites pay for one relaxed atomic load and do not format
|
||||
// strings or touch the filesystem.
|
||||
bool IsEnabled();
|
||||
|
||||
// Appends one timestamped line. Thread-safe, bounded by rotation, never throws.
|
||||
void Write(const std::wstring &line);
|
||||
} // namespace CandidateDiag
|
||||
|
||||
#define CAND_DIAG_LOGF(...) \
|
||||
do \
|
||||
{ \
|
||||
if (::CandidateDiag::IsEnabled()) \
|
||||
{ \
|
||||
::CandidateDiag::Write(fmt::format(__VA_ARGS__)); \
|
||||
} \
|
||||
} while (0)
|
||||
@@ -237,7 +237,8 @@ void PostConfig()
|
||||
{"smart_punctuation_repeat_to_chinese", GetConfiguredSmartPunctuationRepeatToChineseEnabled()},
|
||||
{"paired_punctuation", GetConfiguredPairedPunctuationEnabled()}}},
|
||||
{"general",
|
||||
{{"floating_toolbar", GetConfiguredFloatingToolbarEnabled()},
|
||||
{{"candidate_window_diagnostic_log", GetConfiguredCandidateWindowDiagnosticLogEnabled()},
|
||||
{"floating_toolbar", GetConfiguredFloatingToolbarEnabled()},
|
||||
{"floating_toolbar_fullwidth", toolbar.fullwidth},
|
||||
{"floating_toolbar_punctuation", toolbar.punctuation},
|
||||
{"floating_toolbar_character_set", toolbar.character_set},
|
||||
@@ -433,6 +434,8 @@ bool ApplyConfigUpdate(const json::object &data)
|
||||
return SetConfiguredThemeVoice(json::value_to<std::string>(data.at("value")));
|
||||
if (path == "general.floating_toolbar")
|
||||
return SetConfiguredFloatingToolbarEnabled(json::value_to<bool>(data.at("value")));
|
||||
if (path == "general.candidate_window_diagnostic_log")
|
||||
return SetConfiguredCandidateWindowDiagnosticLogEnabled(json::value_to<bool>(data.at("value")));
|
||||
if (path == "general.floating_toolbar_scale")
|
||||
{
|
||||
const json::value &value = data.at("value");
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "ipc/ipc.h"
|
||||
#include "ipc/event_listener.h"
|
||||
#include "ipc/candidate_ui_action_policy.h"
|
||||
#include "log/candidate_diag_log.h"
|
||||
#include "log/ftb_diag_log.h"
|
||||
#include "settings/settings_launcher.h"
|
||||
#include "utils/window_utils.h"
|
||||
@@ -961,6 +962,11 @@ bool AreSmallWindowWebviewsReady()
|
||||
return AreSmallWindowWebviewsReadyUnlocked();
|
||||
}
|
||||
|
||||
bool IsCandidateWebviewReady()
|
||||
{
|
||||
return candidateNavigationReady && webviewCandWnd != nullptr && webviewControllerCandWnd != nullptr;
|
||||
}
|
||||
|
||||
bool IsFloatingToolbarWebviewReady()
|
||||
{
|
||||
return floatingToolbarNavigationReady && webviewControllerFtbWnd != nullptr;
|
||||
@@ -1085,6 +1091,18 @@ void UpdateSmallWindowWebviewVisibility(HWND hwnd, bool visible)
|
||||
}
|
||||
}
|
||||
|
||||
bool GetCandidateWebviewState(bool &isVisible, RECT &bounds)
|
||||
{
|
||||
if (!webviewControllerCandWnd)
|
||||
return false;
|
||||
BOOL visible = FALSE;
|
||||
if (FAILED(webviewControllerCandWnd->get_IsVisible(&visible)) ||
|
||||
FAILED(webviewControllerCandWnd->get_Bounds(&bounds)))
|
||||
return false;
|
||||
isVisible = visible != FALSE;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::wstring ReadHtmlFile(const std::wstring &filePath)
|
||||
{
|
||||
std::wifstream file(filePath);
|
||||
@@ -1606,6 +1624,8 @@ HRESULT OnControllerCreatedCandWnd( //
|
||||
ICoreWebView2Controller *controller //
|
||||
)
|
||||
{
|
||||
CAND_DIAG_LOGF(L"webview controller callback hr={:#x} controller_present={} hwnd_valid={}",
|
||||
static_cast<unsigned>(result), controller != nullptr, IsWindow(hwnd) != FALSE);
|
||||
if (!controller || FAILED(result))
|
||||
{
|
||||
OnSmallWindowControllerSettled(FAILED(result) ? result : E_FAIL);
|
||||
@@ -1617,6 +1637,7 @@ HRESULT OnControllerCreatedCandWnd( //
|
||||
|
||||
if (!webviewCandWnd)
|
||||
{
|
||||
CAND_DIAG_LOGF(L"webview get_CoreWebView2 failed hr={:#x}", static_cast<unsigned>(getWebviewHr));
|
||||
webviewControllerCandWnd.Reset();
|
||||
OnSmallWindowControllerSettled(FAILED(getWebviewHr) ? getWebviewHr : E_FAIL);
|
||||
return E_FAIL;
|
||||
@@ -1696,6 +1717,8 @@ HRESULT OnControllerCreatedCandWnd( //
|
||||
|
||||
// Navigate to HTML
|
||||
HRESULT hr = webviewCandWnd->NavigateToString(HTMLStringCandWnd.c_str());
|
||||
CAND_DIAG_LOGF(L"webview NavigateToString hr={:#x} html_chars={} skin={}", static_cast<unsigned>(hr),
|
||||
HTMLStringCandWnd.size(), string_to_wstring(preparedCandidateSkin));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
loadedCandidateSkin = preparedCandidateSkin;
|
||||
@@ -1847,7 +1870,10 @@ HRESULT OnControllerCreatedCandWnd( //
|
||||
COREWEBVIEW2_WEB_ERROR_STATUS errorStatus = COREWEBVIEW2_WEB_ERROR_STATUS_UNKNOWN;
|
||||
const HRESULT successHr = args->get_IsSuccess(&success);
|
||||
const HRESULT statusHr = args->get_WebErrorStatus(&errorStatus);
|
||||
(void)0;
|
||||
CAND_DIAG_LOGF(L"webview navigation completed success={} success_hr={:#x} status_hr={:#x} "
|
||||
L"web_error={} logical_shown={}",
|
||||
success != FALSE, static_cast<unsigned>(successHr), static_cast<unsigned>(statusHr),
|
||||
static_cast<int>(errorStatus), ::is_global_wnd_cand_shown);
|
||||
if (success)
|
||||
{
|
||||
NotifySmallWindowNavigationReady(candidateNavigationReady, L"candidate");
|
||||
@@ -1882,7 +1908,8 @@ HRESULT OnControllerCreatedCandWnd( //
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND kind =
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED;
|
||||
const HRESULT hr = args->get_ProcessFailedKind(&kind);
|
||||
(void)0;
|
||||
CAND_DIAG_LOGF(L"webview process failed kind={} hr={:#x}",
|
||||
static_cast<int>(kind), static_cast<unsigned>(hr));
|
||||
return S_OK;
|
||||
})
|
||||
.Get(),
|
||||
@@ -2817,6 +2844,15 @@ HRESULT OnControllerCreatedSettingsWnd( //
|
||||
PostSettingsConfig();
|
||||
}
|
||||
}
|
||||
else if (path == "general.candidate_window_diagnostic_log")
|
||||
{
|
||||
const bool value = json::value_to<bool>(data.at("value"));
|
||||
if (SetConfiguredCandidateWindowDiagnosticLogEnabled(value))
|
||||
{
|
||||
CAND_DIAG_LOGF(L"diagnostic logging enabled from Settings");
|
||||
PostSettingsConfig();
|
||||
}
|
||||
}
|
||||
else if (path.rfind("tencent_tmt.", 0) == 0)
|
||||
{
|
||||
const std::string value = json::value_to<std::string>(data.at("value"));
|
||||
@@ -3167,7 +3203,8 @@ void PostSettingsConfig()
|
||||
{"smart_punctuation_repeat_to_chinese", GetConfiguredSmartPunctuationRepeatToChineseEnabled()},
|
||||
{"paired_punctuation", GetConfiguredPairedPunctuationEnabled()}}},
|
||||
{"general",
|
||||
{{"floating_toolbar", GetConfiguredFloatingToolbarEnabled()},
|
||||
{{"candidate_window_diagnostic_log", GetConfiguredCandidateWindowDiagnosticLogEnabled()},
|
||||
{"floating_toolbar", GetConfiguredFloatingToolbarEnabled()},
|
||||
{"floating_toolbar_fullwidth", toolbar.fullwidth},
|
||||
{"floating_toolbar_punctuation", toolbar.punctuation},
|
||||
{"floating_toolbar_character_set", toolbar.character_set},
|
||||
|
||||
@@ -99,6 +99,7 @@ bool EnsureSmallWindowsTopmost(const wchar_t *reason);
|
||||
// after the WebViews report ready.
|
||||
bool AreSmallWindowsTopmostApplied();
|
||||
bool AreSmallWindowWebviewsReady();
|
||||
bool IsCandidateWebviewReady();
|
||||
// True once the floating toolbar's WebView2 has completed its first navigation
|
||||
// and can actually paint. Its host must stay on-monitor and "visible" until
|
||||
// then, otherwise WebView2 never finishes raster setup for it.
|
||||
@@ -122,6 +123,7 @@ bool GetFloatingToolbarWebviewState(bool &isVisible, RECT &bounds);
|
||||
// Same for the tray menu, whose blank-but-clickable failure mode needs exactly
|
||||
// this to be separated from a host that was never uncloaked.
|
||||
bool GetTrayMenuWebviewState(bool &isVisible, RECT &bounds);
|
||||
bool GetCandidateWebviewState(bool &isVisible, RECT &bounds);
|
||||
void LogSmallWindowReadyGate(const wchar_t *context);
|
||||
// Lift the tray menu to the front of the small-window topmost band (e.g. after
|
||||
// FTB was pinned last), renotifying its controller about the band change. Only
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "utils/ime_utils.h"
|
||||
#include "window_hook.h"
|
||||
#include "window/floating_toolbar_visibility_policy.h"
|
||||
#include "log/candidate_diag_log.h"
|
||||
#include "log/ftb_diag_log.h"
|
||||
#include "voice-input/voice_input_service.h"
|
||||
#include <windowsx.h>
|
||||
@@ -652,6 +653,16 @@ std::wstring DescribeFloatingToolbarHostState()
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::wstring DescribeCandidateHostState()
|
||||
{
|
||||
bool webview_visible = false;
|
||||
RECT webview_bounds{};
|
||||
const bool has_controller = GetCandidateWebviewState(webview_visible, webview_bounds);
|
||||
return fmt::format(L"logical_shown={} nav_ready={} {}", ::is_global_wnd_cand_shown,
|
||||
IsCandidateWebviewReady(),
|
||||
DescribeHostWindowState(::global_hwnd, has_controller, webview_visible, webview_bounds));
|
||||
}
|
||||
|
||||
// External linkage, unlike its toolbar counterpart: the menu's own lifecycle
|
||||
// events live in windows_webview2.cpp and are the ones worth recording.
|
||||
std::wstring DescribeTrayMenuHostState()
|
||||
@@ -1052,6 +1063,7 @@ int CreateCandidateWindow(HINSTANCE hInstance)
|
||||
}
|
||||
|
||||
::global_hwnd = hwnd_cand;
|
||||
CAND_DIAG_LOGF(L"candidate host created {}", DescribeCandidateHostState());
|
||||
|
||||
// A client can activate while the pipe server is already listening but this
|
||||
// window does not exist yet, which is the race that leaves the toolbar
|
||||
@@ -1205,6 +1217,11 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
if (message == WM_SHOWWINDOW)
|
||||
{
|
||||
UpdateSmallWindowWebviewVisibility(hwnd, wParam != FALSE);
|
||||
if (hwnd == ::global_hwnd)
|
||||
{
|
||||
CAND_DIAG_LOGF(L"host WM_SHOWWINDOW showing={} reason={} {}", wParam != FALSE,
|
||||
static_cast<unsigned long long>(lParam), DescribeCandidateHostState());
|
||||
}
|
||||
}
|
||||
|
||||
if (message == WM_APPLY_IME_CONFIG || message == WM_APPLY_IME_INPUT_SCHEME)
|
||||
@@ -1239,6 +1256,14 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
|
||||
LRESULT CALLBACK WndProcCandWindow(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (message == WM_POWERBROADCAST || message == WM_DISPLAYCHANGE || message == WM_DWMCOMPOSITIONCHANGED ||
|
||||
message == WM_SETTINGCHANGE)
|
||||
{
|
||||
CAND_DIAG_LOGF(L"system window event message={:#x} wparam={:#x} lparam={:#x} {}", message,
|
||||
static_cast<unsigned long long>(wParam), static_cast<unsigned long long>(lParam),
|
||||
DescribeCandidateHostState());
|
||||
}
|
||||
|
||||
if (message == WM_IMEACTIVATE)
|
||||
{
|
||||
g_is_ime_active = true;
|
||||
@@ -1262,6 +1287,9 @@ LRESULT CALLBACK WndProcCandWindow(HWND hwnd, UINT message, WPARAM wParam, LPARA
|
||||
std::wstring str = preedit + L"," + Global::CandidateString;
|
||||
(void)0;
|
||||
LogSmallWindowReadyGate(L"show-candidate");
|
||||
CAND_DIAG_LOGF(L"show message preedit_units={} payload_units={} caret=({},{}) {}", preedit.size(),
|
||||
Global::CandidateString.size(), Global::Point[0], Global::Point[1],
|
||||
DescribeCandidateHostState());
|
||||
if (!EnsureSmallWindowsTopmost(L"show-candidate"))
|
||||
{
|
||||
(void)0;
|
||||
@@ -1284,6 +1312,7 @@ LRESULT CALLBACK WndProcCandWindow(HWND hwnd, UINT message, WPARAM wParam, LPARA
|
||||
|
||||
if (message == WM_HIDE_MAIN_WINDOW)
|
||||
{
|
||||
CAND_DIAG_LOGF(L"hide message begin {}", DescribeCandidateHostState());
|
||||
(void)0;
|
||||
// Clear first so any FineTuneWindow callback already queued bails out.
|
||||
::is_global_wnd_cand_shown = false;
|
||||
@@ -1312,6 +1341,7 @@ LRESULT CALLBACK WndProcCandWindow(HWND hwnd, UINT message, WPARAM wParam, LPARA
|
||||
}
|
||||
SetHostWindowCloaked(hwnd, true);
|
||||
UpdateHtmlContentWithJavaScript(webviewCandWnd, L"");
|
||||
CAND_DIAG_LOGF(L"hide message end {}", DescribeCandidateHostState());
|
||||
/* 候选词部分使用全角空格来占位 */
|
||||
// std::wstring str = L" , , , , , , , , ";
|
||||
// InflateCandWnd(str);
|
||||
@@ -1321,6 +1351,8 @@ LRESULT CALLBACK WndProcCandWindow(HWND hwnd, UINT message, WPARAM wParam, LPARA
|
||||
|
||||
if (message == WM_MOVE_CANDIDATE_WINDOW)
|
||||
{
|
||||
CAND_DIAG_LOGF(L"move message caret=({},{}) {}", Global::Point[0], Global::Point[1],
|
||||
DescribeCandidateHostState());
|
||||
FineTuneWindow(hwnd);
|
||||
return 0;
|
||||
}
|
||||
@@ -2448,9 +2480,12 @@ int FineTuneWindow(HWND hwnd)
|
||||
{
|
||||
(void)0;
|
||||
LogSmallWindowReadyGate(L"fine-tune-no-webview");
|
||||
CAND_DIAG_LOGF(L"fine-tune skipped: no webview {}", DescribeCandidateHostState());
|
||||
return 0;
|
||||
}
|
||||
const uint64_t generation = ++g_candidate_finetune_generation;
|
||||
CAND_DIAG_LOGF(L"fine-tune begin generation={} caret=({},{}) {}", generation, caretX, caretY,
|
||||
DescribeCandidateHostState());
|
||||
// Wrap/scroll budget = stable host size (half-screen DIP). Width wraps;
|
||||
// height scrolls inside the card when fonts make the list taller than host.
|
||||
const HalfScreenDipLimits measureLimits = QueryHalfScreenDipLimitsForPoint(caretPt);
|
||||
@@ -2477,12 +2512,15 @@ int FineTuneWindow(HWND hwnd)
|
||||
// measure callback was still pending — do not resurrect it.
|
||||
if (!::is_global_wnd_cand_shown || caretY == Global::INVALID_Y)
|
||||
{
|
||||
(void)0;
|
||||
CAND_DIAG_LOGF(L"fine-tune generation={} discarded: hidden={} invalid_caret={}", generation,
|
||||
!::is_global_wnd_cand_shown, caretY == Global::INVALID_Y);
|
||||
return;
|
||||
}
|
||||
// A newer show/update already queued another FineTune — ignore this one.
|
||||
if (generation != g_candidate_finetune_generation.load())
|
||||
{
|
||||
CAND_DIAG_LOGF(L"fine-tune generation={} discarded: superseded_by={}", generation,
|
||||
g_candidate_finetune_generation.load());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2694,8 +2732,12 @@ int FineTuneWindow(HWND hwnd)
|
||||
UpdateSmallWindowWebviewVisibility(hwnd, true);
|
||||
RECT actualRect{};
|
||||
GetWindowRect(hwnd, &actualRect);
|
||||
(void)actualRect;
|
||||
(void)0;
|
||||
CAND_DIAG_LOGF(L"fine-tune generation={} completed size_dip=({:.1f},{:.1f}) "
|
||||
L"margin=({},{}) rect=({},{},{}x{}) {}",
|
||||
generation, finalSize.first, finalSize.second, Global::MarginLeft,
|
||||
Global::MarginTop, actualRect.left, actualRect.top,
|
||||
actualRect.right - actualRect.left, actualRect.bottom - actualRect.top,
|
||||
DescribeCandidateHostState());
|
||||
};
|
||||
|
||||
// Pass 2: remeasure the painted card after margins. Keep the stable
|
||||
|
||||
Reference in new issue
Block a user