1009 lines
25 KiB
C++
1009 lines
25 KiB
C++
#include "Ipc.h"
|
|
#include <debugapi.h>
|
|
#include <handleapi.h>
|
|
#include <minwindef.h>
|
|
#include <utility>
|
|
#include <winnt.h>
|
|
#include <winuser.h>
|
|
#include "Globals.h"
|
|
#include "FanyDefines.h"
|
|
#include "MetasequoiaIME.h"
|
|
#include <fmt/xchar.h>
|
|
|
|
static HANDLE hMapFile = nullptr;
|
|
static void *pBuf;
|
|
static FanyImeSharedMemoryData *sharedData;
|
|
static bool canUseSharedMemory = false;
|
|
|
|
static HANDLE hPipe = nullptr;
|
|
static HANDLE hFromServerPipe = nullptr;
|
|
|
|
static FanyImeNamedpipeData namedpipeData = {};
|
|
FanyImeNamedpipeDataToTsf namedpipeDataFromServer = {};
|
|
|
|
/* Data size transfered from Server process */
|
|
static const int ServerDtPipeDataSize = 512;
|
|
|
|
int InitIpc()
|
|
{
|
|
//
|
|
// Shared memory, open here
|
|
//
|
|
hMapFile = OpenFileMappingW( //
|
|
FILE_MAP_ALL_ACCESS, //
|
|
FALSE, //
|
|
FANY_IME_SHARED_MEMORY //
|
|
);
|
|
|
|
//
|
|
// Shared memory is not available, try to use namedpipe
|
|
//
|
|
InitNamedpipe();
|
|
|
|
if (!hMapFile)
|
|
{
|
|
// Error handling
|
|
canUseSharedMemory = false;
|
|
|
|
// TODO: Log error
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool alreadyExists = (GetLastError() == ERROR_ALREADY_EXISTS);
|
|
|
|
pBuf = MapViewOfFile( //
|
|
hMapFile, //
|
|
FILE_MAP_ALL_ACCESS, //
|
|
0, //
|
|
0, //
|
|
BUFFER_SIZE //
|
|
); //
|
|
|
|
if (!pBuf)
|
|
{
|
|
// TODO: Error handling
|
|
}
|
|
|
|
sharedData = static_cast<FanyImeSharedMemoryData *>(pBuf);
|
|
// Only initialize the shared memory when first created
|
|
if (!alreadyExists)
|
|
{
|
|
// Initialize
|
|
*sharedData = {};
|
|
sharedData->point[0] = 100;
|
|
sharedData->point[1] = 100;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int InitNamedpipe()
|
|
{
|
|
if (hPipe == nullptr)
|
|
{
|
|
hPipe = CreateFile( //
|
|
FANY_IME_NAMED_PIPE, //
|
|
GENERIC_READ | GENERIC_WRITE, //
|
|
0, //
|
|
nullptr, //
|
|
OPEN_EXISTING, //
|
|
0, //
|
|
nullptr //
|
|
);
|
|
|
|
if (hPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
hPipe = nullptr;
|
|
}
|
|
else
|
|
{
|
|
// TODO: Log
|
|
}
|
|
}
|
|
|
|
if (hFromServerPipe == nullptr)
|
|
{
|
|
hFromServerPipe = CreateFile( //
|
|
FANY_IME_TO_TSF_NAMED_PIPE, //
|
|
GENERIC_READ | GENERIC_WRITE, //
|
|
0, //
|
|
nullptr, //
|
|
OPEN_EXISTING, //
|
|
0, //
|
|
nullptr //
|
|
);
|
|
|
|
if (hFromServerPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
hFromServerPipe = nullptr;
|
|
}
|
|
else
|
|
{
|
|
// TODO: Log
|
|
}
|
|
}
|
|
|
|
if (Global::hToTsfWorkerThreadPipe == nullptr)
|
|
{
|
|
Global::hToTsfWorkerThreadPipe = CreateFile( //
|
|
FANY_IME_TO_TSF_WORKER_THREAD_NAMED_PIPE, //
|
|
GENERIC_READ | GENERIC_WRITE, //
|
|
0, //
|
|
nullptr, //
|
|
OPEN_EXISTING, //
|
|
0, //
|
|
nullptr //
|
|
);
|
|
|
|
if (Global::hToTsfWorkerThreadPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
Global::hToTsfWorkerThreadPipe = nullptr;
|
|
}
|
|
else
|
|
{
|
|
// TODO: Log
|
|
}
|
|
}
|
|
|
|
if (hPipe == nullptr || hPipe == INVALID_HANDLE_VALUE || hFromServerPipe == nullptr ||
|
|
hFromServerPipe == INVALID_HANDLE_VALUE || Global::hToTsfWorkerThreadPipe == nullptr ||
|
|
Global::hToTsfWorkerThreadPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
hPipe = nullptr;
|
|
hFromServerPipe = nullptr;
|
|
Global::hToTsfWorkerThreadPipe = nullptr;
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int ConnectToAllNamedpipe()
|
|
{
|
|
hPipe = CreateFile( //
|
|
FANY_IME_NAMED_PIPE, //
|
|
GENERIC_READ | GENERIC_WRITE, //
|
|
0, //
|
|
nullptr, //
|
|
OPEN_EXISTING, //
|
|
0, //
|
|
nullptr //
|
|
);
|
|
|
|
if (hPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
hPipe = nullptr;
|
|
}
|
|
else
|
|
{
|
|
// TODO: Log
|
|
}
|
|
|
|
hFromServerPipe = CreateFile( //
|
|
FANY_IME_TO_TSF_NAMED_PIPE, //
|
|
GENERIC_READ | GENERIC_WRITE, //
|
|
0, //
|
|
nullptr, //
|
|
OPEN_EXISTING, //
|
|
0, //
|
|
nullptr //
|
|
);
|
|
|
|
if (hFromServerPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
hFromServerPipe = nullptr;
|
|
}
|
|
else
|
|
{
|
|
// TODO: Log
|
|
}
|
|
|
|
Global::hToTsfWorkerThreadPipe = CreateFile( //
|
|
FANY_IME_TO_TSF_WORKER_THREAD_NAMED_PIPE, //
|
|
GENERIC_READ | GENERIC_WRITE, //
|
|
0, //
|
|
nullptr, //
|
|
OPEN_EXISTING, //
|
|
0, //
|
|
nullptr //
|
|
);
|
|
|
|
if (Global::hToTsfWorkerThreadPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
Global::hToTsfWorkerThreadPipe = nullptr;
|
|
}
|
|
else
|
|
{
|
|
// TODO: Log
|
|
}
|
|
|
|
if (hPipe == nullptr || hPipe == INVALID_HANDLE_VALUE || hFromServerPipe == nullptr ||
|
|
hFromServerPipe == INVALID_HANDLE_VALUE || Global::hToTsfWorkerThreadPipe == nullptr ||
|
|
Global::hToTsfWorkerThreadPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
hPipe = nullptr;
|
|
hFromServerPipe = nullptr;
|
|
Global::hToTsfWorkerThreadPipe = nullptr;
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int ConnectToTsfNamedpipe()
|
|
{
|
|
if (hFromServerPipe == nullptr || hFromServerPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
hFromServerPipe = CreateFile( //
|
|
FANY_IME_TO_TSF_NAMED_PIPE, //
|
|
GENERIC_READ | GENERIC_WRITE, //
|
|
0, //
|
|
nullptr, //
|
|
OPEN_EXISTING, //
|
|
0, //
|
|
nullptr //
|
|
);
|
|
|
|
if (hFromServerPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
hFromServerPipe = nullptr;
|
|
}
|
|
else
|
|
{
|
|
// TODO: Log
|
|
}
|
|
}
|
|
if (hFromServerPipe == nullptr || hFromServerPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int CloseIpc()
|
|
{
|
|
//
|
|
// Namedpipe
|
|
//
|
|
CloseNamedpipe();
|
|
|
|
if (!canUseSharedMemory)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// Shared memory
|
|
//
|
|
if (pBuf)
|
|
{
|
|
UnmapViewOfFile(pBuf);
|
|
pBuf = nullptr;
|
|
}
|
|
|
|
if (hMapFile)
|
|
{
|
|
CloseHandle(hMapFile);
|
|
hMapFile = nullptr;
|
|
}
|
|
|
|
//
|
|
// Events
|
|
//
|
|
for (const auto &eventName : FANY_IME_EVENT_ARRAY)
|
|
{
|
|
HANDLE hEvent = OpenEventW( //
|
|
EVENT_ALL_ACCESS, //
|
|
FALSE, //
|
|
eventName.c_str() //
|
|
); //
|
|
if (hEvent)
|
|
{
|
|
CloseHandle(hEvent);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CloseNamedpipe()
|
|
{
|
|
CloseHandle(hPipe);
|
|
hPipe = nullptr;
|
|
CloseHandle(hFromServerPipe);
|
|
hFromServerPipe = nullptr;
|
|
CloseHandle(Global::hToTsfWorkerThreadPipe);
|
|
Global::hToTsfWorkerThreadPipe = nullptr;
|
|
return 0;
|
|
}
|
|
|
|
int WriteDataToSharedMemory( //
|
|
UINT keycode, //
|
|
WCHAR wch, //
|
|
UINT modifiers_down, //
|
|
const int point[2], //
|
|
int pinyin_length, //
|
|
const std::wstring &pinyin_string, //
|
|
UINT write_flag //
|
|
)
|
|
{
|
|
if (!canUseSharedMemory)
|
|
{
|
|
return WriteDataToNamedPipe(keycode, wch, modifiers_down, point, pinyin_length, pinyin_string, write_flag);
|
|
}
|
|
|
|
if (write_flag >> 0 & 1u)
|
|
{
|
|
sharedData->keycode = keycode;
|
|
}
|
|
|
|
if (write_flag >> 1 & 1u)
|
|
{
|
|
sharedData->wch = wch;
|
|
}
|
|
|
|
if (write_flag >> 2 & 1u)
|
|
{
|
|
sharedData->modifiers_down = modifiers_down;
|
|
}
|
|
|
|
if (write_flag >> 3 & 1u)
|
|
{
|
|
sharedData->point[0] = point[0];
|
|
sharedData->point[1] = point[1];
|
|
}
|
|
|
|
if (write_flag >> 4 & 1u)
|
|
{
|
|
sharedData->pinyin_length = pinyin_length;
|
|
}
|
|
|
|
if (write_flag >> 5 & 1u)
|
|
{
|
|
wcscpy_s(sharedData->pinyin_string, pinyin_string.c_str());
|
|
sharedData->pinyin_string[pinyin_length] = L'\0';
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief
|
|
*
|
|
* @param keycode
|
|
* @param modifiers_down
|
|
* @param point
|
|
* @param pinyin_length
|
|
* @param pinyin_string
|
|
* @param write_flag
|
|
* @return int
|
|
*/
|
|
int WriteDataToNamedPipe( //
|
|
UINT keycode, //
|
|
WCHAR wch, //
|
|
UINT modifiers_down, //
|
|
const int point[2], //
|
|
int pinyin_length, //
|
|
const std::wstring &pinyin_string, //
|
|
UINT write_flag //
|
|
)
|
|
{
|
|
if (write_flag >> 0 & 1u)
|
|
{
|
|
namedpipeData.keycode = keycode;
|
|
}
|
|
|
|
if (write_flag >> 1 & 1u)
|
|
{
|
|
namedpipeData.wch = wch;
|
|
}
|
|
|
|
if (write_flag >> 2 & 1u)
|
|
{
|
|
namedpipeData.modifiers_down = modifiers_down;
|
|
}
|
|
|
|
if (write_flag >> 3 & 1u)
|
|
{
|
|
namedpipeData.point[0] = point[0];
|
|
namedpipeData.point[1] = point[1];
|
|
}
|
|
|
|
if (write_flag >> 4 & 1u)
|
|
{
|
|
namedpipeData.pinyin_length = pinyin_length;
|
|
}
|
|
|
|
if (write_flag >> 5 & 1u)
|
|
{
|
|
wcscpy_s(namedpipeData.pinyin_string, pinyin_string.c_str());
|
|
namedpipeData.pinyin_string[pinyin_length] = L'\0';
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int SendKeyEventToUIProcess()
|
|
{
|
|
if (!canUseSharedMemory)
|
|
{
|
|
return SendKeyEventToUIProcessViaNamedPipe();
|
|
}
|
|
|
|
HANDLE hEvent = OpenEventW( //
|
|
EVENT_MODIFY_STATE, //
|
|
FALSE, //
|
|
FANY_IME_EVENT_ARRAY[0].c_str() //
|
|
); //
|
|
|
|
if (!hEvent)
|
|
{
|
|
// TODO: Error handling
|
|
}
|
|
|
|
if (!SetEvent(hEvent))
|
|
{
|
|
// TODO: Error handling
|
|
}
|
|
|
|
CloseHandle(hEvent);
|
|
return 0;
|
|
}
|
|
|
|
int SendHideCandidateWndEventToUIProcess()
|
|
{
|
|
if (!canUseSharedMemory)
|
|
{
|
|
return SendHideCandidateWndEventToUIProcessViaNamedPipe();
|
|
}
|
|
|
|
HANDLE hEvent = OpenEventW( //
|
|
EVENT_MODIFY_STATE, //
|
|
FALSE, //
|
|
FANY_IME_EVENT_ARRAY[1].c_str() // FanyHideCandidateWndEvent
|
|
); //
|
|
|
|
if (!hEvent)
|
|
{
|
|
// TODO: Error handling
|
|
}
|
|
|
|
if (!SetEvent(hEvent))
|
|
{
|
|
// TODO: Error handling
|
|
}
|
|
|
|
CloseHandle(hEvent);
|
|
return 0;
|
|
}
|
|
|
|
int SendShowCandidateWndEventToUIProcess()
|
|
{
|
|
if (!canUseSharedMemory)
|
|
{
|
|
return SendShowCandidateWndEventToUIProcessViaNamedPipe();
|
|
}
|
|
|
|
HANDLE hEvent = OpenEventW( //
|
|
EVENT_MODIFY_STATE, //
|
|
FALSE, //
|
|
FANY_IME_EVENT_ARRAY[2].c_str() // FanyShowCandidateWndEvent
|
|
); //
|
|
|
|
if (!hEvent)
|
|
{
|
|
// TODO: Error handling
|
|
}
|
|
|
|
if (!SetEvent(hEvent))
|
|
{
|
|
// TODO: Error handling
|
|
}
|
|
|
|
CloseHandle(hEvent);
|
|
return 0;
|
|
}
|
|
|
|
int SendMoveCandidateWndEventToUIProcess()
|
|
{
|
|
if (!canUseSharedMemory)
|
|
{
|
|
return SendMoveCandidateWndEventToUIProcessViaNamedPipe();
|
|
}
|
|
|
|
HANDLE hEvent = OpenEventW( //
|
|
EVENT_MODIFY_STATE, //
|
|
FALSE, //
|
|
FANY_IME_EVENT_ARRAY[3].c_str() // FanyMoveCandidateWndEvent
|
|
); //
|
|
|
|
if (!hEvent)
|
|
{
|
|
// TODO: Error handling
|
|
}
|
|
|
|
if (!SetEvent(hEvent))
|
|
{
|
|
// TODO: Error handling
|
|
}
|
|
|
|
CloseHandle(hEvent);
|
|
return 0;
|
|
}
|
|
|
|
int SendLangbarRightClickEventToUIProcess(const RECT *prcArea)
|
|
{
|
|
if (!canUseSharedMemory)
|
|
{
|
|
return SendLangbarRightClickEventToUIProcessViaNamedPipe(prcArea);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Named pipe
|
|
//
|
|
|
|
void SendToNamedpipe()
|
|
{
|
|
if (!hPipe || hPipe == INVALID_HANDLE_VALUE) // Try to reconnect
|
|
{
|
|
hPipe = CreateFile( //
|
|
FANY_IME_NAMED_PIPE, //
|
|
GENERIC_READ | GENERIC_WRITE, //
|
|
0, //
|
|
nullptr, //
|
|
OPEN_EXISTING, //
|
|
0, //
|
|
nullptr //
|
|
);
|
|
|
|
if (hPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
// TODO: Log
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// TODO: Log
|
|
}
|
|
}
|
|
|
|
DWORD bytesWritten = 0;
|
|
BOOL ret = WriteFile( //
|
|
hPipe, //
|
|
&namedpipeData, //
|
|
sizeof(namedpipeData), //
|
|
&bytesWritten, //
|
|
NULL //
|
|
);
|
|
if (!ret || bytesWritten != sizeof(namedpipeData))
|
|
{
|
|
/* Error handling: 必须将 hPipe 置为无效,否则将留下脏句柄,导致有些情况下无法再次连接 */
|
|
DWORD err = GetLastError();
|
|
// if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
|
|
// {
|
|
/* 将两个方向的管道同时置为无效 */
|
|
CloseHandle(hPipe);
|
|
CloseHandle(hFromServerPipe);
|
|
// CloseHandle(Global::hToTsfWorkerThreadPipe);
|
|
hPipe = INVALID_HANDLE_VALUE;
|
|
hFromServerPipe = INVALID_HANDLE_VALUE;
|
|
// Global::hToTsfWorkerThreadPipe = INVALID_HANDLE_VALUE;
|
|
/* 向 Server 端发送 kill 同时重置两个管道的 connect */
|
|
SendToAuxNamedpipe(L"kill");
|
|
OutputDebugString(fmt::format(L"SendToNamedpipe failed eventually01.").c_str());
|
|
// }
|
|
|
|
//
|
|
// 等待 Server 准备好,再重连几次
|
|
//
|
|
|
|
/* toTsfNamedPipe 放到消息窗口的线程中去处理 */
|
|
PostMessage(Global::msgWndHandle, WM_ConnectToTsfNamedpipe, 0, 0);
|
|
for (int i = 0; i < 10; ++i)
|
|
{
|
|
Sleep(10);
|
|
hPipe = CreateFile( //
|
|
FANY_IME_NAMED_PIPE, //
|
|
GENERIC_READ | GENERIC_WRITE, //
|
|
0, //
|
|
nullptr, //
|
|
OPEN_EXISTING, //
|
|
0, //
|
|
nullptr //
|
|
);
|
|
if (hPipe != INVALID_HANDLE_VALUE)
|
|
break;
|
|
}
|
|
|
|
if (hPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
// TODO: Log
|
|
OutputDebugString(fmt::format(L"SendToNamedpipe failed eventually02.").c_str());
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// TODO: Log
|
|
}
|
|
|
|
DWORD bytesWritten = 0;
|
|
BOOL ret = WriteFile( //
|
|
hPipe, //
|
|
&namedpipeData, //
|
|
sizeof(namedpipeData), //
|
|
&bytesWritten, //
|
|
NULL //
|
|
);
|
|
|
|
if (!ret || bytesWritten != sizeof(namedpipeData))
|
|
{
|
|
// TODO: Error handling
|
|
OutputDebugString(fmt::format(L"SendToNamedpipe failed eventually03.").c_str());
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Clear namedpipe data if exists, cause sometimes there may be some useless data sent by last key event from
|
|
* server
|
|
*
|
|
*/
|
|
void ClearNamedpipeDataIfExists()
|
|
{
|
|
bool isSpaceOrNumber = Global::Keycode == VK_SPACE || //
|
|
(Global::Keycode > '0' && Global::Keycode < '9') || //
|
|
(Global::CommitWithFirstCandPunc.count(Global::wch) > 0);
|
|
/* Only clear namedpipe data if keycode is space or number, for better performance */
|
|
if (!isSpaceOrNumber)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!hFromServerPipe || hFromServerPipe == INVALID_HANDLE_VALUE) // Try to reconnect
|
|
{
|
|
hFromServerPipe = CreateFile( //
|
|
FANY_IME_TO_TSF_NAMED_PIPE, //
|
|
GENERIC_READ | GENERIC_WRITE, //
|
|
0, //
|
|
nullptr, //
|
|
OPEN_EXISTING, //
|
|
0, //
|
|
nullptr //
|
|
);
|
|
if (hFromServerPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
// TODO: Log
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// TODO: Log
|
|
}
|
|
}
|
|
|
|
DWORD bytesAvailable = 0;
|
|
DWORD bytesRead = 0;
|
|
while (true)
|
|
{
|
|
BOOL peekOk = PeekNamedPipe( //
|
|
hFromServerPipe, //
|
|
nullptr, //
|
|
0, //
|
|
nullptr, //
|
|
&bytesAvailable, //
|
|
nullptr //
|
|
);
|
|
|
|
if (!peekOk || bytesAvailable == 0)
|
|
{
|
|
break; // no more data or pipe error
|
|
}
|
|
|
|
BOOL readOk = ReadFile( //
|
|
hFromServerPipe, //
|
|
&namedpipeDataFromServer, //
|
|
sizeof(namedpipeDataFromServer), //
|
|
&bytesRead, //
|
|
NULL //
|
|
);
|
|
|
|
if (!readOk || bytesRead == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Try to read selected candiate string data from server pipe with timeout
|
|
*
|
|
* @return struct FanyImeNamedpipeDataToTsf*
|
|
*/
|
|
struct FanyImeNamedpipeDataToTsf *TryReadDataFromServerPipeWithTimeout()
|
|
{
|
|
std::pair<UINT, std::wstring> ret = {0, L""};
|
|
int timeoutMs = 10; // Default timeout 10ms
|
|
int intervalMs = 1; // Default interval 1ms
|
|
|
|
if (!hFromServerPipe || hFromServerPipe == INVALID_HANDLE_VALUE) // Try to reconnect
|
|
{
|
|
hFromServerPipe = CreateFile( //
|
|
FANY_IME_TO_TSF_NAMED_PIPE, //
|
|
GENERIC_READ | GENERIC_WRITE, //
|
|
0, //
|
|
nullptr, //
|
|
OPEN_EXISTING, //
|
|
0, //
|
|
nullptr //
|
|
);
|
|
if (hFromServerPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
// TODO: Log
|
|
namedpipeDataFromServer.msg_type = Global::DataFromServerMsgType::Normal;
|
|
// wcscpy_s(namedpipeDataFromServer.candidate_string, L"PipeOpenError");
|
|
wcscpy_s(namedpipeDataFromServer.candidate_string, L"X");
|
|
return &namedpipeDataFromServer;
|
|
}
|
|
else
|
|
{
|
|
// TODO: Log
|
|
}
|
|
}
|
|
|
|
DWORD bytesAvailable = 0;
|
|
int waited = 0;
|
|
while (waited < timeoutMs)
|
|
{
|
|
// TODO: Do not log
|
|
#ifdef FANY_DEBUG
|
|
OutputDebugString(fmt::format(L"current waited: {}", waited).c_str());
|
|
#endif
|
|
if (PeekNamedPipe(hFromServerPipe, nullptr, 0, nullptr, &bytesAvailable, nullptr) && bytesAvailable > 0)
|
|
{
|
|
auto ret = ReadDataFromServerViaNamedPipe();
|
|
#ifdef FANY_DEBUG
|
|
OutputDebugString(fmt::format(L"PeekNamedPipe: {}", waited).c_str());
|
|
#endif
|
|
return ret;
|
|
}
|
|
Sleep(intervalMs); // TODO: Maybe could use less time
|
|
waited += intervalMs;
|
|
}
|
|
|
|
/* Error handling: 必须将 hFromServerPipe 置为无效,否则将留下脏句柄,导致有些情况下无法再次连接 */
|
|
CloseHandle(hFromServerPipe);
|
|
hFromServerPipe = INVALID_HANDLE_VALUE;
|
|
|
|
namedpipeDataFromServer.msg_type = Global::DataFromServerMsgType::Normal;
|
|
// Pipe timeout error
|
|
wcscpy_s(namedpipeDataFromServer.candidate_string, L"T");
|
|
return &namedpipeDataFromServer;
|
|
}
|
|
|
|
/**
|
|
* @brief Read data sent by server
|
|
*
|
|
* TODO: Cancel when time exceed, we should set a timeout
|
|
*
|
|
* @return struct FanyImeNamedpipeDataToTsf*
|
|
*/
|
|
struct FanyImeNamedpipeDataToTsf *ReadDataFromServerViaNamedPipe()
|
|
{
|
|
if (!hFromServerPipe || hFromServerPipe == INVALID_HANDLE_VALUE) // Try to reconnect
|
|
{
|
|
hFromServerPipe = CreateFile( //
|
|
FANY_IME_TO_TSF_NAMED_PIPE, //
|
|
GENERIC_READ | GENERIC_WRITE, //
|
|
0, //
|
|
nullptr, //
|
|
OPEN_EXISTING, //
|
|
0, //
|
|
nullptr //
|
|
);
|
|
if (hFromServerPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
// TODO: Log
|
|
namedpipeDataFromServer.msg_type = 0;
|
|
// wcscpy_s(namedpipeDataFromServer.candidate_string, L"PipeOpenError");
|
|
wcscpy_s(namedpipeDataFromServer.candidate_string, L"X");
|
|
return &namedpipeDataFromServer;
|
|
}
|
|
else
|
|
{
|
|
// TODO: Log
|
|
}
|
|
}
|
|
|
|
DWORD bytesRead = 0;
|
|
BOOL readResult = ReadFile( //
|
|
hFromServerPipe, //
|
|
&namedpipeDataFromServer, //
|
|
sizeof(namedpipeDataFromServer), //
|
|
&bytesRead, //
|
|
NULL //
|
|
);
|
|
if (!readResult || bytesRead == 0) // Disconnected or error
|
|
{
|
|
// TODO: Log
|
|
}
|
|
else
|
|
{
|
|
#ifdef FANY_DEBUG
|
|
OutputDebugString(namedpipeDataFromServer.candidate_string);
|
|
#endif
|
|
return &namedpipeDataFromServer;
|
|
}
|
|
|
|
namedpipeDataFromServer.msg_type = 0;
|
|
wcscpy_s(namedpipeDataFromServer.candidate_string, L"ReadDataError");
|
|
return &namedpipeDataFromServer;
|
|
}
|
|
|
|
/**
|
|
* @brief 即用即断,不要求一直连接,但是,要让 Server 端的管道一直在 connect 状态阻塞住等待连接
|
|
*
|
|
* @param pipeData
|
|
*/
|
|
void SendToAuxNamedpipe(std::wstring pipeData)
|
|
{
|
|
HANDLE hAuxPipe = CreateFileW( //
|
|
FANY_IME_AUX_NAMED_PIPE, //
|
|
GENERIC_READ | GENERIC_WRITE, //
|
|
0, //
|
|
nullptr, //
|
|
OPEN_EXISTING, //
|
|
0, //
|
|
nullptr //
|
|
);
|
|
if (!hAuxPipe || hAuxPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
#ifdef FANY_DEBUG
|
|
OutputDebugString(fmt::format(L"SendToAuxNamedpipe: PipeOpenError").c_str());
|
|
#endif
|
|
return;
|
|
}
|
|
DWORD bytesWritten = 0;
|
|
BOOL ret = WriteFile( //
|
|
hAuxPipe, //
|
|
pipeData.c_str(), //
|
|
pipeData.length() * sizeof(wchar_t), //
|
|
&bytesWritten, //
|
|
NULL //
|
|
);
|
|
if (!ret || bytesWritten != pipeData.length() * sizeof(wchar_t))
|
|
{
|
|
// TODO: Error handling
|
|
}
|
|
CloseHandle(hAuxPipe);
|
|
}
|
|
|
|
/**
|
|
* event_type
|
|
* 0: FanyImeKeyEvent
|
|
* 1: FanyHideCandidateWndEvent
|
|
* 2: FanyShowCandidateWndEvent
|
|
* 3: FanyMoveCandidateWndEvent
|
|
*/
|
|
int SendKeyEventToUIProcessViaNamedPipe()
|
|
{
|
|
namedpipeData.event_type = 0;
|
|
SendToNamedpipe();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int SendHideCandidateWndEventToUIProcessViaNamedPipe()
|
|
{
|
|
namedpipeData.event_type = 1;
|
|
SendToNamedpipe();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int SendShowCandidateWndEventToUIProcessViaNamedPipe()
|
|
{
|
|
namedpipeData.event_type = 2;
|
|
SendToNamedpipe();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int SendMoveCandidateWndEventToUIProcessViaNamedPipe()
|
|
{
|
|
namedpipeData.event_type = 3;
|
|
SendToNamedpipe();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int SendLangbarRightClickEventToUIProcessViaNamedPipe(const RECT *prcArea)
|
|
{
|
|
namedpipeData.event_type = 4;
|
|
/* 利用其他的字段,把图标的坐标传递过去 */
|
|
namedpipeData.point[0] = prcArea->left;
|
|
namedpipeData.point[1] = prcArea->top;
|
|
namedpipeData.keycode = prcArea->right;
|
|
namedpipeData.modifiers_down = prcArea->bottom;
|
|
SendToNamedpipe();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int SendIMEActivationEventToUIProcessViaNamedPipe()
|
|
{
|
|
SendToAuxNamedpipe(L"IMEActivation");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Send IME status to UI process via named pipe
|
|
*
|
|
* @param kbdIsOpen
|
|
* @param puncIsOpen
|
|
* @return int
|
|
*/
|
|
int SendIMEStatusEventToUIProcessViaNamedPipe(bool kbdIsOpen, bool puncIsOpen)
|
|
{
|
|
std::wstring status = L"ftbStatus";
|
|
if (kbdIsOpen)
|
|
{
|
|
status += L"1";
|
|
}
|
|
else
|
|
{
|
|
status += L"0";
|
|
}
|
|
if (puncIsOpen)
|
|
{
|
|
status += L"1";
|
|
}
|
|
else
|
|
{
|
|
status += L"0";
|
|
}
|
|
SendToAuxNamedpipe(status);
|
|
return 0;
|
|
}
|
|
|
|
int SendIMEDeactivationEventToUIProcessViaNamedPipe()
|
|
{
|
|
SendToAuxNamedpipe(L"IMEDeactivation");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int SendIMESwitchEventToUIProcessViaNamedPipe(UINT uImeStatus)
|
|
{
|
|
namedpipeData.event_type = 7;
|
|
/* 利用其他的字段,把 IME 的中英状态传递过去 */
|
|
namedpipeData.keycode = uImeStatus;
|
|
SendToNamedpipe();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int SendPuncSwitchEventToUIProcessViaNamedPipe(BOOL isPunc)
|
|
{
|
|
namedpipeData.event_type = 8;
|
|
/* 利用其他的字段,把标点符号的中英状态传递过去 */
|
|
namedpipeData.keycode = isPunc;
|
|
SendToNamedpipe();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int SendDoubleSingleByteSwitchEventToUIProcessViaNamedPipe(BOOL isDoubleSingleByte)
|
|
{
|
|
namedpipeData.event_type = 9;
|
|
/* 利用其他的字段,把全角/半角的状态传递过去 */
|
|
namedpipeData.keycode = isDoubleSingleByte;
|
|
SendToNamedpipe();
|
|
|
|
return 0;
|
|
} |