本指南整理了「點擊反查視窗紀錄字根」功能的完整程式碼修改,方便您在版本更新時重新套用。
目標: 新增一個通知類型,用來區分「反查視窗」與其他通知。
在此檔案中找到 enum class NOTIFY_TYPE,加入 NOTIFY_REVERSE_CONVERSION。
// g:\App\DIME\BaseStructure.h
enum class NOTIFY_TYPE
{
NOTIFY_CHN_ENG = 0,
NOTIFY_SINGLEDOUBLEBYTE,
NOTIFY_BEEP,
NOTIFY_OTHERS,
NOTIFY_REVERSE_CONVERSION // [新增]
};目標:
- 讓視窗能儲存「被反查的字」(SourceText)。
- 新增設定這個字的方法。
// g:\App\DIME\NotifyWindow.h
class CNotifyWindow : public CBaseWindow
{
public:
// ... 原有程式碼 ...
void SetNotifyType(enum NOTIFY_TYPE notifytype) { _notifyType = notifytype;}
NOTIFY_TYPE GetNotifyType() { return _notifyType;}
// [新增] 宣告設定來源文字的方法
void SetSourceText(_Inout_ const CStringRange *pSourceText);
private:
// ... 原有程式碼 ...
CStringRange _notifyText;
// [新增] 儲存來源文字 (例如: "我")
CStringRange _sourceText;
NOTIFY_TYPE _notifyType;
// ...
};目標:
- 加入必要的標頭檔 (處理檔案路徑)。
- 實作
SetSourceText。 - 修改
_OnLButtonDown處理點擊與寫入檔案。 - 修正
_WindowProcCallback防止重複觸發。
在檔案最上方加入:
// g:\App\DIME\NotifyWindow.cpp
#include "NotifyWindow.h"
// [新增] 以下 include
#include <memory>
#include <vector>
#include <string>
#include <shlobj.h>
#include <shlwapi.h>
#include <KnownFolders.h>
#pragma comment(lib, "shlwapi.lib")找到 _WindowProcCallback 中的 WM_SETCURSOR 區塊,修改如下:
// g:\App\DIME\NotifyWindow.cpp -> _WindowProcCallback
case WM_SETCURSOR:
{
POINT cursorPoint;
GetCursorPos(&cursorPoint);
MapWindowPoints(NULL, wndHandle, &cursorPoint, 1);
// [修改] 只在 MOUSEMOVE 時處理,避免重複觸發點擊事件
if (HIWORD(lParam) == WM_MOUSEMOVE)
{
_HandleMouseMsg(HIWORD(lParam), cursorPoint);
}
}
return 1;在任意位置 (建議在 _OnLButtonDown 上方) 加入 SetSourceText 實作,並修改 _OnLButtonDown:
// g:\App\DIME\NotifyWindow.cpp
// [新增] 實作 SetSourceText
void CNotifyWindow::SetSourceText(_Inout_ const CStringRange *pSourceText)
{
debugPrint(L"CNotifyWindow::SetSourceText()");
if (pSourceText == nullptr) return;
size_t sourceTextLen = pSourceText->GetLength();
if (sourceTextLen)
{
std::unique_ptr<WCHAR[]> pwchString = std::make_unique<WCHAR[]>(sourceTextLen + 1);
StringCchCopyN(pwchString.get(), sourceTextLen + 1, pSourceText->Get(), sourceTextLen);
_sourceText.Set(pwchString.release(), sourceTextLen);
debugPrint(L"CNotifyWindow::SetSourceText(), sourceTextLen =%d", sourceTextLen);
}
}
// [修改] _OnLButtonDown 加入寫檔邏輯
void CNotifyWindow::_OnLButtonDown(POINT pt)
{
RECT rcWindow = {0, 0, 0, 0};
_GetClientRect(&rcWindow);
if(PtInRect(&rcWindow, pt))
{
if(_notifyType == NOTIFY_TYPE::NOTIFY_CHN_ENG)
{
_pfnCallback(_pObj, NOTIFY_WND::SWITCH_CHN_ENG, NULL, NULL);
}
// [新增] 處理反查視窗點擊
else if (_notifyType == NOTIFY_TYPE::NOTIFY_REVERSE_CONVERSION)
{
PWSTR pProfilePath = nullptr;
// 取得 "我的文件" 路徑
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &pProfilePath)))
{
WCHAR szPath[MAX_PATH];
StringCchPrintf(szPath, MAX_PATH, L"%s\\DIME\\reversed_roots.txt", pProfilePath);
CoTaskMemFree(pProfilePath);
// 建立目錄
WCHAR szDir[MAX_PATH];
StringCchCopy(szDir, MAX_PATH, szPath);
PathRemoveFileSpec(szDir);
CreateDirectory(szDir, NULL);
std::vector<std::wstring> lines;
BOOL found = FALSE;
// 讀取舊檔
FILE* fp = nullptr;
if (_wfopen_s(&fp, szPath, L"r, ccs=UTF-8") == 0 && fp)
{
WCHAR line[1024];
while (fgetws(line, 1024, fp))
{
std::wstring strLine(line);
if (!strLine.empty() && strLine.back() == L'\n') strLine.pop_back();
if (!found)
{
// 搜尋: [字] [字根]
std::wstring searchKey;
searchKey.assign(_sourceText.Get(), _sourceText.GetLength());
searchKey += L" ";
searchKey.append(_notifyText.Get(), _notifyText.GetLength());
if (strLine.find(searchKey) == 0)
{
found = TRUE;
// 更新計數
size_t lastSpace = strLine.find_last_of(L' ');
if (lastSpace != std::wstring::npos)
{
int count = _wtoi(strLine.substr(lastSpace + 1).c_str());
count++;
wchar_t countStr[16];
_itow_s(count, countStr, 10);
strLine = searchKey + L" " + countStr;
}
}
}
lines.push_back(strLine);
}
fclose(fp);
}
// 若沒找到則新增
if (!found)
{
std::wstring newLine;
newLine.assign(_sourceText.Get(), _sourceText.GetLength());
newLine += L" ";
newLine.append(_notifyText.Get(), _notifyText.GetLength());
newLine += L" 1"; // 初始計數 1
lines.push_back(newLine);
}
// 寫回檔案
if (_wfopen_s(&fp, szPath, L"w, ccs=UTF-8") == 0 && fp)
{
for (const auto& l : lines)
{
fputws(l.c_str(), fp);
fputws(L"\n", fp);
}
fclose(fp);
}
}
// 點擊後隱藏視窗
_Show(FALSE, 0, 0);
}
}
else
{
_Show(FALSE,0,0);
}
}目標: 修改 ShowNotifyText 函式,讓它能往下傳遞「來源文字」。
// g:\App\DIME\UIPresenter.h
// [修改] 函式宣告,新增 pSourceText 參數
void ShowNotifyText(_In_ CStringRange *pNotifyText, _In_opt_ UINT delayShow = 0, _In_opt_ UINT timeToHide = 0, _In_opt_ NOTIFY_TYPE notifyType = NOTIFY_TYPE::NOTIFY_OTHERS, _In_opt_ CStringRange *pSourceText = nullptr);// g:\App\DIME\UIPresenter.cpp
// [修改] 函式定義,新增 pSourceText 參數
void CUIPresenter::ShowNotifyText(_In_ CStringRange* pNotifyText, _In_opt_ UINT delayShow, _In_opt_ UINT timeToHide, _In_opt_ NOTIFY_TYPE notifyType, _In_opt_ CStringRange *pSourceText)
{
// ... 前面原本的程式碼 ...
// 找到以下這段,加入傳遞 SourceText 的邏輯
if (SUCCEEDED(pContext->GetActiveView(&pView)) && pView)
{
// [新增] 如果有 pSourceText,就傳給視窗
if (_pNotifyWnd && pSourceText) _pNotifyWnd->SetSourceText(pSourceText);
pView->GetWnd(&parentWndHandle);
// ...
}
// ...
}目標: 在送出反查結果時,把「原本的字」一起送出去,並指定類型為 NOTIFY_REVERSE_CONVERSION。
// g:\App\DIME\ReverseConversion.cpp
// 找到 _AsyncReverseConversionNotification 函式
// [修改]
// 1. 建立 sourceText (原本的 _commitString)
// 2. 呼叫 ShowNotifyText 時傳入 sourceText
// 3. 通知類型改為 NOTIFY_REVERSE_CONVERSION
if(SUCCEEDED(reverseConversionList->GetString(0, &bstrResult)) && bstrResult && SysStringLen(bstrResult))
{
CStringRange reverseConvNotify;
WCHAR* pwch = new (std::nothrow) WCHAR[SysStringLen(bstrResult)+1];
StringCchCopy(pwch, SysStringLen(bstrResult)+1, (WCHAR*) bstrResult);
// [新增] 準備來源文字
CStringRange sourceText;
sourceText.Set(_commitString, wcslen(_commitString));
// [修改] 傳入參數
_pUIPresenter->ShowNotifyText(&reverseConvNotify.Set(pwch, wcslen(pwch)), 0, 0, NOTIFY_TYPE::NOTIFY_REVERSE_CONVERSION, &sourceText);
}