144 lines
4.9 KiB
C++
144 lines
4.9 KiB
C++
#include "ipc/event_listener.h"
|
|
#include "log/fanylog.h"
|
|
#include "window/ime_windows.h"
|
|
#include <commctrl.h>
|
|
#include <thread>
|
|
#include <utility>
|
|
#include "ipc/ipc.h"
|
|
#include "config/ime_config.h"
|
|
#include <windows.h>
|
|
#include <fmt/xchar.h>
|
|
#include <spdlog/spdlog.h>
|
|
#include "cloud/cloud_ime.h"
|
|
#include "english/english_ime.h"
|
|
#include "utils/common_utils.h"
|
|
#include "session/session_factory.h"
|
|
#include "webview2/windows_webview2.h"
|
|
#include "voice-input/voice_input_service.h"
|
|
|
|
namespace
|
|
{
|
|
const char *SchemeTypeToString(SchemeType scheme_type)
|
|
{
|
|
switch (scheme_type)
|
|
{
|
|
case SchemeType::Quanpin:
|
|
return "quanpin";
|
|
case SchemeType::Shuangpin:
|
|
return "shuangpin";
|
|
case SchemeType::Wubi:
|
|
return "wubi";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int CALLBACK WinMain(_In_ HINSTANCE hInstance, _In_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow)
|
|
{
|
|
// Single instance guard
|
|
HANDLE hSingleInstanceMutex = CreateMutexW(nullptr, TRUE, L"Local\\MetasequoiaImeServer_SingleInstance");
|
|
if (hSingleInstanceMutex == nullptr)
|
|
{
|
|
OutputDebugString(fmt::format(L"[msime]: Failed to create single instance mutex.").c_str());
|
|
return 0;
|
|
}
|
|
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
|
{
|
|
OutputDebugString(
|
|
fmt::format(L"[msime]: Single instance already exists, MetasequoiaImeServer is already running.").c_str());
|
|
CloseHandle(hSingleInstanceMutex);
|
|
return 0;
|
|
}
|
|
|
|
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
|
|
|
const HRESULT comResult = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
|
if (FAILED(comResult))
|
|
{
|
|
OutputDebugString(
|
|
fmt::format(L"[msime]: Failed to initialize the UI COM STA: 0x{:08X}",
|
|
static_cast<unsigned long>(comResult))
|
|
.c_str());
|
|
CloseHandle(hSingleInstanceMutex);
|
|
return 1;
|
|
}
|
|
|
|
// #ifdef FANY_DEBUG
|
|
// Initialize for logging
|
|
InitializeSpdLog();
|
|
// #endif
|
|
|
|
// Initialize config
|
|
InitImeConfig();
|
|
VoiceInput::Initialize();
|
|
Global::candidate_ui.page_size = GetConfiguredCandidatePageSize();
|
|
|
|
::InitIpc();
|
|
::InitNamedPipe();
|
|
g_inputSession = CreateInputSessionFromConfig();
|
|
const std::string configured_backend = DescribeConfiguredInputSessionBackendFromConfig();
|
|
const std::string effective_backend = DescribeEffectiveInputSessionBackendFromConfig();
|
|
const std::string session_summary = fmt::format(
|
|
"Input session backend configured={}, effective={}, scheme={}",
|
|
configured_backend.empty() ? "legacy" : configured_backend, effective_backend,
|
|
SchemeTypeToString(g_inputSession->current_scheme_type()));
|
|
spdlog::info(session_summary);
|
|
#ifdef FANY_DEBUG
|
|
OutputDebugString(fmt::format(L"[msime]: {}", string_to_wstring(session_summary)).c_str());
|
|
#endif
|
|
|
|
RegisterCandidateWindowMessage();
|
|
|
|
WNDCLASSEX wcex;
|
|
RegisterIMEWindowsClass(wcex, hInstance);
|
|
|
|
//
|
|
// Pipe
|
|
//
|
|
/* Named Pipe for IPC between tsf and server */
|
|
std::thread pipe_worker(FanyNamedPipe::WorkerThread);
|
|
std::thread pipe_listener(FanyNamedPipe::EventListenerLoopThread);
|
|
/* Named Pipe for IPC, used to pass data to TSF */
|
|
std::thread to_tsf_pipe_listener(FanyNamedPipe::ToTsfPipeEventListenerLoopThread);
|
|
::mainPipeThread = pipe_listener.native_handle();
|
|
::toTsfPipeThread = to_tsf_pipe_listener.native_handle();
|
|
/* To Tsf Worker Thread Named Pipe for IPC, used to pass data to TSF */
|
|
std::thread to_tsf_worker_thread_pipe_listener(FanyNamedPipe::ToTsfWorkerThreadPipeEventListenerLoopThread);
|
|
::toTsfWorkerThreadPipeThread = to_tsf_worker_thread_pipe_listener.native_handle();
|
|
/* Aux Named Pipe for reconnecting main pipe */
|
|
std::thread aux_pipe_listener(FanyNamedPipe::AuxPipeEventListenerLoopThread);
|
|
|
|
CloudIme::Start([](const std::string &candidate, const std::string &pinyin, uint64_t generation) {
|
|
FanyNamedPipe::EnqueueCloudCandidate(candidate, pinyin, generation);
|
|
});
|
|
EnglishIme::Start(CommonUtils::get_ime_data_path() + "\\english.db",
|
|
[](std::vector<WordItem> candidates, const std::string &input, uint64_t generation) {
|
|
FanyNamedPipe::EnqueueEnglishCandidates(std::move(candidates), input, generation);
|
|
});
|
|
|
|
int ret = CreateCandidateWindow(hInstance);
|
|
|
|
FanyNamedPipe::RegisterStatusSnapshotWindow(nullptr);
|
|
ShutdownWebviews();
|
|
|
|
EnglishIme::Stop();
|
|
CloudIme::Stop();
|
|
VoiceInput::Shutdown();
|
|
|
|
pipe_running = false;
|
|
pipe_queueCv.notify_one();
|
|
pipe_worker.join();
|
|
pipe_listener.join();
|
|
// To Tsf Pipe
|
|
to_tsf_pipe_listener.join();
|
|
to_tsf_worker_thread_pipe_listener.join();
|
|
aux_pipe_listener.join();
|
|
|
|
::CloseIpc();
|
|
CoUninitialize();
|
|
CloseHandle(hSingleInstanceMutex);
|
|
return ret;
|
|
}
|