From 21d2bf9df4227c2f1a738002130a47265e70ada8 Mon Sep 17 00:00:00 2001 From: Bambooin Date: Sat, 24 Feb 2024 22:26:15 +0800 Subject: [PATCH] chore: apply clang format This patch won't change any code logic, just format code base. --- RimeWithWeasel/RimeWithWeasel.cpp | 2618 +++++++++-------- RimeWithWeasel/WeaselUtility.cpp | 77 +- WeaselDeployer/Configurator.cpp | 390 +-- WeaselDeployer/Configurator.h | 20 +- WeaselDeployer/DictManagementDialog.cpp | 316 +- WeaselDeployer/DictManagementDialog.h | 70 +- WeaselDeployer/SwitcherSettingsDialog.cpp | 297 +- WeaselDeployer/SwitcherSettingsDialog.h | 67 +- WeaselDeployer/UIStyleSettings.cpp | 105 +- WeaselDeployer/UIStyleSettings.h | 26 +- WeaselDeployer/UIStyleSettingsDialog.cpp | 106 +- WeaselDeployer/UIStyleSettingsDialog.h | 62 +- WeaselDeployer/WeaselDeployer.cpp | 151 +- WeaselDeployer/WeaselDeployer.h | 31 +- WeaselIME/KeyEvent.cpp | 435 +-- WeaselIME/KeyEvent.h | 438 ++- WeaselIME/WeaselIME.cpp | 1048 ++++--- WeaselIME/WeaselIME.h | 109 +- WeaselIME/dllmain.cpp | 46 +- WeaselIME/ime.cpp | 210 +- WeaselIPC/ActionLoader.cpp | 43 +- WeaselIPC/ActionLoader.h | 18 +- WeaselIPC/Committer.cpp | 27 +- WeaselIPC/Committer.h | 18 +- WeaselIPC/Configurator.cpp | 31 +- WeaselIPC/Configurator.h | 18 +- WeaselIPC/ContextUpdater.cpp | 209 +- WeaselIPC/ContextUpdater.h | 38 +- WeaselIPC/Deserializer.cpp | 67 +- WeaselIPC/Deserializer.h | 38 +- WeaselIPC/PipeChannel.cpp | 205 +- WeaselIPC/ResponseParser.cpp | 100 +- WeaselIPC/Styler.cpp | 29 +- WeaselIPC/Styler.h | 20 +- WeaselIPC/WeaselClientImpl.cpp | 407 ++- WeaselIPC/WeaselClientImpl.h | 92 +- WeaselIPCServer/SecurityAttribute.cpp | 128 +- WeaselIPCServer/SecurityAttribute.h | 23 +- WeaselIPCServer/WeaselServerImpl.cpp | 875 +++--- WeaselIPCServer/WeaselServerImpl.h | 158 +- WeaselServer/SystemTraySDK.cpp | 1506 +++++----- WeaselServer/WeaselServer.cpp | 239 +- WeaselServer/WeaselServerApp.cpp | 92 +- WeaselServer/WeaselServerApp.h | 93 +- WeaselServer/WeaselService.cpp | 282 +- WeaselServer/WeaselService.h | 59 +- WeaselServer/WeaselTrayIcon.cpp | 156 +- WeaselServer/WeaselTrayIcon.h | 50 +- WeaselSetup/InstallOptionsDlg.cpp | 177 +- WeaselSetup/InstallOptionsDlg.h | 113 +- WeaselSetup/WeaselSetup.cpp | 285 +- WeaselSetup/imesetup.cpp | 1142 ++++--- WeaselTSF/CandidateList.cpp | 714 +++-- WeaselTSF/CandidateList.h | 160 +- WeaselTSF/Compartment.cpp | 486 ++- WeaselTSF/Compartment.h | 41 +- WeaselTSF/Composition.cpp | 694 ++--- WeaselTSF/DisplayAttribute.cpp | 103 +- WeaselTSF/DisplayAttributeInfo.cpp | 152 +- WeaselTSF/DisplayAttributeInfo.h | 41 +- WeaselTSF/DisplayAttributeProvider.cpp | 63 +- WeaselTSF/EditSession.cpp | 71 +- WeaselTSF/EditSession.h | 100 +- WeaselTSF/EnumDisplayAttributeInfo.cpp | 195 +- WeaselTSF/EnumDisplayAttributeInfo.h | 36 +- WeaselTSF/Globals.cpp | 56 +- WeaselTSF/Globals.h | 19 +- WeaselTSF/KeyEvent.cpp | 446 +-- WeaselTSF/KeyEvent.h | 438 ++- WeaselTSF/KeyEventSink.cpp | 222 +- WeaselTSF/LanguageBar.cpp | 652 ++-- WeaselTSF/LanguageBar.h | 84 +- WeaselTSF/Register.cpp | 436 ++- WeaselTSF/Server.cpp | 179 +- WeaselTSF/TextEditSink.cpp | 211 +- WeaselTSF/ThreadMgrEventSink.cpp | 101 +- WeaselTSF/WeaselTSF.cpp | 284 +- WeaselTSF/WeaselTSF.h | 394 +-- WeaselTSF/dllmain.cpp | 27 +- WeaselUI/DirectWriteResources.cpp | 644 ++-- WeaselUI/FullScreenLayout.cpp | 225 +- WeaselUI/FullScreenLayout.h | 35 +- WeaselUI/GdiplusBlur.cpp | 661 +++-- WeaselUI/GdiplusBlur.h | 4 +- WeaselUI/HorizontalLayout.cpp | 468 +-- WeaselUI/HorizontalLayout.h | 18 +- WeaselUI/Layout.cpp | 154 +- WeaselUI/Layout.h | 193 +- WeaselUI/StandardLayout.cpp | 740 ++--- WeaselUI/StandardLayout.h | 128 +- WeaselUI/VHorizontalLayout.cpp | 1037 +++---- WeaselUI/VHorizontalLayout.h | 23 +- WeaselUI/VerticalLayout.cpp | 428 +-- WeaselUI/VerticalLayout.h | 18 +- WeaselUI/WeaselPanel.cpp | 1991 +++++++------ WeaselUI/WeaselPanel.h | 210 +- WeaselUI/WeaselUI.cpp | 294 +- include/PipeChannel.h | 326 +- include/ResponseParser.h | 41 +- include/RimeWithWeasel.h | 159 +- include/WeaselCommon.h | 1085 ++++--- include/WeaselIPC.h | 347 ++- include/WeaselUI.h | 302 +- include/WeaselUtility.h | 118 +- include/WeaselVersion.h | 2 +- include/no_logging.h | 11 +- .../TestResponseParser/TestResponseParser.cpp | 167 +- test/TestWeaselIPC/TestWeaselIPC.cpp | 310 +- 108 files changed, 14973 insertions(+), 14931 deletions(-) diff --git a/RimeWithWeasel/RimeWithWeasel.cpp b/RimeWithWeasel/RimeWithWeasel.cpp index f16920b88..4a7be0f42 100644 --- a/RimeWithWeasel/RimeWithWeasel.cpp +++ b/RimeWithWeasel/RimeWithWeasel.cpp @@ -10,350 +10,358 @@ #include #include -#define TRANSPARENT_COLOR 0x00000000 -#define ARGB2ABGR(value) ((value & 0xff000000) | ((value & 0x000000ff) << 16) | (value & 0x0000ff00) | ((value & 0x00ff0000) >> 16)) -#define RGBA2ABGR(value) (((value & 0xff) << 24) | ((value & 0xff000000) >> 24) | ((value & 0x00ff0000) >> 8) | ((value & 0x0000ff00) << 8)) -typedef enum -{ - COLOR_ABGR = 0, - COLOR_ARGB, - COLOR_RGBA -} ColorFormat; +#define TRANSPARENT_COLOR 0x00000000 +#define ARGB2ABGR(value) \ + ((value & 0xff000000) | ((value & 0x000000ff) << 16) | \ + (value & 0x0000ff00) | ((value & 0x00ff0000) >> 16)) +#define RGBA2ABGR(value) \ + (((value & 0xff) << 24) | ((value & 0xff000000) >> 24) | \ + ((value & 0x00ff0000) >> 8) | ((value & 0x0000ff00) << 8)) +typedef enum { COLOR_ABGR = 0, COLOR_ARGB, COLOR_RGBA } ColorFormat; #ifdef USE_SHARP_COLOR_CODE - #define HEX_REGEX std::regex("^(0x|#)[0-9a-f]+$", std::regex::icase) - #define TRIMHEAD_REGEX std::regex("0x|#", std::regex::icase) +#define HEX_REGEX std::regex("^(0x|#)[0-9a-f]+$", std::regex::icase) +#define TRIMHEAD_REGEX std::regex("0x|#", std::regex::icase) #else - #define HEX_REGEX std::regex("^0x[0-9a-f]+$", std::regex::icase) - #define TRIMHEAD_REGEX std::regex("0x", std::regex::icase) +#define HEX_REGEX std::regex("^0x[0-9a-f]+$", std::regex::icase) +#define TRIMHEAD_REGEX std::regex("0x", std::regex::icase) #endif using namespace weasel; -int expand_ibus_modifier(int m) -{ - return (m & 0xff) | ((m & 0xff00) << 16); +int expand_ibus_modifier(int m) { + return (m & 0xff) | ((m & 0xff00) << 16); } -RimeWithWeaselHandler::RimeWithWeaselHandler(UI *ui) - : m_ui(ui) - , m_active_session(0) - , m_disabled(true) - , m_current_dark_mode(false) - , m_global_ascii_mode(false) - , m_show_notifications_time(1200) - , _UpdateUICallback(NULL) -{ - _Setup(); +RimeWithWeaselHandler::RimeWithWeaselHandler(UI* ui) + : m_ui(ui), + m_active_session(0), + m_disabled(true), + m_current_dark_mode(false), + m_global_ascii_mode(false), + m_show_notifications_time(1200), + _UpdateUICallback(NULL) { + _Setup(); } -RimeWithWeaselHandler::~RimeWithWeaselHandler() -{ - m_show_notifications.clear(); - m_session_status_map.clear(); - m_app_options.clear(); +RimeWithWeaselHandler::~RimeWithWeaselHandler() { + m_show_notifications.clear(); + m_session_status_map.clear(); + m_app_options.clear(); } bool addsession = false; void _UpdateUIStyle(RimeConfig* config, UI* ui, bool initialize); -bool _UpdateUIStyleColor(RimeConfig* config, UIStyle& style, std::string color = ""); +bool _UpdateUIStyleColor(RimeConfig* config, + UIStyle& style, + std::string color = ""); void _LoadAppOptions(RimeConfig* config, AppOptionsByAppName& app_options); -void _RefreshTrayIcon(const UINT session_id, const std::function _UpdateUICallback) -{ - // Dangerous, don't touch - static char app_name[50]; - RimeGetProperty(session_id, "client_app", app_name, sizeof(app_name) - 1); - if (string_to_wstring(app_name, CP_UTF8) == std::wstring(L"explorer.exe")) - boost::thread th([=]() { ::Sleep(100); if (_UpdateUICallback) _UpdateUICallback(); }); - else - if (_UpdateUICallback) _UpdateUICallback(); +void _RefreshTrayIcon(const UINT session_id, + const std::function _UpdateUICallback) { + // Dangerous, don't touch + static char app_name[50]; + RimeGetProperty(session_id, "client_app", app_name, sizeof(app_name) - 1); + if (string_to_wstring(app_name, CP_UTF8) == std::wstring(L"explorer.exe")) + boost::thread th([=]() { + ::Sleep(100); + if (_UpdateUICallback) + _UpdateUICallback(); + }); + else if (_UpdateUICallback) + _UpdateUICallback(); } -void RimeWithWeaselHandler::_Setup() -{ - RIME_STRUCT(RimeTraits, weasel_traits); - std::string shared_dir = wstring_to_string(WeaselSharedDataPath().wstring(), CP_UTF8); - std::string user_dir = wstring_to_string(WeaselUserDataPath().wstring(), CP_UTF8); - weasel_traits.shared_data_dir = shared_dir.c_str(); - weasel_traits.user_data_dir = user_dir.c_str(); - weasel_traits.prebuilt_data_dir = weasel_traits.shared_data_dir; - std::string distribution_name = wstring_to_string(WEASEL_IME_NAME, CP_UTF8); - weasel_traits.distribution_name = distribution_name.c_str(); - weasel_traits.distribution_code_name = WEASEL_CODE_NAME; - weasel_traits.distribution_version = WEASEL_VERSION; - weasel_traits.app_name = "rime.weasel"; - RimeSetup(&weasel_traits); - RimeSetNotificationHandler(&RimeWithWeaselHandler::OnNotify, this); +void RimeWithWeaselHandler::_Setup() { + RIME_STRUCT(RimeTraits, weasel_traits); + std::string shared_dir = + wstring_to_string(WeaselSharedDataPath().wstring(), CP_UTF8); + std::string user_dir = + wstring_to_string(WeaselUserDataPath().wstring(), CP_UTF8); + weasel_traits.shared_data_dir = shared_dir.c_str(); + weasel_traits.user_data_dir = user_dir.c_str(); + weasel_traits.prebuilt_data_dir = weasel_traits.shared_data_dir; + std::string distribution_name = wstring_to_string(WEASEL_IME_NAME, CP_UTF8); + weasel_traits.distribution_name = distribution_name.c_str(); + weasel_traits.distribution_code_name = WEASEL_CODE_NAME; + weasel_traits.distribution_version = WEASEL_VERSION; + weasel_traits.app_name = "rime.weasel"; + RimeSetup(&weasel_traits); + RimeSetNotificationHandler(&RimeWithWeaselHandler::OnNotify, this); } -void RimeWithWeaselHandler::Initialize() -{ - m_disabled = _IsDeployerRunning(); - if (m_disabled) - { - return; - } - - LOG(INFO) << "Initializing la rime."; - RimeInitialize(NULL); - if (RimeStartMaintenance(/*full_check = */False)) - { - m_disabled = true; - } - - RimeConfig config = { NULL }; - if (RimeConfigOpen("weasel", &config)) - { - if (m_ui) - { - _UpdateUIStyle(&config, m_ui, true); - _UpdateShowNotifications(&config, true); - m_current_dark_mode = IsUserDarkMode(); - if(m_current_dark_mode) { - const int BUF_SIZE = 255; - char buffer[BUF_SIZE + 1] = { 0 }; - if (RimeConfigGetString(&config, "style/color_scheme_dark", buffer, BUF_SIZE)){ - std::string color_name(buffer); - _UpdateUIStyleColor(&config, m_ui->style(), color_name); - } - } - m_base_style = m_ui->style(); - } - Bool global_ascii = false; - if (RimeConfigGetBool(&config, "global_ascii", &global_ascii)) - m_global_ascii_mode = !!global_ascii; - if (!RimeConfigGetInt(&config, "show_notifications_time", &m_show_notifications_time)) - m_show_notifications_time = 1200; - _LoadAppOptions(&config, m_app_options); - RimeConfigClose(&config); - } - m_last_schema_id.clear(); +void RimeWithWeaselHandler::Initialize() { + m_disabled = _IsDeployerRunning(); + if (m_disabled) { + return; + } + + LOG(INFO) << "Initializing la rime."; + RimeInitialize(NULL); + if (RimeStartMaintenance(/*full_check = */ False)) { + m_disabled = true; + } + + RimeConfig config = {NULL}; + if (RimeConfigOpen("weasel", &config)) { + if (m_ui) { + _UpdateUIStyle(&config, m_ui, true); + _UpdateShowNotifications(&config, true); + m_current_dark_mode = IsUserDarkMode(); + if (m_current_dark_mode) { + const int BUF_SIZE = 255; + char buffer[BUF_SIZE + 1] = {0}; + if (RimeConfigGetString(&config, "style/color_scheme_dark", buffer, + BUF_SIZE)) { + std::string color_name(buffer); + _UpdateUIStyleColor(&config, m_ui->style(), color_name); + } + } + m_base_style = m_ui->style(); + } + Bool global_ascii = false; + if (RimeConfigGetBool(&config, "global_ascii", &global_ascii)) + m_global_ascii_mode = !!global_ascii; + if (!RimeConfigGetInt(&config, "show_notifications_time", + &m_show_notifications_time)) + m_show_notifications_time = 1200; + _LoadAppOptions(&config, m_app_options); + RimeConfigClose(&config); + } + m_last_schema_id.clear(); } -void RimeWithWeaselHandler::Finalize() -{ - m_active_session = 0; - m_disabled = true; - m_session_status_map.clear(); - LOG(INFO) << "Finalizing la rime."; - RimeFinalize(); +void RimeWithWeaselHandler::Finalize() { + m_active_session = 0; + m_disabled = true; + m_session_status_map.clear(); + LOG(INFO) << "Finalizing la rime."; + RimeFinalize(); } -UINT RimeWithWeaselHandler::FindSession(UINT session_id) -{ - if (m_disabled) return 0; - Bool found = RimeFindSession(session_id); - DLOG(INFO) << "Find session: session_id = " << session_id << ", found = " << found; - return found ? session_id : 0; +UINT RimeWithWeaselHandler::FindSession(UINT session_id) { + if (m_disabled) + return 0; + Bool found = RimeFindSession(session_id); + DLOG(INFO) << "Find session: session_id = " << session_id + << ", found = " << found; + return found ? session_id : 0; } -UINT RimeWithWeaselHandler::AddSession(LPWSTR buffer, EatLine eat) -{ - if (m_disabled) - { - DLOG(INFO) << "Trying to resume service."; - EndMaintenance(); - if (m_disabled) return 0; - } - UINT session_id = (UINT)RimeCreateSession(); - if(m_global_ascii_mode) { - for (const auto& pair : m_session_status_map) { - if(pair.first) { - RimeSetOption(session_id, "ascii_mode", !!pair.second.status.is_ascii_mode); - break; - } - } - } - DLOG(INFO) << "Add session: created session_id = " << session_id; - _ReadClientInfo(session_id, buffer); - - m_session_status_map[session_id] = SessionStatus(); - m_session_status_map[session_id].style = m_base_style; - - RIME_STRUCT(RimeStatus, status); - if (RimeGetStatus(session_id, &status)) - { - std::string schema_id = status.schema_id; - m_last_schema_id = schema_id; - _LoadSchemaSpecificSettings(session_id, schema_id); - _LoadAppInlinePreeditSet(session_id, true); - _UpdateInlinePreeditStatus(session_id); - _RefreshTrayIcon(session_id, _UpdateUICallback); - m_session_status_map[session_id].status = status; - m_session_status_map[session_id].__synced = false; - RimeFreeStatus(&status); - } - m_ui->style() = m_session_status_map[session_id].style; - // show session's welcome message :-) if any - if (eat) { - _Respond(session_id, eat); - } - addsession = true; - _UpdateUI(session_id); - addsession = false; - m_active_session = session_id; - return session_id; +UINT RimeWithWeaselHandler::AddSession(LPWSTR buffer, EatLine eat) { + if (m_disabled) { + DLOG(INFO) << "Trying to resume service."; + EndMaintenance(); + if (m_disabled) + return 0; + } + UINT session_id = (UINT)RimeCreateSession(); + if (m_global_ascii_mode) { + for (const auto& pair : m_session_status_map) { + if (pair.first) { + RimeSetOption(session_id, "ascii_mode", + !!pair.second.status.is_ascii_mode); + break; + } + } + } + DLOG(INFO) << "Add session: created session_id = " << session_id; + _ReadClientInfo(session_id, buffer); + + m_session_status_map[session_id] = SessionStatus(); + m_session_status_map[session_id].style = m_base_style; + + RIME_STRUCT(RimeStatus, status); + if (RimeGetStatus(session_id, &status)) { + std::string schema_id = status.schema_id; + m_last_schema_id = schema_id; + _LoadSchemaSpecificSettings(session_id, schema_id); + _LoadAppInlinePreeditSet(session_id, true); + _UpdateInlinePreeditStatus(session_id); + _RefreshTrayIcon(session_id, _UpdateUICallback); + m_session_status_map[session_id].status = status; + m_session_status_map[session_id].__synced = false; + RimeFreeStatus(&status); + } + m_ui->style() = m_session_status_map[session_id].style; + // show session's welcome message :-) if any + if (eat) { + _Respond(session_id, eat); + } + addsession = true; + _UpdateUI(session_id); + addsession = false; + m_active_session = session_id; + return session_id; } -UINT RimeWithWeaselHandler::RemoveSession(UINT session_id) -{ - if (m_ui) m_ui->Hide(); - if (m_disabled) return 0; - DLOG(INFO) << "Remove session: session_id = " << session_id; - // TODO: force committing? otherwise current composition would be lost - RimeDestroySession(session_id); - m_session_status_map.erase(session_id); - m_active_session = 0; - return 0; +UINT RimeWithWeaselHandler::RemoveSession(UINT session_id) { + if (m_ui) + m_ui->Hide(); + if (m_disabled) + return 0; + DLOG(INFO) << "Remove session: session_id = " << session_id; + // TODO: force committing? otherwise current composition would be lost + RimeDestroySession(session_id); + m_session_status_map.erase(session_id); + m_active_session = 0; + return 0; } -namespace ibus -{ - enum Keycode - { - Escape = 0xFF1B, - XK_bracketleft = 0x005b, /* U+005B LEFT SQUARE BRACKET */ - XK_c = 0x0063, /* U+0063 LATIN SMALL LETTER C */ - XK_C = 0x0043, /* U+0043 LATIN CAPITAL LETTER C */ - }; +namespace ibus { +enum Keycode { + Escape = 0xFF1B, + XK_bracketleft = 0x005b, /* U+005B LEFT SQUARE BRACKET */ + XK_c = 0x0063, /* U+0063 LATIN SMALL LETTER C */ + XK_C = 0x0043, /* U+0043 LATIN CAPITAL LETTER C */ +}; } -void RimeWithWeaselHandler::UpdateColorTheme(BOOL darkMode) -{ - RimeConfig config = { NULL }; - if (RimeConfigOpen("weasel", &config)) - { - if (m_ui) - { - _UpdateUIStyle(&config, m_ui, true); - m_current_dark_mode = darkMode; - if(darkMode) { - const int BUF_SIZE = 255; - char buffer[BUF_SIZE + 1] = { 0 }; - if (RimeConfigGetString(&config, "style/color_scheme_dark", buffer, BUF_SIZE)) { - std::string color_name(buffer); - _UpdateUIStyleColor(&config, m_ui->style(), color_name); - } - } - m_base_style = m_ui->style(); - } - RimeConfigClose(&config); - } - - for(auto& pair : m_session_status_map) { - RIME_STRUCT(RimeStatus, status); - if (RimeGetStatus(pair.first, &status)) - { - _LoadSchemaSpecificSettings(pair.first, std::string(status.schema_id)); - _LoadAppInlinePreeditSet(pair.first, true); - _UpdateInlinePreeditStatus(pair.first); - pair.second.status = status; - pair.second.__synced = false; - RimeFreeStatus(&status); - } - } - m_ui->style() = m_session_status_map[m_active_session].style; +void RimeWithWeaselHandler::UpdateColorTheme(BOOL darkMode) { + RimeConfig config = {NULL}; + if (RimeConfigOpen("weasel", &config)) { + if (m_ui) { + _UpdateUIStyle(&config, m_ui, true); + m_current_dark_mode = darkMode; + if (darkMode) { + const int BUF_SIZE = 255; + char buffer[BUF_SIZE + 1] = {0}; + if (RimeConfigGetString(&config, "style/color_scheme_dark", buffer, + BUF_SIZE)) { + std::string color_name(buffer); + _UpdateUIStyleColor(&config, m_ui->style(), color_name); + } + } + m_base_style = m_ui->style(); + } + RimeConfigClose(&config); + } + + for (auto& pair : m_session_status_map) { + RIME_STRUCT(RimeStatus, status); + if (RimeGetStatus(pair.first, &status)) { + _LoadSchemaSpecificSettings(pair.first, std::string(status.schema_id)); + _LoadAppInlinePreeditSet(pair.first, true); + _UpdateInlinePreeditStatus(pair.first); + pair.second.status = status; + pair.second.__synced = false; + RimeFreeStatus(&status); + } + } + m_ui->style() = m_session_status_map[m_active_session].style; } -BOOL RimeWithWeaselHandler::ProcessKeyEvent(KeyEvent keyEvent, UINT session_id, EatLine eat) -{ - DLOG(INFO) << "Process key event: keycode = " << keyEvent.keycode << ", mask = " << keyEvent.mask - << ", session_id = " << session_id; - if (m_disabled) return FALSE; - Bool handled = RimeProcessKey(session_id, keyEvent.keycode, expand_ibus_modifier(keyEvent.mask)); - if(!handled) { - bool isVimBackInCommandMode = (keyEvent.keycode == ibus::Keycode::Escape) || - ((keyEvent.mask & (1 << 2)) && (keyEvent.keycode == ibus::Keycode::XK_c || - keyEvent.keycode == ibus::Keycode::XK_c || - keyEvent.keycode == ibus::Keycode::XK_bracketleft)); - if (isVimBackInCommandMode - && RimeGetOption(session_id, "vim_mode") - && !RimeGetOption(session_id, "ascii_mode")) { - RimeSetOption(session_id, "ascii_mode", True); - } - } - _Respond(session_id, eat); - _UpdateUI(session_id); - m_active_session = session_id; - return (BOOL)handled; +BOOL RimeWithWeaselHandler::ProcessKeyEvent(KeyEvent keyEvent, + UINT session_id, + EatLine eat) { + DLOG(INFO) << "Process key event: keycode = " << keyEvent.keycode + << ", mask = " << keyEvent.mask << ", session_id = " << session_id; + if (m_disabled) + return FALSE; + Bool handled = RimeProcessKey(session_id, keyEvent.keycode, + expand_ibus_modifier(keyEvent.mask)); + if (!handled) { + bool isVimBackInCommandMode = + (keyEvent.keycode == ibus::Keycode::Escape) || + ((keyEvent.mask & (1 << 2)) && + (keyEvent.keycode == ibus::Keycode::XK_c || + keyEvent.keycode == ibus::Keycode::XK_c || + keyEvent.keycode == ibus::Keycode::XK_bracketleft)); + if (isVimBackInCommandMode && RimeGetOption(session_id, "vim_mode") && + !RimeGetOption(session_id, "ascii_mode")) { + RimeSetOption(session_id, "ascii_mode", True); + } + } + _Respond(session_id, eat); + _UpdateUI(session_id); + m_active_session = session_id; + return (BOOL)handled; } -void RimeWithWeaselHandler::CommitComposition(UINT session_id) -{ - DLOG(INFO) << "Commit composition: session_id = " << session_id; - if (m_disabled) return; - RimeCommitComposition(session_id); - _UpdateUI(session_id); - m_active_session = session_id; +void RimeWithWeaselHandler::CommitComposition(UINT session_id) { + DLOG(INFO) << "Commit composition: session_id = " << session_id; + if (m_disabled) + return; + RimeCommitComposition(session_id); + _UpdateUI(session_id); + m_active_session = session_id; } -void RimeWithWeaselHandler::ClearComposition(UINT session_id) -{ - DLOG(INFO) << "Clear composition: session_id = " << session_id; - if (m_disabled) return; - RimeClearComposition(session_id); - _UpdateUI(session_id); - m_active_session = session_id; +void RimeWithWeaselHandler::ClearComposition(UINT session_id) { + DLOG(INFO) << "Clear composition: session_id = " << session_id; + if (m_disabled) + return; + RimeClearComposition(session_id); + _UpdateUI(session_id); + m_active_session = session_id; } -void RimeWithWeaselHandler::SelectCandidateOnCurrentPage(size_t index, UINT session_id) -{ - DLOG(INFO) << "select candidate on current page, session_id = " << session_id << ", index = " << index; - if (m_disabled) return; - RimeApi* api = rime_get_api(); - api->select_candidate_on_current_page(session_id, index); +void RimeWithWeaselHandler::SelectCandidateOnCurrentPage(size_t index, + UINT session_id) { + DLOG(INFO) << "select candidate on current page, session_id = " << session_id + << ", index = " << index; + if (m_disabled) + return; + RimeApi* api = rime_get_api(); + api->select_candidate_on_current_page(session_id, index); } -bool RimeWithWeaselHandler::HighlightCandidateOnCurrentPage(size_t index, UINT session_id, EatLine eat) -{ - DLOG(INFO) << "highlight candidate on current page, session_id = " << session_id << ", index = " << index; - RimeApi* api = rime_get_api(); - if(!api) - return false; - bool res = api->highlight_candidate_on_current_page(session_id, index); - _Respond(session_id, eat); - _UpdateUI(session_id); - return res; +bool RimeWithWeaselHandler::HighlightCandidateOnCurrentPage(size_t index, + UINT session_id, + EatLine eat) { + DLOG(INFO) << "highlight candidate on current page, session_id = " + << session_id << ", index = " << index; + RimeApi* api = rime_get_api(); + if (!api) + return false; + bool res = api->highlight_candidate_on_current_page(session_id, index); + _Respond(session_id, eat); + _UpdateUI(session_id); + return res; } -bool RimeWithWeaselHandler::ChangePage(bool backward, UINT session_id, EatLine eat) -{ - DLOG(INFO) << "change page, session_id = " << session_id << (backward? "backward" : "foreward"); - RimeApi* api = rime_get_api(); - if(!api) - return false; - bool res = api->change_page(session_id, backward); - _Respond(session_id, eat); - _UpdateUI(session_id); - return res; +bool RimeWithWeaselHandler::ChangePage(bool backward, + UINT session_id, + EatLine eat) { + DLOG(INFO) << "change page, session_id = " << session_id + << (backward ? "backward" : "foreward"); + RimeApi* api = rime_get_api(); + if (!api) + return false; + bool res = api->change_page(session_id, backward); + _Respond(session_id, eat); + _UpdateUI(session_id); + return res; } -void RimeWithWeaselHandler::FocusIn(DWORD client_caps, UINT session_id) -{ - DLOG(INFO) << "Focus in: session_id = " << session_id << ", client_caps = " << client_caps; - if (m_disabled) return; - _UpdateUI(session_id); - m_active_session = session_id; +void RimeWithWeaselHandler::FocusIn(DWORD client_caps, UINT session_id) { + DLOG(INFO) << "Focus in: session_id = " << session_id + << ", client_caps = " << client_caps; + if (m_disabled) + return; + _UpdateUI(session_id); + m_active_session = session_id; } -void RimeWithWeaselHandler::FocusOut(DWORD param, UINT session_id) -{ - DLOG(INFO) << "Focus out: session_id = " << session_id; - if (m_ui) m_ui->Hide(); - m_active_session = 0; +void RimeWithWeaselHandler::FocusOut(DWORD param, UINT session_id) { + DLOG(INFO) << "Focus out: session_id = " << session_id; + if (m_ui) + m_ui->Hide(); + m_active_session = 0; } -void RimeWithWeaselHandler::UpdateInputPosition(RECT const& rc, UINT session_id) -{ - DLOG(INFO) << "Update input position: (" << rc.left << ", " << rc.top - << "), session_id = " << session_id << ", m_active_session = " << m_active_session; - if (m_ui) m_ui->UpdateInputPosition(rc); - if (m_disabled) return; - if (m_active_session != session_id) - { - _UpdateUI(session_id); - m_active_session = session_id; - } +void RimeWithWeaselHandler::UpdateInputPosition(RECT const& rc, + UINT session_id) { + DLOG(INFO) << "Update input position: (" << rc.left << ", " << rc.top + << "), session_id = " << session_id + << ", m_active_session = " << m_active_session; + if (m_ui) + m_ui->UpdateInputPosition(rc); + if (m_disabled) + return; + if (m_active_session != session_id) { + _UpdateUI(session_id); + m_active_session = session_id; + } } std::string RimeWithWeaselHandler::m_message_type; @@ -362,997 +370,1151 @@ std::string RimeWithWeaselHandler::m_message_label; std::string RimeWithWeaselHandler::m_option_name; void RimeWithWeaselHandler::OnNotify(void* context_object, - uintptr_t session_id, + uintptr_t session_id, const char* message_type, - const char* message_value) -{ - // may be running in a thread when deploying rime - RimeWithWeaselHandler* self = reinterpret_cast(context_object); - if (!self || !message_type || !message_value) return; - m_message_type = message_type; - m_message_value = message_value; - RimeApi* rime = rime_get_api(); - if (RIME_API_AVAILABLE(rime, get_state_label) && - !strcmp(message_type, "option")) { - Bool state = message_value[0] != '!'; - const char* option_name = message_value + !state; - m_option_name = option_name; - const char* state_label = - rime->get_state_label(session_id, option_name, state); - if (state_label) { - m_message_label = std::string(state_label); - } - } + const char* message_value) { + // may be running in a thread when deploying rime + RimeWithWeaselHandler* self = + reinterpret_cast(context_object); + if (!self || !message_type || !message_value) + return; + m_message_type = message_type; + m_message_value = message_value; + RimeApi* rime = rime_get_api(); + if (RIME_API_AVAILABLE(rime, get_state_label) && + !strcmp(message_type, "option")) { + Bool state = message_value[0] != '!'; + const char* option_name = message_value + !state; + m_option_name = option_name; + const char* state_label = + rime->get_state_label(session_id, option_name, state); + if (state_label) { + m_message_label = std::string(state_label); + } + } } -void RimeWithWeaselHandler::_ReadClientInfo(UINT session_id, LPWSTR buffer) -{ - std::string app_name; - std::string client_type; - // parse request text - wbufferstream bs(buffer, WEASEL_IPC_BUFFER_LENGTH); - std::wstring line; - while (bs.good()) - { - std::getline(bs, line); - if (!bs.good()) - break; - // file ends - if (line == L".") - break; - const std::wstring kClientAppKey = L"session.client_app="; - if (starts_with(line, kClientAppKey)) - { - std::wstring lwr = line; - to_lower(lwr); - app_name = wstring_to_string(lwr.substr(kClientAppKey.length()).c_str(), CP_UTF8); - } - const std::wstring kClientTypeKey = L"session.client_type="; - if (starts_with(line, kClientTypeKey)) - { - client_type = wstring_to_string(line.substr(kClientTypeKey.length()).c_str(), CP_UTF8); - } - } - // set app specific options - if (!app_name.empty()) - { - RimeSetProperty(session_id, "client_app", app_name.c_str()); - - auto it = m_app_options.find(app_name); - if (it != m_app_options.end()) - { - AppOptions& options(m_app_options[it->first]); - std::for_each(options.begin(), options.end(), [session_id](std::pair &pair) - { - DLOG(INFO) << "set app option: " << pair.first << " = " << pair.second; - RimeSetOption(session_id, pair.first.c_str(), Bool(pair.second)); - }); - } - } - // ime | tsf - RimeSetProperty(session_id, "client_type", client_type.c_str()); - // inline preedit - bool inline_preedit = m_session_status_map[session_id].style.inline_preedit && (client_type == "tsf"); - RimeSetOption(session_id, "inline_preedit", Bool(inline_preedit)); - // show soft cursor on weasel panel but not inline - RimeSetOption(session_id, "soft_cursor", Bool(!inline_preedit)); +void RimeWithWeaselHandler::_ReadClientInfo(UINT session_id, LPWSTR buffer) { + std::string app_name; + std::string client_type; + // parse request text + wbufferstream bs(buffer, WEASEL_IPC_BUFFER_LENGTH); + std::wstring line; + while (bs.good()) { + std::getline(bs, line); + if (!bs.good()) + break; + // file ends + if (line == L".") + break; + const std::wstring kClientAppKey = L"session.client_app="; + if (starts_with(line, kClientAppKey)) { + std::wstring lwr = line; + to_lower(lwr); + app_name = wstring_to_string(lwr.substr(kClientAppKey.length()).c_str(), + CP_UTF8); + } + const std::wstring kClientTypeKey = L"session.client_type="; + if (starts_with(line, kClientTypeKey)) { + client_type = wstring_to_string( + line.substr(kClientTypeKey.length()).c_str(), CP_UTF8); + } + } + // set app specific options + if (!app_name.empty()) { + RimeSetProperty(session_id, "client_app", app_name.c_str()); + + auto it = m_app_options.find(app_name); + if (it != m_app_options.end()) { + AppOptions& options(m_app_options[it->first]); + std::for_each(options.begin(), options.end(), + [session_id](std::pair& pair) { + DLOG(INFO) << "set app option: " << pair.first << " = " + << pair.second; + RimeSetOption(session_id, pair.first.c_str(), + Bool(pair.second)); + }); + } + } + // ime | tsf + RimeSetProperty(session_id, "client_type", client_type.c_str()); + // inline preedit + bool inline_preedit = m_session_status_map[session_id].style.inline_preedit && + (client_type == "tsf"); + RimeSetOption(session_id, "inline_preedit", Bool(inline_preedit)); + // show soft cursor on weasel panel but not inline + RimeSetOption(session_id, "soft_cursor", Bool(!inline_preedit)); } -void RimeWithWeaselHandler::_GetCandidateInfo(CandidateInfo & cinfo, RimeContext & ctx) -{ - cinfo.candies.resize(ctx.menu.num_candidates); - cinfo.comments.resize(ctx.menu.num_candidates); - cinfo.labels.resize(ctx.menu.num_candidates); - for (int i = 0; i < ctx.menu.num_candidates; ++i) - { - cinfo.candies[i].str = std::regex_replace(string_to_wstring(ctx.menu.candidates[i].text, CP_UTF8), std::wregex(L"\\r\\n|\\n|\\r"), L"\r"); - if (ctx.menu.candidates[i].comment) - { - cinfo.comments[i].str = std::regex_replace(string_to_wstring(ctx.menu.candidates[i].comment, CP_UTF8), std::wregex(L"\\r\\n|\\n|\\r"), L"\r"); - } - if (RIME_STRUCT_HAS_MEMBER(ctx, ctx.select_labels) && ctx.select_labels) - { - cinfo.labels[i].str = std::regex_replace(string_to_wstring(ctx.select_labels[i], CP_UTF8), std::wregex(L"\\r\\n|\\n|\\r"), L"\r"); - } - else if (ctx.menu.select_keys) - { - cinfo.labels[i].str = std::regex_replace(std::wstring(1, ctx.menu.select_keys[i]), std::wregex(L"\\r\\n|\\n|\\r"), L"\r"); - } - else - { - cinfo.labels[i].str = std::to_wstring((i + 1) % 10); - } - } - cinfo.highlighted = ctx.menu.highlighted_candidate_index; - cinfo.currentPage = ctx.menu.page_no; - cinfo.is_last_page = ctx.menu.is_last_page; +void RimeWithWeaselHandler::_GetCandidateInfo(CandidateInfo& cinfo, + RimeContext& ctx) { + cinfo.candies.resize(ctx.menu.num_candidates); + cinfo.comments.resize(ctx.menu.num_candidates); + cinfo.labels.resize(ctx.menu.num_candidates); + for (int i = 0; i < ctx.menu.num_candidates; ++i) { + cinfo.candies[i].str = std::regex_replace( + string_to_wstring(ctx.menu.candidates[i].text, CP_UTF8), + std::wregex(L"\\r\\n|\\n|\\r"), L"\r"); + if (ctx.menu.candidates[i].comment) { + cinfo.comments[i].str = std::regex_replace( + string_to_wstring(ctx.menu.candidates[i].comment, CP_UTF8), + std::wregex(L"\\r\\n|\\n|\\r"), L"\r"); + } + if (RIME_STRUCT_HAS_MEMBER(ctx, ctx.select_labels) && ctx.select_labels) { + cinfo.labels[i].str = + std::regex_replace(string_to_wstring(ctx.select_labels[i], CP_UTF8), + std::wregex(L"\\r\\n|\\n|\\r"), L"\r"); + } else if (ctx.menu.select_keys) { + cinfo.labels[i].str = + std::regex_replace(std::wstring(1, ctx.menu.select_keys[i]), + std::wregex(L"\\r\\n|\\n|\\r"), L"\r"); + } else { + cinfo.labels[i].str = std::to_wstring((i + 1) % 10); + } + } + cinfo.highlighted = ctx.menu.highlighted_candidate_index; + cinfo.currentPage = ctx.menu.page_no; + cinfo.is_last_page = ctx.menu.is_last_page; } -void RimeWithWeaselHandler::StartMaintenance() -{ - m_session_status_map.clear(); - Finalize(); - _UpdateUI(0); +void RimeWithWeaselHandler::StartMaintenance() { + m_session_status_map.clear(); + Finalize(); + _UpdateUI(0); } -void RimeWithWeaselHandler::EndMaintenance() -{ - if (m_disabled) - { - Initialize(); - _UpdateUI(0); - } - m_session_status_map.clear(); +void RimeWithWeaselHandler::EndMaintenance() { + if (m_disabled) { + Initialize(); + _UpdateUI(0); + } + m_session_status_map.clear(); } -void RimeWithWeaselHandler::SetOption(UINT session_id, const std::string & opt, bool val) -{ - // from no-session client, not actual typing session - if (!session_id) - { - if (m_global_ascii_mode && opt == "ascii_mode") - { - for (auto& pair : m_session_status_map) - RimeSetOption(pair.first, "ascii_mode", val); - } - else - RimeSetOption(m_active_session, opt.c_str(), val); - } - else - RimeSetOption(session_id, opt.c_str(), val); +void RimeWithWeaselHandler::SetOption(UINT session_id, + const std::string& opt, + bool val) { + // from no-session client, not actual typing session + if (!session_id) { + if (m_global_ascii_mode && opt == "ascii_mode") { + for (auto& pair : m_session_status_map) + RimeSetOption(pair.first, "ascii_mode", val); + } else + RimeSetOption(m_active_session, opt.c_str(), val); + } else + RimeSetOption(session_id, opt.c_str(), val); } -void RimeWithWeaselHandler::OnUpdateUI(std::function const &cb) -{ - _UpdateUICallback = cb; +void RimeWithWeaselHandler::OnUpdateUI(std::function const& cb) { + _UpdateUICallback = cb; } -bool RimeWithWeaselHandler::_IsDeployerRunning() -{ - HANDLE hMutex = CreateMutex(NULL, TRUE, L"WeaselDeployerMutex"); - bool deployer_detected = hMutex && GetLastError() == ERROR_ALREADY_EXISTS; - if (hMutex) - { - CloseHandle(hMutex); - } - return deployer_detected; +bool RimeWithWeaselHandler::_IsDeployerRunning() { + HANDLE hMutex = CreateMutex(NULL, TRUE, L"WeaselDeployerMutex"); + bool deployer_detected = hMutex && GetLastError() == ERROR_ALREADY_EXISTS; + if (hMutex) { + CloseHandle(hMutex); + } + return deployer_detected; } -void RimeWithWeaselHandler::_UpdateUI(UINT session_id) -{ - Status weasel_status; - Context weasel_context; - - bool is_tsf = _IsSessionTSF(session_id); - - if (session_id == 0) - weasel_status.disabled = m_disabled; - - _GetStatus(weasel_status, session_id, weasel_context); - - if (!is_tsf) { - _GetContext(weasel_context, session_id); - } - - if (!m_ui) return; - - if (RimeGetOption(session_id, "inline_preedit")) - m_session_status_map[session_id].style.client_caps |= INLINE_PREEDIT_CAPABLE; - else - m_session_status_map[session_id].style.client_caps &= ~INLINE_PREEDIT_CAPABLE; - - if (weasel_status.composing) - { - m_ui->Update(weasel_context, weasel_status); - if (!is_tsf) m_ui->Show(); - } - else if (!_ShowMessage(weasel_context, weasel_status)) - { - m_ui->Hide(); - m_ui->Update(weasel_context, weasel_status); - } - - _RefreshTrayIcon(session_id, _UpdateUICallback); - - m_message_type.clear(); - m_message_value.clear(); - m_message_label.clear(); - m_option_name.clear(); +void RimeWithWeaselHandler::_UpdateUI(UINT session_id) { + Status weasel_status; + Context weasel_context; + + bool is_tsf = _IsSessionTSF(session_id); + + if (session_id == 0) + weasel_status.disabled = m_disabled; + + _GetStatus(weasel_status, session_id, weasel_context); + + if (!is_tsf) { + _GetContext(weasel_context, session_id); + } + + if (!m_ui) + return; + + if (RimeGetOption(session_id, "inline_preedit")) + m_session_status_map[session_id].style.client_caps |= + INLINE_PREEDIT_CAPABLE; + else + m_session_status_map[session_id].style.client_caps &= + ~INLINE_PREEDIT_CAPABLE; + + if (weasel_status.composing) { + m_ui->Update(weasel_context, weasel_status); + if (!is_tsf) + m_ui->Show(); + } else if (!_ShowMessage(weasel_context, weasel_status)) { + m_ui->Hide(); + m_ui->Update(weasel_context, weasel_status); + } + + _RefreshTrayIcon(session_id, _UpdateUICallback); + + m_message_type.clear(); + m_message_value.clear(); + m_message_label.clear(); + m_option_name.clear(); } -std::wstring _LoadIconSettingFromSchema(RimeConfig& config, - const char* key1, - const char* key2, - const boost::filesystem::path& user_dir, - const boost::filesystem::path& shared_dir) -{ - const int BUF_SIZE = 255; - char buffer[BUF_SIZE + 1] = {0}; - if (RimeConfigGetString(&config, key1, buffer, BUF_SIZE) || - (key2 != NULL && RimeConfigGetString(&config, key2, buffer, BUF_SIZE))) { - std::wstring resource = string_to_wstring(buffer, CP_UTF8); - DWORD dwAttrib = GetFileAttributes((user_dir / resource).c_str()); - if (INVALID_FILE_ATTRIBUTES != dwAttrib && 0 == (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) { - return (user_dir / resource).wstring(); - } - dwAttrib = GetFileAttributes((shared_dir / resource).c_str()); - if (INVALID_FILE_ATTRIBUTES != dwAttrib && 0 == (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) { - return (shared_dir / resource).wstring(); - } - } - return L""; +std::wstring _LoadIconSettingFromSchema( + RimeConfig& config, + const char* key1, + const char* key2, + const boost::filesystem::path& user_dir, + const boost::filesystem::path& shared_dir) { + const int BUF_SIZE = 255; + char buffer[BUF_SIZE + 1] = {0}; + if (RimeConfigGetString(&config, key1, buffer, BUF_SIZE) || + (key2 != NULL && RimeConfigGetString(&config, key2, buffer, BUF_SIZE))) { + std::wstring resource = string_to_wstring(buffer, CP_UTF8); + DWORD dwAttrib = GetFileAttributes((user_dir / resource).c_str()); + if (INVALID_FILE_ATTRIBUTES != dwAttrib && + 0 == (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) { + return (user_dir / resource).wstring(); + } + dwAttrib = GetFileAttributes((shared_dir / resource).c_str()); + if (INVALID_FILE_ATTRIBUTES != dwAttrib && + 0 == (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) { + return (shared_dir / resource).wstring(); + } + } + return L""; } -void RimeWithWeaselHandler::_LoadSchemaSpecificSettings(UINT session_id, const std::string& schema_id) -{ - if (!m_ui) return; - RimeConfig config; - if (!RimeSchemaOpen(schema_id.c_str(), &config)) return; - _UpdateShowNotifications(&config); - m_ui->style() = m_base_style; - _UpdateUIStyle(&config, m_ui, false); - SessionStatus& session_status = m_session_status_map[session_id]; - session_status.style = m_ui->style(); - // load schema color style config - const int BUF_SIZE = 255; - char buffer[BUF_SIZE + 1] = {0}; - if (!m_current_dark_mode && RimeConfigGetString(&config, "style/color_scheme", buffer, BUF_SIZE)) - { - std::string color_name(buffer); - RimeConfigIterator preset = {0}; - if(RimeConfigBeginMap(&preset, &config, ("preset_color_schemes/" + color_name).c_str())) - { - _UpdateUIStyleColor(&config, session_status.style, color_name); - } - else - { - RimeConfig weaselconfig; - if (RimeConfigOpen("weasel", &weaselconfig)) - { - _UpdateUIStyleColor(&weaselconfig, session_status.style, color_name); - RimeConfigClose(&weaselconfig); - } - } - } - else if (m_current_dark_mode && RimeConfigGetString(&config, "style/color_scheme_dark", buffer, BUF_SIZE)) - { - std::string color_name(buffer); - RimeConfigIterator preset = {0}; - if(RimeConfigBeginMap(&preset, &config, ("preset_color_schemes/" + color_name).c_str())) - { - _UpdateUIStyleColor(&config, session_status.style, color_name); - } - else - { - RimeConfig weaselconfig; - if (RimeConfigOpen("weasel", &weaselconfig)) - { - _UpdateUIStyleColor(&weaselconfig, session_status.style, color_name); - RimeConfigClose(&weaselconfig); - } - } - } - // load schema icon start - { - auto user_dir = WeaselUserDataPath(); - auto shared_dir = WeaselSharedDataPath(); - session_status.style.current_zhung_icon = _LoadIconSettingFromSchema(config, "schema/icon", "schema/zhung_icon", user_dir, shared_dir); - session_status.style.current_ascii_icon = _LoadIconSettingFromSchema(config, "schema/ascii_icon", NULL, user_dir, shared_dir); - session_status.style.current_full_icon = _LoadIconSettingFromSchema(config, "schema/full_icon", NULL, user_dir, shared_dir); - session_status.style.current_half_icon = _LoadIconSettingFromSchema(config, "schema/half_icon", NULL, user_dir, shared_dir); - } - // load schema icon end - RimeConfigClose(&config); +void RimeWithWeaselHandler::_LoadSchemaSpecificSettings( + UINT session_id, + const std::string& schema_id) { + if (!m_ui) + return; + RimeConfig config; + if (!RimeSchemaOpen(schema_id.c_str(), &config)) + return; + _UpdateShowNotifications(&config); + m_ui->style() = m_base_style; + _UpdateUIStyle(&config, m_ui, false); + SessionStatus& session_status = m_session_status_map[session_id]; + session_status.style = m_ui->style(); + // load schema color style config + const int BUF_SIZE = 255; + char buffer[BUF_SIZE + 1] = {0}; + if (!m_current_dark_mode && + RimeConfigGetString(&config, "style/color_scheme", buffer, BUF_SIZE)) { + std::string color_name(buffer); + RimeConfigIterator preset = {0}; + if (RimeConfigBeginMap(&preset, &config, + ("preset_color_schemes/" + color_name).c_str())) { + _UpdateUIStyleColor(&config, session_status.style, color_name); + } else { + RimeConfig weaselconfig; + if (RimeConfigOpen("weasel", &weaselconfig)) { + _UpdateUIStyleColor(&weaselconfig, session_status.style, color_name); + RimeConfigClose(&weaselconfig); + } + } + } else if (m_current_dark_mode && + RimeConfigGetString(&config, "style/color_scheme_dark", buffer, + BUF_SIZE)) { + std::string color_name(buffer); + RimeConfigIterator preset = {0}; + if (RimeConfigBeginMap(&preset, &config, + ("preset_color_schemes/" + color_name).c_str())) { + _UpdateUIStyleColor(&config, session_status.style, color_name); + } else { + RimeConfig weaselconfig; + if (RimeConfigOpen("weasel", &weaselconfig)) { + _UpdateUIStyleColor(&weaselconfig, session_status.style, color_name); + RimeConfigClose(&weaselconfig); + } + } + } + // load schema icon start + { + auto user_dir = WeaselUserDataPath(); + auto shared_dir = WeaselSharedDataPath(); + session_status.style.current_zhung_icon = _LoadIconSettingFromSchema( + config, "schema/icon", "schema/zhung_icon", user_dir, shared_dir); + session_status.style.current_ascii_icon = _LoadIconSettingFromSchema( + config, "schema/ascii_icon", NULL, user_dir, shared_dir); + session_status.style.current_full_icon = _LoadIconSettingFromSchema( + config, "schema/full_icon", NULL, user_dir, shared_dir); + session_status.style.current_half_icon = _LoadIconSettingFromSchema( + config, "schema/half_icon", NULL, user_dir, shared_dir); + } + // load schema icon end + RimeConfigClose(&config); } -void RimeWithWeaselHandler::_LoadAppInlinePreeditSet(UINT session_id, bool ignore_app_name) -{ - static char _app_name[50]; - RimeGetProperty(session_id, "client_app", _app_name, sizeof(_app_name) - 1); - std::string app_name(_app_name); - if(!ignore_app_name && m_last_app_name == app_name) - return; - m_last_app_name = app_name; - SessionStatus& session_status = m_session_status_map[session_id]; - bool inline_preedit = session_status.style.inline_preedit; - if (!app_name.empty()) - { - auto it = m_app_options.find(app_name); - if (it != m_app_options.end()) - { - AppOptions& options(m_app_options[it->first]); - auto pfind = std::make_shared(false); - std::for_each(options.begin(), options.end(), [session_id, pfind, inline_preedit, this](std::pair &pair) - { - if(pair.first == "inline_preedit") - { - *pfind = true; - RimeSetOption(session_id, pair.first.c_str(), Bool(pair.second)); - m_session_status_map[session_id].style.inline_preedit = Bool(pair.second); - if(m_session_status_map[session_id].style.inline_preedit != inline_preedit) - _UpdateInlinePreeditStatus(session_id); - } - }); - if (!(*pfind)) - { - goto load_schema_inline; - } - } - else - { -load_schema_inline: - session_status.style.inline_preedit = m_base_style.inline_preedit; - RIME_STRUCT(RimeStatus, status); - if (RimeGetStatus(session_id, &status)) - { - std::string schema_id = status.schema_id; - RimeConfig config; - if (!RimeSchemaOpen(schema_id.c_str(), &config)) return; - Bool inline_preedit = session_status.style.inline_preedit; - if (RimeConfigGetBool(&config, "style/inline_preedit", &inline_preedit)) - session_status.style.inline_preedit = !!inline_preedit; - RimeConfigClose(&config); - RimeFreeStatus(&status); - if(session_status.style.inline_preedit != (!!inline_preedit)) - _UpdateInlinePreeditStatus(session_id); - } - } - } +void RimeWithWeaselHandler::_LoadAppInlinePreeditSet(UINT session_id, + bool ignore_app_name) { + static char _app_name[50]; + RimeGetProperty(session_id, "client_app", _app_name, sizeof(_app_name) - 1); + std::string app_name(_app_name); + if (!ignore_app_name && m_last_app_name == app_name) + return; + m_last_app_name = app_name; + SessionStatus& session_status = m_session_status_map[session_id]; + bool inline_preedit = session_status.style.inline_preedit; + if (!app_name.empty()) { + auto it = m_app_options.find(app_name); + if (it != m_app_options.end()) { + AppOptions& options(m_app_options[it->first]); + auto pfind = std::make_shared(false); + std::for_each( + options.begin(), options.end(), + [session_id, pfind, inline_preedit, + this](std::pair& pair) { + if (pair.first == "inline_preedit") { + *pfind = true; + RimeSetOption(session_id, pair.first.c_str(), Bool(pair.second)); + m_session_status_map[session_id].style.inline_preedit = + Bool(pair.second); + if (m_session_status_map[session_id].style.inline_preedit != + inline_preedit) + _UpdateInlinePreeditStatus(session_id); + } + }); + if (!(*pfind)) { + goto load_schema_inline; + } + } else { + load_schema_inline: + session_status.style.inline_preedit = m_base_style.inline_preedit; + RIME_STRUCT(RimeStatus, status); + if (RimeGetStatus(session_id, &status)) { + std::string schema_id = status.schema_id; + RimeConfig config; + if (!RimeSchemaOpen(schema_id.c_str(), &config)) + return; + Bool inline_preedit = session_status.style.inline_preedit; + if (RimeConfigGetBool(&config, "style/inline_preedit", &inline_preedit)) + session_status.style.inline_preedit = !!inline_preedit; + RimeConfigClose(&config); + RimeFreeStatus(&status); + if (session_status.style.inline_preedit != (!!inline_preedit)) + _UpdateInlinePreeditStatus(session_id); + } + } + } } bool RimeWithWeaselHandler::_ShowMessage(Context& ctx, Status& status) { - // show as auxiliary string - std::wstring& tips(ctx.aux.str); - bool show_icon = false; - if (m_message_type == "deploy") { - if (m_message_value == "start") - tips = L"正在部署 RIME"; - else if (m_message_value == "success") - tips = L"部署完成"; - else if (m_message_value == "failure") - { - if( GetThreadUILanguage() == MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL) ) - tips = L"有錯誤,請查看日誌 %TEMP%\\rime.weasel.*.INFO"; - else - tips = L"有错误,请查看日志 %TEMP%\\rime.weasel.*.INFO"; - } - } - else if (m_message_type == "schema") { - tips = /*L"【" + */status.schema_name/* + L"】"*/; - } - else if (m_message_type == "option") { - status.type = SCHEMA; - if (m_message_value == "!ascii_mode") - { - show_icon = true; - } - else if (m_message_value == "ascii_mode") - { - show_icon = true; - } - else - tips = string_to_wstring(m_message_label, CP_UTF8); - - if (m_message_value == "full_shape" || m_message_value == "!full_shape") - status.type = FULL_SHAPE; - } - if (tips.empty() && !show_icon) - return m_ui->IsCountingDown(); - auto foption = m_show_notifications.find(m_option_name); - auto falways = m_show_notifications.find("always"); - if ((!addsession && (foption != m_show_notifications.end() || - falways != m_show_notifications.end())) || - m_message_type == "deploy") { - m_ui->Update(ctx, status); - if (m_show_notifications_time) - m_ui->ShowWithTimeout(m_show_notifications_time); - return true; - } else { - return m_ui->IsCountingDown(); - } + // show as auxiliary string + std::wstring& tips(ctx.aux.str); + bool show_icon = false; + if (m_message_type == "deploy") { + if (m_message_value == "start") + tips = L"正在部署 RIME"; + else if (m_message_value == "success") + tips = L"部署完成"; + else if (m_message_value == "failure") { + if (GetThreadUILanguage() == + MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)) + tips = L"有錯誤,請查看日誌 %TEMP%\\rime.weasel.*.INFO"; + else + tips = L"有错误,请查看日志 %TEMP%\\rime.weasel.*.INFO"; + } + } else if (m_message_type == "schema") { + tips = /*L"【" + */ status.schema_name /* + L"】"*/; + } else if (m_message_type == "option") { + status.type = SCHEMA; + if (m_message_value == "!ascii_mode") { + show_icon = true; + } else if (m_message_value == "ascii_mode") { + show_icon = true; + } else + tips = string_to_wstring(m_message_label, CP_UTF8); + + if (m_message_value == "full_shape" || m_message_value == "!full_shape") + status.type = FULL_SHAPE; + } + if (tips.empty() && !show_icon) + return m_ui->IsCountingDown(); + auto foption = m_show_notifications.find(m_option_name); + auto falways = m_show_notifications.find("always"); + if ((!addsession && (foption != m_show_notifications.end() || + falways != m_show_notifications.end())) || + m_message_type == "deploy") { + m_ui->Update(ctx, status); + if (m_show_notifications_time) + m_ui->ShowWithTimeout(m_show_notifications_time); + return true; + } else { + return m_ui->IsCountingDown(); + } } -inline std::string _GetLabelText(const std::vector &labels, int id, const wchar_t *format) -{ - wchar_t buffer[128]; - swprintf_s<128>(buffer, format, labels.at(id).str.c_str()); - return wstring_to_string(std::wstring(buffer), CP_UTF8); +inline std::string _GetLabelText(const std::vector& labels, + int id, + const wchar_t* format) { + wchar_t buffer[128]; + swprintf_s<128>(buffer, format, labels.at(id).str.c_str()); + return wstring_to_string(std::wstring(buffer), CP_UTF8); } -bool RimeWithWeaselHandler::_Respond(UINT session_id, EatLine eat) -{ - std::set actions; - std::list messages; - - SessionStatus& session_status = m_session_status_map[session_id]; - RIME_STRUCT(RimeCommit, commit); - if (RimeGetCommit(session_id, &commit)) - { - actions.insert("commit"); - messages.push_back(std::string("commit=") + commit.text + '\n'); - RimeFreeCommit(&commit); - } - - bool is_composing = false; - RIME_STRUCT(RimeStatus, status); - if (RimeGetStatus(session_id, &status)) - { - is_composing = !!status.is_composing; - actions.insert("status"); - messages.push_back(std::string("status.ascii_mode=") + std::to_string(status.is_ascii_mode) + '\n'); - messages.push_back(std::string("status.composing=") + std::to_string(status.is_composing) + '\n'); - messages.push_back(std::string("status.disabled=") + std::to_string(status.is_disabled) + '\n'); - messages.push_back(std::string("status.full_shape=") + std::to_string(status.is_full_shape) + '\n'); - messages.push_back(std::string("status.schema_id=") + std::string(status.schema_id) + '\n'); - if (m_global_ascii_mode && (session_status.status.is_ascii_mode != status.is_ascii_mode)) { - for (auto& pair : m_session_status_map) { - if(pair.first != session_id) - RimeSetOption(pair.first, "ascii_mode", !!status.is_ascii_mode); - } - } - session_status.status = status; - RimeFreeStatus(&status); - } - - RIME_STRUCT(RimeContext, ctx); - if (RimeGetContext(session_id, &ctx)) - { - if (is_composing) - { - actions.insert("ctx"); - switch (session_status.style.preedit_type) - { - case UIStyle::PREVIEW: - if (ctx.commit_text_preview != NULL) - { - std::string first = ctx.commit_text_preview; - messages.push_back(std::string("ctx.preedit=") + first + '\n'); - messages.push_back(std::string("ctx.preedit.cursor=") + - std::to_string(utf8towcslen(first.c_str(), 0)) + ',' + - std::to_string(utf8towcslen(first.c_str(), first.size())) + ',' + - std::to_string(utf8towcslen(first.c_str(), first.size())) + '\n'); - break; - } - // no preview, fall back to composition - case UIStyle::COMPOSITION: - messages.push_back(std::string("ctx.preedit=") + ctx.composition.preedit + '\n'); - if (ctx.composition.sel_start <= ctx.composition.sel_end) - { - messages.push_back(std::string("ctx.preedit.cursor=") + - std::to_string(utf8towcslen(ctx.composition.preedit, ctx.composition.sel_start)) + ',' + - std::to_string(utf8towcslen(ctx.composition.preedit, ctx.composition.sel_end)) + ',' + - std::to_string(utf8towcslen(ctx.composition.preedit, ctx.composition.cursor_pos)) + '\n'); - } - break; - case UIStyle::PREVIEW_ALL: - CandidateInfo cinfo; - _GetCandidateInfo(cinfo, ctx); - std::string topush = std::string("ctx.preedit=") + ctx.composition.preedit + " ["; - for (auto i = 0; i < ctx.menu.num_candidates; i++) - { - std::string label = session_status.style.label_font_point > 0 ? _GetLabelText(cinfo.labels, i, session_status.style.label_text_format.c_str()) : ""; - std::string comment = session_status.style.comment_font_point > 0 ? wstring_to_string(cinfo.comments.at(i).str, CP_UTF8) : ""; - std::string mark_text = session_status.style.mark_text.empty() ? "*" : wstring_to_string(session_status.style.mark_text, CP_UTF8); - std::string prefix = (i != ctx.menu.highlighted_candidate_index) ? "" : mark_text; - topush += " " + prefix + label + std::string(ctx.menu.candidates[i].text) + " " + comment; - } - messages.push_back(topush + " ]\n"); - //messages.push_back(std::string("ctx.preedit=") + ctx.composition.preedit + '\n'); - if (ctx.composition.sel_start <= ctx.composition.sel_end) - { - messages.push_back(std::string("ctx.preedit.cursor=") + - std::to_string(utf8towcslen(ctx.composition.preedit, ctx.composition.sel_start)) + ',' + - std::to_string(utf8towcslen(ctx.composition.preedit, ctx.composition.sel_end)) + ',' + - std::to_string(utf8towcslen(ctx.composition.preedit, ctx.composition.cursor_pos)) + '\n'); - } - break; - } - } - if (ctx.menu.num_candidates) - { - CandidateInfo cinfo; - std::wstringstream ss; - boost::archive::text_woarchive oa(ss); - _GetCandidateInfo(cinfo, ctx); - - oa << cinfo; - - messages.push_back(std::string("ctx.cand=") + wstring_to_string(ss.str().c_str(), CP_UTF8) + '\n'); - } - RimeFreeContext(&ctx); - } - - // configuration information - actions.insert("config"); - messages.push_back(std::string("config.inline_preedit=") + std::to_string((int)session_status.style.inline_preedit) + '\n'); - - // style - if (!session_status.__synced) { - std::wstringstream ss; - boost::archive::text_woarchive oa(ss); - oa << session_status.style; - - actions.insert("style"); - messages.push_back(std::string("style=") + wstring_to_string(ss.str().c_str(), CP_UTF8) + '\n'); - session_status.__synced = true; - } - - // summarize - - if (actions.empty()) - { - messages.insert(messages.begin(), std::string("action=noop\n")); - } - else - { - std::string actionList(join(actions, ",")); - messages.insert(messages.begin(), std::string("action=") + actionList + '\n'); - } - - messages.push_back(std::string(".\n")); - - return std::all_of(messages.begin(), messages.end(), [&eat](std::string &msg) - { - return eat(std::wstring(string_to_wstring(msg.c_str(), CP_UTF8))); - }); +bool RimeWithWeaselHandler::_Respond(UINT session_id, EatLine eat) { + std::set actions; + std::list messages; + + SessionStatus& session_status = m_session_status_map[session_id]; + RIME_STRUCT(RimeCommit, commit); + if (RimeGetCommit(session_id, &commit)) { + actions.insert("commit"); + messages.push_back(std::string("commit=") + commit.text + '\n'); + RimeFreeCommit(&commit); + } + + bool is_composing = false; + RIME_STRUCT(RimeStatus, status); + if (RimeGetStatus(session_id, &status)) { + is_composing = !!status.is_composing; + actions.insert("status"); + messages.push_back(std::string("status.ascii_mode=") + + std::to_string(status.is_ascii_mode) + '\n'); + messages.push_back(std::string("status.composing=") + + std::to_string(status.is_composing) + '\n'); + messages.push_back(std::string("status.disabled=") + + std::to_string(status.is_disabled) + '\n'); + messages.push_back(std::string("status.full_shape=") + + std::to_string(status.is_full_shape) + '\n'); + messages.push_back(std::string("status.schema_id=") + + std::string(status.schema_id) + '\n'); + if (m_global_ascii_mode && + (session_status.status.is_ascii_mode != status.is_ascii_mode)) { + for (auto& pair : m_session_status_map) { + if (pair.first != session_id) + RimeSetOption(pair.first, "ascii_mode", !!status.is_ascii_mode); + } + } + session_status.status = status; + RimeFreeStatus(&status); + } + + RIME_STRUCT(RimeContext, ctx); + if (RimeGetContext(session_id, &ctx)) { + if (is_composing) { + actions.insert("ctx"); + switch (session_status.style.preedit_type) { + case UIStyle::PREVIEW: + if (ctx.commit_text_preview != NULL) { + std::string first = ctx.commit_text_preview; + messages.push_back(std::string("ctx.preedit=") + first + '\n'); + messages.push_back( + std::string("ctx.preedit.cursor=") + + std::to_string(utf8towcslen(first.c_str(), 0)) + ',' + + std::to_string(utf8towcslen(first.c_str(), first.size())) + + ',' + + std::to_string(utf8towcslen(first.c_str(), first.size())) + + '\n'); + break; + } + // no preview, fall back to composition + case UIStyle::COMPOSITION: + messages.push_back(std::string("ctx.preedit=") + + ctx.composition.preedit + '\n'); + if (ctx.composition.sel_start <= ctx.composition.sel_end) { + messages.push_back( + std::string("ctx.preedit.cursor=") + + std::to_string(utf8towcslen(ctx.composition.preedit, + ctx.composition.sel_start)) + + ',' + + std::to_string(utf8towcslen(ctx.composition.preedit, + ctx.composition.sel_end)) + + ',' + + std::to_string(utf8towcslen(ctx.composition.preedit, + ctx.composition.cursor_pos)) + + '\n'); + } + break; + case UIStyle::PREVIEW_ALL: + CandidateInfo cinfo; + _GetCandidateInfo(cinfo, ctx); + std::string topush = + std::string("ctx.preedit=") + ctx.composition.preedit + " ["; + for (auto i = 0; i < ctx.menu.num_candidates; i++) { + std::string label = + session_status.style.label_font_point > 0 + ? _GetLabelText( + cinfo.labels, i, + session_status.style.label_text_format.c_str()) + : ""; + std::string comment = + session_status.style.comment_font_point > 0 + ? wstring_to_string(cinfo.comments.at(i).str, CP_UTF8) + : ""; + std::string mark_text = + session_status.style.mark_text.empty() + ? "*" + : wstring_to_string(session_status.style.mark_text, + CP_UTF8); + std::string prefix = + (i != ctx.menu.highlighted_candidate_index) ? "" : mark_text; + topush += " " + prefix + label + + std::string(ctx.menu.candidates[i].text) + " " + comment; + } + messages.push_back(topush + " ]\n"); + // messages.push_back(std::string("ctx.preedit=") + + // ctx.composition.preedit + '\n'); + if (ctx.composition.sel_start <= ctx.composition.sel_end) { + messages.push_back( + std::string("ctx.preedit.cursor=") + + std::to_string(utf8towcslen(ctx.composition.preedit, + ctx.composition.sel_start)) + + ',' + + std::to_string(utf8towcslen(ctx.composition.preedit, + ctx.composition.sel_end)) + + ',' + + std::to_string(utf8towcslen(ctx.composition.preedit, + ctx.composition.cursor_pos)) + + '\n'); + } + break; + } + } + if (ctx.menu.num_candidates) { + CandidateInfo cinfo; + std::wstringstream ss; + boost::archive::text_woarchive oa(ss); + _GetCandidateInfo(cinfo, ctx); + + oa << cinfo; + + messages.push_back(std::string("ctx.cand=") + + wstring_to_string(ss.str().c_str(), CP_UTF8) + '\n'); + } + RimeFreeContext(&ctx); + } + + // configuration information + actions.insert("config"); + messages.push_back(std::string("config.inline_preedit=") + + std::to_string((int)session_status.style.inline_preedit) + + '\n'); + + // style + if (!session_status.__synced) { + std::wstringstream ss; + boost::archive::text_woarchive oa(ss); + oa << session_status.style; + + actions.insert("style"); + messages.push_back(std::string("style=") + + wstring_to_string(ss.str().c_str(), CP_UTF8) + '\n'); + session_status.__synced = true; + } + + // summarize + + if (actions.empty()) { + messages.insert(messages.begin(), std::string("action=noop\n")); + } else { + std::string actionList(join(actions, ",")); + messages.insert(messages.begin(), + std::string("action=") + actionList + '\n'); + } + + messages.push_back(std::string(".\n")); + + return std::all_of( + messages.begin(), messages.end(), [&eat](std::string& msg) { + return eat(std::wstring(string_to_wstring(msg.c_str(), CP_UTF8))); + }); } -static inline COLORREF blend_colors(COLORREF fcolor, COLORREF bcolor) -{ - return RGB( - (GetRValue(fcolor) * 2 + GetRValue(bcolor)) / 3, - (GetGValue(fcolor) * 2 + GetGValue(bcolor)) / 3, - (GetBValue(fcolor) * 2 + GetBValue(bcolor)) / 3 - ) | ((((fcolor >> 24)+(bcolor >> 24)/2) << 24)); +static inline COLORREF blend_colors(COLORREF fcolor, COLORREF bcolor) { + return RGB((GetRValue(fcolor) * 2 + GetRValue(bcolor)) / 3, + (GetGValue(fcolor) * 2 + GetGValue(bcolor)) / 3, + (GetBValue(fcolor) * 2 + GetBValue(bcolor)) / 3) | + ((((fcolor >> 24) + (bcolor >> 24) / 2) << 24)); } // convertions from color format to COLOR_ABGR -static inline int ConvertColorToAbgr(int color, ColorFormat fmt = COLOR_ABGR) -{ - if(fmt == COLOR_ABGR) return color; - else if(fmt == COLOR_ARGB) return ARGB2ABGR(color); - else return RGBA2ABGR(color); +static inline int ConvertColorToAbgr(int color, ColorFormat fmt = COLOR_ABGR) { + if (fmt == COLOR_ABGR) + return color; + else if (fmt == COLOR_ARGB) + return ARGB2ABGR(color); + else + return RGBA2ABGR(color); } // parse color value, with fallback value -static Bool _RimeConfigGetColor32bWithFallback(RimeConfig* config, const std::string key, int& value, const ColorFormat& fmt, const int& fallback) -{ - char color[256] = { 0 }; - if (!RimeConfigGetString(config, key.c_str(), color, 256)) - { - value = fallback; - return False; - } - std::string color_str = std::string(color); - // color code hex - if (std::regex_match(color_str, HEX_REGEX)) - { - std::string tmp = std::regex_replace(color_str, TRIMHEAD_REGEX, ""); - // limit first 8 code - tmp = tmp.substr(0, 8); - if(tmp.length() == 6) // color code without alpha, xxyyzz add alpha ff - { - value = std::stoi(tmp, 0, 16); - if(fmt != COLOR_RGBA) value |= 0xff000000; - else value = (value << 8) | 0x000000ff; - } - else if(tmp.length() == 3) // color hex code xyz => xxyyzz and alpha ff - { - tmp = tmp.substr(0, 1) + tmp.substr(0, 1) - + tmp.substr(1, 1) + tmp.substr(1, 1) - + tmp.substr(2, 1) + tmp.substr(2, 1); - - value = std::stoi(tmp, 0, 16); - if(fmt != COLOR_RGBA) value |= 0xff000000; - else value = (value << 8) | 0x000000ff; - } - else if(tmp.length() == 4) // color hex code vxyz => vvxxyyzz - { - tmp = tmp.substr(0, 1) + tmp.substr(0, 1) - + tmp.substr(1, 1) + tmp.substr(1, 1) - + tmp.substr(2, 1) + tmp.substr(2, 1) - + tmp.substr(3, 1) + tmp.substr(3, 1); - - std::string tmp1 = tmp.substr(0, 6); - int value1 = std::stoi(tmp1, 0, 16); - tmp1 = tmp.substr(6); - int value2 = std::stoi(tmp1, 0, 16); - value = (value1 << (tmp1.length() * 4)) | value2; - } - else if(tmp.length() > 6 && tmp.length() <= 8) /* color code with alpha */ - { - // stoi limitation, split to handle - std::string tmp1 = tmp.substr(0, 6); - int value1 = std::stoi(tmp1, 0, 16); - tmp1 = tmp.substr(6); - int value2 = std::stoi(tmp1, 0, 16); - value = (value1 << (tmp1.length() * 4)) | value2; - } - else // reject other code, length less then 3 or length == 5 - { - value = fallback; - return False; - } - value = ConvertColorToAbgr(value, fmt); - value = (value & 0xffffffff); - return True; - } - // regular number or other stuff, if user use pure dec number, they should take care themselves - else - { - int tmp = 0; - if (!RimeConfigGetInt(config, key.c_str(), &tmp)) - { - value = fallback; - return False; - } - if(fmt != COLOR_RGBA) - value = (tmp | 0xff000000) & 0xffffffff; - else - value = ((tmp << 8) | 0x000000ff) & 0xffffffff; - value = ConvertColorToAbgr(value, fmt); - return True; - } +static Bool _RimeConfigGetColor32bWithFallback(RimeConfig* config, + const std::string key, + int& value, + const ColorFormat& fmt, + const int& fallback) { + char color[256] = {0}; + if (!RimeConfigGetString(config, key.c_str(), color, 256)) { + value = fallback; + return False; + } + std::string color_str = std::string(color); + // color code hex + if (std::regex_match(color_str, HEX_REGEX)) { + std::string tmp = std::regex_replace(color_str, TRIMHEAD_REGEX, ""); + // limit first 8 code + tmp = tmp.substr(0, 8); + if (tmp.length() == 6) // color code without alpha, xxyyzz add alpha ff + { + value = std::stoi(tmp, 0, 16); + if (fmt != COLOR_RGBA) + value |= 0xff000000; + else + value = (value << 8) | 0x000000ff; + } else if (tmp.length() == 3) // color hex code xyz => xxyyzz and alpha ff + { + tmp = tmp.substr(0, 1) + tmp.substr(0, 1) + tmp.substr(1, 1) + + tmp.substr(1, 1) + tmp.substr(2, 1) + tmp.substr(2, 1); + + value = std::stoi(tmp, 0, 16); + if (fmt != COLOR_RGBA) + value |= 0xff000000; + else + value = (value << 8) | 0x000000ff; + } else if (tmp.length() == 4) // color hex code vxyz => vvxxyyzz + { + tmp = tmp.substr(0, 1) + tmp.substr(0, 1) + tmp.substr(1, 1) + + tmp.substr(1, 1) + tmp.substr(2, 1) + tmp.substr(2, 1) + + tmp.substr(3, 1) + tmp.substr(3, 1); + + std::string tmp1 = tmp.substr(0, 6); + int value1 = std::stoi(tmp1, 0, 16); + tmp1 = tmp.substr(6); + int value2 = std::stoi(tmp1, 0, 16); + value = (value1 << (tmp1.length() * 4)) | value2; + } else if (tmp.length() > 6 && + tmp.length() <= 8) /* color code with alpha */ + { + // stoi limitation, split to handle + std::string tmp1 = tmp.substr(0, 6); + int value1 = std::stoi(tmp1, 0, 16); + tmp1 = tmp.substr(6); + int value2 = std::stoi(tmp1, 0, 16); + value = (value1 << (tmp1.length() * 4)) | value2; + } else // reject other code, length less then 3 or length == 5 + { + value = fallback; + return False; + } + value = ConvertColorToAbgr(value, fmt); + value = (value & 0xffffffff); + return True; + } + // regular number or other stuff, if user use pure dec number, they should + // take care themselves + else { + int tmp = 0; + if (!RimeConfigGetInt(config, key.c_str(), &tmp)) { + value = fallback; + return False; + } + if (fmt != COLOR_RGBA) + value = (tmp | 0xff000000) & 0xffffffff; + else + value = ((tmp << 8) | 0x000000ff) & 0xffffffff; + value = ConvertColorToAbgr(value, fmt); + return True; + } } // for remove useless spaces around seperators, begining and ending -static inline void _RemoveSpaceAroundSep(std::wstring& str) -{ - str = std::regex_replace(str, std::wregex(L"\\s*(,|:|^|$)\\s*"), L"$1"); +static inline void _RemoveSpaceAroundSep(std::wstring& str) { + str = std::regex_replace(str, std::wregex(L"\\s*(,|:|^|$)\\s*"), L"$1"); } // parset bool type configuration to T type value trueValue / falseValue template -static void _RimeGetBool(RimeConfig* config, char* key, bool cond, T& value, const T& trueValue, const T& falseValue) { - Bool tempb = False; - if (RimeConfigGetBool(config, key, &tempb) || cond) - value = (!!tempb) ? trueValue : falseValue; +static void _RimeGetBool(RimeConfig* config, + char* key, + bool cond, + T& value, + const T& trueValue, + const T& falseValue) { + Bool tempb = False; + if (RimeConfigGetBool(config, key, &tempb) || cond) + value = (!!tempb) ? trueValue : falseValue; } -// parse string option to T type value, with fallback +// parse string option to T type value, with fallback template -void _RimeParseStringOptWithFallback(RimeConfig* config, const std::string key, T& value, const std::map amap, const T& fallback) { - char str_buff[256] = { 0 }; - if (RimeConfigGetString(config, key.c_str(), str_buff, sizeof(str_buff) - 1)) { - auto it = amap.find(std::string(str_buff)); - value = (it != amap.end()) ? it->second : fallback; - } - else value = fallback; +void _RimeParseStringOptWithFallback(RimeConfig* config, + const std::string key, + T& value, + const std::map amap, + const T& fallback) { + char str_buff[256] = {0}; + if (RimeConfigGetString(config, key.c_str(), str_buff, + sizeof(str_buff) - 1)) { + auto it = amap.find(std::string(str_buff)); + value = (it != amap.end()) ? it->second : fallback; + } else + value = fallback; } -static inline void _abs(int* value) { *value = abs(*value); } // turn *value to be non-negative -// get int type value with fallback key fb_key, and func to execute after reading -static void _RimeGetIntWithFallback(RimeConfig* config, const char* key, int* value, const char* fb_key = NULL, std::function func = NULL) -{ - if (!RimeConfigGetInt(config, key, value) && fb_key != NULL) { - RimeConfigGetInt(config, fb_key, value); - } - if (func) func(value); +static inline void _abs(int* value) { + *value = abs(*value); +} // turn *value to be non-negative +// get int type value with fallback key fb_key, and func to execute after +// reading +static void _RimeGetIntWithFallback(RimeConfig* config, + const char* key, + int* value, + const char* fb_key = NULL, + std::function func = NULL) { + if (!RimeConfigGetInt(config, key, value) && fb_key != NULL) { + RimeConfigGetInt(config, fb_key, value); + } + if (func) + func(value); } -// get string value, with fallback value *fallback, and func to execute after reading -static void _RimeGetStringWithFunc(RimeConfig* config, const char* key, std::wstring& value, const std::wstring* fallback = NULL, const std::function func=NULL) -{ - const int BUF_SIZE = 2047; - char buffer[BUF_SIZE + 1] = { 0 }; - if (RimeConfigGetString(config, key, buffer, BUF_SIZE)) { - std::wstring tmp = string_to_wstring(buffer, CP_UTF8); - if (func) func(tmp); - value = tmp; - } - else if(fallback) - value = *fallback; +// get string value, with fallback value *fallback, and func to execute after +// reading +static void _RimeGetStringWithFunc( + RimeConfig* config, + const char* key, + std::wstring& value, + const std::wstring* fallback = NULL, + const std::function func = NULL) { + const int BUF_SIZE = 2047; + char buffer[BUF_SIZE + 1] = {0}; + if (RimeConfigGetString(config, key, buffer, BUF_SIZE)) { + std::wstring tmp = string_to_wstring(buffer, CP_UTF8); + if (func) + func(tmp); + value = tmp; + } else if (fallback) + value = *fallback; } -void RimeWithWeaselHandler::_UpdateShowNotifications(RimeConfig *config, bool initialize) -{ - Bool show_notifications = true; - RimeConfigIterator iter; - if (initialize) - m_show_notifications_base.clear(); - m_show_notifications.clear(); - - if(RimeConfigGetBool(config, "show_notifications", &show_notifications)) { - // config read as bool, for gloal all on or off - if(show_notifications) - m_show_notifications["always"] = true; - if (initialize) - m_show_notifications_base = m_show_notifications; - } else if (RimeConfigBeginList(&iter, config, "show_notifications")) { - // config read as list, list item should be option name in schema - // or key word 'schema' for schema switching tip - while(RimeConfigNext(&iter)) { - char buffer[256] = {0}; - if(RimeConfigGetString(config, iter.path, buffer, 256)) - m_show_notifications[std::string(buffer)] = true; - } - if (initialize) - m_show_notifications_base = m_show_notifications; - } else { - // not configured, or incorrect type - if (initialize) - m_show_notifications_base["always"] = true; - m_show_notifications = m_show_notifications_base; - } +void RimeWithWeaselHandler::_UpdateShowNotifications(RimeConfig* config, + bool initialize) { + Bool show_notifications = true; + RimeConfigIterator iter; + if (initialize) + m_show_notifications_base.clear(); + m_show_notifications.clear(); + + if (RimeConfigGetBool(config, "show_notifications", &show_notifications)) { + // config read as bool, for gloal all on or off + if (show_notifications) + m_show_notifications["always"] = true; + if (initialize) + m_show_notifications_base = m_show_notifications; + } else if (RimeConfigBeginList(&iter, config, "show_notifications")) { + // config read as list, list item should be option name in schema + // or key word 'schema' for schema switching tip + while (RimeConfigNext(&iter)) { + char buffer[256] = {0}; + if (RimeConfigGetString(config, iter.path, buffer, 256)) + m_show_notifications[std::string(buffer)] = true; + } + if (initialize) + m_show_notifications_base = m_show_notifications; + } else { + // not configured, or incorrect type + if (initialize) + m_show_notifications_base["always"] = true; + m_show_notifications = m_show_notifications_base; + } } -// update ui's style parameters, ui has been check before referenced -static void _UpdateUIStyle(RimeConfig* config, UI* ui, bool initialize) -{ - UIStyle &style(ui->style()); - // get font faces - _RimeGetStringWithFunc(config, "style/font_face", style.font_face, NULL, _RemoveSpaceAroundSep); - std::wstring* const pFallbackFontFace = initialize ? &style.font_face : NULL; - _RimeGetStringWithFunc(config, "style/label_font_face", style.label_font_face, pFallbackFontFace, _RemoveSpaceAroundSep); - _RimeGetStringWithFunc(config, "style/comment_font_face", style.comment_font_face, pFallbackFontFace, _RemoveSpaceAroundSep); - // able to set label font/comment font empty, force fallback to font face. - if (style.label_font_face.empty()) - style.label_font_face = style.font_face; - if (style.comment_font_face.empty()) - style.comment_font_face = style.font_face; - // get font points - _RimeGetIntWithFallback(config, "style/font_point", &style.font_point); - if (style.font_point <= 0) - style.font_point = 12; - _RimeGetIntWithFallback(config, "style/label_font_point", &style.label_font_point, "style/font_point", _abs); - _RimeGetIntWithFallback(config, "style/comment_font_point", &style.comment_font_point, "style/font_point", _abs); - _RimeGetIntWithFallback(config, "style/mouse_hover_ms", &style.mouse_hover_ms, NULL, _abs); - _RimeGetIntWithFallback(config, "style/candidate_abbreviate_length", &style.candidate_abbreviate_length, NULL, _abs); - _RimeGetBool(config, "style/inline_preedit", initialize, style.inline_preedit, true, false); - _RimeGetBool(config, "style/vertical_auto_reverse", initialize, style.vertical_auto_reverse, true, false); - const std::map _preeditMap = { - {std::string("composition"), UIStyle::COMPOSITION}, - {std::string("preview"), UIStyle::PREVIEW}, - {std::string("preview_all"), UIStyle::PREVIEW_ALL} - }; - _RimeParseStringOptWithFallback(config, "style/preedit_type", style.preedit_type, _preeditMap, style.preedit_type); - const std::map < std::string , UIStyle::AntiAliasMode > _aliasModeMap = { - {std::string("force_dword"), UIStyle::FORCE_DWORD}, - {std::string("cleartype"), UIStyle::CLEARTYPE}, - {std::string("grayscale"), UIStyle::GRAYSCALE}, - {std::string("aliased"), UIStyle::ALIASED}, - {std::string("default"), UIStyle::DEFAULT} - }; - _RimeParseStringOptWithFallback(config, "style/antialias_mode", style.antialias_mode, _aliasModeMap, style.antialias_mode); - const std::map _alignType = { - {std::string("top"), UIStyle::ALIGN_TOP}, - {std::string("center"), UIStyle::ALIGN_CENTER}, - {std::string("bottom"), UIStyle::ALIGN_BOTTOM} - }; - _RimeParseStringOptWithFallback(config, "style/layout/align_type", style.align_type, _alignType, style.align_type); - _RimeGetBool(config, "style/display_tray_icon", initialize, style.display_tray_icon, true, false); - _RimeGetBool(config, "style/ascii_tip_follow_cursor", initialize, style.ascii_tip_follow_cursor, true, false); - _RimeGetBool(config, "style/horizontal", initialize, style.layout_type, UIStyle::LAYOUT_HORIZONTAL, UIStyle::LAYOUT_VERTICAL); - _RimeGetBool(config, "style/paging_on_scroll", initialize, style.paging_on_scroll, true, false); - _RimeGetBool(config, "style/click_to_capture", initialize, style.click_to_capture, true, false); - _RimeGetBool(config, "style/fullscreen", false, style.layout_type, - ((style.layout_type == UIStyle::LAYOUT_HORIZONTAL) ? UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN : UIStyle::LAYOUT_VERTICAL_FULLSCREEN), style.layout_type); - _RimeGetBool(config, "style/vertical_text", false, style.layout_type, UIStyle::LAYOUT_VERTICAL_TEXT, style.layout_type); - _RimeGetBool(config, "style/vertical_text_left_to_right", false, style.vertical_text_left_to_right, true, false); - _RimeGetBool(config, "style/vertical_text_with_wrap", false, style.vertical_text_with_wrap, true, false); - const std::map _text_orientation = { - {std::string("horizontal"), false}, - {std::string("vertical"), true} - }; - bool _text_orientation_bool = false; - _RimeParseStringOptWithFallback(config, "style/text_orientation", _text_orientation_bool, _text_orientation, _text_orientation_bool); - if(_text_orientation_bool) - style.layout_type = UIStyle::LAYOUT_VERTICAL_TEXT; - _RimeGetStringWithFunc(config, "style/label_format", style.label_text_format); - _RimeGetStringWithFunc(config, "style/mark_text", style.mark_text); - _RimeGetIntWithFallback(config, "style/layout/min_width", &style.min_width, NULL, _abs); - _RimeGetIntWithFallback(config, "style/layout/max_width", &style.max_width, NULL, _abs); - _RimeGetIntWithFallback(config, "style/layout/min_height", &style.min_height, NULL, _abs); - _RimeGetIntWithFallback(config, "style/layout/max_height", &style.max_height, NULL, _abs); - // layout (alternative to style/horizontal) - const std::map < std::string , UIStyle::LayoutType > _layoutMap = { - {std::string("vertical"), UIStyle::LAYOUT_VERTICAL}, - {std::string("horizontal"), UIStyle::LAYOUT_HORIZONTAL}, - {std::string("vertical_text"), UIStyle::LAYOUT_VERTICAL_TEXT}, - {std::string("vertical+fullscreen"), UIStyle::LAYOUT_VERTICAL_FULLSCREEN}, - {std::string("horizontal+fullscreen"), UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN} - }; - _RimeParseStringOptWithFallback(config, "style/layout/type", style.layout_type, _layoutMap, style.layout_type); - // disable max_width when full screen - if( style.layout_type == UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN || style.layout_type == UIStyle::LAYOUT_VERTICAL_FULLSCREEN ) - { - style.max_width = 0; - style.inline_preedit = false; - } - _RimeGetIntWithFallback(config, "style/layout/border", &style.border, "style/layout/border_width", _abs); - _RimeGetIntWithFallback(config, "style/layout/margin_x", &style.margin_x); - _RimeGetIntWithFallback(config, "style/layout/margin_y", &style.margin_y); - _RimeGetIntWithFallback(config, "style/layout/spacing", &style.spacing, NULL, _abs); - _RimeGetIntWithFallback(config, "style/layout/candidate_spacing", &style.candidate_spacing, NULL, _abs); - _RimeGetIntWithFallback(config, "style/layout/hilite_spacing", &style.hilite_spacing, NULL, _abs); - _RimeGetIntWithFallback(config, "style/layout/hilite_padding_x", &style.hilite_padding_x, "style/layout/hilite_padding", _abs); - _RimeGetIntWithFallback(config, "style/layout/hilite_padding_y", &style.hilite_padding_y, "style/layout/hilite_padding", _abs); - _RimeGetIntWithFallback(config, "style/layout/shadow_radius", &style.shadow_radius, NULL, _abs); - // disable shadow for fullscreen layout - style.shadow_radius *= (!( style.layout_type == UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN || style.layout_type == UIStyle::LAYOUT_VERTICAL_FULLSCREEN )); - _RimeGetIntWithFallback(config, "style/layout/shadow_offset_x", &style.shadow_offset_x); - _RimeGetIntWithFallback(config, "style/layout/shadow_offset_y", &style.shadow_offset_y); - // round_corner as alias of hilited_corner_radius - _RimeGetIntWithFallback(config, "style/layout/hilited_corner_radius", &style.round_corner, "style/layout/round_corner", _abs); - // corner_radius not set, fallback to round_corner - _RimeGetIntWithFallback(config, "style/layout/corner_radius", &style.round_corner_ex, "style/layout/round_corner", _abs); - // fix padding and spacing settings - if(style.layout_type != UIStyle::LAYOUT_VERTICAL_TEXT) - { - // hilite_padding vs spacing - style.spacing = max(style.spacing, style.hilite_padding_y * 2); // if hilite_padding over spacing, increase spacing - // hilite_padding vs candidate_spacing - if (style.layout_type == UIStyle::LAYOUT_VERTICAL_FULLSCREEN || style.layout_type == UIStyle::LAYOUT_VERTICAL) { - style.candidate_spacing = max(style.candidate_spacing, style.hilite_padding_y * 2); // vertical, if hilite_padding_y over candidate spacing, increase candidate spacing - } else { - style.candidate_spacing = max(style.candidate_spacing, style.hilite_padding_x * 2); // horizontal, if hilite_padding_x over candidate spacing, increase candidate spacing - } - // hilite_padding_x vs hilite_spacing - if(!style.inline_preedit) - style.hilite_spacing = max(style.hilite_spacing, style.hilite_padding_x); - } - else // LAYOUT_VERTICAL_TEXT - { - // hilite_padding_x vs spacing - style.spacing = max(style.spacing, style.hilite_padding_x * 2); // if hilite_padding over spacing, increase spacing - // hilite_padding vs candidate_spacing - style.candidate_spacing = max(style.candidate_spacing, style.hilite_padding_x * 2); // if hilite_padding_x over candidate spacing, increase candidate spacing - // vertical_text_with_wrap and hilite_padding_y over candidate_spacing - if (style.vertical_text_with_wrap) - style.candidate_spacing = max(style.candidate_spacing, style.hilite_padding_y * 2); - // hilite_padding_y vs hilite_spacing - if(!style.inline_preedit) - style.hilite_spacing = max(style.hilite_spacing, style.hilite_padding_y); - } - // fix padding and margin settings - int scale = style.margin_x < 0 ? -1 : 1; - style.margin_x = scale * max(style.hilite_padding_x, abs(style.margin_x)); - scale = style.margin_y < 0 ? -1 : 1; - style.margin_y = scale * max(style.hilite_padding_y, abs(style.margin_y)); - // get enhanced_position - _RimeGetBool(config, "style/enhanced_position", initialize, style.enhanced_position, true, false); - // get color scheme - const int BUF_SIZE = 255; - char buffer[BUF_SIZE + 1] = { 0 }; - if (initialize && RimeConfigGetString(config, "style/color_scheme", buffer, BUF_SIZE)) - _UpdateUIStyleColor(config, style); +// update ui's style parameters, ui has been check before referenced +static void _UpdateUIStyle(RimeConfig* config, UI* ui, bool initialize) { + UIStyle& style(ui->style()); + // get font faces + _RimeGetStringWithFunc(config, "style/font_face", style.font_face, NULL, + _RemoveSpaceAroundSep); + std::wstring* const pFallbackFontFace = initialize ? &style.font_face : NULL; + _RimeGetStringWithFunc(config, "style/label_font_face", style.label_font_face, + pFallbackFontFace, _RemoveSpaceAroundSep); + _RimeGetStringWithFunc(config, "style/comment_font_face", + style.comment_font_face, pFallbackFontFace, + _RemoveSpaceAroundSep); + // able to set label font/comment font empty, force fallback to font face. + if (style.label_font_face.empty()) + style.label_font_face = style.font_face; + if (style.comment_font_face.empty()) + style.comment_font_face = style.font_face; + // get font points + _RimeGetIntWithFallback(config, "style/font_point", &style.font_point); + if (style.font_point <= 0) + style.font_point = 12; + _RimeGetIntWithFallback(config, "style/label_font_point", + &style.label_font_point, "style/font_point", _abs); + _RimeGetIntWithFallback(config, "style/comment_font_point", + &style.comment_font_point, "style/font_point", _abs); + _RimeGetIntWithFallback(config, "style/mouse_hover_ms", &style.mouse_hover_ms, + NULL, _abs); + _RimeGetIntWithFallback(config, "style/candidate_abbreviate_length", + &style.candidate_abbreviate_length, NULL, _abs); + _RimeGetBool(config, "style/inline_preedit", initialize, style.inline_preedit, + true, false); + _RimeGetBool(config, "style/vertical_auto_reverse", initialize, + style.vertical_auto_reverse, true, false); + const std::map _preeditMap = { + {std::string("composition"), UIStyle::COMPOSITION}, + {std::string("preview"), UIStyle::PREVIEW}, + {std::string("preview_all"), UIStyle::PREVIEW_ALL}}; + _RimeParseStringOptWithFallback(config, "style/preedit_type", + style.preedit_type, _preeditMap, + style.preedit_type); + const std::map _aliasModeMap = { + {std::string("force_dword"), UIStyle::FORCE_DWORD}, + {std::string("cleartype"), UIStyle::CLEARTYPE}, + {std::string("grayscale"), UIStyle::GRAYSCALE}, + {std::string("aliased"), UIStyle::ALIASED}, + {std::string("default"), UIStyle::DEFAULT}}; + _RimeParseStringOptWithFallback(config, "style/antialias_mode", + style.antialias_mode, _aliasModeMap, + style.antialias_mode); + const std::map _alignType = { + {std::string("top"), UIStyle::ALIGN_TOP}, + {std::string("center"), UIStyle::ALIGN_CENTER}, + {std::string("bottom"), UIStyle::ALIGN_BOTTOM}}; + _RimeParseStringOptWithFallback(config, "style/layout/align_type", + style.align_type, _alignType, + style.align_type); + _RimeGetBool(config, "style/display_tray_icon", initialize, + style.display_tray_icon, true, false); + _RimeGetBool(config, "style/ascii_tip_follow_cursor", initialize, + style.ascii_tip_follow_cursor, true, false); + _RimeGetBool(config, "style/horizontal", initialize, style.layout_type, + UIStyle::LAYOUT_HORIZONTAL, UIStyle::LAYOUT_VERTICAL); + _RimeGetBool(config, "style/paging_on_scroll", initialize, + style.paging_on_scroll, true, false); + _RimeGetBool(config, "style/click_to_capture", initialize, + style.click_to_capture, true, false); + _RimeGetBool(config, "style/fullscreen", false, style.layout_type, + ((style.layout_type == UIStyle::LAYOUT_HORIZONTAL) + ? UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN + : UIStyle::LAYOUT_VERTICAL_FULLSCREEN), + style.layout_type); + _RimeGetBool(config, "style/vertical_text", false, style.layout_type, + UIStyle::LAYOUT_VERTICAL_TEXT, style.layout_type); + _RimeGetBool(config, "style/vertical_text_left_to_right", false, + style.vertical_text_left_to_right, true, false); + _RimeGetBool(config, "style/vertical_text_with_wrap", false, + style.vertical_text_with_wrap, true, false); + const std::map _text_orientation = { + {std::string("horizontal"), false}, {std::string("vertical"), true}}; + bool _text_orientation_bool = false; + _RimeParseStringOptWithFallback(config, "style/text_orientation", + _text_orientation_bool, _text_orientation, + _text_orientation_bool); + if (_text_orientation_bool) + style.layout_type = UIStyle::LAYOUT_VERTICAL_TEXT; + _RimeGetStringWithFunc(config, "style/label_format", style.label_text_format); + _RimeGetStringWithFunc(config, "style/mark_text", style.mark_text); + _RimeGetIntWithFallback(config, "style/layout/min_width", &style.min_width, + NULL, _abs); + _RimeGetIntWithFallback(config, "style/layout/max_width", &style.max_width, + NULL, _abs); + _RimeGetIntWithFallback(config, "style/layout/min_height", &style.min_height, + NULL, _abs); + _RimeGetIntWithFallback(config, "style/layout/max_height", &style.max_height, + NULL, _abs); + // layout (alternative to style/horizontal) + const std::map _layoutMap = { + {std::string("vertical"), UIStyle::LAYOUT_VERTICAL}, + {std::string("horizontal"), UIStyle::LAYOUT_HORIZONTAL}, + {std::string("vertical_text"), UIStyle::LAYOUT_VERTICAL_TEXT}, + {std::string("vertical+fullscreen"), UIStyle::LAYOUT_VERTICAL_FULLSCREEN}, + {std::string("horizontal+fullscreen"), + UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN}}; + _RimeParseStringOptWithFallback(config, "style/layout/type", + style.layout_type, _layoutMap, + style.layout_type); + // disable max_width when full screen + if (style.layout_type == UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN || + style.layout_type == UIStyle::LAYOUT_VERTICAL_FULLSCREEN) { + style.max_width = 0; + style.inline_preedit = false; + } + _RimeGetIntWithFallback(config, "style/layout/border", &style.border, + "style/layout/border_width", _abs); + _RimeGetIntWithFallback(config, "style/layout/margin_x", &style.margin_x); + _RimeGetIntWithFallback(config, "style/layout/margin_y", &style.margin_y); + _RimeGetIntWithFallback(config, "style/layout/spacing", &style.spacing, NULL, + _abs); + _RimeGetIntWithFallback(config, "style/layout/candidate_spacing", + &style.candidate_spacing, NULL, _abs); + _RimeGetIntWithFallback(config, "style/layout/hilite_spacing", + &style.hilite_spacing, NULL, _abs); + _RimeGetIntWithFallback(config, "style/layout/hilite_padding_x", + &style.hilite_padding_x, + "style/layout/hilite_padding", _abs); + _RimeGetIntWithFallback(config, "style/layout/hilite_padding_y", + &style.hilite_padding_y, + "style/layout/hilite_padding", _abs); + _RimeGetIntWithFallback(config, "style/layout/shadow_radius", + &style.shadow_radius, NULL, _abs); + // disable shadow for fullscreen layout + style.shadow_radius *= + (!(style.layout_type == UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN || + style.layout_type == UIStyle::LAYOUT_VERTICAL_FULLSCREEN)); + _RimeGetIntWithFallback(config, "style/layout/shadow_offset_x", + &style.shadow_offset_x); + _RimeGetIntWithFallback(config, "style/layout/shadow_offset_y", + &style.shadow_offset_y); + // round_corner as alias of hilited_corner_radius + _RimeGetIntWithFallback(config, "style/layout/hilited_corner_radius", + &style.round_corner, "style/layout/round_corner", + _abs); + // corner_radius not set, fallback to round_corner + _RimeGetIntWithFallback(config, "style/layout/corner_radius", + &style.round_corner_ex, "style/layout/round_corner", + _abs); + // fix padding and spacing settings + if (style.layout_type != UIStyle::LAYOUT_VERTICAL_TEXT) { + // hilite_padding vs spacing + style.spacing = + max(style.spacing, + style.hilite_padding_y * + 2); // if hilite_padding over spacing, increase spacing + // hilite_padding vs candidate_spacing + if (style.layout_type == UIStyle::LAYOUT_VERTICAL_FULLSCREEN || + style.layout_type == UIStyle::LAYOUT_VERTICAL) { + style.candidate_spacing = + max(style.candidate_spacing, + style.hilite_padding_y * + 2); // vertical, if hilite_padding_y over candidate spacing, + // increase candidate spacing + } else { + style.candidate_spacing = + max(style.candidate_spacing, + style.hilite_padding_x * + 2); // horizontal, if hilite_padding_x over candidate + // spacing, increase candidate spacing + } + // hilite_padding_x vs hilite_spacing + if (!style.inline_preedit) + style.hilite_spacing = max(style.hilite_spacing, style.hilite_padding_x); + } else // LAYOUT_VERTICAL_TEXT + { + // hilite_padding_x vs spacing + style.spacing = + max(style.spacing, + style.hilite_padding_x * + 2); // if hilite_padding over spacing, increase spacing + // hilite_padding vs candidate_spacing + style.candidate_spacing = + max(style.candidate_spacing, + style.hilite_padding_x * 2); // if hilite_padding_x over candidate + // spacing, increase candidate spacing + // vertical_text_with_wrap and hilite_padding_y over candidate_spacing + if (style.vertical_text_with_wrap) + style.candidate_spacing = + max(style.candidate_spacing, style.hilite_padding_y * 2); + // hilite_padding_y vs hilite_spacing + if (!style.inline_preedit) + style.hilite_spacing = max(style.hilite_spacing, style.hilite_padding_y); + } + // fix padding and margin settings + int scale = style.margin_x < 0 ? -1 : 1; + style.margin_x = scale * max(style.hilite_padding_x, abs(style.margin_x)); + scale = style.margin_y < 0 ? -1 : 1; + style.margin_y = scale * max(style.hilite_padding_y, abs(style.margin_y)); + // get enhanced_position + _RimeGetBool(config, "style/enhanced_position", initialize, + style.enhanced_position, true, false); + // get color scheme + const int BUF_SIZE = 255; + char buffer[BUF_SIZE + 1] = {0}; + if (initialize && + RimeConfigGetString(config, "style/color_scheme", buffer, BUF_SIZE)) + _UpdateUIStyleColor(config, style); } -// load color configs to style, by "style/color_scheme" or specific scheme name "color" which is default empty -static bool _UpdateUIStyleColor(RimeConfig* config, UIStyle& style, std::string color) -{ - const int BUF_SIZE = 255; - char buffer[BUF_SIZE + 1] = {0}; - std::string color_mark = "style/color_scheme"; - // color scheme - if(RimeConfigGetString(config, color_mark.c_str(), buffer, BUF_SIZE) || !color.empty()) - { - std::string prefix("preset_color_schemes/"); - prefix += (color.empty()) ? buffer : color; - // define color format, default abgr if not set - ColorFormat fmt = COLOR_ABGR; - const std::map _colorFmt = { - {std::string("argb"), COLOR_ARGB}, - {std::string("rgba"), COLOR_RGBA}, - {std::string("abgr"), COLOR_ABGR} - }; - _RimeParseStringOptWithFallback(config, (prefix+"/color_format"), fmt, _colorFmt, COLOR_ABGR); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/back_color"), style.back_color, fmt, 0xffffffff); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/shadow_color"), style.shadow_color, fmt, TRANSPARENT_COLOR); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/prevpage_color"), style.prevpage_color, fmt, TRANSPARENT_COLOR); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/nextpage_color"), style.nextpage_color, fmt, TRANSPARENT_COLOR); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/text_color"), style.text_color, fmt, 0xff000000); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/candidate_text_color"), style.candidate_text_color, fmt, style.text_color); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/candidate_back_color"), style.candidate_back_color, fmt, TRANSPARENT_COLOR); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/border_color"), style.border_color, fmt, style.text_color); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/hilited_text_color"), style.hilited_text_color, fmt, style.text_color); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/hilited_back_color"), style.hilited_back_color, fmt, style.back_color); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/hilited_candidate_text_color"), style.hilited_candidate_text_color, fmt, style.hilited_text_color); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/hilited_candidate_back_color"), style.hilited_candidate_back_color, fmt, style.hilited_back_color); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/hilited_candidate_shadow_color"), style.hilited_candidate_shadow_color, fmt, TRANSPARENT_COLOR); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/hilited_shadow_color"), style.hilited_shadow_color, fmt, TRANSPARENT_COLOR); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/candidate_shadow_color"), style.candidate_shadow_color, fmt, TRANSPARENT_COLOR); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/candidate_border_color"), style.candidate_border_color, fmt, TRANSPARENT_COLOR); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/hilited_candidate_border_color"), style.hilited_candidate_border_color, fmt, TRANSPARENT_COLOR); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/label_color"), style.label_text_color, fmt, blend_colors(style.candidate_text_color, style.candidate_back_color)); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/hilited_label_color"), style.hilited_label_text_color, fmt, blend_colors(style.hilited_candidate_text_color, style.hilited_candidate_back_color)); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/comment_text_color"), style.comment_text_color, fmt, style.label_text_color); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/hilited_comment_text_color"), style.hilited_comment_text_color, fmt, style.hilited_label_text_color); - _RimeConfigGetColor32bWithFallback(config, (prefix + "/hilited_mark_color"), style.hilited_mark_color, fmt, TRANSPARENT_COLOR); - return true; - } - return false; +// load color configs to style, by "style/color_scheme" or specific scheme name +// "color" which is default empty +static bool _UpdateUIStyleColor(RimeConfig* config, + UIStyle& style, + std::string color) { + const int BUF_SIZE = 255; + char buffer[BUF_SIZE + 1] = {0}; + std::string color_mark = "style/color_scheme"; + // color scheme + if (RimeConfigGetString(config, color_mark.c_str(), buffer, BUF_SIZE) || + !color.empty()) { + std::string prefix("preset_color_schemes/"); + prefix += (color.empty()) ? buffer : color; + // define color format, default abgr if not set + ColorFormat fmt = COLOR_ABGR; + const std::map _colorFmt = { + {std::string("argb"), COLOR_ARGB}, + {std::string("rgba"), COLOR_RGBA}, + {std::string("abgr"), COLOR_ABGR}}; + _RimeParseStringOptWithFallback(config, (prefix + "/color_format"), fmt, + _colorFmt, COLOR_ABGR); + _RimeConfigGetColor32bWithFallback(config, (prefix + "/back_color"), + style.back_color, fmt, 0xffffffff); + _RimeConfigGetColor32bWithFallback(config, (prefix + "/shadow_color"), + style.shadow_color, fmt, + TRANSPARENT_COLOR); + _RimeConfigGetColor32bWithFallback(config, (prefix + "/prevpage_color"), + style.prevpage_color, fmt, + TRANSPARENT_COLOR); + _RimeConfigGetColor32bWithFallback(config, (prefix + "/nextpage_color"), + style.nextpage_color, fmt, + TRANSPARENT_COLOR); + _RimeConfigGetColor32bWithFallback(config, (prefix + "/text_color"), + style.text_color, fmt, 0xff000000); + _RimeConfigGetColor32bWithFallback( + config, (prefix + "/candidate_text_color"), style.candidate_text_color, + fmt, style.text_color); + _RimeConfigGetColor32bWithFallback( + config, (prefix + "/candidate_back_color"), style.candidate_back_color, + fmt, TRANSPARENT_COLOR); + _RimeConfigGetColor32bWithFallback(config, (prefix + "/border_color"), + style.border_color, fmt, + style.text_color); + _RimeConfigGetColor32bWithFallback(config, (prefix + "/hilited_text_color"), + style.hilited_text_color, fmt, + style.text_color); + _RimeConfigGetColor32bWithFallback(config, (prefix + "/hilited_back_color"), + style.hilited_back_color, fmt, + style.back_color); + _RimeConfigGetColor32bWithFallback( + config, (prefix + "/hilited_candidate_text_color"), + style.hilited_candidate_text_color, fmt, style.hilited_text_color); + _RimeConfigGetColor32bWithFallback( + config, (prefix + "/hilited_candidate_back_color"), + style.hilited_candidate_back_color, fmt, style.hilited_back_color); + _RimeConfigGetColor32bWithFallback( + config, (prefix + "/hilited_candidate_shadow_color"), + style.hilited_candidate_shadow_color, fmt, TRANSPARENT_COLOR); + _RimeConfigGetColor32bWithFallback( + config, (prefix + "/hilited_shadow_color"), style.hilited_shadow_color, + fmt, TRANSPARENT_COLOR); + _RimeConfigGetColor32bWithFallback( + config, (prefix + "/candidate_shadow_color"), + style.candidate_shadow_color, fmt, TRANSPARENT_COLOR); + _RimeConfigGetColor32bWithFallback( + config, (prefix + "/candidate_border_color"), + style.candidate_border_color, fmt, TRANSPARENT_COLOR); + _RimeConfigGetColor32bWithFallback( + config, (prefix + "/hilited_candidate_border_color"), + style.hilited_candidate_border_color, fmt, TRANSPARENT_COLOR); + _RimeConfigGetColor32bWithFallback( + config, (prefix + "/label_color"), style.label_text_color, fmt, + blend_colors(style.candidate_text_color, style.candidate_back_color)); + _RimeConfigGetColor32bWithFallback( + config, (prefix + "/hilited_label_color"), + style.hilited_label_text_color, fmt, + blend_colors(style.hilited_candidate_text_color, + style.hilited_candidate_back_color)); + _RimeConfigGetColor32bWithFallback(config, (prefix + "/comment_text_color"), + style.comment_text_color, fmt, + style.label_text_color); + _RimeConfigGetColor32bWithFallback( + config, (prefix + "/hilited_comment_text_color"), + style.hilited_comment_text_color, fmt, style.hilited_label_text_color); + _RimeConfigGetColor32bWithFallback(config, (prefix + "/hilited_mark_color"), + style.hilited_mark_color, fmt, + TRANSPARENT_COLOR); + return true; + } + return false; } -static void _LoadAppOptions(RimeConfig* config, AppOptionsByAppName& app_options) -{ - app_options.clear(); - RimeConfigIterator app_iter; - RimeConfigIterator option_iter; - RimeConfigBeginMap(&app_iter, config, "app_options"); - while (RimeConfigNext(&app_iter)) { - AppOptions &options(app_options[app_iter.key]); - RimeConfigBeginMap(&option_iter, config, app_iter.path); - while (RimeConfigNext(&option_iter)) { - Bool value = False; - if (RimeConfigGetBool(config, option_iter.path, &value)) { - options[option_iter.key] = !!value; - } - } - RimeConfigEnd(&option_iter); - } - RimeConfigEnd(&app_iter); +static void _LoadAppOptions(RimeConfig* config, + AppOptionsByAppName& app_options) { + app_options.clear(); + RimeConfigIterator app_iter; + RimeConfigIterator option_iter; + RimeConfigBeginMap(&app_iter, config, "app_options"); + while (RimeConfigNext(&app_iter)) { + AppOptions& options(app_options[app_iter.key]); + RimeConfigBeginMap(&option_iter, config, app_iter.path); + while (RimeConfigNext(&option_iter)) { + Bool value = False; + if (RimeConfigGetBool(config, option_iter.path, &value)) { + options[option_iter.key] = !!value; + } + } + RimeConfigEnd(&option_iter); + } + RimeConfigEnd(&app_iter); } -void RimeWithWeaselHandler::_GetStatus(Status & stat, UINT session_id, Context& ctx) -{ - RIME_STRUCT(RimeStatus, status); - if (RimeGetStatus(session_id, &status)) - { - std::string schema_id = ""; - if(status.schema_id) - schema_id = status.schema_id; - stat.schema_name = string_to_wstring(status.schema_name, CP_UTF8); - stat.schema_id = string_to_wstring(status.schema_id, CP_UTF8); - stat.ascii_mode = !!status.is_ascii_mode; - stat.composing = !!status.is_composing; - stat.disabled = !!status.is_disabled; - stat.full_shape = !!status.is_full_shape; - if (schema_id != m_last_schema_id) - { - m_session_status_map[session_id].__synced = false; - m_last_schema_id = schema_id; - if(schema_id != ".default") { // don't load for schema select menu - bool inline_preedit = m_session_status_map[session_id].style.inline_preedit; - _LoadSchemaSpecificSettings(session_id, schema_id); - _LoadAppInlinePreeditSet(session_id, true); - if(m_session_status_map[session_id].style.inline_preedit != inline_preedit) - _UpdateInlinePreeditStatus(session_id); // in case of inline_preedit set in schema - _RefreshTrayIcon(session_id, _UpdateUICallback); // refresh icon after schema changed - m_ui->style() = m_session_status_map[session_id].style; - if (m_show_notifications.find("schema") != m_show_notifications.end() && m_show_notifications_time > 0) { - ctx.aux.str = stat.schema_name; - m_ui->Update(ctx, stat); - m_ui->ShowWithTimeout(m_show_notifications_time); - } - } - } - RimeFreeStatus(&status); - } +void RimeWithWeaselHandler::_GetStatus(Status& stat, + UINT session_id, + Context& ctx) { + RIME_STRUCT(RimeStatus, status); + if (RimeGetStatus(session_id, &status)) { + std::string schema_id = ""; + if (status.schema_id) + schema_id = status.schema_id; + stat.schema_name = string_to_wstring(status.schema_name, CP_UTF8); + stat.schema_id = string_to_wstring(status.schema_id, CP_UTF8); + stat.ascii_mode = !!status.is_ascii_mode; + stat.composing = !!status.is_composing; + stat.disabled = !!status.is_disabled; + stat.full_shape = !!status.is_full_shape; + if (schema_id != m_last_schema_id) { + m_session_status_map[session_id].__synced = false; + m_last_schema_id = schema_id; + if (schema_id != ".default") { // don't load for schema select menu + bool inline_preedit = + m_session_status_map[session_id].style.inline_preedit; + _LoadSchemaSpecificSettings(session_id, schema_id); + _LoadAppInlinePreeditSet(session_id, true); + if (m_session_status_map[session_id].style.inline_preedit != + inline_preedit) + _UpdateInlinePreeditStatus( + session_id); // in case of inline_preedit set in schema + _RefreshTrayIcon( + session_id, + _UpdateUICallback); // refresh icon after schema changed + m_ui->style() = m_session_status_map[session_id].style; + if (m_show_notifications.find("schema") != m_show_notifications.end() && + m_show_notifications_time > 0) { + ctx.aux.str = stat.schema_name; + m_ui->Update(ctx, stat); + m_ui->ShowWithTimeout(m_show_notifications_time); + } + } + } + RimeFreeStatus(&status); + } } -void RimeWithWeaselHandler::_GetContext(Context & weasel_context, UINT session_id) -{ - RIME_STRUCT(RimeContext, ctx); - if (RimeGetContext(session_id, &ctx)) - { - if (ctx.composition.length > 0) - { - weasel_context.preedit.str = string_to_wstring(ctx.composition.preedit, CP_UTF8); - if (ctx.composition.sel_start < ctx.composition.sel_end) - { - TextAttribute attr; - attr.type = HIGHLIGHTED; - attr.range.start = utf8towcslen(ctx.composition.preedit, ctx.composition.sel_start); - attr.range.end = utf8towcslen(ctx.composition.preedit, ctx.composition.sel_end); - - weasel_context.preedit.attributes.push_back(attr); - } - } - if (ctx.menu.num_candidates) - { - CandidateInfo &cinfo(weasel_context.cinfo); - _GetCandidateInfo(cinfo, ctx); - } - RimeFreeContext(&ctx); - } +void RimeWithWeaselHandler::_GetContext(Context& weasel_context, + UINT session_id) { + RIME_STRUCT(RimeContext, ctx); + if (RimeGetContext(session_id, &ctx)) { + if (ctx.composition.length > 0) { + weasel_context.preedit.str = + string_to_wstring(ctx.composition.preedit, CP_UTF8); + if (ctx.composition.sel_start < ctx.composition.sel_end) { + TextAttribute attr; + attr.type = HIGHLIGHTED; + attr.range.start = + utf8towcslen(ctx.composition.preedit, ctx.composition.sel_start); + attr.range.end = + utf8towcslen(ctx.composition.preedit, ctx.composition.sel_end); + + weasel_context.preedit.attributes.push_back(attr); + } + } + if (ctx.menu.num_candidates) { + CandidateInfo& cinfo(weasel_context.cinfo); + _GetCandidateInfo(cinfo, ctx); + } + RimeFreeContext(&ctx); + } } -bool RimeWithWeaselHandler::_IsSessionTSF(UINT session_id) -{ - static char client_type[20] = { 0 }; - RimeGetProperty(session_id, "client_type", client_type, sizeof(client_type) - 1); - return std::string(client_type) == "tsf"; +bool RimeWithWeaselHandler::_IsSessionTSF(UINT session_id) { + static char client_type[20] = {0}; + RimeGetProperty(session_id, "client_type", client_type, + sizeof(client_type) - 1); + return std::string(client_type) == "tsf"; } -void RimeWithWeaselHandler::_UpdateInlinePreeditStatus(UINT session_id) -{ - if (!m_ui) return; - // set inline_preedit option - bool inline_preedit = m_session_status_map[session_id].style.inline_preedit && _IsSessionTSF(session_id); - RimeSetOption(session_id, "inline_preedit", Bool(inline_preedit)); - // show soft cursor on weasel panel but not inline - RimeSetOption(session_id, "soft_cursor", Bool(!inline_preedit)); +void RimeWithWeaselHandler::_UpdateInlinePreeditStatus(UINT session_id) { + if (!m_ui) + return; + // set inline_preedit option + bool inline_preedit = m_session_status_map[session_id].style.inline_preedit && + _IsSessionTSF(session_id); + RimeSetOption(session_id, "inline_preedit", Bool(inline_preedit)); + // show soft cursor on weasel panel but not inline + RimeSetOption(session_id, "soft_cursor", Bool(!inline_preedit)); } - diff --git a/RimeWithWeasel/WeaselUtility.cpp b/RimeWithWeasel/WeaselUtility.cpp index f1e0e48f0..0951623a3 100644 --- a/RimeWithWeasel/WeaselUtility.cpp +++ b/RimeWithWeasel/WeaselUtility.cpp @@ -6,53 +6,48 @@ namespace fs = boost::filesystem; fs::path WeaselUserDataPath() { - WCHAR _path[MAX_PATH] = {0}; - const WCHAR KEY[] = L"Software\\Rime\\Weasel"; - HKEY hKey; - LSTATUS ret = RegOpenKey(HKEY_CURRENT_USER, KEY, &hKey); - if (ret == ERROR_SUCCESS) - { - DWORD len = sizeof(_path); - DWORD type = 0; - DWORD data = 0; - ret = RegQueryValueEx(hKey, L"RimeUserDir", NULL, &type, (LPBYTE)_path, &len); - RegCloseKey(hKey); - if (ret == ERROR_SUCCESS && type == REG_SZ && _path[0]) - { - return fs::path(_path); - } - } - // default location - ExpandEnvironmentStringsW(L"%AppData%\\Rime", _path, _countof(_path)); - return fs::path(_path); + WCHAR _path[MAX_PATH] = {0}; + const WCHAR KEY[] = L"Software\\Rime\\Weasel"; + HKEY hKey; + LSTATUS ret = RegOpenKey(HKEY_CURRENT_USER, KEY, &hKey); + if (ret == ERROR_SUCCESS) { + DWORD len = sizeof(_path); + DWORD type = 0; + DWORD data = 0; + ret = + RegQueryValueEx(hKey, L"RimeUserDir", NULL, &type, (LPBYTE)_path, &len); + RegCloseKey(hKey); + if (ret == ERROR_SUCCESS && type == REG_SZ && _path[0]) { + return fs::path(_path); + } + } + // default location + ExpandEnvironmentStringsW(L"%AppData%\\Rime", _path, _countof(_path)); + return fs::path(_path); } fs::path WeaselSharedDataPath() { - wchar_t _path[MAX_PATH] = {0}; - GetModuleFileNameW(NULL, _path, _countof(_path)); - return fs::path(_path).remove_filename().append("data"); + wchar_t _path[MAX_PATH] = {0}; + GetModuleFileNameW(NULL, _path, _countof(_path)); + return fs::path(_path).remove_filename().append("data"); } -std::string GetCustomResource(const char *name, const char *type) -{ - const HINSTANCE module = 0; // main executable - HRSRC hRes = FindResourceA(module, name, type); - if ( hRes ) - { - HGLOBAL hData = LoadResource(module, hRes); - if ( hData ) - { - const char *data = (const char*)::LockResource(hData); - size_t size = ::SizeofResource(module, hRes); +std::string GetCustomResource(const char* name, const char* type) { + const HINSTANCE module = 0; // main executable + HRSRC hRes = FindResourceA(module, name, type); + if (hRes) { + HGLOBAL hData = LoadResource(module, hRes); + if (hData) { + const char* data = (const char*)::LockResource(hData); + size_t size = ::SizeofResource(module, hRes); - if ( data && size ) - { - if ( data[size-1] == '\0' ) // null-terminated string - size--; - return std::string(data, size); - } - } + if (data && size) { + if (data[size - 1] == '\0') // null-terminated string + size--; + return std::string(data, size); + } } + } - return std::string(); + return std::string(); } diff --git a/WeaselDeployer/Configurator.cpp b/WeaselDeployer/Configurator.cpp index bec68230d..c01183b2c 100644 --- a/WeaselDeployer/Configurator.cpp +++ b/WeaselDeployer/Configurator.cpp @@ -9,229 +9,229 @@ #include #include #include -#pragma warning(disable: 4005) +#pragma warning(disable : 4005) #include #include -#pragma warning(default: 4005) +#pragma warning(default : 4005) #include #include #include "WeaselDeployer.h" -static void CreateFileIfNotExist(std::string filename) -{ - boost::filesystem::path file_path = WeaselUserDataPath() / string_to_wstring(filename, CP_UTF8); - DWORD dwAttrib = GetFileAttributes(file_path.c_str()); - if (!(INVALID_FILE_ATTRIBUTES != dwAttrib && 0 == (dwAttrib & FILE_ATTRIBUTE_DIRECTORY))) - { - std::wofstream o(file_path.c_str(), std::ios::app); - o.close(); - } +static void CreateFileIfNotExist(std::string filename) { + boost::filesystem::path file_path = + WeaselUserDataPath() / string_to_wstring(filename, CP_UTF8); + DWORD dwAttrib = GetFileAttributes(file_path.c_str()); + if (!(INVALID_FILE_ATTRIBUTES != dwAttrib && + 0 == (dwAttrib & FILE_ATTRIBUTE_DIRECTORY))) { + std::wofstream o(file_path.c_str(), std::ios::app); + o.close(); + } } -Configurator::Configurator() -{ - CreateFileIfNotExist("default.custom.yaml"); - CreateFileIfNotExist("weasel.custom.yaml"); +Configurator::Configurator() { + CreateFileIfNotExist("default.custom.yaml"); + CreateFileIfNotExist("weasel.custom.yaml"); } -void Configurator::Initialize() -{ - RIME_STRUCT(RimeTraits, weasel_traits); - std::string shared_dir = wstring_to_string(WeaselSharedDataPath().wstring(), CP_UTF8); - std::string user_dir = wstring_to_string(WeaselUserDataPath().wstring(), CP_UTF8); - weasel_traits.shared_data_dir = shared_dir.c_str(); - weasel_traits.user_data_dir = user_dir.c_str(); - weasel_traits.prebuilt_data_dir = weasel_traits.shared_data_dir; - std::string distribution_name = wstring_to_string(WEASEL_IME_NAME, CP_UTF8); - weasel_traits.distribution_name = distribution_name.c_str(); - weasel_traits.distribution_code_name = WEASEL_CODE_NAME; - weasel_traits.distribution_version = WEASEL_VERSION; - weasel_traits.app_name = "rime.weasel"; - RimeSetup(&weasel_traits); - - LOG(INFO) << "WeaselDeployer reporting."; - RimeDeployerInitialize(NULL); +void Configurator::Initialize() { + RIME_STRUCT(RimeTraits, weasel_traits); + std::string shared_dir = + wstring_to_string(WeaselSharedDataPath().wstring(), CP_UTF8); + std::string user_dir = + wstring_to_string(WeaselUserDataPath().wstring(), CP_UTF8); + weasel_traits.shared_data_dir = shared_dir.c_str(); + weasel_traits.user_data_dir = user_dir.c_str(); + weasel_traits.prebuilt_data_dir = weasel_traits.shared_data_dir; + std::string distribution_name = wstring_to_string(WEASEL_IME_NAME, CP_UTF8); + weasel_traits.distribution_name = distribution_name.c_str(); + weasel_traits.distribution_code_name = WEASEL_CODE_NAME; + weasel_traits.distribution_version = WEASEL_VERSION; + weasel_traits.app_name = "rime.weasel"; + RimeSetup(&weasel_traits); + + LOG(INFO) << "WeaselDeployer reporting."; + RimeDeployerInitialize(NULL); } -static bool configure_switcher(RimeLeversApi* api, RimeSwitcherSettings* switchcer_settings, bool* reconfigured) -{ - RimeCustomSettings* settings = (RimeCustomSettings*)switchcer_settings; - if (!api->load_settings(settings)) - return false; - SwitcherSettingsDialog dialog(switchcer_settings); - if (dialog.DoModal() == IDOK) { - if (api->save_settings(settings)) - *reconfigured = true; - return true; - } - return false; +static bool configure_switcher(RimeLeversApi* api, + RimeSwitcherSettings* switchcer_settings, + bool* reconfigured) { + RimeCustomSettings* settings = (RimeCustomSettings*)switchcer_settings; + if (!api->load_settings(settings)) + return false; + SwitcherSettingsDialog dialog(switchcer_settings); + if (dialog.DoModal() == IDOK) { + if (api->save_settings(settings)) + *reconfigured = true; + return true; + } + return false; } -static bool configure_ui(RimeLeversApi* api, UIStyleSettings* ui_style_settings, bool* reconfigured) { - RimeCustomSettings* settings = ui_style_settings->settings(); - if (!api->load_settings(settings)) - return false; - UIStyleSettingsDialog dialog(ui_style_settings); - if (dialog.DoModal() == IDOK) { - if (api->save_settings(settings)) - *reconfigured = true; - return true; - } - return false; +static bool configure_ui(RimeLeversApi* api, + UIStyleSettings* ui_style_settings, + bool* reconfigured) { + RimeCustomSettings* settings = ui_style_settings->settings(); + if (!api->load_settings(settings)) + return false; + UIStyleSettingsDialog dialog(ui_style_settings); + if (dialog.DoModal() == IDOK) { + if (api->save_settings(settings)) + *reconfigured = true; + return true; + } + return false; } -int Configurator::Run(bool installing) -{ - RimeModule* levers = rime_get_api()->find_module("levers"); - if (!levers) return 1; - RimeLeversApi* api = (RimeLeversApi*)levers->get_api(); - if (!api) return 1; +int Configurator::Run(bool installing) { + RimeModule* levers = rime_get_api()->find_module("levers"); + if (!levers) + return 1; + RimeLeversApi* api = (RimeLeversApi*)levers->get_api(); + if (!api) + return 1; - bool reconfigured = false; + bool reconfigured = false; - RimeSwitcherSettings* switcher_settings = api->switcher_settings_init(); - UIStyleSettings ui_style_settings; + RimeSwitcherSettings* switcher_settings = api->switcher_settings_init(); + UIStyleSettings ui_style_settings; - bool skip_switcher_settings = installing && !api->is_first_run((RimeCustomSettings*)switcher_settings); - bool skip_ui_style_settings = installing && !api->is_first_run(ui_style_settings.settings()); + bool skip_switcher_settings = + installing && !api->is_first_run((RimeCustomSettings*)switcher_settings); + bool skip_ui_style_settings = + installing && !api->is_first_run(ui_style_settings.settings()); - (skip_switcher_settings || configure_switcher(api, switcher_settings, &reconfigured)) && - (skip_ui_style_settings || configure_ui(api, &ui_style_settings, &reconfigured)); + (skip_switcher_settings || + configure_switcher(api, switcher_settings, &reconfigured)) && + (skip_ui_style_settings || + configure_ui(api, &ui_style_settings, &reconfigured)); - api->custom_settings_destroy((RimeCustomSettings*)switcher_settings); + api->custom_settings_destroy((RimeCustomSettings*)switcher_settings); - if (installing || reconfigured) { - return UpdateWorkspace(reconfigured); - } - return 0; + if (installing || reconfigured) { + return UpdateWorkspace(reconfigured); + } + return 0; } int Configurator::UpdateWorkspace(bool report_errors) { - HANDLE hMutex = CreateMutex(NULL, TRUE, L"WeaselDeployerMutex"); - if (!hMutex) - { - LOG(ERROR) << "Error creating WeaselDeployerMutex."; - return 1; - } - if (GetLastError() == ERROR_ALREADY_EXISTS) - { - LOG(WARNING) << "another deployer process is running; aborting operation."; - CloseHandle(hMutex); - if (report_errors) - { - //MessageBox(NULL, L"正在執行另一項部署任務,方纔所做的修改將在輸入法再次啓動後生效。", L"【小狼毫】", MB_OK | MB_ICONINFORMATION); - MSG_BY_IDS(IDS_STR_DEPLOYING_RESTARTREQ, IDS_STR_WEASEL, MB_OK | MB_ICONINFORMATION); - } - return 1; - } - - weasel::Client client; - if (client.Connect()) - { - LOG(INFO) << "Turning WeaselServer into maintenance mode."; - client.StartMaintenance(); - } - - { - RimeApi* rime = rime_get_api(); - // initialize default config, preset schemas - rime->deploy(); - // initialize weasel config - rime->deploy_config_file("weasel.yaml", "config_version"); - } - - CloseHandle(hMutex); // should be closed before resuming service. - - if (client.Connect()) - { - LOG(INFO) << "Resuming service."; - client.EndMaintenance(); - } - return 0; + HANDLE hMutex = CreateMutex(NULL, TRUE, L"WeaselDeployerMutex"); + if (!hMutex) { + LOG(ERROR) << "Error creating WeaselDeployerMutex."; + return 1; + } + if (GetLastError() == ERROR_ALREADY_EXISTS) { + LOG(WARNING) << "another deployer process is running; aborting operation."; + CloseHandle(hMutex); + if (report_errors) { + // MessageBox(NULL, + // L"正在執行另一項部署任務,方纔所做的修改將在輸入法再次啓動後生效。", + // L"【小狼毫】", MB_OK | MB_ICONINFORMATION); + MSG_BY_IDS(IDS_STR_DEPLOYING_RESTARTREQ, IDS_STR_WEASEL, + MB_OK | MB_ICONINFORMATION); + } + return 1; + } + + weasel::Client client; + if (client.Connect()) { + LOG(INFO) << "Turning WeaselServer into maintenance mode."; + client.StartMaintenance(); + } + + { + RimeApi* rime = rime_get_api(); + // initialize default config, preset schemas + rime->deploy(); + // initialize weasel config + rime->deploy_config_file("weasel.yaml", "config_version"); + } + + CloseHandle(hMutex); // should be closed before resuming service. + + if (client.Connect()) { + LOG(INFO) << "Resuming service."; + client.EndMaintenance(); + } + return 0; } int Configurator::DictManagement() { - HANDLE hMutex = CreateMutex(NULL, TRUE, L"WeaselDeployerMutex"); - if (!hMutex) - { - LOG(ERROR) << "Error creating WeaselDeployerMutex."; - return 1; - } - if (GetLastError() == ERROR_ALREADY_EXISTS) - { - LOG(WARNING) << "another deployer process is running; aborting operation."; - CloseHandle(hMutex); - //MessageBox(NULL, L"正在執行另一項部署任務,請稍候再試。", L"【小狼毫】", MB_OK | MB_ICONINFORMATION); - MSG_BY_IDS(IDS_STR_DEPLOYING_WAIT, IDS_STR_WEASEL, MB_OK | MB_ICONINFORMATION); - return 1; - } - - weasel::Client client; - if (client.Connect()) - { - LOG(INFO) << "Turning WeaselServer into maintenance mode."; - client.StartMaintenance(); - } - - { - RimeApi* rime = rime_get_api(); - if (RIME_API_AVAILABLE(rime, run_task)) - { - rime->run_task("installation_update"); // setup user data sync dir - } - DictManagementDialog dlg; - dlg.DoModal(); - } - - CloseHandle(hMutex); // should be closed before resuming service. - - if (client.Connect()) - { - LOG(INFO) << "Resuming service."; - client.EndMaintenance(); - } - return 0; + HANDLE hMutex = CreateMutex(NULL, TRUE, L"WeaselDeployerMutex"); + if (!hMutex) { + LOG(ERROR) << "Error creating WeaselDeployerMutex."; + return 1; + } + if (GetLastError() == ERROR_ALREADY_EXISTS) { + LOG(WARNING) << "another deployer process is running; aborting operation."; + CloseHandle(hMutex); + // MessageBox(NULL, L"正在執行另一項部署任務,請稍候再試。", L"【小狼毫】", + // MB_OK | MB_ICONINFORMATION); + MSG_BY_IDS(IDS_STR_DEPLOYING_WAIT, IDS_STR_WEASEL, + MB_OK | MB_ICONINFORMATION); + return 1; + } + + weasel::Client client; + if (client.Connect()) { + LOG(INFO) << "Turning WeaselServer into maintenance mode."; + client.StartMaintenance(); + } + + { + RimeApi* rime = rime_get_api(); + if (RIME_API_AVAILABLE(rime, run_task)) { + rime->run_task("installation_update"); // setup user data sync dir + } + DictManagementDialog dlg; + dlg.DoModal(); + } + + CloseHandle(hMutex); // should be closed before resuming service. + + if (client.Connect()) { + LOG(INFO) << "Resuming service."; + client.EndMaintenance(); + } + return 0; } int Configurator::SyncUserData() { - HANDLE hMutex = CreateMutex(NULL, TRUE, L"WeaselDeployerMutex"); - if (!hMutex) - { - LOG(ERROR) << "Error creating WeaselDeployerMutex."; - return 1; - } - if (GetLastError() == ERROR_ALREADY_EXISTS) - { - LOG(WARNING) << "another deployer process is running; aborting operation."; - CloseHandle(hMutex); - //MessageBox(NULL, L"正在執行另一項部署任務,請稍候再試。", L"【小狼毫】", MB_OK | MB_ICONINFORMATION); - MSG_BY_IDS(IDS_STR_DEPLOYING_WAIT, IDS_STR_WEASEL, MB_OK | MB_ICONINFORMATION); - return 1; - } - - weasel::Client client; - if (client.Connect()) - { - LOG(INFO) << "Turning WeaselServer into maintenance mode."; - client.StartMaintenance(); - } - - { - RimeApi* rime = rime_get_api(); - if (!rime->sync_user_data()) - { - LOG(ERROR) << "Error synching user data."; - CloseHandle(hMutex); - return 1; - } - rime->join_maintenance_thread(); - } - - CloseHandle(hMutex); // should be closed before resuming service. - - if (client.Connect()) - { - LOG(INFO) << "Resuming service."; - client.EndMaintenance(); - } - return 0; + HANDLE hMutex = CreateMutex(NULL, TRUE, L"WeaselDeployerMutex"); + if (!hMutex) { + LOG(ERROR) << "Error creating WeaselDeployerMutex."; + return 1; + } + if (GetLastError() == ERROR_ALREADY_EXISTS) { + LOG(WARNING) << "another deployer process is running; aborting operation."; + CloseHandle(hMutex); + // MessageBox(NULL, L"正在執行另一項部署任務,請稍候再試。", L"【小狼毫】", + // MB_OK | MB_ICONINFORMATION); + MSG_BY_IDS(IDS_STR_DEPLOYING_WAIT, IDS_STR_WEASEL, + MB_OK | MB_ICONINFORMATION); + return 1; + } + + weasel::Client client; + if (client.Connect()) { + LOG(INFO) << "Turning WeaselServer into maintenance mode."; + client.StartMaintenance(); + } + + { + RimeApi* rime = rime_get_api(); + if (!rime->sync_user_data()) { + LOG(ERROR) << "Error synching user data."; + CloseHandle(hMutex); + return 1; + } + rime->join_maintenance_thread(); + } + + CloseHandle(hMutex); // should be closed before resuming service. + + if (client.Connect()) { + LOG(INFO) << "Resuming service."; + client.EndMaintenance(); + } + return 0; } diff --git a/WeaselDeployer/Configurator.h b/WeaselDeployer/Configurator.h index 50b88d1de..ac14091d6 100644 --- a/WeaselDeployer/Configurator.h +++ b/WeaselDeployer/Configurator.h @@ -2,15 +2,13 @@ class UIStyleSettings; -class Configurator -{ -public: - explicit Configurator(); - - void Initialize(); - int Run(bool installing); - int UpdateWorkspace(bool report_errors = false); - int DictManagement(); - int SyncUserData(); +class Configurator { + public: + explicit Configurator(); + + void Initialize(); + int Run(bool installing); + int UpdateWorkspace(bool report_errors = false); + int DictManagement(); + int SyncUserData(); }; - diff --git a/WeaselDeployer/DictManagementDialog.cpp b/WeaselDeployer/DictManagementDialog.cpp index 7fa86aec6..aa738aac0 100644 --- a/WeaselDeployer/DictManagementDialog.cpp +++ b/WeaselDeployer/DictManagementDialog.cpp @@ -5,178 +5,196 @@ #include #include "WeaselDeployer.h" -DictManagementDialog::DictManagementDialog() -{ - api_ = (RimeLeversApi*)rime_get_api()->find_module("levers")->get_api(); +DictManagementDialog::DictManagementDialog() { + api_ = (RimeLeversApi*)rime_get_api()->find_module("levers")->get_api(); } -DictManagementDialog::~DictManagementDialog() -{ -} +DictManagementDialog::~DictManagementDialog() {} void DictManagementDialog::Populate() { - RimeUserDictIterator iter = {0}; - api_->user_dict_iterator_init(&iter); - while (const char* dict = api_->next_user_dict(&iter)) { - std::wstring txt = string_to_wstring(dict, CP_UTF8); - user_dict_list_.AddString(txt.c_str()); - } - api_->user_dict_iterator_destroy(&iter); - user_dict_list_.SetCurSel(-1); + RimeUserDictIterator iter = {0}; + api_->user_dict_iterator_init(&iter); + while (const char* dict = api_->next_user_dict(&iter)) { + std::wstring txt = string_to_wstring(dict, CP_UTF8); + user_dict_list_.AddString(txt.c_str()); + } + api_->user_dict_iterator_destroy(&iter); + user_dict_list_.SetCurSel(-1); } LRESULT DictManagementDialog::OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) { - user_dict_list_.Attach(GetDlgItem(IDC_USER_DICT_LIST)); - backup_.Attach(GetDlgItem(IDC_BACKUP)); - backup_.EnableWindow(FALSE); - restore_.Attach(GetDlgItem(IDC_RESTORE)); - restore_.EnableWindow(TRUE); - export_.Attach(GetDlgItem(IDC_EXPORT)); - export_.EnableWindow(FALSE); - import_.Attach(GetDlgItem(IDC_IMPORT)); - import_.EnableWindow(FALSE); - - Populate(); - - CenterWindow(); - BringWindowToTop(); - return TRUE; + user_dict_list_.Attach(GetDlgItem(IDC_USER_DICT_LIST)); + backup_.Attach(GetDlgItem(IDC_BACKUP)); + backup_.EnableWindow(FALSE); + restore_.Attach(GetDlgItem(IDC_RESTORE)); + restore_.EnableWindow(TRUE); + export_.Attach(GetDlgItem(IDC_EXPORT)); + export_.EnableWindow(FALSE); + import_.Attach(GetDlgItem(IDC_IMPORT)); + import_.EnableWindow(FALSE); + + Populate(); + + CenterWindow(); + BringWindowToTop(); + return TRUE; } LRESULT DictManagementDialog::OnClose(UINT, WPARAM, LPARAM, BOOL&) { - EndDialog(IDCANCEL); - return 0; + EndDialog(IDCANCEL); + return 0; } LRESULT DictManagementDialog::OnBackup(WORD, WORD code, HWND, BOOL&) { - int sel = user_dict_list_.GetCurSel(); - if (sel < 0 || sel >= user_dict_list_.GetCount()) { - //MessageBox(L"請在左列選擇要導出的詞典名稱。", L":-(", MB_OK | MB_ICONINFORMATION); - MSG_BY_IDS(IDS_STR_SEL_EXPORT_DICT_NAME, IDS_STR_SAD, MB_OK | MB_ICONINFORMATION); - return 0; - } - std::wstring path; - { - char dir[MAX_PATH] = {0}; - rime_get_api()->get_user_data_sync_dir(dir, _countof(dir)); - WCHAR wdir[MAX_PATH] = {0}; - MultiByteToWideChar(CP_ACP, 0, dir, -1, wdir, _countof(wdir)); - path = wdir; - } - if (_waccess_s(path.c_str(), 0) != 0 && - !CreateDirectoryW(path.c_str(), NULL) && - GetLastError() == ERROR_PATH_NOT_FOUND) { - //MessageBox(L"未能完成導出操作。會不會是同步文件夾無法訪問?", L":-(", MB_OK | MB_ICONERROR); - MSG_BY_IDS(IDS_STR_ERREXPORT_SYNC_UV, IDS_STR_SAD, MB_OK | MB_ICONERROR); - return 0; - } - WCHAR dict_name[100] = {0}; - user_dict_list_.GetText(sel, dict_name); - path += std::wstring(L"\\") + dict_name + L".userdb.txt"; - std::string dict_name_str = wstring_to_string(dict_name, CP_UTF8); - if (!api_->backup_user_dict(dict_name_str.c_str())) { - //MessageBox(L"不知哪裏出錯了,未能完成導出操作。", L":-(", MB_OK | MB_ICONERROR); - MSG_BY_IDS(IDS_STR_ERR_EXPORT_UNKNOWN, IDS_STR_SAD, MB_OK | MB_ICONERROR); - return 0; - } - else if (_waccess(path.c_str(), 0) != 0) { - //MessageBox(L"咦,輸出的快照文件找不着了。", L":-(", MB_OK | MB_ICONERROR); - MSG_BY_IDS(IDS_STR_ERR_EXPORT_SNAP_LOST, IDS_STR_SAD, MB_OK | MB_ICONERROR); - return 0; - } - std::wstring param = L"/select, \"" + path + L"\""; - ShellExecute(NULL, L"open", L"explorer.exe", param.c_str(), NULL, SW_SHOWNORMAL); - return 0; + int sel = user_dict_list_.GetCurSel(); + if (sel < 0 || sel >= user_dict_list_.GetCount()) { + // MessageBox(L"請在左列選擇要導出的詞典名稱。", L":-(", MB_OK | + // MB_ICONINFORMATION); + MSG_BY_IDS(IDS_STR_SEL_EXPORT_DICT_NAME, IDS_STR_SAD, + MB_OK | MB_ICONINFORMATION); + return 0; + } + std::wstring path; + { + char dir[MAX_PATH] = {0}; + rime_get_api()->get_user_data_sync_dir(dir, _countof(dir)); + WCHAR wdir[MAX_PATH] = {0}; + MultiByteToWideChar(CP_ACP, 0, dir, -1, wdir, _countof(wdir)); + path = wdir; + } + if (_waccess_s(path.c_str(), 0) != 0 && + !CreateDirectoryW(path.c_str(), NULL) && + GetLastError() == ERROR_PATH_NOT_FOUND) { + // MessageBox(L"未能完成導出操作。會不會是同步文件夾無法訪問?", L":-(", + // MB_OK | MB_ICONERROR); + MSG_BY_IDS(IDS_STR_ERREXPORT_SYNC_UV, IDS_STR_SAD, MB_OK | MB_ICONERROR); + return 0; + } + WCHAR dict_name[100] = {0}; + user_dict_list_.GetText(sel, dict_name); + path += std::wstring(L"\\") + dict_name + L".userdb.txt"; + std::string dict_name_str = wstring_to_string(dict_name, CP_UTF8); + if (!api_->backup_user_dict(dict_name_str.c_str())) { + // MessageBox(L"不知哪裏出錯了,未能完成導出操作。", L":-(", MB_OK | + // MB_ICONERROR); + MSG_BY_IDS(IDS_STR_ERR_EXPORT_UNKNOWN, IDS_STR_SAD, MB_OK | MB_ICONERROR); + return 0; + } else if (_waccess(path.c_str(), 0) != 0) { + // MessageBox(L"咦,輸出的快照文件找不着了。", L":-(", MB_OK | + // MB_ICONERROR); + MSG_BY_IDS(IDS_STR_ERR_EXPORT_SNAP_LOST, IDS_STR_SAD, MB_OK | MB_ICONERROR); + return 0; + } + std::wstring param = L"/select, \"" + path + L"\""; + ShellExecute(NULL, L"open", L"explorer.exe", param.c_str(), NULL, + SW_SHOWNORMAL); + return 0; } LRESULT DictManagementDialog::OnRestore(WORD, WORD code, HWND, BOOL&) { - CFileDialog dlg(TRUE, L"snapshot", NULL, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, - L"詞典快照\0*.userdb.txt\0KCSS格式詞典快照\0*.userdb.kct.snapshot\0全部文件\0*.*\0"); - if (IDOK == dlg.DoModal()) { - char path[MAX_PATH] = {0}; - WideCharToMultiByte(CP_ACP, 0, dlg.m_szFileName, -1, path, _countof(path), NULL, NULL); - if (!api_->restore_user_dict(path)) { - //MessageBox(L"不知哪裏出錯了,未能完成操作。", L":-(", MB_OK | MB_ICONERROR); - MSG_BY_IDS(IDS_STR_ERR_UNKNOWN, IDS_STR_SAD, MB_OK | MB_ICONERROR); - } - else { - //MessageBox(L"完成了。", L":-)", MB_OK | MB_ICONINFORMATION); - MSG_BY_IDS(IDS_STR_ERR_SUCCESS, IDS_STR_HAPPY, MB_OK | MB_ICONINFORMATION); - } - } - return 0; + CFileDialog dlg(TRUE, L"snapshot", NULL, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, + L"詞典快照\0*.userdb.txt\0KCSS格式詞典快照\0*.userdb.kct." + L"snapshot\0全部文件\0*.*\0"); + if (IDOK == dlg.DoModal()) { + char path[MAX_PATH] = {0}; + WideCharToMultiByte(CP_ACP, 0, dlg.m_szFileName, -1, path, _countof(path), + NULL, NULL); + if (!api_->restore_user_dict(path)) { + // MessageBox(L"不知哪裏出錯了,未能完成操作。", L":-(", MB_OK | + // MB_ICONERROR); + MSG_BY_IDS(IDS_STR_ERR_UNKNOWN, IDS_STR_SAD, MB_OK | MB_ICONERROR); + } else { + // MessageBox(L"完成了。", L":-)", MB_OK | MB_ICONINFORMATION); + MSG_BY_IDS(IDS_STR_ERR_SUCCESS, IDS_STR_HAPPY, + MB_OK | MB_ICONINFORMATION); + } + } + return 0; } LRESULT DictManagementDialog::OnExport(WORD, WORD code, HWND, BOOL&) { - int sel = user_dict_list_.GetCurSel(); - if (sel < 0 || sel >= user_dict_list_.GetCount()) { - //MessageBox(L"請在左列選擇要導出的詞典名稱。", L":-(", MB_OK | MB_ICONINFORMATION); - MSG_BY_IDS(IDS_STR_SEL_EXPORT_DICT_NAME, IDS_STR_SAD, MB_OK | MB_ICONINFORMATION); - return 0; - } - WCHAR dict_name[MAX_PATH] = {0}; - user_dict_list_.GetText(sel, dict_name); - std::wstring file_name(dict_name); - file_name += L"_export.txt"; - CFileDialog dlg(FALSE, L"txt", file_name.c_str(), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, L"文本文檔\0*.txt\0全部文件\0*.*\0"); - if (IDOK == dlg.DoModal()) { - char path[MAX_PATH] = {0}; - WideCharToMultiByte(CP_ACP, 0, dlg.m_szFileName, -1, path, _countof(path), NULL, NULL); - std::string dict_name_str = wstring_to_string(dict_name, CP_UTF8); - int result = api_->export_user_dict(dict_name_str.c_str(), path); - if (result < 0) { - //MessageBox(L"不知哪裏出錯了,未能完成操作。", L":-(", MB_OK | MB_ICONERROR); - MSG_BY_IDS(IDS_STR_ERR_UNKNOWN, IDS_STR_SAD, MB_OK | MB_ICONERROR); - } - else if (_waccess(dlg.m_szFileName, 0) != 0) { - //MessageBox(L"咦,導出的文件找不着了。", L":-(", MB_OK | MB_ICONERROR); - MSG_BY_IDS(IDS_STR_ERR_EXPORT_FILE_LOST, IDS_STR_SAD, MB_OK | MB_ICONERROR); - } - else { - std::wstring report(L"導出了 " + std::to_wstring(result) + L" 條記錄。"); - //MessageBox(report.c_str(), L":-)", MB_OK | MB_ICONINFORMATION); - MSG_ID_CAP(report.c_str(), IDS_STR_SAD, MB_OK | MB_ICONINFORMATION); - std::wstring param = L"/select, \"" + std::wstring(dlg.m_szFileName) + L"\""; - ShellExecute(NULL, L"open", L"explorer.exe", param.c_str(), NULL, SW_SHOWNORMAL); - } - } - return 0; + int sel = user_dict_list_.GetCurSel(); + if (sel < 0 || sel >= user_dict_list_.GetCount()) { + // MessageBox(L"請在左列選擇要導出的詞典名稱。", L":-(", MB_OK | + // MB_ICONINFORMATION); + MSG_BY_IDS(IDS_STR_SEL_EXPORT_DICT_NAME, IDS_STR_SAD, + MB_OK | MB_ICONINFORMATION); + return 0; + } + WCHAR dict_name[MAX_PATH] = {0}; + user_dict_list_.GetText(sel, dict_name); + std::wstring file_name(dict_name); + file_name += L"_export.txt"; + CFileDialog dlg(FALSE, L"txt", file_name.c_str(), + OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, + L"文本文檔\0*.txt\0全部文件\0*.*\0"); + if (IDOK == dlg.DoModal()) { + char path[MAX_PATH] = {0}; + WideCharToMultiByte(CP_ACP, 0, dlg.m_szFileName, -1, path, _countof(path), + NULL, NULL); + std::string dict_name_str = wstring_to_string(dict_name, CP_UTF8); + int result = api_->export_user_dict(dict_name_str.c_str(), path); + if (result < 0) { + // MessageBox(L"不知哪裏出錯了,未能完成操作。", L":-(", MB_OK | + // MB_ICONERROR); + MSG_BY_IDS(IDS_STR_ERR_UNKNOWN, IDS_STR_SAD, MB_OK | MB_ICONERROR); + } else if (_waccess(dlg.m_szFileName, 0) != 0) { + // MessageBox(L"咦,導出的文件找不着了。", L":-(", MB_OK | MB_ICONERROR); + MSG_BY_IDS(IDS_STR_ERR_EXPORT_FILE_LOST, IDS_STR_SAD, + MB_OK | MB_ICONERROR); + } else { + std::wstring report(L"導出了 " + std::to_wstring(result) + L" 條記錄。"); + // MessageBox(report.c_str(), L":-)", MB_OK | MB_ICONINFORMATION); + MSG_ID_CAP(report.c_str(), IDS_STR_SAD, MB_OK | MB_ICONINFORMATION); + std::wstring param = + L"/select, \"" + std::wstring(dlg.m_szFileName) + L"\""; + ShellExecute(NULL, L"open", L"explorer.exe", param.c_str(), NULL, + SW_SHOWNORMAL); + } + } + return 0; } LRESULT DictManagementDialog::OnImport(WORD, WORD code, HWND, BOOL&) { - int sel = user_dict_list_.GetCurSel(); - if (sel < 0 || sel >= user_dict_list_.GetCount()) { - //MessageBox(L"請在左列選擇要導入的詞典名稱。", L":-(", MB_OK | MB_ICONINFORMATION); - MSG_BY_IDS(IDS_STR_SEL_IMPORT_DICT_NAME, IDS_STR_SAD, MB_OK | MB_ICONINFORMATION); - return 0; - } - WCHAR dict_name[MAX_PATH] = {0}; - user_dict_list_.GetText(sel, dict_name); - std::wstring file_name(dict_name); - file_name += L"_export.txt"; - CFileDialog dlg(TRUE, L"txt", file_name.c_str(), OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, L"文本文檔\0*.txt\0全部文件\0*.*\0"); - if (IDOK == dlg.DoModal()) { - char path[MAX_PATH] = {0}; - WideCharToMultiByte(CP_ACP, 0, dlg.m_szFileName, -1, path, _countof(path), NULL, NULL); - int result = api_->import_user_dict(wstring_to_string(dict_name, CP_UTF8).c_str(), path); - if (result < 0) { - //MessageBox(L"不知哪裏出錯了,未能完成操作。", L":-(", MB_OK | MB_ICONERROR); - MSG_BY_IDS(IDS_STR_ERR_UNKNOWN, IDS_STR_SAD, MB_OK | MB_ICONERROR); - } - else { - std::wstring report(L"導入了 " + std::to_wstring(result) + L" 條記錄。"); - //MessageBox(report.c_str(), L":-)", MB_OK | MB_ICONINFORMATION); - MSG_ID_CAP(report.c_str(), IDS_STR_SAD, MB_OK | MB_ICONINFORMATION); - } - } - return 0; + int sel = user_dict_list_.GetCurSel(); + if (sel < 0 || sel >= user_dict_list_.GetCount()) { + // MessageBox(L"請在左列選擇要導入的詞典名稱。", L":-(", MB_OK | + // MB_ICONINFORMATION); + MSG_BY_IDS(IDS_STR_SEL_IMPORT_DICT_NAME, IDS_STR_SAD, + MB_OK | MB_ICONINFORMATION); + return 0; + } + WCHAR dict_name[MAX_PATH] = {0}; + user_dict_list_.GetText(sel, dict_name); + std::wstring file_name(dict_name); + file_name += L"_export.txt"; + CFileDialog dlg(TRUE, L"txt", file_name.c_str(), + OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, + L"文本文檔\0*.txt\0全部文件\0*.*\0"); + if (IDOK == dlg.DoModal()) { + char path[MAX_PATH] = {0}; + WideCharToMultiByte(CP_ACP, 0, dlg.m_szFileName, -1, path, _countof(path), + NULL, NULL); + int result = api_->import_user_dict( + wstring_to_string(dict_name, CP_UTF8).c_str(), path); + if (result < 0) { + // MessageBox(L"不知哪裏出錯了,未能完成操作。", L":-(", MB_OK | + // MB_ICONERROR); + MSG_BY_IDS(IDS_STR_ERR_UNKNOWN, IDS_STR_SAD, MB_OK | MB_ICONERROR); + } else { + std::wstring report(L"導入了 " + std::to_wstring(result) + L" 條記錄。"); + // MessageBox(report.c_str(), L":-)", MB_OK | MB_ICONINFORMATION); + MSG_ID_CAP(report.c_str(), IDS_STR_SAD, MB_OK | MB_ICONINFORMATION); + } + } + return 0; } LRESULT DictManagementDialog::OnUserDictListSelChange(WORD, WORD, HWND, BOOL&) { - int index = user_dict_list_.GetCurSel(); - BOOL enabled = index < 0 ? FALSE : TRUE; - backup_.EnableWindow(enabled); - export_.EnableWindow(enabled); - import_.EnableWindow(enabled); - return 0; + int index = user_dict_list_.GetCurSel(); + BOOL enabled = index < 0 ? FALSE : TRUE; + backup_.EnableWindow(enabled); + export_.EnableWindow(enabled); + import_.EnableWindow(enabled); + return 0; } diff --git a/WeaselDeployer/DictManagementDialog.h b/WeaselDeployer/DictManagementDialog.h index de35ead57..edb878656 100644 --- a/WeaselDeployer/DictManagementDialog.h +++ b/WeaselDeployer/DictManagementDialog.h @@ -4,41 +4,39 @@ #include - class DictManagementDialog : public CDialogImpl { -public: - enum { IDD = IDD_DICT_MANAGEMENT }; - - DictManagementDialog(); - ~DictManagementDialog(); - -protected: - BEGIN_MSG_MAP(DictManagementDialog) - MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) - MESSAGE_HANDLER(WM_CLOSE, OnClose) - COMMAND_ID_HANDLER(IDC_BACKUP, OnBackup) - COMMAND_ID_HANDLER(IDC_RESTORE, OnRestore) - COMMAND_ID_HANDLER(IDC_EXPORT, OnExport) - COMMAND_ID_HANDLER(IDC_IMPORT, OnImport) - COMMAND_HANDLER(IDC_USER_DICT_LIST, LBN_SELCHANGE, OnUserDictListSelChange) - END_MSG_MAP() - - LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&); - LRESULT OnClose(UINT, WPARAM, LPARAM, BOOL&); - LRESULT OnBackup(WORD, WORD code, HWND, BOOL&); - LRESULT OnRestore(WORD, WORD code, HWND, BOOL&); - LRESULT OnExport(WORD, WORD code, HWND, BOOL&); - LRESULT OnImport(WORD, WORD code, HWND, BOOL&); - LRESULT OnUserDictListSelChange(WORD, WORD, HWND, BOOL&); - - void Populate(); - - CListBox user_dict_list_; - CButton backup_; - CButton restore_; - CButton export_; - CButton import_; - - RimeLeversApi* api_; + public: + enum { IDD = IDD_DICT_MANAGEMENT }; + + DictManagementDialog(); + ~DictManagementDialog(); + + protected: + BEGIN_MSG_MAP(DictManagementDialog) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + MESSAGE_HANDLER(WM_CLOSE, OnClose) + COMMAND_ID_HANDLER(IDC_BACKUP, OnBackup) + COMMAND_ID_HANDLER(IDC_RESTORE, OnRestore) + COMMAND_ID_HANDLER(IDC_EXPORT, OnExport) + COMMAND_ID_HANDLER(IDC_IMPORT, OnImport) + COMMAND_HANDLER(IDC_USER_DICT_LIST, LBN_SELCHANGE, OnUserDictListSelChange) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&); + LRESULT OnClose(UINT, WPARAM, LPARAM, BOOL&); + LRESULT OnBackup(WORD, WORD code, HWND, BOOL&); + LRESULT OnRestore(WORD, WORD code, HWND, BOOL&); + LRESULT OnExport(WORD, WORD code, HWND, BOOL&); + LRESULT OnImport(WORD, WORD code, HWND, BOOL&); + LRESULT OnUserDictListSelChange(WORD, WORD, HWND, BOOL&); + + void Populate(); + + CListBox user_dict_list_; + CButton backup_; + CButton restore_; + CButton export_; + CButton import_; + + RimeLeversApi* api_; }; - diff --git a/WeaselDeployer/SwitcherSettingsDialog.cpp b/WeaselDeployer/SwitcherSettingsDialog.cpp index cb563df8a..79dcba628 100644 --- a/WeaselDeployer/SwitcherSettingsDialog.cpp +++ b/WeaselDeployer/SwitcherSettingsDialog.cpp @@ -7,172 +7,183 @@ #include #include "WeaselDeployer.h" - SwitcherSettingsDialog::SwitcherSettingsDialog(RimeSwitcherSettings* settings) - : settings_(settings), loaded_(false), modified_(false) -{ - api_ = (RimeLeversApi*)rime_get_api()->find_module("levers")->get_api(); + : settings_(settings), loaded_(false), modified_(false) { + api_ = (RimeLeversApi*)rime_get_api()->find_module("levers")->get_api(); } - -SwitcherSettingsDialog::~SwitcherSettingsDialog() -{ -} +SwitcherSettingsDialog::~SwitcherSettingsDialog() {} void SwitcherSettingsDialog::Populate() { - if (!settings_) return; - RimeSchemaList available = {0}; - api_->get_available_schema_list(settings_, &available); - RimeSchemaList selected = {0}; - api_->get_selected_schema_list(settings_, &selected); - schema_list_.DeleteAllItems(); - size_t k = 0; - std::set recruited; - for (size_t i = 0; i < selected.size; ++i) { - const char* schema_id = selected.list[i].schema_id; - for (size_t j = 0; j < available.size; ++j) { - RimeSchemaListItem& item(available.list[j]); - RimeSchemaInfo* info = (RimeSchemaInfo*)item.reserved; - if (!strcmp(item.schema_id, schema_id) && recruited.find(info) == recruited.end()) { - recruited.insert(info); - std::wstring itemwstr = string_to_wstring(item.name, CP_UTF8); - schema_list_.AddItem(k, 0, itemwstr.c_str()); - schema_list_.SetItemData(k, (DWORD_PTR)info); - schema_list_.SetCheckState(k, TRUE); - ++k; - break; - } - } - } - for (size_t i = 0; i < available.size; ++i) { - RimeSchemaListItem& item(available.list[i]); - RimeSchemaInfo* info = (RimeSchemaInfo*)item.reserved; - if (recruited.find(info) == recruited.end()) { - recruited.insert(info); - std::wstring itemwstr = string_to_wstring(item.name, CP_UTF8); - schema_list_.AddItem(k, 0, itemwstr.c_str()); - schema_list_.SetItemData(k, (DWORD_PTR)info); - ++k; - } - } - std::wstring txt = string_to_wstring(api_->get_hotkeys(settings_), CP_UTF8); - hotkeys_.SetWindowTextW(txt.c_str()); - loaded_ = true; - modified_ = false; + if (!settings_) + return; + RimeSchemaList available = {0}; + api_->get_available_schema_list(settings_, &available); + RimeSchemaList selected = {0}; + api_->get_selected_schema_list(settings_, &selected); + schema_list_.DeleteAllItems(); + size_t k = 0; + std::set recruited; + for (size_t i = 0; i < selected.size; ++i) { + const char* schema_id = selected.list[i].schema_id; + for (size_t j = 0; j < available.size; ++j) { + RimeSchemaListItem& item(available.list[j]); + RimeSchemaInfo* info = (RimeSchemaInfo*)item.reserved; + if (!strcmp(item.schema_id, schema_id) && + recruited.find(info) == recruited.end()) { + recruited.insert(info); + std::wstring itemwstr = string_to_wstring(item.name, CP_UTF8); + schema_list_.AddItem(k, 0, itemwstr.c_str()); + schema_list_.SetItemData(k, (DWORD_PTR)info); + schema_list_.SetCheckState(k, TRUE); + ++k; + break; + } + } + } + for (size_t i = 0; i < available.size; ++i) { + RimeSchemaListItem& item(available.list[i]); + RimeSchemaInfo* info = (RimeSchemaInfo*)item.reserved; + if (recruited.find(info) == recruited.end()) { + recruited.insert(info); + std::wstring itemwstr = string_to_wstring(item.name, CP_UTF8); + schema_list_.AddItem(k, 0, itemwstr.c_str()); + schema_list_.SetItemData(k, (DWORD_PTR)info); + ++k; + } + } + std::wstring txt = string_to_wstring(api_->get_hotkeys(settings_), CP_UTF8); + hotkeys_.SetWindowTextW(txt.c_str()); + loaded_ = true; + modified_ = false; } void SwitcherSettingsDialog::ShowDetails(RimeSchemaInfo* info) { - if (!info) return; - std::string details; - if (const char* name = api_->get_schema_name(info)) { - details += name; - } - if (const char* author = api_->get_schema_author(info)) { - (details += "\n\n") += author; - } - if (const char* description = api_->get_schema_description(info)) { - (details += "\n\n") += description; - } - std::wstring txt = string_to_wstring(details.c_str(), CP_UTF8); - description_.SetWindowTextW(txt.c_str()); + if (!info) + return; + std::string details; + if (const char* name = api_->get_schema_name(info)) { + details += name; + } + if (const char* author = api_->get_schema_author(info)) { + (details += "\n\n") += author; + } + if (const char* description = api_->get_schema_description(info)) { + (details += "\n\n") += description; + } + std::wstring txt = string_to_wstring(details.c_str(), CP_UTF8); + description_.SetWindowTextW(txt.c_str()); } LRESULT SwitcherSettingsDialog::OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) { - schema_list_.SubclassWindow(GetDlgItem(IDC_SCHEMA_LIST)); - schema_list_.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); - schema_list_.AddColumn(L"方案名稱", 0); - CRect rc; - schema_list_.GetClientRect(&rc); - schema_list_.SetColumnWidth(0, rc.Width() - 20); + schema_list_.SubclassWindow(GetDlgItem(IDC_SCHEMA_LIST)); + schema_list_.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT, + LVS_EX_FULLROWSELECT); + schema_list_.AddColumn(L"方案名稱", 0); + CRect rc; + schema_list_.GetClientRect(&rc); + schema_list_.SetColumnWidth(0, rc.Width() - 20); - description_.Attach(GetDlgItem(IDC_SCHEMA_DESCRIPTION)); - - hotkeys_.Attach(GetDlgItem(IDC_HOTKEYS)); - hotkeys_.EnableWindow(FALSE); + description_.Attach(GetDlgItem(IDC_SCHEMA_DESCRIPTION)); - get_schemata_.Attach(GetDlgItem(IDC_GET_SCHEMATA)); - get_schemata_.EnableWindow(TRUE); - - Populate(); - - CenterWindow(); - BringWindowToTop(); - return TRUE; + hotkeys_.Attach(GetDlgItem(IDC_HOTKEYS)); + hotkeys_.EnableWindow(FALSE); + + get_schemata_.Attach(GetDlgItem(IDC_GET_SCHEMATA)); + get_schemata_.EnableWindow(TRUE); + + Populate(); + + CenterWindow(); + BringWindowToTop(); + return TRUE; } LRESULT SwitcherSettingsDialog::OnClose(UINT, WPARAM, LPARAM, BOOL&) { - EndDialog(IDCANCEL); - return 0; + EndDialog(IDCANCEL); + return 0; } LRESULT SwitcherSettingsDialog::OnGetSchemata(WORD, WORD, HWND hWndCtl, BOOL&) { - HKEY hKey; - LSTATUS ret = RegOpenKey(HKEY_LOCAL_MACHINE, _T("Software\\Rime\\Weasel"), &hKey); - if (ret == ERROR_SUCCESS) { - WCHAR value[MAX_PATH]; - DWORD len = sizeof(value); - DWORD type = 0; - DWORD data = 0; - ret = RegQueryValueExW(hKey, L"WeaselRoot", NULL, &type, (LPBYTE)value, &len); - if (ret == ERROR_SUCCESS && type == REG_SZ) { - WCHAR parameters[MAX_PATH + 37]; - wcscpy_s<_countof(parameters)>(parameters, (std::wstring(L"/k \"") + value + L"\\rime-install.bat\"").c_str()); - SHELLEXECUTEINFOW cmd = { - sizeof(SHELLEXECUTEINFO), - SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC, - hWndCtl, - L"open", - L"cmd", - parameters, - NULL, - SW_SHOW, - NULL, NULL, NULL, NULL, NULL, NULL, NULL - }; - ShellExecuteExW(&cmd); - WaitForSingleObject(cmd.hProcess, INFINITE); - CloseHandle(cmd.hProcess); - api_->load_settings(reinterpret_cast(settings_)); - Populate(); - } - } - RegCloseKey(hKey); - return 0; + HKEY hKey; + LSTATUS ret = + RegOpenKey(HKEY_LOCAL_MACHINE, _T("Software\\Rime\\Weasel"), &hKey); + if (ret == ERROR_SUCCESS) { + WCHAR value[MAX_PATH]; + DWORD len = sizeof(value); + DWORD type = 0; + DWORD data = 0; + ret = + RegQueryValueExW(hKey, L"WeaselRoot", NULL, &type, (LPBYTE)value, &len); + if (ret == ERROR_SUCCESS && type == REG_SZ) { + WCHAR parameters[MAX_PATH + 37]; + wcscpy_s<_countof(parameters)>( + parameters, + (std::wstring(L"/k \"") + value + L"\\rime-install.bat\"").c_str()); + SHELLEXECUTEINFOW cmd = {sizeof(SHELLEXECUTEINFO), + SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC, + hWndCtl, + L"open", + L"cmd", + parameters, + NULL, + SW_SHOW, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL}; + ShellExecuteExW(&cmd); + WaitForSingleObject(cmd.hProcess, INFINITE); + CloseHandle(cmd.hProcess); + api_->load_settings(reinterpret_cast(settings_)); + Populate(); + } + } + RegCloseKey(hKey); + return 0; } LRESULT SwitcherSettingsDialog::OnOK(WORD, WORD code, HWND, BOOL&) { - if (modified_ && settings_ && schema_list_.GetItemCount() != 0) { - const char** selection = new const char*[schema_list_.GetItemCount()]; - int count = 0; - for (int i = 0; i < schema_list_.GetItemCount(); ++i) { - if (!schema_list_.GetCheckState(i)) - continue; - RimeSchemaInfo* info = (RimeSchemaInfo*)(schema_list_.GetItemData(i)); - if (info) { - selection[count++] = api_->get_schema_id(info); - } - } - if (count == 0) { - //MessageBox(_T("至少要選用一項吧。"), _T("小狼毫不是這般用法"), MB_OK | MB_ICONEXCLAMATION); - MSG_BY_IDS(IDS_STR_ERR_AT_LEAST_ONE_SEL, IDS_STR_NOT_REGULAR, MB_OK | MB_ICONEXCLAMATION); - delete selection; - return 0; - } - api_->select_schemas(settings_, selection, count); - delete selection; - } - EndDialog(code); - return 0; + if (modified_ && settings_ && schema_list_.GetItemCount() != 0) { + const char** selection = new const char*[schema_list_.GetItemCount()]; + int count = 0; + for (int i = 0; i < schema_list_.GetItemCount(); ++i) { + if (!schema_list_.GetCheckState(i)) + continue; + RimeSchemaInfo* info = (RimeSchemaInfo*)(schema_list_.GetItemData(i)); + if (info) { + selection[count++] = api_->get_schema_id(info); + } + } + if (count == 0) { + // MessageBox(_T("至少要選用一項吧。"), _T("小狼毫不是這般用法"), MB_OK | + // MB_ICONEXCLAMATION); + MSG_BY_IDS(IDS_STR_ERR_AT_LEAST_ONE_SEL, IDS_STR_NOT_REGULAR, + MB_OK | MB_ICONEXCLAMATION); + delete selection; + return 0; + } + api_->select_schemas(settings_, selection, count); + delete selection; + } + EndDialog(code); + return 0; } LRESULT SwitcherSettingsDialog::OnSchemaListItemChanged(int, LPNMHDR p, BOOL&) { - LPNMLISTVIEW lv = reinterpret_cast(p); - if (!loaded_ || !lv || lv->iItem < 0 && lv->iItem >= schema_list_.GetItemCount()) - return 0; - if ((lv->uNewState & LVIS_STATEIMAGEMASK) != (lv->uOldState & LVIS_STATEIMAGEMASK)) { - modified_ = true; - } - else if ((lv->uNewState & LVIS_SELECTED) && !(lv->uOldState & LVIS_SELECTED)) { - ShowDetails((RimeSchemaInfo*)(schema_list_.GetItemData(lv->iItem))); - } - return 0; + LPNMLISTVIEW lv = reinterpret_cast(p); + if (!loaded_ || !lv || + lv->iItem < 0 && lv->iItem >= schema_list_.GetItemCount()) + return 0; + if ((lv->uNewState & LVIS_STATEIMAGEMASK) != + (lv->uOldState & LVIS_STATEIMAGEMASK)) { + modified_ = true; + } else if ((lv->uNewState & LVIS_SELECTED) && + !(lv->uOldState & LVIS_SELECTED)) { + ShowDetails((RimeSchemaInfo*)(schema_list_.GetItemData(lv->iItem))); + } + return 0; } diff --git a/WeaselDeployer/SwitcherSettingsDialog.h b/WeaselDeployer/SwitcherSettingsDialog.h index db21f0305..08305c358 100644 --- a/WeaselDeployer/SwitcherSettingsDialog.h +++ b/WeaselDeployer/SwitcherSettingsDialog.h @@ -4,38 +4,37 @@ #include class SwitcherSettingsDialog : public CDialogImpl { -public: - enum { IDD = IDD_SWITCHER_SETTING }; - - SwitcherSettingsDialog(RimeSwitcherSettings* settings); - ~SwitcherSettingsDialog(); - -protected: - BEGIN_MSG_MAP(SwitcherSettingsDialog) - MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) - MESSAGE_HANDLER(WM_CLOSE, OnClose) - COMMAND_HANDLER(IDC_GET_SCHEMATA, BN_CLICKED, OnGetSchemata) - COMMAND_ID_HANDLER(IDOK, OnOK) - NOTIFY_HANDLER(IDC_SCHEMA_LIST, LVN_ITEMCHANGED, OnSchemaListItemChanged) - END_MSG_MAP() - - LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&); - LRESULT OnClose(UINT, WPARAM, LPARAM, BOOL&); - LRESULT OnGetSchemata(WORD, WORD, HWND, BOOL&); - LRESULT OnOK(WORD, WORD, HWND, BOOL&); - LRESULT OnSchemaListItemChanged(int, LPNMHDR, BOOL&); - - void Populate(); - void ShowDetails(RimeSchemaInfo* info); - - RimeLeversApi* api_; - RimeSwitcherSettings* settings_; - bool loaded_; - bool modified_; - - CCheckListViewCtrl schema_list_; - CStatic description_; - CEdit hotkeys_; - CButton get_schemata_; + public: + enum { IDD = IDD_SWITCHER_SETTING }; + + SwitcherSettingsDialog(RimeSwitcherSettings* settings); + ~SwitcherSettingsDialog(); + + protected: + BEGIN_MSG_MAP(SwitcherSettingsDialog) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + MESSAGE_HANDLER(WM_CLOSE, OnClose) + COMMAND_HANDLER(IDC_GET_SCHEMATA, BN_CLICKED, OnGetSchemata) + COMMAND_ID_HANDLER(IDOK, OnOK) + NOTIFY_HANDLER(IDC_SCHEMA_LIST, LVN_ITEMCHANGED, OnSchemaListItemChanged) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&); + LRESULT OnClose(UINT, WPARAM, LPARAM, BOOL&); + LRESULT OnGetSchemata(WORD, WORD, HWND, BOOL&); + LRESULT OnOK(WORD, WORD, HWND, BOOL&); + LRESULT OnSchemaListItemChanged(int, LPNMHDR, BOOL&); + + void Populate(); + void ShowDetails(RimeSchemaInfo* info); + + RimeLeversApi* api_; + RimeSwitcherSettings* settings_; + bool loaded_; + bool modified_; + + CCheckListViewCtrl schema_list_; + CStatic description_; + CEdit hotkeys_; + CButton get_schemata_; }; - diff --git a/WeaselDeployer/UIStyleSettings.cpp b/WeaselDeployer/UIStyleSettings.cpp index 20d093808..bc59ea65a 100644 --- a/WeaselDeployer/UIStyleSettings.cpp +++ b/WeaselDeployer/UIStyleSettings.cpp @@ -2,67 +2,74 @@ #include #include "UIStyleSettings.h" - -UIStyleSettings::UIStyleSettings() -{ - api_ = (RimeLeversApi*)rime_get_api()->find_module("levers")->get_api(); - settings_ = api_->custom_settings_init("weasel", "Weasel::UIStyleSettings"); +UIStyleSettings::UIStyleSettings() { + api_ = (RimeLeversApi*)rime_get_api()->find_module("levers")->get_api(); + settings_ = api_->custom_settings_init("weasel", "Weasel::UIStyleSettings"); } -bool UIStyleSettings::GetPresetColorSchemes(std::vector* result) { - if (!result) return false; - result->clear(); - RimeConfig config = {0}; - api_->settings_get_config(settings_, &config); - RimeApi* rime = rime_get_api(); - RimeConfigIterator preset = {0}; - if (!rime->config_begin_map(&preset, &config, "preset_color_schemes")) { - return false; - } - while (rime->config_next(&preset)) { - std::string name_key(preset.path); - name_key += "/name"; - const char* name = rime->config_get_cstring(&config, name_key.c_str()); - std::string author_key(preset.path); - author_key += "/author"; - const char* author = rime->config_get_cstring(&config, author_key.c_str()); - if (!name) continue; - ColorSchemeInfo info; - info.color_scheme_id = preset.key; - info.name = name; - if (author) info.author = author; - result->push_back(info); - } - return true; +bool UIStyleSettings::GetPresetColorSchemes( + std::vector* result) { + if (!result) + return false; + result->clear(); + RimeConfig config = {0}; + api_->settings_get_config(settings_, &config); + RimeApi* rime = rime_get_api(); + RimeConfigIterator preset = {0}; + if (!rime->config_begin_map(&preset, &config, "preset_color_schemes")) { + return false; + } + while (rime->config_next(&preset)) { + std::string name_key(preset.path); + name_key += "/name"; + const char* name = rime->config_get_cstring(&config, name_key.c_str()); + std::string author_key(preset.path); + author_key += "/author"; + const char* author = rime->config_get_cstring(&config, author_key.c_str()); + if (!name) + continue; + ColorSchemeInfo info; + info.color_scheme_id = preset.key; + info.name = name; + if (author) + info.author = author; + result->push_back(info); + } + return true; } // check if a file exists -static inline bool IfFileExist(std::string filename) -{ - DWORD dwAttrib = GetFileAttributes(string_to_wstring(filename).c_str()); - return (INVALID_FILE_ATTRIBUTES != dwAttrib && 0 == (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); +static inline bool IfFileExist(std::string filename) { + DWORD dwAttrib = GetFileAttributes(string_to_wstring(filename).c_str()); + return (INVALID_FILE_ATTRIBUTES != dwAttrib && + 0 == (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); } // get preview image from user dir first, then shared_dir -std::string UIStyleSettings::GetColorSchemePreview(const std::string& color_scheme_id) { - std::string shared_dir = rime_get_api()->get_shared_data_dir(); - std::string user_dir = rime_get_api()->get_user_data_dir(); - std::string filename = user_dir + "\\preview\\color_scheme_" + color_scheme_id + ".png"; - if (IfFileExist(filename)) - return filename; - else - return (shared_dir + "\\preview\\color_scheme_" + color_scheme_id + ".png"); +std::string UIStyleSettings::GetColorSchemePreview( + const std::string& color_scheme_id) { + std::string shared_dir = rime_get_api()->get_shared_data_dir(); + std::string user_dir = rime_get_api()->get_user_data_dir(); + std::string filename = + user_dir + "\\preview\\color_scheme_" + color_scheme_id + ".png"; + if (IfFileExist(filename)) + return filename; + else + return (shared_dir + "\\preview\\color_scheme_" + color_scheme_id + ".png"); } std::string UIStyleSettings::GetActiveColorScheme() { - RimeConfig config = {0}; - api_->settings_get_config(settings_, &config); - const char* value = rime_get_api()->config_get_cstring(&config, "style/color_scheme"); - if (!value) return std::string(); - return std::string(value); + RimeConfig config = {0}; + api_->settings_get_config(settings_, &config); + const char* value = + rime_get_api()->config_get_cstring(&config, "style/color_scheme"); + if (!value) + return std::string(); + return std::string(value); } bool UIStyleSettings::SelectColorScheme(const std::string& color_scheme_id) { - api_->customize_string(settings_, "style/color_scheme", color_scheme_id.c_str()); - return true; + api_->customize_string(settings_, "style/color_scheme", + color_scheme_id.c_str()); + return true; } diff --git a/WeaselDeployer/UIStyleSettings.h b/WeaselDeployer/UIStyleSettings.h index cdfc4b767..f229eecb3 100644 --- a/WeaselDeployer/UIStyleSettings.h +++ b/WeaselDeployer/UIStyleSettings.h @@ -5,23 +5,23 @@ #include struct ColorSchemeInfo { - std::string color_scheme_id; - std::string name; - std::string author; + std::string color_scheme_id; + std::string name; + std::string author; }; class UIStyleSettings { -public: - UIStyleSettings(); + public: + UIStyleSettings(); - bool GetPresetColorSchemes(std::vector* result); - std::string GetColorSchemePreview(const std::string& color_scheme_id); - std::string GetActiveColorScheme(); - bool SelectColorScheme(const std::string& color_scheme_id); + bool GetPresetColorSchemes(std::vector* result); + std::string GetColorSchemePreview(const std::string& color_scheme_id); + std::string GetActiveColorScheme(); + bool SelectColorScheme(const std::string& color_scheme_id); - RimeCustomSettings* settings() { return settings_; } + RimeCustomSettings* settings() { return settings_; } -private: - RimeLeversApi* api_; - RimeCustomSettings* settings_; + private: + RimeLeversApi* api_; + RimeCustomSettings* settings_; }; diff --git a/WeaselDeployer/UIStyleSettingsDialog.cpp b/WeaselDeployer/UIStyleSettingsDialog.cpp index 03cc01df4..a1f1d9586 100644 --- a/WeaselDeployer/UIStyleSettingsDialog.cpp +++ b/WeaselDeployer/UIStyleSettingsDialog.cpp @@ -4,78 +4,76 @@ #include "Configurator.h" #include - UIStyleSettingsDialog::UIStyleSettingsDialog(UIStyleSettings* settings) - : settings_(settings), loaded_(false) -{ -} - + : settings_(settings), loaded_(false) {} -UIStyleSettingsDialog::~UIStyleSettingsDialog() -{ - image_.Destroy(); +UIStyleSettingsDialog::~UIStyleSettingsDialog() { + image_.Destroy(); } - void UIStyleSettingsDialog::Populate() { - if (!settings_) return; - std::string active(settings_->GetActiveColorScheme()); - int active_index = -1; - settings_->GetPresetColorSchemes(&preset_); - for (size_t i = 0; i < preset_.size(); ++i) { - std::wstring txt = string_to_wstring(preset_[i].name.c_str(), CP_UTF8); - color_schemes_.AddString(txt.c_str()); - if (preset_[i].color_scheme_id == active) { - active_index = i; - } - } - if (active_index >= 0) { - color_schemes_.SetCurSel(active_index); - Preview(active_index); - } - loaded_ = true; + if (!settings_) + return; + std::string active(settings_->GetActiveColorScheme()); + int active_index = -1; + settings_->GetPresetColorSchemes(&preset_); + for (size_t i = 0; i < preset_.size(); ++i) { + std::wstring txt = string_to_wstring(preset_[i].name.c_str(), CP_UTF8); + color_schemes_.AddString(txt.c_str()); + if (preset_[i].color_scheme_id == active) { + active_index = i; + } + } + if (active_index >= 0) { + color_schemes_.SetCurSel(active_index); + Preview(active_index); + } + loaded_ = true; } LRESULT UIStyleSettingsDialog::OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) { - color_schemes_.Attach(GetDlgItem(IDC_COLOR_SCHEME)); - preview_.Attach(GetDlgItem(IDC_PREVIEW)); - select_font_.Attach(GetDlgItem(IDC_SELECT_FONT)); - select_font_.EnableWindow(FALSE); - - Populate(); - - CenterWindow(); - BringWindowToTop(); - return TRUE; + color_schemes_.Attach(GetDlgItem(IDC_COLOR_SCHEME)); + preview_.Attach(GetDlgItem(IDC_PREVIEW)); + select_font_.Attach(GetDlgItem(IDC_SELECT_FONT)); + select_font_.EnableWindow(FALSE); + + Populate(); + + CenterWindow(); + BringWindowToTop(); + return TRUE; } LRESULT UIStyleSettingsDialog::OnClose(UINT, WPARAM, LPARAM, BOOL&) { - EndDialog(IDCANCEL); - return 0; + EndDialog(IDCANCEL); + return 0; } LRESULT UIStyleSettingsDialog::OnOK(WORD, WORD code, HWND, BOOL&) { - EndDialog(code); - return 0; + EndDialog(code); + return 0; } LRESULT UIStyleSettingsDialog::OnColorSchemeSelChange(WORD, WORD, HWND, BOOL&) { - int index = color_schemes_.GetCurSel(); - if (index >= 0 && index < (int)preset_.size()) { - settings_->SelectColorScheme(preset_[index].color_scheme_id); - Preview(index); - } - return 0; + int index = color_schemes_.GetCurSel(); + if (index >= 0 && index < (int)preset_.size()) { + settings_->SelectColorScheme(preset_[index].color_scheme_id); + Preview(index); + } + return 0; } void UIStyleSettingsDialog::Preview(int index) { - if (index < 0 || index >= (int)preset_.size()) return; - const std::string file_path(settings_->GetColorSchemePreview(preset_[index].color_scheme_id)); - if (file_path.empty()) return; - image_.Destroy(); - // it is from ansi coding, not utf8 - image_.Load(string_to_wstring(file_path).c_str()); - if (!image_.IsNull()) { - preview_.SetBitmap(image_); - } + if (index < 0 || index >= (int)preset_.size()) + return; + const std::string file_path( + settings_->GetColorSchemePreview(preset_[index].color_scheme_id)); + if (file_path.empty()) + return; + image_.Destroy(); + // it is from ansi coding, not utf8 + image_.Load(string_to_wstring(file_path).c_str()); + if (!image_.IsNull()) { + preview_.SetBitmap(image_); + } } diff --git a/WeaselDeployer/UIStyleSettingsDialog.h b/WeaselDeployer/UIStyleSettingsDialog.h index 167753646..e81aad77b 100644 --- a/WeaselDeployer/UIStyleSettingsDialog.h +++ b/WeaselDeployer/UIStyleSettingsDialog.h @@ -3,37 +3,35 @@ #include "resource.h" #include "UIStyleSettings.h" - class UIStyleSettingsDialog : public CDialogImpl { -public: - enum { IDD = IDD_STYLE_SETTING }; - - UIStyleSettingsDialog(UIStyleSettings* settings); - ~UIStyleSettingsDialog(); - -protected: - BEGIN_MSG_MAP(UIStyleSettingsDialog) - MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) - MESSAGE_HANDLER(WM_CLOSE, OnClose) - COMMAND_ID_HANDLER(IDOK, OnOK) - COMMAND_HANDLER(IDC_COLOR_SCHEME, LBN_SELCHANGE, OnColorSchemeSelChange) - END_MSG_MAP() - - LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&); - LRESULT OnClose(UINT, WPARAM, LPARAM, BOOL&); - LRESULT OnOK(WORD, WORD code, HWND, BOOL&); - LRESULT OnColorSchemeSelChange(WORD, WORD, HWND, BOOL&); - - void Populate(); - void Preview(int index); - - UIStyleSettings* settings_; - bool loaded_; - std::vector preset_; - - CListBox color_schemes_; - CStatic preview_; - CImage image_; - CButton select_font_; + public: + enum { IDD = IDD_STYLE_SETTING }; + + UIStyleSettingsDialog(UIStyleSettings* settings); + ~UIStyleSettingsDialog(); + + protected: + BEGIN_MSG_MAP(UIStyleSettingsDialog) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + MESSAGE_HANDLER(WM_CLOSE, OnClose) + COMMAND_ID_HANDLER(IDOK, OnOK) + COMMAND_HANDLER(IDC_COLOR_SCHEME, LBN_SELCHANGE, OnColorSchemeSelChange) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&); + LRESULT OnClose(UINT, WPARAM, LPARAM, BOOL&); + LRESULT OnOK(WORD, WORD code, HWND, BOOL&); + LRESULT OnColorSchemeSelChange(WORD, WORD, HWND, BOOL&); + + void Populate(); + void Preview(int index); + + UIStyleSettings* settings_; + bool loaded_; + std::vector preset_; + + CListBox color_schemes_; + CStatic preview_; + CImage image_; + CButton select_font_; }; - diff --git a/WeaselDeployer/WeaselDeployer.cpp b/WeaselDeployer/WeaselDeployer.cpp index 752cb5311..9c68fb011 100644 --- a/WeaselDeployer/WeaselDeployer.cpp +++ b/WeaselDeployer/WeaselDeployer.cpp @@ -11,85 +11,78 @@ CAppModule _Module; static int Run(LPTSTR lpCmdLine); int APIENTRY _tWinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPTSTR lpCmdLine, - int nCmdShow) -{ - UNREFERENCED_PARAMETER(hPrevInstance); - - LCID lcid = GetUserDefaultLCID(); - if (lcid == 2052 || lcid == 3072 || lcid == 4100) { - LANGID langId = SetThreadUILanguage(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)); - SetThreadLocale(langId); - } - else { - LANGID langId = SetThreadUILanguage(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)); - SetThreadLocale(langId); - } - - HRESULT hRes = ::CoInitialize(NULL); - // If you are running on NT 4.0 or higher you can use the following call instead to - // make the EXE free threaded. This means that calls come in on a random RPC thread. - //HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); - ATLASSERT(SUCCEEDED(hRes)); - - // this resolves ATL window thunking problem when Microsoft Layer for Unicode (MSLU) is used - ::DefWindowProc(NULL, 0, 0, 0L); - - AtlInitCommonControls(ICC_BAR_CLASSES); // add flags to support other controls - - hRes = _Module.Init(NULL, hInstance); - ATLASSERT(SUCCEEDED(hRes)); - - CreateDirectory(WeaselUserDataPath().c_str(), NULL); - - int ret = 0; - HANDLE hMutex = CreateMutex(NULL, TRUE, L"WeaselDeployerExclusiveMutex"); - if (!hMutex) - { - ret = 1; - } - else if (GetLastError() == ERROR_ALREADY_EXISTS) - { - ret = 1; - } - else - { - ret = Run(lpCmdLine); - } - - if (hMutex) - { - CloseHandle(hMutex); - } - _Module.Term(); - ::CoUninitialize(); - - return ret; + HINSTANCE hPrevInstance, + LPTSTR lpCmdLine, + int nCmdShow) { + UNREFERENCED_PARAMETER(hPrevInstance); + + LCID lcid = GetUserDefaultLCID(); + if (lcid == 2052 || lcid == 3072 || lcid == 4100) { + LANGID langId = SetThreadUILanguage( + MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)); + SetThreadLocale(langId); + } else { + LANGID langId = SetThreadUILanguage( + MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)); + SetThreadLocale(langId); + } + + HRESULT hRes = ::CoInitialize(NULL); + // If you are running on NT 4.0 or higher you can use the following call + // instead to make the EXE free threaded. This means that calls come in on a + // random RPC thread. + // HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); + ATLASSERT(SUCCEEDED(hRes)); + + // this resolves ATL window thunking problem when Microsoft Layer for Unicode + // (MSLU) is used + ::DefWindowProc(NULL, 0, 0, 0L); + + AtlInitCommonControls( + ICC_BAR_CLASSES); // add flags to support other controls + + hRes = _Module.Init(NULL, hInstance); + ATLASSERT(SUCCEEDED(hRes)); + + CreateDirectory(WeaselUserDataPath().c_str(), NULL); + + int ret = 0; + HANDLE hMutex = CreateMutex(NULL, TRUE, L"WeaselDeployerExclusiveMutex"); + if (!hMutex) { + ret = 1; + } else if (GetLastError() == ERROR_ALREADY_EXISTS) { + ret = 1; + } else { + ret = Run(lpCmdLine); + } + + if (hMutex) { + CloseHandle(hMutex); + } + _Module.Term(); + ::CoUninitialize(); + + return ret; } -static int Run(LPTSTR lpCmdLine) -{ - Configurator configurator; - configurator.Initialize(); - bool deployment_scheduled = !wcscmp(L"/deploy", lpCmdLine); - if (deployment_scheduled) - { - return configurator.UpdateWorkspace(); - } - - bool dict_management = !wcscmp(L"/dict", lpCmdLine); - if (dict_management) - { - return configurator.DictManagement(); - } - - bool sync_user_dict = !wcscmp(L"/sync", lpCmdLine); - if (sync_user_dict) - { - return configurator.SyncUserData(); - } - - bool installing = !wcscmp(L"/install", lpCmdLine); - return configurator.Run(installing); +static int Run(LPTSTR lpCmdLine) { + Configurator configurator; + configurator.Initialize(); + bool deployment_scheduled = !wcscmp(L"/deploy", lpCmdLine); + if (deployment_scheduled) { + return configurator.UpdateWorkspace(); + } + + bool dict_management = !wcscmp(L"/dict", lpCmdLine); + if (dict_management) { + return configurator.DictManagement(); + } + + bool sync_user_dict = !wcscmp(L"/sync", lpCmdLine); + if (sync_user_dict) { + return configurator.SyncUserData(); + } + + bool installing = !wcscmp(L"/install", lpCmdLine); + return configurator.Run(installing); } \ No newline at end of file diff --git a/WeaselDeployer/WeaselDeployer.h b/WeaselDeployer/WeaselDeployer.h index 1f3b60d8c..5707c666e 100644 --- a/WeaselDeployer/WeaselDeployer.h +++ b/WeaselDeployer/WeaselDeployer.h @@ -6,20 +6,19 @@ #include #include "resource.h" -#define MSG_BY_IDS(idInfo, idCap, uType) \ - {\ - CString info, cap;\ - info.LoadStringW(idInfo);\ - cap.LoadStringW(idCap);\ - LANGID langID = GetThreadUILanguage();\ - MessageBoxExW(NULL, info, cap, uType, langID);\ - } - -#define MSG_ID_CAP(info, idCap, uType) \ - {\ - CString cap;\ - cap.LoadStringW(idCap);\ - LANGID langID = GetThreadUILanguage();\ - MessageBoxExW(NULL, info, cap, uType, langID);\ - } +#define MSG_BY_IDS(idInfo, idCap, uType) \ + { \ + CString info, cap; \ + info.LoadStringW(idInfo); \ + cap.LoadStringW(idCap); \ + LANGID langID = GetThreadUILanguage(); \ + MessageBoxExW(NULL, info, cap, uType, langID); \ + } +#define MSG_ID_CAP(info, idCap, uType) \ + { \ + CString cap; \ + cap.LoadStringW(idCap); \ + LANGID langID = GetThreadUILanguage(); \ + MessageBoxExW(NULL, info, cap, uType, langID); \ + } diff --git a/WeaselIME/KeyEvent.cpp b/WeaselIME/KeyEvent.cpp index c30cb38ae..a73d5d773 100644 --- a/WeaselIME/KeyEvent.cpp +++ b/WeaselIME/KeyEvent.cpp @@ -1,200 +1,267 @@ #include "stdafx.h" #include "KeyEvent.h" +bool ConvertKeyEvent(UINT vkey, + KeyInfo kinfo, + const LPBYTE keyState, + weasel::KeyEvent& result) { + const BYTE KEY_DOWN = 0x80; + const BYTE TOGGLED = 0x01; + ibus::Keycode TranslateKeycode(UINT vkey, KeyInfo kinfo); -bool ConvertKeyEvent(UINT vkey, KeyInfo kinfo, const LPBYTE keyState, weasel::KeyEvent& result) -{ - const BYTE KEY_DOWN = 0x80; - const BYTE TOGGLED = 0x01; - ibus::Keycode TranslateKeycode(UINT vkey, KeyInfo kinfo); - - // set mask - result.mask = ibus::NULL_MASK; - - if ((keyState[VK_SHIFT] & KEY_DOWN) != 0) - result.mask |= ibus::SHIFT_MASK; - - if ((keyState[VK_CAPITAL] & TOGGLED) != 0) - result.mask |= ibus::LOCK_MASK; - - if ((keyState[VK_CONTROL] & KEY_DOWN) != 0) - result.mask |= ibus::CONTROL_MASK; - - if ((keyState[VK_MENU] & KEY_DOWN) != 0) - result.mask |= ibus::ALT_MASK; - - if (kinfo.isKeyUp) - result.mask |= ibus::RELEASE_MASK; - - if (vkey == VK_CAPITAL && !kinfo.isKeyUp) - { - // NOTE: rime assumes XK_Caps_Lock to be sent before modifier changes, - // while VK_CAPITAL has the modifier changed already. - // so it is necessary to revert LOCK_MASK. - result.mask ^= ibus::LOCK_MASK; - } - - // set keycode - ibus::Keycode code = TranslateKeycode(vkey, kinfo); - if (code) - { - result.keycode = code; - return true; - } - - const int buf_len = 8; - static WCHAR buf[buf_len]; - static BYTE table[256]; - // 清除Ctrl、Alt鍵狀態,以令ToUnicodeEx()返回字符 - memcpy(table, keyState, sizeof(table)); - table[VK_CONTROL] = 0; - table[VK_MENU] = 0; - int ret = ToUnicodeEx(vkey, UINT(kinfo), table, buf, buf_len, 0, NULL); - if (ret == 1) - { - result.keycode = UINT(buf[0]); - return true; - } - - result.keycode = 0; - return false; + // set mask + result.mask = ibus::NULL_MASK; + + if ((keyState[VK_SHIFT] & KEY_DOWN) != 0) + result.mask |= ibus::SHIFT_MASK; + + if ((keyState[VK_CAPITAL] & TOGGLED) != 0) + result.mask |= ibus::LOCK_MASK; + + if ((keyState[VK_CONTROL] & KEY_DOWN) != 0) + result.mask |= ibus::CONTROL_MASK; + + if ((keyState[VK_MENU] & KEY_DOWN) != 0) + result.mask |= ibus::ALT_MASK; + + if (kinfo.isKeyUp) + result.mask |= ibus::RELEASE_MASK; + + if (vkey == VK_CAPITAL && !kinfo.isKeyUp) { + // NOTE: rime assumes XK_Caps_Lock to be sent before modifier changes, + // while VK_CAPITAL has the modifier changed already. + // so it is necessary to revert LOCK_MASK. + result.mask ^= ibus::LOCK_MASK; + } + + // set keycode + ibus::Keycode code = TranslateKeycode(vkey, kinfo); + if (code) { + result.keycode = code; + return true; + } + + const int buf_len = 8; + static WCHAR buf[buf_len]; + static BYTE table[256]; + // 清除Ctrl、Alt鍵狀態,以令ToUnicodeEx()返回字符 + memcpy(table, keyState, sizeof(table)); + table[VK_CONTROL] = 0; + table[VK_MENU] = 0; + int ret = ToUnicodeEx(vkey, UINT(kinfo), table, buf, buf_len, 0, NULL); + if (ret == 1) { + result.keycode = UINT(buf[0]); + return true; + } + + result.keycode = 0; + return false; } -ibus::Keycode TranslateKeycode(UINT vkey, KeyInfo kinfo) -{ - switch (vkey) - { - case VK_BACK: return ibus::BackSpace; - case VK_TAB: return ibus::Tab; - case VK_CLEAR: return ibus::Clear; - case VK_RETURN: - { - if (kinfo.isExtended == 1) - return ibus::KP_Enter; - else - return ibus::Return; - } - case VK_SHIFT: - { - if (kinfo.scanCode == 0x36) - return ibus::Shift_R; - else - return ibus::Shift_L; - } - case VK_CONTROL: - { - if (kinfo.isExtended == 1) - return ibus::Control_R; - else - return ibus::Control_L; - } - case VK_MENU: return ibus::Alt_L; - case VK_PAUSE: return ibus::Pause; - case VK_CAPITAL: return ibus::Caps_Lock; - - case VK_KANA: return ibus::Hiragana_Katakana; - //case VK_JUNJA: return 0; - //case VK_FINAL: return 0; - case VK_KANJI: return ibus::Kanji; - - case VK_ESCAPE: return ibus::Escape; - - //case VK_CONVERT: return 0; - //case VK_NONCONVERT: return 0; - //case VK_ACCEPT: return 0; - //case VK_MODECHANGE: return 0; - - case VK_SPACE: return ibus::space; - case VK_PRIOR: return ibus::Prior; - case VK_NEXT: return ibus::Next; - case VK_END: return ibus::End; - case VK_HOME: return ibus::Home; - case VK_LEFT: return ibus::Left; - case VK_UP: return ibus::Up; - case VK_RIGHT: return ibus::Right; - case VK_DOWN: return ibus::Down; - case VK_SELECT: return ibus::Select; - case VK_PRINT: return ibus::Print; - case VK_EXECUTE: return ibus::Execute; - //case VK_SNAPSHOT: return 0; - case VK_INSERT: return ibus::Insert; - case VK_DELETE: return ibus::Delete; - case VK_HELP: return ibus::Help; - - case VK_LWIN: return ibus::Meta_L; - case VK_RWIN: return ibus::Meta_R; - //case VK_APPS: return 0; - //case VK_SLEEP: return 0; - case VK_NUMPAD0: return ibus::KP_0; - case VK_NUMPAD1: return ibus::KP_1; - case VK_NUMPAD2: return ibus::KP_2; - case VK_NUMPAD3: return ibus::KP_3; - case VK_NUMPAD4: return ibus::KP_4; - case VK_NUMPAD5: return ibus::KP_5; - case VK_NUMPAD6: return ibus::KP_6; - case VK_NUMPAD7: return ibus::KP_7; - case VK_NUMPAD8: return ibus::KP_8; - case VK_NUMPAD9: return ibus::KP_9; - case VK_MULTIPLY: return ibus::KP_Multiply; - case VK_ADD: return ibus::KP_Add; - case VK_SEPARATOR: return ibus::KP_Separator; - case VK_SUBTRACT: return ibus::KP_Subtract; - case VK_DECIMAL: return ibus::KP_Decimal; - case VK_DIVIDE: return ibus::KP_Divide; - case VK_F1: return ibus::F1; - case VK_F2: return ibus::F2; - case VK_F3: return ibus::F3; - case VK_F4: return ibus::F4; - case VK_F5: return ibus::F5; - case VK_F6: return ibus::F6; - case VK_F7: return ibus::F7; - case VK_F8: return ibus::F8; - case VK_F9: return ibus::F9; - case VK_F10: return ibus::F10; - case VK_F11: return ibus::F11; - case VK_F12: return ibus::F12; - case VK_F13: return ibus::F13; - case VK_F14: return ibus::F14; - case VK_F15: return ibus::F15; - case VK_F16: return ibus::F16; - case VK_F17: return ibus::F17; - case VK_F18: return ibus::F18; - case VK_F19: return ibus::F19; - case VK_F20: return ibus::F20; - case VK_F21: return ibus::F21; - case VK_F22: return ibus::F22; - case VK_F23: return ibus::F23; - case VK_F24: return ibus::F24; - - case VK_NUMLOCK: return ibus::Num_Lock; - case VK_SCROLL: return ibus::Scroll_Lock; - - case VK_LSHIFT: return ibus::Shift_L; - case VK_RSHIFT: return ibus::Shift_R; - case VK_LCONTROL: return ibus::Control_L; - case VK_RCONTROL: return ibus::Control_R; - case VK_LMENU: return ibus::Alt_L; - case VK_RMENU: return ibus::Alt_R; - } - return ibus::Null; +ibus::Keycode TranslateKeycode(UINT vkey, KeyInfo kinfo) { + switch (vkey) { + case VK_BACK: + return ibus::BackSpace; + case VK_TAB: + return ibus::Tab; + case VK_CLEAR: + return ibus::Clear; + case VK_RETURN: { + if (kinfo.isExtended == 1) + return ibus::KP_Enter; + else + return ibus::Return; + } + case VK_SHIFT: { + if (kinfo.scanCode == 0x36) + return ibus::Shift_R; + else + return ibus::Shift_L; + } + case VK_CONTROL: { + if (kinfo.isExtended == 1) + return ibus::Control_R; + else + return ibus::Control_L; + } + case VK_MENU: + return ibus::Alt_L; + case VK_PAUSE: + return ibus::Pause; + case VK_CAPITAL: + return ibus::Caps_Lock; + + case VK_KANA: + return ibus::Hiragana_Katakana; + // case VK_JUNJA: return 0; + // case VK_FINAL: return 0; + case VK_KANJI: + return ibus::Kanji; + + case VK_ESCAPE: + return ibus::Escape; + + // case VK_CONVERT: return 0; + // case VK_NONCONVERT: return 0; + // case VK_ACCEPT: return 0; + // case VK_MODECHANGE: return 0; + + case VK_SPACE: + return ibus::space; + case VK_PRIOR: + return ibus::Prior; + case VK_NEXT: + return ibus::Next; + case VK_END: + return ibus::End; + case VK_HOME: + return ibus::Home; + case VK_LEFT: + return ibus::Left; + case VK_UP: + return ibus::Up; + case VK_RIGHT: + return ibus::Right; + case VK_DOWN: + return ibus::Down; + case VK_SELECT: + return ibus::Select; + case VK_PRINT: + return ibus::Print; + case VK_EXECUTE: + return ibus::Execute; + // case VK_SNAPSHOT: return 0; + case VK_INSERT: + return ibus::Insert; + case VK_DELETE: + return ibus::Delete; + case VK_HELP: + return ibus::Help; + + case VK_LWIN: + return ibus::Meta_L; + case VK_RWIN: + return ibus::Meta_R; + // case VK_APPS: return 0; + // case VK_SLEEP: return 0; + case VK_NUMPAD0: + return ibus::KP_0; + case VK_NUMPAD1: + return ibus::KP_1; + case VK_NUMPAD2: + return ibus::KP_2; + case VK_NUMPAD3: + return ibus::KP_3; + case VK_NUMPAD4: + return ibus::KP_4; + case VK_NUMPAD5: + return ibus::KP_5; + case VK_NUMPAD6: + return ibus::KP_6; + case VK_NUMPAD7: + return ibus::KP_7; + case VK_NUMPAD8: + return ibus::KP_8; + case VK_NUMPAD9: + return ibus::KP_9; + case VK_MULTIPLY: + return ibus::KP_Multiply; + case VK_ADD: + return ibus::KP_Add; + case VK_SEPARATOR: + return ibus::KP_Separator; + case VK_SUBTRACT: + return ibus::KP_Subtract; + case VK_DECIMAL: + return ibus::KP_Decimal; + case VK_DIVIDE: + return ibus::KP_Divide; + case VK_F1: + return ibus::F1; + case VK_F2: + return ibus::F2; + case VK_F3: + return ibus::F3; + case VK_F4: + return ibus::F4; + case VK_F5: + return ibus::F5; + case VK_F6: + return ibus::F6; + case VK_F7: + return ibus::F7; + case VK_F8: + return ibus::F8; + case VK_F9: + return ibus::F9; + case VK_F10: + return ibus::F10; + case VK_F11: + return ibus::F11; + case VK_F12: + return ibus::F12; + case VK_F13: + return ibus::F13; + case VK_F14: + return ibus::F14; + case VK_F15: + return ibus::F15; + case VK_F16: + return ibus::F16; + case VK_F17: + return ibus::F17; + case VK_F18: + return ibus::F18; + case VK_F19: + return ibus::F19; + case VK_F20: + return ibus::F20; + case VK_F21: + return ibus::F21; + case VK_F22: + return ibus::F22; + case VK_F23: + return ibus::F23; + case VK_F24: + return ibus::F24; + + case VK_NUMLOCK: + return ibus::Num_Lock; + case VK_SCROLL: + return ibus::Scroll_Lock; + + case VK_LSHIFT: + return ibus::Shift_L; + case VK_RSHIFT: + return ibus::Shift_R; + case VK_LCONTROL: + return ibus::Control_L; + case VK_RCONTROL: + return ibus::Control_R; + case VK_LMENU: + return ibus::Alt_L; + case VK_RMENU: + return ibus::Alt_R; + } + return ibus::Null; } /* struct ModifierNameTableEntry { - LPCTSTR name; - ibus::Modifier modifier; + LPCTSTR name; + ibus::Modifier modifier; }; ModifierNameTableEntry MODIFIER_NAME_TABLE[] = { - { L"Shift", ibus::SHIFT_MASK }, - { L"CapsLock", ibus::LOCK_MASK }, - { L"Ctrl", ibus::CONTROL_MASK }, - { L"Alt", ibus::MOD1_MASK }, - { L"SUPER", ibus::SUPER_MASK }, - { L"Hyper", ibus::HYPER_MASK }, - { L"Meta", ibus::META_MASK }, - { L"Release", ibus::RELEASE_MASK }, - { NULL, ibus::NULL_MASK } + { L"Shift", ibus::SHIFT_MASK }, + { L"CapsLock", ibus::LOCK_MASK }, + { L"Ctrl", ibus::CONTROL_MASK }, + { L"Alt", ibus::MOD1_MASK }, + { L"SUPER", ibus::SUPER_MASK }, + { L"Hyper", ibus::HYPER_MASK }, + { L"Meta", ibus::META_MASK }, + { L"Release", ibus::RELEASE_MASK }, + { NULL, ibus::NULL_MASK } }; */ diff --git a/WeaselIME/KeyEvent.h b/WeaselIME/KeyEvent.h index 9e0386b0f..ac833e1ee 100644 --- a/WeaselIME/KeyEvent.h +++ b/WeaselIME/KeyEvent.h @@ -1,240 +1,232 @@ #pragma once #include -struct KeyInfo -{ - UINT repeatCount: 16; - UINT scanCode: 8; - UINT isExtended: 1; - UINT reserved: 4; - UINT contextCode: 1; - UINT prevKeyState: 1; - UINT isKeyUp: 1; +struct KeyInfo { + UINT repeatCount : 16; + UINT scanCode : 8; + UINT isExtended : 1; + UINT reserved : 4; + UINT contextCode : 1; + UINT prevKeyState : 1; + UINT isKeyUp : 1; - KeyInfo(LPARAM lparam) - { - *this = *reinterpret_cast(&lparam); - } + KeyInfo(LPARAM lparam) { *this = *reinterpret_cast(&lparam); } - operator UINT32() - { - return *reinterpret_cast(this); - } + operator UINT32() { return *reinterpret_cast(this); } }; -bool ConvertKeyEvent(UINT vkey, KeyInfo kinfo, const LPBYTE keyState, weasel::KeyEvent& result); +bool ConvertKeyEvent(UINT vkey, + KeyInfo kinfo, + const LPBYTE keyState, + weasel::KeyEvent& result); +namespace ibus { +// keycodes -namespace ibus -{ - // keycodes - - enum Keycode - { - VoidSymbol = 0xFFFFFF, - space = 0x020, - grave = 0x060, - BackSpace = 0xFF08, - Tab = 0xFF09, - Linefeed = 0xFF0A, - Clear = 0xFF0B, - Return = 0xFF0D, - Pause = 0xFF13, - Scroll_Lock = 0xFF14, - Sys_Req = 0xFF15, - Escape = 0xFF1B, - Delete = 0xFFFF, - Multi_key = 0xFF20, - Codeinput = 0xFF37, - SingleCandidate = 0xFF3C, - MultipleCandidate = 0xFF3D, - PreviousCandidate = 0xFF3E, - Kanji = 0xFF21, - Muhenkan = 0xFF22, - Henkan_Mode = 0xFF23, - Henkan = 0xFF23, - Romaji = 0xFF24, - Hiragana = 0xFF25, - Katakana = 0xFF26, - Hiragana_Katakana = 0xFF27, - Zenkaku = 0xFF28, - Hankaku = 0xFF29, - Zenkaku_Hankaku = 0xFF2A, - Touroku = 0xFF2B, - Massyo = 0xFF2C, - Kana_Lock = 0xFF2D, - Kana_Shift = 0xFF2E, - Eisu_Shift = 0xFF2F, - Eisu_toggle = 0xFF30, - Kanji_Bangou = 0xFF37, - Zen_Koho = 0xFF3D, - Mae_Koho = 0xFF3E, - Home = 0xFF50, - Left = 0xFF51, - Up = 0xFF52, - Right = 0xFF53, - Down = 0xFF54, - Prior = 0xFF55, - Page_Up = 0xFF55, - Next = 0xFF56, - Page_Down = 0xFF56, - End = 0xFF57, - Begin = 0xFF58, - Select = 0xFF60, - Print = 0xFF61, - Execute = 0xFF62, - Insert = 0xFF63, - Undo = 0xFF65, - Redo = 0xFF66, - Menu = 0xFF67, - Find = 0xFF68, - Cancel = 0xFF69, - Help = 0xFF6A, - Break = 0xFF6B, - Mode_switch = 0xFF7E, - script_switch = 0xFF7E, - Num_Lock = 0xFF7F, - KP_Space = 0xFF80, - KP_Tab = 0xFF89, - KP_Enter = 0xFF8D, - KP_F1 = 0xFF91, - KP_F2 = 0xFF92, - KP_F3 = 0xFF93, - KP_F4 = 0xFF94, - KP_Home = 0xFF95, - KP_Left = 0xFF96, - KP_Up = 0xFF97, - KP_Right = 0xFF98, - KP_Down = 0xFF99, - KP_Prior = 0xFF9A, - KP_Page_Up = 0xFF9A, - KP_Next = 0xFF9B, - KP_Page_Down = 0xFF9B, - KP_End = 0xFF9C, - KP_Begin = 0xFF9D, - KP_Insert = 0xFF9E, - KP_Delete = 0xFF9F, - KP_Equal = 0xFFBD, - KP_Multiply = 0xFFAA, - KP_Add = 0xFFAB, - KP_Separator = 0xFFAC, - KP_Subtract = 0xFFAD, - KP_Decimal = 0xFFAE, - KP_Divide = 0xFFAF, - KP_0 = 0xFFB0, - KP_1 = 0xFFB1, - KP_2 = 0xFFB2, - KP_3 = 0xFFB3, - KP_4 = 0xFFB4, - KP_5 = 0xFFB5, - KP_6 = 0xFFB6, - KP_7 = 0xFFB7, - KP_8 = 0xFFB8, - KP_9 = 0xFFB9, - F1 = 0xFFBE, - F2 = 0xFFBF, - F3 = 0xFFC0, - F4 = 0xFFC1, - F5 = 0xFFC2, - F6 = 0xFFC3, - F7 = 0xFFC4, - F8 = 0xFFC5, - F9 = 0xFFC6, - F10 = 0xFFC7, - F11 = 0xFFC8, - L1 = 0xFFC8, - F12 = 0xFFC9, - L2 = 0xFFC9, - F13 = 0xFFCA, - L3 = 0xFFCA, - F14 = 0xFFCB, - L4 = 0xFFCB, - F15 = 0xFFCC, - L5 = 0xFFCC, - F16 = 0xFFCD, - L6 = 0xFFCD, - F17 = 0xFFCE, - L7 = 0xFFCE, - F18 = 0xFFCF, - L8 = 0xFFCF, - F19 = 0xFFD0, - L9 = 0xFFD0, - F20 = 0xFFD1, - L10 = 0xFFD1, - F21 = 0xFFD2, - R1 = 0xFFD2, - F22 = 0xFFD3, - R2 = 0xFFD3, - F23 = 0xFFD4, - R3 = 0xFFD4, - F24 = 0xFFD5, - R4 = 0xFFD5, - F25 = 0xFFD6, - R5 = 0xFFD6, - F26 = 0xFFD7, - R6 = 0xFFD7, - F27 = 0xFFD8, - R7 = 0xFFD8, - F28 = 0xFFD9, - R8 = 0xFFD9, - F29 = 0xFFDA, - R9 = 0xFFDA, - F30 = 0xFFDB, - R10 = 0xFFDB, - F31 = 0xFFDC, - R11 = 0xFFDC, - F32 = 0xFFDD, - R12 = 0xFFDD, - F33 = 0xFFDE, - R13 = 0xFFDE, - F34 = 0xFFDF, - R14 = 0xFFDF, - F35 = 0xFFE0, - R15 = 0xFFE0, - Shift_L = 0xFFE1, - Shift_R = 0xFFE2, - Control_L = 0xFFE3, - Control_R = 0xFFE4, - Caps_Lock = 0xFFE5, - Shift_Lock = 0xFFE6, - Meta_L = 0xFFE7, - Meta_R = 0xFFE8, - Alt_L = 0xFFE9, - Alt_R = 0xFFEA, - Super_L = 0xFFEB, - Super_R = 0xFFEC, - Hyper_L = 0xFFED, - Hyper_R = 0xFFEE, - Null = 0 - }; +enum Keycode { + VoidSymbol = 0xFFFFFF, + space = 0x020, + grave = 0x060, + BackSpace = 0xFF08, + Tab = 0xFF09, + Linefeed = 0xFF0A, + Clear = 0xFF0B, + Return = 0xFF0D, + Pause = 0xFF13, + Scroll_Lock = 0xFF14, + Sys_Req = 0xFF15, + Escape = 0xFF1B, + Delete = 0xFFFF, + Multi_key = 0xFF20, + Codeinput = 0xFF37, + SingleCandidate = 0xFF3C, + MultipleCandidate = 0xFF3D, + PreviousCandidate = 0xFF3E, + Kanji = 0xFF21, + Muhenkan = 0xFF22, + Henkan_Mode = 0xFF23, + Henkan = 0xFF23, + Romaji = 0xFF24, + Hiragana = 0xFF25, + Katakana = 0xFF26, + Hiragana_Katakana = 0xFF27, + Zenkaku = 0xFF28, + Hankaku = 0xFF29, + Zenkaku_Hankaku = 0xFF2A, + Touroku = 0xFF2B, + Massyo = 0xFF2C, + Kana_Lock = 0xFF2D, + Kana_Shift = 0xFF2E, + Eisu_Shift = 0xFF2F, + Eisu_toggle = 0xFF30, + Kanji_Bangou = 0xFF37, + Zen_Koho = 0xFF3D, + Mae_Koho = 0xFF3E, + Home = 0xFF50, + Left = 0xFF51, + Up = 0xFF52, + Right = 0xFF53, + Down = 0xFF54, + Prior = 0xFF55, + Page_Up = 0xFF55, + Next = 0xFF56, + Page_Down = 0xFF56, + End = 0xFF57, + Begin = 0xFF58, + Select = 0xFF60, + Print = 0xFF61, + Execute = 0xFF62, + Insert = 0xFF63, + Undo = 0xFF65, + Redo = 0xFF66, + Menu = 0xFF67, + Find = 0xFF68, + Cancel = 0xFF69, + Help = 0xFF6A, + Break = 0xFF6B, + Mode_switch = 0xFF7E, + script_switch = 0xFF7E, + Num_Lock = 0xFF7F, + KP_Space = 0xFF80, + KP_Tab = 0xFF89, + KP_Enter = 0xFF8D, + KP_F1 = 0xFF91, + KP_F2 = 0xFF92, + KP_F3 = 0xFF93, + KP_F4 = 0xFF94, + KP_Home = 0xFF95, + KP_Left = 0xFF96, + KP_Up = 0xFF97, + KP_Right = 0xFF98, + KP_Down = 0xFF99, + KP_Prior = 0xFF9A, + KP_Page_Up = 0xFF9A, + KP_Next = 0xFF9B, + KP_Page_Down = 0xFF9B, + KP_End = 0xFF9C, + KP_Begin = 0xFF9D, + KP_Insert = 0xFF9E, + KP_Delete = 0xFF9F, + KP_Equal = 0xFFBD, + KP_Multiply = 0xFFAA, + KP_Add = 0xFFAB, + KP_Separator = 0xFFAC, + KP_Subtract = 0xFFAD, + KP_Decimal = 0xFFAE, + KP_Divide = 0xFFAF, + KP_0 = 0xFFB0, + KP_1 = 0xFFB1, + KP_2 = 0xFFB2, + KP_3 = 0xFFB3, + KP_4 = 0xFFB4, + KP_5 = 0xFFB5, + KP_6 = 0xFFB6, + KP_7 = 0xFFB7, + KP_8 = 0xFFB8, + KP_9 = 0xFFB9, + F1 = 0xFFBE, + F2 = 0xFFBF, + F3 = 0xFFC0, + F4 = 0xFFC1, + F5 = 0xFFC2, + F6 = 0xFFC3, + F7 = 0xFFC4, + F8 = 0xFFC5, + F9 = 0xFFC6, + F10 = 0xFFC7, + F11 = 0xFFC8, + L1 = 0xFFC8, + F12 = 0xFFC9, + L2 = 0xFFC9, + F13 = 0xFFCA, + L3 = 0xFFCA, + F14 = 0xFFCB, + L4 = 0xFFCB, + F15 = 0xFFCC, + L5 = 0xFFCC, + F16 = 0xFFCD, + L6 = 0xFFCD, + F17 = 0xFFCE, + L7 = 0xFFCE, + F18 = 0xFFCF, + L8 = 0xFFCF, + F19 = 0xFFD0, + L9 = 0xFFD0, + F20 = 0xFFD1, + L10 = 0xFFD1, + F21 = 0xFFD2, + R1 = 0xFFD2, + F22 = 0xFFD3, + R2 = 0xFFD3, + F23 = 0xFFD4, + R3 = 0xFFD4, + F24 = 0xFFD5, + R4 = 0xFFD5, + F25 = 0xFFD6, + R5 = 0xFFD6, + F26 = 0xFFD7, + R6 = 0xFFD7, + F27 = 0xFFD8, + R7 = 0xFFD8, + F28 = 0xFFD9, + R8 = 0xFFD9, + F29 = 0xFFDA, + R9 = 0xFFDA, + F30 = 0xFFDB, + R10 = 0xFFDB, + F31 = 0xFFDC, + R11 = 0xFFDC, + F32 = 0xFFDD, + R12 = 0xFFDD, + F33 = 0xFFDE, + R13 = 0xFFDE, + F34 = 0xFFDF, + R14 = 0xFFDF, + F35 = 0xFFE0, + R15 = 0xFFE0, + Shift_L = 0xFFE1, + Shift_R = 0xFFE2, + Control_L = 0xFFE3, + Control_R = 0xFFE4, + Caps_Lock = 0xFFE5, + Shift_Lock = 0xFFE6, + Meta_L = 0xFFE7, + Meta_R = 0xFFE8, + Alt_L = 0xFFE9, + Alt_R = 0xFFEA, + Super_L = 0xFFEB, + Super_R = 0xFFEC, + Hyper_L = 0xFFED, + Hyper_R = 0xFFEE, + Null = 0 +}; - // modifiers, modified to fit a UINT16 +// modifiers, modified to fit a UINT16 - enum Modifier - { - NULL_MASK = 0, +enum Modifier { + NULL_MASK = 0, - SHIFT_MASK = 1 << 0, - LOCK_MASK = 1 << 1, - CONTROL_MASK = 1 << 2, - ALT_MASK = 1 << 3, - MOD1_MASK = 1 << 3, - MOD2_MASK = 1 << 4, - MOD3_MASK = 1 << 5, - MOD4_MASK = 1 << 6, - MOD5_MASK = 1 << 7, + SHIFT_MASK = 1 << 0, + LOCK_MASK = 1 << 1, + CONTROL_MASK = 1 << 2, + ALT_MASK = 1 << 3, + MOD1_MASK = 1 << 3, + MOD2_MASK = 1 << 4, + MOD3_MASK = 1 << 5, + MOD4_MASK = 1 << 6, + MOD5_MASK = 1 << 7, - HANDLED_MASK = 1 << 8, // 24 - IGNORED_MASK = 1 << 9, // 25 - FORWARD_MASK = 1 << 9, // 25 + HANDLED_MASK = 1 << 8, // 24 + IGNORED_MASK = 1 << 9, // 25 + FORWARD_MASK = 1 << 9, // 25 - SUPER_MASK = 1 << 10, // 26 - HYPER_MASK = 1 << 11, // 27 - META_MASK = 1 << 12, // 28 + SUPER_MASK = 1 << 10, // 26 + HYPER_MASK = 1 << 11, // 27 + META_MASK = 1 << 12, // 28 - RELEASE_MASK = 1 << 14, // 30 + RELEASE_MASK = 1 << 14, // 30 - MODIFIER_MASK = 0x2fff - }; + MODIFIER_MASK = 0x2fff +}; -} +} // namespace ibus diff --git a/WeaselIME/WeaselIME.cpp b/WeaselIME/WeaselIME.cpp index e80c8eb94..45bfc20dd 100644 --- a/WeaselIME/WeaselIME.cpp +++ b/WeaselIME/WeaselIME.cpp @@ -17,613 +17,551 @@ HINSTANCE WeaselIME::s_hModule = 0; HIMCMap WeaselIME::s_instances; -static void error_message(const WCHAR *msg) -{ - static DWORD next_tick = 0; - DWORD now = GetTickCount(); - if (now > next_tick) - { - next_tick = now + 10000; // (ms) - MessageBox(NULL, msg, WEASEL_IME_NAME, MB_ICONERROR | MB_OK); - } +static void error_message(const WCHAR* msg) { + static DWORD next_tick = 0; + DWORD now = GetTickCount(); + if (now > next_tick) { + next_tick = now + 10000; // (ms) + MessageBox(NULL, msg, WEASEL_IME_NAME, MB_ICONERROR | MB_OK); + } } /* static bool launch_server() { - EZDBGONLYLOGGERPRINT("Launching weasel server."); - - // 從註冊表取得server位置 - HKEY hKey; - LSTATUS ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WEASEL_REG_KEY, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); - if (ret != ERROR_SUCCESS) - { - error_message(L"註冊表信息無影了"); - return false; - } - - WCHAR value[MAX_PATH]; - DWORD len = sizeof(value); - DWORD type = 0; - ret = RegQueryValueEx(hKey, L"WeaselRoot", NULL, &type, (LPBYTE)value, &len); - if (ret != ERROR_SUCCESS) - { - error_message(L"未設置 WeaselRoot"); - RegCloseKey(hKey); - return false; - } - wpath weaselRoot(value); - - len = sizeof(value); - type = 0; - ret = RegQueryValueEx(hKey, L"ServerExecutable", NULL, &type, (LPBYTE)value, &len); - if (ret != ERROR_SUCCESS) - { - error_message(L"未設置 ServerExecutable"); - RegCloseKey(hKey); - return false; - } - wpath serverPath(weaselRoot / value); - - RegCloseKey(hKey); - - // 啓動服務進程 - std::wstring exe = serverPath.wstring(); - std::wstring dir = weaselRoot.wstring(); - - STARTUPINFO startup_info = {0}; - PROCESS_INFORMATION process_info = {0}; - startup_info.cb = sizeof(startup_info); - - if (!CreateProcess(exe.c_str(), NULL, NULL, NULL, FALSE, 0, NULL, dir.c_str(), &startup_info, &process_info)) - { - EZDBGONLYLOGGERPRINT("ERROR: failed to launch weasel server."); - error_message(L"服務進程啓動不起來 :("); - return false; - } - - if (!WaitForInputIdle(process_info.hProcess, 1500)) - { - EZDBGONLYLOGGERPRINT("WARNING: WaitForInputIdle() timed out; succeeding IPC messages might not be delivered."); - } - if (process_info.hProcess) CloseHandle(process_info.hProcess); - if (process_info.hThread) CloseHandle(process_info.hThread); - - return true; + EZDBGONLYLOGGERPRINT("Launching weasel server."); + + // 從註冊表取得server位置 + HKEY hKey; + LSTATUS ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WEASEL_REG_KEY, 0, +KEY_READ | KEY_WOW64_32KEY, &hKey); if (ret != ERROR_SUCCESS) + { + error_message(L"註冊表信息無影了"); + return false; + } + + WCHAR value[MAX_PATH]; + DWORD len = sizeof(value); + DWORD type = 0; + ret = RegQueryValueEx(hKey, L"WeaselRoot", NULL, &type, (LPBYTE)value, +&len); if (ret != ERROR_SUCCESS) + { + error_message(L"未設置 WeaselRoot"); + RegCloseKey(hKey); + return false; + } + wpath weaselRoot(value); + + len = sizeof(value); + type = 0; + ret = RegQueryValueEx(hKey, L"ServerExecutable", NULL, &type, +(LPBYTE)value, &len); if (ret != ERROR_SUCCESS) + { + error_message(L"未設置 ServerExecutable"); + RegCloseKey(hKey); + return false; + } + wpath serverPath(weaselRoot / value); + + RegCloseKey(hKey); + + // 啓動服務進程 + std::wstring exe = serverPath.wstring(); + std::wstring dir = weaselRoot.wstring(); + + STARTUPINFO startup_info = {0}; + PROCESS_INFORMATION process_info = {0}; + startup_info.cb = sizeof(startup_info); + + if (!CreateProcess(exe.c_str(), NULL, NULL, NULL, FALSE, 0, NULL, +dir.c_str(), &startup_info, &process_info)) + { + EZDBGONLYLOGGERPRINT("ERROR: failed to launch weasel server."); + error_message(L"服務進程啓動不起來 :("); + return false; + } + + if (!WaitForInputIdle(process_info.hProcess, 1500)) + { + EZDBGONLYLOGGERPRINT("WARNING: WaitForInputIdle() timed out; +succeeding IPC messages might not be delivered."); + } + if (process_info.hProcess) CloseHandle(process_info.hProcess); + if (process_info.hThread) CloseHandle(process_info.hThread); + + return true; } */ WeaselIME::WeaselIME(HIMC hIMC) -: m_hIMC(hIMC) -, m_composing(false) -, m_preferCandidatePos(false) -{ - WCHAR path[MAX_PATH]; - WCHAR fname[_MAX_FNAME]; - WCHAR ext[_MAX_EXT]; - GetModuleFileNameW(NULL, path, _countof(path)); - _wsplitpath_s(path, NULL, 0, NULL, 0, fname, _countof(fname), ext, _countof(ext)); - if (iequals(L"chrome", fname) && iequals(L"exe", ext)) - m_preferCandidatePos = true; + : m_hIMC(hIMC), m_composing(false), m_preferCandidatePos(false) { + WCHAR path[MAX_PATH]; + WCHAR fname[_MAX_FNAME]; + WCHAR ext[_MAX_EXT]; + GetModuleFileNameW(NULL, path, _countof(path)); + _wsplitpath_s(path, NULL, 0, NULL, 0, fname, _countof(fname), ext, + _countof(ext)); + if (iequals(L"chrome", fname) && iequals(L"exe", ext)) + m_preferCandidatePos = true; } -HINSTANCE WeaselIME::GetModuleInstance() -{ - return s_hModule; +HINSTANCE WeaselIME::GetModuleInstance() { + return s_hModule; } -void WeaselIME::SetModuleInstance(HINSTANCE hModule) -{ - s_hModule = hModule; +void WeaselIME::SetModuleInstance(HINSTANCE hModule) { + s_hModule = hModule; } -HRESULT WeaselIME::RegisterUIClass() -{ - WNDCLASSEX wc; - wc.cbSize = sizeof(WNDCLASSEX); - wc.style = CS_IME; - wc.lpfnWndProc = WeaselIME::UIWndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 2 * sizeof(LONG); - wc.hInstance = GetModuleInstance(); - wc.hCursor = NULL; - wc.hIcon = NULL; - wc.lpszMenuName = NULL; - wc.lpszClassName = GetUIClassName(); - wc.hbrBackground = NULL; - wc.hIconSm = NULL; - - if (RegisterClassExW(&wc) == 0) - { - DWORD dwErr = GetLastError(); - return HRESULT_FROM_WIN32(dwErr); - } - - return S_OK; +HRESULT WeaselIME::RegisterUIClass() { + WNDCLASSEX wc; + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = CS_IME; + wc.lpfnWndProc = WeaselIME::UIWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 2 * sizeof(LONG); + wc.hInstance = GetModuleInstance(); + wc.hCursor = NULL; + wc.hIcon = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = GetUIClassName(); + wc.hbrBackground = NULL; + wc.hIconSm = NULL; + + if (RegisterClassExW(&wc) == 0) { + DWORD dwErr = GetLastError(); + return HRESULT_FROM_WIN32(dwErr); + } + + return S_OK; } -HRESULT WeaselIME::UnregisterUIClass() -{ - if (!UnregisterClassW(GetUIClassName(), GetModuleInstance())) - { - DWORD dwErr = GetLastError(); - return HRESULT_FROM_WIN32(dwErr); - } - return S_OK; +HRESULT WeaselIME::UnregisterUIClass() { + if (!UnregisterClassW(GetUIClassName(), GetModuleInstance())) { + DWORD dwErr = GetLastError(); + return HRESULT_FROM_WIN32(dwErr); + } + return S_OK; } -LPCWSTR WeaselIME::GetUIClassName() -{ - return L"WeaselUIClass"; +LPCWSTR WeaselIME::GetUIClassName() { + return L"WeaselUIClass"; } -LRESULT WINAPI WeaselIME::UIWndProc(HWND hWnd, UINT uMsg, WPARAM wp, LPARAM lp) -{ - HIMC hIMC = (HIMC)GetWindowLongPtr(hWnd, 0); - if (hIMC) - { - std::shared_ptr p = WeaselIME::GetInstance(hIMC); - if (!p) - return 0; - return p->OnUIMessage(hWnd, uMsg, wp, lp); - } - else - { - if (!IsIMEMessage(uMsg)) - { - return DefWindowProcW(hWnd, uMsg, wp, lp); - } - } - - return 0; +LRESULT WINAPI WeaselIME::UIWndProc(HWND hWnd, + UINT uMsg, + WPARAM wp, + LPARAM lp) { + HIMC hIMC = (HIMC)GetWindowLongPtr(hWnd, 0); + if (hIMC) { + std::shared_ptr p = WeaselIME::GetInstance(hIMC); + if (!p) + return 0; + return p->OnUIMessage(hWnd, uMsg, wp, lp); + } else { + if (!IsIMEMessage(uMsg)) { + return DefWindowProcW(hWnd, uMsg, wp, lp); + } + } + + return 0; } -BOOL WeaselIME::IsIMEMessage(UINT uMsg) -{ - switch(uMsg) - { - case WM_IME_STARTCOMPOSITION: - case WM_IME_ENDCOMPOSITION: - case WM_IME_COMPOSITION: - case WM_IME_NOTIFY: - case WM_IME_SETCONTEXT: - case WM_IME_CONTROL: - case WM_IME_COMPOSITIONFULL: - case WM_IME_SELECT: - case WM_IME_CHAR: - return TRUE; - default: - return FALSE; - } - - return FALSE; +BOOL WeaselIME::IsIMEMessage(UINT uMsg) { + switch (uMsg) { + case WM_IME_STARTCOMPOSITION: + case WM_IME_ENDCOMPOSITION: + case WM_IME_COMPOSITION: + case WM_IME_NOTIFY: + case WM_IME_SETCONTEXT: + case WM_IME_CONTROL: + case WM_IME_COMPOSITIONFULL: + case WM_IME_SELECT: + case WM_IME_CHAR: + return TRUE; + default: + return FALSE; + } + + return FALSE; } -std::shared_ptr WeaselIME::GetInstance(HIMC hIMC) -{ - if (!s_instances.is_valid()) - { - return std::shared_ptr(); - } - std::lock_guard lock(s_instances.get_mutex()); - std::shared_ptr& p = s_instances[hIMC]; - if (!p) - { - p.reset(new WeaselIME(hIMC)); - } - return p; +std::shared_ptr WeaselIME::GetInstance(HIMC hIMC) { + if (!s_instances.is_valid()) { + return std::shared_ptr(); + } + std::lock_guard lock(s_instances.get_mutex()); + std::shared_ptr& p = s_instances[hIMC]; + if (!p) { + p.reset(new WeaselIME(hIMC)); + } + return p; } -void WeaselIME::Cleanup() -{ - std::for_each(s_instances.begin(), s_instances.end(), [](std::pair> &pair) - { - pair.second->OnIMESelect(FALSE); - }); - std::lock_guard lock(s_instances.get_mutex()); - s_instances.clear(); +void WeaselIME::Cleanup() { + std::for_each(s_instances.begin(), s_instances.end(), + [](std::pair>& pair) { + pair.second->OnIMESelect(FALSE); + }); + std::lock_guard lock(s_instances.get_mutex()); + s_instances.clear(); } -LRESULT WeaselIME::OnIMESelect(BOOL fSelect) -{ - EZDBGONLYLOGGERPRINT("On IME select: %d, HIMC = 0x%x", fSelect, m_hIMC); - ImmSetOpenStatus(m_hIMC, fSelect); - if (fSelect) - { - // initialize weasel client - m_client.Connect(NULL); - m_client.StartSession(); - - return _Initialize(); - } - else - { - m_client.EndSession(); - - return _Finalize(); - } +LRESULT WeaselIME::OnIMESelect(BOOL fSelect) { + EZDBGONLYLOGGERPRINT("On IME select: %d, HIMC = 0x%x", fSelect, m_hIMC); + ImmSetOpenStatus(m_hIMC, fSelect); + if (fSelect) { + // initialize weasel client + m_client.Connect(NULL); + m_client.StartSession(); + + return _Initialize(); + } else { + m_client.EndSession(); + + return _Finalize(); + } } -LRESULT WeaselIME::OnIMEFocus(BOOL fFocus) -{ - EZDBGONLYLOGGERPRINT("On IME focus: %d, HIMC = 0x%x", fFocus, m_hIMC); - LPINPUTCONTEXT lpIMC = ImmLockIMC(m_hIMC); - if(!lpIMC) - { - return 0; - } - if (fFocus) - { - if(!(lpIMC->fdwInit & INIT_COMPFORM)) - { - lpIMC->cfCompForm.dwStyle = CFS_DEFAULT; - GetCursorPos(&lpIMC->cfCompForm.ptCurrentPos); - ScreenToClient(lpIMC->hWnd, &lpIMC->cfCompForm.ptCurrentPos); - lpIMC->fdwInit |= INIT_COMPFORM; - } - m_client.FocusIn(); - } - else - { - m_client.FocusOut(); - } - ImmUnlockIMC(m_hIMC); - - return 0; +LRESULT WeaselIME::OnIMEFocus(BOOL fFocus) { + EZDBGONLYLOGGERPRINT("On IME focus: %d, HIMC = 0x%x", fFocus, m_hIMC); + LPINPUTCONTEXT lpIMC = ImmLockIMC(m_hIMC); + if (!lpIMC) { + return 0; + } + if (fFocus) { + if (!(lpIMC->fdwInit & INIT_COMPFORM)) { + lpIMC->cfCompForm.dwStyle = CFS_DEFAULT; + GetCursorPos(&lpIMC->cfCompForm.ptCurrentPos); + ScreenToClient(lpIMC->hWnd, &lpIMC->cfCompForm.ptCurrentPos); + lpIMC->fdwInit |= INIT_COMPFORM; + } + m_client.FocusIn(); + } else { + m_client.FocusOut(); + } + ImmUnlockIMC(m_hIMC); + + return 0; } -LRESULT WeaselIME::OnUIMessage(HWND hWnd, UINT uMsg, WPARAM wp, LPARAM lp) -{ - LPINPUTCONTEXT lpIMC = (LPINPUTCONTEXT)ImmLockIMC(m_hIMC); - switch (uMsg) - { - case WM_IME_NOTIFY: - { - EZDBGONLYLOGGERPRINT("WM_IME_NOTIFY: wp = 0x%x, lp = 0x%x, HIMC = 0x%x", wp, lp, m_hIMC); - _OnIMENotify(lpIMC, wp, lp); - } - break; - case WM_IME_SELECT: - { - EZDBGONLYLOGGERPRINT("WM_IME_SELECT: wp = 0x%x, lp = 0x%x, HIMC = 0x%x", wp, lp, m_hIMC); - if (m_preferCandidatePos) - _SetCandidatePos(lpIMC); - else - _SetCompositionWindow(lpIMC); - } - break; - case WM_IME_STARTCOMPOSITION: - { - EZDBGONLYLOGGERPRINT("WM_IME_STARTCOMPOSITION: wp = 0x%x, lp = 0x%x, HIMC = 0x%x", wp, lp, m_hIMC); - if (m_preferCandidatePos) - _SetCandidatePos(lpIMC); - else - _SetCompositionWindow(lpIMC); - } - break; - default: - if (!IsIMEMessage(uMsg)) - { - ImmUnlockIMC(m_hIMC); - return DefWindowProcW(hWnd, uMsg, wp, lp); - } - EZDBGONLYLOGGERPRINT("WM_IME_(0x%x): wp = 0x%x, lp = 0x%x, HIMC = 0x%x", uMsg, wp, lp, m_hIMC); - } - - ImmUnlockIMC(m_hIMC); - return 0; +LRESULT WeaselIME::OnUIMessage(HWND hWnd, UINT uMsg, WPARAM wp, LPARAM lp) { + LPINPUTCONTEXT lpIMC = (LPINPUTCONTEXT)ImmLockIMC(m_hIMC); + switch (uMsg) { + case WM_IME_NOTIFY: { + EZDBGONLYLOGGERPRINT("WM_IME_NOTIFY: wp = 0x%x, lp = 0x%x, HIMC = 0x%x", + wp, lp, m_hIMC); + _OnIMENotify(lpIMC, wp, lp); + } break; + case WM_IME_SELECT: { + EZDBGONLYLOGGERPRINT("WM_IME_SELECT: wp = 0x%x, lp = 0x%x, HIMC = 0x%x", + wp, lp, m_hIMC); + if (m_preferCandidatePos) + _SetCandidatePos(lpIMC); + else + _SetCompositionWindow(lpIMC); + } break; + case WM_IME_STARTCOMPOSITION: { + EZDBGONLYLOGGERPRINT( + "WM_IME_STARTCOMPOSITION: wp = 0x%x, lp = 0x%x, HIMC = 0x%x", wp, lp, + m_hIMC); + if (m_preferCandidatePos) + _SetCandidatePos(lpIMC); + else + _SetCompositionWindow(lpIMC); + } break; + default: + if (!IsIMEMessage(uMsg)) { + ImmUnlockIMC(m_hIMC); + return DefWindowProcW(hWnd, uMsg, wp, lp); + } + EZDBGONLYLOGGERPRINT("WM_IME_(0x%x): wp = 0x%x, lp = 0x%x, HIMC = 0x%x", + uMsg, wp, lp, m_hIMC); + } + + ImmUnlockIMC(m_hIMC); + return 0; } -LRESULT WeaselIME::_OnIMENotify(LPINPUTCONTEXT lpIMC, WPARAM wp, LPARAM lp) -{ - switch (wp) - { - case IMN_OPENCANDIDATE: - { - EZDBGONLYLOGGERPRINT("IMN_OPENCANDIDATE: HIMC = 0x%x", m_hIMC); - if (m_preferCandidatePos) - _SetCandidatePos(lpIMC); - else - _SetCompositionWindow(lpIMC); - } - break; - case IMN_SETCANDIDATEPOS: - { - EZDBGONLYLOGGERPRINT("IMN_SETCANDIDATEPOS: HIMC = 0x%x", m_hIMC); - _SetCandidatePos(lpIMC); - } - break; - case IMN_SETCOMPOSITIONWINDOW: - { - EZDBGONLYLOGGERPRINT("IMN_SETCOMPOSITIONWINDOW: HIMC = 0x%x", m_hIMC); - if (m_preferCandidatePos) - _SetCandidatePos(lpIMC); - else - _SetCompositionWindow(lpIMC); - } - break; - case IMN_SETOPENSTATUS: - { - if (!ImmGetOpenStatus(m_hIMC)) // gvim command mode - { - m_client.ClearComposition(); // cancel unfinished input (eg. quitting insert mode with Ctrl+[ ) - } - } - break; - default: - EZDBGONLYLOGGERPRINT("IMN_(0x%x): HIMC = 0x%x", wp, m_hIMC); - } - - return 0; +LRESULT WeaselIME::_OnIMENotify(LPINPUTCONTEXT lpIMC, WPARAM wp, LPARAM lp) { + switch (wp) { + case IMN_OPENCANDIDATE: { + EZDBGONLYLOGGERPRINT("IMN_OPENCANDIDATE: HIMC = 0x%x", m_hIMC); + if (m_preferCandidatePos) + _SetCandidatePos(lpIMC); + else + _SetCompositionWindow(lpIMC); + } break; + case IMN_SETCANDIDATEPOS: { + EZDBGONLYLOGGERPRINT("IMN_SETCANDIDATEPOS: HIMC = 0x%x", m_hIMC); + _SetCandidatePos(lpIMC); + } break; + case IMN_SETCOMPOSITIONWINDOW: { + EZDBGONLYLOGGERPRINT("IMN_SETCOMPOSITIONWINDOW: HIMC = 0x%x", m_hIMC); + if (m_preferCandidatePos) + _SetCandidatePos(lpIMC); + else + _SetCompositionWindow(lpIMC); + } break; + case IMN_SETOPENSTATUS: { + if (!ImmGetOpenStatus(m_hIMC)) // gvim command mode + { + m_client.ClearComposition(); // cancel unfinished input (eg. quitting + // insert mode with Ctrl+[ ) + } + } break; + default: + EZDBGONLYLOGGERPRINT("IMN_(0x%x): HIMC = 0x%x", wp, m_hIMC); + } + + return 0; } -void WeaselIME::_SetCandidatePos(LPINPUTCONTEXT lpIMC) -{ - EZDBGONLYLOGGERFUNCTRACKER; - POINT pt = lpIMC->cfCandForm[0].ptCurrentPos; - _UpdateInputPosition(lpIMC, pt); +void WeaselIME::_SetCandidatePos(LPINPUTCONTEXT lpIMC) { + EZDBGONLYLOGGERFUNCTRACKER; + POINT pt = lpIMC->cfCandForm[0].ptCurrentPos; + _UpdateInputPosition(lpIMC, pt); } -void WeaselIME::_SetCompositionWindow(LPINPUTCONTEXT lpIMC) -{ - EZDBGONLYLOGGERVAR(lpIMC->cfCompForm.dwStyle); - POINT pt = {-1, -1}; - switch (lpIMC->cfCompForm.dwStyle) - { - case CFS_DEFAULT: - // require caret pos detection - break; - case CFS_RECT: - //pt.x = lpIMC->cfCompForm.rcArea.left; - //pt.y = lpIMC->cfCompForm.rcArea.top; - break; - case CFS_POINT: - if (lpIMC->cfCompForm.rcArea.left == 0 && lpIMC->cfCompForm.rcArea.top == 0) - { - return; // may be invalid position - } - pt = lpIMC->cfCompForm.ptCurrentPos; - break; - case CFS_FORCE_POSITION: - pt = lpIMC->cfCompForm.ptCurrentPos; - break; - case CFS_CANDIDATEPOS: - pt = lpIMC->cfCandForm[0].ptCurrentPos; - break; - default: - // require caret pos detection - break; - } - _UpdateInputPosition(lpIMC, pt); +void WeaselIME::_SetCompositionWindow(LPINPUTCONTEXT lpIMC) { + EZDBGONLYLOGGERVAR(lpIMC->cfCompForm.dwStyle); + POINT pt = {-1, -1}; + switch (lpIMC->cfCompForm.dwStyle) { + case CFS_DEFAULT: + // require caret pos detection + break; + case CFS_RECT: + // pt.x = lpIMC->cfCompForm.rcArea.left; + // pt.y = lpIMC->cfCompForm.rcArea.top; + break; + case CFS_POINT: + if (lpIMC->cfCompForm.rcArea.left == 0 && + lpIMC->cfCompForm.rcArea.top == 0) { + return; // may be invalid position + } + pt = lpIMC->cfCompForm.ptCurrentPos; + break; + case CFS_FORCE_POSITION: + pt = lpIMC->cfCompForm.ptCurrentPos; + break; + case CFS_CANDIDATEPOS: + pt = lpIMC->cfCandForm[0].ptCurrentPos; + break; + default: + // require caret pos detection + break; + } + _UpdateInputPosition(lpIMC, pt); } -BOOL WeaselIME::ProcessKeyEvent(UINT vKey, KeyInfo kinfo, const LPBYTE lpbKeyState) -{ - EZDBGONLYLOGGERPRINT("Process key event: vKey = 0x%x, kinfo = 0x%x, HIMC = 0x%x", vKey, UINT32(kinfo), m_hIMC); - - if (!ImmGetOpenStatus(m_hIMC)) // gvim command mode - { - return FALSE; - } - - if (!m_client.Echo()) - { - m_client.Connect(NULL); - m_client.StartSession(); - } - - weasel::KeyEvent ke; - if (!ConvertKeyEvent(vKey, kinfo, lpbKeyState, ke)) - { - // unknown key event - return FALSE; - } - - bool accepted = m_client.ProcessKeyEvent(ke); - - // get commit string from server - std::wstring commit; - weasel::Status status; - weasel::ResponseParser parser(&commit, NULL, &status); - bool ok = m_client.GetResponseData(std::ref(parser)); - - if (ok) - { - if (!commit.empty()) - { - _EndComposition(commit.c_str()); - } - else if (status.composing != m_composing) - { - if (m_composing) - _EndComposition(NULL); - else - _StartComposition(); - } - } - - return (BOOL)accepted; +BOOL WeaselIME::ProcessKeyEvent(UINT vKey, + KeyInfo kinfo, + const LPBYTE lpbKeyState) { + EZDBGONLYLOGGERPRINT( + "Process key event: vKey = 0x%x, kinfo = 0x%x, HIMC = 0x%x", vKey, + UINT32(kinfo), m_hIMC); + + if (!ImmGetOpenStatus(m_hIMC)) // gvim command mode + { + return FALSE; + } + + if (!m_client.Echo()) { + m_client.Connect(NULL); + m_client.StartSession(); + } + + weasel::KeyEvent ke; + if (!ConvertKeyEvent(vKey, kinfo, lpbKeyState, ke)) { + // unknown key event + return FALSE; + } + + bool accepted = m_client.ProcessKeyEvent(ke); + + // get commit string from server + std::wstring commit; + weasel::Status status; + weasel::ResponseParser parser(&commit, NULL, &status); + bool ok = m_client.GetResponseData(std::ref(parser)); + + if (ok) { + if (!commit.empty()) { + _EndComposition(commit.c_str()); + } else if (status.composing != m_composing) { + if (m_composing) + _EndComposition(NULL); + else + _StartComposition(); + } + } + + return (BOOL)accepted; } -HRESULT WeaselIME::_Initialize() -{ - LPINPUTCONTEXT lpIMC = ImmLockIMC(m_hIMC); - if(!lpIMC) - return E_FAIL; - - lpIMC->fOpen = TRUE; - - HIMCC& hIMCC = lpIMC->hCompStr; - if (!hIMCC) - hIMCC = ImmCreateIMCC(sizeof(CompositionInfo)); - else - hIMCC = ImmReSizeIMCC(hIMCC, sizeof(CompositionInfo)); - if(!hIMCC) - { - ImmUnlockIMC(m_hIMC); - return E_FAIL; - } - - CompositionInfo* pInfo = (CompositionInfo*)ImmLockIMCC(hIMCC); - if (!pInfo) - { - ImmUnlockIMC(m_hIMC); - return E_FAIL; - } - - pInfo->Reset(); - ImmUnlockIMCC(hIMCC); - ImmUnlockIMC(m_hIMC); - - return S_OK; +HRESULT WeaselIME::_Initialize() { + LPINPUTCONTEXT lpIMC = ImmLockIMC(m_hIMC); + if (!lpIMC) + return E_FAIL; + + lpIMC->fOpen = TRUE; + + HIMCC& hIMCC = lpIMC->hCompStr; + if (!hIMCC) + hIMCC = ImmCreateIMCC(sizeof(CompositionInfo)); + else + hIMCC = ImmReSizeIMCC(hIMCC, sizeof(CompositionInfo)); + if (!hIMCC) { + ImmUnlockIMC(m_hIMC); + return E_FAIL; + } + + CompositionInfo* pInfo = (CompositionInfo*)ImmLockIMCC(hIMCC); + if (!pInfo) { + ImmUnlockIMC(m_hIMC); + return E_FAIL; + } + + pInfo->Reset(); + ImmUnlockIMCC(hIMCC); + ImmUnlockIMC(m_hIMC); + + return S_OK; } -HRESULT WeaselIME::_Finalize() -{ - LPINPUTCONTEXT lpIMC = ImmLockIMC(m_hIMC); - if (lpIMC) - { - lpIMC->fOpen = FALSE; - if (lpIMC->hCompStr) - { - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = NULL; - } - } - ImmUnlockIMC(m_hIMC); - - return S_OK; +HRESULT WeaselIME::_Finalize() { + LPINPUTCONTEXT lpIMC = ImmLockIMC(m_hIMC); + if (lpIMC) { + lpIMC->fOpen = FALSE; + if (lpIMC->hCompStr) { + ImmDestroyIMCC(lpIMC->hCompStr); + lpIMC->hCompStr = NULL; + } + } + ImmUnlockIMC(m_hIMC); + + return S_OK; } -HRESULT WeaselIME::_StartComposition() -{ - _AddIMEMessage(WM_IME_STARTCOMPOSITION, 0, 0); - _AddIMEMessage(WM_IME_NOTIFY, IMN_CHANGECANDIDATE, 0); - _AddIMEMessage(WM_IME_NOTIFY, IMN_OPENCANDIDATE, 0); +HRESULT WeaselIME::_StartComposition() { + _AddIMEMessage(WM_IME_STARTCOMPOSITION, 0, 0); + _AddIMEMessage(WM_IME_NOTIFY, IMN_CHANGECANDIDATE, 0); + _AddIMEMessage(WM_IME_NOTIFY, IMN_OPENCANDIDATE, 0); - m_composing = true; - return S_OK; + m_composing = true; + return S_OK; } -HRESULT WeaselIME::_EndComposition(LPCWSTR composition) -{ - if (composition) - { - LPINPUTCONTEXT lpIMC; - LPCOMPOSITIONSTRING lpCompStr; - - lpIMC = ImmLockIMC(m_hIMC); - if (!lpIMC) - return E_FAIL; - - lpCompStr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr); - if (!lpCompStr) - { - ImmUnlockIMC(m_hIMC); - return E_FAIL; - } - - CompositionInfo* pInfo = (CompositionInfo*)lpCompStr; - wcscpy_s(pInfo->szResultStr, composition); - lpCompStr->dwResultStrLen = wcslen(pInfo->szResultStr); - - ImmUnlockIMCC(lpIMC->hCompStr); - ImmUnlockIMC(m_hIMC); - - _AddIMEMessage(WM_IME_COMPOSITION, 0, GCS_COMP|GCS_RESULTSTR); - } - _AddIMEMessage(WM_IME_ENDCOMPOSITION, 0, 0); - _AddIMEMessage(WM_IME_NOTIFY, IMN_CLOSECANDIDATE, 0); - - m_composing = false; - return S_OK; +HRESULT WeaselIME::_EndComposition(LPCWSTR composition) { + if (composition) { + LPINPUTCONTEXT lpIMC; + LPCOMPOSITIONSTRING lpCompStr; + + lpIMC = ImmLockIMC(m_hIMC); + if (!lpIMC) + return E_FAIL; + + lpCompStr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr); + if (!lpCompStr) { + ImmUnlockIMC(m_hIMC); + return E_FAIL; + } + + CompositionInfo* pInfo = (CompositionInfo*)lpCompStr; + wcscpy_s(pInfo->szResultStr, composition); + lpCompStr->dwResultStrLen = wcslen(pInfo->szResultStr); + + ImmUnlockIMCC(lpIMC->hCompStr); + ImmUnlockIMC(m_hIMC); + + _AddIMEMessage(WM_IME_COMPOSITION, 0, GCS_COMP | GCS_RESULTSTR); + } + _AddIMEMessage(WM_IME_ENDCOMPOSITION, 0, 0); + _AddIMEMessage(WM_IME_NOTIFY, IMN_CLOSECANDIDATE, 0); + + m_composing = false; + return S_OK; } -HRESULT WeaselIME::_AddIMEMessage(UINT msg, WPARAM wp, LPARAM lp) -{ - if(!m_hIMC) - return S_FALSE; - - LPINPUTCONTEXT lpIMC = (LPINPUTCONTEXT)ImmLockIMC(m_hIMC); - if(!lpIMC) - return E_FAIL; - - HIMCC hBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, - sizeof(TRANSMSG) * (lpIMC->dwNumMsgBuf + 1)); - if(!hBuf) - { - ImmUnlockIMC(m_hIMC); - return E_FAIL; - } - lpIMC->hMsgBuf = hBuf; - - LPTRANSMSG pBuf = (LPTRANSMSG)ImmLockIMCC(hBuf); - if(!pBuf) - { - ImmUnlockIMC(m_hIMC); - return E_FAIL; - } - - DWORD last = lpIMC->dwNumMsgBuf; - pBuf[last].message = msg; - pBuf[last].wParam = wp; - pBuf[last].lParam = lp; - lpIMC->dwNumMsgBuf++; - ImmUnlockIMCC(hBuf); - - ImmUnlockIMC(m_hIMC); - - if (!ImmGenerateMessage(m_hIMC)) - { - return E_FAIL; - } - - return S_OK; +HRESULT WeaselIME::_AddIMEMessage(UINT msg, WPARAM wp, LPARAM lp) { + if (!m_hIMC) + return S_FALSE; + + LPINPUTCONTEXT lpIMC = (LPINPUTCONTEXT)ImmLockIMC(m_hIMC); + if (!lpIMC) + return E_FAIL; + + HIMCC hBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, + sizeof(TRANSMSG) * (lpIMC->dwNumMsgBuf + 1)); + if (!hBuf) { + ImmUnlockIMC(m_hIMC); + return E_FAIL; + } + lpIMC->hMsgBuf = hBuf; + + LPTRANSMSG pBuf = (LPTRANSMSG)ImmLockIMCC(hBuf); + if (!pBuf) { + ImmUnlockIMC(m_hIMC); + return E_FAIL; + } + + DWORD last = lpIMC->dwNumMsgBuf; + pBuf[last].message = msg; + pBuf[last].wParam = wp; + pBuf[last].lParam = lp; + lpIMC->dwNumMsgBuf++; + ImmUnlockIMCC(hBuf); + + ImmUnlockIMC(m_hIMC); + + if (!ImmGenerateMessage(m_hIMC)) { + return E_FAIL; + } + + return S_OK; } -void WeaselIME::_UpdateInputPosition(LPINPUTCONTEXT lpIMC, POINT pt) -{ - EZDBGONLYLOGGERPRINT("_UpdateInputPosition: (%d, %d)", pt.x, pt.y); - - //EZDBGONLYLOGGERPRINT("cfCompForm: ptCurrentPos = (%d, %d), rcArea = (%d, %d)", - // lpIMC->cfCompForm.ptCurrentPos.x, lpIMC->cfCompForm.ptCurrentPos.y, - // lpIMC->cfCompForm.rcArea.left, lpIMC->cfCompForm.rcArea.top); - //EZDBGONLYLOGGERPRINT("cfCandForm[0]: ptCurrentPos = (%d, %d), rcArea = (%d, %d)", - // lpIMC->cfCandForm[0].ptCurrentPos.x, lpIMC->cfCandForm[0].ptCurrentPos.y, - // lpIMC->cfCandForm[0].rcArea.left, lpIMC->cfCandForm[0].rcArea.top); - //EZDBGONLYLOGGERPRINT("cfCandForm[1]: ptCurrentPos = (%d, %d), rcArea = (%d, %d)", - // lpIMC->cfCandForm[1].ptCurrentPos.x, lpIMC->cfCandForm[1].ptCurrentPos.y, - // lpIMC->cfCandForm[1].rcArea.left, lpIMC->cfCandForm[1].rcArea.top); - - if (pt.x == -1 && pt.y == -1) - { - EZDBGONLYLOGGERPRINT("Caret pos detection required."); - if(!GetCaretPos(&pt)) - { - EZDBGONLYLOGGERPRINT("Failed to determine caret pos."); - pt.x = pt.y = 0; - } - } - - ClientToScreen(lpIMC->hWnd, &pt); - if (pt.x < -4096 || pt.x >= 4096 || pt.y < -4096 || pt.y >= 4096) - { - EZDBGONLYLOGGERPRINT("Input position out of range, possibly invalid."); - return; - } - - int height = abs(lpIMC->lfFont.W.lfHeight); - if (height == 0) - { - HDC hDC = GetDC(lpIMC->hWnd); - SIZE sz = {0}; - GetTextExtentPoint(hDC, L"A", 1, &sz); - height = sz.cy; - ReleaseDC(lpIMC->hWnd, hDC); - } - const int width = 6; - RECT rc; - SetRect(&rc, pt.x, pt.y, pt.x + width, pt.y + height); - EZDBGONLYLOGGERPRINT("Updating input position: (%d, %d)", pt.x, pt.y); - m_client.UpdateInputPosition(rc); +void WeaselIME::_UpdateInputPosition(LPINPUTCONTEXT lpIMC, POINT pt) { + EZDBGONLYLOGGERPRINT("_UpdateInputPosition: (%d, %d)", pt.x, pt.y); + + // EZDBGONLYLOGGERPRINT("cfCompForm: ptCurrentPos = (%d, %d), rcArea = (%d, + // %d)", lpIMC->cfCompForm.ptCurrentPos.x, + // lpIMC->cfCompForm.ptCurrentPos.y, + // lpIMC->cfCompForm.rcArea.left, lpIMC->cfCompForm.rcArea.top); + // EZDBGONLYLOGGERPRINT("cfCandForm[0]: ptCurrentPos = (%d, %d), rcArea = (%d, + // %d)", lpIMC->cfCandForm[0].ptCurrentPos.x, + // lpIMC->cfCandForm[0].ptCurrentPos.y, lpIMC->cfCandForm[0].rcArea.left, + // lpIMC->cfCandForm[0].rcArea.top); EZDBGONLYLOGGERPRINT("cfCandForm[1]: + // ptCurrentPos = (%d, %d), rcArea = (%d, %d)", + // lpIMC->cfCandForm[1].ptCurrentPos.x, + // lpIMC->cfCandForm[1].ptCurrentPos.y, lpIMC->cfCandForm[1].rcArea.left, + // lpIMC->cfCandForm[1].rcArea.top); + + if (pt.x == -1 && pt.y == -1) { + EZDBGONLYLOGGERPRINT("Caret pos detection required."); + if (!GetCaretPos(&pt)) { + EZDBGONLYLOGGERPRINT("Failed to determine caret pos."); + pt.x = pt.y = 0; + } + } + + ClientToScreen(lpIMC->hWnd, &pt); + if (pt.x < -4096 || pt.x >= 4096 || pt.y < -4096 || pt.y >= 4096) { + EZDBGONLYLOGGERPRINT("Input position out of range, possibly invalid."); + return; + } + + int height = abs(lpIMC->lfFont.W.lfHeight); + if (height == 0) { + HDC hDC = GetDC(lpIMC->hWnd); + SIZE sz = {0}; + GetTextExtentPoint(hDC, L"A", 1, &sz); + height = sz.cy; + ReleaseDC(lpIMC->hWnd, hDC); + } + const int width = 6; + RECT rc; + SetRect(&rc, pt.x, pt.y, pt.x + width, pt.y + height); + EZDBGONLYLOGGERPRINT("Updating input position: (%d, %d)", pt.x, pt.y); + m_client.UpdateInputPosition(rc); } diff --git a/WeaselIME/WeaselIME.h b/WeaselIME/WeaselIME.h index c75332ce3..bc32a0a2b 100644 --- a/WeaselIME/WeaselIME.h +++ b/WeaselIME/WeaselIME.h @@ -4,69 +4,66 @@ #define MAX_COMPOSITION_SIZE 256 -struct CompositionInfo -{ - COMPOSITIONSTRING cs; - WCHAR szCompStr[MAX_COMPOSITION_SIZE]; - WCHAR szResultStr[MAX_COMPOSITION_SIZE]; - void Reset() - { - memset(this, 0, sizeof(*this)); - cs.dwSize = sizeof(*this); - cs.dwCompStrOffset = (DWORD)((ptrdiff_t)&szCompStr - (ptrdiff_t)this); - cs.dwResultStrOffset = (DWORD)((ptrdiff_t)&szResultStr - (ptrdiff_t)this); - } +struct CompositionInfo { + COMPOSITIONSTRING cs; + WCHAR szCompStr[MAX_COMPOSITION_SIZE]; + WCHAR szResultStr[MAX_COMPOSITION_SIZE]; + void Reset() { + memset(this, 0, sizeof(*this)); + cs.dwSize = sizeof(*this); + cs.dwCompStrOffset = (DWORD)((ptrdiff_t)&szCompStr - (ptrdiff_t)this); + cs.dwResultStrOffset = (DWORD)((ptrdiff_t)&szResultStr - (ptrdiff_t)this); + } }; class WeaselIME; -class HIMCMap : public std::map > -{ -public: - HIMCMap() : m_valid(true) {} - ~HIMCMap() { m_valid = false; } - std::mutex& get_mutex() { return m_mutex; } - bool is_valid() const { return m_valid; } -private: - bool m_valid; - std::mutex m_mutex; +class HIMCMap : public std::map > { + public: + HIMCMap() : m_valid(true) {} + ~HIMCMap() { m_valid = false; } + std::mutex& get_mutex() { return m_mutex; } + bool is_valid() const { return m_valid; } + + private: + bool m_valid; + std::mutex m_mutex; }; -class WeaselIME -{ -public: - static HINSTANCE GetModuleInstance(); - static void SetModuleInstance(HINSTANCE hModule); - static HRESULT RegisterUIClass(); - static HRESULT UnregisterUIClass(); - static LPCWSTR GetUIClassName(); - static LRESULT WINAPI UIWndProc(HWND hWnd, UINT uMsg, WPARAM wp, LPARAM lp); - static BOOL IsIMEMessage(UINT uMsg); - static std::shared_ptr GetInstance(HIMC hIMC); - static void Cleanup(); +class WeaselIME { + public: + static HINSTANCE GetModuleInstance(); + static void SetModuleInstance(HINSTANCE hModule); + static HRESULT RegisterUIClass(); + static HRESULT UnregisterUIClass(); + static LPCWSTR GetUIClassName(); + static LRESULT WINAPI UIWndProc(HWND hWnd, UINT uMsg, WPARAM wp, LPARAM lp); + static BOOL IsIMEMessage(UINT uMsg); + static std::shared_ptr GetInstance(HIMC hIMC); + static void Cleanup(); - WeaselIME(HIMC hIMC); - LRESULT OnIMESelect(BOOL fSelect); - LRESULT OnIMEFocus(BOOL fFocus); - LRESULT OnUIMessage(HWND hWnd, UINT uMsg, WPARAM wp, LPARAM lp); - BOOL ProcessKeyEvent(UINT vKey, KeyInfo kinfo, const LPBYTE lpbKeyState); + WeaselIME(HIMC hIMC); + LRESULT OnIMESelect(BOOL fSelect); + LRESULT OnIMEFocus(BOOL fFocus); + LRESULT OnUIMessage(HWND hWnd, UINT uMsg, WPARAM wp, LPARAM lp); + BOOL ProcessKeyEvent(UINT vKey, KeyInfo kinfo, const LPBYTE lpbKeyState); -private: - HRESULT _Initialize(); - HRESULT _Finalize(); - LRESULT _OnIMENotify(LPINPUTCONTEXT lpIMC, WPARAM wp, LPARAM lp); - HRESULT _StartComposition(); - HRESULT _EndComposition(LPCWSTR composition); - HRESULT _AddIMEMessage(UINT msg, WPARAM wp, LPARAM lp); - void _SetCandidatePos(LPINPUTCONTEXT lpIMC); - void _SetCompositionWindow(LPINPUTCONTEXT lpIMC); - void _UpdateInputPosition(LPINPUTCONTEXT lpIMC, POINT pt); + private: + HRESULT _Initialize(); + HRESULT _Finalize(); + LRESULT _OnIMENotify(LPINPUTCONTEXT lpIMC, WPARAM wp, LPARAM lp); + HRESULT _StartComposition(); + HRESULT _EndComposition(LPCWSTR composition); + HRESULT _AddIMEMessage(UINT msg, WPARAM wp, LPARAM lp); + void _SetCandidatePos(LPINPUTCONTEXT lpIMC); + void _SetCompositionWindow(LPINPUTCONTEXT lpIMC); + void _UpdateInputPosition(LPINPUTCONTEXT lpIMC, POINT pt); -private: - static HINSTANCE s_hModule; - static HIMCMap s_instances; - HIMC m_hIMC; - bool m_composing; - bool m_preferCandidatePos; - weasel::Client m_client; + private: + static HINSTANCE s_hModule; + static HIMCMap s_instances; + HIMC m_hIMC; + bool m_composing; + bool m_preferCandidatePos; + weasel::Client m_client; }; diff --git a/WeaselIME/dllmain.cpp b/WeaselIME/dllmain.cpp index 931d00525..4d4ce2661 100644 --- a/WeaselIME/dllmain.cpp +++ b/WeaselIME/dllmain.cpp @@ -2,31 +2,25 @@ #include "stdafx.h" #include "WeaselIME.h" +BOOL APIENTRY DllMain(HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved) { + WeaselIME::SetModuleInstance(hModule); -BOOL APIENTRY DllMain( HMODULE hModule, - DWORD ul_reason_for_call, - LPVOID lpReserved - ) -{ - WeaselIME::SetModuleInstance(hModule); - - switch (ul_reason_for_call) - { - case DLL_PROCESS_ATTACH: - { - HRESULT hr = WeaselIME::RegisterUIClass(); - if (FAILED(hr)) - return FALSE; - } - break; - case DLL_THREAD_ATTACH: - break; - case DLL_THREAD_DETACH: - break; - case DLL_PROCESS_DETACH: - WeaselIME::Cleanup(); - WeaselIME::UnregisterUIClass(); - break; - } - return TRUE; + switch (ul_reason_for_call) { + case DLL_PROCESS_ATTACH: { + HRESULT hr = WeaselIME::RegisterUIClass(); + if (FAILED(hr)) + return FALSE; + } break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + WeaselIME::Cleanup(); + WeaselIME::UnregisterUIClass(); + break; + } + return TRUE; } diff --git a/WeaselIME/ime.cpp b/WeaselIME/ime.cpp index 3f8678a65..698d58f08 100644 --- a/WeaselIME/ime.cpp +++ b/WeaselIME/ime.cpp @@ -1,7 +1,7 @@ #include "stdafx.h" #include "WeaselIME.h" -#pragma warning(disable: 4996) +#pragma warning(disable : 4996) static BOOL g_is_winlogon = FALSE; @@ -9,137 +9,147 @@ static BOOL g_is_winlogon = FALSE; // IME export functions // -BOOL WINAPI ImeInquire(IMEINFO* lpIMEInfo, LPWSTR lpszUIClass, DWORD dwSystemInfoFlags) -{ - if (!lpIMEInfo || !lpszUIClass) - return FALSE; +BOOL WINAPI ImeInquire(IMEINFO* lpIMEInfo, + LPWSTR lpszUIClass, + DWORD dwSystemInfoFlags) { + if (!lpIMEInfo || !lpszUIClass) + return FALSE; - if (dwSystemInfoFlags & IME_SYSINFO_WINLOGON) - { - // disable input method in winlogon.exe - g_is_winlogon = TRUE; - } + if (dwSystemInfoFlags & IME_SYSINFO_WINLOGON) { + // disable input method in winlogon.exe + g_is_winlogon = TRUE; + } - wcscpy(lpszUIClass, WeaselIME::GetUIClassName()); + wcscpy(lpszUIClass, WeaselIME::GetUIClassName()); - lpIMEInfo->dwPrivateDataSize = 0; - lpIMEInfo->fdwProperty = IME_PROP_UNICODE | IME_PROP_SPECIAL_UI; - lpIMEInfo->fdwConversionCaps = IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE; - lpIMEInfo->fdwSentenceCaps = IME_SMODE_NONE; - lpIMEInfo->fdwUICaps = UI_CAP_2700; - lpIMEInfo->fdwSCSCaps = 0; - lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION; + lpIMEInfo->dwPrivateDataSize = 0; + lpIMEInfo->fdwProperty = IME_PROP_UNICODE | IME_PROP_SPECIAL_UI; + lpIMEInfo->fdwConversionCaps = IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE; + lpIMEInfo->fdwSentenceCaps = IME_SMODE_NONE; + lpIMEInfo->fdwUICaps = UI_CAP_2700; + lpIMEInfo->fdwSCSCaps = 0; + lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION; - return TRUE; + return TRUE; } -BOOL WINAPI ImeConfigure(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) -{ - if (g_is_winlogon) return TRUE; +BOOL WINAPI ImeConfigure(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) { + if (g_is_winlogon) + return TRUE; - // TODO: - MessageBox(hWnd, L"本品無設定介面 :)", L"輸入法設定", MB_OK); - return TRUE; + // TODO: + MessageBox(hWnd, L"本品無設定介面 :)", L"輸入法設定", MB_OK); + return TRUE; } -DWORD WINAPI ImeConversionList(HIMC hIMC, LPCTSTR lpSource, LPCANDIDATELIST lpCandList, DWORD dwBufLen, UINT uFlag) -{ - // - return TRUE; +DWORD WINAPI ImeConversionList(HIMC hIMC, + LPCTSTR lpSource, + LPCANDIDATELIST lpCandList, + DWORD dwBufLen, + UINT uFlag) { + // + return TRUE; } -BOOL WINAPI ImeDestroy(UINT uForce) -{ - // - return TRUE; +BOOL WINAPI ImeDestroy(UINT uForce) { + // + return TRUE; } -LRESULT WINAPI ImeEscape(HIMC hIMC, UINT uSubFunc, LPVOID lpData) -{ - // - return TRUE; +LRESULT WINAPI ImeEscape(HIMC hIMC, UINT uSubFunc, LPVOID lpData) { + // + return TRUE; } -BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lpbKeyState) -{ - if (g_is_winlogon) return FALSE; - - BOOL accepted = FALSE; - std::shared_ptr p = WeaselIME::GetInstance(hIMC); - if (!p) - return FALSE; - accepted = p->ProcessKeyEvent(vKey, lKeyData, lpbKeyState); - return accepted; +BOOL WINAPI ImeProcessKey(HIMC hIMC, + UINT vKey, + LPARAM lKeyData, + const LPBYTE lpbKeyState) { + if (g_is_winlogon) + return FALSE; + + BOOL accepted = FALSE; + std::shared_ptr p = WeaselIME::GetInstance(hIMC); + if (!p) + return FALSE; + accepted = p->ProcessKeyEvent(vKey, lKeyData, lpbKeyState); + return accepted; } -BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) -{ - if (g_is_winlogon) return TRUE; +BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) { + if (g_is_winlogon) + return TRUE; - std::shared_ptr p = WeaselIME::GetInstance(hIMC); - if (!p) - return FALSE; - HRESULT hr = p->OnIMESelect(fSelect); - if (FAILED(hr)) - return FALSE; + std::shared_ptr p = WeaselIME::GetInstance(hIMC); + if (!p) + return FALSE; + HRESULT hr = p->OnIMESelect(fSelect); + if (FAILED(hr)) + return FALSE; - return TRUE; + return TRUE; } -BOOL WINAPI ImeSetActiveContext(HIMC hIMC, BOOL fFocus) -{ - if (g_is_winlogon) return TRUE; - - if (hIMC) - { - std::shared_ptr p = WeaselIME::GetInstance(hIMC); - if (!p) - return FALSE; - HRESULT hr = p->OnIMEFocus(fFocus); - if (FAILED(hr)) - return FALSE; - } - - return TRUE; +BOOL WINAPI ImeSetActiveContext(HIMC hIMC, BOOL fFocus) { + if (g_is_winlogon) + return TRUE; + + if (hIMC) { + std::shared_ptr p = WeaselIME::GetInstance(hIMC); + if (!p) + return FALSE; + HRESULT hr = p->OnIMEFocus(fFocus); + if (FAILED(hr)) + return FALSE; + } + + return TRUE; } -UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode, CONST LPBYTE lpbKeyState, LPDWORD lpdwTransKey, UINT fuState, HIMC hIMC) -{ - // - return 0; +UINT WINAPI ImeToAsciiEx(UINT uVKey, + UINT uScanCode, + CONST LPBYTE lpbKeyState, + LPDWORD lpdwTransKey, + UINT fuState, + HIMC hIMC) { + // + return 0; } -BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) -{ - // - return TRUE; +BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) { + // + return TRUE; } -BOOL WINAPI ImeRegisterWord(LPCTSTR lpRead, DWORD dw, LPCTSTR lpStr) -{ - // - return FALSE; +BOOL WINAPI ImeRegisterWord(LPCTSTR lpRead, DWORD dw, LPCTSTR lpStr) { + // + return FALSE; } -BOOL WINAPI ImeUnregisterWord(LPCTSTR lpRead, DWORD dw, LPCTSTR lpStr) -{ - // - return FALSE; +BOOL WINAPI ImeUnregisterWord(LPCTSTR lpRead, DWORD dw, LPCTSTR lpStr) { + // + return FALSE; } -UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUF lp) -{ - // - return 0; +UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUF lp) { + // + return 0; } -UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROC lpfn, LPCTSTR lpRead, DWORD dw, LPCTSTR lpStr, LPVOID lpData) -{ - // - return 0; +UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROC lpfn, + LPCTSTR lpRead, + DWORD dw, + LPCTSTR lpStr, + LPVOID lpData) { + // + return 0; } -BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwComp, LPCVOID lpRead, DWORD dwRead) -{ - // - return FALSE; +BOOL WINAPI ImeSetCompositionString(HIMC hIMC, + DWORD dwIndex, + LPCVOID lpComp, + DWORD dwComp, + LPCVOID lpRead, + DWORD dwRead) { + // + return FALSE; } diff --git a/WeaselIPC/ActionLoader.cpp b/WeaselIPC/ActionLoader.cpp index 225525763..5854afaff 100644 --- a/WeaselIPC/ActionLoader.cpp +++ b/WeaselIPC/ActionLoader.cpp @@ -6,33 +6,26 @@ using namespace weasel; - -Deserializer::Ptr ActionLoader::Create(ResponseParser* pTarget) -{ - return Deserializer::Ptr(new ActionLoader(pTarget)); +Deserializer::Ptr ActionLoader::Create(ResponseParser* pTarget) { + return Deserializer::Ptr(new ActionLoader(pTarget)); } -ActionLoader::ActionLoader(ResponseParser* pTarget) -: Deserializer(pTarget) -{ -} +ActionLoader::ActionLoader(ResponseParser* pTarget) : Deserializer(pTarget) {} -ActionLoader::~ActionLoader() -{ -} +ActionLoader::~ActionLoader() {} + +void ActionLoader::Store(Deserializer::KeyType const& key, + std::wstring const& value) { + if (key.size() == 1) // no extention parts + { + // split value by L"," + std::vector vecAction; + split(vecAction, value, L","); -void ActionLoader::Store(Deserializer::KeyType const& key, std::wstring const& value) -{ - if (key.size() == 1) // no extention parts - { - // split value by L"," - std::vector vecAction; - split(vecAction, value, L","); - - // require specified action deserializers - std::for_each(vecAction.begin(), vecAction.end(), [this](std::wstring& action) - { - Deserializer::Require(action, m_pTarget); - }); - } + // require specified action deserializers + std::for_each(vecAction.begin(), vecAction.end(), + [this](std::wstring& action) { + Deserializer::Require(action, m_pTarget); + }); + } } diff --git a/WeaselIPC/ActionLoader.h b/WeaselIPC/ActionLoader.h index 1459ebd5b..e5b1364c3 100644 --- a/WeaselIPC/ActionLoader.h +++ b/WeaselIPC/ActionLoader.h @@ -1,13 +1,13 @@ #pragma once #include "Deserializer.h" -class ActionLoader : public weasel::Deserializer -{ -public: - ActionLoader(weasel::ResponseParser* pTarget); - virtual ~ActionLoader(); - // store data - virtual void Store(weasel::Deserializer::KeyType const& key, std::wstring const& value); - // factory method - static weasel::Deserializer::Ptr Create(weasel::ResponseParser* pTarget); +class ActionLoader : public weasel::Deserializer { + public: + ActionLoader(weasel::ResponseParser* pTarget); + virtual ~ActionLoader(); + // store data + virtual void Store(weasel::Deserializer::KeyType const& key, + std::wstring const& value); + // factory method + static weasel::Deserializer::Ptr Create(weasel::ResponseParser* pTarget); }; diff --git a/WeaselIPC/Committer.cpp b/WeaselIPC/Committer.cpp index f3af428cb..74ac0d94e 100644 --- a/WeaselIPC/Committer.cpp +++ b/WeaselIPC/Committer.cpp @@ -4,25 +4,18 @@ using namespace weasel; - -Deserializer::Ptr Committer::Create(ResponseParser* pTarget) -{ - return Deserializer::Ptr(new Committer(pTarget)); +Deserializer::Ptr Committer::Create(ResponseParser* pTarget) { + return Deserializer::Ptr(new Committer(pTarget)); } -Committer::Committer(ResponseParser* pTarget) -: Deserializer(pTarget) -{ -} +Committer::Committer(ResponseParser* pTarget) : Deserializer(pTarget) {} -Committer::~Committer() -{ -} +Committer::~Committer() {} -void Committer::Store(Deserializer::KeyType const& key, std::wstring const& value) -{ - if (!m_pTarget->p_commit) - return; - if (key.size() == 1) - *m_pTarget->p_commit = value; +void Committer::Store(Deserializer::KeyType const& key, + std::wstring const& value) { + if (!m_pTarget->p_commit) + return; + if (key.size() == 1) + *m_pTarget->p_commit = value; } diff --git a/WeaselIPC/Committer.h b/WeaselIPC/Committer.h index 28130a41a..fea713f4d 100644 --- a/WeaselIPC/Committer.h +++ b/WeaselIPC/Committer.h @@ -1,13 +1,13 @@ #pragma once #include "Deserializer.h" -class Committer : public weasel::Deserializer -{ -public: - Committer(weasel::ResponseParser* pTarget); - virtual ~Committer(); - // store data - virtual void Store(weasel::Deserializer::KeyType const& key, std::wstring const& value); - // factory method - static weasel::Deserializer::Ptr Create(weasel::ResponseParser* pTarget); +class Committer : public weasel::Deserializer { + public: + Committer(weasel::ResponseParser* pTarget); + virtual ~Committer(); + // store data + virtual void Store(weasel::Deserializer::KeyType const& key, + std::wstring const& value); + // factory method + static weasel::Deserializer::Ptr Create(weasel::ResponseParser* pTarget); }; diff --git a/WeaselIPC/Configurator.cpp b/WeaselIPC/Configurator.cpp index 691bcdda7..a16c4fa22 100644 --- a/WeaselIPC/Configurator.cpp +++ b/WeaselIPC/Configurator.cpp @@ -4,27 +4,20 @@ using namespace weasel; -Deserializer::Ptr Configurator::Create(ResponseParser* pTarget) -{ - return Deserializer::Ptr(new Configurator(pTarget)); +Deserializer::Ptr Configurator::Create(ResponseParser* pTarget) { + return Deserializer::Ptr(new Configurator(pTarget)); } -Configurator::Configurator(ResponseParser* pTarget) - : Deserializer(pTarget) -{ -} +Configurator::Configurator(ResponseParser* pTarget) : Deserializer(pTarget) {} -Configurator::~Configurator() -{ -} +Configurator::~Configurator() {} -void Configurator::Store(Deserializer::KeyType const& key, std::wstring const& value) -{ - if (!m_pTarget->p_context || key.size() < 2) - return; - bool bool_value = (!value.empty() && value != L"0"); - if (key[1] == L"inline_preedit") - { - m_pTarget->p_config->inline_preedit = bool_value; - } +void Configurator::Store(Deserializer::KeyType const& key, + std::wstring const& value) { + if (!m_pTarget->p_context || key.size() < 2) + return; + bool bool_value = (!value.empty() && value != L"0"); + if (key[1] == L"inline_preedit") { + m_pTarget->p_config->inline_preedit = bool_value; + } } diff --git a/WeaselIPC/Configurator.h b/WeaselIPC/Configurator.h index 63100987d..7f2aceff5 100644 --- a/WeaselIPC/Configurator.h +++ b/WeaselIPC/Configurator.h @@ -1,13 +1,13 @@ #pragma once #include "Deserializer.h" -class Configurator : public weasel::Deserializer -{ -public: - Configurator(weasel::ResponseParser* pTarget); - virtual ~Configurator(); - // store data - virtual void Store(weasel::Deserializer::KeyType const& key, std::wstring const& value); - // factory method - static weasel::Deserializer::Ptr Create(weasel::ResponseParser* pTarget); +class Configurator : public weasel::Deserializer { + public: + Configurator(weasel::ResponseParser* pTarget); + virtual ~Configurator(); + // store data + virtual void Store(weasel::Deserializer::KeyType const& key, + std::wstring const& value); + // factory method + static weasel::Deserializer::Ptr Create(weasel::ResponseParser* pTarget); }; diff --git a/WeaselIPC/ContextUpdater.cpp b/WeaselIPC/ContextUpdater.cpp index a3564b80b..271beecca 100644 --- a/WeaselIPC/ContextUpdater.cpp +++ b/WeaselIPC/ContextUpdater.cpp @@ -9,137 +9,116 @@ using namespace weasel; // ContextUpdater -Deserializer::Ptr ContextUpdater::Create(ResponseParser* pTarget) -{ - return Deserializer::Ptr(new ContextUpdater(pTarget)); +Deserializer::Ptr ContextUpdater::Create(ResponseParser* pTarget) { + return Deserializer::Ptr(new ContextUpdater(pTarget)); } ContextUpdater::ContextUpdater(ResponseParser* pTarget) - : Deserializer(pTarget) -{ -} + : Deserializer(pTarget) {} -ContextUpdater::~ContextUpdater() -{ -} +ContextUpdater::~ContextUpdater() {} + +void ContextUpdater::Store(Deserializer::KeyType const& k, + std::wstring const& value) { + if (!m_pTarget->p_context || k.size() < 2) + return; + + if (k[1] == L"preedit") { + _StoreText(m_pTarget->p_context->preedit, k, value); + return; + } -void ContextUpdater::Store(Deserializer::KeyType const& k, std::wstring const& value) -{ - if(!m_pTarget->p_context || k.size() < 2) - return; - - if (k[1] == L"preedit") - { - _StoreText(m_pTarget->p_context->preedit, k, value); - return; - } - - if (k[1] == L"aux") - { - _StoreText(m_pTarget->p_context->aux, k, value); - return; - } - - if (k[1] == L"cand") - { - _StoreCand(k, value); - return; - } + if (k[1] == L"aux") { + _StoreText(m_pTarget->p_context->aux, k, value); + return; + } + + if (k[1] == L"cand") { + _StoreCand(k, value); + return; + } } -void ContextUpdater::_StoreText(Text& target, Deserializer::KeyType k, std::wstring const& value) -{ - if(k.size() == 2) - { - target.clear(); - target.str = value; - return; - } - if(k.size() == 3) - { - // ctx.preedit.cursor - if (k[2] == L"cursor") - { - std::vector vec; - split(vec, value, L","); - if (vec.size() < 2) - return; - - weasel::TextAttribute attr; - attr.type = HIGHLIGHTED; - attr.range.start = _wtoi(vec[0].c_str()); - attr.range.end = _wtoi(vec[1].c_str()); - attr.range.cursor = _wtoi(vec[2].c_str()); - if (attr.range.cursor < attr.range.start || attr.range.cursor > attr.range.end) - { - attr.range.cursor = attr.range.end; - } - - target.attributes.push_back(attr); - return; - } - } +void ContextUpdater::_StoreText(Text& target, + Deserializer::KeyType k, + std::wstring const& value) { + if (k.size() == 2) { + target.clear(); + target.str = value; + return; + } + if (k.size() == 3) { + // ctx.preedit.cursor + if (k[2] == L"cursor") { + std::vector vec; + split(vec, value, L","); + if (vec.size() < 2) + return; + + weasel::TextAttribute attr; + attr.type = HIGHLIGHTED; + attr.range.start = _wtoi(vec[0].c_str()); + attr.range.end = _wtoi(vec[1].c_str()); + attr.range.cursor = _wtoi(vec[2].c_str()); + if (attr.range.cursor < attr.range.start || + attr.range.cursor > attr.range.end) { + attr.range.cursor = attr.range.end; + } + + target.attributes.push_back(attr); + return; + } + } } -void ContextUpdater::_StoreCand(Deserializer::KeyType k, std::wstring const& value) -{ - CandidateInfo& cinfo = m_pTarget->p_context->cinfo; - std::wstringstream ss(value); - boost::archive::text_wiarchive ia(ss); +void ContextUpdater::_StoreCand(Deserializer::KeyType k, + std::wstring const& value) { + CandidateInfo& cinfo = m_pTarget->p_context->cinfo; + std::wstringstream ss(value); + boost::archive::text_wiarchive ia(ss); - ia >> cinfo; + ia >> cinfo; } // StatusUpdater -Deserializer::Ptr StatusUpdater::Create(ResponseParser* pTarget) -{ - return Deserializer::Ptr(new StatusUpdater(pTarget)); +Deserializer::Ptr StatusUpdater::Create(ResponseParser* pTarget) { + return Deserializer::Ptr(new StatusUpdater(pTarget)); } -StatusUpdater::StatusUpdater(ResponseParser* pTarget) -: Deserializer(pTarget) -{ -} +StatusUpdater::StatusUpdater(ResponseParser* pTarget) : Deserializer(pTarget) {} -StatusUpdater::~StatusUpdater() -{ -} +StatusUpdater::~StatusUpdater() {} + +void StatusUpdater::Store(Deserializer::KeyType const& k, + std::wstring const& value) { + if (!m_pTarget->p_status || k.size() < 2) + return; + + bool bool_value = (!value.empty() && value != L"0"); + + if (k[1] == L"schema_id") { + m_pTarget->p_status->schema_id = value; + return; + } + + if (k[1] == L"ascii_mode") { + m_pTarget->p_status->ascii_mode = bool_value; + return; + } + + if (k[1] == L"composing") { + m_pTarget->p_status->composing = bool_value; + return; + } + + if (k[1] == L"disabled") { + m_pTarget->p_status->disabled = bool_value; + return; + } -void StatusUpdater::Store(Deserializer::KeyType const& k, std::wstring const& value) -{ - if(!m_pTarget->p_status || k.size() < 2) - return; - - bool bool_value = (!value.empty() && value != L"0"); - - if (k[1] == L"schema_id") - { - m_pTarget->p_status->schema_id = value; - return; - } - - if (k[1] == L"ascii_mode") - { - m_pTarget->p_status->ascii_mode = bool_value; - return; - } - - if (k[1] == L"composing") - { - m_pTarget->p_status->composing = bool_value; - return; - } - - if (k[1] == L"disabled") - { - m_pTarget->p_status->disabled = bool_value; - return; - } - - if (k[1] == L"full_shape") - { - m_pTarget->p_status->full_shape = bool_value; - return; - } + if (k[1] == L"full_shape") { + m_pTarget->p_status->full_shape = bool_value; + return; + } } diff --git a/WeaselIPC/ContextUpdater.h b/WeaselIPC/ContextUpdater.h index 0b3ff7884..092484ae4 100644 --- a/WeaselIPC/ContextUpdater.h +++ b/WeaselIPC/ContextUpdater.h @@ -1,25 +1,27 @@ #pragma once #include "Deserializer.h" -class ContextUpdater : public weasel::Deserializer -{ -public: - ContextUpdater(weasel::ResponseParser* pTarget); - virtual ~ContextUpdater(); - virtual void Store(weasel::Deserializer::KeyType const& key, std::wstring const& value); - - void _StoreText(weasel::Text& target, Deserializer::KeyType k, std::wstring const& value); - void _StoreCand(Deserializer::KeyType k, std::wstring const& value); +class ContextUpdater : public weasel::Deserializer { + public: + ContextUpdater(weasel::ResponseParser* pTarget); + virtual ~ContextUpdater(); + virtual void Store(weasel::Deserializer::KeyType const& key, + std::wstring const& value); - static weasel::Deserializer::Ptr Create(weasel::ResponseParser* pTarget); + void _StoreText(weasel::Text& target, + Deserializer::KeyType k, + std::wstring const& value); + void _StoreCand(Deserializer::KeyType k, std::wstring const& value); + + static weasel::Deserializer::Ptr Create(weasel::ResponseParser* pTarget); }; -class StatusUpdater : public weasel::Deserializer -{ -public: - StatusUpdater(weasel::ResponseParser* pTarget); - virtual ~StatusUpdater(); - virtual void Store(weasel::Deserializer::KeyType const& key, std::wstring const& value); - - static weasel::Deserializer::Ptr Create(weasel::ResponseParser* pTarget); +class StatusUpdater : public weasel::Deserializer { + public: + StatusUpdater(weasel::ResponseParser* pTarget); + virtual ~StatusUpdater(); + virtual void Store(weasel::Deserializer::KeyType const& key, + std::wstring const& value); + + static weasel::Deserializer::Ptr Create(weasel::ResponseParser* pTarget); }; diff --git a/WeaselIPC/Deserializer.cpp b/WeaselIPC/Deserializer.cpp index b62389725..958b24978 100644 --- a/WeaselIPC/Deserializer.cpp +++ b/WeaselIPC/Deserializer.cpp @@ -8,49 +8,44 @@ using namespace weasel; - std::map Deserializer::s_factories; - -void Deserializer::Initialize(ResponseParser* pTarget) -{ - if (s_factories.empty()) - { - // register factory methods - // TODO: extend the parser's functionality in the future by defining more actions here - Define(L"action", ActionLoader::Create); - Define(L"commit", Committer::Create); - Define(L"ctx", ContextUpdater::Create); - Define(L"status", StatusUpdater::Create); - Define(L"config", Configurator::Create); - Define(L"style", Styler::Create); - } - - // loaded by default - Require(L"action", pTarget); +void Deserializer::Initialize(ResponseParser* pTarget) { + if (s_factories.empty()) { + // register factory methods + // TODO: extend the parser's functionality in the future by defining more + // actions here + Define(L"action", ActionLoader::Create); + Define(L"commit", Committer::Create); + Define(L"ctx", ContextUpdater::Create); + Define(L"status", StatusUpdater::Create); + Define(L"config", Configurator::Create); + Define(L"style", Styler::Create); + } + + // loaded by default + Require(L"action", pTarget); } -void Deserializer::Define(std::wstring const& action, Factory factory) -{ - s_factories[action] = factory; - //s_factories.insert(make_pair(action, factory)); +void Deserializer::Define(std::wstring const& action, Factory factory) { + s_factories[action] = factory; + // s_factories.insert(make_pair(action, factory)); } -bool Deserializer::Require(std::wstring const& action, ResponseParser* pTarget) -{ - if (!pTarget) - return false; +bool Deserializer::Require(std::wstring const& action, + ResponseParser* pTarget) { + if (!pTarget) + return false; - std::map::iterator i = s_factories.find(action); - if (i == s_factories.end()) - { - // unknown action type - return false; - } + std::map::iterator i = s_factories.find(action); + if (i == s_factories.end()) { + // unknown action type + return false; + } - Factory& factory = i->second; + Factory& factory = i->second; - pTarget->deserializers[action] = factory(pTarget); - //pTarget->deserializers.insert(make_pair(action, factory(pTarget))); - return true; + pTarget->deserializers[action] = factory(pTarget); + // pTarget->deserializers.insert(make_pair(action, factory(pTarget))); + return true; } \ No newline at end of file diff --git a/WeaselIPC/Deserializer.h b/WeaselIPC/Deserializer.h index 0d22c250d..c1a1ee452 100644 --- a/WeaselIPC/Deserializer.h +++ b/WeaselIPC/Deserializer.h @@ -2,29 +2,27 @@ #include #include -namespace weasel -{ +namespace weasel { - class Deserializer - { - public: - typedef std::vector KeyType; - typedef std::shared_ptr Ptr; - typedef std::function Factory; +class Deserializer { + public: + typedef std::vector KeyType; + typedef std::shared_ptr Ptr; + typedef std::function Factory; - Deserializer(ResponseParser* pTarget) : m_pTarget(pTarget) {} - virtual ~Deserializer() {} - virtual void Store(KeyType const& key, std::wstring const& value) {} + Deserializer(ResponseParser* pTarget) : m_pTarget(pTarget) {} + virtual ~Deserializer() {} + virtual void Store(KeyType const& key, std::wstring const& value) {} - static void Initialize(ResponseParser* pTarget); - static void Define(std::wstring const& action, Factory factory); - static bool Require(std::wstring const& action, ResponseParser* pTarget); + static void Initialize(ResponseParser* pTarget); + static void Define(std::wstring const& action, Factory factory); + static bool Require(std::wstring const& action, ResponseParser* pTarget); - protected: - ResponseParser* m_pTarget; + protected: + ResponseParser* m_pTarget; - private: - static std::map s_factories; - }; + private: + static std::map s_factories; +}; -} +} // namespace weasel diff --git a/WeaselIPC/PipeChannel.cpp b/WeaselIPC/PipeChannel.cpp index 83139c91f..18365696b 100644 --- a/WeaselIPC/PipeChannel.cpp +++ b/WeaselIPC/PipeChannel.cpp @@ -8,127 +8,118 @@ using namespace boost; #define _ThrowLastError throw ::GetLastError() #define _ThrowCode(__c) throw __c -#define _ThrowIfNot(__c) { DWORD err; if ((err = ::GetLastError()) != __c) throw err; } - -PipeChannelBase::PipeChannelBase(std::wstring &&pn_cmd, size_t bs = 4 * 1024, SECURITY_ATTRIBUTES *s = NULL) - : pname(pn_cmd), - write_stream(nullptr), - buff_size(bs), - buffer(std::make_unique(bs)), - hpipe(INVALID_HANDLE_VALUE), - has_body(false), - sa(s) {}; - -PipeChannelBase::PipeChannelBase(PipeChannelBase &&r) - : write_stream(std::move(r.write_stream)), - pname(std::move(r.pname)), - buff_size(r.buff_size), - buffer(std::move(r.buffer)), - hpipe(r.hpipe), - has_body(r.has_body), - sa(r.sa) {}; - - -PipeChannelBase::~PipeChannelBase() -{ - _FinalizePipe(hpipe); +#define _ThrowIfNot(__c) \ + { \ + DWORD err; \ + if ((err = ::GetLastError()) != __c) \ + throw err; \ + } + +PipeChannelBase::PipeChannelBase(std::wstring&& pn_cmd, + size_t bs = 4 * 1024, + SECURITY_ATTRIBUTES* s = NULL) + : pname(pn_cmd), + write_stream(nullptr), + buff_size(bs), + buffer(std::make_unique(bs)), + hpipe(INVALID_HANDLE_VALUE), + has_body(false), + sa(s){}; + +PipeChannelBase::PipeChannelBase(PipeChannelBase&& r) + : write_stream(std::move(r.write_stream)), + pname(std::move(r.pname)), + buff_size(r.buff_size), + buffer(std::move(r.buffer)), + hpipe(r.hpipe), + has_body(r.has_body), + sa(r.sa){}; + +PipeChannelBase::~PipeChannelBase() { + _FinalizePipe(hpipe); } -bool PipeChannelBase::_Ensure() -{ - try { - if (_Invalid(hpipe)) { - hpipe = _Connect(pname.c_str()); - return !_Invalid(hpipe); - } - } - catch (...) { - return false; - } - - return true; +bool PipeChannelBase::_Ensure() { + try { + if (_Invalid(hpipe)) { + hpipe = _Connect(pname.c_str()); + return !_Invalid(hpipe); + } + } catch (...) { + return false; + } + + return true; } -HANDLE PipeChannelBase::_Connect(const wchar_t *name) -{ - HANDLE pipe = INVALID_HANDLE_VALUE; - while (_Invalid(pipe = _TryConnect())) - ::WaitNamedPipe(name, 500); - DWORD mode = PIPE_READMODE_MESSAGE; - if (!SetNamedPipeHandleState(pipe, &mode, NULL, NULL)) { - _ThrowLastError; - } - return pipe; +HANDLE PipeChannelBase::_Connect(const wchar_t* name) { + HANDLE pipe = INVALID_HANDLE_VALUE; + while (_Invalid(pipe = _TryConnect())) + ::WaitNamedPipe(name, 500); + DWORD mode = PIPE_READMODE_MESSAGE; + if (!SetNamedPipeHandleState(pipe, &mode, NULL, NULL)) { + _ThrowLastError; + } + return pipe; } -void PipeChannelBase::_Reconnect() -{ - _FinalizePipe(hpipe); - _Ensure(); +void PipeChannelBase::_Reconnect() { + _FinalizePipe(hpipe); + _Ensure(); } -HANDLE PipeChannelBase::_TryConnect() -{ - auto pipe = ::CreateFile(pname.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); - if (!_Invalid(pipe)) { - // connected to the pipe - return pipe; - } - // being busy is not really an error since we just need to wait. - _ThrowIfNot(ERROR_PIPE_BUSY); - // All pipe instances are busy - return INVALID_HANDLE_VALUE; +HANDLE PipeChannelBase::_TryConnect() { + auto pipe = ::CreateFile(pname.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, 0, NULL); + if (!_Invalid(pipe)) { + // connected to the pipe + return pipe; + } + // being busy is not really an error since we just need to wait. + _ThrowIfNot(ERROR_PIPE_BUSY); + // All pipe instances are busy + return INVALID_HANDLE_VALUE; } -size_t PipeChannelBase::_WritePipe(HANDLE pipe, size_t s, char *b) -{ - DWORD lwritten; - if (!::WriteFile(pipe, b, s, &lwritten, NULL) || lwritten <= 0) { - _ThrowLastError; - } - ::FlushFileBuffers(pipe); - return lwritten; +size_t PipeChannelBase::_WritePipe(HANDLE pipe, size_t s, char* b) { + DWORD lwritten; + if (!::WriteFile(pipe, b, s, &lwritten, NULL) || lwritten <= 0) { + _ThrowLastError; + } + ::FlushFileBuffers(pipe); + return lwritten; } -void PipeChannelBase::_FinalizePipe(HANDLE &p) -{ - if (!_Invalid(p)) { - DisconnectNamedPipe(p); - CloseHandle(p); - } - p = INVALID_HANDLE_VALUE; +void PipeChannelBase::_FinalizePipe(HANDLE& p) { + if (!_Invalid(p)) { + DisconnectNamedPipe(p); + CloseHandle(p); + } + p = INVALID_HANDLE_VALUE; } -void PipeChannelBase::_Receive(HANDLE pipe, LPVOID msg, size_t rec_len) -{ - DWORD lread; - BOOL success = ::ReadFile(pipe, msg, rec_len, &lread, NULL); - if (!success) { - _ThrowIfNot(ERROR_MORE_DATA); - - memset(buffer.get(), 0, buff_size); - success = ::ReadFile(pipe, buffer.get(), buff_size, &lread, NULL); - if (!success) { - _ThrowLastError; - } - } - has_body = false; +void PipeChannelBase::_Receive(HANDLE pipe, LPVOID msg, size_t rec_len) { + DWORD lread; + BOOL success = ::ReadFile(pipe, msg, rec_len, &lread, NULL); + if (!success) { + _ThrowIfNot(ERROR_MORE_DATA); + + memset(buffer.get(), 0, buff_size); + success = ::ReadFile(pipe, buffer.get(), buff_size, &lread, NULL); + if (!success) { + _ThrowLastError; + } + } + has_body = false; } -HANDLE PipeChannelBase::_ConnectServerPipe(std::wstring &pn) -{ - HANDLE pipe = CreateNamedPipe( - pn.c_str(), - PIPE_ACCESS_DUPLEX, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, - buff_size, - buff_size, - 0, - sa); - if (pipe == INVALID_HANDLE_VALUE || !::ConnectNamedPipe(pipe, NULL)) { - _ThrowLastError; - } - return pipe; +HANDLE PipeChannelBase::_ConnectServerPipe(std::wstring& pn) { + HANDLE pipe = + CreateNamedPipe(pn.c_str(), PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, buff_size, buff_size, 0, sa); + if (pipe == INVALID_HANDLE_VALUE || !::ConnectNamedPipe(pipe, NULL)) { + _ThrowLastError; + } + return pipe; } - diff --git a/WeaselIPC/ResponseParser.cpp b/WeaselIPC/ResponseParser.cpp index 5095705ee..7aaf7d202 100644 --- a/WeaselIPC/ResponseParser.cpp +++ b/WeaselIPC/ResponseParser.cpp @@ -5,61 +5,65 @@ using namespace weasel; -ResponseParser::ResponseParser(std::wstring* commit, Context* context, Status* status, Config* config, UIStyle* style) - : p_commit(commit), p_context(context), p_status(status), p_config(config), p_style(style) -{ - Deserializer::Initialize(this); +ResponseParser::ResponseParser(std::wstring* commit, + Context* context, + Status* status, + Config* config, + UIStyle* style) + : p_commit(commit), + p_context(context), + p_status(status), + p_config(config), + p_style(style) { + Deserializer::Initialize(this); } -bool ResponseParser::operator() (LPWSTR buffer, UINT length) -{ - wbufferstream bs(buffer, length); - std::wstring line; - while (bs.good()) - { - std::getline(bs, line); - if (!bs.good()) - return false; +bool ResponseParser::operator()(LPWSTR buffer, UINT length) { + wbufferstream bs(buffer, length); + std::wstring line; + while (bs.good()) { + std::getline(bs, line); + if (!bs.good()) + return false; - // file ends - if (line == L".") - break; - - Feed(line); - } - return bs.good(); + // file ends + if (line == L".") + break; + + Feed(line); + } + return bs.good(); } -void ResponseParser::Feed(const std::wstring& line) -{ - // ignore blank lines and comments - if (line.empty() || line.find_first_of(L'#') == 0) - return; +void ResponseParser::Feed(const std::wstring& line) { + // ignore blank lines and comments + if (line.empty() || line.find_first_of(L'#') == 0) + return; + + Deserializer::KeyType key; + std::wstring value; - Deserializer::KeyType key; - std::wstring value; + // extract key (split by L'.') and value + std::wstring::size_type sep_pos = line.find_first_of(L'='); + if (sep_pos == std::wstring::npos) + return; + split(key, line.substr(0, sep_pos), L"."); + if (key.empty()) + return; + value = line.substr(sep_pos + 1); - // extract key (split by L'.') and value - std::wstring::size_type sep_pos = line.find_first_of(L'='); - if (sep_pos == std::wstring::npos) - return; - split(key, line.substr(0, sep_pos), L"."); - if (key.empty()) - return; - value = line.substr(sep_pos + 1); + // first part of the key serve as action type + std::wstring const& action = key[0]; - // first part of the key serve as action type - std::wstring const& action = key[0]; - - // get required action deserializer instance - std::map::iterator i = deserializers.find(action); - if (i == deserializers.end()) - { - // line ignored... since corresponding deserializer is not active - return; - } + // get required action deserializer instance + std::map::iterator i = + deserializers.find(action); + if (i == deserializers.end()) { + // line ignored... since corresponding deserializer is not active + return; + } - // dispatch - Deserializer::Ptr p = i->second; - p->Store(key, value); + // dispatch + Deserializer::Ptr p = i->second; + p->Store(key, value); } diff --git a/WeaselIPC/Styler.cpp b/WeaselIPC/Styler.cpp index 8a28330ef..42698e97f 100644 --- a/WeaselIPC/Styler.cpp +++ b/WeaselIPC/Styler.cpp @@ -4,27 +4,22 @@ using namespace weasel; -Styler::Styler(weasel::ResponseParser * pTarget) - : Deserializer(pTarget) -{ -} +Styler::Styler(weasel::ResponseParser* pTarget) : Deserializer(pTarget) {} -Styler::~Styler() -{ -} +Styler::~Styler() {} -void Styler::Store(weasel::Deserializer::KeyType const & key, std::wstring const & value) -{ - if (!m_pTarget->p_style) return; +void Styler::Store(weasel::Deserializer::KeyType const& key, + std::wstring const& value) { + if (!m_pTarget->p_style) + return; - UIStyle &sty = *m_pTarget->p_style; - std::wstringstream ss(value); - boost::archive::text_wiarchive ia(ss); + UIStyle& sty = *m_pTarget->p_style; + std::wstringstream ss(value); + boost::archive::text_wiarchive ia(ss); - ia >> sty; + ia >> sty; } -weasel::Deserializer::Ptr Styler::Create(weasel::ResponseParser * pTarget) -{ - return Deserializer::Ptr(new Styler(pTarget)); +weasel::Deserializer::Ptr Styler::Create(weasel::ResponseParser* pTarget) { + return Deserializer::Ptr(new Styler(pTarget)); } diff --git a/WeaselIPC/Styler.h b/WeaselIPC/Styler.h index 089344053..2963b25b3 100644 --- a/WeaselIPC/Styler.h +++ b/WeaselIPC/Styler.h @@ -1,16 +1,16 @@ #pragma once namespace weasel { - class Deserializr; +class Deserializr; } -class Styler : public weasel::Deserializer -{ -public: - Styler(weasel::ResponseParser* pTarget); - virtual ~Styler(); - // store data - virtual void Store(weasel::Deserializer::KeyType const& key, std::wstring const& value); - // factory method - static weasel::Deserializer::Ptr Create(weasel::ResponseParser* pTarget); +class Styler : public weasel::Deserializer { + public: + Styler(weasel::ResponseParser* pTarget); + virtual ~Styler(); + // store data + virtual void Store(weasel::Deserializer::KeyType const& key, + std::wstring const& value); + // factory method + static weasel::Deserializer::Ptr Create(weasel::ResponseParser* pTarget); }; diff --git a/WeaselIPC/WeaselClientImpl.cpp b/WeaselIPC/WeaselClientImpl.cpp index 04a5a3469..26122ad50 100644 --- a/WeaselIPC/WeaselClientImpl.cpp +++ b/WeaselIPC/WeaselClientImpl.cpp @@ -5,330 +5,281 @@ using namespace weasel; ClientImpl::ClientImpl() - : session_id(0), - channel(GetPipeName()), - is_ime(false) -{ - _InitializeClientInfo(); + : session_id(0), channel(GetPipeName()), is_ime(false) { + _InitializeClientInfo(); } -ClientImpl::~ClientImpl() -{ - if (channel.Connected()) - Disconnect(); +ClientImpl::~ClientImpl() { + if (channel.Connected()) + Disconnect(); } -//http://stackoverflow.com/questions/557081/how-do-i-get-the-hmodule-for-the-currently-executing-code -HMODULE GetCurrentModule() -{ // NB: XP+ solution! +// http://stackoverflow.com/questions/557081/how-do-i-get-the-hmodule-for-the-currently-executing-code +HMODULE GetCurrentModule() { // NB: XP+ solution! HMODULE hModule = NULL; - GetModuleHandleEx( - GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - (LPCTSTR)GetCurrentModule, - &hModule); + GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + (LPCTSTR)GetCurrentModule, &hModule); return hModule; } -void ClientImpl::_InitializeClientInfo() -{ - // get app name - WCHAR exe_path[MAX_PATH] = {0}; - GetModuleFileName(NULL, exe_path, MAX_PATH); - std::wstring path = exe_path; - size_t separator_pos = path.find_last_of(L"\\/"); - if (separator_pos < path.size()) - app_name = path.substr(separator_pos + 1); - else - app_name = path; - to_lower(app_name); - // determine client type - GetModuleFileName(GetCurrentModule(), exe_path, MAX_PATH); - path = exe_path; - to_lower(path); - is_ime = ends_with(path, L".ime"); -} +void ClientImpl::_InitializeClientInfo() { + // get app name + WCHAR exe_path[MAX_PATH] = {0}; + GetModuleFileName(NULL, exe_path, MAX_PATH); + std::wstring path = exe_path; + size_t separator_pos = path.find_last_of(L"\\/"); + if (separator_pos < path.size()) + app_name = path.substr(separator_pos + 1); + else + app_name = path; + to_lower(app_name); + // determine client type + GetModuleFileName(GetCurrentModule(), exe_path, MAX_PATH); + path = exe_path; + to_lower(path); + is_ime = ends_with(path, L".ime"); +} -bool ClientImpl::Connect(ServerLauncher const& launcher) -{ - return channel.Connect(); +bool ClientImpl::Connect(ServerLauncher const& launcher) { + return channel.Connect(); } -void ClientImpl::Disconnect() -{ - if (_Active()) - EndSession(); - channel.Disconnect(); +void ClientImpl::Disconnect() { + if (_Active()) + EndSession(); + channel.Disconnect(); } -void ClientImpl::ShutdownServer() -{ - _SendMessage(WEASEL_IPC_SHUTDOWN_SERVER, 0, 0); +void ClientImpl::ShutdownServer() { + _SendMessage(WEASEL_IPC_SHUTDOWN_SERVER, 0, 0); } -bool ClientImpl::ProcessKeyEvent(KeyEvent const& keyEvent) -{ - if (!_Active()) - return false; +bool ClientImpl::ProcessKeyEvent(KeyEvent const& keyEvent) { + if (!_Active()) + return false; - LRESULT ret = _SendMessage(WEASEL_IPC_PROCESS_KEY_EVENT, keyEvent, session_id); - return ret != 0; + LRESULT ret = + _SendMessage(WEASEL_IPC_PROCESS_KEY_EVENT, keyEvent, session_id); + return ret != 0; } -bool ClientImpl::CommitComposition() -{ - if (!_Active()) - return false; +bool ClientImpl::CommitComposition() { + if (!_Active()) + return false; - LRESULT ret = _SendMessage(WEASEL_IPC_COMMIT_COMPOSITION, 0, session_id); - return ret != 0; + LRESULT ret = _SendMessage(WEASEL_IPC_COMMIT_COMPOSITION, 0, session_id); + return ret != 0; } -bool ClientImpl::ClearComposition() -{ - if (!_Active()) - return false; +bool ClientImpl::ClearComposition() { + if (!_Active()) + return false; - LRESULT ret = _SendMessage(WEASEL_IPC_CLEAR_COMPOSITION, 0, session_id); - return ret != 0; + LRESULT ret = _SendMessage(WEASEL_IPC_CLEAR_COMPOSITION, 0, session_id); + return ret != 0; } -bool ClientImpl::SelectCandidateOnCurrentPage(size_t index) -{ - if(!_Active()) - return false; - LRESULT ret = _SendMessage(WEASEL_IPC_SELECT_CANDIDATE_ON_CURRENT_PAGE, index, session_id); - return ret != 0; +bool ClientImpl::SelectCandidateOnCurrentPage(size_t index) { + if (!_Active()) + return false; + LRESULT ret = _SendMessage(WEASEL_IPC_SELECT_CANDIDATE_ON_CURRENT_PAGE, index, + session_id); + return ret != 0; } -bool ClientImpl::HighlightCandidateOnCurrentPage(size_t index) -{ - if(!_Active()) - return false; - LRESULT ret = _SendMessage(WEASEL_IPC_HIGHLIGHT_CANDIDATE_ON_CURRENT_PAGE, index, session_id); - return ret != 0; +bool ClientImpl::HighlightCandidateOnCurrentPage(size_t index) { + if (!_Active()) + return false; + LRESULT ret = _SendMessage(WEASEL_IPC_HIGHLIGHT_CANDIDATE_ON_CURRENT_PAGE, + index, session_id); + return ret != 0; } -bool ClientImpl::ChangePage(bool backward) -{ - if(!_Active()) - return false; - LRESULT ret = _SendMessage(WEASEL_IPC_CHANGE_PAGE, backward, session_id); - return ret != 0; +bool ClientImpl::ChangePage(bool backward) { + if (!_Active()) + return false; + LRESULT ret = _SendMessage(WEASEL_IPC_CHANGE_PAGE, backward, session_id); + return ret != 0; } -void ClientImpl::UpdateInputPosition(RECT const& rc) -{ - if (!_Active()) - return; - /* - 移位标志 = 1bit == 0 - height:0~127 = 7bit - top:-2048~2047 = 12bit(有符号) - left:-2048~2047 = 12bit(有符号) +void ClientImpl::UpdateInputPosition(RECT const& rc) { + if (!_Active()) + return; + /* + 移位标志 = 1bit == 0 + height:0~127 = 7bit + top:-2048~2047 = 12bit(有符号) + left:-2048~2047 = 12bit(有符号) - 高解析度下: - 移位标志 = 1bit == 1 - height:0~254 = 7bit(舍弃低1位) - top:-4096~4094 = 12bit(有符号,舍弃低1位) - left:-4096~4094 = 12bit(有符号,舍弃低1位) - */ - int hi_res = static_cast(rc.bottom - rc.top >= 128 || - rc.left < -2048 || rc.left >= 2048 || rc.top < -2048 || rc.top >= 2048); - int left = max(-2048, min(2047, rc.left >> hi_res)); - int top = max(-2048, min(2047, rc.top >> hi_res)); - int height = max(0, min(127, (rc.bottom - rc.top) >> hi_res)); - DWORD compressed_rect = ((hi_res & 0x01) << 31) | ((height & 0x7f) << 24) | - ((top & 0xfff) << 12) | (left & 0xfff); - _SendMessage(WEASEL_IPC_UPDATE_INPUT_POS, compressed_rect, session_id); + 高解析度下: + 移位标志 = 1bit == 1 + height:0~254 = 7bit(舍弃低1位) + top:-4096~4094 = 12bit(有符号,舍弃低1位) + left:-4096~4094 = 12bit(有符号,舍弃低1位) + */ + int hi_res = + static_cast(rc.bottom - rc.top >= 128 || rc.left < -2048 || + rc.left >= 2048 || rc.top < -2048 || rc.top >= 2048); + int left = max(-2048, min(2047, rc.left >> hi_res)); + int top = max(-2048, min(2047, rc.top >> hi_res)); + int height = max(0, min(127, (rc.bottom - rc.top) >> hi_res)); + DWORD compressed_rect = ((hi_res & 0x01) << 31) | ((height & 0x7f) << 24) | + ((top & 0xfff) << 12) | (left & 0xfff); + _SendMessage(WEASEL_IPC_UPDATE_INPUT_POS, compressed_rect, session_id); } -void ClientImpl::FocusIn() -{ - DWORD client_caps = 0; /* TODO */ - _SendMessage(WEASEL_IPC_FOCUS_IN, client_caps, session_id); +void ClientImpl::FocusIn() { + DWORD client_caps = 0; /* TODO */ + _SendMessage(WEASEL_IPC_FOCUS_IN, client_caps, session_id); } -void ClientImpl::FocusOut() -{ - _SendMessage(WEASEL_IPC_FOCUS_OUT, 0, session_id); +void ClientImpl::FocusOut() { + _SendMessage(WEASEL_IPC_FOCUS_OUT, 0, session_id); } -void ClientImpl::TrayCommand(UINT menuId) -{ - _SendMessage(WEASEL_IPC_TRAY_COMMAND, menuId, session_id); +void ClientImpl::TrayCommand(UINT menuId) { + _SendMessage(WEASEL_IPC_TRAY_COMMAND, menuId, session_id); } -void ClientImpl::StartSession() -{ - if (_Active() && Echo()) - return; +void ClientImpl::StartSession() { + if (_Active() && Echo()) + return; - _WriteClientInfo(); - UINT ret = _SendMessage(WEASEL_IPC_START_SESSION, 0, 0); - session_id = ret; + _WriteClientInfo(); + UINT ret = _SendMessage(WEASEL_IPC_START_SESSION, 0, 0); + session_id = ret; } -void ClientImpl::EndSession() -{ - _SendMessage(WEASEL_IPC_END_SESSION, 0, session_id); - session_id = 0; +void ClientImpl::EndSession() { + _SendMessage(WEASEL_IPC_END_SESSION, 0, session_id); + session_id = 0; } -void ClientImpl::StartMaintenance() -{ - _SendMessage(WEASEL_IPC_START_MAINTENANCE, 0, 0); - session_id = 0; +void ClientImpl::StartMaintenance() { + _SendMessage(WEASEL_IPC_START_MAINTENANCE, 0, 0); + session_id = 0; } -void ClientImpl::EndMaintenance() -{ - _SendMessage(WEASEL_IPC_END_MAINTENANCE, 0, 0); - session_id = 0; +void ClientImpl::EndMaintenance() { + _SendMessage(WEASEL_IPC_END_MAINTENANCE, 0, 0); + session_id = 0; } -bool ClientImpl::Echo() -{ - if (!_Active()) - return false; +bool ClientImpl::Echo() { + if (!_Active()) + return false; - UINT serverEcho = _SendMessage(WEASEL_IPC_ECHO, 0, session_id); - return (serverEcho == session_id); + UINT serverEcho = _SendMessage(WEASEL_IPC_ECHO, 0, session_id); + return (serverEcho == session_id); } -bool ClientImpl::GetResponseData(ResponseHandler const& handler) -{ - if (!handler) { - return false; - } +bool ClientImpl::GetResponseData(ResponseHandler const& handler) { + if (!handler) { + return false; + } - return channel.HandleResponseData(handler); + return channel.HandleResponseData(handler); } - -bool ClientImpl::_WriteClientInfo() -{ - channel << L"action=session\n"; - channel << L"session.client_app=" << app_name.c_str() << L"\n"; - channel << L"session.client_type=" << (is_ime ? L"ime" : L"tsf") << L"\n"; - channel << L".\n"; - return true; +bool ClientImpl::_WriteClientInfo() { + channel << L"action=session\n"; + channel << L"session.client_app=" << app_name.c_str() << L"\n"; + channel << L"session.client_type=" << (is_ime ? L"ime" : L"tsf") << L"\n"; + channel << L".\n"; + return true; } - -LRESULT ClientImpl::_SendMessage(WEASEL_IPC_COMMAND Msg, DWORD wParam, DWORD lParam) -{ - try { - PipeMessage req{ Msg, wParam, lParam }; - return channel.Transact(req); - } - catch (DWORD /* ex */) { - return 0; - } +LRESULT ClientImpl::_SendMessage(WEASEL_IPC_COMMAND Msg, + DWORD wParam, + DWORD lParam) { + try { + PipeMessage req{Msg, wParam, lParam}; + return channel.Transact(req); + } catch (DWORD /* ex */) { + return 0; + } } +Client::Client() : m_pImpl(new ClientImpl()) {} -Client::Client() - : m_pImpl(new ClientImpl()) -{} - -Client::~Client() -{ - if (m_pImpl) - delete m_pImpl; +Client::~Client() { + if (m_pImpl) + delete m_pImpl; } -bool Client::Connect(ServerLauncher launcher) -{ - return m_pImpl->Connect(launcher); +bool Client::Connect(ServerLauncher launcher) { + return m_pImpl->Connect(launcher); } -void Client::Disconnect() -{ - m_pImpl->Disconnect(); +void Client::Disconnect() { + m_pImpl->Disconnect(); } -void Client::ShutdownServer() -{ - m_pImpl->ShutdownServer(); +void Client::ShutdownServer() { + m_pImpl->ShutdownServer(); } -bool Client::ProcessKeyEvent(KeyEvent const& keyEvent) -{ - return m_pImpl->ProcessKeyEvent(keyEvent); +bool Client::ProcessKeyEvent(KeyEvent const& keyEvent) { + return m_pImpl->ProcessKeyEvent(keyEvent); } -bool Client::CommitComposition() -{ - return m_pImpl->CommitComposition(); +bool Client::CommitComposition() { + return m_pImpl->CommitComposition(); } -bool Client::ClearComposition() -{ - return m_pImpl->ClearComposition(); +bool Client::ClearComposition() { + return m_pImpl->ClearComposition(); } -bool Client::SelectCandidateOnCurrentPage(size_t index) -{ - return m_pImpl->SelectCandidateOnCurrentPage(index); +bool Client::SelectCandidateOnCurrentPage(size_t index) { + return m_pImpl->SelectCandidateOnCurrentPage(index); } -bool Client::HighlightCandidateOnCurrentPage(size_t index) -{ - return m_pImpl->HighlightCandidateOnCurrentPage(index); +bool Client::HighlightCandidateOnCurrentPage(size_t index) { + return m_pImpl->HighlightCandidateOnCurrentPage(index); } -bool Client::ChangePage(bool backward) -{ - return m_pImpl->ChangePage(backward); +bool Client::ChangePage(bool backward) { + return m_pImpl->ChangePage(backward); } -void Client::UpdateInputPosition(RECT const& rc) -{ - m_pImpl->UpdateInputPosition(rc); +void Client::UpdateInputPosition(RECT const& rc) { + m_pImpl->UpdateInputPosition(rc); } -void Client::FocusIn() -{ - m_pImpl->FocusIn(); +void Client::FocusIn() { + m_pImpl->FocusIn(); } -void Client::FocusOut() -{ - m_pImpl->FocusOut(); +void Client::FocusOut() { + m_pImpl->FocusOut(); } -void Client::StartSession() -{ - m_pImpl->StartSession(); +void Client::StartSession() { + m_pImpl->StartSession(); } -void Client::EndSession() -{ - m_pImpl->EndSession(); +void Client::EndSession() { + m_pImpl->EndSession(); } -void Client::StartMaintenance() -{ - m_pImpl->StartMaintenance(); +void Client::StartMaintenance() { + m_pImpl->StartMaintenance(); } -void Client::EndMaintenance() -{ - m_pImpl->EndMaintenance(); +void Client::EndMaintenance() { + m_pImpl->EndMaintenance(); } -void Client::TrayCommand(UINT menuId) -{ - m_pImpl->TrayCommand(menuId); +void Client::TrayCommand(UINT menuId) { + m_pImpl->TrayCommand(menuId); } -bool Client::Echo() -{ - return m_pImpl->Echo(); +bool Client::Echo() { + return m_pImpl->Echo(); } -bool Client::GetResponseData(ResponseHandler handler) -{ - return m_pImpl->GetResponseData(handler); +bool Client::GetResponseData(ResponseHandler handler) { + return m_pImpl->GetResponseData(handler); } diff --git a/WeaselIPC/WeaselClientImpl.h b/WeaselIPC/WeaselClientImpl.h index 7c16d7c52..760279286 100644 --- a/WeaselIPC/WeaselClientImpl.h +++ b/WeaselIPC/WeaselClientImpl.h @@ -2,50 +2,48 @@ #include #include -namespace weasel -{ - - class ClientImpl - { - public: - ClientImpl(); - ~ClientImpl(); - - bool Connect(ServerLauncher const& launcher); - void Disconnect(); - void ShutdownServer(); - void StartSession(); - void EndSession(); - void StartMaintenance(); - void EndMaintenance(); - bool Echo(); - bool ProcessKeyEvent(KeyEvent const& keyEvent); - bool CommitComposition(); - bool ClearComposition(); - bool SelectCandidateOnCurrentPage(size_t index); - bool HighlightCandidateOnCurrentPage(size_t index); - bool ChangePage(bool backward); - void UpdateInputPosition(RECT const& rc); - void FocusIn(); - void FocusOut(); - void TrayCommand(UINT menuId); - bool GetResponseData(ResponseHandler const& handler); - - protected: - void _InitializeClientInfo(); - bool _WriteClientInfo(); - - LRESULT _SendMessage(WEASEL_IPC_COMMAND Msg, DWORD wParam, DWORD lParam); - - bool _Connected() const { return channel.Connected(); } - bool _Active() const { return channel.Connected() && session_id != 0; } - - private: - UINT session_id; - std::wstring app_name; - bool is_ime; - - PipeChannel channel; - }; - -} \ No newline at end of file +namespace weasel { + +class ClientImpl { + public: + ClientImpl(); + ~ClientImpl(); + + bool Connect(ServerLauncher const& launcher); + void Disconnect(); + void ShutdownServer(); + void StartSession(); + void EndSession(); + void StartMaintenance(); + void EndMaintenance(); + bool Echo(); + bool ProcessKeyEvent(KeyEvent const& keyEvent); + bool CommitComposition(); + bool ClearComposition(); + bool SelectCandidateOnCurrentPage(size_t index); + bool HighlightCandidateOnCurrentPage(size_t index); + bool ChangePage(bool backward); + void UpdateInputPosition(RECT const& rc); + void FocusIn(); + void FocusOut(); + void TrayCommand(UINT menuId); + bool GetResponseData(ResponseHandler const& handler); + + protected: + void _InitializeClientInfo(); + bool _WriteClientInfo(); + + LRESULT _SendMessage(WEASEL_IPC_COMMAND Msg, DWORD wParam, DWORD lParam); + + bool _Connected() const { return channel.Connected(); } + bool _Active() const { return channel.Connected() && session_id != 0; } + + private: + UINT session_id; + std::wstring app_name; + bool is_ime; + + PipeChannel channel; +}; + +} // namespace weasel \ No newline at end of file diff --git a/WeaselIPCServer/SecurityAttribute.cpp b/WeaselIPCServer/SecurityAttribute.cpp index b503e337e..6047b0908 100644 --- a/WeaselIPCServer/SecurityAttribute.cpp +++ b/WeaselIPCServer/SecurityAttribute.cpp @@ -6,77 +6,73 @@ #define SDDL_ALL_APP_PACKAGES TEXT("AC") #endif -#define LOW_INTEGRITY_SDDL_SACL SDDL_SACL \ - SDDL_DELIMINATOR \ - SDDL_ACE_BEGIN \ - SDDL_MANDATORY_LABEL \ - SDDL_SEPERATOR \ - SDDL_SEPERATOR \ - SDDL_NO_WRITE_UP \ - SDDL_SEPERATOR \ - SDDL_SEPERATOR \ - SDDL_SEPERATOR \ - SDDL_ML_LOW \ - SDDL_ACE_END +#define LOW_INTEGRITY_SDDL_SACL \ + SDDL_SACL \ + SDDL_DELIMINATOR \ + SDDL_ACE_BEGIN \ + SDDL_MANDATORY_LABEL \ + SDDL_SEPERATOR \ + SDDL_SEPERATOR \ + SDDL_NO_WRITE_UP \ + SDDL_SEPERATOR \ + SDDL_SEPERATOR \ + SDDL_SEPERATOR \ + SDDL_ML_LOW \ + SDDL_ACE_END -#define LOCAL_SYSTEM_FILE_ACCESS SDDL_ACE_BEGIN \ - SDDL_ACCESS_ALLOWED \ - SDDL_SEPERATOR \ - SDDL_SEPERATOR \ - SDDL_FILE_ALL \ - SDDL_SEPERATOR \ - SDDL_SEPERATOR \ - SDDL_SEPERATOR \ - SDDL_LOCAL_SYSTEM \ - SDDL_ACE_END +#define LOCAL_SYSTEM_FILE_ACCESS \ + SDDL_ACE_BEGIN \ + SDDL_ACCESS_ALLOWED \ + SDDL_SEPERATOR \ + SDDL_SEPERATOR \ + SDDL_FILE_ALL \ + SDDL_SEPERATOR \ + SDDL_SEPERATOR \ + SDDL_SEPERATOR \ + SDDL_LOCAL_SYSTEM \ + SDDL_ACE_END -#define EVERYONE_FILE_ACCESS SDDL_ACE_BEGIN \ - SDDL_ACCESS_ALLOWED \ - SDDL_SEPERATOR \ - SDDL_SEPERATOR \ - SDDL_FILE_ALL \ - SDDL_SEPERATOR \ - SDDL_SEPERATOR \ - SDDL_SEPERATOR \ - SDDL_EVERYONE \ - SDDL_ACE_END +#define EVERYONE_FILE_ACCESS \ + SDDL_ACE_BEGIN \ + SDDL_ACCESS_ALLOWED \ + SDDL_SEPERATOR \ + SDDL_SEPERATOR \ + SDDL_FILE_ALL \ + SDDL_SEPERATOR \ + SDDL_SEPERATOR \ + SDDL_SEPERATOR \ + SDDL_EVERYONE \ + SDDL_ACE_END -#define ALL_APP_PACKAGES_FILE_ACCESS SDDL_ACE_BEGIN \ - SDDL_ACCESS_ALLOWED \ - SDDL_SEPERATOR \ - SDDL_SEPERATOR \ - SDDL_FILE_ALL \ - SDDL_SEPERATOR \ - SDDL_SEPERATOR \ - SDDL_SEPERATOR \ - SDDL_ALL_APP_PACKAGES \ - SDDL_ACE_END +#define ALL_APP_PACKAGES_FILE_ACCESS \ + SDDL_ACE_BEGIN \ + SDDL_ACCESS_ALLOWED \ + SDDL_SEPERATOR \ + SDDL_SEPERATOR \ + SDDL_FILE_ALL \ + SDDL_SEPERATOR \ + SDDL_SEPERATOR \ + SDDL_SEPERATOR \ + SDDL_ALL_APP_PACKAGES \ + SDDL_ACE_END namespace weasel { - void SecurityAttribute::_Init() - { - // Privileges for UWP and IE protected mode - // https://stackoverflow.com/questions/39138674/accessing-named-pipe-servers-from-within-ie-epm-bho +void SecurityAttribute::_Init() { + // Privileges for UWP and IE protected mode + // https://stackoverflow.com/questions/39138674/accessing-named-pipe-servers-from-within-ie-epm-bho - ConvertStringSecurityDescriptorToSecurityDescriptor( - LOW_INTEGRITY_SDDL_SACL - SDDL_DACL - SDDL_DELIMINATOR - LOCAL_SYSTEM_FILE_ACCESS - EVERYONE_FILE_ACCESS - ALL_APP_PACKAGES_FILE_ACCESS - , - SDDL_REVISION_1, - &pd, - NULL); - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.lpSecurityDescriptor = pd; - sa.bInheritHandle = TRUE; - } + ConvertStringSecurityDescriptorToSecurityDescriptor( + LOW_INTEGRITY_SDDL_SACL SDDL_DACL SDDL_DELIMINATOR + LOCAL_SYSTEM_FILE_ACCESS EVERYONE_FILE_ACCESS + ALL_APP_PACKAGES_FILE_ACCESS, + SDDL_REVISION_1, &pd, NULL); + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = pd; + sa.bInheritHandle = TRUE; +} - SECURITY_ATTRIBUTES *SecurityAttribute::get_attr() - { - return &sa; - } -}; +SECURITY_ATTRIBUTES* SecurityAttribute::get_attr() { + return &sa; +} +}; // namespace weasel diff --git a/WeaselIPCServer/SecurityAttribute.h b/WeaselIPCServer/SecurityAttribute.h index f53568b73..54b7e5d3c 100644 --- a/WeaselIPCServer/SecurityAttribute.h +++ b/WeaselIPCServer/SecurityAttribute.h @@ -1,15 +1,16 @@ #pragma once -#include // for security attributes constants -#include // for ACL +#include // for security attributes constants +#include // for ACL namespace weasel { - class SecurityAttribute { - private: - PSECURITY_DESCRIPTOR pd; - SECURITY_ATTRIBUTES sa; - void _Init(); - public: - SecurityAttribute() : pd(NULL) { _Init(); } - SECURITY_ATTRIBUTES *get_attr(); - }; +class SecurityAttribute { + private: + PSECURITY_DESCRIPTOR pd; + SECURITY_ATTRIBUTES sa; + void _Init(); + + public: + SecurityAttribute() : pd(NULL) { _Init(); } + SECURITY_ATTRIBUTES* get_attr(); }; +}; // namespace weasel diff --git a/WeaselIPCServer/WeaselServerImpl.cpp b/WeaselIPCServer/WeaselServerImpl.cpp index a7c9cd75b..3b5075b42 100644 --- a/WeaselIPCServer/WeaselServerImpl.cpp +++ b/WeaselIPCServer/WeaselServerImpl.cpp @@ -5,471 +5,464 @@ #include namespace weasel { - class PipeServer : public PipeChannel - { - public: - using ServerRunner = std::function; - using Respond = std::function; - using ServerHandler = std::function; +class PipeServer : public PipeChannel { + public: + using ServerRunner = std::function; + using Respond = std::function; + using ServerHandler = std::function; - PipeServer(std::wstring &&pn_cmd, SECURITY_ATTRIBUTES *s); + PipeServer(std::wstring&& pn_cmd, SECURITY_ATTRIBUTES* s); - public: - void Listen(ServerHandler const &handler); - /* Get a server runner */ - ServerRunner GetServerRunner(ServerHandler const &handler); - private: - void _ProcessPipeThread(HANDLE pipe, ServerHandler const &handler); - }; -} + public: + void Listen(ServerHandler const& handler); + /* Get a server runner */ + ServerRunner GetServerRunner(ServerHandler const& handler); + private: + void _ProcessPipeThread(HANDLE pipe, ServerHandler const& handler); +}; +} // namespace weasel using namespace weasel; extern CAppModule _Module; ServerImpl::ServerImpl() - : m_pRequestHandler(NULL), - m_darkMode(IsUserDarkMode()), - channel(std::make_unique(GetPipeName(), sa.get_attr())) -{ - m_hUser32Module = GetModuleHandle(_T("user32.dll")); -} - -ServerImpl::~ServerImpl() -{ - _Finailize(); -} - -void ServerImpl::_Finailize() -{ - if (pipeThread != nullptr) { - pipeThread->interrupt(); - pipeThread = nullptr; - } - else { - // avoid finalize again - return; - } - - if (IsWindow()) - { - DestroyWindow(); - } -} - -LRESULT ServerImpl::OnColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) -{ - if (IsUserDarkMode() != m_darkMode) { - m_darkMode = IsUserDarkMode(); - m_pRequestHandler->UpdateColorTheme(m_darkMode); - } - return 0; -} - -LRESULT ServerImpl::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) -{ - // not neccessary... - ::SetWindowText(m_hWnd, WEASEL_IPC_WINDOW); - return 0; -} - -LRESULT ServerImpl::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) -{ - Stop(); - return 0; -} - -LRESULT ServerImpl::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) -{ - bHandled = FALSE; - return 1; -} - -LRESULT ServerImpl::OnQueryEndSystemSession(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) -{ - return TRUE; -} - -LRESULT ServerImpl::OnEndSystemSession(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) -{ - if (m_pRequestHandler) - { - m_pRequestHandler->Finalize(); - m_pRequestHandler = nullptr; - } - return 0; -} - -LRESULT ServerImpl::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) -{ - UINT uID = LOWORD(wParam); - switch (uID) { - case ID_WEASELTRAY_ENABLE_ASCII: - m_pRequestHandler->SetOption(lParam, "ascii_mode", true); - return 0; - case ID_WEASELTRAY_DISABLE_ASCII: - m_pRequestHandler->SetOption(lParam, "ascii_mode", false); - return 0; - default:; - } - - std::map::iterator it = m_MenuHandlers.find(uID); - if (it == m_MenuHandlers.end()) - { - bHandled = FALSE; - return 0; - } - it->second(); // execute command - return 0; -} - -DWORD ServerImpl::OnCommand(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam) -{ - BOOL handled = TRUE; - OnCommand(uMsg, wParam, lParam, handled); - return handled; + : m_pRequestHandler(NULL), + m_darkMode(IsUserDarkMode()), + channel(std::make_unique(GetPipeName(), sa.get_attr())) { + m_hUser32Module = GetModuleHandle(_T("user32.dll")); +} + +ServerImpl::~ServerImpl() { + _Finailize(); +} + +void ServerImpl::_Finailize() { + if (pipeThread != nullptr) { + pipeThread->interrupt(); + pipeThread = nullptr; + } else { + // avoid finalize again + return; + } + + if (IsWindow()) { + DestroyWindow(); + } +} + +LRESULT ServerImpl::OnColorChange(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled) { + if (IsUserDarkMode() != m_darkMode) { + m_darkMode = IsUserDarkMode(); + m_pRequestHandler->UpdateColorTheme(m_darkMode); + } + return 0; +} + +LRESULT ServerImpl::OnCreate(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled) { + // not neccessary... + ::SetWindowText(m_hWnd, WEASEL_IPC_WINDOW); + return 0; +} + +LRESULT ServerImpl::OnClose(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled) { + Stop(); + return 0; +} + +LRESULT ServerImpl::OnDestroy(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled) { + bHandled = FALSE; + return 1; +} + +LRESULT ServerImpl::OnQueryEndSystemSession(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled) { + return TRUE; +} + +LRESULT ServerImpl::OnEndSystemSession(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled) { + if (m_pRequestHandler) { + m_pRequestHandler->Finalize(); + m_pRequestHandler = nullptr; + } + return 0; +} + +LRESULT ServerImpl::OnCommand(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled) { + UINT uID = LOWORD(wParam); + switch (uID) { + case ID_WEASELTRAY_ENABLE_ASCII: + m_pRequestHandler->SetOption(lParam, "ascii_mode", true); + return 0; + case ID_WEASELTRAY_DISABLE_ASCII: + m_pRequestHandler->SetOption(lParam, "ascii_mode", false); + return 0; + default:; + } + + std::map::iterator it = m_MenuHandlers.find(uID); + if (it == m_MenuHandlers.end()) { + bHandled = FALSE; + return 0; + } + it->second(); // execute command + return 0; +} + +DWORD ServerImpl::OnCommand(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam) { + BOOL handled = TRUE; + OnCommand(uMsg, wParam, lParam, handled); + return handled; +} + +int ServerImpl::Start() { + std::wstring instanceName = L"(WEASEL)Furandōru-Sukāretto-"; + instanceName += getUsername(); + HANDLE hMutexOneInstance = ::CreateMutex(NULL, FALSE, instanceName.c_str()); + bool areYouOK = (::GetLastError() == ERROR_ALREADY_EXISTS || + ::GetLastError() == ERROR_ACCESS_DENIED); + + if (areYouOK) { + return 0; // assure single instance + } + + HWND hwnd = Create(NULL); + + return (int)hwnd; +} + +int ServerImpl::Stop() { + // DO NOT exit process or finalize here + // Let WeaselServer handle this + PostMessage(WM_QUIT); + return 0; +} + +int ServerImpl::Run() { + // This workaround causes a VC internal error: + // void PipeServer::Listen(ServerHandler handler); + // + // auto handler = boost::bind(&ServerImpl::HandlePipeMessage, this); + // auto listener = boost::bind(&PipeServer::Listen, channel.get(), handler); + // + + auto listener = [this](PipeMessage msg, PipeServer::Respond resp) -> void { + HandlePipeMessage(msg, resp); + }; + pipeThread = std::make_unique( + [this, &listener]() { channel->Listen(listener); }); + + CMessageLoop theLoop; + _Module.AddMessageLoop(&theLoop); + int nRet = theLoop.Run(); + _Module.RemoveMessageLoop(); + return nRet; +} + +DWORD ServerImpl::OnEcho(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam) { + if (!m_pRequestHandler) + return 0; + return m_pRequestHandler->FindSession(lParam); +} + +DWORD ServerImpl::OnStartSession(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam) { + if (!m_pRequestHandler) + return 0; + return m_pRequestHandler->AddSession( + reinterpret_cast(channel->ReceiveBuffer()), + [this](std::wstring& msg) -> bool { + *channel << msg; + return true; + }); +} + +DWORD ServerImpl::OnEndSession(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam) { + if (!m_pRequestHandler) + return 0; + return m_pRequestHandler->RemoveSession(lParam); +} + +DWORD ServerImpl::OnKeyEvent(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam) { + if (!m_pRequestHandler /* || !m_pSharedMemory*/) + return 0; + + auto eat = [this](std::wstring& msg) -> bool { + *channel << msg; + return true; + }; + return m_pRequestHandler->ProcessKeyEvent(KeyEvent(wParam), lParam, eat); +} + +DWORD ServerImpl::OnShutdownServer(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam) { + Stop(); + return 0; +} + +DWORD ServerImpl::OnFocusIn(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam) { + if (!m_pRequestHandler) + return 0; + m_pRequestHandler->FocusIn(wParam, lParam); + return 0; +} + +DWORD ServerImpl::OnFocusOut(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam) { + if (!m_pRequestHandler) + return 0; + m_pRequestHandler->FocusOut(wParam, lParam); + return 0; +} + +DWORD ServerImpl::OnUpdateInputPosition(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam) { + if (!m_pRequestHandler) + return 0; + /* + * 移位标志 = 1bit == 0 + * height: 0~127 = 7bit + * top:-2048~2047 = 12bit(有符号) + * left:-2048~2047 = 12bit(有符号) + * + * 高解析度下: + * 移位标志 = 1bit == 1 + * height: 0~254 = 7bit(舍弃低1位) + * top: -4096~4094 = 12bit(有符号,舍弃低1位) + * left: -4096~4094 = 12bit(有符号,舍弃低1位) + */ + RECT rc; + int hi_res = (wParam >> 31) & 0x01; + rc.left = ((wParam & 0x7ff) - (wParam & 0x800)) << hi_res; + rc.top = (((wParam >> 12) & 0x7ff) - ((wParam >> 12) & 0x800)) << hi_res; + const int width = 6; + int height = ((wParam >> 24) & 0x7f) << hi_res; + rc.right = rc.left + width; + rc.bottom = rc.top + height; + + { + using PPTLPFPMDPI = BOOL(WINAPI*)(HWND, LPPOINT); + PPTLPFPMDPI PhysicalToLogicalPointForPerMonitorDPI = + (PPTLPFPMDPI)::GetProcAddress(m_hUser32Module, + "PhysicalToLogicalPointForPerMonitorDPI"); + POINT lt = {rc.left, rc.top}; + POINT rb = {rc.right, rc.bottom}; + PhysicalToLogicalPointForPerMonitorDPI(NULL, <); + PhysicalToLogicalPointForPerMonitorDPI(NULL, &rb); + rc = {lt.x, lt.y, rb.x, rb.y}; + } + + m_pRequestHandler->UpdateInputPosition(rc, lParam); + return 0; +} + +DWORD ServerImpl::OnStartMaintenance(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam) { + if (m_pRequestHandler) + m_pRequestHandler->StartMaintenance(); + return 0; +} + +DWORD ServerImpl::OnEndMaintenance(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam) { + if (m_pRequestHandler) + m_pRequestHandler->EndMaintenance(); + return 0; +} + +DWORD ServerImpl::OnCommitComposition(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam) { + if (m_pRequestHandler) + m_pRequestHandler->CommitComposition(lParam); + return 0; +} + +DWORD ServerImpl::OnClearComposition(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam) { + if (m_pRequestHandler) + m_pRequestHandler->ClearComposition(lParam); + return 0; +} + +DWORD ServerImpl::OnSelectCandidateOnCurrentPage(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam) { + if (m_pRequestHandler) + m_pRequestHandler->SelectCandidateOnCurrentPage(wParam, lParam); + return 0; +} + +DWORD ServerImpl::OnHighlightCandidateOnCurrentPage(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam) { + if (m_pRequestHandler) { + auto eat = [this](std::wstring& msg) -> bool { + *channel << msg; + return true; + }; + m_pRequestHandler->HighlightCandidateOnCurrentPage(wParam, lParam, eat); + } + return 0; +} + +DWORD ServerImpl::OnChangePage(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam) { + if (m_pRequestHandler) { + auto eat = [this](std::wstring& msg) -> bool { + *channel << msg; + return true; + }; + m_pRequestHandler->ChangePage(wParam, lParam, eat); + } + return 0; +} + +#define MAP_PIPE_MSG_HANDLE(__msg, __wParam, __lParam) \ + { \ + auto lParam = __lParam; \ + auto wParam = __wParam; \ + LRESULT _result = 0; \ + switch (__msg) { +#define PIPE_MSG_HANDLE(__msg, __func) \ + case __msg: \ + _result = __func(__msg, wParam, lParam); \ + break; + +#define END_MAP_PIPE_MSG_HANDLE(__result) \ + } \ + __result = _result; \ + } + +template +void ServerImpl::HandlePipeMessage(PipeMessage pipe_msg, _Resp resp) { + DWORD result; + + MAP_PIPE_MSG_HANDLE(pipe_msg.Msg, pipe_msg.wParam, pipe_msg.lParam) + PIPE_MSG_HANDLE(WEASEL_IPC_ECHO, OnEcho) + PIPE_MSG_HANDLE(WEASEL_IPC_START_SESSION, OnStartSession) + PIPE_MSG_HANDLE(WEASEL_IPC_END_SESSION, OnEndSession) + PIPE_MSG_HANDLE(WEASEL_IPC_PROCESS_KEY_EVENT, OnKeyEvent) + PIPE_MSG_HANDLE(WEASEL_IPC_SHUTDOWN_SERVER, OnShutdownServer) + PIPE_MSG_HANDLE(WEASEL_IPC_FOCUS_IN, OnFocusIn) + PIPE_MSG_HANDLE(WEASEL_IPC_FOCUS_OUT, OnFocusOut) + PIPE_MSG_HANDLE(WEASEL_IPC_UPDATE_INPUT_POS, OnUpdateInputPosition) + PIPE_MSG_HANDLE(WEASEL_IPC_START_MAINTENANCE, OnStartMaintenance) + PIPE_MSG_HANDLE(WEASEL_IPC_END_MAINTENANCE, OnEndMaintenance) + PIPE_MSG_HANDLE(WEASEL_IPC_COMMIT_COMPOSITION, OnCommitComposition) + PIPE_MSG_HANDLE(WEASEL_IPC_CLEAR_COMPOSITION, OnClearComposition); + PIPE_MSG_HANDLE(WEASEL_IPC_SELECT_CANDIDATE_ON_CURRENT_PAGE, + OnSelectCandidateOnCurrentPage); + PIPE_MSG_HANDLE(WEASEL_IPC_HIGHLIGHT_CANDIDATE_ON_CURRENT_PAGE, + OnHighlightCandidateOnCurrentPage); + PIPE_MSG_HANDLE(WEASEL_IPC_CHANGE_PAGE, OnChangePage); + PIPE_MSG_HANDLE(WEASEL_IPC_TRAY_COMMAND, OnCommand); + END_MAP_PIPE_MSG_HANDLE(result); + + resp(result); +} + +PipeServer::PipeServer(std::wstring&& pn_cmd, SECURITY_ATTRIBUTES* s) + : PipeChannel(std::move(pn_cmd), s) {} + +void PipeServer::Listen(ServerHandler const& handler) { + for (;;) { + HANDLE pipe = INVALID_HANDLE_VALUE; + try { + boost::this_thread::interruption_point(); + pipe = _ConnectServerPipe(pname); + boost::thread th( + [&handler, pipe, this] { _ProcessPipeThread(pipe, handler); }); + } catch (DWORD ex) { + _FinalizePipe(pipe); + } + boost::this_thread::interruption_point(); + } +} + +PipeServer::ServerRunner PipeServer::GetServerRunner( + ServerHandler const& handler) { + return [&handler, this]() { Listen(handler); }; +} + +void PipeServer::_ProcessPipeThread(HANDLE pipe, ServerHandler const& handler) { + try { + for (;;) { + Res msg; + _Receive(pipe, &msg, sizeof(msg)); + handler(msg, [this, pipe](Msg resp) { _Send(pipe, resp); }); + } + } catch (...) { + _FinalizePipe(pipe); + } } -int ServerImpl::Start() -{ - std::wstring instanceName = L"(WEASEL)Furandōru-Sukāretto-"; - instanceName += getUsername(); - HANDLE hMutexOneInstance = ::CreateMutex(NULL, FALSE, instanceName.c_str()); - bool areYouOK = (::GetLastError() == ERROR_ALREADY_EXISTS || - ::GetLastError() == ERROR_ACCESS_DENIED); - - if (areYouOK) { - return 0; // assure single instance - } - - HWND hwnd = Create(NULL); - - return (int)hwnd; -} - -int ServerImpl::Stop() -{ - // DO NOT exit process or finalize here - // Let WeaselServer handle this - PostMessage(WM_QUIT); - return 0; -} - - - -int ServerImpl::Run() -{ - - // This workaround causes a VC internal error: - // void PipeServer::Listen(ServerHandler handler); - // - // auto handler = boost::bind(&ServerImpl::HandlePipeMessage, this); - // auto listener = boost::bind(&PipeServer::Listen, channel.get(), handler); - // - - auto listener = [this](PipeMessage msg, PipeServer::Respond resp) -> void { - HandlePipeMessage(msg, resp); - }; - pipeThread = std::make_unique([this, &listener]() { - channel->Listen(listener); - }); - - CMessageLoop theLoop; - _Module.AddMessageLoop(&theLoop); - int nRet = theLoop.Run(); - _Module.RemoveMessageLoop(); - return nRet; -} - - - -DWORD ServerImpl::OnEcho(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam) -{ - if (!m_pRequestHandler) - return 0; - return m_pRequestHandler->FindSession(lParam); -} - -DWORD ServerImpl::OnStartSession(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam) -{ - if (!m_pRequestHandler) - return 0; - return m_pRequestHandler->AddSession( - reinterpret_cast(channel->ReceiveBuffer()), - [this](std::wstring &msg) -> bool { - *channel << msg; - return true; - } - ); -} - -DWORD ServerImpl::OnEndSession(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam) -{ - if (!m_pRequestHandler) - return 0; - return m_pRequestHandler->RemoveSession(lParam); -} - -DWORD ServerImpl::OnKeyEvent(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam) -{ - if (!m_pRequestHandler/* || !m_pSharedMemory*/) - return 0; - - auto eat = [this](std::wstring &msg) -> bool { - *channel << msg; - return true; - }; - return m_pRequestHandler->ProcessKeyEvent(KeyEvent(wParam), lParam, eat); -} - -DWORD ServerImpl::OnShutdownServer(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam) -{ - Stop(); - return 0; -} - -DWORD ServerImpl::OnFocusIn(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam) -{ - if (!m_pRequestHandler) - return 0; - m_pRequestHandler->FocusIn(wParam, lParam); - return 0; -} - -DWORD ServerImpl::OnFocusOut(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam) -{ - if (!m_pRequestHandler) - return 0; - m_pRequestHandler->FocusOut(wParam, lParam); - return 0; -} - -DWORD ServerImpl::OnUpdateInputPosition(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam) -{ - if (!m_pRequestHandler) - return 0; - /* - * 移位标志 = 1bit == 0 - * height: 0~127 = 7bit - * top:-2048~2047 = 12bit(有符号) - * left:-2048~2047 = 12bit(有符号) - * - * 高解析度下: - * 移位标志 = 1bit == 1 - * height: 0~254 = 7bit(舍弃低1位) - * top: -4096~4094 = 12bit(有符号,舍弃低1位) - * left: -4096~4094 = 12bit(有符号,舍弃低1位) - */ - RECT rc; - int hi_res = (wParam >> 31) & 0x01; - rc.left = ((wParam & 0x7ff) - (wParam & 0x800)) << hi_res; - rc.top = (((wParam >> 12) & 0x7ff) - ((wParam >> 12) & 0x800)) << hi_res; - const int width = 6; - int height = ((wParam >> 24) & 0x7f) << hi_res; - rc.right = rc.left + width; - rc.bottom = rc.top + height; - - { - using PPTLPFPMDPI = BOOL (WINAPI *)(HWND, LPPOINT); - PPTLPFPMDPI PhysicalToLogicalPointForPerMonitorDPI = (PPTLPFPMDPI)::GetProcAddress(m_hUser32Module, "PhysicalToLogicalPointForPerMonitorDPI"); - POINT lt = { rc.left, rc.top }; - POINT rb = { rc.right, rc.bottom }; - PhysicalToLogicalPointForPerMonitorDPI(NULL, <); - PhysicalToLogicalPointForPerMonitorDPI(NULL, &rb); - rc = { lt.x, lt.y, rb.x, rb.y }; - } - - m_pRequestHandler->UpdateInputPosition(rc, lParam); - return 0; -} - -DWORD ServerImpl::OnStartMaintenance(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam) -{ - if (m_pRequestHandler) - m_pRequestHandler->StartMaintenance(); - return 0; -} - -DWORD ServerImpl::OnEndMaintenance(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam) -{ - if (m_pRequestHandler) - m_pRequestHandler->EndMaintenance(); - return 0; -} - -DWORD ServerImpl::OnCommitComposition(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam) -{ - if (m_pRequestHandler) - m_pRequestHandler->CommitComposition(lParam); - return 0; -} - -DWORD ServerImpl::OnClearComposition(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam) -{ - if (m_pRequestHandler) - m_pRequestHandler->ClearComposition(lParam); - return 0; -} - -DWORD ServerImpl::OnSelectCandidateOnCurrentPage(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam) -{ - if(m_pRequestHandler) - m_pRequestHandler->SelectCandidateOnCurrentPage(wParam, lParam); - return 0; -} - -DWORD ServerImpl::OnHighlightCandidateOnCurrentPage(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam) -{ - if(m_pRequestHandler) - { - auto eat = [this](std::wstring &msg) -> bool { - *channel << msg; - return true; - }; - m_pRequestHandler->HighlightCandidateOnCurrentPage(wParam, lParam, eat); - } - return 0; -} - -DWORD ServerImpl::OnChangePage(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam) -{ - if(m_pRequestHandler) - { - auto eat = [this](std::wstring &msg) -> bool { - *channel << msg; - return true; - }; - m_pRequestHandler->ChangePage(wParam, lParam, eat); - } - return 0; -} - -#define MAP_PIPE_MSG_HANDLE(__msg, __wParam, __lParam) {\ -auto lParam = __lParam;\ -auto wParam = __wParam;\ -LRESULT _result = 0;\ -switch (__msg) {\ - -#define PIPE_MSG_HANDLE(__msg, __func) \ -case __msg:\ - _result = __func(__msg, wParam, lParam);\ - break;\ - -#define END_MAP_PIPE_MSG_HANDLE(__result) }__result = _result; } - -template -void ServerImpl::HandlePipeMessage(PipeMessage pipe_msg, _Resp resp) -{ - DWORD result; - - MAP_PIPE_MSG_HANDLE(pipe_msg.Msg, pipe_msg.wParam, pipe_msg.lParam) - PIPE_MSG_HANDLE(WEASEL_IPC_ECHO, OnEcho) - PIPE_MSG_HANDLE(WEASEL_IPC_START_SESSION, OnStartSession) - PIPE_MSG_HANDLE(WEASEL_IPC_END_SESSION, OnEndSession) - PIPE_MSG_HANDLE(WEASEL_IPC_PROCESS_KEY_EVENT, OnKeyEvent) - PIPE_MSG_HANDLE(WEASEL_IPC_SHUTDOWN_SERVER, OnShutdownServer) - PIPE_MSG_HANDLE(WEASEL_IPC_FOCUS_IN, OnFocusIn) - PIPE_MSG_HANDLE(WEASEL_IPC_FOCUS_OUT, OnFocusOut) - PIPE_MSG_HANDLE(WEASEL_IPC_UPDATE_INPUT_POS, OnUpdateInputPosition) - PIPE_MSG_HANDLE(WEASEL_IPC_START_MAINTENANCE, OnStartMaintenance) - PIPE_MSG_HANDLE(WEASEL_IPC_END_MAINTENANCE, OnEndMaintenance) - PIPE_MSG_HANDLE(WEASEL_IPC_COMMIT_COMPOSITION, OnCommitComposition) - PIPE_MSG_HANDLE(WEASEL_IPC_CLEAR_COMPOSITION, OnClearComposition); - PIPE_MSG_HANDLE(WEASEL_IPC_SELECT_CANDIDATE_ON_CURRENT_PAGE, OnSelectCandidateOnCurrentPage); - PIPE_MSG_HANDLE(WEASEL_IPC_HIGHLIGHT_CANDIDATE_ON_CURRENT_PAGE, OnHighlightCandidateOnCurrentPage); - PIPE_MSG_HANDLE(WEASEL_IPC_CHANGE_PAGE, OnChangePage); - PIPE_MSG_HANDLE(WEASEL_IPC_TRAY_COMMAND, OnCommand); - END_MAP_PIPE_MSG_HANDLE(result); - - resp(result); -} - -PipeServer::PipeServer(std::wstring &&pn_cmd, SECURITY_ATTRIBUTES *s) - : PipeChannel(std::move(pn_cmd), s) -{} - -void PipeServer::Listen(ServerHandler const &handler) -{ - for (;;) { - HANDLE pipe = INVALID_HANDLE_VALUE; - try { - boost::this_thread::interruption_point(); - pipe = _ConnectServerPipe(pname); - boost::thread th([&handler, pipe, this] { - _ProcessPipeThread(pipe, handler); - }); - } - catch (DWORD ex) { - _FinalizePipe(pipe); - } - boost::this_thread::interruption_point(); - } -} - -PipeServer::ServerRunner PipeServer::GetServerRunner(ServerHandler const &handler) -{ - return [&handler, this]() { - Listen(handler); - }; -} - -void PipeServer::_ProcessPipeThread(HANDLE pipe, ServerHandler const &handler) -{ - try { - for (;;) { - Res msg; - _Receive(pipe, &msg, sizeof(msg)); - handler(msg, [this, pipe](Msg resp) { - _Send(pipe, resp); - }); - } - } - catch (...) { - _FinalizePipe(pipe); - } -} - - - // weasel::Server -Server::Server() - : m_pImpl(new ServerImpl) -{} +Server::Server() : m_pImpl(new ServerImpl) {} -Server::~Server() -{ - if (m_pImpl) - delete m_pImpl; +Server::~Server() { + if (m_pImpl) + delete m_pImpl; } -int Server::Start() -{ - return m_pImpl->Start(); +int Server::Start() { + return m_pImpl->Start(); } -int Server::Stop() -{ - return m_pImpl->Stop(); +int Server::Stop() { + return m_pImpl->Stop(); } -int Server::Run() -{ - return m_pImpl->Run(); +int Server::Run() { + return m_pImpl->Run(); } -void Server::SetRequestHandler(RequestHandler* pHandler) -{ - m_pImpl->SetRequestHandler(pHandler); +void Server::SetRequestHandler(RequestHandler* pHandler) { + m_pImpl->SetRequestHandler(pHandler); } -void Server::AddMenuHandler(UINT uID, CommandHandler handler) -{ - m_pImpl->AddMenuHandler(uID, handler); +void Server::AddMenuHandler(UINT uID, CommandHandler handler) { + m_pImpl->AddMenuHandler(uID, handler); } -HWND Server::GetHWnd() -{ - return m_pImpl->m_hWnd; +HWND Server::GetHWnd() { + return m_pImpl->m_hWnd; } diff --git a/WeaselIPCServer/WeaselServerImpl.h b/WeaselIPCServer/WeaselServerImpl.h index d3973d622..a4d123ddb 100644 --- a/WeaselIPCServer/WeaselServerImpl.h +++ b/WeaselIPCServer/WeaselServerImpl.h @@ -1,91 +1,103 @@ #pragma once #include #include -#include // for security attributes constants -#include // for ACL +#include // for security attributes constants +#include // for ACL #include #include #include "SecurityAttribute.h" -namespace weasel -{ - class PipeServer; - - typedef CWinTraits ServerWinTraits; +namespace weasel { +class PipeServer; - class ServerImpl : - public CWindowImpl - //class ServerImpl - { - public: - DECLARE_WND_CLASS (WEASEL_IPC_WINDOW) +typedef CWinTraits ServerWinTraits; - BEGIN_MSG_MAP(WEASEL_IPC_WINDOW) - MESSAGE_HANDLER(WM_CREATE, OnCreate) - MESSAGE_HANDLER(WM_DESTROY, OnDestroy) - MESSAGE_HANDLER(WM_CLOSE, OnClose) - MESSAGE_HANDLER(WM_QUERYENDSESSION, OnQueryEndSystemSession) - MESSAGE_HANDLER(WM_ENDSESSION, OnEndSystemSession) - MESSAGE_HANDLER(WM_DWMCOLORIZATIONCOLORCHANGED, OnColorChange) - MESSAGE_HANDLER(WM_SETTINGCHANGE, OnColorChange) - MESSAGE_HANDLER(WM_COMMAND, OnCommand) - END_MSG_MAP() +class ServerImpl : public CWindowImpl +// class ServerImpl +{ + public: + DECLARE_WND_CLASS(WEASEL_IPC_WINDOW) - LRESULT OnColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); - LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); - LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); - LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); - LRESULT OnQueryEndSystemSession(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); - LRESULT OnEndSystemSession(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); - LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); - DWORD OnCommand(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); - DWORD OnEcho(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); - DWORD OnStartSession(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); - DWORD OnEndSession(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); - DWORD OnKeyEvent(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); - DWORD OnShutdownServer(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); - DWORD OnFocusIn(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); - DWORD OnFocusOut(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); - DWORD OnUpdateInputPosition(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); - DWORD OnStartMaintenance(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); - DWORD OnEndMaintenance(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); - DWORD OnCommitComposition(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); - DWORD OnClearComposition(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); - DWORD OnSelectCandidateOnCurrentPage(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); - DWORD OnHighlightCandidateOnCurrentPage(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); - DWORD OnChangePage(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); + BEGIN_MSG_MAP(WEASEL_IPC_WINDOW) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + MESSAGE_HANDLER(WM_CLOSE, OnClose) + MESSAGE_HANDLER(WM_QUERYENDSESSION, OnQueryEndSystemSession) + MESSAGE_HANDLER(WM_ENDSESSION, OnEndSystemSession) + MESSAGE_HANDLER(WM_DWMCOLORIZATIONCOLORCHANGED, OnColorChange) + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnColorChange) + MESSAGE_HANDLER(WM_COMMAND, OnCommand) + END_MSG_MAP() - public: - ServerImpl(); - ~ServerImpl(); + LRESULT OnColorChange(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled); + LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnQueryEndSystemSession(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled); + LRESULT OnEndSystemSession(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled); + LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + DWORD OnCommand(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); + DWORD OnEcho(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); + DWORD OnStartSession(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); + DWORD OnEndSession(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); + DWORD OnKeyEvent(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); + DWORD OnShutdownServer(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); + DWORD OnFocusIn(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); + DWORD OnFocusOut(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); + DWORD OnUpdateInputPosition(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam); + DWORD OnStartMaintenance(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); + DWORD OnEndMaintenance(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); + DWORD OnCommitComposition(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam); + DWORD OnClearComposition(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); + DWORD OnSelectCandidateOnCurrentPage(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam); + DWORD OnHighlightCandidateOnCurrentPage(WEASEL_IPC_COMMAND uMsg, + DWORD wParam, + DWORD lParam); + DWORD OnChangePage(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam); - int Start(); - int Stop(); - int Run(); + public: + ServerImpl(); + ~ServerImpl(); - void SetRequestHandler(RequestHandler* pHandler) - { - m_pRequestHandler = pHandler; - } - void AddMenuHandler(UINT uID, CommandHandler &handler) - { - m_MenuHandlers[uID] = handler; - } + int Start(); + int Stop(); + int Run(); - private: - void _Finailize(); - template - void HandlePipeMessage(PipeMessage pipe_msg, _Resp resp); + void SetRequestHandler(RequestHandler* pHandler) { + m_pRequestHandler = pHandler; + } + void AddMenuHandler(UINT uID, CommandHandler& handler) { + m_MenuHandlers[uID] = handler; + } - std::unique_ptr channel; - std::unique_ptr pipeThread; - RequestHandler *m_pRequestHandler; // reference - std::map m_MenuHandlers; - HMODULE m_hUser32Module; - SecurityAttribute sa; - BOOL m_darkMode; - }; + private: + void _Finailize(); + template + void HandlePipeMessage(PipeMessage pipe_msg, _Resp resp); + std::unique_ptr channel; + std::unique_ptr pipeThread; + RequestHandler* m_pRequestHandler; // reference + std::map m_MenuHandlers; + HMODULE m_hUser32Module; + SecurityAttribute sa; + BOOL m_darkMode; +}; -} +} // namespace weasel diff --git a/WeaselServer/SystemTraySDK.cpp b/WeaselServer/SystemTraySDK.cpp index 2ec5c296c..4c5745c9e 100644 --- a/WeaselServer/SystemTraySDK.cpp +++ b/WeaselServer/SystemTraySDK.cpp @@ -3,18 +3,22 @@ // NON-MFC VERSION // // This class is a light wrapper around the windows system tray stuff. It -// adds an icon to the system tray with the specified ToolTip text and +// adds an icon to the system tray with the specified ToolTip text and // callback notification value, which is sent back to the Parent window. // -// Updated: 21 Sep 2000 - Added GetDoWndAnimation - animation only occurs if the system -// settings allow it (Matthew Ellis). Updated the GetTrayWndRect -// function to include more fallback logic (Matthew Ellis) +// Updated: 21 Sep 2000 - Added GetDoWndAnimation - animation only occurs if the +// system +// settings allow it (Matthew Ellis). Updated the +// GetTrayWndRect function to include more fallback logic +// (Matthew Ellis) // -// Updated: 4 Aug 2003 - Fixed bug that was stopping icon from being recreated when +// Updated: 4 Aug 2003 - Fixed bug that was stopping icon from being recreated +// when // Explorer crashed // Fixed resource leak in SetIcon -// Animate() now checks for empty icon list - Anton Treskunov -// Added the virutal CustomizeMenu() method - Anton Treskunov +// Animate() now checks for empty +// icon list - Anton Treskunov Added +// the virutal CustomizeMenu() method - Anton Treskunov // // 2007-11-14 GONG Chen - made modifications to enable Unicode support. // @@ -23,13 +27,12 @@ // ///////////////////////////////////////////////////////////////////////////// - #include "stdafx.h" #include "SystemTraySDK.h" #ifdef _DEBUG #undef THIS_FILE -static char THIS_FILE[]=__FILE__; +static char THIS_FILE[] = __FILE__; #define new DEBUG_NEW #endif @@ -39,514 +42,479 @@ static char THIS_FILE[]=__FILE__; #endif #ifndef _countof -#define _countof(x) (sizeof(x)/sizeof(x[0])) +#define _countof(x) (sizeof(x) / sizeof(x[0])) #endif // 2007-11-14 GONG -//#ifdef _UNICODE -//#error "Unicode not yet suported" -//#endif +// #ifdef _UNICODE +// #error "Unicode not yet suported" +// #endif #define TRAYICON_CLASS _T("TrayIconClass") // The option here is to maintain a list of all TrayIcon windows, -// and iterate through them, instead of only allowing a single +// and iterate through them, instead of only allowing a single // TrayIcon per application CSystemTray* CSystemTray::m_pThis = NULL; -const UINT_PTR CSystemTray::m_nTimerID = 4567; -UINT CSystemTray::m_nMaxTooltipLength = 64; // This may change... -const UINT CSystemTray::m_nTaskbarCreatedMsg = ::RegisterWindowMessage(_T("TaskbarCreated")); -HWND CSystemTray::m_hWndInvisible; +const UINT_PTR CSystemTray::m_nTimerID = 4567; +UINT CSystemTray::m_nMaxTooltipLength = 64; // This may change... +const UINT CSystemTray::m_nTaskbarCreatedMsg = + ::RegisterWindowMessage(_T("TaskbarCreated")); +HWND CSystemTray::m_hWndInvisible; ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// -CSystemTray::CSystemTray() -{ - Initialise(); +CSystemTray::CSystemTray() { + Initialise(); } -CSystemTray::CSystemTray(HINSTANCE hInst, // Handle to application instance - HWND hParent, // The window that will recieve tray notifications - UINT uCallbackMessage, // the callback message to send to parent - LPCTSTR szToolTip, // tray icon tooltip - HICON icon, // Handle to icon - UINT uID, // Identifier of tray icon - BOOL bHidden /*=FALSE*/, // Hidden on creation? - LPCTSTR szBalloonTip /*=NULL*/, // Ballon tip (w2k only) - LPCTSTR szBalloonTitle /*=NULL*/, // Balloon tip title (w2k) - DWORD dwBalloonIcon /*=NIIF_NONE*/,// Ballon tip icon (w2k) - UINT uBalloonTimeout /*=10*/) // Balloon timeout (w2k) +CSystemTray::CSystemTray( + HINSTANCE hInst, // Handle to application instance + HWND hParent, // The window that will recieve tray notifications + UINT uCallbackMessage, // the callback message to send to parent + LPCTSTR szToolTip, // tray icon tooltip + HICON icon, // Handle to icon + UINT uID, // Identifier of tray icon + BOOL bHidden /*=FALSE*/, // Hidden on creation? + LPCTSTR szBalloonTip /*=NULL*/, // Ballon tip (w2k only) + LPCTSTR szBalloonTitle /*=NULL*/, // Balloon tip title (w2k) + DWORD dwBalloonIcon /*=NIIF_NONE*/, // Ballon tip icon (w2k) + UINT uBalloonTimeout /*=10*/) // Balloon timeout (w2k) { - Initialise(); - Create(hInst, hParent, uCallbackMessage, szToolTip, icon, uID, bHidden, - szBalloonTip, szBalloonTitle, dwBalloonIcon, uBalloonTimeout); + Initialise(); + Create(hInst, hParent, uCallbackMessage, szToolTip, icon, uID, bHidden, + szBalloonTip, szBalloonTitle, dwBalloonIcon, uBalloonTimeout); } -void CSystemTray::Initialise() -{ - // If maintaining a list of all TrayIcon windows (instead of - // only allowing a single TrayIcon per application) then add - // this TrayIcon to the list - m_pThis = this; +void CSystemTray::Initialise() { + // If maintaining a list of all TrayIcon windows (instead of + // only allowing a single TrayIcon per application) then add + // this TrayIcon to the list + m_pThis = this; - memset(&m_tnd, 0, sizeof(m_tnd)); - m_bEnabled = FALSE; - m_bHidden = TRUE; - m_bRemoved = TRUE; + memset(&m_tnd, 0, sizeof(m_tnd)); + m_bEnabled = FALSE; + m_bHidden = TRUE; + m_bRemoved = TRUE; - m_DefaultMenuItemID = 0; - m_DefaultMenuItemByPos = TRUE; + m_DefaultMenuItemID = 0; + m_DefaultMenuItemByPos = TRUE; - m_bShowIconPending = FALSE; + m_bShowIconPending = FALSE; - m_uIDTimer = 0; - m_hSavedIcon = NULL; + m_uIDTimer = 0; + m_hSavedIcon = NULL; - m_hTargetWnd = NULL; - m_uCreationFlags = 0; + m_hTargetWnd = NULL; + m_uCreationFlags = 0; #ifdef SYSTEMTRAY_USEW2K - OSVERSIONINFO os = { sizeof(os) }; - GetVersionEx(&os); - m_bWin2K = ( VER_PLATFORM_WIN32_NT == os.dwPlatformId && os.dwMajorVersion >= 5 ); + OSVERSIONINFO os = {sizeof(os)}; + GetVersionEx(&os); + m_bWin2K = + (VER_PLATFORM_WIN32_NT == os.dwPlatformId && os.dwMajorVersion >= 5); #else - m_bWin2K = FALSE; + m_bWin2K = FALSE; #endif } -ATOM CSystemTray::RegisterClass(HINSTANCE hInstance) -{ - WNDCLASSEX wcex; - - wcex.cbSize = sizeof(WNDCLASSEX); - - wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; - wcex.lpfnWndProc = (WNDPROC)WindowProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = hInstance; - wcex.hIcon = 0; - wcex.hCursor = 0; - wcex.hbrBackground = 0; - wcex.lpszMenuName = 0; - wcex.lpszClassName = TRAYICON_CLASS; - wcex.hIconSm = 0; - - return RegisterClassEx(&wcex); +ATOM CSystemTray::RegisterClass(HINSTANCE hInstance) { + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; + wcex.lpfnWndProc = (WNDPROC)WindowProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = 0; + wcex.hCursor = 0; + wcex.hbrBackground = 0; + wcex.lpszMenuName = 0; + wcex.lpszClassName = TRAYICON_CLASS; + wcex.hIconSm = 0; + + return RegisterClassEx(&wcex); } -BOOL CSystemTray::Create(HINSTANCE hInst, HWND hParent, UINT uCallbackMessage, - LPCTSTR szToolTip, HICON icon, UINT uID, BOOL bHidden /*=FALSE*/, - LPCTSTR szBalloonTip /*=NULL*/, - LPCTSTR szBalloonTitle /*=NULL*/, - DWORD dwBalloonIcon /*=NIIF_NONE*/, - UINT uBalloonTimeout /*=10*/) -{ +BOOL CSystemTray::Create(HINSTANCE hInst, + HWND hParent, + UINT uCallbackMessage, + LPCTSTR szToolTip, + HICON icon, + UINT uID, + BOOL bHidden /*=FALSE*/, + LPCTSTR szBalloonTip /*=NULL*/, + LPCTSTR szBalloonTitle /*=NULL*/, + DWORD dwBalloonIcon /*=NIIF_NONE*/, + UINT uBalloonTimeout /*=10*/) { #ifdef _WIN32_WCE - m_bEnabled = TRUE; + m_bEnabled = TRUE; #else - // this is only for Windows 95 (or higher) - m_bEnabled = (GetVersion() & 0xff) >= 4; - if (!m_bEnabled) - { - ASSERT(FALSE); - return FALSE; - } + // this is only for Windows 95 (or higher) + m_bEnabled = (GetVersion() & 0xff) >= 4; + if (!m_bEnabled) { + ASSERT(FALSE); + return FALSE; + } #endif - - m_nMaxTooltipLength = _countof(m_tnd.szTip); - - // Make sure we avoid conflict with other messages - ASSERT(uCallbackMessage >= WM_APP); - - // Tray only supports tooltip text up to m_nMaxTooltipLength) characters - ASSERT(_tcslen(szToolTip) <= m_nMaxTooltipLength); - - m_hInstance = hInst; - - RegisterClass(hInst); - - // Create an invisible window - m_hWnd = ::CreateWindow(TRAYICON_CLASS, _T(""), WS_POPUP, - CW_USEDEFAULT,CW_USEDEFAULT, - CW_USEDEFAULT,CW_USEDEFAULT, - NULL, 0, - hInst, 0); - - // load up the NOTIFYICONDATA structure - //m_tnd.cbSize = sizeof(NOTIFYICONDATA); - m_tnd.cbSize = NOTIFYICONDATA_V2_SIZE; // 2012-01-05 GONG Chen, XP compatibility - m_tnd.hWnd = (hParent)? hParent : m_hWnd; - m_tnd.uID = uID; - m_tnd.hIcon = icon; - m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; - m_tnd.uCallbackMessage = uCallbackMessage; -// 2007-11-14 GONG - _tcsncpy_s(m_tnd.szTip, _countof(m_tnd.szTip), szToolTip, m_nMaxTooltipLength); + m_nMaxTooltipLength = _countof(m_tnd.szTip); + + // Make sure we avoid conflict with other messages + ASSERT(uCallbackMessage >= WM_APP); + + // Tray only supports tooltip text up to m_nMaxTooltipLength) characters + ASSERT(_tcslen(szToolTip) <= m_nMaxTooltipLength); + + m_hInstance = hInst; + + RegisterClass(hInst); + + // Create an invisible window + m_hWnd = ::CreateWindow(TRAYICON_CLASS, _T(""), WS_POPUP, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, 0, + hInst, 0); + + // load up the NOTIFYICONDATA structure + // m_tnd.cbSize = sizeof(NOTIFYICONDATA); + m_tnd.cbSize = + NOTIFYICONDATA_V2_SIZE; // 2012-01-05 GONG Chen, XP compatibility + m_tnd.hWnd = (hParent) ? hParent : m_hWnd; + m_tnd.uID = uID; + m_tnd.hIcon = icon; + m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; + m_tnd.uCallbackMessage = uCallbackMessage; + + // 2007-11-14 GONG + _tcsncpy_s(m_tnd.szTip, _countof(m_tnd.szTip), szToolTip, + m_nMaxTooltipLength); #ifdef SYSTEMTRAY_USEW2K - if (m_bWin2K && szBalloonTip) - { + if (m_bWin2K && szBalloonTip) { #if _MSC_VER < 0x1000 - // The balloon tooltip text can be up to 255 chars long. -// ASSERT(AfxIsValidString(szBalloonTip)); - ASSERT(lstrlen(szBalloonTip) < 256); + // The balloon tooltip text can be up to 255 chars long. + // ASSERT(AfxIsValidString(szBalloonTip)); + ASSERT(lstrlen(szBalloonTip) < 256); #endif - // The balloon title text can be up to 63 chars long. - if (szBalloonTitle) - { -// ASSERT(AfxIsValidString(szBalloonTitle)); - ASSERT(lstrlen(szBalloonTitle) < 64); - } - - // dwBalloonIcon must be valid. - ASSERT(NIIF_NONE == dwBalloonIcon || NIIF_INFO == dwBalloonIcon || - NIIF_WARNING == dwBalloonIcon || NIIF_ERROR == dwBalloonIcon); - - // The timeout must be between 10 and 30 seconds. - ASSERT(uBalloonTimeout >= 10 && uBalloonTimeout <= 30); - - m_tnd.uFlags |= NIF_INFO; - - _tcsncpy_s(m_tnd.szInfo, _countof(m_tnd.szInfo), szBalloonTip, 255); - if (szBalloonTitle) - _tcsncpy_s(m_tnd.szInfoTitle, _countof(m_tnd.szInfoTitle), szBalloonTitle, 63); - else - m_tnd.szInfoTitle[0] = _T('\0'); - m_tnd.uTimeout = uBalloonTimeout * 1000; // convert time to ms - m_tnd.dwInfoFlags = dwBalloonIcon; + // The balloon title text can be up to 63 chars long. + if (szBalloonTitle) { + // ASSERT(AfxIsValidString(szBalloonTitle)); + ASSERT(lstrlen(szBalloonTitle) < 64); } -#endif - m_bHidden = bHidden; - m_hTargetWnd = m_tnd.hWnd; + // dwBalloonIcon must be valid. + ASSERT(NIIF_NONE == dwBalloonIcon || NIIF_INFO == dwBalloonIcon || + NIIF_WARNING == dwBalloonIcon || NIIF_ERROR == dwBalloonIcon); -#ifdef SYSTEMTRAY_USEW2K - if (m_bWin2K && m_bHidden) - { - m_tnd.uFlags = NIF_STATE; - m_tnd.dwState = NIS_HIDDEN; - m_tnd.dwStateMask = NIS_HIDDEN; - } + // The timeout must be between 10 and 30 seconds. + ASSERT(uBalloonTimeout >= 10 && uBalloonTimeout <= 30); + + m_tnd.uFlags |= NIF_INFO; + + _tcsncpy_s(m_tnd.szInfo, _countof(m_tnd.szInfo), szBalloonTip, 255); + if (szBalloonTitle) + _tcsncpy_s(m_tnd.szInfoTitle, _countof(m_tnd.szInfoTitle), szBalloonTitle, + 63); + else + m_tnd.szInfoTitle[0] = _T('\0'); + m_tnd.uTimeout = uBalloonTimeout * 1000; // convert time to ms + m_tnd.dwInfoFlags = dwBalloonIcon; + } #endif - m_uCreationFlags = m_tnd.uFlags; // Store in case we need to recreate in OnTaskBarCreate + m_bHidden = bHidden; + m_hTargetWnd = m_tnd.hWnd; - BOOL bResult = TRUE; - if (!m_bHidden || m_bWin2K) - { - bResult = Shell_NotifyIcon(NIM_ADD, &m_tnd); - m_bShowIconPending = m_bHidden = m_bRemoved = !bResult; - } - -#ifdef SYSTEMTRAY_USEW2K - if (m_bWin2K && szBalloonTip) - { - // Zero out the balloon text string so that later operations won't redisplay - // the balloon. - m_tnd.szInfo[0] = _T('\0'); - } +#ifdef SYSTEMTRAY_USEW2K + if (m_bWin2K && m_bHidden) { + m_tnd.uFlags = NIF_STATE; + m_tnd.dwState = NIS_HIDDEN; + m_tnd.dwStateMask = NIS_HIDDEN; + } #endif + m_uCreationFlags = + m_tnd.uFlags; // Store in case we need to recreate in OnTaskBarCreate + + BOOL bResult = TRUE; + if (!m_bHidden || m_bWin2K) { + bResult = Shell_NotifyIcon(NIM_ADD, &m_tnd); + m_bShowIconPending = m_bHidden = m_bRemoved = !bResult; + } + +#ifdef SYSTEMTRAY_USEW2K + if (m_bWin2K && szBalloonTip) { + // Zero out the balloon text string so that later operations won't redisplay + // the balloon. + m_tnd.szInfo[0] = _T('\0'); + } +#endif - return bResult; + return bResult; } -CSystemTray::~CSystemTray() -{ - RemoveIcon(); - m_IconList.clear(); - if (m_hWnd) - ::DestroyWindow(m_hWnd); +CSystemTray::~CSystemTray() { + RemoveIcon(); + m_IconList.clear(); + if (m_hWnd) + ::DestroyWindow(m_hWnd); } ///////////////////////////////////////////////////////////////////////////// // CSystemTray icon manipulation -void CSystemTray::SetFocus() -{ +void CSystemTray::SetFocus() { #ifdef SYSTEMTRAY_USEW2K - Shell_NotifyIcon ( NIM_SETFOCUS, &m_tnd ); + Shell_NotifyIcon(NIM_SETFOCUS, &m_tnd); #endif } -BOOL CSystemTray::MoveToRight() -{ - RemoveIcon(); - return AddIcon(); +BOOL CSystemTray::MoveToRight() { + RemoveIcon(); + return AddIcon(); } -BOOL CSystemTray::AddIcon() -{ - if (!m_bRemoved) - RemoveIcon(); - - if (m_bEnabled) - { - m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; - if (!Shell_NotifyIcon(NIM_ADD, &m_tnd)) - m_bShowIconPending = TRUE; - else - m_bRemoved = m_bHidden = FALSE; - } - return (m_bRemoved == FALSE); +BOOL CSystemTray::AddIcon() { + if (!m_bRemoved) + RemoveIcon(); + + if (m_bEnabled) { + m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; + if (!Shell_NotifyIcon(NIM_ADD, &m_tnd)) + m_bShowIconPending = TRUE; + else + m_bRemoved = m_bHidden = FALSE; + } + return (m_bRemoved == FALSE); } -BOOL CSystemTray::RemoveIcon() -{ - m_bShowIconPending = FALSE; +BOOL CSystemTray::RemoveIcon() { + m_bShowIconPending = FALSE; - if (!m_bEnabled || m_bRemoved) - return TRUE; + if (!m_bEnabled || m_bRemoved) + return TRUE; - m_tnd.uFlags = 0; - if (Shell_NotifyIcon(NIM_DELETE, &m_tnd)) - m_bRemoved = m_bHidden = TRUE; + m_tnd.uFlags = 0; + if (Shell_NotifyIcon(NIM_DELETE, &m_tnd)) + m_bRemoved = m_bHidden = TRUE; - return (m_bRemoved == TRUE); + return (m_bRemoved == TRUE); } -BOOL CSystemTray::HideIcon() -{ - if (!m_bEnabled || m_bRemoved || m_bHidden) - return TRUE; +BOOL CSystemTray::HideIcon() { + if (!m_bEnabled || m_bRemoved || m_bHidden) + return TRUE; #ifdef SYSTEMTRAY_USEW2K - if (m_bWin2K) - { - m_tnd.uFlags = NIF_STATE; - m_tnd.dwState = NIS_HIDDEN; - m_tnd.dwStateMask = NIS_HIDDEN; + if (m_bWin2K) { + m_tnd.uFlags = NIF_STATE; + m_tnd.dwState = NIS_HIDDEN; + m_tnd.dwStateMask = NIS_HIDDEN; - m_bHidden = Shell_NotifyIcon( NIM_MODIFY, &m_tnd); - } - else + m_bHidden = Shell_NotifyIcon(NIM_MODIFY, &m_tnd); + } else #endif - RemoveIcon(); + RemoveIcon(); - return (m_bHidden == TRUE); + return (m_bHidden == TRUE); } -BOOL CSystemTray::ShowIcon() -{ - if (m_bRemoved) - return AddIcon(); +BOOL CSystemTray::ShowIcon() { + if (m_bRemoved) + return AddIcon(); - if (!m_bHidden) - return TRUE; + if (!m_bHidden) + return TRUE; #ifdef SYSTEMTRAY_USEW2K - if (m_bWin2K) - { - m_tnd.uFlags = NIF_STATE; - m_tnd.dwState = 0; - m_tnd.dwStateMask = NIS_HIDDEN; - Shell_NotifyIcon ( NIM_MODIFY, &m_tnd ); - } - else + if (m_bWin2K) { + m_tnd.uFlags = NIF_STATE; + m_tnd.dwState = 0; + m_tnd.dwStateMask = NIS_HIDDEN; + Shell_NotifyIcon(NIM_MODIFY, &m_tnd); + } else #endif - AddIcon(); + AddIcon(); - return (m_bHidden == FALSE); + return (m_bHidden == FALSE); } -BOOL CSystemTray::SetIcon(HICON hIcon) -{ - if (!m_bEnabled) - return FALSE; +BOOL CSystemTray::SetIcon(HICON hIcon) { + if (!m_bEnabled) + return FALSE; - m_tnd.uFlags = NIF_ICON; - m_tnd.hIcon = hIcon; + m_tnd.uFlags = NIF_ICON; + m_tnd.hIcon = hIcon; - if (m_bHidden) - return TRUE; - else - return Shell_NotifyIcon(NIM_MODIFY, &m_tnd); + if (m_bHidden) + return TRUE; + else + return Shell_NotifyIcon(NIM_MODIFY, &m_tnd); } -BOOL CSystemTray::SetIcon(LPCTSTR lpszIconName) -{ - HICON hIcon = (HICON) ::LoadImage(m_hInstance, - lpszIconName, - IMAGE_ICON, - 0, 0, - LR_LOADFROMFILE); - - if (!hIcon) - return FALSE; - BOOL returnCode = SetIcon(hIcon); - ::DestroyIcon(hIcon); - return returnCode; +BOOL CSystemTray::SetIcon(LPCTSTR lpszIconName) { + HICON hIcon = (HICON)::LoadImage(m_hInstance, lpszIconName, IMAGE_ICON, 0, 0, + LR_LOADFROMFILE); + + if (!hIcon) + return FALSE; + BOOL returnCode = SetIcon(hIcon); + ::DestroyIcon(hIcon); + return returnCode; } -BOOL CSystemTray::SetIcon(UINT nIDResource) -{ - HICON hIcon = (HICON) ::LoadImage(m_hInstance, - MAKEINTRESOURCE(nIDResource), - IMAGE_ICON, - 0, 0, - LR_DEFAULTCOLOR); - - BOOL returnCode = SetIcon(hIcon); - ::DestroyIcon(hIcon); - return returnCode; +BOOL CSystemTray::SetIcon(UINT nIDResource) { + HICON hIcon = (HICON)::LoadImage(m_hInstance, MAKEINTRESOURCE(nIDResource), + IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR); + + BOOL returnCode = SetIcon(hIcon); + ::DestroyIcon(hIcon); + return returnCode; } -BOOL CSystemTray::SetStandardIcon(LPCTSTR lpIconName) -{ - HICON hIcon = ::LoadIcon(NULL, lpIconName); +BOOL CSystemTray::SetStandardIcon(LPCTSTR lpIconName) { + HICON hIcon = ::LoadIcon(NULL, lpIconName); - return SetIcon(hIcon); + return SetIcon(hIcon); } -BOOL CSystemTray::SetStandardIcon(UINT nIDResource) -{ - HICON hIcon = ::LoadIcon(NULL, MAKEINTRESOURCE(nIDResource)); +BOOL CSystemTray::SetStandardIcon(UINT nIDResource) { + HICON hIcon = ::LoadIcon(NULL, MAKEINTRESOURCE(nIDResource)); - return SetIcon(hIcon); + return SetIcon(hIcon); } - -HICON CSystemTray::GetIcon() const -{ - return (m_bEnabled)? m_tnd.hIcon : NULL; + +HICON CSystemTray::GetIcon() const { + return (m_bEnabled) ? m_tnd.hIcon : NULL; } -BOOL CSystemTray::SetIconList(UINT uFirstIconID, UINT uLastIconID) -{ - if (uFirstIconID > uLastIconID) - return FALSE; +BOOL CSystemTray::SetIconList(UINT uFirstIconID, UINT uLastIconID) { + if (uFirstIconID > uLastIconID) + return FALSE; - UINT uIconArraySize = uLastIconID - uFirstIconID + 1; + UINT uIconArraySize = uLastIconID - uFirstIconID + 1; + m_IconList.clear(); + try { + for (UINT i = uFirstIconID; i <= uLastIconID; i++) + m_IconList.push_back(::LoadIcon(m_hInstance, MAKEINTRESOURCE(i))); + } catch (...) { m_IconList.clear(); - try - { - for (UINT i = uFirstIconID; i <= uLastIconID; i++) - m_IconList.push_back(::LoadIcon(m_hInstance, MAKEINTRESOURCE(i))); - } - catch (...) - { - m_IconList.clear(); - return FALSE; - } + return FALSE; + } - return TRUE; + return TRUE; } -BOOL CSystemTray::SetIconList(HICON* pHIconList, UINT nNumIcons) -{ - m_IconList.clear(); +BOOL CSystemTray::SetIconList(HICON* pHIconList, UINT nNumIcons) { + m_IconList.clear(); - try { - for (UINT i = 0; i <= nNumIcons; i++) - m_IconList.push_back(pHIconList[i]); - } - catch (...) - { - m_IconList.clear(); - return FALSE; - } + try { + for (UINT i = 0; i <= nNumIcons; i++) + m_IconList.push_back(pHIconList[i]); + } catch (...) { + m_IconList.clear(); + return FALSE; + } - return TRUE; + return TRUE; } -BOOL CSystemTray::Animate(UINT nDelayMilliSeconds, int nNumSeconds /*=-1*/) -{ - if (m_IconList.empty()) - return FALSE; +BOOL CSystemTray::Animate(UINT nDelayMilliSeconds, int nNumSeconds /*=-1*/) { + if (m_IconList.empty()) + return FALSE; - StopAnimation(); + StopAnimation(); - m_nCurrentIcon = 0; - time(&m_StartTime); - m_nAnimationPeriod = nNumSeconds; - m_hSavedIcon = GetIcon(); + m_nCurrentIcon = 0; + time(&m_StartTime); + m_nAnimationPeriod = nNumSeconds; + m_hSavedIcon = GetIcon(); - // Setup a timer for the animation - m_uIDTimer = ::SetTimer(m_hWnd, m_nTimerID, nDelayMilliSeconds, NULL); - return (m_uIDTimer != 0); + // Setup a timer for the animation + m_uIDTimer = ::SetTimer(m_hWnd, m_nTimerID, nDelayMilliSeconds, NULL); + return (m_uIDTimer != 0); } -BOOL CSystemTray::StepAnimation() -{ - if (!m_IconList.size()) - return FALSE; +BOOL CSystemTray::StepAnimation() { + if (!m_IconList.size()) + return FALSE; - m_nCurrentIcon++; - if (m_nCurrentIcon >= (int)m_IconList.size()) - m_nCurrentIcon = 0; + m_nCurrentIcon++; + if (m_nCurrentIcon >= (int)m_IconList.size()) + m_nCurrentIcon = 0; - return SetIcon(m_IconList[m_nCurrentIcon]); + return SetIcon(m_IconList[m_nCurrentIcon]); } -BOOL CSystemTray::StopAnimation() -{ - BOOL bResult = FALSE; +BOOL CSystemTray::StopAnimation() { + BOOL bResult = FALSE; - if (m_uIDTimer) - bResult = ::KillTimer(m_hWnd, m_uIDTimer); - m_uIDTimer = 0; + if (m_uIDTimer) + bResult = ::KillTimer(m_hWnd, m_uIDTimer); + m_uIDTimer = 0; - if (m_hSavedIcon) - SetIcon(m_hSavedIcon); - m_hSavedIcon = NULL; + if (m_hSavedIcon) + SetIcon(m_hSavedIcon); + m_hSavedIcon = NULL; - return bResult; + return bResult; } ///////////////////////////////////////////////////////////////////////////// // CSystemTray tooltip text manipulation -BOOL CSystemTray::SetTooltipText(LPCTSTR pszTip) -{ - ASSERT(_tcslen(pszTip) < m_nMaxTooltipLength); +BOOL CSystemTray::SetTooltipText(LPCTSTR pszTip) { + ASSERT(_tcslen(pszTip) < m_nMaxTooltipLength); - if (!m_bEnabled) - return FALSE; + if (!m_bEnabled) + return FALSE; - m_tnd.uFlags = NIF_TIP; - _tcsncpy_s(m_tnd.szTip, _countof(m_tnd.szTip), pszTip, m_nMaxTooltipLength-1); + m_tnd.uFlags = NIF_TIP; + _tcsncpy_s(m_tnd.szTip, _countof(m_tnd.szTip), pszTip, + m_nMaxTooltipLength - 1); - if (m_bHidden) - return TRUE; - else - return Shell_NotifyIcon(NIM_MODIFY, &m_tnd); + if (m_bHidden) + return TRUE; + else + return Shell_NotifyIcon(NIM_MODIFY, &m_tnd); } -BOOL CSystemTray::SetTooltipText(UINT nID) -{ - TCHAR strBuffer[1024]; - ASSERT(1024 >= m_nMaxTooltipLength); +BOOL CSystemTray::SetTooltipText(UINT nID) { + TCHAR strBuffer[1024]; + ASSERT(1024 >= m_nMaxTooltipLength); - if (!LoadString(m_hInstance, nID, strBuffer, m_nMaxTooltipLength-1)) - return FALSE; + if (!LoadString(m_hInstance, nID, strBuffer, m_nMaxTooltipLength - 1)) + return FALSE; - return SetTooltipText(strBuffer); + return SetTooltipText(strBuffer); } -LPTSTR CSystemTray::GetTooltipText() const -{ - if (!m_bEnabled) - return FALSE; - - static TCHAR strBuffer[1024]; - ASSERT(1024 >= m_nMaxTooltipLength); +LPTSTR CSystemTray::GetTooltipText() const { + if (!m_bEnabled) + return FALSE; -// 2007-11-14 GONG -//#ifdef _UNICODE -// strBuffer[0] = _T('\0'); -// MultiByteToWideChar(CP_ACP, 0, m_tnd.szTip, -1, strBuffer, m_nMaxTooltipLength, NULL, NULL); -//#else -// strncpy(strBuffer, m_tnd.szTip, m_nMaxTooltipLength-1); -//#endif - _tcsncpy_s(strBuffer, _countof(strBuffer), m_tnd.szTip, m_nMaxTooltipLength-1); - - return strBuffer; + static TCHAR strBuffer[1024]; + ASSERT(1024 >= m_nMaxTooltipLength); + + // 2007-11-14 GONG + // #ifdef _UNICODE + // strBuffer[0] = _T('\0'); + // MultiByteToWideChar(CP_ACP, 0, m_tnd.szTip, -1, strBuffer, + // m_nMaxTooltipLength, NULL, NULL); + // #else + // strncpy(strBuffer, m_tnd.szTip, m_nMaxTooltipLength-1); + // #endif + _tcsncpy_s(strBuffer, _countof(strBuffer), m_tnd.szTip, + m_nMaxTooltipLength - 1); + + return strBuffer; } ////////////////////////////////////////////////////////////////////////// @@ -576,166 +544,153 @@ LPTSTR CSystemTray::GetTooltipText() const ////////////////////////////////////////////////////////////////////////// BOOL CSystemTray::ShowBalloon(LPCTSTR szText, - LPCTSTR szTitle /*=NULL*/, - DWORD dwIcon /*=NIIF_NONE*/, - UINT uTimeout /*=10*/ ) -{ + LPCTSTR szTitle /*=NULL*/, + DWORD dwIcon /*=NIIF_NONE*/, + UINT uTimeout /*=10*/) { #ifndef SYSTEMTRAY_USEW2K - return FALSE; + return FALSE; #else - // Bail out if we're not on Win 2K. - if (!m_bWin2K) - return FALSE; + // Bail out if we're not on Win 2K. + if (!m_bWin2K) + return FALSE; - // Verify input parameters. + // Verify input parameters. - // The balloon tooltip text can be up to 255 chars long. -// ASSERT(AfxIsValidString(szText)); - ASSERT(lstrlen(szText) < 256); + // The balloon tooltip text can be up to 255 chars long. + // ASSERT(AfxIsValidString(szText)); + ASSERT(lstrlen(szText) < 256); - // The balloon title text can be up to 63 chars long. - if (szTitle) - { -// ASSERT(AfxIsValidString( szTitle)); - ASSERT(lstrlen(szTitle) < 64); - } + // The balloon title text can be up to 63 chars long. + if (szTitle) { + // ASSERT(AfxIsValidString( szTitle)); + ASSERT(lstrlen(szTitle) < 64); + } - // dwBalloonIcon must be valid. - ASSERT(NIIF_NONE == dwIcon || NIIF_INFO == dwIcon || - NIIF_WARNING == dwIcon || NIIF_ERROR == dwIcon); - - // The timeout must be between 10 and 30 seconds. - ASSERT(uTimeout >= 10 && uTimeout <= 30); + // dwBalloonIcon must be valid. + ASSERT(NIIF_NONE == dwIcon || NIIF_INFO == dwIcon || NIIF_WARNING == dwIcon || + NIIF_ERROR == dwIcon); + // The timeout must be between 10 and 30 seconds. + ASSERT(uTimeout >= 10 && uTimeout <= 30); - m_tnd.uFlags = NIF_INFO; - _tcsncpy_s(m_tnd.szInfo, _countof(m_tnd.szInfo), szText, 256); - if (szTitle) - _tcsncpy_s(m_tnd.szInfoTitle, _countof(m_tnd.szInfoTitle), szTitle, 64); - else - m_tnd.szInfoTitle[0] = _T('\0'); - m_tnd.dwInfoFlags = dwIcon; - m_tnd.uTimeout = uTimeout * 1000; // convert time to ms + m_tnd.uFlags = NIF_INFO; + _tcsncpy_s(m_tnd.szInfo, _countof(m_tnd.szInfo), szText, 256); + if (szTitle) + _tcsncpy_s(m_tnd.szInfoTitle, _countof(m_tnd.szInfoTitle), szTitle, 64); + else + m_tnd.szInfoTitle[0] = _T('\0'); + m_tnd.dwInfoFlags = dwIcon; + m_tnd.uTimeout = uTimeout * 1000; // convert time to ms - BOOL bSuccess = Shell_NotifyIcon (NIM_MODIFY, &m_tnd); + BOOL bSuccess = Shell_NotifyIcon(NIM_MODIFY, &m_tnd); - // Zero out the balloon text string so that later operations won't redisplay - // the balloon. - m_tnd.szInfo[0] = _T('\0'); + // Zero out the balloon text string so that later operations won't redisplay + // the balloon. + m_tnd.szInfo[0] = _T('\0'); - return bSuccess; + return bSuccess; #endif } ///////////////////////////////////////////////////////////////////////////// // CSystemTray notification window stuff -BOOL CSystemTray::SetNotificationWnd(HWND hNotifyWnd) -{ - if (!m_bEnabled) - return FALSE; - - // Make sure Notification window is valid - if (!hNotifyWnd || !::IsWindow(hNotifyWnd)) - { - ASSERT(FALSE); - return FALSE; - } +BOOL CSystemTray::SetNotificationWnd(HWND hNotifyWnd) { + if (!m_bEnabled) + return FALSE; - m_tnd.hWnd = hNotifyWnd; - m_tnd.uFlags = 0; + // Make sure Notification window is valid + if (!hNotifyWnd || !::IsWindow(hNotifyWnd)) { + ASSERT(FALSE); + return FALSE; + } - if (m_bHidden) - return TRUE; - else - return Shell_NotifyIcon(NIM_MODIFY, &m_tnd); + m_tnd.hWnd = hNotifyWnd; + m_tnd.uFlags = 0; + + if (m_bHidden) + return TRUE; + else + return Shell_NotifyIcon(NIM_MODIFY, &m_tnd); } -HWND CSystemTray::GetNotificationWnd() const -{ - return m_tnd.hWnd; +HWND CSystemTray::GetNotificationWnd() const { + return m_tnd.hWnd; } // Hatr added // Change or retrive the window to send menu commands to -BOOL CSystemTray::SetTargetWnd(HWND hTargetWnd) -{ - m_hTargetWnd = hTargetWnd; - return TRUE; -} // CSystemTray::SetTargetWnd() - -HWND CSystemTray::GetTargetWnd() const -{ - if (m_hTargetWnd) - return m_hTargetWnd; - else - return m_tnd.hWnd; -} // CSystemTray::GetTargetWnd() +BOOL CSystemTray::SetTargetWnd(HWND hTargetWnd) { + m_hTargetWnd = hTargetWnd; + return TRUE; +} // CSystemTray::SetTargetWnd() + +HWND CSystemTray::GetTargetWnd() const { + if (m_hTargetWnd) + return m_hTargetWnd; + else + return m_tnd.hWnd; +} // CSystemTray::GetTargetWnd() ///////////////////////////////////////////////////////////////////////////// // CSystemTray notification message stuff -BOOL CSystemTray::SetCallbackMessage(UINT uCallbackMessage) -{ - if (!m_bEnabled) - return FALSE; +BOOL CSystemTray::SetCallbackMessage(UINT uCallbackMessage) { + if (!m_bEnabled) + return FALSE; - // Make sure we avoid conflict with other messages - ASSERT(uCallbackMessage >= WM_APP); + // Make sure we avoid conflict with other messages + ASSERT(uCallbackMessage >= WM_APP); - m_tnd.uCallbackMessage = uCallbackMessage; - m_tnd.uFlags = NIF_MESSAGE; + m_tnd.uCallbackMessage = uCallbackMessage; + m_tnd.uFlags = NIF_MESSAGE; - if (m_bHidden) - return TRUE; - else - return Shell_NotifyIcon(NIM_MODIFY, &m_tnd); + if (m_bHidden) + return TRUE; + else + return Shell_NotifyIcon(NIM_MODIFY, &m_tnd); } -UINT CSystemTray::GetCallbackMessage() const -{ - return m_tnd.uCallbackMessage; +UINT CSystemTray::GetCallbackMessage() const { + return m_tnd.uCallbackMessage; } ///////////////////////////////////////////////////////////////////////////// // CSystemTray menu manipulation -BOOL CSystemTray::SetMenuDefaultItem(UINT uItem, BOOL bByPos) -{ +BOOL CSystemTray::SetMenuDefaultItem(UINT uItem, BOOL bByPos) { #ifdef _WIN32_WCE - return FALSE; + return FALSE; #else - if ((m_DefaultMenuItemID == uItem) && (m_DefaultMenuItemByPos == bByPos)) - return TRUE; + if ((m_DefaultMenuItemID == uItem) && (m_DefaultMenuItemByPos == bByPos)) + return TRUE; - m_DefaultMenuItemID = uItem; - m_DefaultMenuItemByPos = bByPos; + m_DefaultMenuItemID = uItem; + m_DefaultMenuItemByPos = bByPos; - HMENU hMenu = ::LoadMenu(m_hInstance, MAKEINTRESOURCE(m_tnd.uID)); - if (!hMenu) - return FALSE; + HMENU hMenu = ::LoadMenu(m_hInstance, MAKEINTRESOURCE(m_tnd.uID)); + if (!hMenu) + return FALSE; - HMENU hSubMenu = ::GetSubMenu(hMenu, 0); - if (!hSubMenu) - { - ::DestroyMenu(hMenu); - return FALSE; - } + HMENU hSubMenu = ::GetSubMenu(hMenu, 0); + if (!hSubMenu) { + ::DestroyMenu(hMenu); + return FALSE; + } - ::SetMenuDefaultItem(hSubMenu, m_DefaultMenuItemID, m_DefaultMenuItemByPos); + ::SetMenuDefaultItem(hSubMenu, m_DefaultMenuItemID, m_DefaultMenuItemByPos); - ::DestroyMenu(hSubMenu); - ::DestroyMenu(hMenu); + ::DestroyMenu(hSubMenu); + ::DestroyMenu(hMenu); - return TRUE; + return TRUE; #endif } -void CSystemTray::GetMenuDefaultItem(UINT& uItem, BOOL& bByPos) -{ - uItem = m_DefaultMenuItemID; - bByPos = m_DefaultMenuItemByPos; +void CSystemTray::GetMenuDefaultItem(UINT& uItem, BOOL& bByPos) { + uItem = m_DefaultMenuItemID; + bByPos = m_DefaultMenuItemByPos; } ///////////////////////////////////////////////////////////////////////////// @@ -743,385 +698,364 @@ void CSystemTray::GetMenuDefaultItem(UINT& uItem, BOOL& bByPos) /* If we were in MFC this is what we'd use... BEGIN_MESSAGE_MAP(CSystemTray, CWnd) - //{{AFX_MSG_MAP(CSystemTray) - ON_WM_TIMER() - //}}AFX_MSG_MAP + //{{AFX_MSG_MAP(CSystemTray) + ON_WM_TIMER() + //}}AFX_MSG_MAP #ifndef _WIN32_WCE - ON_WM_SETTINGCHANGE() + ON_WM_SETTINGCHANGE() #endif ON_REGISTERED_MESSAGE(WM_TASKBARCREATED, OnTaskbarCreated) END_MESSAGE_MAP() */ -LRESULT CSystemTray::OnTimer(UINT nIDEvent) -{ - if (nIDEvent != m_uIDTimer) - { - ASSERT(FALSE); - return 0L; - } - - time_t CurrentTime; - time(&CurrentTime); - - time_t period = CurrentTime - m_StartTime; - if (m_nAnimationPeriod > 0 && m_nAnimationPeriod < period) - { - StopAnimation(); - return 0L; - } +LRESULT CSystemTray::OnTimer(UINT nIDEvent) { + if (nIDEvent != m_uIDTimer) { + ASSERT(FALSE); + return 0L; + } - StepAnimation(); + time_t CurrentTime; + time(&CurrentTime); + time_t period = CurrentTime - m_StartTime; + if (m_nAnimationPeriod > 0 && m_nAnimationPeriod < period) { + StopAnimation(); return 0L; + } + + StepAnimation(); + + return 0L; } // This is called whenever the taskbar is created (eg after explorer crashes // and restarts. Please note that the WM_TASKBARCREATED message is only passed // to TOP LEVEL windows (like WM_QUERYNEWPALETTE) -LRESULT CSystemTray::OnTaskbarCreated(WPARAM wParam, LPARAM lParam) -{ - InstallIconPending(); - return 0L; +LRESULT CSystemTray::OnTaskbarCreated(WPARAM wParam, LPARAM lParam) { + InstallIconPending(); + return 0L; } #ifndef _WIN32_WCE -LRESULT CSystemTray::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) -{ - if (uFlags == SPI_SETWORKAREA) - InstallIconPending(); - return 0L; +LRESULT CSystemTray::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) { + if (uFlags == SPI_SETWORKAREA) + InstallIconPending(); + return 0L; } #endif -LRESULT CSystemTray::OnTrayNotification(WPARAM wParam, LPARAM lParam) -{ - //Return quickly if its not for this tray icon - if (wParam != m_tnd.uID) - return 0L; +LRESULT CSystemTray::OnTrayNotification(WPARAM wParam, LPARAM lParam) { + // Return quickly if its not for this tray icon + if (wParam != m_tnd.uID) + return 0L; - HWND hTargetWnd = GetTargetWnd(); - if (!hTargetWnd) - return 0L; + HWND hTargetWnd = GetTargetWnd(); + if (!hTargetWnd) + return 0L; // Clicking with right button brings up a context menu -#if defined(_WIN32_WCE) //&& _WIN32_WCE < 211 - BOOL bAltPressed = ((GetKeyState(VK_MENU) & (1 << (sizeof(SHORT)*8-1))) != 0); - if (LOWORD(lParam) == WM_LBUTTONUP && bAltPressed) +#if defined(_WIN32_WCE) //&& _WIN32_WCE < 211 + BOOL bAltPressed = + ((GetKeyState(VK_MENU) & (1 << (sizeof(SHORT) * 8 - 1))) != 0); + if (LOWORD(lParam) == WM_LBUTTONUP && bAltPressed) #else - if (LOWORD(lParam) == WM_RBUTTONUP) + if (LOWORD(lParam) == WM_RBUTTONUP) #endif - { - HMENU hMenu = ::LoadMenu(m_hInstance, MAKEINTRESOURCE(m_tnd.uID)); - if (!hMenu) - return 0; - - HMENU hSubMenu = ::GetSubMenu(hMenu, 0); - if (!hSubMenu) - { - ::DestroyMenu(hMenu); //Be sure to Destroy Menu Before Returning - return 0; - } + { + HMENU hMenu = ::LoadMenu(m_hInstance, MAKEINTRESOURCE(m_tnd.uID)); + if (!hMenu) + return 0; + + HMENU hSubMenu = ::GetSubMenu(hMenu, 0); + if (!hSubMenu) { + ::DestroyMenu(hMenu); // Be sure to Destroy Menu Before Returning + return 0; + } #ifndef _WIN32_WCE - // Make chosen menu item the default (bold font) - ::SetMenuDefaultItem(hSubMenu, m_DefaultMenuItemID, m_DefaultMenuItemByPos); + // Make chosen menu item the default (bold font) + ::SetMenuDefaultItem(hSubMenu, m_DefaultMenuItemID, m_DefaultMenuItemByPos); #endif - CustomizeMenu(hSubMenu); + CustomizeMenu(hSubMenu); - // Display and track the popup menu - POINT pos; + // Display and track the popup menu + POINT pos; #ifdef _WIN32_WCE - DWORD messagepos = ::GetMessagePos(); - pos.x = GET_X_LPARAM(messagepos); - pos.y = GET_Y_LPARAM(messagepos); + DWORD messagepos = ::GetMessagePos(); + pos.x = GET_X_LPARAM(messagepos); + pos.y = GET_Y_LPARAM(messagepos); #else - GetCursorPos(&pos); + GetCursorPos(&pos); #endif - ::SetForegroundWindow(m_tnd.hWnd); - ::TrackPopupMenu(hSubMenu, 0, pos.x, pos.y, 0, hTargetWnd, NULL); + ::SetForegroundWindow(m_tnd.hWnd); + ::TrackPopupMenu(hSubMenu, 0, pos.x, pos.y, 0, hTargetWnd, NULL); - // BUGFIX: See "PRB: Menus for Notification Icons Don't Work Correctly" - ::PostMessage(m_tnd.hWnd, WM_NULL, 0, 0); + // BUGFIX: See "PRB: Menus for Notification Icons Don't Work Correctly" + ::PostMessage(m_tnd.hWnd, WM_NULL, 0, 0); - DestroyMenu(hMenu); - } -#if defined(_WIN32_WCE) //&& _WIN32_WCE < 211 - if (LOWORD(lParam) == WM_LBUTTONDBLCLK && bAltPressed) + DestroyMenu(hMenu); + } +#if defined(_WIN32_WCE) //&& _WIN32_WCE < 211 + if (LOWORD(lParam) == WM_LBUTTONDBLCLK && bAltPressed) #else - else if (LOWORD(lParam) == WM_LBUTTONDBLCLK) + else if (LOWORD(lParam) == WM_LBUTTONDBLCLK) #endif - { - // double click received, the default action is to execute default menu item - ::SetForegroundWindow(m_tnd.hWnd); - - UINT uItem; - if (m_DefaultMenuItemByPos) - { - HMENU hMenu = ::LoadMenu(m_hInstance, MAKEINTRESOURCE(m_tnd.uID)); - if (!hMenu) - return 0; - - HMENU hSubMenu = ::GetSubMenu(hMenu, 0); - if (!hSubMenu) - return 0; - uItem = ::GetMenuItemID(hSubMenu, m_DefaultMenuItemID); - - DestroyMenu(hMenu); - } - else - uItem = m_DefaultMenuItemID; - - ::PostMessage(hTargetWnd, WM_COMMAND, uItem, 0); - } + { + // double click received, the default action is to execute default menu item + ::SetForegroundWindow(m_tnd.hWnd); - return 1; + UINT uItem; + if (m_DefaultMenuItemByPos) { + HMENU hMenu = ::LoadMenu(m_hInstance, MAKEINTRESOURCE(m_tnd.uID)); + if (!hMenu) + return 0; + + HMENU hSubMenu = ::GetSubMenu(hMenu, 0); + if (!hSubMenu) + return 0; + uItem = ::GetMenuItemID(hSubMenu, m_DefaultMenuItemID); + + DestroyMenu(hMenu); + } else + uItem = m_DefaultMenuItemID; + + ::PostMessage(hTargetWnd, WM_COMMAND, uItem, 0); + } + + return 1; } // This is the global (static) callback function for all TrayIcon windows -LRESULT PASCAL CSystemTray::WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - // The option here is to maintain a list of all TrayIcon windows, - // and iterate through them. If you do this, remove these 3 lines. - CSystemTray* pTrayIcon = m_pThis; - if (pTrayIcon->GetSafeHwnd() != hWnd) - return ::DefWindowProc(hWnd, message, wParam, lParam); - - // If maintaining a list of TrayIcon windows, then the following... - // pTrayIcon = GetFirstTrayIcon() - // while (pTrayIcon != NULL) - // { - // if (pTrayIcon->GetSafeHwnd() != hWnd) continue; - - // Taskbar has been recreated - all TrayIcons must process this. - if (message == CSystemTray::m_nTaskbarCreatedMsg) - return pTrayIcon->OnTaskbarCreated(wParam, lParam); - - // Animation timer - if (message == WM_TIMER && wParam == pTrayIcon->GetTimerID()) - return pTrayIcon->OnTimer(wParam); - - // Settings changed - if (message == WM_SETTINGCHANGE && wParam == pTrayIcon->GetTimerID()) - return pTrayIcon->OnSettingChange(wParam, (LPCTSTR) lParam); - - // Is the message from the icon for this TrayIcon? - if (message == pTrayIcon->GetCallbackMessage()) - return pTrayIcon->OnTrayNotification(wParam, lParam); - - // pTrayIcon = GetNextTrayIcon(); - // } - - // Message has not been processed, so default. +LRESULT PASCAL CSystemTray::WindowProc(HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam) { + // The option here is to maintain a list of all TrayIcon windows, + // and iterate through them. If you do this, remove these 3 lines. + CSystemTray* pTrayIcon = m_pThis; + if (pTrayIcon->GetSafeHwnd() != hWnd) return ::DefWindowProc(hWnd, message, wParam, lParam); + + // If maintaining a list of TrayIcon windows, then the following... + // pTrayIcon = GetFirstTrayIcon() + // while (pTrayIcon != NULL) + // { + // if (pTrayIcon->GetSafeHwnd() != hWnd) continue; + + // Taskbar has been recreated - all TrayIcons must process this. + if (message == CSystemTray::m_nTaskbarCreatedMsg) + return pTrayIcon->OnTaskbarCreated(wParam, lParam); + + // Animation timer + if (message == WM_TIMER && wParam == pTrayIcon->GetTimerID()) + return pTrayIcon->OnTimer(wParam); + + // Settings changed + if (message == WM_SETTINGCHANGE && wParam == pTrayIcon->GetTimerID()) + return pTrayIcon->OnSettingChange(wParam, (LPCTSTR)lParam); + + // Is the message from the icon for this TrayIcon? + if (message == pTrayIcon->GetCallbackMessage()) + return pTrayIcon->OnTrayNotification(wParam, lParam); + + // pTrayIcon = GetNextTrayIcon(); + // } + + // Message has not been processed, so default. + return ::DefWindowProc(hWnd, message, wParam, lParam); } -void CSystemTray::InstallIconPending() -{ - // Is the icon display pending, and it's not been set as "hidden"? - if (!m_bShowIconPending || m_bHidden) - return; +void CSystemTray::InstallIconPending() { + // Is the icon display pending, and it's not been set as "hidden"? + if (!m_bShowIconPending || m_bHidden) + return; - // Reset the flags to what was used at creation - m_tnd.uFlags = m_uCreationFlags; + // Reset the flags to what was used at creation + m_tnd.uFlags = m_uCreationFlags; - // Try and recreate the icon - m_bHidden = !Shell_NotifyIcon(NIM_ADD, &m_tnd); + // Try and recreate the icon + m_bHidden = !Shell_NotifyIcon(NIM_ADD, &m_tnd); - // If it's STILL hidden, then have another go next time... - m_bShowIconPending = !m_bHidden; + // If it's STILL hidden, then have another go next time... + m_bShowIconPending = !m_bHidden; - ASSERT(m_bHidden == FALSE); + ASSERT(m_bHidden == FALSE); } ///////////////////////////////////////////////////////////////////////////// // For minimising/maximising from system tray -BOOL CALLBACK FindTrayWnd(HWND hwnd, LPARAM lParam) -{ - TCHAR szClassName[256]; - GetClassName(hwnd, szClassName, 255); - - // Did we find the Main System Tray? If so, then get its size and keep going - if (_tcscmp(szClassName, _T("TrayNotifyWnd")) == 0) - { - LPRECT lpRect = (LPRECT) lParam; - ::GetWindowRect(hwnd, lpRect); - return TRUE; - } +BOOL CALLBACK FindTrayWnd(HWND hwnd, LPARAM lParam) { + TCHAR szClassName[256]; + GetClassName(hwnd, szClassName, 255); - // Did we find the System Clock? If so, then adjust the size of the rectangle - // we have and quit (clock will be found after the system tray) - if (_tcscmp(szClassName, _T("TrayClockWClass")) == 0) - { - LPRECT lpRect = (LPRECT) lParam; - RECT rectClock; - ::GetWindowRect(hwnd, &rectClock); - // if clock is above system tray adjust accordingly - if (rectClock.bottom < lpRect->bottom-5) // 10 = random fudge factor. - lpRect->top = rectClock.bottom; - else - lpRect->right = rectClock.left; - return FALSE; - } - + // Did we find the Main System Tray? If so, then get its size and keep going + if (_tcscmp(szClassName, _T("TrayNotifyWnd")) == 0) { + LPRECT lpRect = (LPRECT)lParam; + ::GetWindowRect(hwnd, lpRect); return TRUE; + } + + // Did we find the System Clock? If so, then adjust the size of the rectangle + // we have and quit (clock will be found after the system tray) + if (_tcscmp(szClassName, _T("TrayClockWClass")) == 0) { + LPRECT lpRect = (LPRECT)lParam; + RECT rectClock; + ::GetWindowRect(hwnd, &rectClock); + // if clock is above system tray adjust accordingly + if (rectClock.bottom < lpRect->bottom - 5) // 10 = random fudge factor. + lpRect->top = rectClock.bottom; + else + lpRect->right = rectClock.left; + return FALSE; + } + + return TRUE; } - + #ifndef _WIN32_WCE -void CSystemTray::GetTrayWndRect(LPRECT lprect) -{ +void CSystemTray::GetTrayWndRect(LPRECT lprect) { #define DEFAULT_RECT_WIDTH 150 #define DEFAULT_RECT_HEIGHT 30 - HWND hShellTrayWnd = FindWindow(_T("Shell_TrayWnd"), NULL); - if (hShellTrayWnd) - { - GetWindowRect(hShellTrayWnd, lprect); - EnumChildWindows(hShellTrayWnd, FindTrayWnd, (LPARAM)lprect); - return; - } - // OK, we failed to get the rect from the quick hack. Either explorer isn't - // running or it's a new version of the shell with the window class names - // changed (how dare Microsoft change these undocumented class names!) So, we - // try to find out what side of the screen the taskbar is connected to. We - // know that the system tray is either on the right or the bottom of the - // taskbar, so we can make a good guess at where to minimize to - APPBARDATA appBarData; - appBarData.cbSize=sizeof(appBarData); - if (SHAppBarMessage(ABM_GETTASKBARPOS,&appBarData)) - { - // We know the edge the taskbar is connected to, so guess the rect of the - // system tray. Use various fudge factor to make it look good - switch(appBarData.uEdge) - { - case ABE_LEFT: - case ABE_RIGHT: - // We want to minimize to the bottom of the taskbar - lprect->top = appBarData.rc.bottom-100; - lprect->bottom = appBarData.rc.bottom-16; - lprect->left = appBarData.rc.left; - lprect->right = appBarData.rc.right; - break; - - case ABE_TOP: - case ABE_BOTTOM: - // We want to minimize to the right of the taskbar - lprect->top = appBarData.rc.top; - lprect->bottom = appBarData.rc.bottom; - lprect->left = appBarData.rc.right-100; - lprect->right = appBarData.rc.right-16; - break; - } - return; + HWND hShellTrayWnd = FindWindow(_T("Shell_TrayWnd"), NULL); + if (hShellTrayWnd) { + GetWindowRect(hShellTrayWnd, lprect); + EnumChildWindows(hShellTrayWnd, FindTrayWnd, (LPARAM)lprect); + return; + } + // OK, we failed to get the rect from the quick hack. Either explorer isn't + // running or it's a new version of the shell with the window class names + // changed (how dare Microsoft change these undocumented class names!) So, we + // try to find out what side of the screen the taskbar is connected to. We + // know that the system tray is either on the right or the bottom of the + // taskbar, so we can make a good guess at where to minimize to + APPBARDATA appBarData; + appBarData.cbSize = sizeof(appBarData); + if (SHAppBarMessage(ABM_GETTASKBARPOS, &appBarData)) { + // We know the edge the taskbar is connected to, so guess the rect of the + // system tray. Use various fudge factor to make it look good + switch (appBarData.uEdge) { + case ABE_LEFT: + case ABE_RIGHT: + // We want to minimize to the bottom of the taskbar + lprect->top = appBarData.rc.bottom - 100; + lprect->bottom = appBarData.rc.bottom - 16; + lprect->left = appBarData.rc.left; + lprect->right = appBarData.rc.right; + break; + + case ABE_TOP: + case ABE_BOTTOM: + // We want to minimize to the right of the taskbar + lprect->top = appBarData.rc.top; + lprect->bottom = appBarData.rc.bottom; + lprect->left = appBarData.rc.right - 100; + lprect->right = appBarData.rc.right - 16; + break; } - - // Blimey, we really aren't in luck. It's possible that a third party shell - // is running instead of explorer. This shell might provide support for the - // system tray, by providing a Shell_TrayWnd window (which receives the - // messages for the icons) So, look for a Shell_TrayWnd window and work out - // the rect from that. Remember that explorer's taskbar is the Shell_TrayWnd, - // and stretches either the width or the height of the screen. We can't rely - // on the 3rd party shell's Shell_TrayWnd doing the same, in fact, we can't - // rely on it being any size. The best we can do is just blindly use the - // window rect, perhaps limiting the width and height to, say 150 square. - // Note that if the 3rd party shell supports the same configuraion as - // explorer (the icons hosted in NotifyTrayWnd, which is a child window of - // Shell_TrayWnd), we would already have caught it above - if (hShellTrayWnd) - { - ::GetWindowRect(hShellTrayWnd, lprect); - if (lprect->right - lprect->left > DEFAULT_RECT_WIDTH) - lprect->left = lprect->right - DEFAULT_RECT_WIDTH; - if (lprect->bottom - lprect->top > DEFAULT_RECT_HEIGHT) - lprect->top = lprect->bottom - DEFAULT_RECT_HEIGHT; - - return; - } - - // OK. Haven't found a thing. Provide a default rect based on the current work - // area - SystemParametersInfo(SPI_GETWORKAREA,0,lprect, 0); - lprect->left = lprect->right - DEFAULT_RECT_WIDTH; - lprect->top = lprect->bottom - DEFAULT_RECT_HEIGHT; + return; + } + + // Blimey, we really aren't in luck. It's possible that a third party shell + // is running instead of explorer. This shell might provide support for the + // system tray, by providing a Shell_TrayWnd window (which receives the + // messages for the icons) So, look for a Shell_TrayWnd window and work out + // the rect from that. Remember that explorer's taskbar is the Shell_TrayWnd, + // and stretches either the width or the height of the screen. We can't rely + // on the 3rd party shell's Shell_TrayWnd doing the same, in fact, we can't + // rely on it being any size. The best we can do is just blindly use the + // window rect, perhaps limiting the width and height to, say 150 square. + // Note that if the 3rd party shell supports the same configuraion as + // explorer (the icons hosted in NotifyTrayWnd, which is a child window of + // Shell_TrayWnd), we would already have caught it above + if (hShellTrayWnd) { + ::GetWindowRect(hShellTrayWnd, lprect); + if (lprect->right - lprect->left > DEFAULT_RECT_WIDTH) + lprect->left = lprect->right - DEFAULT_RECT_WIDTH; + if (lprect->bottom - lprect->top > DEFAULT_RECT_HEIGHT) + lprect->top = lprect->bottom - DEFAULT_RECT_HEIGHT; + + return; + } + + // OK. Haven't found a thing. Provide a default rect based on the current work + // area + SystemParametersInfo(SPI_GETWORKAREA, 0, lprect, 0); + lprect->left = lprect->right - DEFAULT_RECT_WIDTH; + lprect->top = lprect->bottom - DEFAULT_RECT_HEIGHT; } -// Check to see if the animation has been disabled (Matthew Ellis ) -BOOL CSystemTray::GetDoWndAnimation() -{ +// Check to see if the animation has been disabled (Matthew Ellis +// ) +BOOL CSystemTray::GetDoWndAnimation() { ANIMATIONINFO ai; - ai.cbSize=sizeof(ai); - SystemParametersInfo(SPI_GETANIMATION,sizeof(ai),&ai,0); + ai.cbSize = sizeof(ai); + SystemParametersInfo(SPI_GETANIMATION, sizeof(ai), &ai, 0); - return ai.iMinAnimate?TRUE:FALSE; + return ai.iMinAnimate ? TRUE : FALSE; } #endif -BOOL CSystemTray::RemoveTaskbarIcon(HWND hWnd) -{ - // Create static invisible window - if (!::IsWindow(m_hWndInvisible)) - { -// 2007-11-14 GONG - m_hWndInvisible = CreateWindowEx(0, _T("Static"), _T(""), WS_POPUP, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - NULL, 0, NULL, 0); +BOOL CSystemTray::RemoveTaskbarIcon(HWND hWnd) { + // Create static invisible window + if (!::IsWindow(m_hWndInvisible)) { + // 2007-11-14 GONG + m_hWndInvisible = CreateWindowEx( + 0, _T("Static"), _T(""), WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, NULL, 0, NULL, 0); - if (!m_hWndInvisible) - return FALSE; - } + if (!m_hWndInvisible) + return FALSE; + } - SetParent(hWnd, m_hWndInvisible); + SetParent(hWnd, m_hWndInvisible); - return TRUE; + return TRUE; } -void CSystemTray::MinimiseToTray(HWND hWnd) -{ +void CSystemTray::MinimiseToTray(HWND hWnd) { #ifndef _WIN32_WCE - if (GetDoWndAnimation()) - { - RECT rectFrom, rectTo; + if (GetDoWndAnimation()) { + RECT rectFrom, rectTo; - GetWindowRect(hWnd, &rectFrom); - GetTrayWndRect(&rectTo); + GetWindowRect(hWnd, &rectFrom); + GetTrayWndRect(&rectTo); - DrawAnimatedRects(hWnd, IDANI_CAPTION, &rectFrom, &rectTo); - } + DrawAnimatedRects(hWnd, IDANI_CAPTION, &rectFrom, &rectTo); + } - RemoveTaskbarIcon(hWnd); - SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) &~ WS_VISIBLE); + RemoveTaskbarIcon(hWnd); + SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) & ~WS_VISIBLE); #endif } -void CSystemTray::MaximiseFromTray(HWND hWnd) -{ +void CSystemTray::MaximiseFromTray(HWND hWnd) { #ifndef _WIN32_WCE - if (GetDoWndAnimation()) - { - RECT rectTo; - ::GetWindowRect(hWnd, &rectTo); - - RECT rectFrom; - GetTrayWndRect(&rectFrom); - - ::SetParent(hWnd, NULL); - DrawAnimatedRects(hWnd, IDANI_CAPTION, &rectFrom, &rectTo); - } - else - ::SetParent(hWnd, NULL); - - SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) | WS_VISIBLE); - RedrawWindow(hWnd, NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_FRAME | - RDW_INVALIDATE | RDW_ERASE); - - // Move focus away and back again to ensure taskbar icon is recreated - if (::IsWindow(m_hWndInvisible)) - SetActiveWindow(m_hWndInvisible); - SetActiveWindow(hWnd); - SetForegroundWindow(hWnd); + if (GetDoWndAnimation()) { + RECT rectTo; + ::GetWindowRect(hWnd, &rectTo); + + RECT rectFrom; + GetTrayWndRect(&rectFrom); + + ::SetParent(hWnd, NULL); + DrawAnimatedRects(hWnd, IDANI_CAPTION, &rectFrom, &rectTo); + } else + ::SetParent(hWnd, NULL); + + SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) | WS_VISIBLE); + RedrawWindow( + hWnd, NULL, NULL, + RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_FRAME | RDW_INVALIDATE | RDW_ERASE); + + // Move focus away and back again to ensure taskbar icon is recreated + if (::IsWindow(m_hWndInvisible)) + SetActiveWindow(m_hWndInvisible); + SetActiveWindow(hWnd); + SetForegroundWindow(hWnd); #endif } \ No newline at end of file diff --git a/WeaselServer/WeaselServer.cpp b/WeaselServer/WeaselServer.cpp index edeff0915..1ed867b31 100644 --- a/WeaselServer/WeaselServer.cpp +++ b/WeaselServer/WeaselServer.cpp @@ -17,124 +17,123 @@ #pragma comment(lib, "Shcore.lib") CAppModule _Module; -int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow) -{ - LCID lcid = GetUserDefaultLCID(); - if (lcid == 2052 || lcid == 3072 || lcid == 4100) { - LANGID langId = SetThreadUILanguage(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)); - SetThreadLocale(langId); - } - else { - LANGID langId = SetThreadUILanguage(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)); - SetThreadLocale(langId); - } - - if( !IsWindowsBlueOrLaterEx() ) - { - if(GetThreadUILanguage() == MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)) - ::MessageBox(NULL, L"僅支持Windows 8.1或更高版本系統", L"系統版本過低", MB_ICONERROR); - else - ::MessageBox(NULL, L"仅支持Windows 8.1或更高版本系统", L"系统版本过低", MB_ICONERROR); - return 0; - } - SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); - - // 防止服务进程开启输入法 - ImmDisableIME(-1); - - WCHAR user_name[20] = {0}; - DWORD size = _countof(user_name); - GetUserName(user_name, &size); - if (!_wcsicmp(user_name, L"SYSTEM")) - { - return 1; - } - - HRESULT hRes = ::CoInitialize(NULL); - // If you are running on NT 4.0 or higher you can use the following call instead to - // make the EXE free threaded. This means that calls come in on a random RPC thread. - //HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); - ATLASSERT(SUCCEEDED(hRes)); - - // this resolves ATL window thunking problem when Microsoft Layer for Unicode (MSLU) is used - ::DefWindowProc(NULL, 0, 0, 0L); - - AtlInitCommonControls(ICC_BAR_CLASSES); // add flags to support other controls - - hRes = _Module.Init(NULL, hInstance); - ATLASSERT(SUCCEEDED(hRes)); - - if (!wcscmp(L"/userdir", lpstrCmdLine)) - { - CreateDirectory(WeaselUserDataPath().c_str(), NULL); - WeaselServerApp::explore(WeaselUserDataPath()); - return 0; - } - if (!wcscmp(L"/weaseldir", lpstrCmdLine)) - { - WeaselServerApp::explore(WeaselServerApp::install_dir()); - return 0; - } - if (!wcscmp(L"/ascii", lpstrCmdLine) || !wcscmp(L"/nascii", lpstrCmdLine)) - { - weasel::Client client; - bool ascii = !wcscmp(L"/ascii", lpstrCmdLine); - if (client.Connect()) // try to connect to running server - { - if (ascii) - client.TrayCommand(ID_WEASELTRAY_ENABLE_ASCII); - else - client.TrayCommand(ID_WEASELTRAY_DISABLE_ASCII); - } - return 0; - } - - // command line option /q stops the running server - bool quit = !wcscmp(L"/q", lpstrCmdLine) || !wcscmp(L"/quit", lpstrCmdLine); - // restart if already running - { - weasel::Client client; - if (client.Connect()) // try to connect to running server - { - client.ShutdownServer(); - if (quit) - return 0; - int retry = 0; - while (client.Connect() && retry < 10) { - client.ShutdownServer(); - retry++; - Sleep(50); - } - if (retry >= 10) - return 0; - } - else if (quit) - return 0; - } - - bool check_updates = !wcscmp(L"/update", lpstrCmdLine); - if (check_updates) - { - WeaselServerApp::check_update(); - } - - CreateDirectory(WeaselUserDataPath().c_str(), NULL); - - int nRet = 0; - try - { - WeaselServerApp app; - RegisterApplicationRestart(NULL, 0); - nRet = app.Run(); - } - catch (...) - { - // bad luck... - nRet = -1; - } - - _Module.Term(); - ::CoUninitialize(); - - return nRet; +int WINAPI _tWinMain(HINSTANCE hInstance, + HINSTANCE /*hPrevInstance*/, + LPTSTR lpstrCmdLine, + int nCmdShow) { + LCID lcid = GetUserDefaultLCID(); + if (lcid == 2052 || lcid == 3072 || lcid == 4100) { + LANGID langId = SetThreadUILanguage( + MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)); + SetThreadLocale(langId); + } else { + LANGID langId = SetThreadUILanguage( + MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)); + SetThreadLocale(langId); + } + + if (!IsWindowsBlueOrLaterEx()) { + if (GetThreadUILanguage() == + MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)) + ::MessageBox(NULL, L"僅支持Windows 8.1或更高版本系統", L"系統版本過低", + MB_ICONERROR); + else + ::MessageBox(NULL, L"仅支持Windows 8.1或更高版本系统", L"系统版本过低", + MB_ICONERROR); + return 0; + } + SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); + + // 防止服务进程开启输入法 + ImmDisableIME(-1); + + WCHAR user_name[20] = {0}; + DWORD size = _countof(user_name); + GetUserName(user_name, &size); + if (!_wcsicmp(user_name, L"SYSTEM")) { + return 1; + } + + HRESULT hRes = ::CoInitialize(NULL); + // If you are running on NT 4.0 or higher you can use the following call + // instead to make the EXE free threaded. This means that calls come in on a + // random RPC thread. + // HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); + ATLASSERT(SUCCEEDED(hRes)); + + // this resolves ATL window thunking problem when Microsoft Layer for Unicode + // (MSLU) is used + ::DefWindowProc(NULL, 0, 0, 0L); + + AtlInitCommonControls( + ICC_BAR_CLASSES); // add flags to support other controls + + hRes = _Module.Init(NULL, hInstance); + ATLASSERT(SUCCEEDED(hRes)); + + if (!wcscmp(L"/userdir", lpstrCmdLine)) { + CreateDirectory(WeaselUserDataPath().c_str(), NULL); + WeaselServerApp::explore(WeaselUserDataPath()); + return 0; + } + if (!wcscmp(L"/weaseldir", lpstrCmdLine)) { + WeaselServerApp::explore(WeaselServerApp::install_dir()); + return 0; + } + if (!wcscmp(L"/ascii", lpstrCmdLine) || !wcscmp(L"/nascii", lpstrCmdLine)) { + weasel::Client client; + bool ascii = !wcscmp(L"/ascii", lpstrCmdLine); + if (client.Connect()) // try to connect to running server + { + if (ascii) + client.TrayCommand(ID_WEASELTRAY_ENABLE_ASCII); + else + client.TrayCommand(ID_WEASELTRAY_DISABLE_ASCII); + } + return 0; + } + + // command line option /q stops the running server + bool quit = !wcscmp(L"/q", lpstrCmdLine) || !wcscmp(L"/quit", lpstrCmdLine); + // restart if already running + { + weasel::Client client; + if (client.Connect()) // try to connect to running server + { + client.ShutdownServer(); + if (quit) + return 0; + int retry = 0; + while (client.Connect() && retry < 10) { + client.ShutdownServer(); + retry++; + Sleep(50); + } + if (retry >= 10) + return 0; + } else if (quit) + return 0; + } + + bool check_updates = !wcscmp(L"/update", lpstrCmdLine); + if (check_updates) { + WeaselServerApp::check_update(); + } + + CreateDirectory(WeaselUserDataPath().c_str(), NULL); + + int nRet = 0; + try { + WeaselServerApp app; + RegisterApplicationRestart(NULL, 0); + nRet = app.Run(); + } catch (...) { + // bad luck... + nRet = -1; + } + + _Module.Term(); + ::CoUninitialize(); + + return nRet; } diff --git a/WeaselServer/WeaselServerApp.cpp b/WeaselServer/WeaselServerApp.cpp index 65e7ee656..93243fbbc 100644 --- a/WeaselServer/WeaselServerApp.cpp +++ b/WeaselServer/WeaselServerApp.cpp @@ -3,58 +3,64 @@ #include WeaselServerApp::WeaselServerApp() - : m_handler(std::make_unique(&m_ui)) - , tray_icon(m_ui) -{ - //m_handler.reset(new RimeWithWeaselHandler(&m_ui)); - m_server.SetRequestHandler(m_handler.get()); - SetupMenuHandlers(); + : m_handler(std::make_unique(&m_ui)), + tray_icon(m_ui) { + // m_handler.reset(new RimeWithWeaselHandler(&m_ui)); + m_server.SetRequestHandler(m_handler.get()); + SetupMenuHandlers(); } -WeaselServerApp::~WeaselServerApp() -{ -} +WeaselServerApp::~WeaselServerApp() {} -int WeaselServerApp::Run() -{ - if (!m_server.Start()) - return -1; +int WeaselServerApp::Run() { + if (!m_server.Start()) + return -1; - //win_sparkle_set_appcast_url("http://localhost:8000/weasel/update/appcast.xml"); - win_sparkle_set_registry_path("Software\\Rime\\Weasel\\Updates"); - win_sparkle_init(); - m_ui.Create(m_server.GetHWnd()); + // win_sparkle_set_appcast_url("http://localhost:8000/weasel/update/appcast.xml"); + win_sparkle_set_registry_path("Software\\Rime\\Weasel\\Updates"); + win_sparkle_init(); + m_ui.Create(m_server.GetHWnd()); - tray_icon.Create(m_server.GetHWnd()); - tray_icon.Refresh(); + tray_icon.Create(m_server.GetHWnd()); + tray_icon.Refresh(); - m_handler->Initialize(); - m_handler->OnUpdateUI([this]() { - tray_icon.Refresh(); - }); + m_handler->Initialize(); + m_handler->OnUpdateUI([this]() { tray_icon.Refresh(); }); - int ret = m_server.Run(); + int ret = m_server.Run(); - m_handler->Finalize(); - m_ui.Destroy(); - tray_icon.RemoveIcon(); - win_sparkle_cleanup(); + m_handler->Finalize(); + m_ui.Destroy(); + tray_icon.RemoveIcon(); + win_sparkle_cleanup(); - return ret; + return ret; } -void WeaselServerApp::SetupMenuHandlers() -{ - boost::filesystem::path dir = install_dir(); - m_server.AddMenuHandler(ID_WEASELTRAY_QUIT, [this] { return m_server.Stop() == 0; }); - m_server.AddMenuHandler(ID_WEASELTRAY_DEPLOY, std::bind(execute, dir / L"WeaselDeployer.exe", std::wstring(L"/deploy"))); - m_server.AddMenuHandler(ID_WEASELTRAY_SETTINGS, std::bind(execute, dir / L"WeaselDeployer.exe", std::wstring())); - m_server.AddMenuHandler(ID_WEASELTRAY_DICT_MANAGEMENT, std::bind(execute, dir / L"WeaselDeployer.exe", std::wstring(L"/dict"))); - m_server.AddMenuHandler(ID_WEASELTRAY_SYNC, std::bind(execute, dir / L"WeaselDeployer.exe", std::wstring(L"/sync"))); - m_server.AddMenuHandler(ID_WEASELTRAY_WIKI, std::bind(open, L"https://rime.im/docs/")); - m_server.AddMenuHandler(ID_WEASELTRAY_HOMEPAGE, std::bind(open, L"https://rime.im/")); - m_server.AddMenuHandler(ID_WEASELTRAY_FORUM, std::bind(open, L"https://rime.im/discuss/")); - m_server.AddMenuHandler(ID_WEASELTRAY_CHECKUPDATE, check_update); - m_server.AddMenuHandler(ID_WEASELTRAY_INSTALLDIR, std::bind(explore, dir)); - m_server.AddMenuHandler(ID_WEASELTRAY_USERCONFIG, std::bind(explore, WeaselUserDataPath())); +void WeaselServerApp::SetupMenuHandlers() { + boost::filesystem::path dir = install_dir(); + m_server.AddMenuHandler(ID_WEASELTRAY_QUIT, + [this] { return m_server.Stop() == 0; }); + m_server.AddMenuHandler(ID_WEASELTRAY_DEPLOY, + std::bind(execute, dir / L"WeaselDeployer.exe", + std::wstring(L"/deploy"))); + m_server.AddMenuHandler( + ID_WEASELTRAY_SETTINGS, + std::bind(execute, dir / L"WeaselDeployer.exe", std::wstring())); + m_server.AddMenuHandler( + ID_WEASELTRAY_DICT_MANAGEMENT, + std::bind(execute, dir / L"WeaselDeployer.exe", std::wstring(L"/dict"))); + m_server.AddMenuHandler( + ID_WEASELTRAY_SYNC, + std::bind(execute, dir / L"WeaselDeployer.exe", std::wstring(L"/sync"))); + m_server.AddMenuHandler(ID_WEASELTRAY_WIKI, + std::bind(open, L"https://rime.im/docs/")); + m_server.AddMenuHandler(ID_WEASELTRAY_HOMEPAGE, + std::bind(open, L"https://rime.im/")); + m_server.AddMenuHandler(ID_WEASELTRAY_FORUM, + std::bind(open, L"https://rime.im/discuss/")); + m_server.AddMenuHandler(ID_WEASELTRAY_CHECKUPDATE, check_update); + m_server.AddMenuHandler(ID_WEASELTRAY_INSTALLDIR, std::bind(explore, dir)); + m_server.AddMenuHandler(ID_WEASELTRAY_USERCONFIG, + std::bind(explore, WeaselUserDataPath())); } diff --git a/WeaselServer/WeaselServerApp.h b/WeaselServer/WeaselServerApp.h index eaca3a976..a214c1921 100644 --- a/WeaselServer/WeaselServerApp.h +++ b/WeaselServer/WeaselServerApp.h @@ -15,52 +15,49 @@ namespace fs = boost::filesystem; class WeaselServerApp { -public: - static bool execute(const fs::path &cmd, const std::wstring &args) - { - return (int)ShellExecuteW(NULL, NULL, cmd.c_str(), args.c_str(), NULL, SW_SHOWNORMAL) > 32; - } - - static bool explore(const fs::path &path) - { - std::wstring quoted_path(L"\"" + path.wstring() + L"\""); - return (int)ShellExecuteW(NULL, L"open", L"explorer", quoted_path.c_str(), NULL, SW_SHOWNORMAL) > 32; - } - - static bool open(const fs::path &path) - { - return (int)ShellExecuteW(NULL, L"open", path.c_str(), NULL, NULL, SW_SHOWNORMAL) > 32; - } - - static bool check_update() - { - // when checked manually, show testing versions too - std::string feed_url = GetCustomResource("ManualUpdateFeedURL", "APPCAST"); - if (!feed_url.empty()) - { - win_sparkle_set_appcast_url(feed_url.c_str()); - } - win_sparkle_check_update_with_ui(); - return true; - } - - static fs::path install_dir() - { - WCHAR exe_path[MAX_PATH] = { 0 }; - GetModuleFileNameW(GetModuleHandle(NULL), exe_path, _countof(exe_path)); - return fs::path(exe_path).remove_filename(); - } - -public: - WeaselServerApp(); - ~WeaselServerApp(); - int Run(); - -protected: - void SetupMenuHandlers(); - - weasel::Server m_server; - weasel::UI m_ui; - WeaselTrayIcon tray_icon; - std::unique_ptr m_handler; + public: + static bool execute(const fs::path& cmd, const std::wstring& args) { + return (int)ShellExecuteW(NULL, NULL, cmd.c_str(), args.c_str(), NULL, + SW_SHOWNORMAL) > 32; + } + + static bool explore(const fs::path& path) { + std::wstring quoted_path(L"\"" + path.wstring() + L"\""); + return (int)ShellExecuteW(NULL, L"open", L"explorer", quoted_path.c_str(), + NULL, SW_SHOWNORMAL) > 32; + } + + static bool open(const fs::path& path) { + return (int)ShellExecuteW(NULL, L"open", path.c_str(), NULL, NULL, + SW_SHOWNORMAL) > 32; + } + + static bool check_update() { + // when checked manually, show testing versions too + std::string feed_url = GetCustomResource("ManualUpdateFeedURL", "APPCAST"); + if (!feed_url.empty()) { + win_sparkle_set_appcast_url(feed_url.c_str()); + } + win_sparkle_check_update_with_ui(); + return true; + } + + static fs::path install_dir() { + WCHAR exe_path[MAX_PATH] = {0}; + GetModuleFileNameW(GetModuleHandle(NULL), exe_path, _countof(exe_path)); + return fs::path(exe_path).remove_filename(); + } + + public: + WeaselServerApp(); + ~WeaselServerApp(); + int Run(); + + protected: + void SetupMenuHandlers(); + + weasel::Server m_server; + weasel::UI m_ui; + WeaselTrayIcon tray_icon; + std::unique_ptr m_handler; }; diff --git a/WeaselServer/WeaselService.cpp b/WeaselServer/WeaselService.cpp index 317412cd4..1545a45d8 100644 --- a/WeaselServer/WeaselService.cpp +++ b/WeaselServer/WeaselService.cpp @@ -3,179 +3,153 @@ #include "WeaselServerApp.h" #include -WeaselService *WeaselService::_service = NULL; - -WeaselService::WeaselService( - BOOL fCanStop = TRUE, - BOOL fCanShutdown = TRUE, - BOOL fCanPauseContinue = FALSE) -{ - _statusHandle = NULL; - - // The service runs in its own process. - _status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - - // The service is starting. - _status.dwCurrentState = SERVICE_START_PENDING; - - // The accepted commands of the service. - DWORD dwControlsAccepted = 0; - if (fCanStop) - dwControlsAccepted |= SERVICE_ACCEPT_STOP; - if (fCanShutdown) - dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN; - if (fCanPauseContinue) - dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE; - _status.dwControlsAccepted = dwControlsAccepted; - - _status.dwWin32ExitCode = NO_ERROR; - _status.dwServiceSpecificExitCode = 0; - _status.dwCheckPoint = 0; - _status.dwWaitHint = 0; - - _stopping = FALSE; - - // Create a manual-reset event that is not signaled at first to indicate - // the stopped signal of the service. - _stoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (_stoppedEvent == NULL) - { - throw GetLastError(); - } +WeaselService* WeaselService::_service = NULL; + +WeaselService::WeaselService(BOOL fCanStop = TRUE, + BOOL fCanShutdown = TRUE, + BOOL fCanPauseContinue = FALSE) { + _statusHandle = NULL; + + // The service runs in its own process. + _status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + + // The service is starting. + _status.dwCurrentState = SERVICE_START_PENDING; + + // The accepted commands of the service. + DWORD dwControlsAccepted = 0; + if (fCanStop) + dwControlsAccepted |= SERVICE_ACCEPT_STOP; + if (fCanShutdown) + dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN; + if (fCanPauseContinue) + dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE; + _status.dwControlsAccepted = dwControlsAccepted; + + _status.dwWin32ExitCode = NO_ERROR; + _status.dwServiceSpecificExitCode = 0; + _status.dwCheckPoint = 0; + _status.dwWaitHint = 0; + + _stopping = FALSE; + + // Create a manual-reset event that is not signaled at first to indicate + // the stopped signal of the service. + _stoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (_stoppedEvent == NULL) { + throw GetLastError(); + } } -WeaselService::~WeaselService() -{ - if (_stoppedEvent != NULL) - { - CloseHandle(_stoppedEvent); - } +WeaselService::~WeaselService() { + if (_stoppedEvent != NULL) { + CloseHandle(_stoppedEvent); + } } -BOOL WeaselService::Run(WeaselService &serv) -{ - _service = &serv; - SERVICE_TABLE_ENTRY serviceTable[] = - { - { WEASEL_SERVICE_NAME, ServiceMain }, - { NULL, NULL } - }; - - // Connects the main thread of a service process to the service control - // manager, which causes the thread to be the service control dispatcher - // thread for the calling process. This call returns when the service has - // stopped. The process should simply terminate when the call returns. - return StartServiceCtrlDispatcher(serviceTable); +BOOL WeaselService::Run(WeaselService& serv) { + _service = &serv; + SERVICE_TABLE_ENTRY serviceTable[] = {{WEASEL_SERVICE_NAME, ServiceMain}, + {NULL, NULL}}; + + // Connects the main thread of a service process to the service control + // manager, which causes the thread to be the service control dispatcher + // thread for the calling process. This call returns when the service has + // stopped. The process should simply terminate when the call returns. + return StartServiceCtrlDispatcher(serviceTable); } -void WeaselService::Start(DWORD dwArgc = 0, PWSTR * pszArgv = NULL) -{ - try - { - // Tell SCM that the service is starting. - SetServiceStatus(SERVICE_START_PENDING); - - // Perform service-specific initialization. - // if (IsWindowsVistaOrGreater()) - { - RegisterApplicationRestart(NULL, 0); - } - boost::thread{ [this] { - app.Run(); - } }; - // Tell SCM that the service is started. - SetServiceStatus(SERVICE_RUNNING); - - } - catch (DWORD dwError) - { - // Set the service status to be stopped. - SetServiceStatus(SERVICE_STOPPED, dwError); - } - catch (...) - { - // Set the service status to be stopped. - SetServiceStatus(SERVICE_STOPPED); - } +void WeaselService::Start(DWORD dwArgc = 0, PWSTR* pszArgv = NULL) { + try { + // Tell SCM that the service is starting. + SetServiceStatus(SERVICE_START_PENDING); + + // Perform service-specific initialization. + // if (IsWindowsVistaOrGreater()) + { RegisterApplicationRestart(NULL, 0); } + boost::thread{[this] { app.Run(); }}; + // Tell SCM that the service is started. + SetServiceStatus(SERVICE_RUNNING); + + } catch (DWORD dwError) { + // Set the service status to be stopped. + SetServiceStatus(SERVICE_STOPPED, dwError); + } catch (...) { + // Set the service status to be stopped. + SetServiceStatus(SERVICE_STOPPED); + } } -void WeaselService::Stop() -{ - DWORD dwOriginalState = _status.dwCurrentState; - try - { - // Tell SCM that the service is stopping. - SetServiceStatus(SERVICE_STOP_PENDING); - - // Perform service-specific stop operations. - weasel::Client client; - if (client.Connect()) // try to connect to running server - { - client.ShutdownServer(); - } - - // Tell SCM that the service is stopped. - SetServiceStatus(SERVICE_STOPPED); - } - catch (DWORD/* dwError */) - { - // Set the orginal service status. - SetServiceStatus(dwOriginalState); - } - catch (...) - { - // Set the orginal service status. - SetServiceStatus(dwOriginalState); - } +void WeaselService::Stop() { + DWORD dwOriginalState = _status.dwCurrentState; + try { + // Tell SCM that the service is stopping. + SetServiceStatus(SERVICE_STOP_PENDING); + + // Perform service-specific stop operations. + weasel::Client client; + if (client.Connect()) // try to connect to running server + { + client.ShutdownServer(); + } + + // Tell SCM that the service is stopped. + SetServiceStatus(SERVICE_STOPPED); + } catch (DWORD /* dwError */) { + // Set the orginal service status. + SetServiceStatus(dwOriginalState); + } catch (...) { + // Set the orginal service status. + SetServiceStatus(dwOriginalState); + } } -void WeaselService::ServiceMain(DWORD dwArgc, PWSTR *pszArgv) -{ - _service->_statusHandle = RegisterServiceCtrlHandler( - WEASEL_SERVICE_NAME, ServiceCtrlHandler); - if (_service->_statusHandle == NULL) - { - throw GetLastError(); - } - - // Start the service. - _service->Start(dwArgc, pszArgv); +void WeaselService::ServiceMain(DWORD dwArgc, PWSTR* pszArgv) { + _service->_statusHandle = + RegisterServiceCtrlHandler(WEASEL_SERVICE_NAME, ServiceCtrlHandler); + if (_service->_statusHandle == NULL) { + throw GetLastError(); + } + + // Start the service. + _service->Start(dwArgc, pszArgv); } -void WeaselService::ServiceCtrlHandler(DWORD dwCtrl) -{ - switch (dwCtrl) - { - case SERVICE_CONTROL_STOP: _service->Stop(); break; - case SERVICE_CONTROL_SHUTDOWN: _service->Shutdown(); break; - case SERVICE_CONTROL_INTERROGATE: break; - default: break; - } +void WeaselService::ServiceCtrlHandler(DWORD dwCtrl) { + switch (dwCtrl) { + case SERVICE_CONTROL_STOP: + _service->Stop(); + break; + case SERVICE_CONTROL_SHUTDOWN: + _service->Shutdown(); + break; + case SERVICE_CONTROL_INTERROGATE: + break; + default: + break; + } } void WeaselService::SetServiceStatus(DWORD dwCurrentState, - DWORD dwWin32ExitCode, - DWORD dwWaitHint) -{ - static DWORD dwCheckPoint = 1; + DWORD dwWin32ExitCode, + DWORD dwWaitHint) { + static DWORD dwCheckPoint = 1; - // Fill in the SERVICE_STATUS structure of the service. + // Fill in the SERVICE_STATUS structure of the service. - _status.dwCurrentState = dwCurrentState; - _status.dwWin32ExitCode = dwWin32ExitCode; - _status.dwWaitHint = dwWaitHint; + _status.dwCurrentState = dwCurrentState; + _status.dwWin32ExitCode = dwWin32ExitCode; + _status.dwWaitHint = dwWaitHint; - _status.dwCheckPoint = - ((dwCurrentState == SERVICE_RUNNING) || - (dwCurrentState == SERVICE_STOPPED)) ? - 0 : dwCheckPoint++; + _status.dwCheckPoint = ((dwCurrentState == SERVICE_RUNNING) || + (dwCurrentState == SERVICE_STOPPED)) + ? 0 + : dwCheckPoint++; - // Report the status of the service to the SCM. - ::SetServiceStatus(_statusHandle, &_status); + // Report the status of the service to the SCM. + ::SetServiceStatus(_statusHandle, &_status); } - -void WeaselService::Shutdown() -{ - SetServiceStatus(SERVICE_STOPPED); +void WeaselService::Shutdown() { + SetServiceStatus(SERVICE_STOPPED); } diff --git a/WeaselServer/WeaselService.h b/WeaselServer/WeaselService.h index 2683dbb2f..28927fbff 100644 --- a/WeaselServer/WeaselService.h +++ b/WeaselServer/WeaselService.h @@ -8,45 +8,42 @@ #define WEASEL_SERVICE_NAME L"WeaselInputService" class WeaselService { -public: - WeaselService( - BOOL fCanStop, - BOOL fCanShutdown, - BOOL fCanPauseContinue); - ~WeaselService(); - static BOOL Run(WeaselService &serv); + public: + WeaselService(BOOL fCanStop, BOOL fCanShutdown, BOOL fCanPauseContinue); + ~WeaselService(); + static BOOL Run(WeaselService& serv); - void Stop(); - // Start the service. - void Start(DWORD dwArgc, PWSTR *pszArgv); + void Stop(); + // Start the service. + void Start(DWORD dwArgc, PWSTR* pszArgv); -protected: - // Entry point for the service. It registers the handler function for the - // service and starts the service. - static void WINAPI ServiceMain(DWORD dwArgc, PWSTR *pszArgv); + protected: + // Entry point for the service. It registers the handler function for the + // service and starts the service. + static void WINAPI ServiceMain(DWORD dwArgc, PWSTR* pszArgv); - // The function is called by the SCM whenever a control code is sent to - // the service. - static void WINAPI ServiceCtrlHandler(DWORD dwCtrl); + // The function is called by the SCM whenever a control code is sent to + // the service. + static void WINAPI ServiceCtrlHandler(DWORD dwCtrl); - void SetServiceStatus(DWORD dwCurrentState, - DWORD dwWin32ExitCode = NO_ERROR, - DWORD dwWaitHint = 0); + void SetServiceStatus(DWORD dwCurrentState, + DWORD dwWin32ExitCode = NO_ERROR, + DWORD dwWaitHint = 0); - // Execute when the system is shutting down. - void Shutdown(); -private: - static WeaselService *_service; + // Execute when the system is shutting down. + void Shutdown(); - // The status of the service - SERVICE_STATUS _status; + private: + static WeaselService* _service; - // The service status handle - SERVICE_STATUS_HANDLE _statusHandle; + // The status of the service + SERVICE_STATUS _status; - BOOL _stopping; - HANDLE _stoppedEvent; + // The service status handle + SERVICE_STATUS_HANDLE _statusHandle; - WeaselServerApp app; + BOOL _stopping; + HANDLE _stoppedEvent; + WeaselServerApp app; }; diff --git a/WeaselServer/WeaselTrayIcon.cpp b/WeaselServer/WeaselTrayIcon.cpp index a02d9616c..53582a591 100644 --- a/WeaselServer/WeaselTrayIcon.cpp +++ b/WeaselServer/WeaselTrayIcon.cpp @@ -4,92 +4,84 @@ // nasty #include -static UINT mode_icon[] = { IDI_ZH, IDI_ZH, IDI_EN, IDI_RELOAD }; -static const WCHAR *mode_label[] = { NULL, /*L"中文"*/ NULL, /*L"西文"*/ NULL, L"維護中" }; +static UINT mode_icon[] = {IDI_ZH, IDI_ZH, IDI_EN, IDI_RELOAD}; +static const WCHAR* mode_label[] = {NULL, /*L"中文"*/ NULL, /*L"西文"*/ NULL, + L"維護中"}; -WeaselTrayIcon::WeaselTrayIcon(weasel::UI &ui) - : m_style(ui.style()), m_status(ui.status()), m_mode(INITIAL), m_schema_zhung_icon(), m_schema_ascii_icon(), m_disabled(false) -{ -} +WeaselTrayIcon::WeaselTrayIcon(weasel::UI& ui) + : m_style(ui.style()), + m_status(ui.status()), + m_mode(INITIAL), + m_schema_zhung_icon(), + m_schema_ascii_icon(), + m_disabled(false) {} -void WeaselTrayIcon::CustomizeMenu(HMENU hMenu) -{ -} +void WeaselTrayIcon::CustomizeMenu(HMENU hMenu) {} -BOOL WeaselTrayIcon::Create(HWND hTargetWnd) -{ - HMODULE hModule = GetModuleHandle(NULL); - CIcon icon; - icon.LoadIconW(IDI_ZH); - BOOL bRet = CSystemTray::Create(hModule, NULL, WM_WEASEL_TRAY_NOTIFY, - WEASEL_IME_NAME, icon, IDR_MENU_POPUP); - if (hTargetWnd) - { - SetTargetWnd(hTargetWnd); - } - if (!m_style.display_tray_icon) - { - RemoveIcon(); - } - return bRet; +BOOL WeaselTrayIcon::Create(HWND hTargetWnd) { + HMODULE hModule = GetModuleHandle(NULL); + CIcon icon; + icon.LoadIconW(IDI_ZH); + BOOL bRet = CSystemTray::Create(hModule, NULL, WM_WEASEL_TRAY_NOTIFY, + WEASEL_IME_NAME, icon, IDR_MENU_POPUP); + if (hTargetWnd) { + SetTargetWnd(hTargetWnd); + } + if (!m_style.display_tray_icon) { + RemoveIcon(); + } + return bRet; } -void WeaselTrayIcon::Refresh() -{ - if (!m_style.display_tray_icon && !m_status.disabled) // display notification when deploying - { - if (m_mode != INITIAL) - { - RemoveIcon(); - m_mode = INITIAL; - } - m_disabled = false; - return; - } - WeaselTrayMode mode = m_status.disabled ? DISABLED : - m_status.ascii_mode ? ASCII : ZHUNG; - /* change icon, when - 1,mode changed - 2,icon changed - 3,both m_schema_zhung_icon and m_style.current_zhung_icon empty(for initialize) - 4,both m_schema_ascii_icon and m_style.current_ascii_icon empty(for initialize) - */ - if (mode != m_mode - || m_schema_zhung_icon != m_style.current_zhung_icon - || (m_schema_zhung_icon.empty() && m_style.current_zhung_icon.empty()) - || m_schema_ascii_icon != m_style.current_ascii_icon - || (m_schema_ascii_icon.empty() && m_style.current_ascii_icon.empty()) - ) - { - ShowIcon(); - m_mode = mode; - m_schema_zhung_icon = m_style.current_zhung_icon; - m_schema_ascii_icon = m_style.current_ascii_icon; - if(mode == ASCII) { - if(m_schema_ascii_icon.empty()) - SetIcon(mode_icon[mode]); - else - SetIcon(m_schema_ascii_icon.c_str()); - } - else if(mode == ZHUNG) { - if(m_schema_zhung_icon.empty()) - SetIcon(mode_icon[mode]); - else - SetIcon(m_schema_zhung_icon.c_str()); - } - else - SetIcon(mode_icon[mode]); +void WeaselTrayIcon::Refresh() { + if (!m_style.display_tray_icon && + !m_status.disabled) // display notification when deploying + { + if (m_mode != INITIAL) { + RemoveIcon(); + m_mode = INITIAL; + } + m_disabled = false; + return; + } + WeaselTrayMode mode = m_status.disabled ? DISABLED + : m_status.ascii_mode ? ASCII + : ZHUNG; + /* change icon, when + 1,mode changed + 2,icon changed + 3,both m_schema_zhung_icon and m_style.current_zhung_icon empty(for + initialize) 4,both m_schema_ascii_icon and m_style.current_ascii_icon + empty(for initialize) + */ + if (mode != m_mode || m_schema_zhung_icon != m_style.current_zhung_icon || + (m_schema_zhung_icon.empty() && m_style.current_zhung_icon.empty()) || + m_schema_ascii_icon != m_style.current_ascii_icon || + (m_schema_ascii_icon.empty() && m_style.current_ascii_icon.empty())) { + ShowIcon(); + m_mode = mode; + m_schema_zhung_icon = m_style.current_zhung_icon; + m_schema_ascii_icon = m_style.current_ascii_icon; + if (mode == ASCII) { + if (m_schema_ascii_icon.empty()) + SetIcon(mode_icon[mode]); + else + SetIcon(m_schema_ascii_icon.c_str()); + } else if (mode == ZHUNG) { + if (m_schema_zhung_icon.empty()) + SetIcon(mode_icon[mode]); + else + SetIcon(m_schema_zhung_icon.c_str()); + } else + SetIcon(mode_icon[mode]); - if (mode_label[mode] && m_disabled == false) - { - ShowBalloon(mode_label[mode], WEASEL_IME_NAME); - m_disabled = true; - } - if(m_mode != DISABLED) - m_disabled = false; - } - else if (!Visible()) - { - ShowIcon(); - } + if (mode_label[mode] && m_disabled == false) { + ShowBalloon(mode_label[mode], WEASEL_IME_NAME); + m_disabled = true; + } + if (m_mode != DISABLED) + m_disabled = false; + } else if (!Visible()) { + ShowIcon(); + } } diff --git a/WeaselServer/WeaselTrayIcon.h b/WeaselServer/WeaselTrayIcon.h index f9aedda29..42d407aaa 100644 --- a/WeaselServer/WeaselTrayIcon.h +++ b/WeaselServer/WeaselTrayIcon.h @@ -3,29 +3,29 @@ #include #include "SystemTraySDK.h" -#define WM_WEASEL_TRAY_NOTIFY (WEASEL_IPC_LAST_COMMAND + 100) - - -class WeaselTrayIcon : public CSystemTray -{ -public: - enum WeaselTrayMode { - INITIAL, ZHUNG, ASCII, DISABLED, - }; - - WeaselTrayIcon(weasel::UI &ui); - - BOOL Create(HWND hTargetWnd); - void Refresh(); - -protected: - virtual void CustomizeMenu(HMENU hMenu); - - weasel::UIStyle &m_style; - weasel::Status &m_status; - WeaselTrayMode m_mode; - std::wstring m_schema_zhung_icon; - std::wstring m_schema_ascii_icon; - bool m_disabled; +#define WM_WEASEL_TRAY_NOTIFY (WEASEL_IPC_LAST_COMMAND + 100) + +class WeaselTrayIcon : public CSystemTray { + public: + enum WeaselTrayMode { + INITIAL, + ZHUNG, + ASCII, + DISABLED, + }; + + WeaselTrayIcon(weasel::UI& ui); + + BOOL Create(HWND hTargetWnd); + void Refresh(); + + protected: + virtual void CustomizeMenu(HMENU hMenu); + + weasel::UIStyle& m_style; + weasel::Status& m_status; + WeaselTrayMode m_mode; + std::wstring m_schema_zhung_icon; + std::wstring m_schema_ascii_icon; + bool m_disabled; }; - diff --git a/WeaselSetup/InstallOptionsDlg.cpp b/WeaselSetup/InstallOptionsDlg.cpp index d6cc723b8..13c6f138c 100644 --- a/WeaselSetup/InstallOptionsDlg.cpp +++ b/WeaselSetup/InstallOptionsDlg.cpp @@ -5,115 +5,110 @@ int uninstall(bool silent); InstallOptionsDialog::InstallOptionsDialog() - : installed(false), hant(false), user_dir() -{ -} + : installed(false), hant(false), user_dir() {} -InstallOptionsDialog::~InstallOptionsDialog() -{ -} +InstallOptionsDialog::~InstallOptionsDialog() {} LRESULT InstallOptionsDialog::OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) { - cn_.Attach(GetDlgItem(IDC_RADIO_CN)); - tw_.Attach(GetDlgItem(IDC_RADIO_TW)); - remove_.Attach(GetDlgItem(IDC_REMOVE)); - default_dir_.Attach(GetDlgItem(IDC_RADIO_DEFAULT_DIR)); - custom_dir_.Attach(GetDlgItem(IDC_RADIO_CUSTOM_DIR)); - dir_.Attach(GetDlgItem(IDC_EDIT_DIR)); - - CheckRadioButton(IDC_RADIO_CN, IDC_RADIO_TW, - (hant ? IDC_RADIO_TW : IDC_RADIO_CN)); - CheckRadioButton(IDC_RADIO_DEFAULT_DIR, IDC_RADIO_CUSTOM_DIR, - (user_dir.empty() ? IDC_RADIO_DEFAULT_DIR : IDC_RADIO_CUSTOM_DIR)); - dir_.SetWindowTextW(user_dir.c_str()); - - cn_.EnableWindow(!installed); - tw_.EnableWindow(!installed); - remove_.EnableWindow(installed); - dir_.EnableWindow(user_dir.empty() ? FALSE : TRUE); - - button_custom_dir_.Attach(GetDlgItem(IDC_BUTTON_CUSTOM_DIR)); - button_custom_dir_.EnableWindow(user_dir.empty() ? FALSE : TRUE); - - ok_.Attach(GetDlgItem(IDOK)); - if (installed) { - CString str; - str.LoadStringW(IDS_STRING_MODIFY); - ok_.SetWindowTextW(str); - } - - ime_.Attach(GetDlgItem(IDC_CHECK_INSTIME)); - if (installed) - ime_.EnableWindow(FALSE); - - CenterWindow(); - return 0; + cn_.Attach(GetDlgItem(IDC_RADIO_CN)); + tw_.Attach(GetDlgItem(IDC_RADIO_TW)); + remove_.Attach(GetDlgItem(IDC_REMOVE)); + default_dir_.Attach(GetDlgItem(IDC_RADIO_DEFAULT_DIR)); + custom_dir_.Attach(GetDlgItem(IDC_RADIO_CUSTOM_DIR)); + dir_.Attach(GetDlgItem(IDC_EDIT_DIR)); + + CheckRadioButton(IDC_RADIO_CN, IDC_RADIO_TW, + (hant ? IDC_RADIO_TW : IDC_RADIO_CN)); + CheckRadioButton( + IDC_RADIO_DEFAULT_DIR, IDC_RADIO_CUSTOM_DIR, + (user_dir.empty() ? IDC_RADIO_DEFAULT_DIR : IDC_RADIO_CUSTOM_DIR)); + dir_.SetWindowTextW(user_dir.c_str()); + + cn_.EnableWindow(!installed); + tw_.EnableWindow(!installed); + remove_.EnableWindow(installed); + dir_.EnableWindow(user_dir.empty() ? FALSE : TRUE); + + button_custom_dir_.Attach(GetDlgItem(IDC_BUTTON_CUSTOM_DIR)); + button_custom_dir_.EnableWindow(user_dir.empty() ? FALSE : TRUE); + + ok_.Attach(GetDlgItem(IDOK)); + if (installed) { + CString str; + str.LoadStringW(IDS_STRING_MODIFY); + ok_.SetWindowTextW(str); + } + + ime_.Attach(GetDlgItem(IDC_CHECK_INSTIME)); + if (installed) + ime_.EnableWindow(FALSE); + + CenterWindow(); + return 0; } LRESULT InstallOptionsDialog::OnClose(UINT, WPARAM, LPARAM, BOOL&) { - EndDialog(IDCANCEL); - return 0; + EndDialog(IDCANCEL); + return 0; } LRESULT InstallOptionsDialog::OnOK(WORD, WORD code, HWND, BOOL&) { - hant = (IsDlgButtonChecked(IDC_RADIO_TW) == BST_CHECKED); - old_ime_support = (IsDlgButtonChecked(IDC_CHECK_INSTIME) == BST_CHECKED); - if (IsDlgButtonChecked(IDC_RADIO_CUSTOM_DIR) == BST_CHECKED) { - CStringW text; - dir_.GetWindowTextW(text); - user_dir = text; - } - else { - user_dir.clear(); - } - EndDialog(IDOK); - return 0; + hant = (IsDlgButtonChecked(IDC_RADIO_TW) == BST_CHECKED); + old_ime_support = (IsDlgButtonChecked(IDC_CHECK_INSTIME) == BST_CHECKED); + if (IsDlgButtonChecked(IDC_RADIO_CUSTOM_DIR) == BST_CHECKED) { + CStringW text; + dir_.GetWindowTextW(text); + user_dir = text; + } else { + user_dir.clear(); + } + EndDialog(IDOK); + return 0; } LRESULT InstallOptionsDialog::OnRemove(WORD, WORD code, HWND, BOOL&) { - const bool non_silent = false; - uninstall(non_silent); - installed = false; - ime_.EnableWindow(!installed); - CString str; - str.LoadStringW(IDS_STRING_INSTALL); - ok_.SetWindowTextW(str); - cn_.EnableWindow(!installed); - tw_.EnableWindow(!installed); - remove_.EnableWindow(installed); - return 0; + const bool non_silent = false; + uninstall(non_silent); + installed = false; + ime_.EnableWindow(!installed); + CString str; + str.LoadStringW(IDS_STRING_INSTALL); + ok_.SetWindowTextW(str); + cn_.EnableWindow(!installed); + tw_.EnableWindow(!installed); + remove_.EnableWindow(installed); + return 0; } LRESULT InstallOptionsDialog::OnUseDefaultDir(WORD, WORD code, HWND, BOOL&) { - dir_.EnableWindow(FALSE); - dir_.SetWindowTextW(L""); - button_custom_dir_.EnableWindow(FALSE); - return 0; + dir_.EnableWindow(FALSE); + dir_.SetWindowTextW(L""); + button_custom_dir_.EnableWindow(FALSE); + return 0; } LRESULT InstallOptionsDialog::OnUseCustomDir(WORD, WORD code, HWND, BOOL&) { - CFolderDialog dlg; - CStringW text; - dir_.GetWindowTextW(text); - if(!text.IsEmpty()) - dlg.SetInitialFolder(text, false); - if (dlg.DoModal() == IDOK) - dir_.SetWindowTextW(dlg.m_szFolderPath); - button_custom_dir_.EnableWindow(TRUE); - dir_.EnableWindow(TRUE); - dir_.SetFocus(); - return 0; + CFolderDialog dlg; + CStringW text; + dir_.GetWindowTextW(text); + if (!text.IsEmpty()) + dlg.SetInitialFolder(text, false); + if (dlg.DoModal() == IDOK) + dir_.SetWindowTextW(dlg.m_szFolderPath); + button_custom_dir_.EnableWindow(TRUE); + dir_.EnableWindow(TRUE); + dir_.SetFocus(); + return 0; } -LRESULT InstallOptionsDialog::OnBtnCustomDir(WORD, WORD code, HWND, BOOL&) -{ - CFolderDialog dlg; - CStringW text; - dir_.GetWindowTextW(text); - if(!text.IsEmpty()) - dlg.SetInitialFolder(text, false); - if (dlg.DoModal() == IDOK) - dir_.SetWindowTextW(dlg.m_szFolderPath); - ok_.SetFocus(); - return 0; +LRESULT InstallOptionsDialog::OnBtnCustomDir(WORD, WORD code, HWND, BOOL&) { + CFolderDialog dlg; + CStringW text; + dir_.GetWindowTextW(text); + if (!text.IsEmpty()) + dlg.SetInitialFolder(text, false); + if (dlg.DoModal() == IDOK) + dir_.SetWindowTextW(dlg.m_szFolderPath); + ok_.SetFocus(); + return 0; } diff --git a/WeaselSetup/InstallOptionsDlg.h b/WeaselSetup/InstallOptionsDlg.h index f02c3c3cd..a43e51866 100644 --- a/WeaselSetup/InstallOptionsDlg.h +++ b/WeaselSetup/InstallOptionsDlg.h @@ -3,65 +3,72 @@ #include "resource.h" #include -#define MSG_BY_IDS(idInfo, idCap, uType) \ - {\ - CString info, cap;\ - info.LoadStringW(idInfo);\ - cap.LoadStringW(idCap);\ - LANGID langID = GetThreadUILanguage();\ - MessageBoxExW(NULL, info, cap, uType, langID);\ - } +#define MSG_BY_IDS(idInfo, idCap, uType) \ + { \ + CString info, cap; \ + info.LoadStringW(idInfo); \ + cap.LoadStringW(idCap); \ + LANGID langID = GetThreadUILanguage(); \ + MessageBoxExW(NULL, info, cap, uType, langID); \ + } -#define MSG_ID_CAP(info, idCap, uType) \ - {\ - CString cap;\ - cap.LoadStringW(idCap);\ - LANGID langID = GetThreadUILanguage();\ - MessageBoxExW(NULL, info, cap, uType, langID);\ - } +#define MSG_ID_CAP(info, idCap, uType) \ + { \ + CString cap; \ + cap.LoadStringW(idCap); \ + LANGID langID = GetThreadUILanguage(); \ + MessageBoxExW(NULL, info, cap, uType, langID); \ + } -#define MSG_NOT_SILENT_BY_IDS(silent, idInfo, idCap, uType) {if(!silent) MSG_BY_IDS(idInfo, idCap, uType); } -#define MSG_NOT_SILENT_ID_CAP(silent, info, idCap, uType) {if(!silent) MSG_ID_CAP(info, idCap, uType);} +#define MSG_NOT_SILENT_BY_IDS(silent, idInfo, idCap, uType) \ + { \ + if (!silent) \ + MSG_BY_IDS(idInfo, idCap, uType); \ + } +#define MSG_NOT_SILENT_ID_CAP(silent, info, idCap, uType) \ + { \ + if (!silent) \ + MSG_ID_CAP(info, idCap, uType); \ + } -class InstallOptionsDialog : public CDialogImpl -{ -public: - enum { IDD = IDD_INSTALL_OPTIONS }; +class InstallOptionsDialog : public CDialogImpl { + public: + enum { IDD = IDD_INSTALL_OPTIONS }; - InstallOptionsDialog(); - ~InstallOptionsDialog(); + InstallOptionsDialog(); + ~InstallOptionsDialog(); - bool installed; - bool hant; - bool old_ime_support; - std::wstring user_dir; + bool installed; + bool hant; + bool old_ime_support; + std::wstring user_dir; -protected: - BEGIN_MSG_MAP(InstallOptionsDialog) - MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) - MESSAGE_HANDLER(WM_CLOSE, OnClose) - COMMAND_ID_HANDLER(IDOK, OnOK) - COMMAND_ID_HANDLER(IDC_REMOVE, OnRemove) - COMMAND_ID_HANDLER(IDC_RADIO_DEFAULT_DIR, OnUseDefaultDir) - COMMAND_ID_HANDLER(IDC_RADIO_CUSTOM_DIR, OnUseCustomDir) - COMMAND_ID_HANDLER(IDC_BUTTON_CUSTOM_DIR, OnBtnCustomDir) - END_MSG_MAP() + protected: + BEGIN_MSG_MAP(InstallOptionsDialog) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + MESSAGE_HANDLER(WM_CLOSE, OnClose) + COMMAND_ID_HANDLER(IDOK, OnOK) + COMMAND_ID_HANDLER(IDC_REMOVE, OnRemove) + COMMAND_ID_HANDLER(IDC_RADIO_DEFAULT_DIR, OnUseDefaultDir) + COMMAND_ID_HANDLER(IDC_RADIO_CUSTOM_DIR, OnUseCustomDir) + COMMAND_ID_HANDLER(IDC_BUTTON_CUSTOM_DIR, OnBtnCustomDir) + END_MSG_MAP() - LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&); - LRESULT OnClose(UINT, WPARAM, LPARAM, BOOL&); - LRESULT OnOK(WORD, WORD code, HWND, BOOL&); - LRESULT OnRemove(WORD, WORD code, HWND, BOOL&); - LRESULT OnUseDefaultDir(WORD, WORD code, HWND, BOOL&); - LRESULT OnUseCustomDir(WORD, WORD code, HWND, BOOL&); - LRESULT OnBtnCustomDir(WORD, WORD code, HWND, BOOL&); + LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&); + LRESULT OnClose(UINT, WPARAM, LPARAM, BOOL&); + LRESULT OnOK(WORD, WORD code, HWND, BOOL&); + LRESULT OnRemove(WORD, WORD code, HWND, BOOL&); + LRESULT OnUseDefaultDir(WORD, WORD code, HWND, BOOL&); + LRESULT OnUseCustomDir(WORD, WORD code, HWND, BOOL&); + LRESULT OnBtnCustomDir(WORD, WORD code, HWND, BOOL&); - CButton cn_; - CButton tw_; - CButton remove_; - CButton default_dir_; - CButton custom_dir_; - CButton ok_; - CButton ime_; - CButton button_custom_dir_; - CEdit dir_; + CButton cn_; + CButton tw_; + CButton remove_; + CButton default_dir_; + CButton custom_dir_; + CButton ok_; + CButton ime_; + CButton button_custom_dir_; + CEdit dir_; }; diff --git a/WeaselSetup/WeaselSetup.cpp b/WeaselSetup/WeaselSetup.cpp index 705ec0b8f..3f72348f8 100644 --- a/WeaselSetup/WeaselSetup.cpp +++ b/WeaselSetup/WeaselSetup.cpp @@ -14,156 +14,155 @@ CAppModule _Module; static int Run(LPTSTR lpCmdLine); -int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int /*nCmdShow*/) -{ - HRESULT hRes = ::CoInitialize(NULL); - ATLASSERT(SUCCEEDED(hRes)); - - AtlInitCommonControls(ICC_BAR_CLASSES); // add flags to support other controls - - hRes = _Module.Init(NULL, hInstance); - ATLASSERT(SUCCEEDED(hRes)); - - LCID lcid = GetUserDefaultLCID(); - if (lcid == 2052 || lcid == 3072 || lcid == 4100) { - LANGID langId = SetThreadUILanguage(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)); - SetThreadLocale(langId); - } - else { - LANGID langId = SetThreadUILanguage(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)); - SetThreadLocale(langId); - } - - int nRet = Run(lpstrCmdLine); - - _Module.Term(); - ::CoUninitialize(); - - return nRet; +int WINAPI _tWinMain(HINSTANCE hInstance, + HINSTANCE /*hPrevInstance*/, + LPTSTR lpstrCmdLine, + int /*nCmdShow*/) { + HRESULT hRes = ::CoInitialize(NULL); + ATLASSERT(SUCCEEDED(hRes)); + + AtlInitCommonControls( + ICC_BAR_CLASSES); // add flags to support other controls + + hRes = _Module.Init(NULL, hInstance); + ATLASSERT(SUCCEEDED(hRes)); + + LCID lcid = GetUserDefaultLCID(); + if (lcid == 2052 || lcid == 3072 || lcid == 4100) { + LANGID langId = SetThreadUILanguage( + MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)); + SetThreadLocale(langId); + } else { + LANGID langId = SetThreadUILanguage( + MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)); + SetThreadLocale(langId); + } + + int nRet = Run(lpstrCmdLine); + + _Module.Term(); + ::CoUninitialize(); + + return nRet; } int install(bool hant, bool silent, bool old_ime_support); int uninstall(bool silent); bool has_installed(); -static std::wstring install_dir() -{ - WCHAR exe_path[MAX_PATH] = { 0 }; - GetModuleFileNameW(GetModuleHandle(NULL), exe_path, _countof(exe_path)); - std::wstring dir(exe_path); - size_t pos = dir.find_last_of(L"\\"); - dir.resize(pos); - return dir; +static std::wstring install_dir() { + WCHAR exe_path[MAX_PATH] = {0}; + GetModuleFileNameW(GetModuleHandle(NULL), exe_path, _countof(exe_path)); + std::wstring dir(exe_path); + size_t pos = dir.find_last_of(L"\\"); + dir.resize(pos); + return dir; } -static int CustomInstall(bool installing) -{ - bool hant = false; - bool silent = false; - bool old_ime_support = false; - std::wstring user_dir; - - const WCHAR KEY[] = L"Software\\Rime\\Weasel"; - HKEY hKey; - LSTATUS ret = RegOpenKey(HKEY_CURRENT_USER, KEY, &hKey); - if (ret == ERROR_SUCCESS) - { - WCHAR value[MAX_PATH]; - DWORD len = sizeof(value); - DWORD type = 0; - DWORD data = 0; - ret = RegQueryValueEx(hKey, L"RimeUserDir", NULL, &type, (LPBYTE)value, &len); - if (ret == ERROR_SUCCESS && type == REG_SZ) - { - user_dir = value; - } - len = sizeof(data); - ret = RegQueryValueEx(hKey, L"Hant", NULL, &type, (LPBYTE)&data, &len); - if (ret == ERROR_SUCCESS && type == REG_DWORD) - { - hant = (data != 0); - if (installing) - silent = true; - } - RegCloseKey(hKey); - } - bool _has_installed = has_installed(); - if (!silent) - { - InstallOptionsDialog dlg; - dlg.installed = _has_installed; - dlg.hant = hant; - dlg.user_dir = user_dir; - if (IDOK != dlg.DoModal()) { - if (!installing) - return 1; // aborted by user - } - else { - hant = dlg.hant; - user_dir = dlg.user_dir; - old_ime_support = dlg.old_ime_support; - _has_installed = dlg.installed; - } - } - if(!_has_installed) - if (0 != install(hant, silent, old_ime_support)) - return 1; - - ret = RegCreateKeyEx(HKEY_CURRENT_USER, KEY, - 0, NULL, 0, KEY_ALL_ACCESS, 0, &hKey, NULL); - if (FAILED(HRESULT_FROM_WIN32(ret))) - { - MSG_ID_CAP(KEY, IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - - ret = RegSetValueEx(hKey, L"RimeUserDir", 0, REG_SZ, - (const BYTE*)user_dir.c_str(), - (user_dir.length() + 1) * sizeof(WCHAR)); - if (FAILED(HRESULT_FROM_WIN32(ret))) - { - MSG_BY_IDS(IDS_STR_ERR_WRITE_USER_DIR, IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - - DWORD data = hant ? 1 : 0; - ret = RegSetValueEx(hKey, L"Hant", 0, REG_DWORD, (const BYTE*)&data, sizeof(DWORD)); - if (FAILED(HRESULT_FROM_WIN32(ret))) - { - MSG_BY_IDS(IDS_STR_ERR_WRITE_HANT, IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - if (_has_installed) - { - std::wstring dir(install_dir()); - std::thread th([dir]() { - ShellExecuteW(NULL, NULL, (dir + L"\\WeaselServer.exe").c_str(), L"/q", NULL, SW_SHOWNORMAL); - Sleep(500); - ShellExecuteW(NULL, NULL, (dir + L"\\WeaselServer.exe").c_str(), L"", NULL, SW_SHOWNORMAL); - Sleep(500); - ShellExecuteW(NULL, NULL, (dir + L"\\WeaselDeployer.exe").c_str(), L"/deploy", NULL, SW_SHOWNORMAL); - }); - th.detach(); - MSG_BY_IDS(IDS_STR_MODIFY_SUCCESS_INFO, IDS_STR_MODIFY_SUCCESS_CAP, MB_ICONINFORMATION | MB_OK); - } - - return 0; +static int CustomInstall(bool installing) { + bool hant = false; + bool silent = false; + bool old_ime_support = false; + std::wstring user_dir; + + const WCHAR KEY[] = L"Software\\Rime\\Weasel"; + HKEY hKey; + LSTATUS ret = RegOpenKey(HKEY_CURRENT_USER, KEY, &hKey); + if (ret == ERROR_SUCCESS) { + WCHAR value[MAX_PATH]; + DWORD len = sizeof(value); + DWORD type = 0; + DWORD data = 0; + ret = + RegQueryValueEx(hKey, L"RimeUserDir", NULL, &type, (LPBYTE)value, &len); + if (ret == ERROR_SUCCESS && type == REG_SZ) { + user_dir = value; + } + len = sizeof(data); + ret = RegQueryValueEx(hKey, L"Hant", NULL, &type, (LPBYTE)&data, &len); + if (ret == ERROR_SUCCESS && type == REG_DWORD) { + hant = (data != 0); + if (installing) + silent = true; + } + RegCloseKey(hKey); + } + bool _has_installed = has_installed(); + if (!silent) { + InstallOptionsDialog dlg; + dlg.installed = _has_installed; + dlg.hant = hant; + dlg.user_dir = user_dir; + if (IDOK != dlg.DoModal()) { + if (!installing) + return 1; // aborted by user + } else { + hant = dlg.hant; + user_dir = dlg.user_dir; + old_ime_support = dlg.old_ime_support; + _has_installed = dlg.installed; + } + } + if (!_has_installed) + if (0 != install(hant, silent, old_ime_support)) + return 1; + + ret = RegCreateKeyEx(HKEY_CURRENT_USER, KEY, 0, NULL, 0, KEY_ALL_ACCESS, 0, + &hKey, NULL); + if (FAILED(HRESULT_FROM_WIN32(ret))) { + MSG_ID_CAP(KEY, IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); + return 1; + } + + ret = RegSetValueEx(hKey, L"RimeUserDir", 0, REG_SZ, + (const BYTE*)user_dir.c_str(), + (user_dir.length() + 1) * sizeof(WCHAR)); + if (FAILED(HRESULT_FROM_WIN32(ret))) { + MSG_BY_IDS(IDS_STR_ERR_WRITE_USER_DIR, IDS_STR_INSTALL_FAILED, + MB_ICONERROR | MB_OK); + return 1; + } + + DWORD data = hant ? 1 : 0; + ret = RegSetValueEx(hKey, L"Hant", 0, REG_DWORD, (const BYTE*)&data, + sizeof(DWORD)); + if (FAILED(HRESULT_FROM_WIN32(ret))) { + MSG_BY_IDS(IDS_STR_ERR_WRITE_HANT, IDS_STR_INSTALL_FAILED, + MB_ICONERROR | MB_OK); + return 1; + } + if (_has_installed) { + std::wstring dir(install_dir()); + std::thread th([dir]() { + ShellExecuteW(NULL, NULL, (dir + L"\\WeaselServer.exe").c_str(), L"/q", + NULL, SW_SHOWNORMAL); + Sleep(500); + ShellExecuteW(NULL, NULL, (dir + L"\\WeaselServer.exe").c_str(), L"", + NULL, SW_SHOWNORMAL); + Sleep(500); + ShellExecuteW(NULL, NULL, (dir + L"\\WeaselDeployer.exe").c_str(), + L"/deploy", NULL, SW_SHOWNORMAL); + }); + th.detach(); + MSG_BY_IDS(IDS_STR_MODIFY_SUCCESS_INFO, IDS_STR_MODIFY_SUCCESS_CAP, + MB_ICONINFORMATION | MB_OK); + } + + return 0; } -static int Run(LPTSTR lpCmdLine) -{ - constexpr bool silent = true; - constexpr bool old_ime_support = false; - bool uninstalling = !wcscmp(L"/u", lpCmdLine); - if (uninstalling) - return uninstall(silent); - - bool hans = !wcscmp(L"/s", lpCmdLine); - if (hans) - return install(false, silent, old_ime_support); - bool hant = !wcscmp(L"/t", lpCmdLine); - if (hant) - return install(true, silent, old_ime_support); - bool installing = !wcscmp(L"/i", lpCmdLine); - return CustomInstall(installing); +static int Run(LPTSTR lpCmdLine) { + constexpr bool silent = true; + constexpr bool old_ime_support = false; + bool uninstalling = !wcscmp(L"/u", lpCmdLine); + if (uninstalling) + return uninstall(silent); + + bool hans = !wcscmp(L"/s", lpCmdLine); + if (hans) + return install(false, silent, old_ime_support); + bool hant = !wcscmp(L"/t", lpCmdLine); + if (hant) + return install(true, silent, old_ime_support); + bool installing = !wcscmp(L"/i", lpCmdLine); + return CustomInstall(installing); } - diff --git a/WeaselSetup/imesetup.cpp b/WeaselSetup/imesetup.cpp index 758d564a9..bb312a7a3 100644 --- a/WeaselSetup/imesetup.cpp +++ b/WeaselSetup/imesetup.cpp @@ -7,613 +7,611 @@ #include #include "InstallOptionsDlg.h" - // {A3F4CDED-B1E9-41EE-9CA6-7B4D0DE6CB0A} -static const GUID c_clsidTextService = -{ 0xa3f4cded, 0xb1e9, 0x41ee, { 0x9c, 0xa6, 0x7b, 0x4d, 0xd, 0xe6, 0xcb, 0xa } }; +static const GUID c_clsidTextService = { + 0xa3f4cded, + 0xb1e9, + 0x41ee, + {0x9c, 0xa6, 0x7b, 0x4d, 0xd, 0xe6, 0xcb, 0xa}}; // {3D02CAB6-2B8E-4781-BA20-1C9267529467} -static const GUID c_guidProfile = -{ 0x3d02cab6, 0x2b8e, 0x4781, { 0xba, 0x20, 0x1c, 0x92, 0x67, 0x52, 0x94, 0x67 } }; - - -BOOL copy_file(const std::wstring& src, const std::wstring& dest) -{ - BOOL ret = CopyFile(src.c_str(), dest.c_str(), FALSE); - if (!ret) - { - for (int i = 0; i < 10; ++i) - { - std::wstring old = dest + L".old." + std::to_wstring(i); - if (MoveFileEx(dest.c_str(), old.c_str(), MOVEFILE_REPLACE_EXISTING)) - { - MoveFileEx(old.c_str(), NULL, MOVEFILE_DELAY_UNTIL_REBOOT); - break; - } - } - ret = CopyFile(src.c_str(), dest.c_str(), FALSE); - } - return ret; +static const GUID c_guidProfile = { + 0x3d02cab6, + 0x2b8e, + 0x4781, + {0xba, 0x20, 0x1c, 0x92, 0x67, 0x52, 0x94, 0x67}}; + +BOOL copy_file(const std::wstring& src, const std::wstring& dest) { + BOOL ret = CopyFile(src.c_str(), dest.c_str(), FALSE); + if (!ret) { + for (int i = 0; i < 10; ++i) { + std::wstring old = dest + L".old." + std::to_wstring(i); + if (MoveFileEx(dest.c_str(), old.c_str(), MOVEFILE_REPLACE_EXISTING)) { + MoveFileEx(old.c_str(), NULL, MOVEFILE_DELAY_UNTIL_REBOOT); + break; + } + } + ret = CopyFile(src.c_str(), dest.c_str(), FALSE); + } + return ret; } -BOOL delete_file(const std::wstring& file) -{ - BOOL ret = DeleteFile(file.c_str()); - if (!ret) - { - for (int i = 0; i < 10; ++i) - { - std::wstring old = file + L".old." + std::to_wstring(i); - if (MoveFileEx(file.c_str(), old.c_str(), MOVEFILE_REPLACE_EXISTING)) - { - MoveFileEx(old.c_str(), NULL, MOVEFILE_DELAY_UNTIL_REBOOT); - return TRUE; - } - } - } - return ret; +BOOL delete_file(const std::wstring& file) { + BOOL ret = DeleteFile(file.c_str()); + if (!ret) { + for (int i = 0; i < 10; ++i) { + std::wstring old = file + L".old." + std::to_wstring(i); + if (MoveFileEx(file.c_str(), old.c_str(), MOVEFILE_REPLACE_EXISTING)) { + MoveFileEx(old.c_str(), NULL, MOVEFILE_DELAY_UNTIL_REBOOT); + return TRUE; + } + } + } + return ret; } -BOOL is_wow64() -{ - DWORD errorCode; - if (GetSystemWow64DirectoryW(NULL, 0) == 0) - if ((errorCode = GetLastError()) == ERROR_CALL_NOT_IMPLEMENTED) - return FALSE; - else - ExitProcess((UINT)errorCode); - else - return TRUE; +BOOL is_wow64() { + DWORD errorCode; + if (GetSystemWow64DirectoryW(NULL, 0) == 0) + if ((errorCode = GetLastError()) == ERROR_CALL_NOT_IMPLEMENTED) + return FALSE; + else + ExitProcess((UINT)errorCode); + else + return TRUE; } typedef BOOL(WINAPI* PISWOW64P2)(HANDLE, USHORT*, USHORT*); -BOOL is_arm64_machine() -{ - PISWOW64P2 fnIsWow64Process2 = (PISWOW64P2)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "IsWow64Process2"); - - if (fnIsWow64Process2 == NULL) - { - return FALSE; - } - - USHORT processMachine; - USHORT nativeMachine; - - if (!fnIsWow64Process2(GetCurrentProcess(), &processMachine, &nativeMachine)) - { - return FALSE; - } - return nativeMachine == IMAGE_FILE_MACHINE_ARM64; +BOOL is_arm64_machine() { + PISWOW64P2 fnIsWow64Process2 = (PISWOW64P2)GetProcAddress( + GetModuleHandle(_T("kernel32.dll")), "IsWow64Process2"); + + if (fnIsWow64Process2 == NULL) { + return FALSE; + } + + USHORT processMachine; + USHORT nativeMachine; + + if (!fnIsWow64Process2(GetCurrentProcess(), &processMachine, + &nativeMachine)) { + return FALSE; + } + return nativeMachine == IMAGE_FILE_MACHINE_ARM64; } typedef HRESULT(WINAPI* PISWOWGMS)(USHORT, BOOL*); typedef UINT(WINAPI* PGSW64DIR2)(LPWSTR, UINT, WORD); -INT get_wow_arm32_system_dir(LPWSTR lpBuffer, UINT uSize) -{ - PISWOWGMS fnIsWow64GuestMachineSupported = (PISWOWGMS)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "IsWow64GuestMachineSupported"); - PGSW64DIR2 fnGetSystemWow64Directory2W = (PGSW64DIR2)GetProcAddress(GetModuleHandle(_T("kernelbase.dll")), "GetSystemWow64Directory2W"); - - if (fnIsWow64GuestMachineSupported == NULL || fnGetSystemWow64Directory2W == NULL) - { - return 0; - } - - BOOL supported; - if (fnIsWow64GuestMachineSupported(IMAGE_FILE_MACHINE_ARMNT, &supported) != S_OK) - { - return 0; - } - - if (!supported) - { - return 0; - } - - return fnGetSystemWow64Directory2W(lpBuffer, uSize, IMAGE_FILE_MACHINE_ARMNT); +INT get_wow_arm32_system_dir(LPWSTR lpBuffer, UINT uSize) { + PISWOWGMS fnIsWow64GuestMachineSupported = (PISWOWGMS)GetProcAddress( + GetModuleHandle(_T("kernel32.dll")), "IsWow64GuestMachineSupported"); + PGSW64DIR2 fnGetSystemWow64Directory2W = (PGSW64DIR2)GetProcAddress( + GetModuleHandle(_T("kernelbase.dll")), "GetSystemWow64Directory2W"); + + if (fnIsWow64GuestMachineSupported == NULL || + fnGetSystemWow64Directory2W == NULL) { + return 0; + } + + BOOL supported; + if (fnIsWow64GuestMachineSupported(IMAGE_FILE_MACHINE_ARMNT, &supported) != + S_OK) { + return 0; + } + + if (!supported) { + return 0; + } + + return fnGetSystemWow64Directory2W(lpBuffer, uSize, IMAGE_FILE_MACHINE_ARMNT); } -typedef int (*ime_register_func)(const std::wstring& ime_path, bool register_ime, bool is_wow64, bool is_wowarm, bool hant, bool silent); - -int install_ime_file(std::wstring& srcPath, const std::wstring& ext, bool hant, bool silent, ime_register_func func) -{ - WCHAR path[MAX_PATH]; - GetModuleFileNameW(GetModuleHandle(NULL), path, _countof(path)); - - std::wstring srcFileName = (hant ? L"weaselt" : L"weasel"); - srcFileName += ext; - WCHAR drive[_MAX_DRIVE]; - WCHAR dir[_MAX_DIR]; - _wsplitpath_s(path, drive, _countof(drive), dir, _countof(dir), NULL, 0, NULL, 0); - srcPath = std::wstring(drive) + dir + srcFileName; - - GetSystemDirectoryW(path, _countof(path)); - std::wstring destPath = std::wstring(path) + L"\\weasel" + ext; - - int retval = 0; - // 复制 .dll/.ime 到系统目录 - if (!copy_file(srcPath, destPath)) - { - MSG_NOT_SILENT_ID_CAP(silent, destPath.c_str(), IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - retval += func(destPath, true, false, false, hant, silent); - if (is_wow64()) - { - PVOID OldValue = NULL; - // PW64DW64FR fnWow64DisableWow64FsRedirection = (PW64DW64FR)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "Wow64DisableWow64FsRedirection"); - // PW64RW64FR fnWow64RevertWow64FsRedirection = (PW64RW64FR)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "Wow64RevertWow64FsRedirection"); - if (Wow64DisableWow64FsRedirection(&OldValue) == FALSE) - { - MSG_NOT_SILENT_BY_IDS(silent, IDS_STR_ERRCANCELFSREDIRECT, IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - - if (is_arm64_machine()) - { - WCHAR sysarm32[MAX_PATH]; - if (get_wow_arm32_system_dir(sysarm32, _countof(sysarm32)) > 0) - { - // Install the ARM32 version if ARM32 WOW is supported (lower than Windows 11 24H2). - std::wstring srcPathARM32 = srcPath; - ireplace_last(srcPathARM32, ext, L"ARM" + ext); - - std::wstring destPathARM32 = std::wstring(sysarm32) + L"\\weasel" + ext; - if (!copy_file(srcPathARM32, destPathARM32)) - { - MSG_NOT_SILENT_ID_CAP(silent, destPathARM32.c_str(), IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - retval += func(destPathARM32, true, true, true, hant, silent); - } - - // Then install the ARM64 (and x64) version. - // On ARM64 weasel.dll(ime) is an ARM64X redirection DLL (weaselARM64X). - // When loaded, it will be redirected to weaselARM64.dll(ime) on ARM64 processes, - // and weaselx64.dll(ime) on x64 processes. - // So we need a total of three files. - - std::wstring srcPathX64 = srcPath; - std::wstring destPathX64 = destPath; - ireplace_last(srcPathX64, ext, L"x64" + ext); - ireplace_last(destPathX64, ext, L"x64" + ext); - if (!copy_file(srcPathX64, destPathX64)) - { - MSG_NOT_SILENT_ID_CAP(silent, destPathX64.c_str(), IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - - std::wstring srcPathARM64 = srcPath; - std::wstring destPathARM64 = destPath; - ireplace_last(srcPathARM64, ext, L"ARM64" + ext); - ireplace_last(destPathARM64, ext, L"ARM64" + ext); - if (!copy_file(srcPathARM64, destPathARM64)) - { - MSG_NOT_SILENT_ID_CAP(silent, destPathARM64.c_str(), IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - - // Since weaselARM64X is just a redirector we don't have separate - // HANS and HANT variants. - srcPath = std::wstring(drive) + dir + L"weaselARM64X" + ext; - } - else - { - ireplace_last(srcPath, ext, L"x64" + ext); - } - - if (!copy_file(srcPath, destPath)) - { - MSG_NOT_SILENT_ID_CAP(silent, destPath.c_str(), IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - retval += func(destPath, true, true, false, hant, silent); - if (Wow64RevertWow64FsRedirection(OldValue) == FALSE) - { - MSG_NOT_SILENT_BY_IDS(silent, IDS_STR_ERRRECOVERFSREDIRECT, IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - } - return retval; +typedef int (*ime_register_func)(const std::wstring& ime_path, + bool register_ime, + bool is_wow64, + bool is_wowarm, + bool hant, + bool silent); + +int install_ime_file(std::wstring& srcPath, + const std::wstring& ext, + bool hant, + bool silent, + ime_register_func func) { + WCHAR path[MAX_PATH]; + GetModuleFileNameW(GetModuleHandle(NULL), path, _countof(path)); + + std::wstring srcFileName = (hant ? L"weaselt" : L"weasel"); + srcFileName += ext; + WCHAR drive[_MAX_DRIVE]; + WCHAR dir[_MAX_DIR]; + _wsplitpath_s(path, drive, _countof(drive), dir, _countof(dir), NULL, 0, NULL, + 0); + srcPath = std::wstring(drive) + dir + srcFileName; + + GetSystemDirectoryW(path, _countof(path)); + std::wstring destPath = std::wstring(path) + L"\\weasel" + ext; + + int retval = 0; + // 复制 .dll/.ime 到系统目录 + if (!copy_file(srcPath, destPath)) { + MSG_NOT_SILENT_ID_CAP(silent, destPath.c_str(), IDS_STR_INSTALL_FAILED, + MB_ICONERROR | MB_OK); + return 1; + } + retval += func(destPath, true, false, false, hant, silent); + if (is_wow64()) { + PVOID OldValue = NULL; + // PW64DW64FR fnWow64DisableWow64FsRedirection = + // (PW64DW64FR)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), + // "Wow64DisableWow64FsRedirection"); PW64RW64FR + // fnWow64RevertWow64FsRedirection = + // (PW64RW64FR)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), + // "Wow64RevertWow64FsRedirection"); + if (Wow64DisableWow64FsRedirection(&OldValue) == FALSE) { + MSG_NOT_SILENT_BY_IDS(silent, IDS_STR_ERRCANCELFSREDIRECT, + IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); + return 1; + } + + if (is_arm64_machine()) { + WCHAR sysarm32[MAX_PATH]; + if (get_wow_arm32_system_dir(sysarm32, _countof(sysarm32)) > 0) { + // Install the ARM32 version if ARM32 WOW is supported (lower than + // Windows 11 24H2). + std::wstring srcPathARM32 = srcPath; + ireplace_last(srcPathARM32, ext, L"ARM" + ext); + + std::wstring destPathARM32 = std::wstring(sysarm32) + L"\\weasel" + ext; + if (!copy_file(srcPathARM32, destPathARM32)) { + MSG_NOT_SILENT_ID_CAP(silent, destPathARM32.c_str(), + IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); + return 1; + } + retval += func(destPathARM32, true, true, true, hant, silent); + } + + // Then install the ARM64 (and x64) version. + // On ARM64 weasel.dll(ime) is an ARM64X redirection DLL (weaselARM64X). + // When loaded, it will be redirected to weaselARM64.dll(ime) on ARM64 + // processes, and weaselx64.dll(ime) on x64 processes. So we need a total + // of three files. + + std::wstring srcPathX64 = srcPath; + std::wstring destPathX64 = destPath; + ireplace_last(srcPathX64, ext, L"x64" + ext); + ireplace_last(destPathX64, ext, L"x64" + ext); + if (!copy_file(srcPathX64, destPathX64)) { + MSG_NOT_SILENT_ID_CAP(silent, destPathX64.c_str(), + IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); + return 1; + } + + std::wstring srcPathARM64 = srcPath; + std::wstring destPathARM64 = destPath; + ireplace_last(srcPathARM64, ext, L"ARM64" + ext); + ireplace_last(destPathARM64, ext, L"ARM64" + ext); + if (!copy_file(srcPathARM64, destPathARM64)) { + MSG_NOT_SILENT_ID_CAP(silent, destPathARM64.c_str(), + IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); + return 1; + } + + // Since weaselARM64X is just a redirector we don't have separate + // HANS and HANT variants. + srcPath = std::wstring(drive) + dir + L"weaselARM64X" + ext; + } else { + ireplace_last(srcPath, ext, L"x64" + ext); + } + + if (!copy_file(srcPath, destPath)) { + MSG_NOT_SILENT_ID_CAP(silent, destPath.c_str(), IDS_STR_INSTALL_FAILED, + MB_ICONERROR | MB_OK); + return 1; + } + retval += func(destPath, true, true, false, hant, silent); + if (Wow64RevertWow64FsRedirection(OldValue) == FALSE) { + MSG_NOT_SILENT_BY_IDS(silent, IDS_STR_ERRRECOVERFSREDIRECT, + IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); + return 1; + } + } + return retval; } -int uninstall_ime_file(const std::wstring& ext, bool silent, ime_register_func func) -{ - int retval = 0; - WCHAR path[MAX_PATH]; - GetSystemDirectoryW(path, _countof(path)); - std::wstring imePath(path); - imePath += L"\\weasel" + ext; - retval += func(imePath, false, false, false, false, silent); - delete_file(imePath); - if (is_wow64()) - { - retval += func(imePath, false, true, false, false, silent); - PVOID OldValue = NULL; - // PW64DW64FR fnWow64DisableWow64FsRedirection = (PW64DW64FR)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "Wow64DisableWow64FsRedirection"); - // PW64RW64FR fnWow64RevertWow64FsRedirection = (PW64RW64FR)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "Wow64RevertWow64FsRedirection"); - if (Wow64DisableWow64FsRedirection(&OldValue) == FALSE) - { - MSG_NOT_SILENT_BY_IDS(silent, IDS_STR_ERRCANCELFSREDIRECT, IDS_STR_UNINSTALL_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - - if (is_arm64_machine()) - { - WCHAR sysarm32[MAX_PATH]; - if (get_wow_arm32_system_dir(sysarm32, _countof(sysarm32)) > 0) - { - std::wstring imePathARM32 = std::wstring(sysarm32) + L"\\weasel" + ext; - retval += func(imePathARM32, false, true, true, false, silent); - delete_file(imePathARM32); - } - - std::wstring imePathX64 = imePath; - ireplace_last(imePathX64, ext, L"x64" + ext); - delete_file(imePathX64); - - std::wstring imePathARM64 = imePath; - ireplace_last(imePathARM64, ext, L"ARM64" + ext); - delete_file(imePathARM64); - } - - delete_file(imePath); - if (Wow64RevertWow64FsRedirection(OldValue) == FALSE) - { - MSG_NOT_SILENT_BY_IDS(silent, IDS_STR_ERRRECOVERFSREDIRECT, IDS_STR_UNINSTALL_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - } - return retval; +int uninstall_ime_file(const std::wstring& ext, + bool silent, + ime_register_func func) { + int retval = 0; + WCHAR path[MAX_PATH]; + GetSystemDirectoryW(path, _countof(path)); + std::wstring imePath(path); + imePath += L"\\weasel" + ext; + retval += func(imePath, false, false, false, false, silent); + delete_file(imePath); + if (is_wow64()) { + retval += func(imePath, false, true, false, false, silent); + PVOID OldValue = NULL; + // PW64DW64FR fnWow64DisableWow64FsRedirection = + // (PW64DW64FR)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), + // "Wow64DisableWow64FsRedirection"); PW64RW64FR + // fnWow64RevertWow64FsRedirection = + // (PW64RW64FR)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), + // "Wow64RevertWow64FsRedirection"); + if (Wow64DisableWow64FsRedirection(&OldValue) == FALSE) { + MSG_NOT_SILENT_BY_IDS(silent, IDS_STR_ERRCANCELFSREDIRECT, + IDS_STR_UNINSTALL_FAILED, MB_ICONERROR | MB_OK); + return 1; + } + + if (is_arm64_machine()) { + WCHAR sysarm32[MAX_PATH]; + if (get_wow_arm32_system_dir(sysarm32, _countof(sysarm32)) > 0) { + std::wstring imePathARM32 = std::wstring(sysarm32) + L"\\weasel" + ext; + retval += func(imePathARM32, false, true, true, false, silent); + delete_file(imePathARM32); + } + + std::wstring imePathX64 = imePath; + ireplace_last(imePathX64, ext, L"x64" + ext); + delete_file(imePathX64); + + std::wstring imePathARM64 = imePath; + ireplace_last(imePathARM64, ext, L"ARM64" + ext); + delete_file(imePathARM64); + } + + delete_file(imePath); + if (Wow64RevertWow64FsRedirection(OldValue) == FALSE) { + MSG_NOT_SILENT_BY_IDS(silent, IDS_STR_ERRRECOVERFSREDIRECT, + IDS_STR_UNINSTALL_FAILED, MB_ICONERROR | MB_OK); + return 1; + } + } + return retval; } // 注册IME输入法 -int register_ime(const std::wstring& ime_path, bool register_ime, bool is_wow64, bool is_wowarm, bool hant, bool silent) -{ - if (is_wow64) - { - return 0; // only once - } - - const WCHAR KEYBOARD_LAYOUTS_KEY[] = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts"; - const WCHAR PRELOAD_KEY[] = L"Keyboard Layout\\Preload"; - - if (register_ime) - { - HKL hKL = ImmInstallIME(ime_path.c_str(), WEASEL_IME_NAME); - if (!hKL) - { - // manually register ime - WCHAR hkl_str[16] = { 0 }; - HKEY hKey; - LSTATUS ret = RegOpenKey(HKEY_LOCAL_MACHINE, KEYBOARD_LAYOUTS_KEY, &hKey); - if (ret == ERROR_SUCCESS) - { - for (DWORD k = 0xE0200000 + (hant ? 0x0404 : 0x0804); k <= 0xE0FF0804; k += 0x10000) - { - StringCchPrintfW(hkl_str, _countof(hkl_str), L"%08X", k); - HKEY hSubKey; - ret = RegOpenKey(hKey, hkl_str, &hSubKey); - if (ret == ERROR_SUCCESS) - { - WCHAR imeFile[32] = { 0 }; - DWORD len = sizeof(imeFile); - DWORD type = 0; - ret = RegQueryValueEx(hSubKey, L"Ime File", NULL, &type, (LPBYTE)imeFile, &len); - if (ret = ERROR_SUCCESS) - { - if (_wcsicmp(imeFile, L"weasel.ime") == 0) - { - hKL = (HKL)k; // already there - } - } - RegCloseKey(hSubKey); - } - else - { - // found a spare number to register - ret = RegCreateKey(hKey, hkl_str, &hSubKey); - if (ret == ERROR_SUCCESS) - { - const WCHAR ime_file[] = L"weasel.ime"; - RegSetValueEx(hSubKey, L"Ime File", 0, REG_SZ, (LPBYTE)ime_file, sizeof(ime_file)); - const WCHAR layout_file[] = L"kbdus.dll"; - RegSetValueEx(hSubKey, L"Layout File", 0, REG_SZ, (LPBYTE)layout_file, sizeof(layout_file)); - const WCHAR layout_text[] = WEASEL_IME_NAME; - RegSetValueEx(hSubKey, L"Layout Text", 0, REG_SZ, (LPBYTE)layout_text, sizeof(layout_text)); - RegCloseKey(hSubKey); - hKL = (HKL)k; - } - break; - } - } - RegCloseKey(hKey); - } - if (hKL) - { - HKEY hPreloadKey; - ret = RegOpenKey(HKEY_CURRENT_USER, PRELOAD_KEY, &hPreloadKey); - if (ret == ERROR_SUCCESS) - { - for (size_t i = 1; true; ++i) - { - std::wstring number = std::to_wstring(i); - DWORD type = 0; - WCHAR value[32]; - DWORD len = sizeof(value); - ret = RegQueryValueEx(hPreloadKey, number.c_str(), 0, &type, (LPBYTE)value, &len); - if (ret != ERROR_SUCCESS) - { - RegSetValueEx(hPreloadKey, number.c_str(), 0, REG_SZ, - (const BYTE*)hkl_str, - (wcslen(hkl_str) + 1) * sizeof(WCHAR)); - break; - } - } - RegCloseKey(hPreloadKey); - } - } - } - if (!hKL) - { - DWORD dwErr = GetLastError(); - WCHAR msg[100]; - CString str; - str.LoadStringW(IDS_STR_ERRREGIME); - StringCchPrintfW(msg, _countof(msg), str, hKL, dwErr); - MSG_NOT_SILENT_ID_CAP(silent, msg, IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - return 0; - } - - // unregister ime - - HKEY hKey; - LSTATUS ret = RegOpenKey(HKEY_LOCAL_MACHINE, KEYBOARD_LAYOUTS_KEY, &hKey); - if (ret != ERROR_SUCCESS) - { - MSG_NOT_SILENT_ID_CAP(silent, KEYBOARD_LAYOUTS_KEY, IDS_STR_UNINSTALL_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - - for (int i = 0; true; ++i) - { - WCHAR subKey[16]; - ret = RegEnumKey(hKey, i, subKey, _countof(subKey)); - if (ret != ERROR_SUCCESS) - break; - - // 中文键盘布局? - if (wcscmp(subKey + 4, L"0804") == 0 || wcscmp(subKey + 4, L"0404") == 0) - { - HKEY hSubKey; - ret = RegOpenKey(hKey, subKey, &hSubKey); - if (ret != ERROR_SUCCESS) - continue; - - WCHAR imeFile[32]; - DWORD len = sizeof(imeFile); - DWORD type = 0; - ret = RegQueryValueEx(hSubKey, L"Ime File", NULL, &type, (LPBYTE)imeFile, &len); - RegCloseKey(hSubKey); - if (ret != ERROR_SUCCESS) - continue; - - // 小狼毫? - if (_wcsicmp(imeFile, L"weasel.ime") == 0) - { - DWORD value; - swscanf_s(subKey, L"%x", &value); - UnloadKeyboardLayout((HKL)value); - - RegDeleteKey(hKey, subKey); - - // 移除preload - HKEY hPreloadKey; - ret = RegOpenKey(HKEY_CURRENT_USER, PRELOAD_KEY, &hPreloadKey); - if (ret != ERROR_SUCCESS) - continue; - std::vector preloads; - std::wstring number; - for (size_t i = 1; true; ++i) - { - number = std::to_wstring(i); - DWORD type = 0; - WCHAR value[32]; - DWORD len = sizeof(value); - ret = RegQueryValueEx(hPreloadKey, number.c_str(), 0, &type, (LPBYTE)value, &len); - if (ret != ERROR_SUCCESS) - { - if (i > preloads.size()) - { - // 删除最大一号注册表值 - number = std::to_wstring(i - 1); - RegDeleteValue(hPreloadKey, number.c_str()); - } - break; - } - if (_wcsicmp(subKey, value) != 0) - { - preloads.push_back(value); - } - } - // 重写preloads - for (size_t i = 0; i < preloads.size(); ++i) - { - number = std::to_wstring(i + 1); - RegSetValueEx(hPreloadKey, number.c_str(), 0, REG_SZ, - (const BYTE*)preloads[i].c_str(), - (preloads[i].length() + 1) * sizeof(WCHAR)); - } - RegCloseKey(hPreloadKey); - } - } - } - - RegCloseKey(hKey); - return 0; +int register_ime(const std::wstring& ime_path, + bool register_ime, + bool is_wow64, + bool is_wowarm, + bool hant, + bool silent) { + if (is_wow64) { + return 0; // only once + } + + const WCHAR KEYBOARD_LAYOUTS_KEY[] = + L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts"; + const WCHAR PRELOAD_KEY[] = L"Keyboard Layout\\Preload"; + + if (register_ime) { + HKL hKL = ImmInstallIME(ime_path.c_str(), WEASEL_IME_NAME); + if (!hKL) { + // manually register ime + WCHAR hkl_str[16] = {0}; + HKEY hKey; + LSTATUS ret = RegOpenKey(HKEY_LOCAL_MACHINE, KEYBOARD_LAYOUTS_KEY, &hKey); + if (ret == ERROR_SUCCESS) { + for (DWORD k = 0xE0200000 + (hant ? 0x0404 : 0x0804); k <= 0xE0FF0804; + k += 0x10000) { + StringCchPrintfW(hkl_str, _countof(hkl_str), L"%08X", k); + HKEY hSubKey; + ret = RegOpenKey(hKey, hkl_str, &hSubKey); + if (ret == ERROR_SUCCESS) { + WCHAR imeFile[32] = {0}; + DWORD len = sizeof(imeFile); + DWORD type = 0; + ret = RegQueryValueEx(hSubKey, L"Ime File", NULL, &type, + (LPBYTE)imeFile, &len); + if (ret = ERROR_SUCCESS) { + if (_wcsicmp(imeFile, L"weasel.ime") == 0) { + hKL = (HKL)k; // already there + } + } + RegCloseKey(hSubKey); + } else { + // found a spare number to register + ret = RegCreateKey(hKey, hkl_str, &hSubKey); + if (ret == ERROR_SUCCESS) { + const WCHAR ime_file[] = L"weasel.ime"; + RegSetValueEx(hSubKey, L"Ime File", 0, REG_SZ, (LPBYTE)ime_file, + sizeof(ime_file)); + const WCHAR layout_file[] = L"kbdus.dll"; + RegSetValueEx(hSubKey, L"Layout File", 0, REG_SZ, + (LPBYTE)layout_file, sizeof(layout_file)); + const WCHAR layout_text[] = WEASEL_IME_NAME; + RegSetValueEx(hSubKey, L"Layout Text", 0, REG_SZ, + (LPBYTE)layout_text, sizeof(layout_text)); + RegCloseKey(hSubKey); + hKL = (HKL)k; + } + break; + } + } + RegCloseKey(hKey); + } + if (hKL) { + HKEY hPreloadKey; + ret = RegOpenKey(HKEY_CURRENT_USER, PRELOAD_KEY, &hPreloadKey); + if (ret == ERROR_SUCCESS) { + for (size_t i = 1; true; ++i) { + std::wstring number = std::to_wstring(i); + DWORD type = 0; + WCHAR value[32]; + DWORD len = sizeof(value); + ret = RegQueryValueEx(hPreloadKey, number.c_str(), 0, &type, + (LPBYTE)value, &len); + if (ret != ERROR_SUCCESS) { + RegSetValueEx(hPreloadKey, number.c_str(), 0, REG_SZ, + (const BYTE*)hkl_str, + (wcslen(hkl_str) + 1) * sizeof(WCHAR)); + break; + } + } + RegCloseKey(hPreloadKey); + } + } + } + if (!hKL) { + DWORD dwErr = GetLastError(); + WCHAR msg[100]; + CString str; + str.LoadStringW(IDS_STR_ERRREGIME); + StringCchPrintfW(msg, _countof(msg), str, hKL, dwErr); + MSG_NOT_SILENT_ID_CAP(silent, msg, IDS_STR_INSTALL_FAILED, + MB_ICONERROR | MB_OK); + return 1; + } + return 0; + } + + // unregister ime + + HKEY hKey; + LSTATUS ret = RegOpenKey(HKEY_LOCAL_MACHINE, KEYBOARD_LAYOUTS_KEY, &hKey); + if (ret != ERROR_SUCCESS) { + MSG_NOT_SILENT_ID_CAP(silent, KEYBOARD_LAYOUTS_KEY, + IDS_STR_UNINSTALL_FAILED, MB_ICONERROR | MB_OK); + return 1; + } + + for (int i = 0; true; ++i) { + WCHAR subKey[16]; + ret = RegEnumKey(hKey, i, subKey, _countof(subKey)); + if (ret != ERROR_SUCCESS) + break; + + // 中文键盘布局? + if (wcscmp(subKey + 4, L"0804") == 0 || wcscmp(subKey + 4, L"0404") == 0) { + HKEY hSubKey; + ret = RegOpenKey(hKey, subKey, &hSubKey); + if (ret != ERROR_SUCCESS) + continue; + + WCHAR imeFile[32]; + DWORD len = sizeof(imeFile); + DWORD type = 0; + ret = RegQueryValueEx(hSubKey, L"Ime File", NULL, &type, (LPBYTE)imeFile, + &len); + RegCloseKey(hSubKey); + if (ret != ERROR_SUCCESS) + continue; + + // 小狼毫? + if (_wcsicmp(imeFile, L"weasel.ime") == 0) { + DWORD value; + swscanf_s(subKey, L"%x", &value); + UnloadKeyboardLayout((HKL)value); + + RegDeleteKey(hKey, subKey); + + // 移除preload + HKEY hPreloadKey; + ret = RegOpenKey(HKEY_CURRENT_USER, PRELOAD_KEY, &hPreloadKey); + if (ret != ERROR_SUCCESS) + continue; + std::vector preloads; + std::wstring number; + for (size_t i = 1; true; ++i) { + number = std::to_wstring(i); + DWORD type = 0; + WCHAR value[32]; + DWORD len = sizeof(value); + ret = RegQueryValueEx(hPreloadKey, number.c_str(), 0, &type, + (LPBYTE)value, &len); + if (ret != ERROR_SUCCESS) { + if (i > preloads.size()) { + // 删除最大一号注册表值 + number = std::to_wstring(i - 1); + RegDeleteValue(hPreloadKey, number.c_str()); + } + break; + } + if (_wcsicmp(subKey, value) != 0) { + preloads.push_back(value); + } + } + // 重写preloads + for (size_t i = 0; i < preloads.size(); ++i) { + number = std::to_wstring(i + 1); + RegSetValueEx(hPreloadKey, number.c_str(), 0, REG_SZ, + (const BYTE*)preloads[i].c_str(), + (preloads[i].length() + 1) * sizeof(WCHAR)); + } + RegCloseKey(hPreloadKey); + } + } + } + + RegCloseKey(hKey); + return 0; } void enable_profile(BOOL fEnable, bool hant) { - HRESULT hr; - ITfInputProcessorProfiles* pProfiles = NULL; - - hr = CoCreateInstance(CLSID_TF_InputProcessorProfiles, - NULL, - CLSCTX_INPROC_SERVER, - IID_ITfInputProcessorProfiles, - (LPVOID*)&pProfiles); - - if (SUCCEEDED(hr)) - { - LANGID lang_id = hant ? 0x0404 : 0x0804; - if (fEnable) { - pProfiles->EnableLanguageProfile(c_clsidTextService, lang_id, c_guidProfile, fEnable); - pProfiles->EnableLanguageProfileByDefault(c_clsidTextService, lang_id, c_guidProfile, fEnable); - } - else { - pProfiles->RemoveLanguageProfile(c_clsidTextService, lang_id, c_guidProfile); - } - - pProfiles->Release(); - } + HRESULT hr; + ITfInputProcessorProfiles* pProfiles = NULL; + + hr = CoCreateInstance(CLSID_TF_InputProcessorProfiles, NULL, + CLSCTX_INPROC_SERVER, IID_ITfInputProcessorProfiles, + (LPVOID*)&pProfiles); + + if (SUCCEEDED(hr)) { + LANGID lang_id = hant ? 0x0404 : 0x0804; + if (fEnable) { + pProfiles->EnableLanguageProfile(c_clsidTextService, lang_id, + c_guidProfile, fEnable); + pProfiles->EnableLanguageProfileByDefault(c_clsidTextService, lang_id, + c_guidProfile, fEnable); + } else { + pProfiles->RemoveLanguageProfile(c_clsidTextService, lang_id, + c_guidProfile); + } + + pProfiles->Release(); + } } // 注册TSF输入法 -int register_text_service(const std::wstring& tsf_path, bool register_ime, bool is_wow64, bool is_wowarm32, bool hant, bool silent) -{ - using RegisterServerFunction = HRESULT(STDAPICALLTYPE*)(); - - if (!register_ime) - enable_profile(FALSE, hant); - - std::wstring params = L" \"" + tsf_path + L"\""; - if (!register_ime) - { - params = L" /u " + params; // unregister - } - //if (silent) // always silent - { - params = L" /s " + params; - } - - std::wstring app = L"regsvr32.exe"; - if (is_wowarm32) - { - WCHAR sysarm32[MAX_PATH]; - get_wow_arm32_system_dir(sysarm32, _countof(sysarm32)); - - app = std::wstring(sysarm32) + L"\\" + app; - } - - SHELLEXECUTEINFOW shExInfo = { 0 }; - shExInfo.cbSize = sizeof(shExInfo); - shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS; - shExInfo.hwnd = 0; - shExInfo.lpVerb = L"open"; // Operation to perform - shExInfo.lpFile = app.c_str(); // Application to start - shExInfo.lpParameters = params.c_str(); // Additional parameters - shExInfo.lpDirectory = 0; - shExInfo.nShow = SW_SHOW; - shExInfo.hInstApp = 0; - if (ShellExecuteExW(&shExInfo)) - { - WaitForSingleObject(shExInfo.hProcess, INFINITE); - CloseHandle(shExInfo.hProcess); - } - else - { - WCHAR msg[100]; - CString str; - str.LoadStringW(IDS_STR_ERRREGTSF); - StringCchPrintfW(msg, _countof(msg), str, params.c_str()); - //StringCchPrintfW(msg, _countof(msg), L"註冊輸入法錯誤 regsvr32.exe %s", params.c_str()); - //if (!silent) MessageBoxW(NULL, msg, L"安装/卸載失败", MB_ICONERROR | MB_OK); - MSG_NOT_SILENT_ID_CAP(silent, msg, IDS_STR_INORUN_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - - if (register_ime) - enable_profile(TRUE, hant); - - return 0; +int register_text_service(const std::wstring& tsf_path, + bool register_ime, + bool is_wow64, + bool is_wowarm32, + bool hant, + bool silent) { + using RegisterServerFunction = HRESULT(STDAPICALLTYPE*)(); + + if (!register_ime) + enable_profile(FALSE, hant); + + std::wstring params = L" \"" + tsf_path + L"\""; + if (!register_ime) { + params = L" /u " + params; // unregister + } + // if (silent) // always silent + { params = L" /s " + params; } + + std::wstring app = L"regsvr32.exe"; + if (is_wowarm32) { + WCHAR sysarm32[MAX_PATH]; + get_wow_arm32_system_dir(sysarm32, _countof(sysarm32)); + + app = std::wstring(sysarm32) + L"\\" + app; + } + + SHELLEXECUTEINFOW shExInfo = {0}; + shExInfo.cbSize = sizeof(shExInfo); + shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS; + shExInfo.hwnd = 0; + shExInfo.lpVerb = L"open"; // Operation to perform + shExInfo.lpFile = app.c_str(); // Application to start + shExInfo.lpParameters = params.c_str(); // Additional parameters + shExInfo.lpDirectory = 0; + shExInfo.nShow = SW_SHOW; + shExInfo.hInstApp = 0; + if (ShellExecuteExW(&shExInfo)) { + WaitForSingleObject(shExInfo.hProcess, INFINITE); + CloseHandle(shExInfo.hProcess); + } else { + WCHAR msg[100]; + CString str; + str.LoadStringW(IDS_STR_ERRREGTSF); + StringCchPrintfW(msg, _countof(msg), str, params.c_str()); + // StringCchPrintfW(msg, _countof(msg), L"註冊輸入法錯誤 regsvr32.exe %s", + // params.c_str()); if (!silent) MessageBoxW(NULL, msg, L"安装/卸載失败", + // MB_ICONERROR | MB_OK); + MSG_NOT_SILENT_ID_CAP(silent, msg, IDS_STR_INORUN_FAILED, + MB_ICONERROR | MB_OK); + return 1; + } + + if (register_ime) + enable_profile(TRUE, hant); + + return 0; } -int install(bool hant, bool silent, bool old_ime_support) -{ - std::wstring ime_src_path; - int retval = 0; - if (old_ime_support) - { - retval += install_ime_file(ime_src_path, L".ime", hant, silent, ®ister_ime); - } - retval += install_ime_file(ime_src_path, L".dll", hant, silent, ®ister_text_service); - - // 写注册表 - HKEY hKey; - LSTATUS ret = RegCreateKeyEx(HKEY_LOCAL_MACHINE, WEASEL_REG_KEY, - 0, NULL, 0, KEY_ALL_ACCESS, 0, &hKey, NULL); - if (FAILED(HRESULT_FROM_WIN32(ret))) - { - MSG_NOT_SILENT_ID_CAP(silent, WEASEL_REG_KEY, IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - - WCHAR drive[_MAX_DRIVE]; - WCHAR dir[_MAX_DIR]; - _wsplitpath_s(ime_src_path.c_str(), drive, _countof(drive), dir, _countof(dir), NULL, 0, NULL, 0); - std::wstring rootDir = std::wstring(drive) + dir; - rootDir.pop_back(); - ret = RegSetValueEx(hKey, L"WeaselRoot", 0, REG_SZ, - (const BYTE*)rootDir.c_str(), - (rootDir.length() + 1) * sizeof(WCHAR)); - if (FAILED(HRESULT_FROM_WIN32(ret))) - { - MSG_NOT_SILENT_BY_IDS(silent, IDS_STR_ERRWRITEWEASELROOT, IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - - const std::wstring executable = L"WeaselServer.exe"; - ret = RegSetValueEx(hKey, L"ServerExecutable", 0, REG_SZ, - (const BYTE*)executable.c_str(), - (executable.length() + 1) * sizeof(WCHAR)); - if (FAILED(HRESULT_FROM_WIN32(ret))) - { - MSG_NOT_SILENT_BY_IDS(silent, IDS_STR_ERRREGIMEWRITESVREXE, IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); - return 1; - } - - RegCloseKey(hKey); - - if (retval) - return 1; - - MSG_NOT_SILENT_BY_IDS(silent, IDS_STR_INSTALL_SUCCESS_INFO, IDS_STR_INSTALL_SUCCESS_CAP, MB_ICONINFORMATION | MB_OK); - return 0; +int install(bool hant, bool silent, bool old_ime_support) { + std::wstring ime_src_path; + int retval = 0; + if (old_ime_support) { + retval += + install_ime_file(ime_src_path, L".ime", hant, silent, ®ister_ime); + } + retval += install_ime_file(ime_src_path, L".dll", hant, silent, + ®ister_text_service); + + // 写注册表 + HKEY hKey; + LSTATUS ret = RegCreateKeyEx(HKEY_LOCAL_MACHINE, WEASEL_REG_KEY, 0, NULL, 0, + KEY_ALL_ACCESS, 0, &hKey, NULL); + if (FAILED(HRESULT_FROM_WIN32(ret))) { + MSG_NOT_SILENT_ID_CAP(silent, WEASEL_REG_KEY, IDS_STR_INSTALL_FAILED, + MB_ICONERROR | MB_OK); + return 1; + } + + WCHAR drive[_MAX_DRIVE]; + WCHAR dir[_MAX_DIR]; + _wsplitpath_s(ime_src_path.c_str(), drive, _countof(drive), dir, + _countof(dir), NULL, 0, NULL, 0); + std::wstring rootDir = std::wstring(drive) + dir; + rootDir.pop_back(); + ret = RegSetValueEx(hKey, L"WeaselRoot", 0, REG_SZ, + (const BYTE*)rootDir.c_str(), + (rootDir.length() + 1) * sizeof(WCHAR)); + if (FAILED(HRESULT_FROM_WIN32(ret))) { + MSG_NOT_SILENT_BY_IDS(silent, IDS_STR_ERRWRITEWEASELROOT, + IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); + return 1; + } + + const std::wstring executable = L"WeaselServer.exe"; + ret = RegSetValueEx(hKey, L"ServerExecutable", 0, REG_SZ, + (const BYTE*)executable.c_str(), + (executable.length() + 1) * sizeof(WCHAR)); + if (FAILED(HRESULT_FROM_WIN32(ret))) { + MSG_NOT_SILENT_BY_IDS(silent, IDS_STR_ERRREGIMEWRITESVREXE, + IDS_STR_INSTALL_FAILED, MB_ICONERROR | MB_OK); + return 1; + } + + RegCloseKey(hKey); + + if (retval) + return 1; + + MSG_NOT_SILENT_BY_IDS(silent, IDS_STR_INSTALL_SUCCESS_INFO, + IDS_STR_INSTALL_SUCCESS_CAP, + MB_ICONINFORMATION | MB_OK); + return 0; } -int uninstall(bool silent) -{ - // 注销输入法 - int retval = 0; - uninstall_ime_file(L".ime", silent, ®ister_ime); - retval += uninstall_ime_file(L".dll", silent, ®ister_text_service); +int uninstall(bool silent) { + // 注销输入法 + int retval = 0; + uninstall_ime_file(L".ime", silent, ®ister_ime); + retval += uninstall_ime_file(L".dll", silent, ®ister_text_service); - // 清除注册信息 - RegDeleteKey(HKEY_LOCAL_MACHINE, WEASEL_REG_KEY); - RegDeleteKey(HKEY_LOCAL_MACHINE, RIME_REG_KEY); + // 清除注册信息 + RegDeleteKey(HKEY_LOCAL_MACHINE, WEASEL_REG_KEY); + RegDeleteKey(HKEY_LOCAL_MACHINE, RIME_REG_KEY); - if (retval) - return 1; + if (retval) + return 1; - MSG_NOT_SILENT_BY_IDS(silent, IDS_STR_UNINSTALL_SUCCESS_INFO, IDS_STR_UNINSTALL_SUCCESS_CAP, MB_ICONINFORMATION | MB_OK); - return 0; + MSG_NOT_SILENT_BY_IDS(silent, IDS_STR_UNINSTALL_SUCCESS_INFO, + IDS_STR_UNINSTALL_SUCCESS_CAP, + MB_ICONINFORMATION | MB_OK); + return 0; } bool has_installed() { - WCHAR path[MAX_PATH]; - GetSystemDirectory(path, _countof(path)); - std::wstring sysPath(path); - DWORD attr = GetFileAttributesW((sysPath + L"\\weasel.dll").c_str()); - return (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY)); + WCHAR path[MAX_PATH]; + GetSystemDirectory(path, _countof(path)); + std::wstring sysPath(path); + DWORD attr = GetFileAttributesW((sysPath + L"\\weasel.dll").c_str()); + return (attr != INVALID_FILE_ATTRIBUTES && + !(attr & FILE_ATTRIBUTE_DIRECTORY)); } diff --git a/WeaselTSF/CandidateList.cpp b/WeaselTSF/CandidateList.cpp index d603a6fbb..bb1bc1550 100644 --- a/WeaselTSF/CandidateList.cpp +++ b/WeaselTSF/CandidateList.cpp @@ -9,475 +9,423 @@ using namespace std; using namespace weasel; CCandidateList::CCandidateList(com_ptr pTextService) - : _ui(make_unique()) - , _tsf(pTextService) - , _pbShow(TRUE) -{ - _cRef = 1; + : _ui(make_unique()), _tsf(pTextService), _pbShow(TRUE) { + _cRef = 1; } -CCandidateList::~CCandidateList() -{} +CCandidateList::~CCandidateList() {} -STDMETHODIMP CCandidateList::QueryInterface(REFIID riid, void ** ppvObj) -{ - if (ppvObj == nullptr) - { - return E_INVALIDARG; - } +STDMETHODIMP CCandidateList::QueryInterface(REFIID riid, void** ppvObj) { + if (ppvObj == nullptr) { + return E_INVALIDARG; + } - *ppvObj = nullptr; + *ppvObj = nullptr; - if (IsEqualIID(riid, IID_ITfUIElement) || - IsEqualIID(riid, IID_ITfCandidateListUIElement) || - IsEqualIID(riid, IID_ITfCandidateListUIElementBehavior)) - { - *ppvObj = (ITfCandidateListUIElementBehavior*)this; - } - else if (IsEqualIID(riid, IID_IUnknown) || - IsEqualIID(riid, __uuidof(ITfIntegratableCandidateListUIElement))) - { - *ppvObj = (ITfIntegratableCandidateListUIElement*)this; - } + if (IsEqualIID(riid, IID_ITfUIElement) || + IsEqualIID(riid, IID_ITfCandidateListUIElement) || + IsEqualIID(riid, IID_ITfCandidateListUIElementBehavior)) { + *ppvObj = (ITfCandidateListUIElementBehavior*)this; + } else if (IsEqualIID(riid, IID_IUnknown) || + IsEqualIID(riid, + __uuidof(ITfIntegratableCandidateListUIElement))) { + *ppvObj = (ITfIntegratableCandidateListUIElement*)this; + } - if (*ppvObj) - { - AddRef(); - return S_OK; - } + if (*ppvObj) { + AddRef(); + return S_OK; + } - return E_NOINTERFACE; + return E_NOINTERFACE; } -STDMETHODIMP_(ULONG) CCandidateList::AddRef(void) -{ - return ++_cRef; +STDMETHODIMP_(ULONG) CCandidateList::AddRef(void) { + return ++_cRef; } -STDMETHODIMP_(ULONG) CCandidateList::Release(void) -{ - LONG cr = --_cRef; +STDMETHODIMP_(ULONG) CCandidateList::Release(void) { + LONG cr = --_cRef; - assert(_cRef >= 0); + assert(_cRef >= 0); - if (_cRef == 0) - { - delete this; - } + if (_cRef == 0) { + delete this; + } - return cr; + return cr; } -STDMETHODIMP CCandidateList::GetDescription(BSTR * pbstr) -{ - static auto str = SysAllocString(L"Candidate List"); - if (pbstr) - { - *pbstr = str; - } - return S_OK; +STDMETHODIMP CCandidateList::GetDescription(BSTR* pbstr) { + static auto str = SysAllocString(L"Candidate List"); + if (pbstr) { + *pbstr = str; + } + return S_OK; } -STDMETHODIMP CCandidateList::GetGUID(GUID * pguid) -{ - /// 36c3c795-7159-45aa-ab12-30229a51dbd3 - *pguid = { 0x36c3c795, 0x7159, 0x45aa, { 0xab, 0x12, 0x30, 0x22, 0x9a, 0x51, 0xdb, 0xd3 } }; - return S_OK; +STDMETHODIMP CCandidateList::GetGUID(GUID* pguid) { + /// 36c3c795-7159-45aa-ab12-30229a51dbd3 + *pguid = {0x36c3c795, + 0x7159, + 0x45aa, + {0xab, 0x12, 0x30, 0x22, 0x9a, 0x51, 0xdb, 0xd3}}; + return S_OK; } -STDMETHODIMP CCandidateList::Show(BOOL showCandidateWindow) -{ - if (showCandidateWindow) - _ui->Show(); - else - _ui->Hide(); - return S_OK; +STDMETHODIMP CCandidateList::Show(BOOL showCandidateWindow) { + if (showCandidateWindow) + _ui->Show(); + else + _ui->Hide(); + return S_OK; } -STDMETHODIMP CCandidateList::IsShown(BOOL * pIsShow) -{ - *pIsShow = _ui->IsShown(); - return S_OK; +STDMETHODIMP CCandidateList::IsShown(BOOL* pIsShow) { + *pIsShow = _ui->IsShown(); + return S_OK; } -STDMETHODIMP CCandidateList::GetUpdatedFlags(DWORD * pdwFlags) -{ - if (!pdwFlags) - return E_INVALIDARG; +STDMETHODIMP CCandidateList::GetUpdatedFlags(DWORD* pdwFlags) { + if (!pdwFlags) + return E_INVALIDARG; - *pdwFlags = TF_CLUIE_DOCUMENTMGR | TF_CLUIE_COUNT | TF_CLUIE_SELECTION | TF_CLUIE_STRING | TF_CLUIE_CURRENTPAGE; - return S_OK; + *pdwFlags = TF_CLUIE_DOCUMENTMGR | TF_CLUIE_COUNT | TF_CLUIE_SELECTION | + TF_CLUIE_STRING | TF_CLUIE_CURRENTPAGE; + return S_OK; } -STDMETHODIMP CCandidateList::GetDocumentMgr(ITfDocumentMgr ** ppdim) -{ - *ppdim = nullptr; - auto pThreadMgr = _tsf->_GetThreadMgr(); - if (pThreadMgr == nullptr) - { - return E_FAIL; - } - if (FAILED(pThreadMgr->GetFocus(ppdim)) || (*ppdim == nullptr)) - { - return E_FAIL; - } - return S_OK; +STDMETHODIMP CCandidateList::GetDocumentMgr(ITfDocumentMgr** ppdim) { + *ppdim = nullptr; + auto pThreadMgr = _tsf->_GetThreadMgr(); + if (pThreadMgr == nullptr) { + return E_FAIL; + } + if (FAILED(pThreadMgr->GetFocus(ppdim)) || (*ppdim == nullptr)) { + return E_FAIL; + } + return S_OK; } -STDMETHODIMP CCandidateList::GetCount(UINT * pCandidateCount) -{ - *pCandidateCount = _ui->ctx().cinfo.candies.size(); - return S_OK; +STDMETHODIMP CCandidateList::GetCount(UINT* pCandidateCount) { + *pCandidateCount = _ui->ctx().cinfo.candies.size(); + return S_OK; } -STDMETHODIMP CCandidateList::GetSelection(UINT * pSelectedCandidateIndex) -{ - *pSelectedCandidateIndex = _ui->ctx().cinfo.highlighted; - return S_OK; +STDMETHODIMP CCandidateList::GetSelection(UINT* pSelectedCandidateIndex) { + *pSelectedCandidateIndex = _ui->ctx().cinfo.highlighted; + return S_OK; } -STDMETHODIMP CCandidateList::GetString(UINT uIndex, BSTR * pbstr) -{ - *pbstr = nullptr; - auto &cinfo = _ui->ctx().cinfo; - if (uIndex >= cinfo.candies.size()) - return E_INVALIDARG; +STDMETHODIMP CCandidateList::GetString(UINT uIndex, BSTR* pbstr) { + *pbstr = nullptr; + auto& cinfo = _ui->ctx().cinfo; + if (uIndex >= cinfo.candies.size()) + return E_INVALIDARG; - auto &str = cinfo.candies[uIndex].str; - *pbstr = SysAllocStringLen(str.c_str(), str.size() + 1); + auto& str = cinfo.candies[uIndex].str; + *pbstr = SysAllocStringLen(str.c_str(), str.size() + 1); - return S_OK; + return S_OK; } -STDMETHODIMP CCandidateList::GetPageIndex(UINT * pIndex, UINT uSize, UINT * puPageCnt) -{ - if (!puPageCnt) - return E_INVALIDARG; - *puPageCnt = 1; - if (pIndex) { - if (uSize < *puPageCnt) { - return E_INVALIDARG; - } - *pIndex = 0; - } - return S_OK; +STDMETHODIMP CCandidateList::GetPageIndex(UINT* pIndex, + UINT uSize, + UINT* puPageCnt) { + if (!puPageCnt) + return E_INVALIDARG; + *puPageCnt = 1; + if (pIndex) { + if (uSize < *puPageCnt) { + return E_INVALIDARG; + } + *pIndex = 0; + } + return S_OK; } -STDMETHODIMP CCandidateList::SetPageIndex(UINT * pIndex, UINT uPageCnt) -{ - if (!pIndex) - return E_INVALIDARG; - return S_OK; +STDMETHODIMP CCandidateList::SetPageIndex(UINT* pIndex, UINT uPageCnt) { + if (!pIndex) + return E_INVALIDARG; + return S_OK; } -STDMETHODIMP CCandidateList::GetCurrentPage(UINT * puPage) -{ - *puPage = 0; - return S_OK; +STDMETHODIMP CCandidateList::GetCurrentPage(UINT* puPage) { + *puPage = 0; + return S_OK; } -STDMETHODIMP CCandidateList::SetSelection(UINT nIndex) -{ - _ui->ctx().cinfo.highlighted = nIndex; - return S_OK; +STDMETHODIMP CCandidateList::SetSelection(UINT nIndex) { + _ui->ctx().cinfo.highlighted = nIndex; + return S_OK; } -STDMETHODIMP CCandidateList::Finalize(void) -{ - Destroy(); - return S_OK; +STDMETHODIMP CCandidateList::Finalize(void) { + Destroy(); + return S_OK; } -STDMETHODIMP CCandidateList::Abort(void) -{ - _tsf->_AbortComposition(true); - Destroy(); - return S_OK; +STDMETHODIMP CCandidateList::Abort(void) { + _tsf->_AbortComposition(true); + Destroy(); + return S_OK; } -STDMETHODIMP CCandidateList::SetIntegrationStyle(GUID guidIntegrationStyle) -{ - return S_OK; +STDMETHODIMP CCandidateList::SetIntegrationStyle(GUID guidIntegrationStyle) { + return S_OK; } -STDMETHODIMP CCandidateList::GetSelectionStyle(TfIntegratableCandidateListSelectionStyle * ptfSelectionStyle) -{ - *ptfSelectionStyle = _selectionStyle; - return S_OK; +STDMETHODIMP CCandidateList::GetSelectionStyle( + TfIntegratableCandidateListSelectionStyle* ptfSelectionStyle) { + *ptfSelectionStyle = _selectionStyle; + return S_OK; } -STDMETHODIMP CCandidateList::OnKeyDown(WPARAM wParam, LPARAM lParam, BOOL * pIsEaten) -{ - *pIsEaten = TRUE; - return S_OK; +STDMETHODIMP CCandidateList::OnKeyDown(WPARAM wParam, + LPARAM lParam, + BOOL* pIsEaten) { + *pIsEaten = TRUE; + return S_OK; } -STDMETHODIMP CCandidateList::ShowCandidateNumbers(BOOL * pIsShow) -{ - *pIsShow = TRUE; - return S_OK; +STDMETHODIMP CCandidateList::ShowCandidateNumbers(BOOL* pIsShow) { + *pIsShow = TRUE; + return S_OK; } -STDMETHODIMP CCandidateList::FinalizeExactCompositionString() -{ - _tsf->_AbortComposition(false); - return E_NOTIMPL; +STDMETHODIMP CCandidateList::FinalizeExactCompositionString() { + _tsf->_AbortComposition(false); + return E_NOTIMPL; } -void CCandidateList::UpdateUI(const Context & ctx, const Status & status) -{ - if (_ui->style().inline_preedit) { - _ui->style().client_caps |= weasel::INLINE_PREEDIT_CAPABLE; - } - else { - _ui->style().client_caps &= ~weasel::INLINE_PREEDIT_CAPABLE; - } +void CCandidateList::UpdateUI(const Context& ctx, const Status& status) { + if (_ui->style().inline_preedit) { + _ui->style().client_caps |= weasel::INLINE_PREEDIT_CAPABLE; + } else { + _ui->style().client_caps &= ~weasel::INLINE_PREEDIT_CAPABLE; + } - /// In UWP, candidate window will only be shown - /// if it is owned by active view window - //_UpdateOwner(); - _ui->Update(ctx, status); - if (_pbShow == FALSE) - _UpdateUIElement(); + /// In UWP, candidate window will only be shown + /// if it is owned by active view window + //_UpdateOwner(); + _ui->Update(ctx, status); + if (_pbShow == FALSE) + _UpdateUIElement(); - if (status.composing) - Show(_pbShow); - else - Show(FALSE); + if (status.composing) + Show(_pbShow); + else + Show(FALSE); } -void CCandidateList::UpdateStyle(const UIStyle & sty) -{ - _ui->style() = sty; +void CCandidateList::UpdateStyle(const UIStyle& sty) { + _ui->style() = sty; } -void CCandidateList::UpdateInputPosition(RECT const & rc) -{ - _ui->UpdateInputPosition(rc); +void CCandidateList::UpdateInputPosition(RECT const& rc) { + _ui->UpdateInputPosition(rc); } -void CCandidateList::Destroy() -{ - //EndUI(); - Show(FALSE); - _DisposeUIWindowAll(); +void CCandidateList::Destroy() { + // EndUI(); + Show(FALSE); + _DisposeUIWindowAll(); } -UIStyle & CCandidateList::style() -{ - //return _ui->style(); - return _style; +UIStyle& CCandidateList::style() { + // return _ui->style(); + return _style; } -HWND CCandidateList::_GetActiveWnd() -{ - com_ptr pDocumentMgr; - com_ptr pContext; - com_ptr pContextView; - com_ptr pThreadMgr = _tsf->_GetThreadMgr(); +HWND CCandidateList::_GetActiveWnd() { + com_ptr pDocumentMgr; + com_ptr pContext; + com_ptr pContextView; + com_ptr pThreadMgr = _tsf->_GetThreadMgr(); - HWND w = NULL; + HWND w = NULL; - // Reset current context - _pContextDocument = nullptr; + // Reset current context + _pContextDocument = nullptr; - if (pThreadMgr != nullptr - && SUCCEEDED(pThreadMgr->GetFocus(&pDocumentMgr)) - && SUCCEEDED(pDocumentMgr->GetTop(&pContext)) - && SUCCEEDED(pContext->GetActiveView(&pContextView))) - { - // Set current context - _pContextDocument = pContext; - pContextView->GetWnd(&w); - } + if (pThreadMgr != nullptr && SUCCEEDED(pThreadMgr->GetFocus(&pDocumentMgr)) && + SUCCEEDED(pDocumentMgr->GetTop(&pContext)) && + SUCCEEDED(pContext->GetActiveView(&pContextView))) { + // Set current context + _pContextDocument = pContext; + pContextView->GetWnd(&w); + } - if (w == NULL) w = ::GetFocus(); - return w; + if (w == NULL) + w = ::GetFocus(); + return w; } -HRESULT CCandidateList::_UpdateUIElement() -{ - HRESULT hr = S_OK; +HRESULT CCandidateList::_UpdateUIElement() { + HRESULT hr = S_OK; - com_ptr pUIElementMgr; - com_ptr pThreadMgr = _tsf->_GetThreadMgr(); - if (nullptr == pThreadMgr) - { - return S_OK; - } - hr = pThreadMgr->QueryInterface(IID_ITfUIElementMgr, (void **)&pUIElementMgr); + com_ptr pUIElementMgr; + com_ptr pThreadMgr = _tsf->_GetThreadMgr(); + if (nullptr == pThreadMgr) { + return S_OK; + } + hr = pThreadMgr->QueryInterface(IID_ITfUIElementMgr, (void**)&pUIElementMgr); - if (hr == S_OK) - { - pUIElementMgr->UpdateUIElement(uiid); - } + if (hr == S_OK) { + pUIElementMgr->UpdateUIElement(uiid); + } - return S_OK; + return S_OK; } -void CCandidateList::StartUI() -{ - com_ptr pThreadMgr = _tsf->_GetThreadMgr(); - com_ptr pUIElementMgr; - auto hr = pThreadMgr->QueryInterface(&pUIElementMgr); - if (FAILED(hr)) - return; +void CCandidateList::StartUI() { + com_ptr pThreadMgr = _tsf->_GetThreadMgr(); + com_ptr pUIElementMgr; + auto hr = pThreadMgr->QueryInterface(&pUIElementMgr); + if (FAILED(hr)) + return; - if (pUIElementMgr == NULL) - { - return; - } + if (pUIElementMgr == NULL) { + return; + } - if(!_ui->uiCallback()) - _ui->SetUICallBack([this](size_t* const sel, size_t* const hov, bool* const next, bool* const scroll_next) { _tsf->HandleUICallback(sel, hov, next, scroll_next); }); - pUIElementMgr->BeginUIElement(this, &_pbShow, &uiid); - //pUIElementMgr->UpdateUIElement(uiid); - if (_pbShow) - { - _ui->style() = _style; - _MakeUIWindow(); - } + if (!_ui->uiCallback()) + _ui->SetUICallBack([this](size_t* const sel, size_t* const hov, + bool* const next, bool* const scroll_next) { + _tsf->HandleUICallback(sel, hov, next, scroll_next); + }); + pUIElementMgr->BeginUIElement(this, &_pbShow, &uiid); + // pUIElementMgr->UpdateUIElement(uiid); + if (_pbShow) { + _ui->style() = _style; + _MakeUIWindow(); + } } -void CCandidateList::EndUI() -{ - com_ptr pThreadMgr = _tsf->_GetThreadMgr(); - com_ptr emgr; - auto hr = pThreadMgr->QueryInterface(&emgr); - if (FAILED(hr)) - return; - if (emgr != NULL) - emgr->EndUIElement(uiid); - _DisposeUIWindow(); +void CCandidateList::EndUI() { + com_ptr pThreadMgr = _tsf->_GetThreadMgr(); + com_ptr emgr; + auto hr = pThreadMgr->QueryInterface(&emgr); + if (FAILED(hr)) + return; + if (emgr != NULL) + emgr->EndUIElement(uiid); + _DisposeUIWindow(); } -com_ptr CCandidateList::GetContextDocument() -{ - return _pContextDocument; -} - -void CCandidateList::_DisposeUIWindow() -{ - if (_ui == nullptr) - { - return; - } - - _ui->Destroy(); -} - -void CCandidateList::_DisposeUIWindowAll() -{ - if (_ui == nullptr) - { - return; - } - - // call _ui->Destroy(true) to clean resources - _ui->Destroy(true); -} - -void CCandidateList::_MakeUIWindow() -{ - HWND p = _GetActiveWnd(); - _ui->Create(p); -} - -void WeaselTSF::_UpdateUI(const Context & ctx, const Status & status) -{ - _cand->UpdateUI(ctx, status); -} - -void WeaselTSF::_StartUI() -{ - _cand->StartUI(); -} - -void WeaselTSF::_EndUI() -{ - _cand->EndUI(); -} - -void WeaselTSF::_ShowUI() -{ - _cand->Show(TRUE); -} - -void WeaselTSF::_HideUI() -{ - _cand->Show(FALSE); -} - -com_ptr WeaselTSF::_GetUIContextDocument() -{ - return _cand->GetContextDocument(); -} - -void WeaselTSF::_DeleteCandidateList() -{ - _cand->Destroy(); -} - -void WeaselTSF::_SelectCandidateOnCurrentPage(size_t index) -{ - m_client.SelectCandidateOnCurrentPage(index); - // simulate a VK_SELECT presskey to get data back and DoEditSession - // the simulated keycode must be the one make TranslateKeycode Non-Zero return - // fix me: are there any better ways? - INPUT inputs[2]; - inputs[0].type = INPUT_KEYBOARD; - inputs[0].ki = {VK_SELECT, 0,0,0,0}; - inputs[1].type = INPUT_KEYBOARD; - inputs[1].ki = {VK_SELECT, 0,KEYEVENTF_KEYUP,0,0}; - ::SendInput(sizeof(inputs) / sizeof(INPUT), inputs, sizeof(INPUT)); -} - -void WeaselTSF::_HandleMousePageEvent( bool* const nextPage, bool* const scrollNextPage) -{ - // from scrolling event - if ( scrollNextPage ) { - if(_cand->style().paging_on_scroll) - m_client.ChangePage(!(*scrollNextPage)); - else { - UINT current_select = 0, cand_count = 0; - _cand->GetSelection(¤t_select); - _cand->GetCount(&cand_count); - bool is_reposition = _cand->GetIsReposition(); - int offset = *scrollNextPage ? 1 : -1; - offset = offset * (is_reposition ? -1 : 1); - int index = (int)current_select + offset; - if (index >= 0 && index < cand_count) - m_client.HighlightCandidateOnCurrentPage((size_t)index); - else { - KeyEvent ke{0, 0}; - ke.keycode = (index < 0) ? ibus::Up : ibus::Down; - m_client.ProcessKeyEvent(ke); - } - } - } else { // from click event - m_client.ChangePage(!(*nextPage)); - } - _UpdateComposition(_pEditSessionContext); -} - -void WeaselTSF::_HandleMouseHoverEvent(const size_t index) -{ - UINT current_select = 0; - _cand->GetSelection(¤t_select); - - if(index != current_select) - { - m_client.HighlightCandidateOnCurrentPage(index); - _UpdateComposition(_pEditSessionContext); - } -} - -void WeaselTSF::HandleUICallback(size_t* const sel, size_t* const hov, bool* const next, bool* const scroll_next) -{ - if (sel) - _SelectCandidateOnCurrentPage(*sel); - else if (hov) - _HandleMouseHoverEvent(*hov); - else if (next || scroll_next) - _HandleMousePageEvent(next, scroll_next); +com_ptr CCandidateList::GetContextDocument() { + return _pContextDocument; +} + +void CCandidateList::_DisposeUIWindow() { + if (_ui == nullptr) { + return; + } + + _ui->Destroy(); +} + +void CCandidateList::_DisposeUIWindowAll() { + if (_ui == nullptr) { + return; + } + + // call _ui->Destroy(true) to clean resources + _ui->Destroy(true); +} + +void CCandidateList::_MakeUIWindow() { + HWND p = _GetActiveWnd(); + _ui->Create(p); +} + +void WeaselTSF::_UpdateUI(const Context& ctx, const Status& status) { + _cand->UpdateUI(ctx, status); +} + +void WeaselTSF::_StartUI() { + _cand->StartUI(); +} + +void WeaselTSF::_EndUI() { + _cand->EndUI(); +} + +void WeaselTSF::_ShowUI() { + _cand->Show(TRUE); +} + +void WeaselTSF::_HideUI() { + _cand->Show(FALSE); +} + +com_ptr WeaselTSF::_GetUIContextDocument() { + return _cand->GetContextDocument(); +} + +void WeaselTSF::_DeleteCandidateList() { + _cand->Destroy(); +} + +void WeaselTSF::_SelectCandidateOnCurrentPage(size_t index) { + m_client.SelectCandidateOnCurrentPage(index); + // simulate a VK_SELECT presskey to get data back and DoEditSession + // the simulated keycode must be the one make TranslateKeycode Non-Zero return + // fix me: are there any better ways? + INPUT inputs[2]; + inputs[0].type = INPUT_KEYBOARD; + inputs[0].ki = {VK_SELECT, 0, 0, 0, 0}; + inputs[1].type = INPUT_KEYBOARD; + inputs[1].ki = {VK_SELECT, 0, KEYEVENTF_KEYUP, 0, 0}; + ::SendInput(sizeof(inputs) / sizeof(INPUT), inputs, sizeof(INPUT)); +} + +void WeaselTSF::_HandleMousePageEvent(bool* const nextPage, + bool* const scrollNextPage) { + // from scrolling event + if (scrollNextPage) { + if (_cand->style().paging_on_scroll) + m_client.ChangePage(!(*scrollNextPage)); + else { + UINT current_select = 0, cand_count = 0; + _cand->GetSelection(¤t_select); + _cand->GetCount(&cand_count); + bool is_reposition = _cand->GetIsReposition(); + int offset = *scrollNextPage ? 1 : -1; + offset = offset * (is_reposition ? -1 : 1); + int index = (int)current_select + offset; + if (index >= 0 && index < cand_count) + m_client.HighlightCandidateOnCurrentPage((size_t)index); + else { + KeyEvent ke{0, 0}; + ke.keycode = (index < 0) ? ibus::Up : ibus::Down; + m_client.ProcessKeyEvent(ke); + } + } + } else { // from click event + m_client.ChangePage(!(*nextPage)); + } + _UpdateComposition(_pEditSessionContext); +} + +void WeaselTSF::_HandleMouseHoverEvent(const size_t index) { + UINT current_select = 0; + _cand->GetSelection(¤t_select); + + if (index != current_select) { + m_client.HighlightCandidateOnCurrentPage(index); + _UpdateComposition(_pEditSessionContext); + } +} + +void WeaselTSF::HandleUICallback(size_t* const sel, + size_t* const hov, + bool* const next, + bool* const scroll_next) { + if (sel) + _SelectCandidateOnCurrentPage(*sel); + else if (hov) + _HandleMouseHoverEvent(*hov); + else if (next || scroll_next) + _HandleMousePageEvent(next, scroll_next); } diff --git a/WeaselTSF/CandidateList.h b/WeaselTSF/CandidateList.h index 75db58ebe..799174c10 100644 --- a/WeaselTSF/CandidateList.h +++ b/WeaselTSF/CandidateList.h @@ -4,81 +4,87 @@ class WeaselTSF; -class CCandidateList : - public ITfIntegratableCandidateListUIElement, - public ITfCandidateListUIElementBehavior -{ -public: - CCandidateList(com_ptr pTextService); - ~CCandidateList(); - - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, _Outptr_ void **ppvObj); - STDMETHODIMP_(ULONG) AddRef(void); - STDMETHODIMP_(ULONG) Release(void); - - // ITfUIElement - STDMETHODIMP GetDescription(BSTR *pbstr); - STDMETHODIMP GetGUID(GUID *pguid); - STDMETHODIMP Show(BOOL showCandidateWindow); - STDMETHODIMP IsShown(BOOL *pIsShow); - - // ITfCandidateListUIElement - STDMETHODIMP GetUpdatedFlags(DWORD *pdwFlags); - STDMETHODIMP GetDocumentMgr(ITfDocumentMgr **ppdim); - STDMETHODIMP GetCount(UINT *pCandidateCount); - STDMETHODIMP GetSelection(UINT *pSelectedCandidateIndex); - STDMETHODIMP GetString(UINT uIndex, BSTR *pbstr); - STDMETHODIMP GetPageIndex(UINT *pIndex, UINT uSize, UINT *puPageCnt); - STDMETHODIMP SetPageIndex(UINT *pIndex, UINT uPageCnt); - STDMETHODIMP GetCurrentPage(UINT *puPage); - - // ITfCandidateListUIElementBehavior methods - STDMETHODIMP SetSelection(UINT nIndex); - STDMETHODIMP Finalize(void); - STDMETHODIMP Abort(void); - - // ITfIntegratableCandidateListUIElement methods - STDMETHODIMP SetIntegrationStyle(GUID guidIntegrationStyle); - STDMETHODIMP GetSelectionStyle(_Out_ TfIntegratableCandidateListSelectionStyle *ptfSelectionStyle); - STDMETHODIMP OnKeyDown(_In_ WPARAM wParam, _In_ LPARAM lParam, _Out_ BOOL *pIsEaten); - STDMETHODIMP ShowCandidateNumbers(_Out_ BOOL *pIsShow); - STDMETHODIMP FinalizeExactCompositionString(); - - /* Update */ - void UpdateUI(const weasel::Context &ctx, const weasel::Status &status); - void UpdateStyle(const weasel::UIStyle &sty); - void UpdateInputPosition(RECT const& rc); - void Destroy(); - void StartUI(); - void EndUI(); - - com_ptr GetContextDocument(); - bool GetIsReposition(){ if(_ui) return _ui->GetIsReposition(); else return false; } - - weasel::UIStyle &style(); - - -private: - //void _UpdateOwner(); - HWND _GetActiveWnd(); - HRESULT _UpdateUIElement(); - - // for CCandidateList::EndUI(), after ending composition || WeaselTSF::_EndUI() - void _DisposeUIWindow(); - // for CCandidateList::Destroy(), when inputing app exit - void _DisposeUIWindowAll(); - void _MakeUIWindow(); - - std::unique_ptr _ui; - DWORD _cRef; - com_ptr _tsf; - DWORD uiid; - TfIntegratableCandidateListSelectionStyle _selectionStyle = STYLE_ACTIVE_SELECTION; - - BOOL _pbShow; - weasel::UIStyle _style; - - com_ptr _pContextDocument; +class CCandidateList : public ITfIntegratableCandidateListUIElement, + public ITfCandidateListUIElementBehavior { + public: + CCandidateList(com_ptr pTextService); + ~CCandidateList(); + + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, _Outptr_ void** ppvObj); + STDMETHODIMP_(ULONG) AddRef(void); + STDMETHODIMP_(ULONG) Release(void); + + // ITfUIElement + STDMETHODIMP GetDescription(BSTR* pbstr); + STDMETHODIMP GetGUID(GUID* pguid); + STDMETHODIMP Show(BOOL showCandidateWindow); + STDMETHODIMP IsShown(BOOL* pIsShow); + + // ITfCandidateListUIElement + STDMETHODIMP GetUpdatedFlags(DWORD* pdwFlags); + STDMETHODIMP GetDocumentMgr(ITfDocumentMgr** ppdim); + STDMETHODIMP GetCount(UINT* pCandidateCount); + STDMETHODIMP GetSelection(UINT* pSelectedCandidateIndex); + STDMETHODIMP GetString(UINT uIndex, BSTR* pbstr); + STDMETHODIMP GetPageIndex(UINT* pIndex, UINT uSize, UINT* puPageCnt); + STDMETHODIMP SetPageIndex(UINT* pIndex, UINT uPageCnt); + STDMETHODIMP GetCurrentPage(UINT* puPage); + + // ITfCandidateListUIElementBehavior methods + STDMETHODIMP SetSelection(UINT nIndex); + STDMETHODIMP Finalize(void); + STDMETHODIMP Abort(void); + + // ITfIntegratableCandidateListUIElement methods + STDMETHODIMP SetIntegrationStyle(GUID guidIntegrationStyle); + STDMETHODIMP GetSelectionStyle( + _Out_ TfIntegratableCandidateListSelectionStyle* ptfSelectionStyle); + STDMETHODIMP OnKeyDown(_In_ WPARAM wParam, + _In_ LPARAM lParam, + _Out_ BOOL* pIsEaten); + STDMETHODIMP ShowCandidateNumbers(_Out_ BOOL* pIsShow); + STDMETHODIMP FinalizeExactCompositionString(); + + /* Update */ + void UpdateUI(const weasel::Context& ctx, const weasel::Status& status); + void UpdateStyle(const weasel::UIStyle& sty); + void UpdateInputPosition(RECT const& rc); + void Destroy(); + void StartUI(); + void EndUI(); + + com_ptr GetContextDocument(); + bool GetIsReposition() { + if (_ui) + return _ui->GetIsReposition(); + else + return false; + } + + weasel::UIStyle& style(); + + private: + // void _UpdateOwner(); + HWND _GetActiveWnd(); + HRESULT _UpdateUIElement(); + + // for CCandidateList::EndUI(), after ending composition || + // WeaselTSF::_EndUI() + void _DisposeUIWindow(); + // for CCandidateList::Destroy(), when inputing app exit + void _DisposeUIWindowAll(); + void _MakeUIWindow(); + + std::unique_ptr _ui; + DWORD _cRef; + com_ptr _tsf; + DWORD uiid; + TfIntegratableCandidateListSelectionStyle _selectionStyle = + STYLE_ACTIVE_SELECTION; + + BOOL _pbShow; + weasel::UIStyle _style; + + com_ptr _pContextDocument; }; - diff --git a/WeaselTSF/Compartment.cpp b/WeaselTSF/Compartment.cpp index a6ed82574..a3b6a25a2 100644 --- a/WeaselTSF/Compartment.cpp +++ b/WeaselTSF/Compartment.cpp @@ -6,296 +6,258 @@ #include "ResponseParser.h" #include "CandidateList.h" -STDAPI CCompartmentEventSink::QueryInterface(REFIID riid, _Outptr_ void **ppvObj) -{ - if (ppvObj == nullptr) - return E_INVALIDARG; - - *ppvObj = nullptr; - - if (IsEqualIID(riid, IID_IUnknown) || - IsEqualIID(riid, IID_ITfCompartmentEventSink)) - { - *ppvObj = (CCompartmentEventSink *)this; - } - - if (*ppvObj) - { - AddRef(); - return S_OK; - } - - return E_NOINTERFACE; +STDAPI CCompartmentEventSink::QueryInterface(REFIID riid, + _Outptr_ void** ppvObj) { + if (ppvObj == nullptr) + return E_INVALIDARG; + + *ppvObj = nullptr; + + if (IsEqualIID(riid, IID_IUnknown) || + IsEqualIID(riid, IID_ITfCompartmentEventSink)) { + *ppvObj = (CCompartmentEventSink*)this; + } + + if (*ppvObj) { + AddRef(); + return S_OK; + } + + return E_NOINTERFACE; } -STDAPI_(ULONG) CCompartmentEventSink::AddRef() -{ - return ++_refCount; +STDAPI_(ULONG) CCompartmentEventSink::AddRef() { + return ++_refCount; } -STDAPI_(ULONG) CCompartmentEventSink::Release() -{ - LONG cr = --_refCount; +STDAPI_(ULONG) CCompartmentEventSink::Release() { + LONG cr = --_refCount; - assert(_refCount >= 0); + assert(_refCount >= 0); - if (_refCount == 0) - { - delete this; - } + if (_refCount == 0) { + delete this; + } - return cr; + return cr; } -STDAPI CCompartmentEventSink::OnChange(_In_ REFGUID guidCompartment) -{ - return _callback(guidCompartment); +STDAPI CCompartmentEventSink::OnChange(_In_ REFGUID guidCompartment) { + return _callback(guidCompartment); } -HRESULT CCompartmentEventSink::_Advise(_In_ com_ptr punk, _In_ REFGUID guidCompartment) -{ - HRESULT hr = S_OK; - ITfCompartmentMgr* pCompartmentMgr = nullptr; - ITfSource* pSource = nullptr; - - hr = punk->QueryInterface(IID_ITfCompartmentMgr, (void **)&pCompartmentMgr); - if (FAILED(hr)) - { - return hr; - } - - hr = pCompartmentMgr->GetCompartment(guidCompartment, &_compartment); - if (SUCCEEDED(hr)) - { - hr = _compartment->QueryInterface(IID_ITfSource, (void **)&pSource); - if (SUCCEEDED(hr)) - { - hr = pSource->AdviseSink(IID_ITfCompartmentEventSink, this, &_cookie); - pSource->Release(); - } - } - - pCompartmentMgr->Release(); - - return hr; -} -HRESULT CCompartmentEventSink::_Unadvise() -{ - HRESULT hr = S_OK; - ITfSource* pSource = nullptr; - - hr = _compartment->QueryInterface(IID_ITfSource, (void **)&pSource); - if (SUCCEEDED(hr)) - { - hr = pSource->UnadviseSink(_cookie); - pSource->Release(); - } - - _compartment = nullptr; - _cookie = 0; - - return hr; +HRESULT CCompartmentEventSink::_Advise(_In_ com_ptr punk, + _In_ REFGUID guidCompartment) { + HRESULT hr = S_OK; + ITfCompartmentMgr* pCompartmentMgr = nullptr; + ITfSource* pSource = nullptr; + + hr = punk->QueryInterface(IID_ITfCompartmentMgr, (void**)&pCompartmentMgr); + if (FAILED(hr)) { + return hr; + } + + hr = pCompartmentMgr->GetCompartment(guidCompartment, &_compartment); + if (SUCCEEDED(hr)) { + hr = _compartment->QueryInterface(IID_ITfSource, (void**)&pSource); + if (SUCCEEDED(hr)) { + hr = pSource->AdviseSink(IID_ITfCompartmentEventSink, this, &_cookie); + pSource->Release(); + } + } + + pCompartmentMgr->Release(); + + return hr; } +HRESULT CCompartmentEventSink::_Unadvise() { + HRESULT hr = S_OK; + ITfSource* pSource = nullptr; + hr = _compartment->QueryInterface(IID_ITfSource, (void**)&pSource); + if (SUCCEEDED(hr)) { + hr = pSource->UnadviseSink(_cookie); + pSource->Release(); + } -BOOL WeaselTSF::_IsKeyboardDisabled() -{ - ITfCompartmentMgr *pCompMgr = NULL; - ITfDocumentMgr *pDocMgrFocus = NULL; - ITfContext *pContext = NULL; - BOOL fDisabled = FALSE; - - if ((_pThreadMgr->GetFocus(&pDocMgrFocus) != S_OK) || (pDocMgrFocus == NULL)) - { - fDisabled = TRUE; - goto Exit; - } - - if ((pDocMgrFocus->GetTop(&pContext) != S_OK) || (pContext == NULL)) - { - fDisabled = TRUE; - goto Exit; - } - - if (pContext->QueryInterface(IID_ITfCompartmentMgr, (void **) &pCompMgr) == S_OK) - { - ITfCompartment *pCompartmentDisabled; - ITfCompartment *pCompartmentEmptyContext; - - /* Check GUID_COMPARTMENT_KEYBOARD_DISABLED */ - if (pCompMgr->GetCompartment(GUID_COMPARTMENT_KEYBOARD_DISABLED, &pCompartmentDisabled) == S_OK) - { - VARIANT var; - if (pCompartmentDisabled->GetValue(&var) == S_OK) - { - if (var.vt == VT_I4) // Even VT_EMPTY, GetValue() can succeed - fDisabled = (BOOL) var.lVal; - } - pCompartmentDisabled->Release(); - } - - /* Check GUID_COMPARTMENT_EMPTYCONTEXT */ - if (pCompMgr->GetCompartment(GUID_COMPARTMENT_EMPTYCONTEXT, &pCompartmentEmptyContext) == S_OK) - { - VARIANT var; - if (pCompartmentEmptyContext->GetValue(&var) == S_OK) - { - if (var.vt == VT_I4) // Even VT_EMPTY, GetValue() can succeed - fDisabled = (BOOL) var.lVal; - } - pCompartmentEmptyContext->Release(); - } - pCompMgr->Release(); - } + _compartment = nullptr; + _cookie = 0; -Exit: - if (pContext) - pContext->Release(); - if (pDocMgrFocus) - pDocMgrFocus->Release(); - return fDisabled; + return hr; } -BOOL WeaselTSF::_IsKeyboardOpen() -{ - com_ptr pCompMgr; - BOOL fOpen = FALSE; - - if (_pThreadMgr->QueryInterface(&pCompMgr) == S_OK) - { - com_ptr pCompartment; - if (pCompMgr->GetCompartment(GUID_COMPARTMENT_KEYBOARD_OPENCLOSE, &pCompartment) == S_OK) - { - VARIANT var; - if (pCompartment->GetValue(&var) == S_OK) - { - if (var.vt == VT_I4) // Even VT_EMPTY, GetValue() can succeed - fOpen = (BOOL) var.lVal; - } - } - } - return fOpen; +BOOL WeaselTSF::_IsKeyboardDisabled() { + ITfCompartmentMgr* pCompMgr = NULL; + ITfDocumentMgr* pDocMgrFocus = NULL; + ITfContext* pContext = NULL; + BOOL fDisabled = FALSE; + + if ((_pThreadMgr->GetFocus(&pDocMgrFocus) != S_OK) || + (pDocMgrFocus == NULL)) { + fDisabled = TRUE; + goto Exit; + } + + if ((pDocMgrFocus->GetTop(&pContext) != S_OK) || (pContext == NULL)) { + fDisabled = TRUE; + goto Exit; + } + + if (pContext->QueryInterface(IID_ITfCompartmentMgr, (void**)&pCompMgr) == + S_OK) { + ITfCompartment* pCompartmentDisabled; + ITfCompartment* pCompartmentEmptyContext; + + /* Check GUID_COMPARTMENT_KEYBOARD_DISABLED */ + if (pCompMgr->GetCompartment(GUID_COMPARTMENT_KEYBOARD_DISABLED, + &pCompartmentDisabled) == S_OK) { + VARIANT var; + if (pCompartmentDisabled->GetValue(&var) == S_OK) { + if (var.vt == VT_I4) // Even VT_EMPTY, GetValue() can succeed + fDisabled = (BOOL)var.lVal; + } + pCompartmentDisabled->Release(); + } + + /* Check GUID_COMPARTMENT_EMPTYCONTEXT */ + if (pCompMgr->GetCompartment(GUID_COMPARTMENT_EMPTYCONTEXT, + &pCompartmentEmptyContext) == S_OK) { + VARIANT var; + if (pCompartmentEmptyContext->GetValue(&var) == S_OK) { + if (var.vt == VT_I4) // Even VT_EMPTY, GetValue() can succeed + fDisabled = (BOOL)var.lVal; + } + pCompartmentEmptyContext->Release(); + } + pCompMgr->Release(); + } + +Exit: + if (pContext) + pContext->Release(); + if (pDocMgrFocus) + pDocMgrFocus->Release(); + return fDisabled; } -HRESULT WeaselTSF::_SetKeyboardOpen(BOOL fOpen) -{ - HRESULT hr = E_FAIL; - com_ptr pCompMgr; - - if (_pThreadMgr->QueryInterface(&pCompMgr) == S_OK) - { - ITfCompartment *pCompartment; - if (pCompMgr->GetCompartment(GUID_COMPARTMENT_KEYBOARD_OPENCLOSE, &pCompartment) == S_OK) - { - VARIANT var; - var.vt = VT_I4; - var.lVal = fOpen; - hr = pCompartment->SetValue(_tfClientId, &var); - } - } - - return hr; +BOOL WeaselTSF::_IsKeyboardOpen() { + com_ptr pCompMgr; + BOOL fOpen = FALSE; + + if (_pThreadMgr->QueryInterface(&pCompMgr) == S_OK) { + com_ptr pCompartment; + if (pCompMgr->GetCompartment(GUID_COMPARTMENT_KEYBOARD_OPENCLOSE, + &pCompartment) == S_OK) { + VARIANT var; + if (pCompartment->GetValue(&var) == S_OK) { + if (var.vt == VT_I4) // Even VT_EMPTY, GetValue() can succeed + fOpen = (BOOL)var.lVal; + } + } + } + return fOpen; } -HRESULT WeaselTSF::_GetCompartmentDWORD(DWORD& value, const GUID guid) -{ - HRESULT hr = E_FAIL; - com_ptr pComMgr; - if (_pThreadMgr->QueryInterface(&pComMgr) == S_OK) - { - ITfCompartment* pCompartment; - if (pComMgr->GetCompartment(guid, &pCompartment) == S_OK) - { - VARIANT var; - if (pCompartment->GetValue(&var) == S_OK) - { - if (var.vt == VT_I4) - value = var.lVal; - else - hr = S_FALSE; - } - } - pCompartment->Release(); - } - return hr; +HRESULT WeaselTSF::_SetKeyboardOpen(BOOL fOpen) { + HRESULT hr = E_FAIL; + com_ptr pCompMgr; + + if (_pThreadMgr->QueryInterface(&pCompMgr) == S_OK) { + ITfCompartment* pCompartment; + if (pCompMgr->GetCompartment(GUID_COMPARTMENT_KEYBOARD_OPENCLOSE, + &pCompartment) == S_OK) { + VARIANT var; + var.vt = VT_I4; + var.lVal = fOpen; + hr = pCompartment->SetValue(_tfClientId, &var); + } + } + + return hr; } -HRESULT WeaselTSF::_SetCompartmentDWORD(const DWORD& value, const GUID guid) -{ - HRESULT hr = S_OK; - com_ptr pComMgr; - if (_pThreadMgr->QueryInterface(&pComMgr) == S_OK) - { - ITfCompartment* pCompartment; - if (pComMgr->GetCompartment(guid, &pCompartment) == S_OK) - { - VARIANT var; - var.vt = VT_I4; - var.lVal = value; - hr = pCompartment->SetValue(_tfClientId, &var); - } - pCompartment->Release(); - } - return hr; +HRESULT WeaselTSF::_GetCompartmentDWORD(DWORD& value, const GUID guid) { + HRESULT hr = E_FAIL; + com_ptr pComMgr; + if (_pThreadMgr->QueryInterface(&pComMgr) == S_OK) { + ITfCompartment* pCompartment; + if (pComMgr->GetCompartment(guid, &pCompartment) == S_OK) { + VARIANT var; + if (pCompartment->GetValue(&var) == S_OK) { + if (var.vt == VT_I4) + value = var.lVal; + else + hr = S_FALSE; + } + } + pCompartment->Release(); + } + return hr; } -BOOL WeaselTSF::_InitCompartment() -{ - using namespace std::placeholders; - - auto callback = std::bind(&WeaselTSF::_HandleCompartment, this, _1); - _pKeyboardCompartmentSink = new CCompartmentEventSink(callback); - if (!_pKeyboardCompartmentSink) - return FALSE; - DWORD hr = _pKeyboardCompartmentSink->_Advise( - (IUnknown *)_pThreadMgr, - GUID_COMPARTMENT_KEYBOARD_OPENCLOSE - ); - - _pConvertionCompartmentSink = new CCompartmentEventSink(callback); - if (!_pConvertionCompartmentSink) - return FALSE; - hr = _pConvertionCompartmentSink->_Advise( - (IUnknown*)_pThreadMgr, - GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION - ); - return SUCCEEDED(hr); +HRESULT WeaselTSF::_SetCompartmentDWORD(const DWORD& value, const GUID guid) { + HRESULT hr = S_OK; + com_ptr pComMgr; + if (_pThreadMgr->QueryInterface(&pComMgr) == S_OK) { + ITfCompartment* pCompartment; + if (pComMgr->GetCompartment(guid, &pCompartment) == S_OK) { + VARIANT var; + var.vt = VT_I4; + var.lVal = value; + hr = pCompartment->SetValue(_tfClientId, &var); + } + pCompartment->Release(); + } + return hr; } -void WeaselTSF::_UninitCompartment() -{ - if (_pKeyboardCompartmentSink) { - _pKeyboardCompartmentSink->_Unadvise(); - _pKeyboardCompartmentSink = NULL; - } - if (_pConvertionCompartmentSink) { - _pConvertionCompartmentSink->_Unadvise(); - _pConvertionCompartmentSink = NULL; - } +BOOL WeaselTSF::_InitCompartment() { + using namespace std::placeholders; + + auto callback = std::bind(&WeaselTSF::_HandleCompartment, this, _1); + _pKeyboardCompartmentSink = new CCompartmentEventSink(callback); + if (!_pKeyboardCompartmentSink) + return FALSE; + DWORD hr = _pKeyboardCompartmentSink->_Advise( + (IUnknown*)_pThreadMgr, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE); + + _pConvertionCompartmentSink = new CCompartmentEventSink(callback); + if (!_pConvertionCompartmentSink) + return FALSE; + hr = _pConvertionCompartmentSink->_Advise( + (IUnknown*)_pThreadMgr, GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION); + return SUCCEEDED(hr); +} +void WeaselTSF::_UninitCompartment() { + if (_pKeyboardCompartmentSink) { + _pKeyboardCompartmentSink->_Unadvise(); + _pKeyboardCompartmentSink = NULL; + } + if (_pConvertionCompartmentSink) { + _pConvertionCompartmentSink->_Unadvise(); + _pConvertionCompartmentSink = NULL; + } } -HRESULT WeaselTSF::_HandleCompartment(REFGUID guidCompartment) -{ - if (IsEqualGUID(guidCompartment, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE)) - { - BOOL isOpen = _IsKeyboardOpen(); - // clear composition when close keyboard - if (!isOpen && _pEditSessionContext) { - m_client.ClearComposition(); - _EndComposition(_pEditSessionContext, true); - } - _EnableLanguageBar(isOpen); - } - else if (IsEqualGUID(guidCompartment, GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION)) - { - BOOL isOpen = _IsKeyboardOpen(); - if (isOpen) - { - weasel::ResponseParser parser(NULL, NULL, &_status, NULL, &_cand->style()); - bool ok = m_client.GetResponseData(std::ref(parser)); - _UpdateLanguageBar(_status); - } - } - return S_OK; +HRESULT WeaselTSF::_HandleCompartment(REFGUID guidCompartment) { + if (IsEqualGUID(guidCompartment, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE)) { + BOOL isOpen = _IsKeyboardOpen(); + // clear composition when close keyboard + if (!isOpen && _pEditSessionContext) { + m_client.ClearComposition(); + _EndComposition(_pEditSessionContext, true); + } + _EnableLanguageBar(isOpen); + } else if (IsEqualGUID(guidCompartment, + GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION)) { + BOOL isOpen = _IsKeyboardOpen(); + if (isOpen) { + weasel::ResponseParser parser(NULL, NULL, &_status, NULL, + &_cand->style()); + bool ok = m_client.GetResponseData(std::ref(parser)); + _UpdateLanguageBar(_status); + } + } + return S_OK; } diff --git a/WeaselTSF/Compartment.h b/WeaselTSF/Compartment.h index f039e06c7..9316f9781 100644 --- a/WeaselTSF/Compartment.h +++ b/WeaselTSF/Compartment.h @@ -2,30 +2,29 @@ #include #include -class CCompartmentEventSink : public ITfCompartmentEventSink -{ -public: - using Callback = std::function; - CCompartmentEventSink(Callback callback) - : _callback(callback), _refCount(1) {}; - ~CCompartmentEventSink() = default; +class CCompartmentEventSink : public ITfCompartmentEventSink { + public: + using Callback = std::function; + CCompartmentEventSink(Callback callback) + : _callback(callback), _refCount(1){}; + ~CCompartmentEventSink() = default; - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, _Outptr_ void **ppvObj); - STDMETHODIMP_(ULONG) AddRef(void); - STDMETHODIMP_(ULONG) Release(void); + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, _Outptr_ void** ppvObj); + STDMETHODIMP_(ULONG) AddRef(void); + STDMETHODIMP_(ULONG) Release(void); - // ITfCompartmentEventSink - STDMETHODIMP OnChange(_In_ REFGUID guid); + // ITfCompartmentEventSink + STDMETHODIMP OnChange(_In_ REFGUID guid); - // function - HRESULT _Advise(_In_ com_ptr punk, _In_ REFGUID guidCompartment); - HRESULT _Unadvise(); + // function + HRESULT _Advise(_In_ com_ptr punk, _In_ REFGUID guidCompartment); + HRESULT _Unadvise(); -private: - com_ptr _compartment; - DWORD _cookie; - Callback _callback; + private: + com_ptr _compartment; + DWORD _cookie; + Callback _callback; - LONG _refCount; + LONG _refCount; }; diff --git a/WeaselTSF/Composition.cpp b/WeaselTSF/Composition.cpp index 38b7f2dea..6345f4499 100644 --- a/WeaselTSF/Composition.cpp +++ b/WeaselTSF/Composition.cpp @@ -5,411 +5,411 @@ #include "CandidateList.h" /* Start Composition */ -class CStartCompositionEditSession: public CEditSession -{ -public: - CStartCompositionEditSession(com_ptr pTextService, com_ptr pContext, BOOL fCUASWorkaroundEnabled, BOOL inlinePreeditEnabled) - : CEditSession(pTextService, pContext), _inlinePreeditEnabled(inlinePreeditEnabled) - { - _fCUASWorkaroundEnabled = fCUASWorkaroundEnabled; - } - - /* ITfEditSession */ - STDMETHODIMP DoEditSession(TfEditCookie ec); - -private: - BOOL _fCUASWorkaroundEnabled; - BOOL _inlinePreeditEnabled; +class CStartCompositionEditSession : public CEditSession { + public: + CStartCompositionEditSession(com_ptr pTextService, + com_ptr pContext, + BOOL fCUASWorkaroundEnabled, + BOOL inlinePreeditEnabled) + : CEditSession(pTextService, pContext), + _inlinePreeditEnabled(inlinePreeditEnabled) { + _fCUASWorkaroundEnabled = fCUASWorkaroundEnabled; + } + + /* ITfEditSession */ + STDMETHODIMP DoEditSession(TfEditCookie ec); + + private: + BOOL _fCUASWorkaroundEnabled; + BOOL _inlinePreeditEnabled; }; -STDAPI CStartCompositionEditSession::DoEditSession(TfEditCookie ec) -{ - HRESULT hr = E_FAIL; - com_ptr pInsertAtSelection; - com_ptr pRangeComposition; - if (_pContext->QueryInterface(IID_ITfInsertAtSelection, (LPVOID *) &pInsertAtSelection) != S_OK) - return hr; - if (pInsertAtSelection->InsertTextAtSelection(ec, TF_IAS_QUERYONLY, NULL, 0, &pRangeComposition) != S_OK) - return hr; - - com_ptr pContextComposition; - com_ptr pComposition; - if (_pContext->QueryInterface(IID_ITfContextComposition, (LPVOID *) &pContextComposition) != S_OK) - return hr; - if ((pContextComposition->StartComposition(ec, pRangeComposition, _pTextService, &pComposition) == S_OK) - && (pComposition != NULL)) - { - _pTextService->_SetComposition(pComposition); - - /* WORKAROUND: - * CUAS does not provide a correct GetTextExt() position unless the composition is filled with characters. - * So we insert a zero width space here. - * The workaround is only needed when inline preedit is not enabled. - * See https://github.com/rime/weasel/pull/883#issuecomment-1567625762 - */ - if (!_inlinePreeditEnabled) - { - pRangeComposition->SetText(ec, TF_ST_CORRECTION, L" ", 1); - } - - /* set selection */ - TF_SELECTION tfSelection; - if(_inlinePreeditEnabled) - pRangeComposition->Collapse(ec, TF_ANCHOR_END); - else - pRangeComposition->Collapse(ec, TF_ANCHOR_START); - tfSelection.range = pRangeComposition; - tfSelection.style.ase = TF_AE_NONE; - tfSelection.style.fInterimChar = FALSE; - _pContext->SetSelection(ec, 1, &tfSelection); - } - - return hr; +STDAPI CStartCompositionEditSession::DoEditSession(TfEditCookie ec) { + HRESULT hr = E_FAIL; + com_ptr pInsertAtSelection; + com_ptr pRangeComposition; + if (_pContext->QueryInterface(IID_ITfInsertAtSelection, + (LPVOID*)&pInsertAtSelection) != S_OK) + return hr; + if (pInsertAtSelection->InsertTextAtSelection(ec, TF_IAS_QUERYONLY, NULL, 0, + &pRangeComposition) != S_OK) + return hr; + + com_ptr pContextComposition; + com_ptr pComposition; + if (_pContext->QueryInterface(IID_ITfContextComposition, + (LPVOID*)&pContextComposition) != S_OK) + return hr; + if ((pContextComposition->StartComposition( + ec, pRangeComposition, _pTextService, &pComposition) == S_OK) && + (pComposition != NULL)) { + _pTextService->_SetComposition(pComposition); + + /* WORKAROUND: + * CUAS does not provide a correct GetTextExt() position unless the + * composition is filled with characters. So we insert a zero width space + * here. The workaround is only needed when inline preedit is not enabled. + * See https://github.com/rime/weasel/pull/883#issuecomment-1567625762 + */ + if (!_inlinePreeditEnabled) { + pRangeComposition->SetText(ec, TF_ST_CORRECTION, L" ", 1); + } + + /* set selection */ + TF_SELECTION tfSelection; + if (_inlinePreeditEnabled) + pRangeComposition->Collapse(ec, TF_ANCHOR_END); + else + pRangeComposition->Collapse(ec, TF_ANCHOR_START); + tfSelection.range = pRangeComposition; + tfSelection.style.ase = TF_AE_NONE; + tfSelection.style.fInterimChar = FALSE; + _pContext->SetSelection(ec, 1, &tfSelection); + } + + return hr; } -void WeaselTSF::_StartComposition(com_ptr pContext, BOOL fCUASWorkaroundEnabled) -{ - com_ptr pStartCompositionEditSession; - pStartCompositionEditSession.Attach(new CStartCompositionEditSession(this, pContext, fCUASWorkaroundEnabled, _cand->style().inline_preedit)); - _cand->StartUI(); - if (pStartCompositionEditSession != nullptr) - { - HRESULT hr; - pContext->RequestEditSession(_tfClientId, pStartCompositionEditSession, TF_ES_SYNC | TF_ES_READWRITE, &hr); - } +void WeaselTSF::_StartComposition(com_ptr pContext, + BOOL fCUASWorkaroundEnabled) { + com_ptr pStartCompositionEditSession; + pStartCompositionEditSession.Attach(new CStartCompositionEditSession( + this, pContext, fCUASWorkaroundEnabled, _cand->style().inline_preedit)); + _cand->StartUI(); + if (pStartCompositionEditSession != nullptr) { + HRESULT hr; + pContext->RequestEditSession(_tfClientId, pStartCompositionEditSession, + TF_ES_SYNC | TF_ES_READWRITE, &hr); + } } /* End Composition */ -class CEndCompositionEditSession: public CEditSession -{ -public: - CEndCompositionEditSession(com_ptr pTextService, com_ptr pContext, com_ptr pComposition, BOOL clear = TRUE) - : CEditSession(pTextService, pContext), _clear(clear) - { - _pComposition = pComposition; - } - - /* ITfEditSession */ - STDMETHODIMP DoEditSession(TfEditCookie ec); - -private: - com_ptr _pComposition; - BOOL _clear; +class CEndCompositionEditSession : public CEditSession { + public: + CEndCompositionEditSession(com_ptr pTextService, + com_ptr pContext, + com_ptr pComposition, + BOOL clear = TRUE) + : CEditSession(pTextService, pContext), _clear(clear) { + _pComposition = pComposition; + } + + /* ITfEditSession */ + STDMETHODIMP DoEditSession(TfEditCookie ec); + + private: + com_ptr _pComposition; + BOOL _clear; }; -STDAPI CEndCompositionEditSession::DoEditSession(TfEditCookie ec) -{ - /* Clear the dummy text we set before, if any. */ - if (_pComposition == nullptr) return S_OK; +STDAPI CEndCompositionEditSession::DoEditSession(TfEditCookie ec) { + /* Clear the dummy text we set before, if any. */ + if (_pComposition == nullptr) + return S_OK; - _pTextService->_ClearCompositionDisplayAttributes(ec, _pContext); + _pTextService->_ClearCompositionDisplayAttributes(ec, _pContext); - ITfRange *pCompositionRange; - if (_clear && _pComposition->GetRange(&pCompositionRange) == S_OK) - pCompositionRange->SetText(ec, 0, L"", 0); - - _pComposition->EndComposition(ec); - _pTextService->_FinalizeComposition(); - return S_OK; + ITfRange* pCompositionRange; + if (_clear && _pComposition->GetRange(&pCompositionRange) == S_OK) + pCompositionRange->SetText(ec, 0, L"", 0); + + _pComposition->EndComposition(ec); + _pTextService->_FinalizeComposition(); + return S_OK; } -void WeaselTSF::_EndComposition(com_ptr pContext, BOOL clear) -{ - CEndCompositionEditSession *pEditSession; - HRESULT hr; - - _cand->EndUI(); - if ((pEditSession = new CEndCompositionEditSession(this, pContext, _pComposition, clear)) != NULL) - { - pContext->RequestEditSession(_tfClientId, pEditSession, TF_ES_SYNC | TF_ES_READWRITE, &hr); - pEditSession->Release(); - } +void WeaselTSF::_EndComposition(com_ptr pContext, BOOL clear) { + CEndCompositionEditSession* pEditSession; + HRESULT hr; + + _cand->EndUI(); + if ((pEditSession = new CEndCompositionEditSession( + this, pContext, _pComposition, clear)) != NULL) { + pContext->RequestEditSession(_tfClientId, pEditSession, + TF_ES_SYNC | TF_ES_READWRITE, &hr); + pEditSession->Release(); + } } /* Get Text Extent */ -class CGetTextExtentEditSession: public CEditSession -{ -public: - CGetTextExtentEditSession(com_ptr pTextService, com_ptr pContext, com_ptr pContextView, com_ptr pComposition, bool enhancedPosition) - : CEditSession(pTextService, pContext) - { - _pContextView = pContextView; - _pComposition = pComposition; - _enhancedPosition = enhancedPosition; - } - - /* ITfEditSession */ - STDMETHODIMP DoEditSession(TfEditCookie ec); - -private: - com_ptr _pContextView; - com_ptr _pComposition; - bool _enhancedPosition; +class CGetTextExtentEditSession : public CEditSession { + public: + CGetTextExtentEditSession(com_ptr pTextService, + com_ptr pContext, + com_ptr pContextView, + com_ptr pComposition, + bool enhancedPosition) + : CEditSession(pTextService, pContext) { + _pContextView = pContextView; + _pComposition = pComposition; + _enhancedPosition = enhancedPosition; + } + + /* ITfEditSession */ + STDMETHODIMP DoEditSession(TfEditCookie ec); + + private: + com_ptr _pContextView; + com_ptr _pComposition; + bool _enhancedPosition; }; -STDAPI CGetTextExtentEditSession::DoEditSession(TfEditCookie ec) -{ - com_ptr pInsertAtSelection; - com_ptr pRangeComposition; - ITfRange* pRange; - RECT rc; - BOOL fClipped; - TF_SELECTION selection; - ULONG nSelection; - LONG cch; - - if (FAILED(_pContext->QueryInterface(IID_ITfInsertAtSelection, (LPVOID *) &pInsertAtSelection))) - return E_FAIL; - if (FAILED(_pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &selection, &nSelection))) - return E_FAIL; - - if (_pComposition != nullptr && _pComposition->GetRange(&pRange) == S_OK) - { - pRange->Collapse(ec, TF_ANCHOR_START); - } - else - { - // composition end - // note: selection.range is always an empty range - pRange = selection.range; - } - - if ((_pContextView->GetTextExt(ec, pRange, &rc, &fClipped)) == S_OK && (rc.left != 0 || rc.top != 0)) - { - // get the foreground window pos and check if rc from GetTextExt is out of window - if (_enhancedPosition) - { - HWND hwnd; - RECT rcForegroundWindow; - hwnd = GetForegroundWindow(); - ::GetWindowRect(hwnd, &rcForegroundWindow); - - if(rc.left < rcForegroundWindow.left || rc.left > rcForegroundWindow.right - || rc.top < rcForegroundWindow.top || rc.top > rcForegroundWindow.bottom) - { - POINT pt; - bool hasCaret = ::GetCaretPos(&pt); - int offsetx = rcForegroundWindow.left - rc.left + (hasCaret? pt.x : 0); - int offsety = rcForegroundWindow.top - rc.top + (hasCaret? pt.y : 0); - rc.left += offsetx; - rc.right += offsetx; - rc.top += offsety; - rc.bottom += offsety; - } - } - _pTextService->_SetCompositionPosition(rc); - } - return S_OK; +STDAPI CGetTextExtentEditSession::DoEditSession(TfEditCookie ec) { + com_ptr pInsertAtSelection; + com_ptr pRangeComposition; + ITfRange* pRange; + RECT rc; + BOOL fClipped; + TF_SELECTION selection; + ULONG nSelection; + LONG cch; + + if (FAILED(_pContext->QueryInterface(IID_ITfInsertAtSelection, + (LPVOID*)&pInsertAtSelection))) + return E_FAIL; + if (FAILED(_pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &selection, + &nSelection))) + return E_FAIL; + + if (_pComposition != nullptr && _pComposition->GetRange(&pRange) == S_OK) { + pRange->Collapse(ec, TF_ANCHOR_START); + } else { + // composition end + // note: selection.range is always an empty range + pRange = selection.range; + } + + if ((_pContextView->GetTextExt(ec, pRange, &rc, &fClipped)) == S_OK && + (rc.left != 0 || rc.top != 0)) { + // get the foreground window pos and check if rc from GetTextExt is out of + // window + if (_enhancedPosition) { + HWND hwnd; + RECT rcForegroundWindow; + hwnd = GetForegroundWindow(); + ::GetWindowRect(hwnd, &rcForegroundWindow); + + if (rc.left < rcForegroundWindow.left || + rc.left > rcForegroundWindow.right || + rc.top < rcForegroundWindow.top || + rc.top > rcForegroundWindow.bottom) { + POINT pt; + bool hasCaret = ::GetCaretPos(&pt); + int offsetx = rcForegroundWindow.left - rc.left + (hasCaret ? pt.x : 0); + int offsety = rcForegroundWindow.top - rc.top + (hasCaret ? pt.y : 0); + rc.left += offsetx; + rc.right += offsetx; + rc.top += offsety; + rc.bottom += offsety; + } + } + _pTextService->_SetCompositionPosition(rc); + } + return S_OK; } /* Composition Window Handling */ -BOOL WeaselTSF::_UpdateCompositionWindow(com_ptr pContext) -{ - com_ptr pContextView; - if (pContext->GetActiveView(&pContextView) != S_OK) - return FALSE; - com_ptr pEditSession; - pEditSession.Attach(new CGetTextExtentEditSession(this, pContext, pContextView, _pComposition, _cand->style().enhanced_position)); - if (pEditSession == NULL) - { - return FALSE; - } - HRESULT hr; - pContext->RequestEditSession(_tfClientId, pEditSession, TF_ES_SYNC | TF_ES_READ, &hr); - return SUCCEEDED(hr); +BOOL WeaselTSF::_UpdateCompositionWindow(com_ptr pContext) { + com_ptr pContextView; + if (pContext->GetActiveView(&pContextView) != S_OK) + return FALSE; + com_ptr pEditSession; + pEditSession.Attach( + new CGetTextExtentEditSession(this, pContext, pContextView, _pComposition, + _cand->style().enhanced_position)); + if (pEditSession == NULL) { + return FALSE; + } + HRESULT hr; + pContext->RequestEditSession(_tfClientId, pEditSession, + TF_ES_SYNC | TF_ES_READ, &hr); + return SUCCEEDED(hr); } -void WeaselTSF::_SetCompositionPosition(const RECT &rc) -{ - /* Test if rect is valid. - * If it is invalid during CUAS test, we need to apply CUAS workaround */ - if (!_fCUASWorkaroundTested) - { - _fCUASWorkaroundTested = TRUE; - if (rc.top == rc.bottom) - { - _fCUASWorkaroundEnabled = TRUE; - return; - } - } - RECT _rc; - _rc.left = _rc.right = rc.left; - _rc.top = _rc.bottom = rc.bottom; - m_client.UpdateInputPosition(rc); - _cand->UpdateInputPosition(rc); +void WeaselTSF::_SetCompositionPosition(const RECT& rc) { + /* Test if rect is valid. + * If it is invalid during CUAS test, we need to apply CUAS workaround */ + if (!_fCUASWorkaroundTested) { + _fCUASWorkaroundTested = TRUE; + if (rc.top == rc.bottom) { + _fCUASWorkaroundEnabled = TRUE; + return; + } + } + RECT _rc; + _rc.left = _rc.right = rc.left; + _rc.top = _rc.bottom = rc.bottom; + m_client.UpdateInputPosition(rc); + _cand->UpdateInputPosition(rc); } /* Inline Preedit */ -class CInlinePreeditEditSession: public CEditSession -{ -public: - CInlinePreeditEditSession(com_ptr pTextService, com_ptr pContext, com_ptr pComposition, const std::shared_ptr context) - : CEditSession(pTextService, pContext), _pComposition(pComposition), _context(context) - { - } - - /* ITfEditSession */ - STDMETHODIMP DoEditSession(TfEditCookie ec); - -private: - com_ptr _pComposition; - const std::shared_ptr _context; +class CInlinePreeditEditSession : public CEditSession { + public: + CInlinePreeditEditSession(com_ptr pTextService, + com_ptr pContext, + com_ptr pComposition, + const std::shared_ptr context) + : CEditSession(pTextService, pContext), + _pComposition(pComposition), + _context(context) {} + + /* ITfEditSession */ + STDMETHODIMP DoEditSession(TfEditCookie ec); + + private: + com_ptr _pComposition; + const std::shared_ptr _context; }; -STDAPI CInlinePreeditEditSession::DoEditSession(TfEditCookie ec) -{ - std::wstring preedit = _context->preedit.str; - - com_ptr pRangeComposition; - if ((_pComposition->GetRange(&pRangeComposition)) != S_OK) - return E_FAIL; - - if ((pRangeComposition->SetText(ec, 0, preedit.c_str(), preedit.length())) != S_OK) - return E_FAIL; - - /* TODO: Check the availability and correctness of these values */ - int sel_cursor = -1; - for (size_t i = 0; i < _context->preedit.attributes.size(); i++) - { - if (_context->preedit.attributes.at(i).type == weasel::HIGHLIGHTED) - { - sel_cursor = _context->preedit.attributes.at(i).range.cursor; - break; - } - } - - _pTextService->_SetCompositionDisplayAttributes(ec, _pContext, pRangeComposition); - - /* Set caret */ - LONG cch; - TF_SELECTION tfSelection; - if (sel_cursor < 0) - { - pRangeComposition->Collapse(ec, TF_ANCHOR_END); - } - else - { - pRangeComposition->Collapse(ec, TF_ANCHOR_START); - pRangeComposition->ShiftStart(ec, sel_cursor, &cch, NULL); - } - tfSelection.range = pRangeComposition; - tfSelection.style.ase = TF_AE_NONE; - tfSelection.style.fInterimChar = FALSE; - _pContext->SetSelection(ec, 1, &tfSelection); - - return S_OK; +STDAPI CInlinePreeditEditSession::DoEditSession(TfEditCookie ec) { + std::wstring preedit = _context->preedit.str; + + com_ptr pRangeComposition; + if ((_pComposition->GetRange(&pRangeComposition)) != S_OK) + return E_FAIL; + + if ((pRangeComposition->SetText(ec, 0, preedit.c_str(), preedit.length())) != + S_OK) + return E_FAIL; + + /* TODO: Check the availability and correctness of these values */ + int sel_cursor = -1; + for (size_t i = 0; i < _context->preedit.attributes.size(); i++) { + if (_context->preedit.attributes.at(i).type == weasel::HIGHLIGHTED) { + sel_cursor = _context->preedit.attributes.at(i).range.cursor; + break; + } + } + + _pTextService->_SetCompositionDisplayAttributes(ec, _pContext, + pRangeComposition); + + /* Set caret */ + LONG cch; + TF_SELECTION tfSelection; + if (sel_cursor < 0) { + pRangeComposition->Collapse(ec, TF_ANCHOR_END); + } else { + pRangeComposition->Collapse(ec, TF_ANCHOR_START); + pRangeComposition->ShiftStart(ec, sel_cursor, &cch, NULL); + } + tfSelection.range = pRangeComposition; + tfSelection.style.ase = TF_AE_NONE; + tfSelection.style.fInterimChar = FALSE; + _pContext->SetSelection(ec, 1, &tfSelection); + + return S_OK; } -BOOL WeaselTSF::_ShowInlinePreedit(com_ptr pContext, const std::shared_ptr context) -{ - com_ptr pEditSession; - pEditSession.Attach(new CInlinePreeditEditSession(this, pContext, _pComposition, context)); - if (pEditSession != NULL) - { - HRESULT hr; - pContext->RequestEditSession(_tfClientId, pEditSession, TF_ES_ASYNCDONTCARE | TF_ES_READWRITE, &hr); - } - return TRUE; +BOOL WeaselTSF::_ShowInlinePreedit( + com_ptr pContext, + const std::shared_ptr context) { + com_ptr pEditSession; + pEditSession.Attach( + new CInlinePreeditEditSession(this, pContext, _pComposition, context)); + if (pEditSession != NULL) { + HRESULT hr; + pContext->RequestEditSession(_tfClientId, pEditSession, + TF_ES_ASYNCDONTCARE | TF_ES_READWRITE, &hr); + } + return TRUE; } /* Update Composition */ -class CInsertTextEditSession : public CEditSession -{ -public: - CInsertTextEditSession(com_ptr pTextService, com_ptr pContext, com_ptr pComposition, const std::wstring &text) - : CEditSession(pTextService, pContext), _text(text), _pComposition(pComposition) - { - } - - /* ITfEditSession */ - STDMETHODIMP DoEditSession(TfEditCookie ec); - -private: - std::wstring _text; - com_ptr _pComposition; +class CInsertTextEditSession : public CEditSession { + public: + CInsertTextEditSession(com_ptr pTextService, + com_ptr pContext, + com_ptr pComposition, + const std::wstring& text) + : CEditSession(pTextService, pContext), + _text(text), + _pComposition(pComposition) {} + + /* ITfEditSession */ + STDMETHODIMP DoEditSession(TfEditCookie ec); + + private: + std::wstring _text; + com_ptr _pComposition; }; -STDMETHODIMP CInsertTextEditSession::DoEditSession(TfEditCookie ec) -{ - com_ptr pRange; - TF_SELECTION tfSelection; - HRESULT hRet = S_OK; +STDMETHODIMP CInsertTextEditSession::DoEditSession(TfEditCookie ec) { + com_ptr pRange; + TF_SELECTION tfSelection; + HRESULT hRet = S_OK; - if (FAILED(_pComposition->GetRange(&pRange))) - return E_FAIL; + if (FAILED(_pComposition->GetRange(&pRange))) + return E_FAIL; - if (FAILED(pRange->SetText(ec, 0, _text.c_str(), _text.length()))) - return E_FAIL; + if (FAILED(pRange->SetText(ec, 0, _text.c_str(), _text.length()))) + return E_FAIL; - /* update the selection to an insertion point just past the inserted text. */ - pRange->Collapse(ec, TF_ANCHOR_END); + /* update the selection to an insertion point just past the inserted text. */ + pRange->Collapse(ec, TF_ANCHOR_END); - tfSelection.range = pRange; - tfSelection.style.ase = TF_AE_NONE; - tfSelection.style.fInterimChar = FALSE; + tfSelection.range = pRange; + tfSelection.style.ase = TF_AE_NONE; + tfSelection.style.fInterimChar = FALSE; - _pContext->SetSelection(ec, 1, &tfSelection); + _pContext->SetSelection(ec, 1, &tfSelection); - return hRet; + return hRet; } -BOOL WeaselTSF::_InsertText(com_ptr pContext, const std::wstring& text) -{ - CInsertTextEditSession *pEditSession; - HRESULT hr; +BOOL WeaselTSF::_InsertText(com_ptr pContext, + const std::wstring& text) { + CInsertTextEditSession* pEditSession; + HRESULT hr; - if ((pEditSession = new CInsertTextEditSession(this, pContext, _pComposition, text)) != NULL) - { - pContext->RequestEditSession(_tfClientId, pEditSession, TF_ES_ASYNCDONTCARE | TF_ES_READWRITE, &hr); - pEditSession->Release(); - } + if ((pEditSession = new CInsertTextEditSession(this, pContext, _pComposition, + text)) != NULL) { + pContext->RequestEditSession(_tfClientId, pEditSession, + TF_ES_ASYNCDONTCARE | TF_ES_READWRITE, &hr); + pEditSession->Release(); + } - return TRUE; + return TRUE; } -void WeaselTSF::_UpdateComposition(com_ptr pContext) -{ - HRESULT hr; +void WeaselTSF::_UpdateComposition(com_ptr pContext) { + HRESULT hr; - _pEditSessionContext = pContext; - - _pEditSessionContext->RequestEditSession(_tfClientId, this, TF_ES_ASYNCDONTCARE | TF_ES_READWRITE, &hr); - _UpdateCompositionWindow(pContext); + _pEditSessionContext = pContext; + _pEditSessionContext->RequestEditSession( + _tfClientId, this, TF_ES_ASYNCDONTCARE | TF_ES_READWRITE, &hr); + _UpdateCompositionWindow(pContext); } /* Composition State */ -STDAPI WeaselTSF::OnCompositionTerminated(TfEditCookie ecWrite, ITfComposition *pComposition) -{ - // NOTE: - // This will be called when an edit session ended up with an empty composition string, - // Even if it is closed normally. - // Silly M$. - - _AbortComposition(); - return S_OK; +STDAPI WeaselTSF::OnCompositionTerminated(TfEditCookie ecWrite, + ITfComposition* pComposition) { + // NOTE: + // This will be called when an edit session ended up with an empty composition + // string, Even if it is closed normally. Silly M$. + + _AbortComposition(); + return S_OK; } -void WeaselTSF::_AbortComposition(bool clear) -{ - m_client.ClearComposition(); - if (_IsComposing()) { - _EndComposition(_pEditSessionContext, clear); - } - _cand->Destroy(); +void WeaselTSF::_AbortComposition(bool clear) { + m_client.ClearComposition(); + if (_IsComposing()) { + _EndComposition(_pEditSessionContext, clear); + } + _cand->Destroy(); } -void WeaselTSF::_FinalizeComposition() -{ - _pComposition = nullptr; +void WeaselTSF::_FinalizeComposition() { + _pComposition = nullptr; } -void WeaselTSF::_SetComposition(com_ptr pComposition) -{ - _pComposition = pComposition; +void WeaselTSF::_SetComposition(com_ptr pComposition) { + _pComposition = pComposition; } -BOOL WeaselTSF::_IsComposing() -{ - return _pComposition != NULL; +BOOL WeaselTSF::_IsComposing() { + return _pComposition != NULL; } diff --git a/WeaselTSF/DisplayAttribute.cpp b/WeaselTSF/DisplayAttribute.cpp index eb2bbc820..679c79926 100644 --- a/WeaselTSF/DisplayAttribute.cpp +++ b/WeaselTSF/DisplayAttribute.cpp @@ -2,75 +2,74 @@ #include "WeaselTSF.h" -void WeaselTSF::_ClearCompositionDisplayAttributes(TfEditCookie ec, _In_ ITfContext* pContext) -{ - ITfRange* pRangeComposition = nullptr; - ITfProperty* pDisplayAttributeProperty = nullptr; +void WeaselTSF::_ClearCompositionDisplayAttributes(TfEditCookie ec, + _In_ ITfContext* pContext) { + ITfRange* pRangeComposition = nullptr; + ITfProperty* pDisplayAttributeProperty = nullptr; - if (FAILED(_pComposition->GetRange(&pRangeComposition))) - { - return; - } + if (FAILED(_pComposition->GetRange(&pRangeComposition))) { + return; + } - if (SUCCEEDED(pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pDisplayAttributeProperty))) - { - pDisplayAttributeProperty->Clear(ec, pRangeComposition); + if (SUCCEEDED(pContext->GetProperty(GUID_PROP_ATTRIBUTE, + &pDisplayAttributeProperty))) { + pDisplayAttributeProperty->Clear(ec, pRangeComposition); - pDisplayAttributeProperty->Release(); - } + pDisplayAttributeProperty->Release(); + } - pRangeComposition->Release(); + pRangeComposition->Release(); } -BOOL WeaselTSF::_SetCompositionDisplayAttributes(TfEditCookie ec, _In_ ITfContext* pContext, ITfRange *pRangeComposition) -{ - ITfProperty* pDisplayAttributeProperty = nullptr; - HRESULT hr = S_OK; +BOOL WeaselTSF::_SetCompositionDisplayAttributes(TfEditCookie ec, + _In_ ITfContext* pContext, + ITfRange* pRangeComposition) { + ITfProperty* pDisplayAttributeProperty = nullptr; + HRESULT hr = S_OK; - if (pRangeComposition == nullptr) - hr = _pComposition->GetRange(&pRangeComposition); - if (FAILED(hr)) - { - return FALSE; - } + if (pRangeComposition == nullptr) + hr = _pComposition->GetRange(&pRangeComposition); + if (FAILED(hr)) { + return FALSE; + } - hr = E_FAIL; + hr = E_FAIL; - if (SUCCEEDED(pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pDisplayAttributeProperty))) - { - VARIANT var; - var.vt = VT_I4; // we're going to set a TfGuidAtom - var.lVal = _gaDisplayAttributeInput; + if (SUCCEEDED(pContext->GetProperty(GUID_PROP_ATTRIBUTE, + &pDisplayAttributeProperty))) { + VARIANT var; + var.vt = VT_I4; // we're going to set a TfGuidAtom + var.lVal = _gaDisplayAttributeInput; - hr = pDisplayAttributeProperty->SetValue(ec, pRangeComposition, &var); + hr = pDisplayAttributeProperty->SetValue(ec, pRangeComposition, &var); - pDisplayAttributeProperty->Release(); - } + pDisplayAttributeProperty->Release(); + } - // DO NOT release range composition here - // it will be released in another function - // pRangeComposition->Release(); - return (hr == S_OK); + // DO NOT release range composition here + // it will be released in another function + // pRangeComposition->Release(); + return (hr == S_OK); } -BOOL WeaselTSF::_InitDisplayAttributeGuidAtom() -{ - ITfCategoryMgr* pCategoryMgr = nullptr; - HRESULT hr = CoCreateInstance(CLSID_TF_CategoryMgr, nullptr, CLSCTX_INPROC_SERVER, IID_ITfCategoryMgr, (void**)&pCategoryMgr); +BOOL WeaselTSF::_InitDisplayAttributeGuidAtom() { + ITfCategoryMgr* pCategoryMgr = nullptr; + HRESULT hr = + CoCreateInstance(CLSID_TF_CategoryMgr, nullptr, CLSCTX_INPROC_SERVER, + IID_ITfCategoryMgr, (void**)&pCategoryMgr); - if (FAILED(hr)) - { - return FALSE; - } + if (FAILED(hr)) { + return FALSE; + } - hr = pCategoryMgr->RegisterGUID(c_guidDisplayAttributeInput, &_gaDisplayAttributeInput); - if (FAILED(hr)) - { - goto Exit; - } + hr = pCategoryMgr->RegisterGUID(c_guidDisplayAttributeInput, + &_gaDisplayAttributeInput); + if (FAILED(hr)) { + goto Exit; + } Exit: - pCategoryMgr->Release(); + pCategoryMgr->Release(); - return (hr == S_OK); + return (hr == S_OK); } diff --git a/WeaselTSF/DisplayAttributeInfo.cpp b/WeaselTSF/DisplayAttributeInfo.cpp index 6a6670e84..a18bdb4f0 100644 --- a/WeaselTSF/DisplayAttributeInfo.cpp +++ b/WeaselTSF/DisplayAttributeInfo.cpp @@ -7,125 +7,111 @@ const WCHAR _daiInputName[] = L"DisplayAttributeInput"; const WCHAR _daiDescription[] = L"Weasel Display Attribute Input"; // change style only, leave color to app -const TF_DISPLAYATTRIBUTE _daiDisplayAttribute = -{ - { TF_CT_NONE, 0 }, // text color - { TF_CT_NONE, 0 }, // background color (TF_CT_NONE => app default) - TF_LS_DOT, // underline style - FALSE, // underline boldness - { TF_CT_NONE, 0 }, // underline color - TF_ATTR_INPUT // attribute info +const TF_DISPLAYATTRIBUTE _daiDisplayAttribute = { + {TF_CT_NONE, 0}, // text color + {TF_CT_NONE, 0}, // background color (TF_CT_NONE => app default) + TF_LS_DOT, // underline style + FALSE, // underline boldness + {TF_CT_NONE, 0}, // underline color + TF_ATTR_INPUT // attribute info }; -CDisplayAttributeInfoInput::CDisplayAttributeInfoInput() -{ - DllAddRef(); - _refCount = 1; +CDisplayAttributeInfoInput::CDisplayAttributeInfoInput() { + DllAddRef(); + _refCount = 1; - _pguid = &c_guidDisplayAttributeInput; - _pDisplayAttribute = &_daiDisplayAttribute; - _pDescription = _daiDescription; - _pValueName = _daiInputName; + _pguid = &c_guidDisplayAttributeInput; + _pDisplayAttribute = &_daiDisplayAttribute; + _pDescription = _daiDescription; + _pValueName = _daiInputName; } -CDisplayAttributeInfoInput::~CDisplayAttributeInfoInput() -{ - DllRelease(); +CDisplayAttributeInfoInput::~CDisplayAttributeInfoInput() { + DllRelease(); } -STDAPI CDisplayAttributeInfoInput::QueryInterface(REFIID riid, _Outptr_ void** ppvObj) -{ - if (ppvObj == nullptr) - return E_INVALIDARG; +STDAPI CDisplayAttributeInfoInput::QueryInterface(REFIID riid, + _Outptr_ void** ppvObj) { + if (ppvObj == nullptr) + return E_INVALIDARG; - *ppvObj = nullptr; + *ppvObj = nullptr; - if (IsEqualIID(riid, IID_IUnknown) || - IsEqualIID(riid, IID_ITfDisplayAttributeInfo)) - { - *ppvObj = (ITfDisplayAttributeInfo*)this; - } + if (IsEqualIID(riid, IID_IUnknown) || + IsEqualIID(riid, IID_ITfDisplayAttributeInfo)) { + *ppvObj = (ITfDisplayAttributeInfo*)this; + } - if (*ppvObj) - { - AddRef(); - return S_OK; - } + if (*ppvObj) { + AddRef(); + return S_OK; + } - return E_NOINTERFACE; + return E_NOINTERFACE; } -ULONG CDisplayAttributeInfoInput::AddRef(void) -{ - return ++_refCount; +ULONG CDisplayAttributeInfoInput::AddRef(void) { + return ++_refCount; } -ULONG CDisplayAttributeInfoInput::Release(void) -{ - LONG cr = --_refCount; +ULONG CDisplayAttributeInfoInput::Release(void) { + LONG cr = --_refCount; - assert(_refCount >= 0); + assert(_refCount >= 0); - if (_refCount == 0) - { - delete this; - } + if (_refCount == 0) { + delete this; + } - return cr; + return cr; } -STDAPI CDisplayAttributeInfoInput::GetGUID(_Out_ GUID* pguid) -{ - if (pguid == nullptr) - return E_INVALIDARG; +STDAPI CDisplayAttributeInfoInput::GetGUID(_Out_ GUID* pguid) { + if (pguid == nullptr) + return E_INVALIDARG; - if (_pguid == nullptr) - return E_FAIL; + if (_pguid == nullptr) + return E_FAIL; - *pguid = *_pguid; + *pguid = *_pguid; - return S_OK; + return S_OK; } -STDAPI CDisplayAttributeInfoInput::GetDescription(_Out_ BSTR* pbstrDesc) -{ - BSTR tempDesc; +STDAPI CDisplayAttributeInfoInput::GetDescription(_Out_ BSTR* pbstrDesc) { + BSTR tempDesc; - if (pbstrDesc == nullptr) - { - return E_INVALIDARG; - } + if (pbstrDesc == nullptr) { + return E_INVALIDARG; + } - *pbstrDesc = nullptr; + *pbstrDesc = nullptr; - if ((tempDesc = SysAllocString(_pDescription)) == nullptr) - { - return E_OUTOFMEMORY; - } + if ((tempDesc = SysAllocString(_pDescription)) == nullptr) { + return E_OUTOFMEMORY; + } - *pbstrDesc = tempDesc; + *pbstrDesc = tempDesc; - return S_OK; + return S_OK; } -STDAPI CDisplayAttributeInfoInput::GetAttributeInfo(_Out_ TF_DISPLAYATTRIBUTE* ptfDisplayAttr) -{ - if (ptfDisplayAttr == nullptr) - { - return E_INVALIDARG; - } +STDAPI CDisplayAttributeInfoInput::GetAttributeInfo( + _Out_ TF_DISPLAYATTRIBUTE* ptfDisplayAttr) { + if (ptfDisplayAttr == nullptr) { + return E_INVALIDARG; + } - *ptfDisplayAttr = *_pDisplayAttribute; + *ptfDisplayAttr = *_pDisplayAttribute; - return S_OK; + return S_OK; } -STDAPI CDisplayAttributeInfoInput::SetAttributeInfo(_In_ const TF_DISPLAYATTRIBUTE* /*ptfDisplayAttr*/) -{ - return E_NOTIMPL; +STDAPI CDisplayAttributeInfoInput::SetAttributeInfo( + _In_ const TF_DISPLAYATTRIBUTE* /*ptfDisplayAttr*/) { + return E_NOTIMPL; } -STDAPI CDisplayAttributeInfoInput::Reset() -{ - return SetAttributeInfo(_pDisplayAttribute); +STDAPI CDisplayAttributeInfoInput::Reset() { + return SetAttributeInfo(_pDisplayAttribute); } diff --git a/WeaselTSF/DisplayAttributeInfo.h b/WeaselTSF/DisplayAttributeInfo.h index 0b6a5f026..99e6eaf03 100644 --- a/WeaselTSF/DisplayAttributeInfo.h +++ b/WeaselTSF/DisplayAttributeInfo.h @@ -2,28 +2,27 @@ #include -class CDisplayAttributeInfoInput : public ITfDisplayAttributeInfo -{ -public: - CDisplayAttributeInfoInput(); - ~CDisplayAttributeInfoInput(); +class CDisplayAttributeInfoInput : public ITfDisplayAttributeInfo { + public: + CDisplayAttributeInfoInput(); + ~CDisplayAttributeInfoInput(); - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, _Outptr_ void** ppvObj); - STDMETHODIMP_(ULONG) AddRef(void); - STDMETHODIMP_(ULONG) Release(void); + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, _Outptr_ void** ppvObj); + STDMETHODIMP_(ULONG) AddRef(void); + STDMETHODIMP_(ULONG) Release(void); - // ITfDisplayAttributeInfo - STDMETHODIMP GetGUID(_Out_ GUID* pguid); - STDMETHODIMP GetDescription(_Out_ BSTR* pbstrDesc); - STDMETHODIMP GetAttributeInfo(_Out_ TF_DISPLAYATTRIBUTE* pTSFDisplayAttr); - STDMETHODIMP SetAttributeInfo(_In_ const TF_DISPLAYATTRIBUTE* ptfDisplayAttr); - STDMETHODIMP Reset(); + // ITfDisplayAttributeInfo + STDMETHODIMP GetGUID(_Out_ GUID* pguid); + STDMETHODIMP GetDescription(_Out_ BSTR* pbstrDesc); + STDMETHODIMP GetAttributeInfo(_Out_ TF_DISPLAYATTRIBUTE* pTSFDisplayAttr); + STDMETHODIMP SetAttributeInfo(_In_ const TF_DISPLAYATTRIBUTE* ptfDisplayAttr); + STDMETHODIMP Reset(); -private: - const GUID* _pguid; - const TF_DISPLAYATTRIBUTE* _pDisplayAttribute; - const WCHAR* _pDescription; - const WCHAR* _pValueName; - LONG _refCount; // COM ref count + private: + const GUID* _pguid; + const TF_DISPLAYATTRIBUTE* _pDisplayAttribute; + const WCHAR* _pDescription; + const WCHAR* _pValueName; + LONG _refCount; // COM ref count }; diff --git a/WeaselTSF/DisplayAttributeProvider.cpp b/WeaselTSF/DisplayAttributeProvider.cpp index 6abefeb93..25b3a2fb0 100644 --- a/WeaselTSF/DisplayAttributeProvider.cpp +++ b/WeaselTSF/DisplayAttributeProvider.cpp @@ -4,50 +4,43 @@ #include "EnumDisplayAttributeInfo.h" #include "DisplayAttributeInfo.h" -STDAPI WeaselTSF::EnumDisplayAttributeInfo(__RPC__deref_out_opt IEnumTfDisplayAttributeInfo** ppEnum) -{ - CEnumDisplayAttributeInfo* pAttributeEnum = nullptr; +STDAPI WeaselTSF::EnumDisplayAttributeInfo( + __RPC__deref_out_opt IEnumTfDisplayAttributeInfo** ppEnum) { + CEnumDisplayAttributeInfo* pAttributeEnum = nullptr; - if (ppEnum == nullptr) - { - return E_INVALIDARG; - } + if (ppEnum == nullptr) { + return E_INVALIDARG; + } - *ppEnum = nullptr; + *ppEnum = nullptr; - pAttributeEnum = new (std::nothrow) CEnumDisplayAttributeInfo(); - if (pAttributeEnum == nullptr) - { - return E_OUTOFMEMORY; - } + pAttributeEnum = new (std::nothrow) CEnumDisplayAttributeInfo(); + if (pAttributeEnum == nullptr) { + return E_OUTOFMEMORY; + } - *ppEnum = pAttributeEnum; + *ppEnum = pAttributeEnum; - return S_OK; + return S_OK; } -STDAPI WeaselTSF::GetDisplayAttributeInfo(__RPC__in REFGUID guidInfo, __RPC__deref_out_opt ITfDisplayAttributeInfo** ppInfo) -{ - if (ppInfo == nullptr) - { - return E_INVALIDARG; - } +STDAPI WeaselTSF::GetDisplayAttributeInfo( + __RPC__in REFGUID guidInfo, + __RPC__deref_out_opt ITfDisplayAttributeInfo** ppInfo) { + if (ppInfo == nullptr) { + return E_INVALIDARG; + } - *ppInfo = nullptr; + *ppInfo = nullptr; - if (IsEqualGUID(guidInfo, c_guidDisplayAttributeInput)) - { - *ppInfo = new (std::nothrow) CDisplayAttributeInfoInput(); - if ((*ppInfo) == nullptr) - { - return E_OUTOFMEMORY; - } + if (IsEqualGUID(guidInfo, c_guidDisplayAttributeInput)) { + *ppInfo = new (std::nothrow) CDisplayAttributeInfoInput(); + if ((*ppInfo) == nullptr) { + return E_OUTOFMEMORY; } - else - { - return E_INVALIDARG; - } - + } else { + return E_INVALIDARG; + } - return S_OK; + return S_OK; } diff --git a/WeaselTSF/EditSession.cpp b/WeaselTSF/EditSession.cpp index 2445d3886..59004d363 100644 --- a/WeaselTSF/EditSession.cpp +++ b/WeaselTSF/EditSession.cpp @@ -3,47 +3,42 @@ #include "CandidateList.h" #include "ResponseParser.h" -STDAPI WeaselTSF::DoEditSession(TfEditCookie ec) -{ - // get commit string from server - std::wstring commit; - weasel::Config config; - auto context = std::make_shared(); - weasel::ResponseParser parser(&commit, context.get(), &_status, &config, &_cand->style()); +STDAPI WeaselTSF::DoEditSession(TfEditCookie ec) { + // get commit string from server + std::wstring commit; + weasel::Config config; + auto context = std::make_shared(); + weasel::ResponseParser parser(&commit, context.get(), &_status, &config, + &_cand->style()); - bool ok = m_client.GetResponseData(std::ref(parser)); + bool ok = m_client.GetResponseData(std::ref(parser)); - _UpdateLanguageBar(_status); + _UpdateLanguageBar(_status); - if (ok) - { - if (!commit.empty()) - { - // For auto-selecting, commit and preedit can both exist. - // Commit and close the original composition first. - if (!_IsComposing()) { - _StartComposition(_pEditSessionContext, _fCUASWorkaroundEnabled && !config.inline_preedit); - } - _InsertText(_pEditSessionContext, commit); - _EndComposition(_pEditSessionContext, false); - } - if (_status.composing && !_IsComposing()) - { - _StartComposition(_pEditSessionContext, _fCUASWorkaroundEnabled && !config.inline_preedit); - } - else if (!_status.composing && _IsComposing()) - { - _EndComposition(_pEditSessionContext, true); - } - _UpdateCompositionWindow(_pEditSessionContext); - if (_IsComposing() && config.inline_preedit) - { - _ShowInlinePreedit(_pEditSessionContext, context); - } - } + if (ok) { + if (!commit.empty()) { + // For auto-selecting, commit and preedit can both exist. + // Commit and close the original composition first. + if (!_IsComposing()) { + _StartComposition(_pEditSessionContext, + _fCUASWorkaroundEnabled && !config.inline_preedit); + } + _InsertText(_pEditSessionContext, commit); + _EndComposition(_pEditSessionContext, false); + } + if (_status.composing && !_IsComposing()) { + _StartComposition(_pEditSessionContext, + _fCUASWorkaroundEnabled && !config.inline_preedit); + } else if (!_status.composing && _IsComposing()) { + _EndComposition(_pEditSessionContext, true); + } + _UpdateCompositionWindow(_pEditSessionContext); + if (_IsComposing() && config.inline_preedit) { + _ShowInlinePreedit(_pEditSessionContext, context); + } + } - _UpdateUI(*context, _status); + _UpdateUI(*context, _status); - return TRUE; + return TRUE; } - diff --git a/WeaselTSF/EditSession.h b/WeaselTSF/EditSession.h index 9d0edb729..7071885ed 100644 --- a/WeaselTSF/EditSession.h +++ b/WeaselTSF/EditSession.h @@ -3,59 +3,49 @@ #include "stdafx.h" #include "WeaselTSF.h" -class CEditSession: public ITfEditSession -{ -public: - CEditSession(com_ptr pTextService, com_ptr pContext) - : _pTextService(pTextService), _pContext(pContext) - { - _cRef = 1; - } - - virtual ~CEditSession() - { - } - - /* IUnknown */ - STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) - { - if (ppvObject == NULL) - return E_INVALIDARG; - - *ppvObject = NULL; - - if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfEditSession)) - *ppvObject = (ITfEditSession *) this; - - if (*ppvObject) - { - AddRef(); - return S_OK; - } - return E_NOINTERFACE; - } - - STDMETHODIMP_(ULONG) AddRef() - { - return ++_cRef; - } - - STDMETHODIMP_(ULONG) Release() - { - LONG cr = --_cRef; - assert(_cRef >= 0); - if (_cRef == 0) - delete this; - return cr; - } - - /* ITfEditSession */ - virtual STDMETHODIMP DoEditSession(TfEditCookie ec) = 0; - -protected: - com_ptr _pTextService; - com_ptr _pContext; - -private: - LONG _cRef; /* COM reference count */ +class CEditSession : public ITfEditSession { + public: + CEditSession(com_ptr pTextService, com_ptr pContext) + : _pTextService(pTextService), _pContext(pContext) { + _cRef = 1; + } + + virtual ~CEditSession() {} + + /* IUnknown */ + STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == NULL) + return E_INVALIDARG; + + *ppvObject = NULL; + + if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfEditSession)) + *ppvObject = (ITfEditSession*)this; + + if (*ppvObject) { + AddRef(); + return S_OK; + } + return E_NOINTERFACE; + } + + STDMETHODIMP_(ULONG) AddRef() { return ++_cRef; } + + STDMETHODIMP_(ULONG) Release() { + LONG cr = --_cRef; + assert(_cRef >= 0); + if (_cRef == 0) + delete this; + return cr; + } + + /* ITfEditSession */ + virtual STDMETHODIMP DoEditSession(TfEditCookie ec) = 0; + + protected: + com_ptr _pTextService; + com_ptr _pContext; + + private: + LONG _cRef; /* COM reference count */ }; \ No newline at end of file diff --git a/WeaselTSF/EnumDisplayAttributeInfo.cpp b/WeaselTSF/EnumDisplayAttributeInfo.cpp index b9b923d68..293df2bae 100644 --- a/WeaselTSF/EnumDisplayAttributeInfo.cpp +++ b/WeaselTSF/EnumDisplayAttributeInfo.cpp @@ -4,145 +4,128 @@ #include "Globals.h" #include "DisplayAttributeInfo.h" -CEnumDisplayAttributeInfo::CEnumDisplayAttributeInfo() -{ - DllAddRef(); +CEnumDisplayAttributeInfo::CEnumDisplayAttributeInfo() { + DllAddRef(); - _index = 0; - _refCount = 1; + _index = 0; + _refCount = 1; } -CEnumDisplayAttributeInfo::~CEnumDisplayAttributeInfo() -{ - DllRelease(); +CEnumDisplayAttributeInfo::~CEnumDisplayAttributeInfo() { + DllRelease(); } -STDAPI CEnumDisplayAttributeInfo::QueryInterface(REFIID riid, _Outptr_ void** ppvObj) -{ - if (ppvObj == nullptr) - return E_INVALIDARG; +STDAPI CEnumDisplayAttributeInfo::QueryInterface(REFIID riid, + _Outptr_ void** ppvObj) { + if (ppvObj == nullptr) + return E_INVALIDARG; - *ppvObj = nullptr; + *ppvObj = nullptr; - if (IsEqualIID(riid, IID_IUnknown) || - IsEqualIID(riid, IID_IEnumTfDisplayAttributeInfo)) - { - *ppvObj = (IEnumTfDisplayAttributeInfo*)this; - } + if (IsEqualIID(riid, IID_IUnknown) || + IsEqualIID(riid, IID_IEnumTfDisplayAttributeInfo)) { + *ppvObj = (IEnumTfDisplayAttributeInfo*)this; + } - if (*ppvObj) - { - AddRef(); - return S_OK; - } + if (*ppvObj) { + AddRef(); + return S_OK; + } - return E_NOINTERFACE; + return E_NOINTERFACE; } -STDAPI_(ULONG) CEnumDisplayAttributeInfo::AddRef() -{ - return ++_refCount; +STDAPI_(ULONG) CEnumDisplayAttributeInfo::AddRef() { + return ++_refCount; } -STDAPI_(ULONG) CEnumDisplayAttributeInfo::Release() -{ - LONG cr = --_refCount; +STDAPI_(ULONG) CEnumDisplayAttributeInfo::Release() { + LONG cr = --_refCount; - assert(_refCount >= 0); + assert(_refCount >= 0); - if (_refCount == 0) - { - delete this; - } + if (_refCount == 0) { + delete this; + } - return cr; + return cr; } -STDAPI CEnumDisplayAttributeInfo::Clone(_Out_ IEnumTfDisplayAttributeInfo** ppEnum) -{ - CEnumDisplayAttributeInfo* pClone = nullptr; +STDAPI CEnumDisplayAttributeInfo::Clone( + _Out_ IEnumTfDisplayAttributeInfo** ppEnum) { + CEnumDisplayAttributeInfo* pClone = nullptr; - if (ppEnum == nullptr) - { - return E_INVALIDARG; - } + if (ppEnum == nullptr) { + return E_INVALIDARG; + } - *ppEnum = nullptr; + *ppEnum = nullptr; - pClone = new (std::nothrow) CEnumDisplayAttributeInfo(); - if ((pClone) == nullptr) - { - return E_OUTOFMEMORY; - } + pClone = new (std::nothrow) CEnumDisplayAttributeInfo(); + if ((pClone) == nullptr) { + return E_OUTOFMEMORY; + } - // the clone should match this object's state - pClone->_index = _index; + // the clone should match this object's state + pClone->_index = _index; - *ppEnum = pClone; + *ppEnum = pClone; - return S_OK; + return S_OK; } -STDAPI CEnumDisplayAttributeInfo::Next(ULONG ulCount, __RPC__out_ecount_part(ulCount, *pcFetched) ITfDisplayAttributeInfo** rgInfo, __RPC__out ULONG* pcFetched) -{ - ULONG fetched; +STDAPI CEnumDisplayAttributeInfo::Next(ULONG ulCount, + __RPC__out_ecount_part(ulCount, + *pcFetched) + ITfDisplayAttributeInfo** rgInfo, + __RPC__out ULONG* pcFetched) { + ULONG fetched; - fetched = 0; + fetched = 0; - if (ulCount == 0) - { - return S_OK; - } - if (rgInfo == nullptr) - { - return E_INVALIDARG; - } - *rgInfo = nullptr; - - while (fetched < ulCount) - { - ITfDisplayAttributeInfo* pDisplayAttributeInfo = nullptr; - - if (_index == 0) - { - pDisplayAttributeInfo = new (std::nothrow) CDisplayAttributeInfoInput(); - if ((pDisplayAttributeInfo) == nullptr) - { - return E_OUTOFMEMORY; - } - } - else - { - break; - } - - *rgInfo = pDisplayAttributeInfo; - rgInfo++; - fetched++; - _index++; + if (ulCount == 0) { + return S_OK; + } + if (rgInfo == nullptr) { + return E_INVALIDARG; + } + *rgInfo = nullptr; + + while (fetched < ulCount) { + ITfDisplayAttributeInfo* pDisplayAttributeInfo = nullptr; + + if (_index == 0) { + pDisplayAttributeInfo = new (std::nothrow) CDisplayAttributeInfoInput(); + if ((pDisplayAttributeInfo) == nullptr) { + return E_OUTOFMEMORY; + } + } else { + break; } - if (pcFetched != nullptr) - { - *pcFetched = fetched; - } + *rgInfo = pDisplayAttributeInfo; + rgInfo++; + fetched++; + _index++; + } - return (fetched == ulCount) ? S_OK : S_FALSE; + if (pcFetched != nullptr) { + *pcFetched = fetched; + } + + return (fetched == ulCount) ? S_OK : S_FALSE; } -STDAPI CEnumDisplayAttributeInfo::Reset() -{ - _index = 0; - return S_OK; +STDAPI CEnumDisplayAttributeInfo::Reset() { + _index = 0; + return S_OK; } -STDAPI CEnumDisplayAttributeInfo::Skip(ULONG ulCount) -{ - if ((ulCount + _index) > 1 || (ulCount + _index) < ulCount) - { - _index = 1; - return S_FALSE; - } - _index += ulCount; - return S_OK; +STDAPI CEnumDisplayAttributeInfo::Skip(ULONG ulCount) { + if ((ulCount + _index) > 1 || (ulCount + _index) < ulCount) { + _index = 1; + return S_FALSE; + } + _index += ulCount; + return S_OK; } diff --git a/WeaselTSF/EnumDisplayAttributeInfo.h b/WeaselTSF/EnumDisplayAttributeInfo.h index 869379342..4113186d8 100644 --- a/WeaselTSF/EnumDisplayAttributeInfo.h +++ b/WeaselTSF/EnumDisplayAttributeInfo.h @@ -1,23 +1,25 @@ #pragma once -class CEnumDisplayAttributeInfo : public IEnumTfDisplayAttributeInfo -{ -public: - CEnumDisplayAttributeInfo(); - ~CEnumDisplayAttributeInfo(); +class CEnumDisplayAttributeInfo : public IEnumTfDisplayAttributeInfo { + public: + CEnumDisplayAttributeInfo(); + ~CEnumDisplayAttributeInfo(); - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, _Outptr_ void** ppvObj); - STDMETHODIMP_(ULONG) AddRef(void); - STDMETHODIMP_(ULONG) Release(void); + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, _Outptr_ void** ppvObj); + STDMETHODIMP_(ULONG) AddRef(void); + STDMETHODIMP_(ULONG) Release(void); - // IEnumTfDisplayAttributeInfo - STDMETHODIMP Clone(_Out_ IEnumTfDisplayAttributeInfo** ppEnum); - STDMETHODIMP Next(ULONG ulCount, __RPC__out_ecount_part(ulCount, *pcFetched) ITfDisplayAttributeInfo** rgInfo, __RPC__out ULONG* pcFetched); - STDMETHODIMP Reset(); - STDMETHODIMP Skip(ULONG ulCount); + // IEnumTfDisplayAttributeInfo + STDMETHODIMP Clone(_Out_ IEnumTfDisplayAttributeInfo** ppEnum); + STDMETHODIMP Next(ULONG ulCount, + __RPC__out_ecount_part(ulCount, *pcFetched) + ITfDisplayAttributeInfo** rgInfo, + __RPC__out ULONG* pcFetched); + STDMETHODIMP Reset(); + STDMETHODIMP Skip(ULONG ulCount); -private: - LONG _index; // next display attribute to enum - LONG _refCount; // COM ref count + private: + LONG _index; // next display attribute to enum + LONG _refCount; // COM ref count }; diff --git a/WeaselTSF/Globals.cpp b/WeaselTSF/Globals.cpp index d74c3dcc1..c5d28b9a0 100644 --- a/WeaselTSF/Globals.cpp +++ b/WeaselTSF/Globals.cpp @@ -8,34 +8,58 @@ LONG g_cRefDll = -1; CRITICAL_SECTION g_cs; // {A3F4CDED-B1E9-41EE-9CA6-7B4D0DE6CB0A} -static const GUID c_clsidTextService = -{ 0xa3f4cded, 0xb1e9, 0x41ee, { 0x9c, 0xa6, 0x7b, 0x4d, 0xd, 0xe6, 0xcb, 0xa } }; +static const GUID c_clsidTextService = { + 0xa3f4cded, + 0xb1e9, + 0x41ee, + {0x9c, 0xa6, 0x7b, 0x4d, 0xd, 0xe6, 0xcb, 0xa}}; // {3D02CAB6-2B8E-4781-BA20-1C9267529467} -static const GUID c_guidProfile = -{ 0x3d02cab6, 0x2b8e, 0x4781, { 0xba, 0x20, 0x1c, 0x92, 0x67, 0x52, 0x94, 0x67 } }; +static const GUID c_guidProfile = { + 0x3d02cab6, + 0x2b8e, + 0x4781, + {0xba, 0x20, 0x1c, 0x92, 0x67, 0x52, 0x94, 0x67}}; // {341F9E3A-B8AD-499D-936C-48701E329FB2} -static const GUID c_guidLangBarItemButton = -{ 0x341f9e3a, 0xb8ad, 0x499d, { 0x93, 0x6c, 0x48, 0x70, 0x1e, 0x32, 0x9f, 0xb2 } }; +static const GUID c_guidLangBarItemButton = { + 0x341f9e3a, + 0xb8ad, + 0x499d, + {0x93, 0x6c, 0x48, 0x70, 0x1e, 0x32, 0x9f, 0xb2}}; // {2AC87E79-3260-4B32-9DEA-F8390976C20B} -static const GUID c_guidDisplayAttributeInput = -{ 0x2ac87e79, 0x3260, 0x4b32, { 0x9d, 0xea, 0xf8, 0x39, 0x09, 0x76, 0xc2, 0x0b } }; +static const GUID c_guidDisplayAttributeInput = { + 0x2ac87e79, + 0x3260, + 0x4b32, + {0x9d, 0xea, 0xf8, 0x39, 0x09, 0x76, 0xc2, 0x0b}}; #ifdef WEASEL_USING_OLDER_TSF_SDK /* For Windows 8 */ -const GUID GUID_TFCAT_TIPCAP_IMMERSIVESUPPORT = -{ 0x13A016DF, 0x560B, 0x46CD, { 0x94, 0x7A, 0x4C, 0x3A, 0xF1, 0xE0, 0xE3, 0x5D } }; +const GUID GUID_TFCAT_TIPCAP_IMMERSIVESUPPORT = { + 0x13A016DF, + 0x560B, + 0x46CD, + {0x94, 0x7A, 0x4C, 0x3A, 0xF1, 0xE0, 0xE3, 0x5D}}; -const GUID GUID_TFCAT_TIPCAP_SYSTRAYSUPPORT = -{ 0x25504FB4, 0x7BAB, 0x4BC1, { 0x9C, 0x69, 0xCF, 0x81, 0x89, 0x0F, 0x0E, 0xF5 } }; +const GUID GUID_TFCAT_TIPCAP_SYSTRAYSUPPORT = { + 0x25504FB4, + 0x7BAB, + 0x4BC1, + {0x9C, 0x69, 0xCF, 0x81, 0x89, 0x0F, 0x0E, 0xF5}}; #endif -const GUID GUID_LBI_INPUTMODE = -{ 0x2C77A81E, 0x41CC, 0x4178, { 0xA3, 0xA7, 0x5F, 0x8A, 0x98, 0x75, 0x68, 0xE6 } }; +const GUID GUID_LBI_INPUTMODE = { + 0x2C77A81E, + 0x41CC, + 0x4178, + {0xA3, 0xA7, 0x5F, 0x8A, 0x98, 0x75, 0x68, 0xE6}}; -const GUID GUID_IME_MODE_PRESERVED_KEY = -{ 0x0bd899fc, 0xa8f7, 0x4b42, { 0xa9, 0x6d, 0xce, 0xc7, 0xc5, 0x0e, 0x0e, 0xae } }; +const GUID GUID_IME_MODE_PRESERVED_KEY = { + 0x0bd899fc, + 0xa8f7, + 0x4b42, + {0xa9, 0x6d, 0xce, 0xc7, 0xc5, 0x0e, 0x0e, 0xae}}; diff --git a/WeaselTSF/Globals.h b/WeaselTSF/Globals.h index 135a3e240..6fc94a476 100644 --- a/WeaselTSF/Globals.h +++ b/WeaselTSF/Globals.h @@ -5,16 +5,16 @@ #include #ifdef WEASEL_HANT -#define TEXTSERVICE_LANGID MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL) +#define TEXTSERVICE_LANGID MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL) #else -#define TEXTSERVICE_LANGID MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED) +#define TEXTSERVICE_LANGID MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED) #endif -#define TEXTSERVICE_DESC WEASEL_IME_NAME -#define TEXTSERVICE_DESC_A "Weasel" -#define TEXTSERVICE_MODEL "Apartment" +#define TEXTSERVICE_DESC WEASEL_IME_NAME +#define TEXTSERVICE_DESC_A "Weasel" +#define TEXTSERVICE_MODEL "Apartment" -#define TEXTSERVICE_ICON_INDEX 0 +#define TEXTSERVICE_ICON_INDEX 0 void DllAddRef(); void DllRelease(); @@ -38,9 +38,9 @@ extern const GUID c_guidDisplayAttributeInput; #define WEASEL_USING_OLDER_TSF_SDK /* for Windows 8 */ -#define TF_TMF_IMMERSIVEMODE 0x40000000 -#define TF_IPP_CAPS_IMMERSIVESUPPORT 0x00010000 -#define TF_IPP_CAPS_SYSTRAYSUPPORT 0x00020000 +#define TF_TMF_IMMERSIVEMODE 0x40000000 +#define TF_IPP_CAPS_IMMERSIVESUPPORT 0x00010000 +#define TF_IPP_CAPS_SYSTRAYSUPPORT 0x00020000 extern const GUID GUID_TFCAT_TIPCAP_IMMERSIVESUPPORT; extern const GUID GUID_TFCAT_TIPCAP_SYSTRAYSUPPORT; @@ -49,4 +49,3 @@ extern const GUID GUID_TFCAT_TIPCAP_SYSTRAYSUPPORT; extern const GUID GUID_LBI_INPUTMODE; extern const GUID GUID_IME_MODE_PRESERVED_KEY; - diff --git a/WeaselTSF/KeyEvent.cpp b/WeaselTSF/KeyEvent.cpp index 56daa7d27..fb183aa34 100644 --- a/WeaselTSF/KeyEvent.cpp +++ b/WeaselTSF/KeyEvent.cpp @@ -1,204 +1,274 @@ #include "stdafx.h" #include "KeyEvent.h" +bool ConvertKeyEvent(UINT vkey, + KeyInfo kinfo, + const LPBYTE keyState, + weasel::KeyEvent& result) { + const BYTE KEY_DOWN = 0x80; + const BYTE TOGGLED = 0x01; + ibus::Keycode TranslateKeycode(UINT vkey, KeyInfo kinfo); -bool ConvertKeyEvent(UINT vkey, KeyInfo kinfo, const LPBYTE keyState, weasel::KeyEvent& result) -{ - const BYTE KEY_DOWN = 0x80; - const BYTE TOGGLED = 0x01; - ibus::Keycode TranslateKeycode(UINT vkey, KeyInfo kinfo); - - // set mask - result.mask = ibus::NULL_MASK; - - if ((keyState[VK_SHIFT] & KEY_DOWN) != 0) - result.mask |= ibus::SHIFT_MASK; - - if ((keyState[VK_CAPITAL] & TOGGLED) != 0) - result.mask |= ibus::LOCK_MASK; - - if ((keyState[VK_CONTROL] & KEY_DOWN) != 0) - result.mask |= ibus::CONTROL_MASK; - - if ((keyState[VK_MENU] & KEY_DOWN) != 0) - result.mask |= ibus::ALT_MASK; - - if (kinfo.isKeyUp) - result.mask |= ibus::RELEASE_MASK; - - if (vkey == VK_CAPITAL && !kinfo.isKeyUp) - { - // NOTE: rime assumes XK_Caps_Lock to be sent before modifier changes, - // while VK_CAPITAL has the modifier changed already. - // so it is necessary to revert LOCK_MASK. - result.mask ^= ibus::LOCK_MASK; - } - - // set keycode - ibus::Keycode code = TranslateKeycode(vkey, kinfo); - if (code) - { - result.keycode = code; - return true; - } - - const int buf_len = 8; - static WCHAR buf[buf_len]; - static BYTE table[256]; - // 清除Ctrl、Alt鍵狀態,以令ToUnicodeEx()返回字符 - memcpy(table, keyState, sizeof(table)); - table[VK_CONTROL] = 0; - table[VK_MENU] = 0; - int ret = ToUnicodeEx(vkey, UINT(kinfo), table, buf, buf_len, 0, NULL); - if (ret == 1) - { - result.keycode = UINT(buf[0]); - return true; - } - - result.keycode = 0; - return false; + // set mask + result.mask = ibus::NULL_MASK; + + if ((keyState[VK_SHIFT] & KEY_DOWN) != 0) + result.mask |= ibus::SHIFT_MASK; + + if ((keyState[VK_CAPITAL] & TOGGLED) != 0) + result.mask |= ibus::LOCK_MASK; + + if ((keyState[VK_CONTROL] & KEY_DOWN) != 0) + result.mask |= ibus::CONTROL_MASK; + + if ((keyState[VK_MENU] & KEY_DOWN) != 0) + result.mask |= ibus::ALT_MASK; + + if (kinfo.isKeyUp) + result.mask |= ibus::RELEASE_MASK; + + if (vkey == VK_CAPITAL && !kinfo.isKeyUp) { + // NOTE: rime assumes XK_Caps_Lock to be sent before modifier changes, + // while VK_CAPITAL has the modifier changed already. + // so it is necessary to revert LOCK_MASK. + result.mask ^= ibus::LOCK_MASK; + } + + // set keycode + ibus::Keycode code = TranslateKeycode(vkey, kinfo); + if (code) { + result.keycode = code; + return true; + } + + const int buf_len = 8; + static WCHAR buf[buf_len]; + static BYTE table[256]; + // 清除Ctrl、Alt鍵狀態,以令ToUnicodeEx()返回字符 + memcpy(table, keyState, sizeof(table)); + table[VK_CONTROL] = 0; + table[VK_MENU] = 0; + int ret = ToUnicodeEx(vkey, UINT(kinfo), table, buf, buf_len, 0, NULL); + if (ret == 1) { + result.keycode = UINT(buf[0]); + return true; + } + + result.keycode = 0; + return false; } -ibus::Keycode TranslateKeycode(UINT vkey, KeyInfo kinfo) -{ - switch (vkey) - { - case VK_BACK: return ibus::BackSpace; - case VK_TAB: return ibus::Tab; - case VK_CLEAR: return ibus::Clear; - case VK_RETURN: - { - if (kinfo.isExtended == 1) - return ibus::KP_Enter; - else - return ibus::Return; - } - case VK_SHIFT: - { - if (kinfo.scanCode == 0x36) - return ibus::Shift_R; - else - return ibus::Shift_L; - } - case VK_CONTROL: - { - if (kinfo.isExtended == 1) - return ibus::Control_R; - else - return ibus::Control_L; - } - case VK_MENU: return ibus::Alt_L; - case VK_PAUSE: return ibus::Pause; - case VK_CAPITAL: return ibus::Caps_Lock; - - case VK_KANA: return ibus::Hiragana_Katakana; - //case VK_JUNJA: return 0; - //case VK_FINAL: return 0; - case VK_KANJI: return ibus::Kanji; - - case VK_ESCAPE: return ibus::Escape; - - case VK_CONVERT: return ibus::Henkan; - case VK_NONCONVERT: return ibus::Muhenkan; - //case VK_ACCEPT: return 0; - //case VK_MODECHANGE: return 0; - - case VK_SPACE: return ibus::space; - case VK_PRIOR: return ibus::Prior; - case VK_NEXT: return ibus::Next; - case VK_END: return ibus::End; - case VK_HOME: return ibus::Home; - case VK_LEFT: return ibus::Left; - case VK_UP: return ibus::Up; - case VK_RIGHT: return ibus::Right; - case VK_DOWN: return ibus::Down; - case VK_SELECT: return ibus::Select; - case VK_PRINT: return ibus::Print; - case VK_EXECUTE: return ibus::Execute; - //case VK_SNAPSHOT: return 0; - case VK_INSERT: return ibus::Insert; - case VK_DELETE: return ibus::Delete; - case VK_HELP: return ibus::Help; - - case VK_LWIN: return ibus::Meta_L; - case VK_RWIN: return ibus::Meta_R; - //case VK_APPS: return 0; - //case VK_SLEEP: return 0; - case VK_NUMPAD0: return ibus::KP_0; - case VK_NUMPAD1: return ibus::KP_1; - case VK_NUMPAD2: return ibus::KP_2; - case VK_NUMPAD3: return ibus::KP_3; - case VK_NUMPAD4: return ibus::KP_4; - case VK_NUMPAD5: return ibus::KP_5; - case VK_NUMPAD6: return ibus::KP_6; - case VK_NUMPAD7: return ibus::KP_7; - case VK_NUMPAD8: return ibus::KP_8; - case VK_NUMPAD9: return ibus::KP_9; - case VK_MULTIPLY: return ibus::KP_Multiply; - case VK_ADD: return ibus::KP_Add; - case VK_SEPARATOR: return ibus::KP_Separator; - case VK_SUBTRACT: return ibus::KP_Subtract; - case VK_DECIMAL: return ibus::KP_Decimal; - case VK_DIVIDE: return ibus::KP_Divide; - case VK_F1: return ibus::F1; - case VK_F2: return ibus::F2; - case VK_F3: return ibus::F3; - case VK_F4: return ibus::F4; - case VK_F5: return ibus::F5; - case VK_F6: return ibus::F6; - case VK_F7: return ibus::F7; - case VK_F8: return ibus::F8; - case VK_F9: return ibus::F9; - case VK_F10: return ibus::F10; - case VK_F11: return ibus::F11; - case VK_F12: return ibus::F12; - case VK_F13: return ibus::F13; - case VK_F14: return ibus::F14; - case VK_F15: return ibus::F15; - case VK_F16: return ibus::F16; - case VK_F17: return ibus::F17; - case VK_F18: return ibus::F18; - case VK_F19: return ibus::F19; - case VK_F20: return ibus::F20; - case VK_F21: return ibus::F21; - case VK_F22: return ibus::F22; - case VK_F23: return ibus::F23; - case VK_F24: return ibus::F24; - - case VK_NUMLOCK: return ibus::Num_Lock; - case VK_SCROLL: return ibus::Scroll_Lock; - - case VK_LSHIFT: return ibus::Shift_L; - case VK_RSHIFT: return ibus::Shift_R; - case VK_LCONTROL: return ibus::Control_L; - case VK_RCONTROL: return ibus::Control_R; - case VK_LMENU: return ibus::Alt_L; - case VK_RMENU: return ibus::Alt_R; - - case VK_OEM_AUTO: return ibus::Zenkaku_Hankaku; - case VK_OEM_ENLW: return ibus::Zenkaku_Hankaku; - - } - return ibus::Null; +ibus::Keycode TranslateKeycode(UINT vkey, KeyInfo kinfo) { + switch (vkey) { + case VK_BACK: + return ibus::BackSpace; + case VK_TAB: + return ibus::Tab; + case VK_CLEAR: + return ibus::Clear; + case VK_RETURN: { + if (kinfo.isExtended == 1) + return ibus::KP_Enter; + else + return ibus::Return; + } + case VK_SHIFT: { + if (kinfo.scanCode == 0x36) + return ibus::Shift_R; + else + return ibus::Shift_L; + } + case VK_CONTROL: { + if (kinfo.isExtended == 1) + return ibus::Control_R; + else + return ibus::Control_L; + } + case VK_MENU: + return ibus::Alt_L; + case VK_PAUSE: + return ibus::Pause; + case VK_CAPITAL: + return ibus::Caps_Lock; + + case VK_KANA: + return ibus::Hiragana_Katakana; + // case VK_JUNJA: return 0; + // case VK_FINAL: return 0; + case VK_KANJI: + return ibus::Kanji; + + case VK_ESCAPE: + return ibus::Escape; + + case VK_CONVERT: + return ibus::Henkan; + case VK_NONCONVERT: + return ibus::Muhenkan; + // case VK_ACCEPT: return 0; + // case VK_MODECHANGE: return 0; + + case VK_SPACE: + return ibus::space; + case VK_PRIOR: + return ibus::Prior; + case VK_NEXT: + return ibus::Next; + case VK_END: + return ibus::End; + case VK_HOME: + return ibus::Home; + case VK_LEFT: + return ibus::Left; + case VK_UP: + return ibus::Up; + case VK_RIGHT: + return ibus::Right; + case VK_DOWN: + return ibus::Down; + case VK_SELECT: + return ibus::Select; + case VK_PRINT: + return ibus::Print; + case VK_EXECUTE: + return ibus::Execute; + // case VK_SNAPSHOT: return 0; + case VK_INSERT: + return ibus::Insert; + case VK_DELETE: + return ibus::Delete; + case VK_HELP: + return ibus::Help; + + case VK_LWIN: + return ibus::Meta_L; + case VK_RWIN: + return ibus::Meta_R; + // case VK_APPS: return 0; + // case VK_SLEEP: return 0; + case VK_NUMPAD0: + return ibus::KP_0; + case VK_NUMPAD1: + return ibus::KP_1; + case VK_NUMPAD2: + return ibus::KP_2; + case VK_NUMPAD3: + return ibus::KP_3; + case VK_NUMPAD4: + return ibus::KP_4; + case VK_NUMPAD5: + return ibus::KP_5; + case VK_NUMPAD6: + return ibus::KP_6; + case VK_NUMPAD7: + return ibus::KP_7; + case VK_NUMPAD8: + return ibus::KP_8; + case VK_NUMPAD9: + return ibus::KP_9; + case VK_MULTIPLY: + return ibus::KP_Multiply; + case VK_ADD: + return ibus::KP_Add; + case VK_SEPARATOR: + return ibus::KP_Separator; + case VK_SUBTRACT: + return ibus::KP_Subtract; + case VK_DECIMAL: + return ibus::KP_Decimal; + case VK_DIVIDE: + return ibus::KP_Divide; + case VK_F1: + return ibus::F1; + case VK_F2: + return ibus::F2; + case VK_F3: + return ibus::F3; + case VK_F4: + return ibus::F4; + case VK_F5: + return ibus::F5; + case VK_F6: + return ibus::F6; + case VK_F7: + return ibus::F7; + case VK_F8: + return ibus::F8; + case VK_F9: + return ibus::F9; + case VK_F10: + return ibus::F10; + case VK_F11: + return ibus::F11; + case VK_F12: + return ibus::F12; + case VK_F13: + return ibus::F13; + case VK_F14: + return ibus::F14; + case VK_F15: + return ibus::F15; + case VK_F16: + return ibus::F16; + case VK_F17: + return ibus::F17; + case VK_F18: + return ibus::F18; + case VK_F19: + return ibus::F19; + case VK_F20: + return ibus::F20; + case VK_F21: + return ibus::F21; + case VK_F22: + return ibus::F22; + case VK_F23: + return ibus::F23; + case VK_F24: + return ibus::F24; + + case VK_NUMLOCK: + return ibus::Num_Lock; + case VK_SCROLL: + return ibus::Scroll_Lock; + + case VK_LSHIFT: + return ibus::Shift_L; + case VK_RSHIFT: + return ibus::Shift_R; + case VK_LCONTROL: + return ibus::Control_L; + case VK_RCONTROL: + return ibus::Control_R; + case VK_LMENU: + return ibus::Alt_L; + case VK_RMENU: + return ibus::Alt_R; + + case VK_OEM_AUTO: + return ibus::Zenkaku_Hankaku; + case VK_OEM_ENLW: + return ibus::Zenkaku_Hankaku; + } + return ibus::Null; } /* struct ModifierNameTableEntry { - LPCTSTR name; - ibus::Modifier modifier; + LPCTSTR name; + ibus::Modifier modifier; }; ModifierNameTableEntry MODIFIER_NAME_TABLE[] = { - { L"Shift", ibus::SHIFT_MASK }, - { L"CapsLock", ibus::LOCK_MASK }, - { L"Ctrl", ibus::CONTROL_MASK }, - { L"Alt", ibus::MOD1_MASK }, - { L"SUPER", ibus::SUPER_MASK }, - { L"Hyper", ibus::HYPER_MASK }, - { L"Meta", ibus::META_MASK }, - { L"Release", ibus::RELEASE_MASK }, - { NULL, ibus::NULL_MASK } + { L"Shift", ibus::SHIFT_MASK }, + { L"CapsLock", ibus::LOCK_MASK }, + { L"Ctrl", ibus::CONTROL_MASK }, + { L"Alt", ibus::MOD1_MASK }, + { L"SUPER", ibus::SUPER_MASK }, + { L"Hyper", ibus::HYPER_MASK }, + { L"Meta", ibus::META_MASK }, + { L"Release", ibus::RELEASE_MASK }, + { NULL, ibus::NULL_MASK } }; */ diff --git a/WeaselTSF/KeyEvent.h b/WeaselTSF/KeyEvent.h index e942b2da1..bcef60c71 100644 --- a/WeaselTSF/KeyEvent.h +++ b/WeaselTSF/KeyEvent.h @@ -1,240 +1,232 @@ #pragma once #include -struct KeyInfo -{ - UINT repeatCount: 16; - UINT scanCode: 8; - UINT isExtended: 1; - UINT reserved: 4; - UINT contextCode: 1; - UINT prevKeyState: 1; - UINT isKeyUp: 1; +struct KeyInfo { + UINT repeatCount : 16; + UINT scanCode : 8; + UINT isExtended : 1; + UINT reserved : 4; + UINT contextCode : 1; + UINT prevKeyState : 1; + UINT isKeyUp : 1; - KeyInfo(LPARAM lparam) - { - *this = *reinterpret_cast(&lparam); - } + KeyInfo(LPARAM lparam) { *this = *reinterpret_cast(&lparam); } - operator UINT32() - { - return *reinterpret_cast(this); - } + operator UINT32() { return *reinterpret_cast(this); } }; -bool ConvertKeyEvent(UINT vkey, KeyInfo kinfo, const LPBYTE keyState, weasel::KeyEvent& result); +bool ConvertKeyEvent(UINT vkey, + KeyInfo kinfo, + const LPBYTE keyState, + weasel::KeyEvent& result); +namespace ibus { +// keycodes -namespace ibus -{ - // keycodes - - enum Keycode - { - VoidSymbol = 0xFFFFFF, - space = 0x020, - grave = 0x060, - BackSpace = 0xFF08, - Tab = 0xFF09, - Linefeed = 0xFF0A, - Clear = 0xFF0B, - Return = 0xFF0D, - Pause = 0xFF13, - Scroll_Lock = 0xFF14, - Sys_Req = 0xFF15, - Escape = 0xFF1B, - Delete = 0xFFFF, - Multi_key = 0xFF20, - Codeinput = 0xFF37, - SingleCandidate = 0xFF3C, - MultipleCandidate = 0xFF3D, - PreviousCandidate = 0xFF3E, - Kanji = 0xFF21, - Muhenkan = 0xFF22, - Henkan_Mode = 0xFF23, - Henkan = 0xFF23, - Romaji = 0xFF24, - Hiragana = 0xFF25, - Katakana = 0xFF26, - Hiragana_Katakana = 0xFF27, - Zenkaku = 0xFF28, - Hankaku = 0xFF29, - Zenkaku_Hankaku = 0xFF2A, - Touroku = 0xFF2B, - Massyo = 0xFF2C, - Kana_Lock = 0xFF2D, - Kana_Shift = 0xFF2E, - Eisu_Shift = 0xFF2F, - Eisu_toggle = 0xFF30, - Kanji_Bangou = 0xFF37, - Zen_Koho = 0xFF3D, - Mae_Koho = 0xFF3E, - Home = 0xFF50, - Left = 0xFF51, - Up = 0xFF52, - Right = 0xFF53, - Down = 0xFF54, - Prior = 0xFF55, - Page_Up = 0xFF55, - Next = 0xFF56, - Page_Down = 0xFF56, - End = 0xFF57, - Begin = 0xFF58, - Select = 0xFF60, - Print = 0xFF61, - Execute = 0xFF62, - Insert = 0xFF63, - Undo = 0xFF65, - Redo = 0xFF66, - Menu = 0xFF67, - Find = 0xFF68, - Cancel = 0xFF69, - Help = 0xFF6A, - Break = 0xFF6B, - Mode_switch = 0xFF7E, - script_switch = 0xFF7E, - Num_Lock = 0xFF7F, - KP_Space = 0xFF80, - KP_Tab = 0xFF89, - KP_Enter = 0xFF8D, - KP_F1 = 0xFF91, - KP_F2 = 0xFF92, - KP_F3 = 0xFF93, - KP_F4 = 0xFF94, - KP_Home = 0xFF95, - KP_Left = 0xFF96, - KP_Up = 0xFF97, - KP_Right = 0xFF98, - KP_Down = 0xFF99, - KP_Prior = 0xFF9A, - KP_Page_Up = 0xFF9A, - KP_Next = 0xFF9B, - KP_Page_Down = 0xFF9B, - KP_End = 0xFF9C, - KP_Begin = 0xFF9D, - KP_Insert = 0xFF9E, - KP_Delete = 0xFF9F, - KP_Equal = 0xFFBD, - KP_Multiply = 0xFFAA, - KP_Add = 0xFFAB, - KP_Separator = 0xFFAC, - KP_Subtract = 0xFFAD, - KP_Decimal = 0xFFAE, - KP_Divide = 0xFFAF, - KP_0 = 0xFFB0, - KP_1 = 0xFFB1, - KP_2 = 0xFFB2, - KP_3 = 0xFFB3, - KP_4 = 0xFFB4, - KP_5 = 0xFFB5, - KP_6 = 0xFFB6, - KP_7 = 0xFFB7, - KP_8 = 0xFFB8, - KP_9 = 0xFFB9, - F1 = 0xFFBE, - F2 = 0xFFBF, - F3 = 0xFFC0, - F4 = 0xFFC1, - F5 = 0xFFC2, - F6 = 0xFFC3, - F7 = 0xFFC4, - F8 = 0xFFC5, - F9 = 0xFFC6, - F10 = 0xFFC7, - F11 = 0xFFC8, - L1 = 0xFFC8, - F12 = 0xFFC9, - L2 = 0xFFC9, - F13 = 0xFFCA, - L3 = 0xFFCA, - F14 = 0xFFCB, - L4 = 0xFFCB, - F15 = 0xFFCC, - L5 = 0xFFCC, - F16 = 0xFFCD, - L6 = 0xFFCD, - F17 = 0xFFCE, - L7 = 0xFFCE, - F18 = 0xFFCF, - L8 = 0xFFCF, - F19 = 0xFFD0, - L9 = 0xFFD0, - F20 = 0xFFD1, - L10 = 0xFFD1, - F21 = 0xFFD2, - R1 = 0xFFD2, - F22 = 0xFFD3, - R2 = 0xFFD3, - F23 = 0xFFD4, - R3 = 0xFFD4, - F24 = 0xFFD5, - R4 = 0xFFD5, - F25 = 0xFFD6, - R5 = 0xFFD6, - F26 = 0xFFD7, - R6 = 0xFFD7, - F27 = 0xFFD8, - R7 = 0xFFD8, - F28 = 0xFFD9, - R8 = 0xFFD9, - F29 = 0xFFDA, - R9 = 0xFFDA, - F30 = 0xFFDB, - R10 = 0xFFDB, - F31 = 0xFFDC, - R11 = 0xFFDC, - F32 = 0xFFDD, - R12 = 0xFFDD, - F33 = 0xFFDE, - R13 = 0xFFDE, - F34 = 0xFFDF, - R14 = 0xFFDF, - F35 = 0xFFE0, - R15 = 0xFFE0, - Shift_L = 0xFFE1, - Shift_R = 0xFFE2, - Control_L = 0xFFE3, - Control_R = 0xFFE4, - Caps_Lock = 0xFFE5, - Shift_Lock = 0xFFE6, - Meta_L = 0xFFE7, - Meta_R = 0xFFE8, - Alt_L = 0xFFE9, - Alt_R = 0xFFEA, - Super_L = 0xFFEB, - Super_R = 0xFFEC, - Hyper_L = 0xFFED, - Hyper_R = 0xFFEE, - Null = 0 - }; +enum Keycode { + VoidSymbol = 0xFFFFFF, + space = 0x020, + grave = 0x060, + BackSpace = 0xFF08, + Tab = 0xFF09, + Linefeed = 0xFF0A, + Clear = 0xFF0B, + Return = 0xFF0D, + Pause = 0xFF13, + Scroll_Lock = 0xFF14, + Sys_Req = 0xFF15, + Escape = 0xFF1B, + Delete = 0xFFFF, + Multi_key = 0xFF20, + Codeinput = 0xFF37, + SingleCandidate = 0xFF3C, + MultipleCandidate = 0xFF3D, + PreviousCandidate = 0xFF3E, + Kanji = 0xFF21, + Muhenkan = 0xFF22, + Henkan_Mode = 0xFF23, + Henkan = 0xFF23, + Romaji = 0xFF24, + Hiragana = 0xFF25, + Katakana = 0xFF26, + Hiragana_Katakana = 0xFF27, + Zenkaku = 0xFF28, + Hankaku = 0xFF29, + Zenkaku_Hankaku = 0xFF2A, + Touroku = 0xFF2B, + Massyo = 0xFF2C, + Kana_Lock = 0xFF2D, + Kana_Shift = 0xFF2E, + Eisu_Shift = 0xFF2F, + Eisu_toggle = 0xFF30, + Kanji_Bangou = 0xFF37, + Zen_Koho = 0xFF3D, + Mae_Koho = 0xFF3E, + Home = 0xFF50, + Left = 0xFF51, + Up = 0xFF52, + Right = 0xFF53, + Down = 0xFF54, + Prior = 0xFF55, + Page_Up = 0xFF55, + Next = 0xFF56, + Page_Down = 0xFF56, + End = 0xFF57, + Begin = 0xFF58, + Select = 0xFF60, + Print = 0xFF61, + Execute = 0xFF62, + Insert = 0xFF63, + Undo = 0xFF65, + Redo = 0xFF66, + Menu = 0xFF67, + Find = 0xFF68, + Cancel = 0xFF69, + Help = 0xFF6A, + Break = 0xFF6B, + Mode_switch = 0xFF7E, + script_switch = 0xFF7E, + Num_Lock = 0xFF7F, + KP_Space = 0xFF80, + KP_Tab = 0xFF89, + KP_Enter = 0xFF8D, + KP_F1 = 0xFF91, + KP_F2 = 0xFF92, + KP_F3 = 0xFF93, + KP_F4 = 0xFF94, + KP_Home = 0xFF95, + KP_Left = 0xFF96, + KP_Up = 0xFF97, + KP_Right = 0xFF98, + KP_Down = 0xFF99, + KP_Prior = 0xFF9A, + KP_Page_Up = 0xFF9A, + KP_Next = 0xFF9B, + KP_Page_Down = 0xFF9B, + KP_End = 0xFF9C, + KP_Begin = 0xFF9D, + KP_Insert = 0xFF9E, + KP_Delete = 0xFF9F, + KP_Equal = 0xFFBD, + KP_Multiply = 0xFFAA, + KP_Add = 0xFFAB, + KP_Separator = 0xFFAC, + KP_Subtract = 0xFFAD, + KP_Decimal = 0xFFAE, + KP_Divide = 0xFFAF, + KP_0 = 0xFFB0, + KP_1 = 0xFFB1, + KP_2 = 0xFFB2, + KP_3 = 0xFFB3, + KP_4 = 0xFFB4, + KP_5 = 0xFFB5, + KP_6 = 0xFFB6, + KP_7 = 0xFFB7, + KP_8 = 0xFFB8, + KP_9 = 0xFFB9, + F1 = 0xFFBE, + F2 = 0xFFBF, + F3 = 0xFFC0, + F4 = 0xFFC1, + F5 = 0xFFC2, + F6 = 0xFFC3, + F7 = 0xFFC4, + F8 = 0xFFC5, + F9 = 0xFFC6, + F10 = 0xFFC7, + F11 = 0xFFC8, + L1 = 0xFFC8, + F12 = 0xFFC9, + L2 = 0xFFC9, + F13 = 0xFFCA, + L3 = 0xFFCA, + F14 = 0xFFCB, + L4 = 0xFFCB, + F15 = 0xFFCC, + L5 = 0xFFCC, + F16 = 0xFFCD, + L6 = 0xFFCD, + F17 = 0xFFCE, + L7 = 0xFFCE, + F18 = 0xFFCF, + L8 = 0xFFCF, + F19 = 0xFFD0, + L9 = 0xFFD0, + F20 = 0xFFD1, + L10 = 0xFFD1, + F21 = 0xFFD2, + R1 = 0xFFD2, + F22 = 0xFFD3, + R2 = 0xFFD3, + F23 = 0xFFD4, + R3 = 0xFFD4, + F24 = 0xFFD5, + R4 = 0xFFD5, + F25 = 0xFFD6, + R5 = 0xFFD6, + F26 = 0xFFD7, + R6 = 0xFFD7, + F27 = 0xFFD8, + R7 = 0xFFD8, + F28 = 0xFFD9, + R8 = 0xFFD9, + F29 = 0xFFDA, + R9 = 0xFFDA, + F30 = 0xFFDB, + R10 = 0xFFDB, + F31 = 0xFFDC, + R11 = 0xFFDC, + F32 = 0xFFDD, + R12 = 0xFFDD, + F33 = 0xFFDE, + R13 = 0xFFDE, + F34 = 0xFFDF, + R14 = 0xFFDF, + F35 = 0xFFE0, + R15 = 0xFFE0, + Shift_L = 0xFFE1, + Shift_R = 0xFFE2, + Control_L = 0xFFE3, + Control_R = 0xFFE4, + Caps_Lock = 0xFFE5, + Shift_Lock = 0xFFE6, + Meta_L = 0xFFE7, + Meta_R = 0xFFE8, + Alt_L = 0xFFE9, + Alt_R = 0xFFEA, + Super_L = 0xFFEB, + Super_R = 0xFFEC, + Hyper_L = 0xFFED, + Hyper_R = 0xFFEE, + Null = 0 +}; - // modifiers, modified to fit a UINT16 +// modifiers, modified to fit a UINT16 - enum Modifier - { - NULL_MASK = 0, +enum Modifier { + NULL_MASK = 0, - SHIFT_MASK = 1 << 0, - LOCK_MASK = 1 << 1, - CONTROL_MASK = 1 << 2, - ALT_MASK = 1 << 3, - MOD1_MASK = 1 << 3, - MOD2_MASK = 1 << 4, - MOD3_MASK = 1 << 5, - MOD4_MASK = 1 << 6, - MOD5_MASK = 1 << 7, + SHIFT_MASK = 1 << 0, + LOCK_MASK = 1 << 1, + CONTROL_MASK = 1 << 2, + ALT_MASK = 1 << 3, + MOD1_MASK = 1 << 3, + MOD2_MASK = 1 << 4, + MOD3_MASK = 1 << 5, + MOD4_MASK = 1 << 6, + MOD5_MASK = 1 << 7, - HANDLED_MASK = 1 << 8, // 24 - IGNORED_MASK = 1 << 9, // 25 - FORWARD_MASK = 1 << 9, // 25 + HANDLED_MASK = 1 << 8, // 24 + IGNORED_MASK = 1 << 9, // 25 + FORWARD_MASK = 1 << 9, // 25 - SUPER_MASK = 1 << 10, // 26 - HYPER_MASK = 1 << 11, // 27 - META_MASK = 1 << 12, // 28 + SUPER_MASK = 1 << 10, // 26 + HYPER_MASK = 1 << 11, // 27 + META_MASK = 1 << 12, // 28 - RELEASE_MASK = 1 << 14, // 30 + RELEASE_MASK = 1 << 14, // 30 - MODIFIER_MASK = 0x2fff - }; + MODIFIER_MASK = 0x2fff +}; -} +} // namespace ibus diff --git a/WeaselTSF/KeyEventSink.cpp b/WeaselTSF/KeyEventSink.cpp index c141a66ac..a9ac24b06 100644 --- a/WeaselTSF/KeyEventSink.cpp +++ b/WeaselTSF/KeyEventSink.cpp @@ -4,148 +4,142 @@ #include "KeyEvent.h" #include "CandidateList.h" -void WeaselTSF::_ProcessKeyEvent(WPARAM wParam, LPARAM lParam, BOOL *pfEaten) -{ - if (!_IsKeyboardOpen()) - return; - - _EnsureServerConnected(); - weasel::KeyEvent ke; - GetKeyboardState(_lpbKeyState); - if (!ConvertKeyEvent(wParam, lParam, _lpbKeyState, ke)) - { - /* Unknown key event */ - *pfEaten = FALSE; - } - else - { - // cheet key code when vertical auto reverse happened, swap up and down - if(_cand->GetIsReposition()) - { - if(ke.keycode == ibus::Up) - ke.keycode = ibus::Down; - else if(ke.keycode == ibus::Down) - ke.keycode = ibus::Up; - } - *pfEaten = (BOOL) m_client.ProcessKeyEvent(ke); +void WeaselTSF::_ProcessKeyEvent(WPARAM wParam, LPARAM lParam, BOOL* pfEaten) { + if (!_IsKeyboardOpen()) + return; + + _EnsureServerConnected(); + weasel::KeyEvent ke; + GetKeyboardState(_lpbKeyState); + if (!ConvertKeyEvent(wParam, lParam, _lpbKeyState, ke)) { + /* Unknown key event */ + *pfEaten = FALSE; + } else { + // cheet key code when vertical auto reverse happened, swap up and down + if (_cand->GetIsReposition()) { + if (ke.keycode == ibus::Up) + ke.keycode = ibus::Down; + else if (ke.keycode == ibus::Down) + ke.keycode = ibus::Up; } + *pfEaten = (BOOL)m_client.ProcessKeyEvent(ke); + } } -STDAPI WeaselTSF::OnSetFocus(BOOL fForeground) -{ - if (fForeground) - m_client.FocusIn(); - else { - m_client.FocusOut(); - _AbortComposition(); - } +STDAPI WeaselTSF::OnSetFocus(BOOL fForeground) { + if (fForeground) + m_client.FocusIn(); + else { + m_client.FocusOut(); + _AbortComposition(); + } - return S_OK; + return S_OK; } /* Some apps sends strange OnTestKeyDown/OnKeyDown combinations: * Some sends OnKeyDown() only. (QQ2012) - * Some sends multiple OnTestKeyDown() for a single key event. (MS WORD 2010 x64) + * Some sends multiple OnTestKeyDown() for a single key event. (MS WORD 2010 + * x64) * * We assume every key event will eventually cause a OnKeyDown() call. * We use _fTestKeyDownPending to omit multiple OnTestKeyDown() calls, * and for OnKeyDown() to check if the key has already been sent to the server. */ -STDAPI WeaselTSF::OnTestKeyDown(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten) -{ - _fTestKeyUpPending = FALSE; - if (_fTestKeyDownPending) - { - *pfEaten = TRUE; - return S_OK; - } - _ProcessKeyEvent(wParam, lParam, pfEaten); - _UpdateComposition(pContext); - if (*pfEaten) - _fTestKeyDownPending = TRUE; - return S_OK; +STDAPI WeaselTSF::OnTestKeyDown(ITfContext* pContext, + WPARAM wParam, + LPARAM lParam, + BOOL* pfEaten) { + _fTestKeyUpPending = FALSE; + if (_fTestKeyDownPending) { + *pfEaten = TRUE; + return S_OK; + } + _ProcessKeyEvent(wParam, lParam, pfEaten); + _UpdateComposition(pContext); + if (*pfEaten) + _fTestKeyDownPending = TRUE; + return S_OK; } -STDAPI WeaselTSF::OnKeyDown(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten) -{ - _fTestKeyUpPending = FALSE; - if (_fTestKeyDownPending) - { - _fTestKeyDownPending = FALSE; - *pfEaten = TRUE; - } - else - { - _ProcessKeyEvent(wParam, lParam, pfEaten); - _UpdateComposition(pContext); - } - return S_OK; -} +STDAPI WeaselTSF::OnKeyDown(ITfContext* pContext, + WPARAM wParam, + LPARAM lParam, + BOOL* pfEaten) { + _fTestKeyUpPending = FALSE; + if (_fTestKeyDownPending) { + _fTestKeyDownPending = FALSE; + *pfEaten = TRUE; + } else { + _ProcessKeyEvent(wParam, lParam, pfEaten); + _UpdateComposition(pContext); + } + return S_OK; +} -STDAPI WeaselTSF::OnTestKeyUp(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten) -{ - _fTestKeyDownPending = FALSE; - if (_fTestKeyUpPending) - { - *pfEaten = TRUE; - return S_OK; - } - _ProcessKeyEvent(wParam, lParam, pfEaten); - _UpdateComposition(pContext); - if (*pfEaten) - _fTestKeyUpPending = TRUE; - return S_OK; +STDAPI WeaselTSF::OnTestKeyUp(ITfContext* pContext, + WPARAM wParam, + LPARAM lParam, + BOOL* pfEaten) { + _fTestKeyDownPending = FALSE; + if (_fTestKeyUpPending) { + *pfEaten = TRUE; + return S_OK; + } + _ProcessKeyEvent(wParam, lParam, pfEaten); + _UpdateComposition(pContext); + if (*pfEaten) + _fTestKeyUpPending = TRUE; + return S_OK; } -STDAPI WeaselTSF::OnKeyUp(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten) -{ - _fTestKeyDownPending = FALSE; - if (_fTestKeyUpPending) - { - _fTestKeyUpPending = FALSE; - *pfEaten = TRUE; - } - else - { - _ProcessKeyEvent(wParam, lParam, pfEaten); - _UpdateComposition(pContext); - } - return S_OK; +STDAPI WeaselTSF::OnKeyUp(ITfContext* pContext, + WPARAM wParam, + LPARAM lParam, + BOOL* pfEaten) { + _fTestKeyDownPending = FALSE; + if (_fTestKeyUpPending) { + _fTestKeyUpPending = FALSE; + *pfEaten = TRUE; + } else { + _ProcessKeyEvent(wParam, lParam, pfEaten); + _UpdateComposition(pContext); + } + return S_OK; } -STDAPI WeaselTSF::OnPreservedKey(ITfContext *pContext, REFGUID rguid, BOOL *pfEaten) -{ - *pfEaten = FALSE; - return S_OK; +STDAPI WeaselTSF::OnPreservedKey(ITfContext* pContext, + REFGUID rguid, + BOOL* pfEaten) { + *pfEaten = FALSE; + return S_OK; } -BOOL WeaselTSF::_InitKeyEventSink() -{ - com_ptr pKeystrokeMgr; - HRESULT hr; +BOOL WeaselTSF::_InitKeyEventSink() { + com_ptr pKeystrokeMgr; + HRESULT hr; - if (_pThreadMgr->QueryInterface(&pKeystrokeMgr) != S_OK) - return FALSE; + if (_pThreadMgr->QueryInterface(&pKeystrokeMgr) != S_OK) + return FALSE; - hr = pKeystrokeMgr->AdviseKeyEventSink(_tfClientId, (ITfKeyEventSink *) this, TRUE); - - return (hr == S_OK); + hr = pKeystrokeMgr->AdviseKeyEventSink(_tfClientId, (ITfKeyEventSink*)this, + TRUE); + + return (hr == S_OK); } -void WeaselTSF::_UninitKeyEventSink() -{ - com_ptr pKeystrokeMgr; - - if (_pThreadMgr->QueryInterface(&pKeystrokeMgr) != S_OK) - return; +void WeaselTSF::_UninitKeyEventSink() { + com_ptr pKeystrokeMgr; - pKeystrokeMgr->UnadviseKeyEventSink(_tfClientId); + if (_pThreadMgr->QueryInterface(&pKeystrokeMgr) != S_OK) + return; + + pKeystrokeMgr->UnadviseKeyEventSink(_tfClientId); } -BOOL WeaselTSF::_InitPreservedKey() -{ - return TRUE; +BOOL WeaselTSF::_InitPreservedKey() { + return TRUE; #if 0 com_ptr pKeystrokeMgr; if (_pThreadMgr->QueryInterface(pKeystrokeMgr.GetAddressOf()) != S_OK) @@ -167,6 +161,4 @@ BOOL WeaselTSF::_InitPreservedKey() #endif } -void WeaselTSF::_UninitPreservedKey() -{ -} +void WeaselTSF::_UninitPreservedKey() {} diff --git a/WeaselTSF/LanguageBar.cpp b/WeaselTSF/LanguageBar.cpp index 959362f4a..49c357698 100644 --- a/WeaselTSF/LanguageBar.cpp +++ b/WeaselTSF/LanguageBar.cpp @@ -8,415 +8,371 @@ static const DWORD LANGBARITEMSINK_COOKIE = 0x42424242; -static void HMENU2ITfMenu(HMENU hMenu, ITfMenu *pTfMenu) -{ - /* NOTE: Only limited functions are supported */ - int N = GetMenuItemCount(hMenu); - for (int i = 0; i < N; i++) - { - MENUITEMINFO mii; - mii.cbSize = sizeof(MENUITEMINFO); - mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING; - mii.dwTypeData = NULL; - if (GetMenuItemInfo(hMenu, i, TRUE, &mii)) - { - UINT id = mii.wID; - if (mii.fType == MFT_SEPARATOR) - pTfMenu->AddMenuItem(id, TF_LBMENUF_SEPARATOR, NULL, NULL, NULL, 0, NULL); - else if (mii.fType == MFT_STRING) - { - mii.dwTypeData = (LPWSTR) malloc(sizeof(WCHAR) * (mii.cch + 1)); - mii.cch++; - if (GetMenuItemInfo(hMenu, i, TRUE, &mii)) - pTfMenu->AddMenuItem(id, 0, NULL, NULL, mii.dwTypeData, mii.cch, NULL); - free(mii.dwTypeData); - } - } - } +static void HMENU2ITfMenu(HMENU hMenu, ITfMenu* pTfMenu) { + /* NOTE: Only limited functions are supported */ + int N = GetMenuItemCount(hMenu); + for (int i = 0; i < N; i++) { + MENUITEMINFO mii; + mii.cbSize = sizeof(MENUITEMINFO); + mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING; + mii.dwTypeData = NULL; + if (GetMenuItemInfo(hMenu, i, TRUE, &mii)) { + UINT id = mii.wID; + if (mii.fType == MFT_SEPARATOR) + pTfMenu->AddMenuItem(id, TF_LBMENUF_SEPARATOR, NULL, NULL, NULL, 0, + NULL); + else if (mii.fType == MFT_STRING) { + mii.dwTypeData = (LPWSTR)malloc(sizeof(WCHAR) * (mii.cch + 1)); + mii.cch++; + if (GetMenuItemInfo(hMenu, i, TRUE, &mii)) + pTfMenu->AddMenuItem(id, 0, NULL, NULL, mii.dwTypeData, mii.cch, + NULL); + free(mii.dwTypeData); + } + } + } } -CLangBarItemButton::CLangBarItemButton(com_ptr pTextService, REFGUID guid, weasel::UIStyle& style) - : _status(0), _style(style), _current_schema_zhung_icon(), _current_schema_ascii_icon() -{ - DllAddRef(); - - _pLangBarItemSink = NULL; - _cRef = 1; - _pTextService = pTextService; - _guid = guid; - ascii_mode = false; +CLangBarItemButton::CLangBarItemButton(com_ptr pTextService, + REFGUID guid, + weasel::UIStyle& style) + : _status(0), + _style(style), + _current_schema_zhung_icon(), + _current_schema_ascii_icon() { + DllAddRef(); + + _pLangBarItemSink = NULL; + _cRef = 1; + _pTextService = pTextService; + _guid = guid; + ascii_mode = false; } -CLangBarItemButton::~CLangBarItemButton() -{ - DllRelease(); +CLangBarItemButton::~CLangBarItemButton() { + DllRelease(); } -STDAPI CLangBarItemButton::QueryInterface(REFIID riid, void **ppvObject) -{ - if (ppvObject == NULL) - return E_INVALIDARG; - - *ppvObject = NULL; - if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfLangBarItem) || IsEqualIID(riid, IID_ITfLangBarItemButton)) - *ppvObject = (ITfLangBarItemButton *) this; - else if (IsEqualIID(riid, IID_ITfSource)) - *ppvObject = (ITfSource *) this; - - if (*ppvObject) - { - AddRef(); - return S_OK; - } - return E_NOINTERFACE; +STDAPI CLangBarItemButton::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == NULL) + return E_INVALIDARG; + + *ppvObject = NULL; + if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfLangBarItem) || + IsEqualIID(riid, IID_ITfLangBarItemButton)) + *ppvObject = (ITfLangBarItemButton*)this; + else if (IsEqualIID(riid, IID_ITfSource)) + *ppvObject = (ITfSource*)this; + + if (*ppvObject) { + AddRef(); + return S_OK; + } + return E_NOINTERFACE; } -STDAPI_(ULONG) CLangBarItemButton::AddRef() -{ - return ++_cRef; +STDAPI_(ULONG) CLangBarItemButton::AddRef() { + return ++_cRef; } -STDAPI_(ULONG) CLangBarItemButton::Release() -{ - LONG cr = --_cRef; - assert(_cRef >= 0); - if (_cRef == 0) - delete this; - return cr; +STDAPI_(ULONG) CLangBarItemButton::Release() { + LONG cr = --_cRef; + assert(_cRef >= 0); + if (_cRef == 0) + delete this; + return cr; } -STDAPI CLangBarItemButton::GetInfo(TF_LANGBARITEMINFO *pInfo) -{ - pInfo->clsidService = c_clsidTextService; - pInfo->guidItem = _guid; - pInfo->dwStyle = TF_LBI_STYLE_BTN_BUTTON | TF_LBI_STYLE_BTN_MENU | TF_LBI_STYLE_SHOWNINTRAY; - pInfo->ulSort = 1; - lstrcpyW(pInfo->szDescription, L"WeaselTSF Button"); - return S_OK; +STDAPI CLangBarItemButton::GetInfo(TF_LANGBARITEMINFO* pInfo) { + pInfo->clsidService = c_clsidTextService; + pInfo->guidItem = _guid; + pInfo->dwStyle = TF_LBI_STYLE_BTN_BUTTON | TF_LBI_STYLE_BTN_MENU | + TF_LBI_STYLE_SHOWNINTRAY; + pInfo->ulSort = 1; + lstrcpyW(pInfo->szDescription, L"WeaselTSF Button"); + return S_OK; } -STDAPI CLangBarItemButton::GetStatus(DWORD *pdwStatus) -{ - *pdwStatus = _status; - return S_OK; +STDAPI CLangBarItemButton::GetStatus(DWORD* pdwStatus) { + *pdwStatus = _status; + return S_OK; } -STDAPI CLangBarItemButton::Show(BOOL fShow) -{ - SetLangbarStatus(TF_LBI_STATUS_HIDDEN, fShow ? FALSE : TRUE); - return S_OK; +STDAPI CLangBarItemButton::Show(BOOL fShow) { + SetLangbarStatus(TF_LBI_STATUS_HIDDEN, fShow ? FALSE : TRUE); + return S_OK; } -STDAPI CLangBarItemButton::GetTooltipString(BSTR *pbstrToolTip) -{ +STDAPI CLangBarItemButton::GetTooltipString(BSTR* pbstrToolTip) { #ifdef WEASEL_HANT - *pbstrToolTip = SysAllocString(L"左鍵切換模式,右鍵打開菜單"); + *pbstrToolTip = SysAllocString(L"左鍵切換模式,右鍵打開菜單"); #else - *pbstrToolTip = SysAllocString(L"左键切换模式,右键打开菜单"); + *pbstrToolTip = SysAllocString(L"左键切换模式,右键打开菜单"); #endif - return (*pbstrToolTip == NULL)? E_OUTOFMEMORY: S_OK; + return (*pbstrToolTip == NULL) ? E_OUTOFMEMORY : S_OK; } -STDAPI CLangBarItemButton::OnClick(TfLBIClick click, POINT pt, const RECT *prcArea) -{ - if (click == TF_LBI_CLK_LEFT) - { - _pTextService->_HandleLangBarMenuSelect(ascii_mode ? ID_WEASELTRAY_DISABLE_ASCII : ID_WEASELTRAY_ENABLE_ASCII); - ascii_mode = !ascii_mode; - if (_pLangBarItemSink) { - _pLangBarItemSink->OnUpdate(TF_LBI_STATUS | TF_LBI_ICON); - } - } - else if (click == TF_LBI_CLK_RIGHT) - { - /* Open menu */ - HWND hwnd = _pTextService->_GetFocusedContextWindow(); - if (hwnd != NULL) - { - HMENU menu = LoadMenuW(g_hInst, MAKEINTRESOURCE(IDR_MENU_POPUP)); - HMENU popupMenu = GetSubMenu(menu, 0); - UINT wID = TrackPopupMenuEx(popupMenu, TPM_NONOTIFY | TPM_RETURNCMD | TPM_HORPOSANIMATION, pt.x, pt.y, hwnd, NULL); - DestroyMenu(menu); - _pTextService->_HandleLangBarMenuSelect(wID); - } - } - return S_OK; +STDAPI CLangBarItemButton::OnClick(TfLBIClick click, + POINT pt, + const RECT* prcArea) { + if (click == TF_LBI_CLK_LEFT) { + _pTextService->_HandleLangBarMenuSelect( + ascii_mode ? ID_WEASELTRAY_DISABLE_ASCII : ID_WEASELTRAY_ENABLE_ASCII); + ascii_mode = !ascii_mode; + if (_pLangBarItemSink) { + _pLangBarItemSink->OnUpdate(TF_LBI_STATUS | TF_LBI_ICON); + } + } else if (click == TF_LBI_CLK_RIGHT) { + /* Open menu */ + HWND hwnd = _pTextService->_GetFocusedContextWindow(); + if (hwnd != NULL) { + HMENU menu = LoadMenuW(g_hInst, MAKEINTRESOURCE(IDR_MENU_POPUP)); + HMENU popupMenu = GetSubMenu(menu, 0); + UINT wID = TrackPopupMenuEx( + popupMenu, TPM_NONOTIFY | TPM_RETURNCMD | TPM_HORPOSANIMATION, pt.x, + pt.y, hwnd, NULL); + DestroyMenu(menu); + _pTextService->_HandleLangBarMenuSelect(wID); + } + } + return S_OK; } -STDAPI CLangBarItemButton::InitMenu(ITfMenu *pMenu) -{ - HMENU menu = LoadMenuW(g_hInst, MAKEINTRESOURCE(IDR_MENU_POPUP)); - HMENU popupMenu = GetSubMenu(menu, 0); - HMENU2ITfMenu(popupMenu, pMenu); - DestroyMenu(menu); - return S_OK; +STDAPI CLangBarItemButton::InitMenu(ITfMenu* pMenu) { + HMENU menu = LoadMenuW(g_hInst, MAKEINTRESOURCE(IDR_MENU_POPUP)); + HMENU popupMenu = GetSubMenu(menu, 0); + HMENU2ITfMenu(popupMenu, pMenu); + DestroyMenu(menu); + return S_OK; } -STDAPI CLangBarItemButton::OnMenuSelect(UINT wID) -{ - _pTextService->_HandleLangBarMenuSelect(wID); - return S_OK; +STDAPI CLangBarItemButton::OnMenuSelect(UINT wID) { + _pTextService->_HandleLangBarMenuSelect(wID); + return S_OK; } -STDAPI CLangBarItemButton::GetIcon(HICON *phIcon) -{ - if (ascii_mode) - { - if(_style.current_ascii_icon.empty()) - *phIcon = (HICON)LoadImageW( - g_hInst, - MAKEINTRESOURCEW(IDI_EN), - IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), - LR_SHARED); - else - *phIcon = (HICON)LoadImageW( - NULL, - _style.current_ascii_icon.c_str(), - IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), - LR_LOADFROMFILE); - } - else - { - if( _style.current_zhung_icon.empty()) - *phIcon = (HICON)LoadImageW( - g_hInst, - MAKEINTRESOURCEW(IDI_ZH), - IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), - LR_SHARED); - else - *phIcon = (HICON)LoadImageW( - NULL, - _style.current_zhung_icon.c_str(), - IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), - LR_LOADFROMFILE); - } - return (*phIcon == NULL)? E_FAIL: S_OK; +STDAPI CLangBarItemButton::GetIcon(HICON* phIcon) { + if (ascii_mode) { + if (_style.current_ascii_icon.empty()) + *phIcon = (HICON)LoadImageW(g_hInst, MAKEINTRESOURCEW(IDI_EN), IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), LR_SHARED); + else + *phIcon = + (HICON)LoadImageW(NULL, _style.current_ascii_icon.c_str(), IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), LR_LOADFROMFILE); + } else { + if (_style.current_zhung_icon.empty()) + *phIcon = (HICON)LoadImageW(g_hInst, MAKEINTRESOURCEW(IDI_ZH), IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), LR_SHARED); + else + *phIcon = + (HICON)LoadImageW(NULL, _style.current_zhung_icon.c_str(), IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), LR_LOADFROMFILE); + } + return (*phIcon == NULL) ? E_FAIL : S_OK; } -STDAPI CLangBarItemButton::GetText(BSTR *pbstrText) -{ - *pbstrText = SysAllocString(L"WeaselTSF Button"); - return (*pbstrText == NULL)? E_OUTOFMEMORY: S_OK; +STDAPI CLangBarItemButton::GetText(BSTR* pbstrText) { + *pbstrText = SysAllocString(L"WeaselTSF Button"); + return (*pbstrText == NULL) ? E_OUTOFMEMORY : S_OK; } -STDAPI CLangBarItemButton::AdviseSink(REFIID riid, IUnknown *punk, DWORD *pdwCookie) -{ - if (!IsEqualIID(riid, IID_ITfLangBarItemSink)) - return CONNECT_E_CANNOTCONNECT; - if (_pLangBarItemSink != NULL) - return CONNECT_E_ADVISELIMIT; - - if (punk->QueryInterface(IID_ITfLangBarItemSink, (LPVOID *) &_pLangBarItemSink) != S_OK) - { - _pLangBarItemSink = NULL; - return E_NOINTERFACE; - } - *pdwCookie = LANGBARITEMSINK_COOKIE; - return S_OK; +STDAPI CLangBarItemButton::AdviseSink(REFIID riid, + IUnknown* punk, + DWORD* pdwCookie) { + if (!IsEqualIID(riid, IID_ITfLangBarItemSink)) + return CONNECT_E_CANNOTCONNECT; + if (_pLangBarItemSink != NULL) + return CONNECT_E_ADVISELIMIT; + + if (punk->QueryInterface(IID_ITfLangBarItemSink, + (LPVOID*)&_pLangBarItemSink) != S_OK) { + _pLangBarItemSink = NULL; + return E_NOINTERFACE; + } + *pdwCookie = LANGBARITEMSINK_COOKIE; + return S_OK; } -STDAPI CLangBarItemButton::UnadviseSink(DWORD dwCookie) -{ - if (dwCookie != LANGBARITEMSINK_COOKIE || _pLangBarItemSink == NULL) - return CONNECT_E_NOCONNECTION; - _pLangBarItemSink = NULL; - return S_OK; +STDAPI CLangBarItemButton::UnadviseSink(DWORD dwCookie) { + if (dwCookie != LANGBARITEMSINK_COOKIE || _pLangBarItemSink == NULL) + return CONNECT_E_NOCONNECTION; + _pLangBarItemSink = NULL; + return S_OK; } -void CLangBarItemButton::UpdateWeaselStatus(weasel::Status stat) -{ - if (stat.ascii_mode != ascii_mode) { - ascii_mode = stat.ascii_mode; - if (_pLangBarItemSink) { - _pLangBarItemSink->OnUpdate(TF_LBI_STATUS | TF_LBI_ICON); - } - } - if (_current_schema_zhung_icon != _style.current_zhung_icon) { - _current_schema_zhung_icon = _style.current_zhung_icon; - if (_pLangBarItemSink) { - _pLangBarItemSink->OnUpdate(TF_LBI_STATUS | TF_LBI_ICON); - } - } - if (_current_schema_ascii_icon != _style.current_ascii_icon) { - _current_schema_ascii_icon = _style.current_ascii_icon; - if (_pLangBarItemSink) { - _pLangBarItemSink->OnUpdate(TF_LBI_STATUS | TF_LBI_ICON); - } - } - +void CLangBarItemButton::UpdateWeaselStatus(weasel::Status stat) { + if (stat.ascii_mode != ascii_mode) { + ascii_mode = stat.ascii_mode; + if (_pLangBarItemSink) { + _pLangBarItemSink->OnUpdate(TF_LBI_STATUS | TF_LBI_ICON); + } + } + if (_current_schema_zhung_icon != _style.current_zhung_icon) { + _current_schema_zhung_icon = _style.current_zhung_icon; + if (_pLangBarItemSink) { + _pLangBarItemSink->OnUpdate(TF_LBI_STATUS | TF_LBI_ICON); + } + } + if (_current_schema_ascii_icon != _style.current_ascii_icon) { + _current_schema_ascii_icon = _style.current_ascii_icon; + if (_pLangBarItemSink) { + _pLangBarItemSink->OnUpdate(TF_LBI_STATUS | TF_LBI_ICON); + } + } } -void CLangBarItemButton::SetLangbarStatus(DWORD dwStatus, BOOL fSet) -{ - BOOL isChange = FALSE; - - if (fSet) - { - if (!(_status & dwStatus)) - { - _status |= dwStatus; - isChange = TRUE; - } - } - else - { - if (_status & dwStatus) - { - _status &= ~dwStatus; - isChange = TRUE; - } - } - - if (isChange && _pLangBarItemSink) - { - _pLangBarItemSink->OnUpdate(TF_LBI_STATUS | TF_LBI_ICON); - } - - return; +void CLangBarItemButton::SetLangbarStatus(DWORD dwStatus, BOOL fSet) { + BOOL isChange = FALSE; + + if (fSet) { + if (!(_status & dwStatus)) { + _status |= dwStatus; + isChange = TRUE; + } + } else { + if (_status & dwStatus) { + _status &= ~dwStatus; + isChange = TRUE; + } + } + + if (isChange && _pLangBarItemSink) { + _pLangBarItemSink->OnUpdate(TF_LBI_STATUS | TF_LBI_ICON); + } + + return; } -BOOL is_wow64() -{ - DWORD errorCode; - if (GetSystemWow64DirectoryW(NULL, 0) == 0) - if ((errorCode = GetLastError()) == ERROR_CALL_NOT_IMPLEMENTED) - return FALSE; - else - ExitProcess((UINT)errorCode); - else - return TRUE; +BOOL is_wow64() { + DWORD errorCode; + if (GetSystemWow64DirectoryW(NULL, 0) == 0) + if ((errorCode = GetLastError()) == ERROR_CALL_NOT_IMPLEMENTED) + return FALSE; + else + ExitProcess((UINT)errorCode); + else + return TRUE; } -void WeaselTSF::_HandleLangBarMenuSelect(UINT wID) -{ - if(wID != ID_WEASELTRAY_RERUN_SERVICE) - m_client.TrayCommand(wID); - else - { - std::wstring WEASEL_REG_NAME_; - if(is_wow64()) - WEASEL_REG_NAME_ = L"Software\\WOW6432Node\\Rime\\Weasel"; - else - WEASEL_REG_NAME_ = L"Software\\Rime\\Weasel"; - - TCHAR szValue[MAX_PATH]; - DWORD dwBufLen = MAX_PATH; - - LONG lRes = RegGetValue(HKEY_LOCAL_MACHINE, WEASEL_REG_NAME_.c_str(), L"WeaselRoot", RRF_RT_REG_SZ, NULL, szValue, &dwBufLen); - if(lRes == ERROR_SUCCESS) - { - std::wstring dir(szValue); - std::thread th([dir]() { - ShellExecuteW(NULL, L"open", (dir + L"\\start_service.bat").c_str(), NULL, dir.c_str(), SW_HIDE); - }); - th.detach(); - } - } +void WeaselTSF::_HandleLangBarMenuSelect(UINT wID) { + if (wID != ID_WEASELTRAY_RERUN_SERVICE) + m_client.TrayCommand(wID); + else { + std::wstring WEASEL_REG_NAME_; + if (is_wow64()) + WEASEL_REG_NAME_ = L"Software\\WOW6432Node\\Rime\\Weasel"; + else + WEASEL_REG_NAME_ = L"Software\\Rime\\Weasel"; + + TCHAR szValue[MAX_PATH]; + DWORD dwBufLen = MAX_PATH; + + LONG lRes = + RegGetValue(HKEY_LOCAL_MACHINE, WEASEL_REG_NAME_.c_str(), L"WeaselRoot", + RRF_RT_REG_SZ, NULL, szValue, &dwBufLen); + if (lRes == ERROR_SUCCESS) { + std::wstring dir(szValue); + std::thread th([dir]() { + ShellExecuteW(NULL, L"open", (dir + L"\\start_service.bat").c_str(), + NULL, dir.c_str(), SW_HIDE); + }); + th.detach(); + } + } } -HWND WeaselTSF::_GetFocusedContextWindow() -{ - HWND hwnd = NULL; - ITfDocumentMgr *pDocMgr; - if (_pThreadMgr->GetFocus(&pDocMgr) == S_OK && pDocMgr != NULL) - { - ITfContext *pContext; - if (pDocMgr->GetTop(&pContext) == S_OK && pContext != NULL) - { - ITfContextView *pContextView; - if (pContext->GetActiveView(&pContextView) == S_OK && pContextView != NULL) - { - pContextView->GetWnd(&hwnd); - pContextView->Release(); - } - pContext->Release(); - } - pDocMgr->Release(); - } - - if (hwnd == NULL) - { - HWND hwndForeground = GetForegroundWindow(); - if (GetWindowThreadProcessId(hwndForeground, NULL) == GetCurrentThreadId()) - hwnd = hwndForeground; - } - - return hwnd; +HWND WeaselTSF::_GetFocusedContextWindow() { + HWND hwnd = NULL; + ITfDocumentMgr* pDocMgr; + if (_pThreadMgr->GetFocus(&pDocMgr) == S_OK && pDocMgr != NULL) { + ITfContext* pContext; + if (pDocMgr->GetTop(&pContext) == S_OK && pContext != NULL) { + ITfContextView* pContextView; + if (pContext->GetActiveView(&pContextView) == S_OK && + pContextView != NULL) { + pContextView->GetWnd(&hwnd); + pContextView->Release(); + } + pContext->Release(); + } + pDocMgr->Release(); + } + + if (hwnd == NULL) { + HWND hwndForeground = GetForegroundWindow(); + if (GetWindowThreadProcessId(hwndForeground, NULL) == GetCurrentThreadId()) + hwnd = hwndForeground; + } + + return hwnd; } -BOOL WeaselTSF::_InitLanguageBar() -{ - com_ptr pLangBarItemMgr; - BOOL fRet = FALSE; +BOOL WeaselTSF::_InitLanguageBar() { + com_ptr pLangBarItemMgr; + BOOL fRet = FALSE; - if (_pThreadMgr->QueryInterface(&pLangBarItemMgr) != S_OK) - return FALSE; + if (_pThreadMgr->QueryInterface(&pLangBarItemMgr) != S_OK) + return FALSE; - if ((_pLangBarButton = new CLangBarItemButton(this, GUID_LBI_INPUTMODE, _cand->style())) == NULL) - return FALSE; + if ((_pLangBarButton = new CLangBarItemButton(this, GUID_LBI_INPUTMODE, + _cand->style())) == NULL) + return FALSE; - if (pLangBarItemMgr->AddItem(_pLangBarButton) != S_OK) - { - _pLangBarButton = NULL; - return FALSE; - } + if (pLangBarItemMgr->AddItem(_pLangBarButton) != S_OK) { + _pLangBarButton = NULL; + return FALSE; + } - _pLangBarButton->Show(TRUE); - fRet = TRUE; + _pLangBarButton->Show(TRUE); + fRet = TRUE; - return fRet; + return fRet; } -void WeaselTSF::_UninitLanguageBar() -{ - com_ptr pLangBarItemMgr; +void WeaselTSF::_UninitLanguageBar() { + com_ptr pLangBarItemMgr; - if (_pLangBarButton == NULL) - return; + if (_pLangBarButton == NULL) + return; - if (_pThreadMgr->QueryInterface(&pLangBarItemMgr) == S_OK) - { - pLangBarItemMgr->RemoveItem(_pLangBarButton); - } + if (_pThreadMgr->QueryInterface(&pLangBarItemMgr) == S_OK) { + pLangBarItemMgr->RemoveItem(_pLangBarButton); + } - _pLangBarButton = NULL; + _pLangBarButton = NULL; } -void WeaselTSF::_UpdateLanguageBar(weasel::Status stat) -{ - if (!_pLangBarButton) return; - DWORD flags; - _GetCompartmentDWORD(flags, GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION); - if (stat.ascii_mode) - flags &= (~TF_CONVERSIONMODE_NATIVE); - else - flags |= TF_CONVERSIONMODE_NATIVE; - if (stat.full_shape) - flags |= TF_CONVERSIONMODE_FULLSHAPE; - else - flags &= (~TF_CONVERSIONMODE_FULLSHAPE); - _SetCompartmentDWORD(flags, GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION); - - _pLangBarButton->UpdateWeaselStatus(stat); +void WeaselTSF::_UpdateLanguageBar(weasel::Status stat) { + if (!_pLangBarButton) + return; + DWORD flags; + _GetCompartmentDWORD(flags, GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION); + if (stat.ascii_mode) + flags &= (~TF_CONVERSIONMODE_NATIVE); + else + flags |= TF_CONVERSIONMODE_NATIVE; + if (stat.full_shape) + flags |= TF_CONVERSIONMODE_FULLSHAPE; + else + flags &= (~TF_CONVERSIONMODE_FULLSHAPE); + _SetCompartmentDWORD(flags, GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION); + + _pLangBarButton->UpdateWeaselStatus(stat); } -void WeaselTSF::_ShowLanguageBar(BOOL show) -{ - if (!_pLangBarButton) return; - _pLangBarButton->Show(show); - +void WeaselTSF::_ShowLanguageBar(BOOL show) { + if (!_pLangBarButton) + return; + _pLangBarButton->Show(show); } -void WeaselTSF::_EnableLanguageBar(BOOL enable) -{ - if (!_pLangBarButton) return; - _pLangBarButton->SetLangbarStatus(TF_LBI_STATUS_DISABLED, !enable); +void WeaselTSF::_EnableLanguageBar(BOOL enable) { + if (!_pLangBarButton) + return; + _pLangBarButton->SetLangbarStatus(TF_LBI_STATUS_DISABLED, !enable); } diff --git a/WeaselTSF/LanguageBar.h b/WeaselTSF/LanguageBar.h index acb9571bc..667eab3fd 100644 --- a/WeaselTSF/LanguageBar.h +++ b/WeaselTSF/LanguageBar.h @@ -2,46 +2,46 @@ #include #include -class CLangBarItemButton : public ITfLangBarItemButton, public ITfSource -{ -public: - CLangBarItemButton(com_ptr pTextService, REFGUID guid, weasel::UIStyle& style ); - ~CLangBarItemButton(); - - /* IUnknown */ - STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject); - STDMETHODIMP_(ULONG) AddRef(); - STDMETHODIMP_(ULONG) Release(); - - /* ITfLangBarItem */ - STDMETHODIMP GetInfo(TF_LANGBARITEMINFO *pInfo); - STDMETHODIMP GetStatus(DWORD *pdwStatus); - STDMETHODIMP Show(BOOL fShow); - STDMETHODIMP GetTooltipString(BSTR *pbstrToolTip); - - /* ITfLangBarItemButton */ - STDMETHODIMP OnClick(TfLBIClick click, POINT pt, const RECT *prcArea); - STDMETHODIMP InitMenu(ITfMenu *pMenu); - STDMETHODIMP OnMenuSelect(UINT wID); - STDMETHODIMP GetIcon(HICON *phIcon); - STDMETHODIMP GetText(BSTR *pbstrText); - - /* ITfSource */ - STDMETHODIMP AdviseSink(REFIID riid, IUnknown *punk, DWORD *pdwCookie); - STDMETHODIMP UnadviseSink(DWORD dwCookie); - - void UpdateWeaselStatus(weasel::Status stat); - void SetLangbarStatus(DWORD dwStatus, BOOL fSet); - -private: - GUID _guid; - com_ptr _pTextService; - com_ptr _pLangBarItemSink; - LONG _cRef; /* COM Reference count */ - DWORD _status; - bool ascii_mode; - weasel::UIStyle& _style; - std::wstring _current_schema_zhung_icon; - std::wstring _current_schema_ascii_icon; +class CLangBarItemButton : public ITfLangBarItemButton, public ITfSource { + public: + CLangBarItemButton(com_ptr pTextService, + REFGUID guid, + weasel::UIStyle& style); + ~CLangBarItemButton(); + + /* IUnknown */ + STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + /* ITfLangBarItem */ + STDMETHODIMP GetInfo(TF_LANGBARITEMINFO* pInfo); + STDMETHODIMP GetStatus(DWORD* pdwStatus); + STDMETHODIMP Show(BOOL fShow); + STDMETHODIMP GetTooltipString(BSTR* pbstrToolTip); + + /* ITfLangBarItemButton */ + STDMETHODIMP OnClick(TfLBIClick click, POINT pt, const RECT* prcArea); + STDMETHODIMP InitMenu(ITfMenu* pMenu); + STDMETHODIMP OnMenuSelect(UINT wID); + STDMETHODIMP GetIcon(HICON* phIcon); + STDMETHODIMP GetText(BSTR* pbstrText); + + /* ITfSource */ + STDMETHODIMP AdviseSink(REFIID riid, IUnknown* punk, DWORD* pdwCookie); + STDMETHODIMP UnadviseSink(DWORD dwCookie); + + void UpdateWeaselStatus(weasel::Status stat); + void SetLangbarStatus(DWORD dwStatus, BOOL fSet); + + private: + GUID _guid; + com_ptr _pTextService; + com_ptr _pLangBarItemSink; + LONG _cRef; /* COM Reference count */ + DWORD _status; + bool ascii_mode; + weasel::UIStyle& _style; + std::wstring _current_schema_zhung_icon; + std::wstring _current_schema_ascii_icon; }; - diff --git a/WeaselTSF/Register.cpp b/WeaselTSF/Register.cpp index 6a96f5e19..4ad961d8f 100644 --- a/WeaselTSF/Register.cpp +++ b/WeaselTSF/Register.cpp @@ -9,254 +9,240 @@ static const char c_szTipKeyPrefix[] = "Software\\Microsft\\CTF\\TIP\\"; static const char c_szInProcSvr32[] = "InprocServer32"; static const char c_szModelName[] = "ThreadingModel"; -HKL FindIME() -{ - HKL hKL = NULL; - WCHAR key[9]; - HKEY hKey; - LSTATUS ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts", 0, KEY_READ, &hKey); - if (ret == ERROR_SUCCESS) - { - for (DWORD id = (0xE0200000 | TEXTSERVICE_LANGID); hKL == NULL && id <= (0xE0FF0000 | TEXTSERVICE_LANGID); id += 0x10000) - { - StringCchPrintfW(key, _countof(key), L"%08X", id); - HKEY hSubKey; - ret = RegOpenKeyExW(hKey, key, 0, KEY_READ, &hSubKey); - if (ret == ERROR_SUCCESS) - { - WCHAR data[32]; - DWORD type; - DWORD size = sizeof data; - ret = RegQueryValueExW(hSubKey, L"Ime File", NULL, &type, (LPBYTE)data, &size); - if (ret == ERROR_SUCCESS && type == REG_SZ && _wcsicmp(data, L"weasel.ime") == 0) - hKL = (HKL)id; - } - RegCloseKey(hSubKey); - } - } - RegCloseKey(hKey); - return hKL; +HKL FindIME() { + HKL hKL = NULL; + WCHAR key[9]; + HKEY hKey; + LSTATUS ret = + RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts", 0, + KEY_READ, &hKey); + if (ret == ERROR_SUCCESS) { + for (DWORD id = (0xE0200000 | TEXTSERVICE_LANGID); + hKL == NULL && id <= (0xE0FF0000 | TEXTSERVICE_LANGID); + id += 0x10000) { + StringCchPrintfW(key, _countof(key), L"%08X", id); + HKEY hSubKey; + ret = RegOpenKeyExW(hKey, key, 0, KEY_READ, &hSubKey); + if (ret == ERROR_SUCCESS) { + WCHAR data[32]; + DWORD type; + DWORD size = sizeof data; + ret = RegQueryValueExW(hSubKey, L"Ime File", NULL, &type, (LPBYTE)data, + &size); + if (ret == ERROR_SUCCESS && type == REG_SZ && + _wcsicmp(data, L"weasel.ime") == 0) + hKL = (HKL)id; + } + RegCloseKey(hSubKey); + } + } + RegCloseKey(hKey); + return hKL; } -BOOL RegisterProfiles() -{ - WCHAR achIconFile[MAX_PATH]; - ULONG cchIconFile = GetModuleFileNameW(g_hInst, achIconFile, ARRAYSIZE(achIconFile)); - HRESULT hr; - - { - CComPtr pInputProcessorProfileMgr; - hr = pInputProcessorProfileMgr.CoCreateInstance(CLSID_TF_InputProcessorProfiles, NULL, CLSCTX_ALL); - if (FAILED(hr)) - return FALSE; - - hr = pInputProcessorProfileMgr->RegisterProfile( - c_clsidTextService, - TEXTSERVICE_LANGID, - c_guidProfile, - TEXTSERVICE_DESC, - (ULONG)wcslen(TEXTSERVICE_DESC), - achIconFile, - cchIconFile, - TEXTSERVICE_ICON_INDEX, - FindIME(), - 0, - TRUE, - 0); - if (FAILED(hr)) - return FALSE; - } - - return TRUE; +BOOL RegisterProfiles() { + WCHAR achIconFile[MAX_PATH]; + ULONG cchIconFile = + GetModuleFileNameW(g_hInst, achIconFile, ARRAYSIZE(achIconFile)); + HRESULT hr; + + { + CComPtr pInputProcessorProfileMgr; + hr = pInputProcessorProfileMgr.CoCreateInstance( + CLSID_TF_InputProcessorProfiles, NULL, CLSCTX_ALL); + if (FAILED(hr)) + return FALSE; + + hr = pInputProcessorProfileMgr->RegisterProfile( + c_clsidTextService, TEXTSERVICE_LANGID, c_guidProfile, TEXTSERVICE_DESC, + (ULONG)wcslen(TEXTSERVICE_DESC), achIconFile, cchIconFile, + TEXTSERVICE_ICON_INDEX, FindIME(), 0, TRUE, 0); + if (FAILED(hr)) + return FALSE; + } + + return TRUE; } -void UnregisterProfiles() -{ - HRESULT hr; +void UnregisterProfiles() { + HRESULT hr; - { - CComPtr pInputProcessorProfileMgr; - hr = pInputProcessorProfileMgr.CoCreateInstance(CLSID_TF_InputProcessorProfiles, NULL, CLSCTX_ALL); - if (FAILED(hr)) - return; - - hr = pInputProcessorProfileMgr->UnregisterProfile( - c_clsidTextService, - TEXTSERVICE_LANGID, - c_guidProfile, - 0); - } + { + CComPtr pInputProcessorProfileMgr; + hr = pInputProcessorProfileMgr.CoCreateInstance( + CLSID_TF_InputProcessorProfiles, NULL, CLSCTX_ALL); + if (FAILED(hr)) + return; + hr = pInputProcessorProfileMgr->UnregisterProfile( + c_clsidTextService, TEXTSERVICE_LANGID, c_guidProfile, 0); + } } -const GUID SupportCategories0[] = -{ - GUID_TFCAT_CATEGORY_OF_TIP, - GUID_TFCAT_TIP_KEYBOARD, - // GUID_TFCAT_TIP_SPEECH, - // GUID_TFCAT_TIP_HANDWRITING, - GUID_TFCAT_TIPCAP_SECUREMODE, - GUID_TFCAT_TIPCAP_UIELEMENTENABLED, - GUID_TFCAT_TIPCAP_INPUTMODECOMPARTMENT, - GUID_TFCAT_TIPCAP_COMLESS, - GUID_TFCAT_TIPCAP_WOW16, - GUID_TFCAT_TIPCAP_IMMERSIVESUPPORT, - GUID_TFCAT_TIPCAP_SYSTRAYSUPPORT, - GUID_TFCAT_PROP_AUDIODATA, - GUID_TFCAT_PROP_INKDATA, - GUID_TFCAT_PROPSTYLE_CUSTOM, - GUID_TFCAT_PROPSTYLE_STATIC, - GUID_TFCAT_PROPSTYLE_STATICCOMPACT, - GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, - GUID_TFCAT_DISPLAYATTRIBUTEPROPERTY -}; - -BOOL RegisterCategories() -{ - ITfCategoryMgr* pCategoryMgr; - HRESULT hr; - - hr = CoCreateInstance(CLSID_TF_CategoryMgr, NULL, CLSCTX_INPROC_SERVER, IID_ITfCategoryMgr, (void**)&pCategoryMgr); - if (hr != S_OK) - return FALSE; - - BOOL flag = TRUE; - for (const auto& guid : SupportCategories0) - { - hr = pCategoryMgr->RegisterCategory(c_clsidTextService, guid, c_clsidTextService); - if (hr != S_OK) - flag = FALSE; - } - - pCategoryMgr->Release(); - return flag; +const GUID SupportCategories0[] = { + GUID_TFCAT_CATEGORY_OF_TIP, GUID_TFCAT_TIP_KEYBOARD, + // GUID_TFCAT_TIP_SPEECH, + // GUID_TFCAT_TIP_HANDWRITING, + GUID_TFCAT_TIPCAP_SECUREMODE, GUID_TFCAT_TIPCAP_UIELEMENTENABLED, + GUID_TFCAT_TIPCAP_INPUTMODECOMPARTMENT, GUID_TFCAT_TIPCAP_COMLESS, + GUID_TFCAT_TIPCAP_WOW16, GUID_TFCAT_TIPCAP_IMMERSIVESUPPORT, + GUID_TFCAT_TIPCAP_SYSTRAYSUPPORT, GUID_TFCAT_PROP_AUDIODATA, + GUID_TFCAT_PROP_INKDATA, GUID_TFCAT_PROPSTYLE_CUSTOM, + GUID_TFCAT_PROPSTYLE_STATIC, GUID_TFCAT_PROPSTYLE_STATICCOMPACT, + GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, GUID_TFCAT_DISPLAYATTRIBUTEPROPERTY}; + +BOOL RegisterCategories() { + ITfCategoryMgr* pCategoryMgr; + HRESULT hr; + + hr = CoCreateInstance(CLSID_TF_CategoryMgr, NULL, CLSCTX_INPROC_SERVER, + IID_ITfCategoryMgr, (void**)&pCategoryMgr); + if (hr != S_OK) + return FALSE; + + BOOL flag = TRUE; + for (const auto& guid : SupportCategories0) { + hr = pCategoryMgr->RegisterCategory(c_clsidTextService, guid, + c_clsidTextService); + if (hr != S_OK) + flag = FALSE; + } + + pCategoryMgr->Release(); + return flag; } -void UnregisterCategories() -{ - ITfCategoryMgr* pCategoryMgr; - HRESULT hr; +void UnregisterCategories() { + ITfCategoryMgr* pCategoryMgr; + HRESULT hr; - hr = CoCreateInstance(CLSID_TF_CategoryMgr, NULL, CLSCTX_INPROC_SERVER, IID_ITfCategoryMgr, (void**)&pCategoryMgr); - if (FAILED(hr)) - return; + hr = CoCreateInstance(CLSID_TF_CategoryMgr, NULL, CLSCTX_INPROC_SERVER, + IID_ITfCategoryMgr, (void**)&pCategoryMgr); + if (FAILED(hr)) + return; - for (const auto& guid : SupportCategories0) - pCategoryMgr->UnregisterCategory(c_clsidTextService, guid, c_clsidTextService); + for (const auto& guid : SupportCategories0) + pCategoryMgr->UnregisterCategory(c_clsidTextService, guid, + c_clsidTextService); - pCategoryMgr->Release(); + pCategoryMgr->Release(); } -static BOOL CLSIDToStringA(REFGUID refGUID, char *pchA) -{ - static const BYTE GuidMap[] = { 3, 2, 1, 0, '-', 5, 4, '-', 7, 6, '-', - 8, 9, '-', 10, 11, 12, 13, 14, 15 }; - - static const char szDigits[] = "0123456789ABCDEF"; - - int i; - char *p = pchA; - - const BYTE *pBytes = (const BYTE *)&refGUID; - - *p++ = '{'; - for (i = 0; i < sizeof(GuidMap); i++) - { - if (GuidMap[i] == '-') - *p++ = '-'; - else - { - *p++ = szDigits[(pBytes[GuidMap[i]] & 0xF0) >> 4]; - *p++ = szDigits[(pBytes[GuidMap[i]] & 0x0F)]; - } - } - *p++ = '}'; - *p = '\0'; - return TRUE; +static BOOL CLSIDToStringA(REFGUID refGUID, char* pchA) { + static const BYTE GuidMap[] = {3, 2, 1, 0, '-', 5, 4, '-', 7, 6, + '-', 8, 9, '-', 10, 11, 12, 13, 14, 15}; + + static const char szDigits[] = "0123456789ABCDEF"; + + int i; + char* p = pchA; + + const BYTE* pBytes = (const BYTE*)&refGUID; + + *p++ = '{'; + for (i = 0; i < sizeof(GuidMap); i++) { + if (GuidMap[i] == '-') + *p++ = '-'; + else { + *p++ = szDigits[(pBytes[GuidMap[i]] & 0xF0) >> 4]; + *p++ = szDigits[(pBytes[GuidMap[i]] & 0x0F)]; + } + } + *p++ = '}'; + *p = '\0'; + return TRUE; } -static LONG RecurseDeleteKeyA(HKEY hParentKey, LPCSTR lpszKey) -{ - HKEY hKey; - LONG lRes; - FILETIME time; - CHAR szBuffer[256]; - DWORD dwSize = ARRAYSIZE(szBuffer); - - if (RegOpenKeyA(hParentKey, lpszKey, &hKey) != ERROR_SUCCESS) - return ERROR_SUCCESS; - - lRes = ERROR_SUCCESS; - while (RegEnumKeyExA(hKey, 0, szBuffer, &dwSize, NULL, NULL, NULL, &time) == ERROR_SUCCESS) - { - szBuffer[ARRAYSIZE(szBuffer) - 1] = '\0'; - lRes = RecurseDeleteKeyA(hKey, szBuffer); - if (lRes != ERROR_SUCCESS) - break; - dwSize = ARRAYSIZE(szBuffer); - } - RegCloseKey(hKey); - - return lRes == ERROR_SUCCESS ? RegDeleteKeyA(hParentKey, lpszKey) : lRes; +static LONG RecurseDeleteKeyA(HKEY hParentKey, LPCSTR lpszKey) { + HKEY hKey; + LONG lRes; + FILETIME time; + CHAR szBuffer[256]; + DWORD dwSize = ARRAYSIZE(szBuffer); + + if (RegOpenKeyA(hParentKey, lpszKey, &hKey) != ERROR_SUCCESS) + return ERROR_SUCCESS; + + lRes = ERROR_SUCCESS; + while (RegEnumKeyExA(hKey, 0, szBuffer, &dwSize, NULL, NULL, NULL, &time) == + ERROR_SUCCESS) { + szBuffer[ARRAYSIZE(szBuffer) - 1] = '\0'; + lRes = RecurseDeleteKeyA(hKey, szBuffer); + if (lRes != ERROR_SUCCESS) + break; + dwSize = ARRAYSIZE(szBuffer); + } + RegCloseKey(hKey); + + return lRes == ERROR_SUCCESS ? RegDeleteKeyA(hParentKey, lpszKey) : lRes; } -BOOL RegisterServer() -{ - DWORD dw; - HKEY hKey; - HKEY hSubKey; - BOOL fRet; - char achIMEKey[ARRAYSIZE(c_szInfoKeyPrefix) + CLSID_STRLEN]; - char achFileName[MAX_PATH]; - - if (!CLSIDToStringA(c_clsidTextService, achIMEKey + ARRAYSIZE(c_szInfoKeyPrefix) - 1)) - return FALSE; - memcpy(achIMEKey, c_szInfoKeyPrefix, sizeof(c_szInfoKeyPrefix) - 1); - - if (fRet = RegCreateKeyExA(HKEY_CLASSES_ROOT, achIMEKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dw) == ERROR_SUCCESS) - { - fRet &= RegSetValueExA(hKey, NULL, 0, REG_SZ, (BYTE *)TEXTSERVICE_DESC_A, sizeof TEXTSERVICE_DESC_A) == ERROR_SUCCESS; - if (fRet &= RegCreateKeyExA(hKey, c_szInProcSvr32, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hSubKey, &dw) == ERROR_SUCCESS) - { - dw = GetModuleFileNameA(g_hInst, achFileName, ARRAYSIZE(achFileName)); +BOOL RegisterServer() { + DWORD dw; + HKEY hKey; + HKEY hSubKey; + BOOL fRet; + char achIMEKey[ARRAYSIZE(c_szInfoKeyPrefix) + CLSID_STRLEN]; + char achFileName[MAX_PATH]; + + if (!CLSIDToStringA(c_clsidTextService, + achIMEKey + ARRAYSIZE(c_szInfoKeyPrefix) - 1)) + return FALSE; + memcpy(achIMEKey, c_szInfoKeyPrefix, sizeof(c_szInfoKeyPrefix) - 1); + + if (fRet = RegCreateKeyExA(HKEY_CLASSES_ROOT, achIMEKey, 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, + &dw) == ERROR_SUCCESS) { + fRet &= RegSetValueExA(hKey, NULL, 0, REG_SZ, (BYTE*)TEXTSERVICE_DESC_A, + sizeof TEXTSERVICE_DESC_A) == ERROR_SUCCESS; + if (fRet &= + RegCreateKeyExA(hKey, c_szInProcSvr32, 0, NULL, REG_OPTION_NON_VOLATILE, + KEY_WRITE, NULL, &hSubKey, &dw) == ERROR_SUCCESS) { + dw = GetModuleFileNameA(g_hInst, achFileName, ARRAYSIZE(achFileName)); #ifdef _M_ARM64 - { - // On ARM64 we use ARM64X redirection DLL. - // When loaded, weasel.dll will be redirected to weaselARM64.dll on ARM64 processes, - // and weaselx64.dll on x64 processes. - // - // But GetModuleFileNameA will return the actual loaded DLL name aka weaselARM64.dll - // Rewrite the path to point to the redirector. - - char wrapperPath[MAX_PATH]; - StringCbCatA(achFileName, MAX_PATH, "\\..\\weasel.dll"); - GetFullPathNameA(achFileName, MAX_PATH, wrapperPath, NULL); - memcpy(achFileName, wrapperPath, MAX_PATH); - } + { + // On ARM64 we use ARM64X redirection DLL. + // When loaded, weasel.dll will be redirected to weaselARM64.dll on + // ARM64 processes, and weaselx64.dll on x64 processes. + // + // But GetModuleFileNameA will return the actual loaded DLL name aka + // weaselARM64.dll Rewrite the path to point to the redirector. + + char wrapperPath[MAX_PATH]; + StringCbCatA(achFileName, MAX_PATH, "\\..\\weasel.dll"); + GetFullPathNameA(achFileName, MAX_PATH, wrapperPath, NULL); + memcpy(achFileName, wrapperPath, MAX_PATH); + } #endif - fRet &= RegSetValueExA(hSubKey, NULL, 0, REG_SZ, (BYTE *)achFileName, (strlen(achFileName) + 1) * sizeof(char)) == ERROR_SUCCESS; - fRet &= RegSetValueExA(hSubKey, c_szModelName, 0, REG_SZ, (BYTE *)TEXTSERVICE_MODEL, sizeof TEXTSERVICE_MODEL) == ERROR_SUCCESS; - RegCloseKey(hSubKey); - } - RegCloseKey(hKey); - } - return fRet; + fRet &= RegSetValueExA(hSubKey, NULL, 0, REG_SZ, (BYTE*)achFileName, + (strlen(achFileName) + 1) * sizeof(char)) == + ERROR_SUCCESS; + fRet &= RegSetValueExA(hSubKey, c_szModelName, 0, REG_SZ, + (BYTE*)TEXTSERVICE_MODEL, + sizeof TEXTSERVICE_MODEL) == ERROR_SUCCESS; + RegCloseKey(hSubKey); + } + RegCloseKey(hKey); + } + return fRet; } -void UnregisterServer() -{ - char achIMEKey[ARRAYSIZE(c_szInfoKeyPrefix) + CLSID_STRLEN]; - if (!CLSIDToStringA(c_clsidTextService, achIMEKey + ARRAYSIZE(c_szInfoKeyPrefix) - 1)) - return; - memcpy(achIMEKey, c_szInfoKeyPrefix, sizeof(c_szInfoKeyPrefix) - 1); - RecurseDeleteKeyA(HKEY_CLASSES_ROOT, achIMEKey); - - // On Windows 8, we need to manually delete the registry key for our TIP - char tipKey[ARRAYSIZE(c_szTipKeyPrefix) + CLSID_STRLEN]; - if (!CLSIDToStringA(c_clsidTextService, tipKey + ARRAYSIZE(c_szTipKeyPrefix) - 1)) - return; - memcpy(tipKey, c_szTipKeyPrefix, sizeof(c_szTipKeyPrefix) - 1); - RecurseDeleteKeyA(HKEY_CLASSES_ROOT, tipKey); +void UnregisterServer() { + char achIMEKey[ARRAYSIZE(c_szInfoKeyPrefix) + CLSID_STRLEN]; + if (!CLSIDToStringA(c_clsidTextService, + achIMEKey + ARRAYSIZE(c_szInfoKeyPrefix) - 1)) + return; + memcpy(achIMEKey, c_szInfoKeyPrefix, sizeof(c_szInfoKeyPrefix) - 1); + RecurseDeleteKeyA(HKEY_CLASSES_ROOT, achIMEKey); + + // On Windows 8, we need to manually delete the registry key for our TIP + char tipKey[ARRAYSIZE(c_szTipKeyPrefix) + CLSID_STRLEN]; + if (!CLSIDToStringA(c_clsidTextService, + tipKey + ARRAYSIZE(c_szTipKeyPrefix) - 1)) + return; + memcpy(tipKey, c_szTipKeyPrefix, sizeof(c_szTipKeyPrefix) - 1); + RecurseDeleteKeyA(HKEY_CLASSES_ROOT, tipKey); } diff --git a/WeaselTSF/Server.cpp b/WeaselTSF/Server.cpp index 2c81e46c2..cf3f75f1b 100644 --- a/WeaselTSF/Server.cpp +++ b/WeaselTSF/Server.cpp @@ -5,125 +5,112 @@ #include "WeaselTSF.h" #include -void DllAddRef() -{ - InterlockedIncrement(&g_cRefDll); +void DllAddRef() { + InterlockedIncrement(&g_cRefDll); } -void DllRelease() -{ - InterlockedDecrement(&g_cRefDll); +void DllRelease() { + InterlockedDecrement(&g_cRefDll); } -class CClassFactory: public IClassFactory -{ -public: - // IUnknown methods - STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject); - STDMETHODIMP_(ULONG) AddRef(); - STDMETHODIMP_(ULONG) Release(); - - // IClassFactory methods - STDMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject); - STDMETHODIMP LockServer(BOOL fLock); +class CClassFactory : public IClassFactory { + public: + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IClassFactory methods + STDMETHODIMP CreateInstance(IUnknown* pUnkOuter, + REFIID riid, + void** ppvObject); + STDMETHODIMP LockServer(BOOL fLock); }; -STDAPI CClassFactory::QueryInterface(REFIID riid, void **ppvObject) -{ - if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown)) - { - *ppvObject = this; - DllAddRef(); - return NOERROR; - } - *ppvObject = NULL; - return E_NOINTERFACE; +STDAPI CClassFactory::QueryInterface(REFIID riid, void** ppvObject) { + if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown)) { + *ppvObject = this; + DllAddRef(); + return NOERROR; + } + *ppvObject = NULL; + return E_NOINTERFACE; } -STDAPI_(ULONG) CClassFactory::AddRef() -{ - DllAddRef(); - return g_cRefDll + 1; +STDAPI_(ULONG) CClassFactory::AddRef() { + DllAddRef(); + return g_cRefDll + 1; } -STDAPI_(ULONG) CClassFactory::Release() -{ - DllRelease(); - return g_cRefDll + 1; +STDAPI_(ULONG) CClassFactory::Release() { + DllRelease(); + return g_cRefDll + 1; } -STDAPI CClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject) -{ - WeaselTSF *pCase; - HRESULT hr; - if (ppvObject == NULL) - return E_INVALIDARG; - *ppvObject = NULL; - if (pUnkOuter != NULL) - return CLASS_E_NOAGGREGATION; - if ((pCase = new WeaselTSF()) == NULL) - return E_OUTOFMEMORY; - hr = pCase->QueryInterface(riid, ppvObject); - pCase->Release(); // caller still holds ref if hr == S_OK - return hr; +STDAPI CClassFactory::CreateInstance(IUnknown* pUnkOuter, + REFIID riid, + void** ppvObject) { + WeaselTSF* pCase; + HRESULT hr; + if (ppvObject == NULL) + return E_INVALIDARG; + *ppvObject = NULL; + if (pUnkOuter != NULL) + return CLASS_E_NOAGGREGATION; + if ((pCase = new WeaselTSF()) == NULL) + return E_OUTOFMEMORY; + hr = pCase->QueryInterface(riid, ppvObject); + pCase->Release(); // caller still holds ref if hr == S_OK + return hr; } -STDAPI CClassFactory::LockServer(BOOL fLock) -{ - if (fLock) - DllAddRef(); - else - DllRelease(); - return S_OK; +STDAPI CClassFactory::LockServer(BOOL fLock) { + if (fLock) + DllAddRef(); + else + DllRelease(); + return S_OK; } -static CClassFactory *g_classFactory = NULL; +static CClassFactory* g_classFactory = NULL; -static void BuildGlobalObjects() -{ - g_classFactory = new CClassFactory(); +static void BuildGlobalObjects() { + g_classFactory = new CClassFactory(); } -STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppvObject) -{ - if (g_classFactory == NULL) - { - EnterCriticalSection(&g_cs); - if (g_classFactory == NULL) - BuildGlobalObjects(); - LeaveCriticalSection(&g_cs); - } - if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown)) - { - *ppvObject = g_classFactory; - DllAddRef(); - return NOERROR; - } - *ppvObject = NULL; - return CLASS_E_CLASSNOTAVAILABLE; +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppvObject) { + if (g_classFactory == NULL) { + EnterCriticalSection(&g_cs); + if (g_classFactory == NULL) + BuildGlobalObjects(); + LeaveCriticalSection(&g_cs); + } + if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown)) { + *ppvObject = g_classFactory; + DllAddRef(); + return NOERROR; + } + *ppvObject = NULL; + return CLASS_E_CLASSNOTAVAILABLE; } -STDAPI DllCanUnloadNow() -{ - if (g_cRefDll >= 0) - return S_FALSE; - return S_OK; +STDAPI DllCanUnloadNow() { + if (g_cRefDll >= 0) + return S_FALSE; + return S_OK; } -STDAPI DllRegisterServer() -{ - if (!RegisterServer() || !RegisterProfiles() || !RegisterCategories()) - { - DllUnregisterServer(); - return E_FAIL; - } - return S_OK; +STDAPI DllRegisterServer() { + if (!RegisterServer() || !RegisterProfiles() || !RegisterCategories()) { + DllUnregisterServer(); + return E_FAIL; + } + return S_OK; } -STDAPI DllUnregisterServer() -{ - UnregisterProfiles(); - UnregisterCategories(); - UnregisterServer(); - return S_OK; +STDAPI DllUnregisterServer() { + UnregisterProfiles(); + UnregisterCategories(); + UnregisterServer(); + return S_OK; } diff --git a/WeaselTSF/TextEditSink.cpp b/WeaselTSF/TextEditSink.cpp index 4dd8cb350..a6bc1f02d 100644 --- a/WeaselTSF/TextEditSink.cpp +++ b/WeaselTSF/TextEditSink.cpp @@ -1,117 +1,118 @@ #include "stdafx.h" #include "WeaselTSF.h" -static BOOL IsRangeCovered(TfEditCookie ec, ITfRange *pRangeTest, ITfRange *pRangeCover) -{ - LONG lResult; - - if (pRangeCover->CompareStart(ec, pRangeTest, TF_ANCHOR_START, &lResult) != S_OK || lResult > 0) - return FALSE; - if (pRangeCover->CompareEnd(ec, pRangeTest, TF_ANCHOR_END, &lResult) != S_OK || lResult < 0) - return FALSE; - return TRUE; +static BOOL IsRangeCovered(TfEditCookie ec, + ITfRange* pRangeTest, + ITfRange* pRangeCover) { + LONG lResult; + + if (pRangeCover->CompareStart(ec, pRangeTest, TF_ANCHOR_START, &lResult) != + S_OK || + lResult > 0) + return FALSE; + if (pRangeCover->CompareEnd(ec, pRangeTest, TF_ANCHOR_END, &lResult) != + S_OK || + lResult < 0) + return FALSE; + return TRUE; } -STDAPI WeaselTSF::OnEndEdit(ITfContext *pContext, TfEditCookie ecReadOnly, ITfEditRecord *pEditRecord) -{ - BOOL fSelectionChanged; - IEnumTfRanges *pEnumTextChanges; - ITfRange *pRange; - - /* did the selection change? */ - if (pEditRecord->GetSelectionStatus(&fSelectionChanged) == S_OK && fSelectionChanged) - { - if (_IsComposing()) - { - /* if the caret moves out of composition range, stop the composition */ - TF_SELECTION tfSelection; - ULONG cFetched; - - if (pContext->GetSelection(ecReadOnly, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) == S_OK && cFetched == 1) - { - ITfRange *pRangeComposition; - if (_pComposition->GetRange(&pRangeComposition) == S_OK) - { - if (!IsRangeCovered(ecReadOnly, tfSelection.range, pRangeComposition)) - _EndComposition(pContext, true); - pRangeComposition->Release(); - } - } - } - } - - /* text modification? */ - if (pEditRecord->GetTextAndPropertyUpdates(TF_GTP_INCL_TEXT, NULL, 0, &pEnumTextChanges) == S_OK) - { - if (pEnumTextChanges->Next(1, &pRange, NULL) == S_OK) - { - pRange->Release(); - } - pEnumTextChanges->Release(); - } - return S_OK; +STDAPI WeaselTSF::OnEndEdit(ITfContext* pContext, + TfEditCookie ecReadOnly, + ITfEditRecord* pEditRecord) { + BOOL fSelectionChanged; + IEnumTfRanges* pEnumTextChanges; + ITfRange* pRange; + + /* did the selection change? */ + if (pEditRecord->GetSelectionStatus(&fSelectionChanged) == S_OK && + fSelectionChanged) { + if (_IsComposing()) { + /* if the caret moves out of composition range, stop the composition */ + TF_SELECTION tfSelection; + ULONG cFetched; + + if (pContext->GetSelection(ecReadOnly, TF_DEFAULT_SELECTION, 1, + &tfSelection, &cFetched) == S_OK && + cFetched == 1) { + ITfRange* pRangeComposition; + if (_pComposition->GetRange(&pRangeComposition) == S_OK) { + if (!IsRangeCovered(ecReadOnly, tfSelection.range, pRangeComposition)) + _EndComposition(pContext, true); + pRangeComposition->Release(); + } + } + } + } + + /* text modification? */ + if (pEditRecord->GetTextAndPropertyUpdates(TF_GTP_INCL_TEXT, NULL, 0, + &pEnumTextChanges) == S_OK) { + if (pEnumTextChanges->Next(1, &pRange, NULL) == S_OK) { + pRange->Release(); + } + pEnumTextChanges->Release(); + } + return S_OK; } -STDAPI WeaselTSF::OnLayoutChange(ITfContext *pContext, TfLayoutCode lcode, ITfContextView *pContextView) -{ - if (!_IsComposing()) - return S_OK; +STDAPI WeaselTSF::OnLayoutChange(ITfContext* pContext, + TfLayoutCode lcode, + ITfContextView* pContextView) { + if (!_IsComposing()) + return S_OK; - if (pContext != _pTextEditSinkContext) - return S_OK; + if (pContext != _pTextEditSinkContext) + return S_OK; - if (lcode == TF_LC_CHANGE) - _UpdateCompositionWindow(pContext); - return S_OK; + if (lcode == TF_LC_CHANGE) + _UpdateCompositionWindow(pContext); + return S_OK; } -BOOL WeaselTSF::_InitTextEditSink(com_ptr pDocMgr) -{ - com_ptr pSource; - BOOL fRet; - - /* clear out any previous sink first */ - if (_dwTextEditSinkCookie != TF_INVALID_COOKIE) - { - _pTextEditSinkContext->QueryInterface(&pSource); - if (pSource != nullptr) - { - pSource->UnadviseSink(_dwTextEditSinkCookie); - pSource->UnadviseSink(_dwTextLayoutSinkCookie); - } - _pTextEditSinkContext = nullptr; - _dwTextEditSinkCookie = TF_INVALID_COOKIE; - } - if (pDocMgr == NULL) - return TRUE; - - if (pDocMgr->GetTop(&_pTextEditSinkContext) != S_OK) - return FALSE; - - if (_pTextEditSinkContext == NULL) - return TRUE; - - fRet = FALSE; - - pSource.Release(); - - if (_pTextEditSinkContext->QueryInterface(IID_ITfSource, (void **) &pSource) == S_OK) - { - if (pSource->AdviseSink(IID_ITfTextEditSink, (ITfTextEditSink *) this, &_dwTextEditSinkCookie) == S_OK) - fRet = TRUE; - else - _dwTextEditSinkCookie = TF_INVALID_COOKIE; - if (pSource->AdviseSink(IID_ITfTextLayoutSink, (ITfTextLayoutSink *) this, &_dwTextLayoutSinkCookie) == S_OK) - { - fRet = TRUE; - } - else - _dwTextLayoutSinkCookie = TF_INVALID_COOKIE; - } - if (fRet == FALSE) - { - _pTextEditSinkContext = nullptr; - } - - return fRet; +BOOL WeaselTSF::_InitTextEditSink(com_ptr pDocMgr) { + com_ptr pSource; + BOOL fRet; + + /* clear out any previous sink first */ + if (_dwTextEditSinkCookie != TF_INVALID_COOKIE) { + _pTextEditSinkContext->QueryInterface(&pSource); + if (pSource != nullptr) { + pSource->UnadviseSink(_dwTextEditSinkCookie); + pSource->UnadviseSink(_dwTextLayoutSinkCookie); + } + _pTextEditSinkContext = nullptr; + _dwTextEditSinkCookie = TF_INVALID_COOKIE; + } + if (pDocMgr == NULL) + return TRUE; + + if (pDocMgr->GetTop(&_pTextEditSinkContext) != S_OK) + return FALSE; + + if (_pTextEditSinkContext == NULL) + return TRUE; + + fRet = FALSE; + + pSource.Release(); + + if (_pTextEditSinkContext->QueryInterface(IID_ITfSource, (void**)&pSource) == + S_OK) { + if (pSource->AdviseSink(IID_ITfTextEditSink, (ITfTextEditSink*)this, + &_dwTextEditSinkCookie) == S_OK) + fRet = TRUE; + else + _dwTextEditSinkCookie = TF_INVALID_COOKIE; + if (pSource->AdviseSink(IID_ITfTextLayoutSink, (ITfTextLayoutSink*)this, + &_dwTextLayoutSinkCookie) == S_OK) { + fRet = TRUE; + } else + _dwTextLayoutSinkCookie = TF_INVALID_COOKIE; + } + if (fRet == FALSE) { + _pTextEditSinkContext = nullptr; + } + + return fRet; } diff --git a/WeaselTSF/ThreadMgrEventSink.cpp b/WeaselTSF/ThreadMgrEventSink.cpp index bee8422cf..a46ca3786 100644 --- a/WeaselTSF/ThreadMgrEventSink.cpp +++ b/WeaselTSF/ThreadMgrEventSink.cpp @@ -1,71 +1,62 @@ #include "stdafx.h" #include "WeaselTSF.h" -STDAPI WeaselTSF::OnInitDocumentMgr(ITfDocumentMgr *pDocMgr) -{ - return S_OK; +STDAPI WeaselTSF::OnInitDocumentMgr(ITfDocumentMgr* pDocMgr) { + return S_OK; } -STDAPI WeaselTSF::OnUninitDocumentMgr(ITfDocumentMgr *pDocMgr) -{ - return S_OK; +STDAPI WeaselTSF::OnUninitDocumentMgr(ITfDocumentMgr* pDocMgr) { + return S_OK; } -STDAPI WeaselTSF::OnSetFocus(ITfDocumentMgr *pDocMgrFocus, ITfDocumentMgr *pDocMgrPrevFocus) -{ - _InitTextEditSink(pDocMgrFocus); - - com_ptr pCandidateListDocumentMgr; - com_ptr pTfContext = _GetUIContextDocument(); - if ((nullptr != pTfContext) && SUCCEEDED(pTfContext->GetDocumentMgr(&pCandidateListDocumentMgr))) - { - if (pCandidateListDocumentMgr != pDocMgrFocus) - { - _HideUI(); - } - else - { - _ShowUI(); - } - } - - return S_OK; +STDAPI WeaselTSF::OnSetFocus(ITfDocumentMgr* pDocMgrFocus, + ITfDocumentMgr* pDocMgrPrevFocus) { + _InitTextEditSink(pDocMgrFocus); + + com_ptr pCandidateListDocumentMgr; + com_ptr pTfContext = _GetUIContextDocument(); + if ((nullptr != pTfContext) && + SUCCEEDED(pTfContext->GetDocumentMgr(&pCandidateListDocumentMgr))) { + if (pCandidateListDocumentMgr != pDocMgrFocus) { + _HideUI(); + } else { + _ShowUI(); + } + } + + return S_OK; } -STDAPI WeaselTSF::OnPushContext(ITfContext *pContext) -{ - return S_OK; +STDAPI WeaselTSF::OnPushContext(ITfContext* pContext) { + return S_OK; } -STDAPI WeaselTSF::OnPopContext(ITfContext *pContext) -{ - return S_OK; +STDAPI WeaselTSF::OnPopContext(ITfContext* pContext) { + return S_OK; } -BOOL WeaselTSF::_InitThreadMgrEventSink() -{ - ITfSource *pSource; - if (_pThreadMgr->QueryInterface(IID_ITfSource, (void **) &pSource) != S_OK) - return FALSE; - if (pSource->AdviseSink(IID_ITfThreadMgrEventSink, (ITfThreadMgrEventSink *) this, &_dwThreadMgrEventSinkCookie) != S_OK) - { - _dwThreadMgrEventSinkCookie = TF_INVALID_COOKIE; - pSource->Release(); - return FALSE; - } - pSource->Release(); - return TRUE; +BOOL WeaselTSF::_InitThreadMgrEventSink() { + ITfSource* pSource; + if (_pThreadMgr->QueryInterface(IID_ITfSource, (void**)&pSource) != S_OK) + return FALSE; + if (pSource->AdviseSink(IID_ITfThreadMgrEventSink, + (ITfThreadMgrEventSink*)this, + &_dwThreadMgrEventSinkCookie) != S_OK) { + _dwThreadMgrEventSinkCookie = TF_INVALID_COOKIE; + pSource->Release(); + return FALSE; + } + pSource->Release(); + return TRUE; } -void WeaselTSF::_UninitThreadMgrEventSink() -{ - ITfSource *pSource; - if (_dwThreadMgrEventSinkCookie == TF_INVALID_COOKIE) - return; - if (SUCCEEDED(_pThreadMgr->QueryInterface(IID_ITfSource, (void **) &pSource))) - { - pSource->UnadviseSink(_dwThreadMgrEventSinkCookie); - pSource->Release(); - } - _dwThreadMgrEventSinkCookie = TF_INVALID_COOKIE; +void WeaselTSF::_UninitThreadMgrEventSink() { + ITfSource* pSource; + if (_dwThreadMgrEventSinkCookie == TF_INVALID_COOKIE) + return; + if (SUCCEEDED(_pThreadMgr->QueryInterface(IID_ITfSource, (void**)&pSource))) { + pSource->UnadviseSink(_dwThreadMgrEventSinkCookie); + pSource->Release(); + } + _dwThreadMgrEventSinkCookie = TF_INVALID_COOKIE; } diff --git a/WeaselTSF/WeaselTSF.cpp b/WeaselTSF/WeaselTSF.cpp index afbd8736a..1280ad81f 100644 --- a/WeaselTSF/WeaselTSF.cpp +++ b/WeaselTSF/WeaselTSF.cpp @@ -7,205 +7,193 @@ #include "Compartment.h" #include "ResponseParser.h" -static void error_message(const WCHAR *msg) -{ - static DWORD next_tick = 0; - DWORD now = GetTickCount(); - if (now > next_tick) - { - next_tick = now + 10000; // (ms) - MessageBox(NULL, msg, TEXTSERVICE_DESC, MB_ICONERROR | MB_OK); - } +static void error_message(const WCHAR* msg) { + static DWORD next_tick = 0; + DWORD now = GetTickCount(); + if (now > next_tick) { + next_tick = now + 10000; // (ms) + MessageBox(NULL, msg, TEXTSERVICE_DESC, MB_ICONERROR | MB_OK); + } } -WeaselTSF::WeaselTSF() -{ - _cRef = 1; +WeaselTSF::WeaselTSF() { + _cRef = 1; - _dwThreadMgrEventSinkCookie = TF_INVALID_COOKIE; + _dwThreadMgrEventSinkCookie = TF_INVALID_COOKIE; - _dwTextEditSinkCookie = TF_INVALID_COOKIE; - _dwTextLayoutSinkCookie = TF_INVALID_COOKIE; - _fTestKeyDownPending = FALSE; - _fTestKeyUpPending = FALSE; + _dwTextEditSinkCookie = TF_INVALID_COOKIE; + _dwTextLayoutSinkCookie = TF_INVALID_COOKIE; + _fTestKeyDownPending = FALSE; + _fTestKeyUpPending = FALSE; - _fCUASWorkaroundTested = _fCUASWorkaroundEnabled = FALSE; + _fCUASWorkaroundTested = _fCUASWorkaroundEnabled = FALSE; - _cand = new CCandidateList(this); + _cand = new CCandidateList(this); - DllAddRef(); + DllAddRef(); } -WeaselTSF::~WeaselTSF() -{ - DllRelease(); +WeaselTSF::~WeaselTSF() { + DllRelease(); } -STDAPI WeaselTSF::QueryInterface(REFIID riid, void **ppvObject) -{ - if (ppvObject == NULL) - return E_INVALIDARG; - - *ppvObject = NULL; - - if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfTextInputProcessor)) - *ppvObject = (ITfTextInputProcessor*)this; - else if (IsEqualIID(riid, IID_ITfTextInputProcessorEx)) - *ppvObject = (ITfTextInputProcessorEx*)this; - else if (IsEqualIID(riid, IID_ITfThreadMgrEventSink)) - *ppvObject = (ITfThreadMgrEventSink*)this; - else if (IsEqualIID(riid, IID_ITfTextEditSink)) - *ppvObject = (ITfTextEditSink*)this; - else if (IsEqualIID(riid, IID_ITfTextLayoutSink)) - *ppvObject = (ITfTextLayoutSink*)this; - else if (IsEqualIID(riid, IID_ITfKeyEventSink)) - *ppvObject = (ITfKeyEventSink*)this; - else if (IsEqualIID(riid, IID_ITfCompositionSink)) - *ppvObject = (ITfCompositionSink*)this; - else if (IsEqualIID(riid, IID_ITfEditSession)) - *ppvObject = (ITfEditSession*)this; - else if (IsEqualIID(riid, IID_ITfThreadFocusSink)) - *ppvObject = (ITfThreadFocusSink*)this; - else if (IsEqualIID(riid, IID_ITfDisplayAttributeProvider)) - *ppvObject = (ITfDisplayAttributeProvider*)this; - - if (*ppvObject) - { - AddRef(); - return S_OK; - } - return E_NOINTERFACE; +STDAPI WeaselTSF::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == NULL) + return E_INVALIDARG; + + *ppvObject = NULL; + + if (IsEqualIID(riid, IID_IUnknown) || + IsEqualIID(riid, IID_ITfTextInputProcessor)) + *ppvObject = (ITfTextInputProcessor*)this; + else if (IsEqualIID(riid, IID_ITfTextInputProcessorEx)) + *ppvObject = (ITfTextInputProcessorEx*)this; + else if (IsEqualIID(riid, IID_ITfThreadMgrEventSink)) + *ppvObject = (ITfThreadMgrEventSink*)this; + else if (IsEqualIID(riid, IID_ITfTextEditSink)) + *ppvObject = (ITfTextEditSink*)this; + else if (IsEqualIID(riid, IID_ITfTextLayoutSink)) + *ppvObject = (ITfTextLayoutSink*)this; + else if (IsEqualIID(riid, IID_ITfKeyEventSink)) + *ppvObject = (ITfKeyEventSink*)this; + else if (IsEqualIID(riid, IID_ITfCompositionSink)) + *ppvObject = (ITfCompositionSink*)this; + else if (IsEqualIID(riid, IID_ITfEditSession)) + *ppvObject = (ITfEditSession*)this; + else if (IsEqualIID(riid, IID_ITfThreadFocusSink)) + *ppvObject = (ITfThreadFocusSink*)this; + else if (IsEqualIID(riid, IID_ITfDisplayAttributeProvider)) + *ppvObject = (ITfDisplayAttributeProvider*)this; + + if (*ppvObject) { + AddRef(); + return S_OK; + } + return E_NOINTERFACE; } -STDAPI_(ULONG) WeaselTSF::AddRef() -{ - return ++_cRef; +STDAPI_(ULONG) WeaselTSF::AddRef() { + return ++_cRef; } -STDAPI_(ULONG) WeaselTSF::Release() -{ - LONG cr = --_cRef; +STDAPI_(ULONG) WeaselTSF::Release() { + LONG cr = --_cRef; - assert(_cRef >= 0); + assert(_cRef >= 0); - if (_cRef == 0) - delete this; + if (_cRef == 0) + delete this; - return cr; + return cr; } -STDAPI WeaselTSF::Activate(ITfThreadMgr *pThreadMgr, TfClientId tfClientId) -{ - return ActivateEx(pThreadMgr, tfClientId, 0U); +STDAPI WeaselTSF::Activate(ITfThreadMgr* pThreadMgr, TfClientId tfClientId) { + return ActivateEx(pThreadMgr, tfClientId, 0U); } -STDAPI WeaselTSF::Deactivate() -{ - m_client.EndSession(); +STDAPI WeaselTSF::Deactivate() { + m_client.EndSession(); - _InitTextEditSink(com_ptr()); + _InitTextEditSink(com_ptr()); - _UninitThreadMgrEventSink(); + _UninitThreadMgrEventSink(); - _UninitKeyEventSink(); - _UninitPreservedKey(); + _UninitKeyEventSink(); + _UninitPreservedKey(); - _UninitLanguageBar(); + _UninitLanguageBar(); - _UninitCompartment(); + _UninitCompartment(); - _pThreadMgr = NULL; + _pThreadMgr = NULL; - _tfClientId = TF_CLIENTID_NULL; + _tfClientId = TF_CLIENTID_NULL; - _cand->Destroy(); + _cand->Destroy(); - return S_OK; + return S_OK; } -STDAPI WeaselTSF::ActivateEx(ITfThreadMgr *pThreadMgr, TfClientId tfClientId, DWORD dwFlags) -{ - com_ptr pDocMgrFocus; - _activateFlags = dwFlags; +STDAPI WeaselTSF::ActivateEx(ITfThreadMgr* pThreadMgr, + TfClientId tfClientId, + DWORD dwFlags) { + com_ptr pDocMgrFocus; + _activateFlags = dwFlags; - _pThreadMgr = pThreadMgr; - _tfClientId = tfClientId; + _pThreadMgr = pThreadMgr; + _tfClientId = tfClientId; - if (!_InitThreadMgrEventSink()) - goto ExitError; + if (!_InitThreadMgrEventSink()) + goto ExitError; - if ((_pThreadMgr->GetFocus(&pDocMgrFocus) == S_OK) && (pDocMgrFocus != NULL)) - { - _InitTextEditSink(pDocMgrFocus); - } + if ((_pThreadMgr->GetFocus(&pDocMgrFocus) == S_OK) && + (pDocMgrFocus != NULL)) { + _InitTextEditSink(pDocMgrFocus); + } - if (!_InitKeyEventSink()) - goto ExitError; + if (!_InitKeyEventSink()) + goto ExitError; - //if (!_InitDisplayAttributeGuidAtom()) - // goto ExitError; - // some app might init failed because it not provide DisplayAttributeInfo, like some opengl stuff - _InitDisplayAttributeGuidAtom(); + // if (!_InitDisplayAttributeGuidAtom()) + // goto ExitError; + // some app might init failed because it not provide DisplayAttributeInfo, + // like some opengl stuff + _InitDisplayAttributeGuidAtom(); - if (!_InitPreservedKey()) - goto ExitError; + if (!_InitPreservedKey()) + goto ExitError; - if (!_InitLanguageBar()) - goto ExitError; + if (!_InitLanguageBar()) + goto ExitError; - if (!_IsKeyboardOpen()) - _SetKeyboardOpen(TRUE); + if (!_IsKeyboardOpen()) + _SetKeyboardOpen(TRUE); - if (!_InitCompartment()) - goto ExitError; + if (!_InitCompartment()) + goto ExitError; - _EnsureServerConnected(); + _EnsureServerConnected(); - return S_OK; + return S_OK; ExitError: - Deactivate(); - return E_FAIL; + Deactivate(); + return E_FAIL; } -STDMETHODIMP WeaselTSF::OnSetThreadFocus() -{ - return S_OK; +STDMETHODIMP WeaselTSF::OnSetThreadFocus() { + return S_OK; } -STDMETHODIMP WeaselTSF::OnKillThreadFocus() -{ - _AbortComposition(); - return S_OK; +STDMETHODIMP WeaselTSF::OnKillThreadFocus() { + _AbortComposition(); + return S_OK; } -STDMETHODIMP WeaselTSF::OnActivated(REFCLSID clsid, REFGUID guidProfile, BOOL isActivated) -{ - if (!IsEqualCLSID(clsid, c_clsidTextService)) - { - return S_OK; - } - - if (isActivated) { - _ShowLanguageBar(TRUE); - } - else { - _DeleteCandidateList(); - _ShowLanguageBar(FALSE); - } - return S_OK; +STDMETHODIMP WeaselTSF::OnActivated(REFCLSID clsid, + REFGUID guidProfile, + BOOL isActivated) { + if (!IsEqualCLSID(clsid, c_clsidTextService)) { + return S_OK; + } + + if (isActivated) { + _ShowLanguageBar(TRUE); + } else { + _DeleteCandidateList(); + _ShowLanguageBar(FALSE); + } + return S_OK; } -void WeaselTSF::_EnsureServerConnected() -{ - if (!m_client.Echo()) - { - m_client.Disconnect(); - m_client.Connect(NULL); - m_client.StartSession(); - weasel::ResponseParser parser(NULL, NULL, &_status, NULL, &_cand->style()); - bool ok = m_client.GetResponseData(std::ref(parser)); - if (ok) { - _UpdateLanguageBar(_status); - } - } +void WeaselTSF::_EnsureServerConnected() { + if (!m_client.Echo()) { + m_client.Disconnect(); + m_client.Connect(NULL); + m_client.StartSession(); + weasel::ResponseParser parser(NULL, NULL, &_status, NULL, &_cand->style()); + bool ok = m_client.GetResponseData(std::ref(parser)); + if (ok) { + _UpdateLanguageBar(_status); + } + } } diff --git a/WeaselTSF/WeaselTSF.h b/WeaselTSF/WeaselTSF.h index 1048fc605..53e9b4bbb 100644 --- a/WeaselTSF/WeaselTSF.h +++ b/WeaselTSF/WeaselTSF.h @@ -8,187 +8,219 @@ class CCandidateList; class CLangBarItemButton; class CCompartmentEventSink; -class WeaselTSF: - public ITfTextInputProcessorEx, - public ITfThreadMgrEventSink, - public ITfTextEditSink, - public ITfTextLayoutSink, - public ITfKeyEventSink, - public ITfCompositionSink, - public ITfThreadFocusSink, - public ITfActiveLanguageProfileNotifySink, - public ITfEditSession, - public ITfDisplayAttributeProvider -{ -public: - WeaselTSF(); - ~WeaselTSF(); - - /* IUnknown */ - STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject); - STDMETHODIMP_(ULONG) AddRef(); - STDMETHODIMP_(ULONG) Release(); - - /* ITfTextInputProcessor */ - STDMETHODIMP Activate(ITfThreadMgr *pThreadMgr, TfClientId tfClientId); - STDMETHODIMP Deactivate(); - - /* ITfTextInputProcessorEx */ - STDMETHODIMP ActivateEx(ITfThreadMgr *pThreadMgr, TfClientId tfClientId, DWORD dwFlags); - - /* ITfThreadMgrEventSink */ - STDMETHODIMP OnInitDocumentMgr(ITfDocumentMgr *pDocMgr); - STDMETHODIMP OnUninitDocumentMgr(ITfDocumentMgr *pDocMgr); - STDMETHODIMP OnSetFocus(ITfDocumentMgr *pDocMgrFocus, ITfDocumentMgr *pDocMgrPrevFocus); - STDMETHODIMP OnPushContext(ITfContext *pContext); - STDMETHODIMP OnPopContext(ITfContext *pContext); - - /* ITfTextEditSink */ - STDMETHODIMP OnEndEdit(ITfContext *pic, TfEditCookie ecReadOnly, ITfEditRecord *pEditRecord); - - /* ITfTextLayoutSink */ - STDMETHODIMP OnLayoutChange(ITfContext *pContext, TfLayoutCode lcode, ITfContextView *pContextView); - - /* ITfKeyEventSink */ - STDMETHODIMP OnSetFocus(BOOL fForeground); - STDMETHODIMP OnTestKeyDown(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten); - STDMETHODIMP OnKeyDown(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten); - STDMETHODIMP OnTestKeyUp(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten); - STDMETHODIMP OnKeyUp(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten); - STDMETHODIMP OnPreservedKey(ITfContext *pContext, REFGUID rguid, BOOL *pfEaten); - - // ITfThreadFocusSink - STDMETHODIMP OnSetThreadFocus(); - STDMETHODIMP OnKillThreadFocus(); - - /* ITfCompositionSink */ - STDMETHODIMP OnCompositionTerminated(TfEditCookie ecWrite, ITfComposition *pComposition); - - /* ITfEditSession */ - STDMETHODIMP DoEditSession(TfEditCookie ec); - - /* ITfActiveLanguageProfileNotifySink */ - STDMETHODIMP OnActivated(REFCLSID clsid, REFGUID guidProfile, BOOL isActivated); - - // ITfDisplayAttributeProvider - STDMETHODIMP EnumDisplayAttributeInfo(__RPC__deref_out_opt IEnumTfDisplayAttributeInfo** ppEnum); - STDMETHODIMP GetDisplayAttributeInfo(__RPC__in REFGUID guidInfo, __RPC__deref_out_opt ITfDisplayAttributeInfo** ppInfo); - - ///* ITfCompartmentEventSink */ - //STDMETHODIMP OnChange(_In_ REFGUID guid); - - /* Compartments */ - BOOL _IsKeyboardDisabled(); - BOOL _IsKeyboardOpen(); - HRESULT _SetKeyboardOpen(BOOL fOpen); - HRESULT _GetCompartmentDWORD(DWORD& value, const GUID guid); - HRESULT _SetCompartmentDWORD(const DWORD& value, const GUID guid); - - /* Composition */ - void _StartComposition(com_ptr pContext, BOOL fCUASWorkaroundEnabled); - void _EndComposition(com_ptr pContext, BOOL clear); - BOOL _ShowInlinePreedit(com_ptr pContext, const std::shared_ptr context); - void _UpdateComposition(com_ptr pContext); - BOOL _IsComposing(); - void _SetComposition(com_ptr pComposition); - void _SetCompositionPosition(const RECT &rc); - BOOL _UpdateCompositionWindow(com_ptr pContext); - void _FinalizeComposition(); - void _AbortComposition(bool clear = true); - - /* Language bar */ - HWND _GetFocusedContextWindow(); - void _HandleLangBarMenuSelect(UINT wID); - - /* IPC */ - void _EnsureServerConnected(); - - /* UI */ - void _UpdateUI(const weasel::Context & ctx, const weasel::Status & status); - void _StartUI(); - void _EndUI(); - void _ShowUI(); - void _HideUI(); - com_ptr _GetUIContextDocument(); - - /* Display Attribute */ - void _ClearCompositionDisplayAttributes(TfEditCookie ec, _In_ ITfContext* pContext); - BOOL _SetCompositionDisplayAttributes(TfEditCookie ec, _In_ ITfContext* pContext, ITfRange* pRangeComposition); - BOOL _InitDisplayAttributeGuidAtom(); - - - com_ptr _GetThreadMgr() { return _pThreadMgr; } - void HandleUICallback(size_t* const sel, size_t* const hov, bool* const next, bool* const scroll_next); - -private: - /* ui callback functions private */ - void _SelectCandidateOnCurrentPage(const size_t index); - void _HandleMouseHoverEvent(const size_t index); - void _HandleMousePageEvent( bool* const nextPage, bool* const scrollNextPage); - /* TSF Related */ - BOOL _InitThreadMgrEventSink(); - void _UninitThreadMgrEventSink(); +class WeaselTSF : public ITfTextInputProcessorEx, + public ITfThreadMgrEventSink, + public ITfTextEditSink, + public ITfTextLayoutSink, + public ITfKeyEventSink, + public ITfCompositionSink, + public ITfThreadFocusSink, + public ITfActiveLanguageProfileNotifySink, + public ITfEditSession, + public ITfDisplayAttributeProvider { + public: + WeaselTSF(); + ~WeaselTSF(); + + /* IUnknown */ + STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + /* ITfTextInputProcessor */ + STDMETHODIMP Activate(ITfThreadMgr* pThreadMgr, TfClientId tfClientId); + STDMETHODIMP Deactivate(); + + /* ITfTextInputProcessorEx */ + STDMETHODIMP ActivateEx(ITfThreadMgr* pThreadMgr, + TfClientId tfClientId, + DWORD dwFlags); + + /* ITfThreadMgrEventSink */ + STDMETHODIMP OnInitDocumentMgr(ITfDocumentMgr* pDocMgr); + STDMETHODIMP OnUninitDocumentMgr(ITfDocumentMgr* pDocMgr); + STDMETHODIMP OnSetFocus(ITfDocumentMgr* pDocMgrFocus, + ITfDocumentMgr* pDocMgrPrevFocus); + STDMETHODIMP OnPushContext(ITfContext* pContext); + STDMETHODIMP OnPopContext(ITfContext* pContext); + + /* ITfTextEditSink */ + STDMETHODIMP OnEndEdit(ITfContext* pic, + TfEditCookie ecReadOnly, + ITfEditRecord* pEditRecord); + + /* ITfTextLayoutSink */ + STDMETHODIMP OnLayoutChange(ITfContext* pContext, + TfLayoutCode lcode, + ITfContextView* pContextView); + + /* ITfKeyEventSink */ + STDMETHODIMP OnSetFocus(BOOL fForeground); + STDMETHODIMP OnTestKeyDown(ITfContext* pContext, + WPARAM wParam, + LPARAM lParam, + BOOL* pfEaten); + STDMETHODIMP OnKeyDown(ITfContext* pContext, + WPARAM wParam, + LPARAM lParam, + BOOL* pfEaten); + STDMETHODIMP OnTestKeyUp(ITfContext* pContext, + WPARAM wParam, + LPARAM lParam, + BOOL* pfEaten); + STDMETHODIMP OnKeyUp(ITfContext* pContext, + WPARAM wParam, + LPARAM lParam, + BOOL* pfEaten); + STDMETHODIMP OnPreservedKey(ITfContext* pContext, + REFGUID rguid, + BOOL* pfEaten); + + // ITfThreadFocusSink + STDMETHODIMP OnSetThreadFocus(); + STDMETHODIMP OnKillThreadFocus(); + + /* ITfCompositionSink */ + STDMETHODIMP OnCompositionTerminated(TfEditCookie ecWrite, + ITfComposition* pComposition); + + /* ITfEditSession */ + STDMETHODIMP DoEditSession(TfEditCookie ec); + + /* ITfActiveLanguageProfileNotifySink */ + STDMETHODIMP OnActivated(REFCLSID clsid, + REFGUID guidProfile, + BOOL isActivated); + + // ITfDisplayAttributeProvider + STDMETHODIMP EnumDisplayAttributeInfo( + __RPC__deref_out_opt IEnumTfDisplayAttributeInfo** ppEnum); + STDMETHODIMP GetDisplayAttributeInfo( + __RPC__in REFGUID guidInfo, + __RPC__deref_out_opt ITfDisplayAttributeInfo** ppInfo); + + ///* ITfCompartmentEventSink */ + // STDMETHODIMP OnChange(_In_ REFGUID guid); + + /* Compartments */ + BOOL _IsKeyboardDisabled(); + BOOL _IsKeyboardOpen(); + HRESULT _SetKeyboardOpen(BOOL fOpen); + HRESULT _GetCompartmentDWORD(DWORD& value, const GUID guid); + HRESULT _SetCompartmentDWORD(const DWORD& value, const GUID guid); + + /* Composition */ + void _StartComposition(com_ptr pContext, + BOOL fCUASWorkaroundEnabled); + void _EndComposition(com_ptr pContext, BOOL clear); + BOOL _ShowInlinePreedit(com_ptr pContext, + const std::shared_ptr context); + void _UpdateComposition(com_ptr pContext); + BOOL _IsComposing(); + void _SetComposition(com_ptr pComposition); + void _SetCompositionPosition(const RECT& rc); + BOOL _UpdateCompositionWindow(com_ptr pContext); + void _FinalizeComposition(); + void _AbortComposition(bool clear = true); + + /* Language bar */ + HWND _GetFocusedContextWindow(); + void _HandleLangBarMenuSelect(UINT wID); + + /* IPC */ + void _EnsureServerConnected(); + + /* UI */ + void _UpdateUI(const weasel::Context& ctx, const weasel::Status& status); + void _StartUI(); + void _EndUI(); + void _ShowUI(); + void _HideUI(); + com_ptr _GetUIContextDocument(); + + /* Display Attribute */ + void _ClearCompositionDisplayAttributes(TfEditCookie ec, + _In_ ITfContext* pContext); + BOOL _SetCompositionDisplayAttributes(TfEditCookie ec, + _In_ ITfContext* pContext, + ITfRange* pRangeComposition); + BOOL _InitDisplayAttributeGuidAtom(); + + com_ptr _GetThreadMgr() { return _pThreadMgr; } + void HandleUICallback(size_t* const sel, + size_t* const hov, + bool* const next, + bool* const scroll_next); + + private: + /* ui callback functions private */ + void _SelectCandidateOnCurrentPage(const size_t index); + void _HandleMouseHoverEvent(const size_t index); + void _HandleMousePageEvent(bool* const nextPage, bool* const scrollNextPage); + /* TSF Related */ + BOOL _InitThreadMgrEventSink(); + void _UninitThreadMgrEventSink(); + + BOOL _InitTextEditSink(com_ptr pDocMgr); + + BOOL _InitKeyEventSink(); + void _UninitKeyEventSink(); + void _ProcessKeyEvent(WPARAM wParam, LPARAM lParam, BOOL* pfEaten); + + BOOL _InitPreservedKey(); + void _UninitPreservedKey(); + + BOOL _InitLanguageBar(); + void _UninitLanguageBar(); + void _UpdateLanguageBar(weasel::Status stat); + void _ShowLanguageBar(BOOL show); + void _EnableLanguageBar(BOOL enable); + + BOOL _InsertText(com_ptr pContext, const std::wstring& ext); + + void _DeleteCandidateList(); + + BOOL _InitCompartment(); + void _UninitCompartment(); + HRESULT _HandleCompartment(REFGUID guidCompartment); + + bool isImmersive() const { + return (_activateFlags & TF_TMF_IMMERSIVEMODE) != 0; + } + + com_ptr _pThreadMgr; + TfClientId _tfClientId; + DWORD _dwThreadMgrEventSinkCookie; + + com_ptr _pTextEditSinkContext; + DWORD _dwTextEditSinkCookie, _dwTextLayoutSinkCookie; + BYTE _lpbKeyState[256]; + BOOL _fTestKeyDownPending, _fTestKeyUpPending; + + com_ptr _pEditSessionContext; + std::wstring _editSessionText; + + com_ptr _pKeyboardCompartmentSink; + com_ptr _pConvertionCompartmentSink; + + com_ptr _pComposition; + + com_ptr _pLangBarButton; + + com_ptr _cand; + + LONG _cRef; // COM ref count + + /* CUAS Candidate Window Position Workaround */ + BOOL _fCUASWorkaroundTested, _fCUASWorkaroundEnabled; + + /* Weasel Related */ + weasel::Client m_client; + DWORD _activateFlags; - BOOL _InitTextEditSink(com_ptr pDocMgr); - - BOOL _InitKeyEventSink(); - void _UninitKeyEventSink(); - void _ProcessKeyEvent(WPARAM wParam, LPARAM lParam, BOOL *pfEaten); - - BOOL _InitPreservedKey(); - void _UninitPreservedKey(); - - BOOL _InitLanguageBar(); - void _UninitLanguageBar(); - void _UpdateLanguageBar(weasel::Status stat); - void _ShowLanguageBar(BOOL show); - void _EnableLanguageBar(BOOL enable); - - BOOL _InsertText(com_ptr pContext, const std::wstring& ext); + /* IME status */ + weasel::Status _status; - void _DeleteCandidateList(); - - BOOL _InitCompartment(); - void _UninitCompartment(); - HRESULT _HandleCompartment(REFGUID guidCompartment); - - bool isImmersive() const { - return (_activateFlags & TF_TMF_IMMERSIVEMODE) != 0; - } - - com_ptr _pThreadMgr; - TfClientId _tfClientId; - DWORD _dwThreadMgrEventSinkCookie; - - com_ptr _pTextEditSinkContext; - DWORD _dwTextEditSinkCookie, _dwTextLayoutSinkCookie; - BYTE _lpbKeyState[256]; - BOOL _fTestKeyDownPending, _fTestKeyUpPending; - - com_ptr _pEditSessionContext; - std::wstring _editSessionText; - - com_ptr _pKeyboardCompartmentSink; - com_ptr _pConvertionCompartmentSink; - - com_ptr _pComposition; - - com_ptr _pLangBarButton; - - com_ptr _cand; - - LONG _cRef; // COM ref count - - /* CUAS Candidate Window Position Workaround */ - BOOL _fCUASWorkaroundTested, _fCUASWorkaroundEnabled; - - /* Weasel Related */ - weasel::Client m_client; - DWORD _activateFlags; - - /* IME status */ - weasel::Status _status; - - // guidatom for the display attibute. - TfGuidAtom _gaDisplayAttributeInput; + // guidatom for the display attibute. + TfGuidAtom _gaDisplayAttributeInput; }; diff --git a/WeaselTSF/dllmain.cpp b/WeaselTSF/dllmain.cpp index 4ed9fbcb6..ad9f81a9d 100644 --- a/WeaselTSF/dllmain.cpp +++ b/WeaselTSF/dllmain.cpp @@ -2,20 +2,17 @@ #include "stdafx.h" #include "Globals.h" -BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID pvReserved) -{ - switch (dwReason) - { - case DLL_PROCESS_ATTACH: - g_hInst = hInstance; - if (!InitializeCriticalSectionAndSpinCount(&g_cs, 0)) - return FALSE; - break; +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID pvReserved) { + switch (dwReason) { + case DLL_PROCESS_ATTACH: + g_hInst = hInstance; + if (!InitializeCriticalSectionAndSpinCount(&g_cs, 0)) + return FALSE; + break; - case DLL_PROCESS_DETACH: - DeleteCriticalSection(&g_cs); - break; - } - return TRUE; + case DLL_PROCESS_DETACH: + DeleteCriticalSection(&g_cs); + break; + } + return TRUE; } - diff --git a/WeaselUI/DirectWriteResources.cpp b/WeaselUI/DirectWriteResources.cpp index 15c8ccc0e..4ae87edfd 100644 --- a/WeaselUI/DirectWriteResources.cpp +++ b/WeaselUI/DirectWriteResources.cpp @@ -5,346 +5,364 @@ #include using namespace weasel; -#define STYLEORWEIGHT (L":[^:]*[^a-f0-9:]+[^:]*") +#define STYLEORWEIGHT (L":[^:]*[^a-f0-9:]+[^:]*") -std::vector ws_split(const std::wstring& in, const std::wstring& delim) -{ - std::wregex re{ delim }; - return std::vector { - std::wsregex_token_iterator(in.begin(), in.end(), re, -1), - std::wsregex_token_iterator() - }; +std::vector ws_split(const std::wstring& in, + const std::wstring& delim) { + std::wregex re{delim}; + return std::vector{ + std::wsregex_token_iterator(in.begin(), in.end(), re, -1), + std::wsregex_token_iterator()}; } -std::vector c_split(const char* in, const char* delim) -{ - std::regex re{ delim }; - return std::vector { - std::cregex_token_iterator(in, in + strlen(in),re, -1), - std::cregex_token_iterator() - }; +std::vector c_split(const char* in, const char* delim) { + std::regex re{delim}; + return std::vector{ + std::cregex_token_iterator(in, in + strlen(in), re, -1), + std::cregex_token_iterator()}; } -std::vector wc_split(const wchar_t* in, const wchar_t* delim) -{ - std::wregex re{ delim }; - return std::vector { - std::wcregex_token_iterator(in, in + wcslen(in),re, -1), - std::wcregex_token_iterator() - }; +std::vector wc_split(const wchar_t* in, const wchar_t* delim) { + std::wregex re{delim}; + return std::vector{ + std::wcregex_token_iterator(in, in + wcslen(in), re, -1), + std::wcregex_token_iterator()}; } -DirectWriteResources::DirectWriteResources(weasel::UIStyle& style, UINT dpi = 96) : - _style(style), - dpiScaleX_(0), - dpiScaleY_(0), - pD2d1Factory(NULL), - pDWFactory(NULL), - pRenderTarget(NULL), - pBrush(NULL), - pTextLayout(NULL), - pPreeditTextFormat(NULL), - pTextFormat(NULL), - pLabelTextFormat(NULL), - pCommentTextFormat(NULL) -{ - D2D1_TEXT_ANTIALIAS_MODE mode = _style.antialias_mode <= 3 ? (D2D1_TEXT_ANTIALIAS_MODE)(_style.antialias_mode) : D2D1_TEXT_ANTIALIAS_MODE_FORCE_DWORD; // prepare d2d1 resources - HRESULT hResult = S_OK; - // create factory - if (pD2d1Factory == NULL) - hResult = ::D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, pD2d1Factory.GetAddressOf()); - // create IDWriteFactory - if (pDWFactory == NULL) - hResult = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast(pDWFactory.GetAddressOf())); - /* ID2D1HwndRenderTarget */ - if (pRenderTarget == NULL) - { - const D2D1_PIXEL_FORMAT format = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED); - const D2D1_RENDER_TARGET_PROPERTIES properties = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, format); - pD2d1Factory->CreateDCRenderTarget(&properties, &pRenderTarget); - pRenderTarget->SetTextAntialiasMode(mode); - pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); - } - pRenderTarget->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), pBrush.GetAddressOf()); - //get the dpi information - dpiScaleX_ = dpiScaleY_ = dpi; - dpiScaleX_ /= 72.0f; - dpiScaleY_ /= 72.0f; +DirectWriteResources::DirectWriteResources(weasel::UIStyle& style, + UINT dpi = 96) + : _style(style), + dpiScaleX_(0), + dpiScaleY_(0), + pD2d1Factory(NULL), + pDWFactory(NULL), + pRenderTarget(NULL), + pBrush(NULL), + pTextLayout(NULL), + pPreeditTextFormat(NULL), + pTextFormat(NULL), + pLabelTextFormat(NULL), + pCommentTextFormat(NULL) { + D2D1_TEXT_ANTIALIAS_MODE mode = + _style.antialias_mode <= 3 + ? (D2D1_TEXT_ANTIALIAS_MODE)(_style.antialias_mode) + : D2D1_TEXT_ANTIALIAS_MODE_FORCE_DWORD; // prepare d2d1 resources + HRESULT hResult = S_OK; + // create factory + if (pD2d1Factory == NULL) + hResult = ::D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, + pD2d1Factory.GetAddressOf()); + // create IDWriteFactory + if (pDWFactory == NULL) + hResult = DWriteCreateFactory( + DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), + reinterpret_cast(pDWFactory.GetAddressOf())); + /* ID2D1HwndRenderTarget */ + if (pRenderTarget == NULL) { + const D2D1_PIXEL_FORMAT format = D2D1::PixelFormat( + DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED); + const D2D1_RENDER_TARGET_PROPERTIES properties = + D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, format); + pD2d1Factory->CreateDCRenderTarget(&properties, &pRenderTarget); + pRenderTarget->SetTextAntialiasMode(mode); + pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); + } + pRenderTarget->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), + pBrush.GetAddressOf()); + // get the dpi information + dpiScaleX_ = dpiScaleY_ = dpi; + dpiScaleX_ /= 72.0f; + dpiScaleY_ /= 72.0f; - InitResources(style, dpi); + InitResources(style, dpi); } -DirectWriteResources::~DirectWriteResources() -{ - pPreeditTextFormat.Reset(); - pTextFormat.Reset(); - pLabelTextFormat.Reset(); - pCommentTextFormat.Reset(); - pTextLayout.Reset(); - pBrush.Reset(); - pRenderTarget.Reset(); - pDWFactory.Reset(); - pD2d1Factory.Reset(); +DirectWriteResources::~DirectWriteResources() { + pPreeditTextFormat.Reset(); + pTextFormat.Reset(); + pLabelTextFormat.Reset(); + pCommentTextFormat.Reset(); + pTextLayout.Reset(); + pBrush.Reset(); + pRenderTarget.Reset(); + pDWFactory.Reset(); + pD2d1Factory.Reset(); } -HRESULT DirectWriteResources::InitResources(const std::wstring& label_font_face, const int& label_font_point, - const std::wstring& font_face, const int& font_point, - const std::wstring& comment_font_face, const int& comment_font_point, const bool& vertical_text) -{ - // prepare d2d1 resources - pPreeditTextFormat.Reset(); - pTextFormat.Reset(); - pLabelTextFormat.Reset(); - pCommentTextFormat.Reset(); - DWRITE_WORD_WRAPPING wrapping = ((_style.max_width == 0 && _style.layout_type != UIStyle::LAYOUT_VERTICAL_TEXT) - || (_style.max_height == 0 && _style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT)) ? - DWRITE_WORD_WRAPPING_NO_WRAP : DWRITE_WORD_WRAPPING_CHARACTER; - DWRITE_FLOW_DIRECTION flow = _style.vertical_text_left_to_right ? DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT : DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT; +HRESULT DirectWriteResources::InitResources( + const std::wstring& label_font_face, + const int& label_font_point, + const std::wstring& font_face, + const int& font_point, + const std::wstring& comment_font_face, + const int& comment_font_point, + const bool& vertical_text) { + // prepare d2d1 resources + pPreeditTextFormat.Reset(); + pTextFormat.Reset(); + pLabelTextFormat.Reset(); + pCommentTextFormat.Reset(); + DWRITE_WORD_WRAPPING wrapping = + ((_style.max_width == 0 && + _style.layout_type != UIStyle::LAYOUT_VERTICAL_TEXT) || + (_style.max_height == 0 && + _style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT)) + ? DWRITE_WORD_WRAPPING_NO_WRAP + : DWRITE_WORD_WRAPPING_CHARACTER; + DWRITE_FLOW_DIRECTION flow = _style.vertical_text_left_to_right + ? DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT + : DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT; - HRESULT hResult = S_OK; - std::vector fontFaceStrVector; + HRESULT hResult = S_OK; + std::vector fontFaceStrVector; - // text font text format set up - fontFaceStrVector = ws_split(font_face, L","); - // set main font a invalid font name, to make every font range customizable - const std::wstring _mainFontFace = L"_InvalidFontName_"; - DWRITE_FONT_WEIGHT fontWeight = DWRITE_FONT_WEIGHT_NORMAL; - DWRITE_FONT_STYLE fontStyle = DWRITE_FONT_STYLE_NORMAL; - // setup font weight and font style by the first unit of font_face setting string - _ParseFontFace(font_face, fontWeight, fontStyle); - fontFaceStrVector[0] = std::regex_replace(fontFaceStrVector[0], std::wregex(STYLEORWEIGHT, std::wregex::icase), L""); - hResult = pDWFactory->CreateTextFormat(_mainFontFace.c_str(), NULL, - fontWeight, fontStyle, DWRITE_FONT_STRETCH_NORMAL, - font_point * dpiScaleX_, L"", reinterpret_cast(pTextFormat.GetAddressOf())); - if( pTextFormat != NULL) - { - if (vertical_text) - { - pTextFormat->SetFlowDirection(flow); - pTextFormat->SetReadingDirection(DWRITE_READING_DIRECTION_TOP_TO_BOTTOM); - pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); - } - else - pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); + // text font text format set up + fontFaceStrVector = ws_split(font_face, L","); + // set main font a invalid font name, to make every font range customizable + const std::wstring _mainFontFace = L"_InvalidFontName_"; + DWRITE_FONT_WEIGHT fontWeight = DWRITE_FONT_WEIGHT_NORMAL; + DWRITE_FONT_STYLE fontStyle = DWRITE_FONT_STYLE_NORMAL; + // setup font weight and font style by the first unit of font_face setting + // string + _ParseFontFace(font_face, fontWeight, fontStyle); + fontFaceStrVector[0] = + std::regex_replace(fontFaceStrVector[0], + std::wregex(STYLEORWEIGHT, std::wregex::icase), L""); + hResult = pDWFactory->CreateTextFormat( + _mainFontFace.c_str(), NULL, fontWeight, fontStyle, + DWRITE_FONT_STRETCH_NORMAL, font_point * dpiScaleX_, L"", + reinterpret_cast(pTextFormat.GetAddressOf())); + if (pTextFormat != NULL) { + if (vertical_text) { + pTextFormat->SetFlowDirection(flow); + pTextFormat->SetReadingDirection(DWRITE_READING_DIRECTION_TOP_TO_BOTTOM); + pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); + } else + pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); - pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); - pTextFormat->SetWordWrapping(wrapping); - _SetFontFallback(pTextFormat, fontFaceStrVector); - } - decltype(fontFaceStrVector)().swap(fontFaceStrVector); + pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); + pTextFormat->SetWordWrapping(wrapping); + _SetFontFallback(pTextFormat, fontFaceStrVector); + } + decltype(fontFaceStrVector)().swap(fontFaceStrVector); - fontFaceStrVector = ws_split(font_face, L","); - //_ParseFontFace(fontFaceStrVector[0], fontWeight, fontStyle); - fontFaceStrVector[0] = std::regex_replace(fontFaceStrVector[0], std::wregex(STYLEORWEIGHT, std::wregex::icase), L""); - hResult = pDWFactory->CreateTextFormat(_mainFontFace.c_str(), NULL, - fontWeight, fontStyle, DWRITE_FONT_STRETCH_NORMAL, - font_point * dpiScaleX_, L"", reinterpret_cast(pPreeditTextFormat.GetAddressOf())); - if( pPreeditTextFormat != NULL) - { - if (vertical_text) - { - pPreeditTextFormat->SetFlowDirection(flow); - pPreeditTextFormat->SetReadingDirection(DWRITE_READING_DIRECTION_TOP_TO_BOTTOM); - pPreeditTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); - } - else - pPreeditTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); - pPreeditTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); - pPreeditTextFormat->SetWordWrapping(wrapping); - _SetFontFallback(pPreeditTextFormat, fontFaceStrVector); - } - decltype(fontFaceStrVector)().swap(fontFaceStrVector); + fontFaceStrVector = ws_split(font_face, L","); + //_ParseFontFace(fontFaceStrVector[0], fontWeight, fontStyle); + fontFaceStrVector[0] = + std::regex_replace(fontFaceStrVector[0], + std::wregex(STYLEORWEIGHT, std::wregex::icase), L""); + hResult = pDWFactory->CreateTextFormat( + _mainFontFace.c_str(), NULL, fontWeight, fontStyle, + DWRITE_FONT_STRETCH_NORMAL, font_point * dpiScaleX_, L"", + reinterpret_cast(pPreeditTextFormat.GetAddressOf())); + if (pPreeditTextFormat != NULL) { + if (vertical_text) { + pPreeditTextFormat->SetFlowDirection(flow); + pPreeditTextFormat->SetReadingDirection( + DWRITE_READING_DIRECTION_TOP_TO_BOTTOM); + pPreeditTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); + } else + pPreeditTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); + pPreeditTextFormat->SetParagraphAlignment( + DWRITE_PARAGRAPH_ALIGNMENT_CENTER); + pPreeditTextFormat->SetWordWrapping(wrapping); + _SetFontFallback(pPreeditTextFormat, fontFaceStrVector); + } + decltype(fontFaceStrVector)().swap(fontFaceStrVector); - // label font text format set up - fontFaceStrVector = ws_split(label_font_face, L","); - // setup weight and style of label_font_face - _ParseFontFace(label_font_face, fontWeight, fontStyle); - fontFaceStrVector[0] = std::regex_replace(fontFaceStrVector[0], std::wregex(STYLEORWEIGHT, std::wregex::icase), L""); - hResult = pDWFactory->CreateTextFormat(_mainFontFace.c_str(), NULL, - fontWeight, fontStyle, DWRITE_FONT_STRETCH_NORMAL, - label_font_point * dpiScaleX_, L"", reinterpret_cast(pLabelTextFormat.GetAddressOf())); - if( pLabelTextFormat != NULL) - { - if (vertical_text) - { - pLabelTextFormat->SetFlowDirection(flow); - pLabelTextFormat->SetReadingDirection(DWRITE_READING_DIRECTION_TOP_TO_BOTTOM); - pLabelTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); - } - else - pLabelTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); - pLabelTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); - pLabelTextFormat->SetWordWrapping(wrapping); - _SetFontFallback(pLabelTextFormat, fontFaceStrVector); - } - decltype(fontFaceStrVector)().swap(fontFaceStrVector); + // label font text format set up + fontFaceStrVector = ws_split(label_font_face, L","); + // setup weight and style of label_font_face + _ParseFontFace(label_font_face, fontWeight, fontStyle); + fontFaceStrVector[0] = + std::regex_replace(fontFaceStrVector[0], + std::wregex(STYLEORWEIGHT, std::wregex::icase), L""); + hResult = pDWFactory->CreateTextFormat( + _mainFontFace.c_str(), NULL, fontWeight, fontStyle, + DWRITE_FONT_STRETCH_NORMAL, label_font_point * dpiScaleX_, L"", + reinterpret_cast(pLabelTextFormat.GetAddressOf())); + if (pLabelTextFormat != NULL) { + if (vertical_text) { + pLabelTextFormat->SetFlowDirection(flow); + pLabelTextFormat->SetReadingDirection( + DWRITE_READING_DIRECTION_TOP_TO_BOTTOM); + pLabelTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); + } else + pLabelTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); + pLabelTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); + pLabelTextFormat->SetWordWrapping(wrapping); + _SetFontFallback(pLabelTextFormat, fontFaceStrVector); + } + decltype(fontFaceStrVector)().swap(fontFaceStrVector); - // comment font text format set up - fontFaceStrVector = ws_split(comment_font_face, L","); - // setup weight and style of label_font_face - _ParseFontFace(comment_font_face, fontWeight, fontStyle); - fontFaceStrVector[0] = std::regex_replace(fontFaceStrVector[0], std::wregex(STYLEORWEIGHT, std::wregex::icase), L""); - hResult = pDWFactory->CreateTextFormat(_mainFontFace.c_str(), NULL, - fontWeight, fontStyle, DWRITE_FONT_STRETCH_NORMAL, - comment_font_point * dpiScaleX_, L"", reinterpret_cast(pCommentTextFormat.GetAddressOf())); - if( pCommentTextFormat != NULL) - { - if (vertical_text) - { - pCommentTextFormat->SetFlowDirection(flow); - pCommentTextFormat->SetReadingDirection(DWRITE_READING_DIRECTION_TOP_TO_BOTTOM); - pCommentTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); - } - else - pCommentTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); - pCommentTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); - pCommentTextFormat->SetWordWrapping(wrapping); - _SetFontFallback(pCommentTextFormat, fontFaceStrVector); - } - decltype(fontFaceStrVector)().swap(fontFaceStrVector); - return hResult; + // comment font text format set up + fontFaceStrVector = ws_split(comment_font_face, L","); + // setup weight and style of label_font_face + _ParseFontFace(comment_font_face, fontWeight, fontStyle); + fontFaceStrVector[0] = + std::regex_replace(fontFaceStrVector[0], + std::wregex(STYLEORWEIGHT, std::wregex::icase), L""); + hResult = pDWFactory->CreateTextFormat( + _mainFontFace.c_str(), NULL, fontWeight, fontStyle, + DWRITE_FONT_STRETCH_NORMAL, comment_font_point * dpiScaleX_, L"", + reinterpret_cast(pCommentTextFormat.GetAddressOf())); + if (pCommentTextFormat != NULL) { + if (vertical_text) { + pCommentTextFormat->SetFlowDirection(flow); + pCommentTextFormat->SetReadingDirection( + DWRITE_READING_DIRECTION_TOP_TO_BOTTOM); + pCommentTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); + } else + pCommentTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); + pCommentTextFormat->SetParagraphAlignment( + DWRITE_PARAGRAPH_ALIGNMENT_CENTER); + pCommentTextFormat->SetWordWrapping(wrapping); + _SetFontFallback(pCommentTextFormat, fontFaceStrVector); + } + decltype(fontFaceStrVector)().swap(fontFaceStrVector); + return hResult; } -HRESULT DirectWriteResources::InitResources(const UIStyle& style, const UINT& dpi = 96) -{ - _style = style; - if(dpi) - { - dpiScaleX_ = dpi / 72.0f; - dpiScaleY_ = dpi / 72.0f; - } - return InitResources(style.label_font_face, style.label_font_point, style.font_face, style.font_point, - style.comment_font_face, style.comment_font_point, style.layout_type==UIStyle::LAYOUT_VERTICAL_TEXT); +HRESULT DirectWriteResources::InitResources(const UIStyle& style, + const UINT& dpi = 96) { + _style = style; + if (dpi) { + dpiScaleX_ = dpi / 72.0f; + dpiScaleY_ = dpi / 72.0f; + } + return InitResources(style.label_font_face, style.label_font_point, + style.font_face, style.font_point, + style.comment_font_face, style.comment_font_point, + style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT); } -void weasel::DirectWriteResources::SetDpi(const UINT& dpi) -{ - dpiScaleX_ = dpi / 72.0f; - dpiScaleY_ = dpi / 72.0f; - - pPreeditTextFormat.Reset(); - pTextFormat.Reset(); - pLabelTextFormat.Reset(); - pCommentTextFormat.Reset(); - InitResources(_style); +void weasel::DirectWriteResources::SetDpi(const UINT& dpi) { + dpiScaleX_ = dpi / 72.0f; + dpiScaleY_ = dpi / 72.0f; + + pPreeditTextFormat.Reset(); + pTextFormat.Reset(); + pLabelTextFormat.Reset(); + pCommentTextFormat.Reset(); + InitResources(_style); } -static std::wstring _MatchWordsOutLowerCaseTrim1st(const std::wstring& wstr, const std::wstring& pat) -{ - std::wstring mat = L""; - std::wsmatch mc; - std::wregex pattern(pat, std::wregex::icase); - std::wstring::const_iterator iter = wstr.cbegin(); - std::wstring::const_iterator end = wstr.cend(); - while (regex_search(iter, end, mc, pattern)) { - for (const auto& m : mc) { - mat = m; - mat = mat.substr(1); - break; - } - iter = mc.suffix().first; - } - std::wstring res; - std::transform(mat.begin(), mat.end(), std::back_inserter(res), ::tolower); - return res; +static std::wstring _MatchWordsOutLowerCaseTrim1st(const std::wstring& wstr, + const std::wstring& pat) { + std::wstring mat = L""; + std::wsmatch mc; + std::wregex pattern(pat, std::wregex::icase); + std::wstring::const_iterator iter = wstr.cbegin(); + std::wstring::const_iterator end = wstr.cend(); + while (regex_search(iter, end, mc, pattern)) { + for (const auto& m : mc) { + mat = m; + mat = mat.substr(1); + break; + } + iter = mc.suffix().first; + } + std::wstring res; + std::transform(mat.begin(), mat.end(), std::back_inserter(res), ::tolower); + return res; } -void DirectWriteResources::_ParseFontFace(const std::wstring& fontFaceStr, DWRITE_FONT_WEIGHT& fontWeight, DWRITE_FONT_STYLE& fontStyle) -{ - const std::wstring patWeight(L"(:thin|:extra_light|:ultra_light|:light|:semi_light|:medium|:demi_bold|:semi_bold|:bold|:extra_bold|:ultra_bold|:black|:heavy|:extra_black|:ultra_black)"); - const std::map _mapWeight = { - {L"thin", DWRITE_FONT_WEIGHT_THIN}, - {L"extra_light", DWRITE_FONT_WEIGHT_EXTRA_LIGHT}, - {L"ultra_light", DWRITE_FONT_WEIGHT_ULTRA_LIGHT}, - {L"light", DWRITE_FONT_WEIGHT_LIGHT}, - {L"semi_light", DWRITE_FONT_WEIGHT_SEMI_LIGHT}, - {L"medium", DWRITE_FONT_WEIGHT_MEDIUM}, - {L"demi_bold", DWRITE_FONT_WEIGHT_DEMI_BOLD}, - {L"semi_bold", DWRITE_FONT_WEIGHT_SEMI_BOLD}, - {L"bold", DWRITE_FONT_WEIGHT_BOLD}, - {L"extra_bold", DWRITE_FONT_WEIGHT_EXTRA_BOLD}, - {L"ultra_bold", DWRITE_FONT_WEIGHT_ULTRA_BOLD}, - {L"black", DWRITE_FONT_WEIGHT_BLACK}, - {L"heavy", DWRITE_FONT_WEIGHT_HEAVY}, - {L"extra_black", DWRITE_FONT_WEIGHT_EXTRA_BLACK}, - {L"normal", DWRITE_FONT_WEIGHT_NORMAL}, - {L"ultra_black", DWRITE_FONT_WEIGHT_ULTRA_BLACK} - }; - std::wstring weight = _MatchWordsOutLowerCaseTrim1st(fontFaceStr, patWeight); - auto it = _mapWeight.find(weight); - fontWeight = (it != _mapWeight.end()) ? it->second : DWRITE_FONT_WEIGHT_NORMAL; +void DirectWriteResources::_ParseFontFace(const std::wstring& fontFaceStr, + DWRITE_FONT_WEIGHT& fontWeight, + DWRITE_FONT_STYLE& fontStyle) { + const std::wstring patWeight( + L"(:thin|:extra_light|:ultra_light|:light|:semi_light|:medium|:demi_bold|" + L":semi_bold|:bold|:extra_bold|:ultra_bold|:black|:heavy|:extra_black|:" + L"ultra_black)"); + const std::map _mapWeight = { + {L"thin", DWRITE_FONT_WEIGHT_THIN}, + {L"extra_light", DWRITE_FONT_WEIGHT_EXTRA_LIGHT}, + {L"ultra_light", DWRITE_FONT_WEIGHT_ULTRA_LIGHT}, + {L"light", DWRITE_FONT_WEIGHT_LIGHT}, + {L"semi_light", DWRITE_FONT_WEIGHT_SEMI_LIGHT}, + {L"medium", DWRITE_FONT_WEIGHT_MEDIUM}, + {L"demi_bold", DWRITE_FONT_WEIGHT_DEMI_BOLD}, + {L"semi_bold", DWRITE_FONT_WEIGHT_SEMI_BOLD}, + {L"bold", DWRITE_FONT_WEIGHT_BOLD}, + {L"extra_bold", DWRITE_FONT_WEIGHT_EXTRA_BOLD}, + {L"ultra_bold", DWRITE_FONT_WEIGHT_ULTRA_BOLD}, + {L"black", DWRITE_FONT_WEIGHT_BLACK}, + {L"heavy", DWRITE_FONT_WEIGHT_HEAVY}, + {L"extra_black", DWRITE_FONT_WEIGHT_EXTRA_BLACK}, + {L"normal", DWRITE_FONT_WEIGHT_NORMAL}, + {L"ultra_black", DWRITE_FONT_WEIGHT_ULTRA_BLACK}}; + std::wstring weight = _MatchWordsOutLowerCaseTrim1st(fontFaceStr, patWeight); + auto it = _mapWeight.find(weight); + fontWeight = + (it != _mapWeight.end()) ? it->second : DWRITE_FONT_WEIGHT_NORMAL; - const std::wstring patStyle(L"(:italic|:oblique|:normal)"); - const std::map _mapStyle = { - {L"italic", DWRITE_FONT_STYLE_ITALIC}, - {L"oblique", DWRITE_FONT_STYLE_OBLIQUE}, - {L"normal", DWRITE_FONT_STYLE_NORMAL}, - }; - std::wstring style = _MatchWordsOutLowerCaseTrim1st(fontFaceStr, patStyle); - auto it2 = _mapStyle.find(style); - fontStyle = (it2 != _mapStyle.end()) ? it2->second : DWRITE_FONT_STYLE_NORMAL; + const std::wstring patStyle(L"(:italic|:oblique|:normal)"); + const std::map _mapStyle = { + {L"italic", DWRITE_FONT_STYLE_ITALIC}, + {L"oblique", DWRITE_FONT_STYLE_OBLIQUE}, + {L"normal", DWRITE_FONT_STYLE_NORMAL}, + }; + std::wstring style = _MatchWordsOutLowerCaseTrim1st(fontFaceStr, patStyle); + auto it2 = _mapStyle.find(style); + fontStyle = (it2 != _mapStyle.end()) ? it2->second : DWRITE_FONT_STYLE_NORMAL; } -void DirectWriteResources::_SetFontFallback(ComPtr textFormat, const std::vector& fontVector) -{ - ComPtr pSysFallback; - pDWFactory->GetSystemFontFallback(pSysFallback.GetAddressOf()); - ComPtr pFontFallback = NULL; - ComPtr pFontFallbackBuilder = NULL; - pDWFactory->CreateFontFallbackBuilder(pFontFallbackBuilder.GetAddressOf()); - std::vector fallbackFontsVector; - for (UINT32 i = 0; i < fontVector.size(); i++) - { - fallbackFontsVector = ws_split(fontVector[i], L":"); - std::wstring _fontFaceWstr, firstWstr, lastWstr; - if (fallbackFontsVector.size() == 3) - { - _fontFaceWstr = fallbackFontsVector[0]; - firstWstr = fallbackFontsVector[1]; - lastWstr = fallbackFontsVector[2]; - if (lastWstr.empty()) - lastWstr = L"10ffff"; - if (firstWstr.empty()) - firstWstr = L"0"; - } - else if (fallbackFontsVector.size() == 2) // fontName : codepoint - { - _fontFaceWstr = fallbackFontsVector[0]; - firstWstr = fallbackFontsVector[1]; - if (firstWstr.empty()) - firstWstr = L"0"; - lastWstr = L"10ffff"; - } - else if (fallbackFontsVector.size() == 1) // if only font defined, use all range - { - _fontFaceWstr = fallbackFontsVector[0]; - firstWstr = L"0"; - lastWstr = L"10ffff"; - } - UINT first = 0, last = 0x10ffff; - try { - first = std::stoi(firstWstr.c_str(), 0, 16); - } - catch(...){ - first = 0; - } - try { - last = std::stoi(lastWstr.c_str(), 0, 16); - } - catch(...){ - last = 0x10ffff; - } - DWRITE_UNICODE_RANGE range = { first, last }; - const WCHAR* familys = { _fontFaceWstr.c_str() }; - pFontFallbackBuilder->AddMapping(&range, 1, &familys, 1); - decltype(fallbackFontsVector)().swap(fallbackFontsVector); - } - // add system defalt font fallback - pFontFallbackBuilder->AddMappings(pSysFallback.Get()); - pFontFallbackBuilder->CreateFontFallback(pFontFallback.GetAddressOf()); - textFormat->SetFontFallback(pFontFallback.Get()); - decltype(fallbackFontsVector)().swap(fallbackFontsVector); - pFontFallback.Reset(); - pSysFallback.Reset(); - pFontFallbackBuilder.Reset(); +void DirectWriteResources::_SetFontFallback( + ComPtr textFormat, + const std::vector& fontVector) { + ComPtr pSysFallback; + pDWFactory->GetSystemFontFallback(pSysFallback.GetAddressOf()); + ComPtr pFontFallback = NULL; + ComPtr pFontFallbackBuilder = NULL; + pDWFactory->CreateFontFallbackBuilder(pFontFallbackBuilder.GetAddressOf()); + std::vector fallbackFontsVector; + for (UINT32 i = 0; i < fontVector.size(); i++) { + fallbackFontsVector = ws_split(fontVector[i], L":"); + std::wstring _fontFaceWstr, firstWstr, lastWstr; + if (fallbackFontsVector.size() == 3) { + _fontFaceWstr = fallbackFontsVector[0]; + firstWstr = fallbackFontsVector[1]; + lastWstr = fallbackFontsVector[2]; + if (lastWstr.empty()) + lastWstr = L"10ffff"; + if (firstWstr.empty()) + firstWstr = L"0"; + } else if (fallbackFontsVector.size() == 2) // fontName : codepoint + { + _fontFaceWstr = fallbackFontsVector[0]; + firstWstr = fallbackFontsVector[1]; + if (firstWstr.empty()) + firstWstr = L"0"; + lastWstr = L"10ffff"; + } else if (fallbackFontsVector.size() == + 1) // if only font defined, use all range + { + _fontFaceWstr = fallbackFontsVector[0]; + firstWstr = L"0"; + lastWstr = L"10ffff"; + } + UINT first = 0, last = 0x10ffff; + try { + first = std::stoi(firstWstr.c_str(), 0, 16); + } catch (...) { + first = 0; + } + try { + last = std::stoi(lastWstr.c_str(), 0, 16); + } catch (...) { + last = 0x10ffff; + } + DWRITE_UNICODE_RANGE range = {first, last}; + const WCHAR* familys = {_fontFaceWstr.c_str()}; + pFontFallbackBuilder->AddMapping(&range, 1, &familys, 1); + decltype(fallbackFontsVector)().swap(fallbackFontsVector); + } + // add system defalt font fallback + pFontFallbackBuilder->AddMappings(pSysFallback.Get()); + pFontFallbackBuilder->CreateFontFallback(pFontFallback.GetAddressOf()); + textFormat->SetFontFallback(pFontFallback.Get()); + decltype(fallbackFontsVector)().swap(fallbackFontsVector); + pFontFallback.Reset(); + pSysFallback.Reset(); + pFontFallbackBuilder.Reset(); } diff --git a/WeaselUI/FullScreenLayout.cpp b/WeaselUI/FullScreenLayout.cpp index 6dd98a905..f3564db94 100644 --- a/WeaselUI/FullScreenLayout.cpp +++ b/WeaselUI/FullScreenLayout.cpp @@ -3,126 +3,127 @@ using namespace weasel; -void weasel::FullScreenLayout::DoLayout(CDCHandle dc, PDWR pDWR) -{ - if (_context.empty()) - { - int width = 0, height = 0; - UpdateStatusIconLayout(&width, &height); - _contentSize.SetSize(width, height); - return; - } +void weasel::FullScreenLayout::DoLayout(CDCHandle dc, PDWR pDWR) { + if (_context.empty()) { + int width = 0, height = 0; + UpdateStatusIconLayout(&width, &height); + _contentSize.SetSize(width, height); + return; + } - CRect workArea; - HMONITOR hMonitor = MonitorFromRect(mr_inputPos, MONITOR_DEFAULTTONEAREST); - if (hMonitor) - { - MONITORINFO info; - info.cbSize = sizeof(MONITORINFO); - if (GetMonitorInfo(hMonitor, &info)) - { - workArea = info.rcWork; - } - } + CRect workArea; + HMONITOR hMonitor = MonitorFromRect(mr_inputPos, MONITOR_DEFAULTTONEAREST); + if (hMonitor) { + MONITORINFO info; + info.cbSize = sizeof(MONITORINFO); + if (GetMonitorInfo(hMonitor, &info)) { + workArea = info.rcWork; + } + } - int step = 32; - do { - m_layout->DoLayout(dc, pDWR); - if ((_style.hilited_mark_color & 0xff000000)) - { - CSize sg; - if(_style.mark_text.empty()) - GetTextSizeDW(L"|", 1, pDWR->pTextFormat, pDWR, &sg); - else - GetTextSizeDW(_style.mark_text, _style.mark_text.length(), pDWR->pTextFormat, pDWR, &sg); - MARK_WIDTH = sg.cx; - MARK_HEIGHT = sg.cy; - if(_style.mark_text.empty()) - MARK_WIDTH /= 2; - MARK_GAP = (_style.mark_text.empty()) ? MARK_WIDTH : MARK_WIDTH + _style.hilite_spacing; - } - } - while (AdjustFontPoint(dc, workArea, step, pDWR)); + int step = 32; + do { + m_layout->DoLayout(dc, pDWR); + if ((_style.hilited_mark_color & 0xff000000)) { + CSize sg; + if (_style.mark_text.empty()) + GetTextSizeDW(L"|", 1, pDWR->pTextFormat, pDWR, &sg); + else + GetTextSizeDW(_style.mark_text, _style.mark_text.length(), + pDWR->pTextFormat, pDWR, &sg); + MARK_WIDTH = sg.cx; + MARK_HEIGHT = sg.cy; + if (_style.mark_text.empty()) + MARK_WIDTH /= 2; + MARK_GAP = (_style.mark_text.empty()) + ? MARK_WIDTH + : MARK_WIDTH + _style.hilite_spacing; + } + } while (AdjustFontPoint(dc, workArea, step, pDWR)); - int offsetx = (workArea.Width() - m_layout->GetContentSize().cx) / 2; - int offsety = (workArea.Height() - m_layout->GetContentSize().cy) / 2; - _preeditRect = m_layout->GetPreeditRect(); - _preeditRect.OffsetRect(offsetx, offsety); - _auxiliaryRect = m_layout->GetAuxiliaryRect(); - _auxiliaryRect.OffsetRect(offsetx, offsety); - _highlightRect = m_layout->GetHighlightRect(); - _highlightRect.OffsetRect(offsetx, offsety); + int offsetx = (workArea.Width() - m_layout->GetContentSize().cx) / 2; + int offsety = (workArea.Height() - m_layout->GetContentSize().cy) / 2; + _preeditRect = m_layout->GetPreeditRect(); + _preeditRect.OffsetRect(offsetx, offsety); + _auxiliaryRect = m_layout->GetAuxiliaryRect(); + _auxiliaryRect.OffsetRect(offsetx, offsety); + _highlightRect = m_layout->GetHighlightRect(); + _highlightRect.OffsetRect(offsetx, offsety); - _prePageRect = m_layout->GetPrepageRect(); - _prePageRect.OffsetRect(offsetx, offsety); - _nextPageRect = m_layout->GetNextpageRect(); - _nextPageRect.OffsetRect(offsetx, offsety); + _prePageRect = m_layout->GetPrepageRect(); + _prePageRect.OffsetRect(offsetx, offsety); + _nextPageRect = m_layout->GetNextpageRect(); + _nextPageRect.OffsetRect(offsetx, offsety); - for (auto i = 0, n = (int)_context.cinfo.candies.size(); i < n && i < MAX_CANDIDATES_COUNT; ++i) - { - _candidateLabelRects[i] = m_layout->GetCandidateLabelRect(i); - _candidateLabelRects[i].OffsetRect(offsetx, offsety); - _candidateTextRects[i] = m_layout->GetCandidateTextRect(i); - _candidateTextRects[i].OffsetRect(offsetx, offsety); - _candidateCommentRects[i] = m_layout->GetCandidateCommentRect(i); - _candidateCommentRects[i].OffsetRect(offsetx, offsety); - _candidateRects[i] = m_layout->GetCandidateRect(i); - _candidateRects[i].OffsetRect(offsetx, offsety); - } - _statusIconRect = m_layout->GetStatusIconRect(); + for (auto i = 0, n = (int)_context.cinfo.candies.size(); + i < n && i < MAX_CANDIDATES_COUNT; ++i) { + _candidateLabelRects[i] = m_layout->GetCandidateLabelRect(i); + _candidateLabelRects[i].OffsetRect(offsetx, offsety); + _candidateTextRects[i] = m_layout->GetCandidateTextRect(i); + _candidateTextRects[i].OffsetRect(offsetx, offsety); + _candidateCommentRects[i] = m_layout->GetCandidateCommentRect(i); + _candidateCommentRects[i].OffsetRect(offsetx, offsety); + _candidateRects[i] = m_layout->GetCandidateRect(i); + _candidateRects[i].OffsetRect(offsetx, offsety); + } + _statusIconRect = m_layout->GetStatusIconRect(); - _contentSize.SetSize(workArea.Width(), workArea.Height()); - _contentRect.SetRect(0, 0, workArea.Width(), workArea.Height()); - _contentRect.DeflateRect(offsetX, offsetY); + _contentSize.SetSize(workArea.Width(), workArea.Height()); + _contentRect.SetRect(0, 0, workArea.Width(), workArea.Height()); + _contentRect.DeflateRect(offsetX, offsetY); } -bool FullScreenLayout::AdjustFontPoint(CDCHandle dc, const CRect& workArea, int& step, PDWR pDWR) -{ - if (_context.empty() || step == 0) - return false; - { - int fontPointLabel; - int fontPoint; - int fontPointComment; +bool FullScreenLayout::AdjustFontPoint(CDCHandle dc, + const CRect& workArea, + int& step, + PDWR pDWR) { + if (_context.empty() || step == 0) + return false; + { + int fontPointLabel; + int fontPoint; + int fontPointComment; - if (pDWR->pLabelTextFormat != NULL) - fontPointLabel = pDWR->pLabelTextFormat->GetFontSize() / pDWR->dpiScaleX_; - else - fontPointLabel = 0; - if (pDWR->pTextFormat != NULL) - fontPoint = pDWR->pTextFormat->GetFontSize() / pDWR->dpiScaleX_; - else - fontPoint = 0; - if (pDWR->pCommentTextFormat != NULL) - fontPointComment = pDWR->pCommentTextFormat->GetFontSize() / pDWR->dpiScaleX_; - else - fontPointComment = 0; - CSize sz = m_layout->GetContentSize(); - if (sz.cx > workArea.Width() - offsetX * 2 || sz.cy > workArea.Height() - offsetY * 2) - { - if (step > 0) - { - step = -(step >> 1); - } - fontPoint += step; - fontPointLabel += step; - fontPointComment += step; - pDWR->InitResources(_style.label_font_face, fontPointLabel, _style.font_face, fontPoint, _style.comment_font_face, fontPointComment); - return true; - } - else if (sz.cx <= (workArea.Width() - offsetX * 2) * 31 / 32 && sz.cy <= (workArea.Height() - offsetY * 2) * 31 / 32) - { - if (step < 0) - { - step = -step >> 1; - } - fontPoint += step; - fontPointLabel += step; - fontPointComment += step; - pDWR->InitResources(_style.label_font_face, fontPointLabel, _style.font_face, fontPoint, _style.comment_font_face, fontPointComment); - return true; - } + if (pDWR->pLabelTextFormat != NULL) + fontPointLabel = pDWR->pLabelTextFormat->GetFontSize() / pDWR->dpiScaleX_; + else + fontPointLabel = 0; + if (pDWR->pTextFormat != NULL) + fontPoint = pDWR->pTextFormat->GetFontSize() / pDWR->dpiScaleX_; + else + fontPoint = 0; + if (pDWR->pCommentTextFormat != NULL) + fontPointComment = + pDWR->pCommentTextFormat->GetFontSize() / pDWR->dpiScaleX_; + else + fontPointComment = 0; + CSize sz = m_layout->GetContentSize(); + if (sz.cx > workArea.Width() - offsetX * 2 || + sz.cy > workArea.Height() - offsetY * 2) { + if (step > 0) { + step = -(step >> 1); + } + fontPoint += step; + fontPointLabel += step; + fontPointComment += step; + pDWR->InitResources(_style.label_font_face, fontPointLabel, + _style.font_face, fontPoint, _style.comment_font_face, + fontPointComment); + return true; + } else if (sz.cx <= (workArea.Width() - offsetX * 2) * 31 / 32 && + sz.cy <= (workArea.Height() - offsetY * 2) * 31 / 32) { + if (step < 0) { + step = -step >> 1; + } + fontPoint += step; + fontPointLabel += step; + fontPointComment += step; + pDWR->InitResources(_style.label_font_face, fontPointLabel, + _style.font_face, fontPoint, _style.comment_font_face, + fontPointComment); + return true; + } - return false; - } + return false; + } } diff --git a/WeaselUI/FullScreenLayout.h b/WeaselUI/FullScreenLayout.h index c84a3e1dd..aee24f4d0 100644 --- a/WeaselUI/FullScreenLayout.h +++ b/WeaselUI/FullScreenLayout.h @@ -2,21 +2,28 @@ #include "StandardLayout.h" -namespace weasel -{ - class FullScreenLayout: public StandardLayout - { - public: - FullScreenLayout(const UIStyle &style, const Context &context, const Status &status, const CRect& inputPos, Layout* layout) - : StandardLayout(style, context, status), mr_inputPos(inputPos), m_layout(layout) { } - virtual ~FullScreenLayout(){ delete m_layout; } +namespace weasel { +class FullScreenLayout : public StandardLayout { + public: + FullScreenLayout(const UIStyle& style, + const Context& context, + const Status& status, + const CRect& inputPos, + Layout* layout) + : StandardLayout(style, context, status), + mr_inputPos(inputPos), + m_layout(layout) {} + virtual ~FullScreenLayout() { delete m_layout; } - virtual void DoLayout(CDCHandle dc, PDWR pDWR = NULL); + virtual void DoLayout(CDCHandle dc, PDWR pDWR = NULL); - private: - bool AdjustFontPoint(CDCHandle dc, const CRect& workArea, int& step, PDWR pDWR = NULL); + private: + bool AdjustFontPoint(CDCHandle dc, + const CRect& workArea, + int& step, + PDWR pDWR = NULL); - const CRect& mr_inputPos; - Layout* m_layout; - }; + const CRect& mr_inputPos; + Layout* m_layout; }; +}; // namespace weasel diff --git a/WeaselUI/GdiplusBlur.cpp b/WeaselUI/GdiplusBlur.cpp index 116fb41d8..23c4d3cbf 100644 --- a/WeaselUI/GdiplusBlur.cpp +++ b/WeaselUI/GdiplusBlur.cpp @@ -1,336 +1,361 @@ #include "stdafx.h" #include "GdiplusBlur.h" -namespace weasel{ -/* start image gauss blur functions from https://github.com/kenjinote/DropShadow/ */ -#define myround(x) (int)((x)+0.5) - -void boxesForGauss(double sigma, int* sizes, int n) -{ - double wIdeal = sqrt((12 * sigma * sigma / n) + 1); - int wl = (int)floor(wIdeal); - if (wl % 2 == 0) --wl; - - const double wu = (double)wl + 2; - - const double mIdeal = (12 * sigma * sigma - n * (LONGLONG)wl * wl - 4 *(LONGLONG)n * wl - 3 * (LONGLONG)n) / (-4 * (LONGLONG)wl - 4); - const int m = myround(mIdeal); +namespace weasel { +/* start image gauss blur functions from + * https://github.com/kenjinote/DropShadow/ */ +#define myround(x) (int)((x) + 0.5) + +void boxesForGauss(double sigma, int* sizes, int n) { + double wIdeal = sqrt((12 * sigma * sigma / n) + 1); + int wl = (int)floor(wIdeal); + if (wl % 2 == 0) + --wl; + + const double wu = (double)wl + 2; + + const double mIdeal = (12 * sigma * sigma - n * (LONGLONG)wl * wl - + 4 * (LONGLONG)n * wl - 3 * (LONGLONG)n) / + (-4 * (LONGLONG)wl - 4); + const int m = myround(mIdeal); + + for (int i = 0; i < n; ++i) + sizes[i] = int(i < m ? wl : wu); +} - for (int i = 0; i < n; ++i) - sizes[i] = int(i < m ? wl : wu); +void boxBlurH_4(BYTE* scl, + BYTE* tcl, + int w, + int h, + int r, + int bpp, + int stride) { + float iarr = (float)(1. / ((LONGLONG)r + r + 1)); + for (int i = 0; i < h; ++i) { + int ti1 = i * stride; + int ti2 = i * stride + 1; + int ti3 = i * stride + 2; + int ti4 = i * stride + 3; + + int li1 = ti1; + int li2 = ti2; + int li3 = ti3; + int li4 = ti4; + + int ri1 = ti1 + r * bpp; + int ri2 = ti2 + r * bpp; + int ri3 = ti3 + r * bpp; + int ri4 = ti4 + r * bpp; + + int fv1 = scl[ti1]; + int fv2 = scl[ti2]; + int fv3 = scl[ti3]; + int fv4 = scl[ti4]; + + int lv1 = scl[ti1 + (w - 1) * bpp]; + int lv2 = scl[ti2 + (w - 1) * bpp]; + int lv3 = scl[ti3 + (w - 1) * bpp]; + int lv4 = scl[ti4 + (w - 1) * bpp]; + + int val1 = (r + 1) * fv1; + int val2 = (r + 1) * fv2; + int val3 = (r + 1) * fv3; + int val4 = (r + 1) * fv4; + + for (int j = 0; j < r; ++j) { + val1 += scl[ti1 + j * bpp]; + val2 += scl[ti2 + j * bpp]; + val3 += scl[ti3 + j * bpp]; + val4 += scl[ti4 + j * bpp]; + } + + for (int j = 0; j <= r; ++j) { + val1 += scl[ri1] - fv1; + val2 += scl[ri2] - fv2; + val3 += scl[ri3] - fv3; + val4 += scl[ri4] - fv4; + + tcl[ti1] = myround(val1 * iarr); + tcl[ti2] = myround(val2 * iarr); + tcl[ti3] = myround(val3 * iarr); + tcl[ti4] = myround(val4 * iarr); + + ri1 += bpp; + ri2 += bpp; + ri3 += bpp; + ri4 += bpp; + + ti1 += bpp; + ti2 += bpp; + ti3 += bpp; + ti4 += bpp; + } + + for (int j = r + 1; j < w - r; ++j) { + val1 += scl[ri1] - scl[li1]; + val2 += scl[ri2] - scl[li2]; + val3 += scl[ri3] - scl[li3]; + val4 += scl[ri4] - scl[li4]; + + tcl[ti1] = myround(val1 * iarr); + tcl[ti2] = myround(val2 * iarr); + tcl[ti3] = myround(val3 * iarr); + tcl[ti4] = myround(val4 * iarr); + + ri1 += bpp; + ri2 += bpp; + ri3 += bpp; + ri4 += bpp; + + li1 += bpp; + li2 += bpp; + li3 += bpp; + li4 += bpp; + + ti1 += bpp; + ti2 += bpp; + ti3 += bpp; + ti4 += bpp; + } + + for (int j = w - r; j < w; ++j) { + val1 += lv1 - scl[li1]; + val2 += lv2 - scl[li2]; + val3 += lv3 - scl[li3]; + val4 += lv4 - scl[li4]; + + tcl[ti1] = myround(val1 * iarr); + tcl[ti2] = myround(val2 * iarr); + tcl[ti3] = myround(val3 * iarr); + tcl[ti4] = myround(val4 * iarr); + + li1 += bpp; + li2 += bpp; + li3 += bpp; + li4 += bpp; + + ti1 += bpp; + ti2 += bpp; + ti3 += bpp; + ti4 += bpp; + } + } } -void boxBlurH_4(BYTE* scl, BYTE* tcl, int w, int h, int r, int bpp, int stride) -{ - float iarr = (float)(1. / ((LONGLONG)r + r + 1)); - for (int i = 0; i < h; ++i) { - int ti1 = i * stride; - int ti2 = i * stride + 1; - int ti3 = i * stride + 2; - int ti4 = i * stride + 3; - - int li1 = ti1; - int li2 = ti2; - int li3 = ti3; - int li4 = ti4; - - int ri1 = ti1 + r * bpp; - int ri2 = ti2 + r * bpp; - int ri3 = ti3 + r * bpp; - int ri4 = ti4 + r * bpp; - - int fv1 = scl[ti1]; - int fv2 = scl[ti2]; - int fv3 = scl[ti3]; - int fv4 = scl[ti4]; - - int lv1 = scl[ti1 + (w - 1) * bpp]; - int lv2 = scl[ti2 + (w - 1) * bpp]; - int lv3 = scl[ti3 + (w - 1) * bpp]; - int lv4 = scl[ti4 + (w - 1) * bpp]; - - int val1 = (r + 1) * fv1; - int val2 = (r + 1) * fv2; - int val3 = (r + 1) * fv3; - int val4 = (r + 1) * fv4; - - for (int j = 0; j < r; ++j) { - val1 += scl[ti1 + j * bpp]; - val2 += scl[ti2 + j * bpp]; - val3 += scl[ti3 + j * bpp]; - val4 += scl[ti4 + j * bpp]; - } - - for (int j = 0; j <= r; ++j) { - val1 += scl[ri1] - fv1; - val2 += scl[ri2] - fv2; - val3 += scl[ri3] - fv3; - val4 += scl[ri4] - fv4; - - tcl[ti1] = myround(val1 * iarr); - tcl[ti2] = myround(val2 * iarr); - tcl[ti3] = myround(val3 * iarr); - tcl[ti4] = myround(val4 * iarr); - - ri1 += bpp; - ri2 += bpp; - ri3 += bpp; - ri4 += bpp; - - ti1 += bpp; - ti2 += bpp; - ti3 += bpp; - ti4 += bpp; - } - - for (int j = r + 1; j < w - r; ++j) { - val1 += scl[ri1] - scl[li1]; - val2 += scl[ri2] - scl[li2]; - val3 += scl[ri3] - scl[li3]; - val4 += scl[ri4] - scl[li4]; - - tcl[ti1] = myround(val1 * iarr); - tcl[ti2] = myround(val2 * iarr); - tcl[ti3] = myround(val3 * iarr); - tcl[ti4] = myround(val4 * iarr); - - ri1 += bpp; - ri2 += bpp; - ri3 += bpp; - ri4 += bpp; - - li1 += bpp; - li2 += bpp; - li3 += bpp; - li4 += bpp; - - ti1 += bpp; - ti2 += bpp; - ti3 += bpp; - ti4 += bpp; - } - - for (int j = w - r; j < w; ++j) { - val1 += lv1 - scl[li1]; - val2 += lv2 - scl[li2]; - val3 += lv3 - scl[li3]; - val4 += lv4 - scl[li4]; - - tcl[ti1] = myround(val1 * iarr); - tcl[ti2] = myround(val2 * iarr); - tcl[ti3] = myround(val3 * iarr); - tcl[ti4] = myround(val4 * iarr); - - li1 += bpp; - li2 += bpp; - li3 += bpp; - li4 += bpp; - - ti1 += bpp; - ti2 += bpp; - ti3 += bpp; - ti4 += bpp; - } - } +void boxBlurT_4(BYTE* scl, + BYTE* tcl, + int w, + int h, + int r, + int bpp, + int stride) { + float iarr = (float)(1.0f / (r + r + 1.0f)); + for (int i = 0; i < w; ++i) { + int ti1 = i * bpp; + int ti2 = i * bpp + 1; + int ti3 = i * bpp + 2; + int ti4 = i * bpp + 3; + + int li1 = ti1; + int li2 = ti2; + int li3 = ti3; + int li4 = ti4; + + int ri1 = ti1 + r * stride; + int ri2 = ti2 + r * stride; + int ri3 = ti3 + r * stride; + int ri4 = ti4 + r * stride; + + int fv1 = scl[ti1]; + int fv2 = scl[ti2]; + int fv3 = scl[ti3]; + int fv4 = scl[ti4]; + + int lv1 = scl[ti1 + stride * (h - 1)]; + int lv2 = scl[ti2 + stride * (h - 1)]; + int lv3 = scl[ti3 + stride * (h - 1)]; + int lv4 = scl[ti4 + stride * (h - 1)]; + + int val1 = (r + 1) * fv1; + int val2 = (r + 1) * fv2; + int val3 = (r + 1) * fv3; + int val4 = (r + 1) * fv4; + + for (int j = 0; j < r; ++j) { + val1 += scl[ti1 + j * stride]; + val2 += scl[ti2 + j * stride]; + val3 += scl[ti3 + j * stride]; + val4 += scl[ti4 + j * stride]; + } + + for (int j = 0; j <= r; ++j) { + val1 += scl[ri1] - fv1; + val2 += scl[ri2] - fv2; + val3 += scl[ri3] - fv3; + val4 += scl[ri4] - fv4; + + tcl[ti1] = myround(val1 * iarr); + tcl[ti2] = myround(val2 * iarr); + tcl[ti3] = myround(val3 * iarr); + tcl[ti4] = myround(val4 * iarr); + + ri1 += stride; + ri2 += stride; + ri3 += stride; + ri4 += stride; + + ti1 += stride; + ti2 += stride; + ti3 += stride; + ti4 += stride; + } + + for (int j = r + 1; j < h - r; ++j) { + val1 += scl[ri1] - scl[li1]; + val2 += scl[ri2] - scl[li2]; + val3 += scl[ri3] - scl[li3]; + val4 += scl[ri4] - scl[li4]; + + tcl[ti1] = myround(val1 * iarr); + tcl[ti2] = myround(val2 * iarr); + tcl[ti3] = myround(val3 * iarr); + tcl[ti4] = myround(val4 * iarr); + + li1 += stride; + li2 += stride; + li3 += stride; + li4 += stride; + + ri1 += stride; + ri2 += stride; + ri3 += stride; + ri4 += stride; + + ti1 += stride; + ti2 += stride; + ti3 += stride; + ti4 += stride; + } + + for (int j = h - r; j < h; ++j) { + val1 += lv1 - scl[li1]; + val2 += lv2 - scl[li2]; + val3 += lv3 - scl[li3]; + val4 += lv4 - scl[li4]; + + tcl[ti1] = myround(val1 * iarr); + tcl[ti2] = myround(val2 * iarr); + tcl[ti3] = myround(val3 * iarr); + tcl[ti4] = myround(val4 * iarr); + + li1 += stride; + li2 += stride; + li3 += stride; + li4 += stride; + + ti1 += stride; + ti2 += stride; + ti3 += stride; + ti4 += stride; + } + } } -void boxBlurT_4(BYTE* scl, BYTE* tcl, int w, int h, int r, int bpp, int stride) -{ - float iarr = (float)(1.0f / (r + r + 1.0f)); - for (int i = 0; i < w; ++i) { - int ti1 = i * bpp; - int ti2 = i * bpp + 1; - int ti3 = i * bpp + 2; - int ti4 = i * bpp + 3; - - int li1 = ti1; - int li2 = ti2; - int li3 = ti3; - int li4 = ti4; - - int ri1 = ti1 + r * stride; - int ri2 = ti2 + r * stride; - int ri3 = ti3 + r * stride; - int ri4 = ti4 + r * stride; - - int fv1 = scl[ti1]; - int fv2 = scl[ti2]; - int fv3 = scl[ti3]; - int fv4 = scl[ti4]; - - int lv1 = scl[ti1 + stride * (h - 1)]; - int lv2 = scl[ti2 + stride * (h - 1)]; - int lv3 = scl[ti3 + stride * (h - 1)]; - int lv4 = scl[ti4 + stride * (h - 1)]; - - int val1 = (r + 1) * fv1; - int val2 = (r + 1) * fv2; - int val3 = (r + 1) * fv3; - int val4 = (r + 1) * fv4; - - for (int j = 0; j < r; ++j) { - val1 += scl[ti1 + j * stride]; - val2 += scl[ti2 + j * stride]; - val3 += scl[ti3 + j * stride]; - val4 += scl[ti4 + j * stride]; - } - - for (int j = 0; j <= r; ++j) { - val1 += scl[ri1] - fv1; - val2 += scl[ri2] - fv2; - val3 += scl[ri3] - fv3; - val4 += scl[ri4] - fv4; - - tcl[ti1] = myround(val1 * iarr); - tcl[ti2] = myround(val2 * iarr); - tcl[ti3] = myround(val3 * iarr); - tcl[ti4] = myround(val4 * iarr); - - ri1 += stride; - ri2 += stride; - ri3 += stride; - ri4 += stride; - - ti1 += stride; - ti2 += stride; - ti3 += stride; - ti4 += stride; - } - - for (int j = r + 1; j < h - r; ++j) { - val1 += scl[ri1] - scl[li1]; - val2 += scl[ri2] - scl[li2]; - val3 += scl[ri3] - scl[li3]; - val4 += scl[ri4] - scl[li4]; - - tcl[ti1] = myround(val1 * iarr); - tcl[ti2] = myround(val2 * iarr); - tcl[ti3] = myround(val3 * iarr); - tcl[ti4] = myround(val4 * iarr); - - li1 += stride; - li2 += stride; - li3 += stride; - li4 += stride; - - ri1 += stride; - ri2 += stride; - ri3 += stride; - ri4 += stride; - - ti1 += stride; - ti2 += stride; - ti3 += stride; - ti4 += stride; - } - - for (int j = h - r; j < h; ++j) { - val1 += lv1 - scl[li1]; - val2 += lv2 - scl[li2]; - val3 += lv3 - scl[li3]; - val4 += lv4 - scl[li4]; - - tcl[ti1] = myround(val1 * iarr); - tcl[ti2] = myround(val2 * iarr); - tcl[ti3] = myround(val3 * iarr); - tcl[ti4] = myround(val4 * iarr); - - li1 += stride; - li2 += stride; - li3 += stride; - li4 += stride; - - ti1 += stride; - ti2 += stride; - ti3 += stride; - ti4 += stride; - } - } +void boxBlur_4(BYTE* scl, + BYTE* tcl, + int w, + int h, + int rx, + int ry, + int bpp, + int stride) { + memcpy(tcl, scl, stride * h); + boxBlurH_4(tcl, scl, w, h, rx, bpp, stride); + boxBlurT_4(scl, tcl, w, h, ry, bpp, stride); } -void boxBlur_4(BYTE* scl, BYTE* tcl, int w, int h, int rx, int ry, int bpp, int stride) -{ - memcpy(tcl, scl, stride * h); - boxBlurH_4(tcl, scl, w, h, rx, bpp, stride); - boxBlurT_4(scl, tcl, w, h, ry, bpp, stride); +void gaussBlur_4(BYTE* scl, + BYTE* tcl, + int w, + int h, + float rx, + float ry, + int bpp, + int stride) { + int bxsX[4]; + boxesForGauss(rx, bxsX, 4); + + int bxsY[4]; + boxesForGauss(ry, bxsY, 4); + + boxBlur_4(scl, tcl, w, h, (bxsX[0] - 1) / 2, (bxsY[0] - 1) / 2, bpp, stride); + boxBlur_4(tcl, scl, w, h, (bxsX[1] - 1) / 2, (bxsY[1] - 1) / 2, bpp, stride); + boxBlur_4(scl, tcl, w, h, (bxsX[2] - 1) / 2, (bxsY[2] - 1) / 2, bpp, stride); + boxBlur_4(scl, tcl, w, h, (bxsX[3] - 1) / 2, (bxsY[3] - 1) / 2, bpp, stride); } -void gaussBlur_4(BYTE* scl, BYTE* tcl, int w, int h, float rx, float ry, int bpp, int stride) -{ - int bxsX[4]; - boxesForGauss(rx, bxsX, 4); +void DoGaussianBlur(Gdiplus::Bitmap* img, float radiusX, float radiusY) { + if (img == 0 || (radiusX == 0.0f && radiusY == 0.0f)) + return; - int bxsY[4]; - boxesForGauss(ry, bxsY, 4); + const int w = img->GetWidth(); + const int h = img->GetHeight(); - boxBlur_4(scl, tcl, w, h, (bxsX[0] - 1) / 2, (bxsY[0] - 1) / 2, bpp, stride); - boxBlur_4(tcl, scl, w, h, (bxsX[1] - 1) / 2, (bxsY[1] - 1) / 2, bpp, stride); - boxBlur_4(scl, tcl, w, h, (bxsX[2] - 1) / 2, (bxsY[2] - 1) / 2, bpp, stride); - boxBlur_4(scl, tcl, w, h, (bxsX[3] - 1) / 2, (bxsY[3] - 1) / 2, bpp, stride); -} + if (radiusX > w / 2) { + radiusX = (float)(w / 2); + } -void DoGaussianBlur(Gdiplus::Bitmap* img, float radiusX, float radiusY) -{ - if (img == 0 || (radiusX == 0.0f && radiusY == 0.0f)) return; - - const int w = img->GetWidth(); - const int h = img->GetHeight(); - - if (radiusX > w / 2) { - radiusX = (float)(w / 2); - } - - if (radiusY > h / 2) { - radiusY = (float)(h / 2); - } - - Gdiplus::Bitmap* temp = new Gdiplus::Bitmap(img->GetWidth(), img->GetHeight(), img->GetPixelFormat()); - - Gdiplus::BitmapData bitmapData1; - Gdiplus::BitmapData bitmapData2; - Gdiplus::Rect rect(0, 0, img->GetWidth(), img->GetHeight()); - - if (Gdiplus::Ok == img->LockBits( - &rect, - Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeWrite, - img->GetPixelFormat(), - &bitmapData1 - ) - && - Gdiplus::Ok == temp->LockBits( - &rect, - Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeWrite, - temp->GetPixelFormat(), - &bitmapData2 - )) { - BYTE* src = (BYTE*)bitmapData1.Scan0; - BYTE* dst = (BYTE*)bitmapData2.Scan0; - - const int bpp = 4; - const int stride = bitmapData1.Stride; - - gaussBlur_4(src, dst, w, h, radiusX, radiusY, bpp, stride); - - img->UnlockBits(&bitmapData1); - temp->UnlockBits(&bitmapData2); - } - - delete temp; -} + if (radiusY > h / 2) { + radiusY = (float)(h / 2); + } + + Gdiplus::Bitmap* temp = new Gdiplus::Bitmap(img->GetWidth(), img->GetHeight(), + img->GetPixelFormat()); -void DoGaussianBlurPower(Gdiplus::Bitmap* img, float radiusX, float radiusY, int nPower) -{ - Gdiplus::Bitmap* pBitmap = img->Clone(0, 0, img->GetWidth(), img->GetHeight(), PixelFormat32bppARGB); - DoGaussianBlur(pBitmap, radiusX, radiusY); - Gdiplus::Graphics g(pBitmap); - for (int i = 0; i < 8; ++i) { - g.DrawImage(pBitmap, 0, 0); - if ((1 << i) & nPower) { - Gdiplus::Graphics g(img); - g.DrawImage(pBitmap, 0, 0); - } - } - delete pBitmap; + Gdiplus::BitmapData bitmapData1; + Gdiplus::BitmapData bitmapData2; + Gdiplus::Rect rect(0, 0, img->GetWidth(), img->GetHeight()); + + if (Gdiplus::Ok == + img->LockBits( + &rect, Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeWrite, + img->GetPixelFormat(), &bitmapData1) && + Gdiplus::Ok == + temp->LockBits( + &rect, Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeWrite, + temp->GetPixelFormat(), &bitmapData2)) { + BYTE* src = (BYTE*)bitmapData1.Scan0; + BYTE* dst = (BYTE*)bitmapData2.Scan0; + + const int bpp = 4; + const int stride = bitmapData1.Stride; + + gaussBlur_4(src, dst, w, h, radiusX, radiusY, bpp, stride); + + img->UnlockBits(&bitmapData1); + temp->UnlockBits(&bitmapData2); + } + + delete temp; } -/* end image gauss blur functions from https://github.com/kenjinote/DropShadow/ */ + +void DoGaussianBlurPower(Gdiplus::Bitmap* img, + float radiusX, + float radiusY, + int nPower) { + Gdiplus::Bitmap* pBitmap = + img->Clone(0, 0, img->GetWidth(), img->GetHeight(), PixelFormat32bppARGB); + DoGaussianBlur(pBitmap, radiusX, radiusY); + Gdiplus::Graphics g(pBitmap); + for (int i = 0; i < 8; ++i) { + g.DrawImage(pBitmap, 0, 0); + if ((1 << i) & nPower) { + Gdiplus::Graphics g(img); + g.DrawImage(pBitmap, 0, 0); + } + } + delete pBitmap; } +/* end image gauss blur functions from https://github.com/kenjinote/DropShadow/ + */ +} // namespace weasel diff --git a/WeaselUI/GdiplusBlur.h b/WeaselUI/GdiplusBlur.h index 73785987a..198914dd7 100644 --- a/WeaselUI/GdiplusBlur.h +++ b/WeaselUI/GdiplusBlur.h @@ -2,6 +2,6 @@ #include #pragma comment(lib, "gdiplus.lib") -namespace weasel{ - void DoGaussianBlur(Gdiplus::Bitmap* img, float radiusX, float radiusY); +namespace weasel { +void DoGaussianBlur(Gdiplus::Bitmap* img, float radiusX, float radiusY); } diff --git a/WeaselUI/HorizontalLayout.cpp b/WeaselUI/HorizontalLayout.cpp index d1f7fa703..5e34e8474 100644 --- a/WeaselUI/HorizontalLayout.cpp +++ b/WeaselUI/HorizontalLayout.cpp @@ -3,225 +3,251 @@ using namespace weasel; -void HorizontalLayout::DoLayout(CDCHandle dc, PDWR pDWR ) -{ - CSize size; - int width = offsetX + real_margin_x, height = offsetY + real_margin_y; - int w = offsetX + real_margin_x; - - /* calc mark_text sizes */ - if ((_style.hilited_mark_color & 0xff000000)) - { - CSize sg; - if(_style.mark_text.empty()) - GetTextSizeDW(L"|", 1, pDWR->pTextFormat, pDWR, &sg); - else - GetTextSizeDW(_style.mark_text, _style.mark_text.length(), pDWR->pTextFormat, pDWR, &sg); - - MARK_WIDTH = sg.cx; - MARK_HEIGHT = sg.cy; - if(_style.mark_text.empty()) - MARK_WIDTH /= 2; - MARK_GAP = (_style.mark_text.empty()) ? MARK_WIDTH : MARK_WIDTH + _style.hilite_spacing; - } - int base_offset = ((_style.hilited_mark_color & 0xff000000)) ? MARK_GAP : 0; - - // calc page indicator - CSize pgszl, pgszr; - GetTextSizeDW(pre, pre.length(), pDWR->pPreeditTextFormat, pDWR, &pgszl); - GetTextSizeDW(next, next.length(), pDWR->pPreeditTextFormat, pDWR, &pgszr); - bool page_en = (_style.prevpage_color & 0xff000000) && (_style.nextpage_color & 0xff000000); - int pgw = page_en ? (pgszl.cx + pgszr.cx + _style.hilite_spacing + _style.hilite_padding_x * 2) : 0; - int pgh = page_en ? max(pgszl.cy, pgszr.cy) : 0; - - /* Preedit */ - if (!IsInlinePreedit() && !_context.preedit.str.empty()) - { - size = GetPreeditSize(dc, _context.preedit, pDWR->pPreeditTextFormat, pDWR); - int szx = pgw, szy = max(size.cy, pgh); - // icon size higher then preedit text - int yoffset = (STATUS_ICON_SIZE >= szy && ShouldDisplayStatusIcon()) ? (STATUS_ICON_SIZE - szy) / 2 : 0; - _preeditRect.SetRect(w, height + yoffset, w + size.cx, height + yoffset + size.cy); - height += szy + 2 * yoffset + _style.spacing; - width = max(width, real_margin_x * 2 + size.cx + szx); - if(ShouldDisplayStatusIcon()) width += STATUS_ICON_SIZE; - } - - /* Auxiliary */ - if (!_context.aux.str.empty()) - { - size = GetPreeditSize(dc, _context.aux, pDWR->pPreeditTextFormat, pDWR); - // icon size higher then auxiliary text - int yoffset = (STATUS_ICON_SIZE >= size.cy && ShouldDisplayStatusIcon()) ? (STATUS_ICON_SIZE - size.cy) / 2 : 0; - _auxiliaryRect.SetRect(w, height + yoffset, w + size.cx, height + yoffset + size.cy); - height += size.cy + 2 * yoffset + _style.spacing; - width = max(width, real_margin_x * 2 + size.cx); - } - - int row_cnt = 0; - int max_width_of_rows = 0; - int height_of_rows[MAX_CANDIDATES_COUNT] = {0}; // height of every row - int row_of_candidate[MAX_CANDIDATES_COUNT] = {0}; // row info of every cand - int mintop_of_rows[MAX_CANDIDATES_COUNT] = {0}; - // only when there are candidates - if(candidates_count) - { - w = offsetX + real_margin_x; - for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) - { - int current_cand_width = 0; - if (i > 0) w += _style.candidate_spacing; - if( id == i ) w += base_offset; - /* Label */ - std::wstring label = GetLabelText(labels, i, _style.label_text_format.c_str()); - GetTextSizeDW(label, label.length(), pDWR->pLabelTextFormat, pDWR, &size); - _candidateLabelRects[i].SetRect(w, height, w + size.cx * labelFontValid, height + size.cy); - w += size.cx * labelFontValid; - current_cand_width += size.cx * labelFontValid; - - /* Text */ - w += _style.hilite_spacing; - const std::wstring& text = candidates.at(i).str; - GetTextSizeDW(text, text.length(), pDWR->pTextFormat, pDWR, &size); - _candidateTextRects[i].SetRect(w, height, w + size.cx * textFontValid, height + size.cy); - w += size.cx * textFontValid; - current_cand_width += (size.cx + _style.hilite_spacing) * textFontValid; - - /* Comment */ - bool cmtFontNotTrans = (i == id && (_style.hilited_comment_text_color & 0xff000000)) || - (i != id && (_style.comment_text_color & 0xff000000)); - if (!comments.at(i).str.empty() && cmtFontValid && cmtFontNotTrans) - { - const std::wstring& comment = comments.at(i).str; - GetTextSizeDW(comment, comment.length(), pDWR->pCommentTextFormat, pDWR, &size); - w += _style.hilite_spacing; - _candidateCommentRects[i].SetRect(w, height, w + size.cx * cmtFontValid, height + size.cy); - w += size.cx * cmtFontValid; - current_cand_width += (size.cx + _style.hilite_spacing) * cmtFontValid; - } - else /* Used for highlighted candidate calculation below */ - _candidateCommentRects[i].SetRect(w, height, w, height + size.cy); - - int base_left = (i==id) ? _candidateLabelRects[i].left - base_offset : _candidateLabelRects[i].left; - // if not the first candidate of current row, and current candidate's right > _style.max_width - if(_style.max_width > 0 && (base_left > real_margin_x + offsetX) && (_candidateCommentRects[i].right - offsetX + real_margin_x > _style.max_width)) - { - // max_width_of_rows current row - max_width_of_rows = max(max_width_of_rows, _candidateCommentRects[i-1].right); - w = offsetX + real_margin_x + (i==id ? base_offset : 0); - int ofx = w - _candidateLabelRects[i].left; - int ofy = height_of_rows[row_cnt] + _style.candidate_spacing; - // offset rects to next row - _candidateLabelRects[i].OffsetRect(ofx, ofy); - _candidateTextRects[i].OffsetRect(ofx, ofy); - _candidateCommentRects[i].OffsetRect(ofx, ofy); - // max width of next row, if it's the last candidate, make sure max_width_of_rows calc right - max_width_of_rows = max(max_width_of_rows, _candidateCommentRects[i].right); - mintop_of_rows[row_cnt] = height; - height += ofy; - // re calc rect position, decrease offsetX for origin - w += current_cand_width; - row_cnt ++; - } - else - max_width_of_rows = max(max_width_of_rows, w); - // calculate height of current row is the max of three rects - mintop_of_rows[row_cnt] = height; - height_of_rows[row_cnt] = max(height_of_rows[row_cnt], _candidateLabelRects[i].Height()); - height_of_rows[row_cnt] = max(height_of_rows[row_cnt], _candidateTextRects[i].Height()); - height_of_rows[row_cnt] = max(height_of_rows[row_cnt], _candidateCommentRects[i].Height()); - // set row info of current candidate - row_of_candidate[i] = row_cnt; - } - - // reposition for alignment, exp when rect height not equal to height_of_rows - for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) - { - int base_left = (i==id) ? _candidateLabelRects[i].left - base_offset : _candidateLabelRects[i].left; - _candidateRects[i].SetRect(base_left, mintop_of_rows[row_of_candidate[i]], - _candidateCommentRects[i].right, mintop_of_rows[row_of_candidate[i]] + height_of_rows[row_of_candidate[i]]); - int ol = 0, ot = 0, oc = 0; - if (_style.align_type == UIStyle::ALIGN_CENTER) - { - ol = (height_of_rows[row_of_candidate[i]] - _candidateLabelRects[i].Height()) / 2; - ot = (height_of_rows[row_of_candidate[i]] - _candidateTextRects[i].Height()) / 2; - oc = (height_of_rows[row_of_candidate[i]] - _candidateCommentRects[i].Height()) / 2; - } - else if (_style.align_type == UIStyle::ALIGN_BOTTOM) - { - ol = (height_of_rows[row_of_candidate[i]] - _candidateLabelRects[i].Height()) ; - ot = (height_of_rows[row_of_candidate[i]] - _candidateTextRects[i].Height()) ; - oc = (height_of_rows[row_of_candidate[i]] - _candidateCommentRects[i].Height()) ; - } - _candidateLabelRects[i].OffsetRect(0, ol); - _candidateTextRects[i].OffsetRect(0, ot); - _candidateCommentRects[i].OffsetRect(0, oc); - } - height = mintop_of_rows[row_cnt] + height_of_rows[row_cnt] - offsetY; - width = max(width, max_width_of_rows); - } - else - { - height -= _style.spacing + offsetY; - width += _style.hilite_spacing + _style.border; - } - - width += real_margin_x; - height += real_margin_y; - - if (!_context.preedit.str.empty() && candidates_count) - { - width = max(width, _style.min_width); - height = max(height, _style.min_height); - } - if(candidates_count) - { - for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) - { - // make rightest candidate's rect right the same for better look - if(( i < candidates_count - 1 && row_of_candidate[i] < row_of_candidate[i+1] ) || (i == candidates_count - 1)) - _candidateRects[i].right = width - real_margin_x; - } - } - _highlightRect = _candidateRects[id]; - UpdateStatusIconLayout(&width, &height); - _contentSize.SetSize(width + offsetX, height + 2 * offsetY); - _contentRect.SetRect(0, 0, _contentSize.cx, _contentSize.cy); - - // calc page indicator - if(page_en && candidates_count && !_style.inline_preedit) - { - int _prex = _contentSize.cx - offsetX - real_margin_x + _style.hilite_padding_x - pgw; - int _prey = (_preeditRect.top + _preeditRect.bottom) / 2 - pgszl.cy / 2; - _prePageRect.SetRect(_prex, _prey, _prex + pgszl.cx, _prey + pgszl.cy); - _nextPageRect.SetRect(_prePageRect.right + _style.hilite_spacing, - _prey, _prePageRect.right + _style.hilite_spacing + pgszr.cx, _prey + pgszr.cy); - if (ShouldDisplayStatusIcon()) - { - _prePageRect.OffsetRect(-STATUS_ICON_SIZE, 0); - _nextPageRect.OffsetRect(-STATUS_ICON_SIZE, 0); - } - } - - // prepare temp rect _bgRect for roundinfo calculation - CopyRect(_bgRect, _contentRect); - _bgRect.DeflateRect(offsetX + 1, offsetY + 1); - // prepare round info for single row status, only for single row situation - _PrepareRoundInfo(dc); - // readjust for multi rows - if(row_cnt) // row_cnt > 0, at least 2 candidates - { - _roundInfo[0].IsBottomLeftNeedToRound = false; - _roundInfo[candidates_count - 1].IsTopRightNeedToRound = false; - for(auto i = 1; i < candidates_count; i++) - { - _roundInfo[i].Hemispherical = _roundInfo[0].Hemispherical; - if(row_of_candidate[i] == row_cnt && row_of_candidate[i-1] == row_cnt - 1) - _roundInfo[i].IsBottomLeftNeedToRound = true; - if(row_of_candidate[i] == 0 && row_of_candidate[i+1] == 1) - _roundInfo[i].IsTopRightNeedToRound = _style.inline_preedit; - } - } - // truely draw content size calculation - _contentRect.DeflateRect(offsetX, offsetY); +void HorizontalLayout::DoLayout(CDCHandle dc, PDWR pDWR) { + CSize size; + int width = offsetX + real_margin_x, height = offsetY + real_margin_y; + int w = offsetX + real_margin_x; + + /* calc mark_text sizes */ + if ((_style.hilited_mark_color & 0xff000000)) { + CSize sg; + if (_style.mark_text.empty()) + GetTextSizeDW(L"|", 1, pDWR->pTextFormat, pDWR, &sg); + else + GetTextSizeDW(_style.mark_text, _style.mark_text.length(), + pDWR->pTextFormat, pDWR, &sg); + + MARK_WIDTH = sg.cx; + MARK_HEIGHT = sg.cy; + if (_style.mark_text.empty()) + MARK_WIDTH /= 2; + MARK_GAP = (_style.mark_text.empty()) ? MARK_WIDTH + : MARK_WIDTH + _style.hilite_spacing; + } + int base_offset = ((_style.hilited_mark_color & 0xff000000)) ? MARK_GAP : 0; + + // calc page indicator + CSize pgszl, pgszr; + GetTextSizeDW(pre, pre.length(), pDWR->pPreeditTextFormat, pDWR, &pgszl); + GetTextSizeDW(next, next.length(), pDWR->pPreeditTextFormat, pDWR, &pgszr); + bool page_en = (_style.prevpage_color & 0xff000000) && + (_style.nextpage_color & 0xff000000); + int pgw = page_en ? (pgszl.cx + pgszr.cx + _style.hilite_spacing + + _style.hilite_padding_x * 2) + : 0; + int pgh = page_en ? max(pgszl.cy, pgszr.cy) : 0; + + /* Preedit */ + if (!IsInlinePreedit() && !_context.preedit.str.empty()) { + size = GetPreeditSize(dc, _context.preedit, pDWR->pPreeditTextFormat, pDWR); + int szx = pgw, szy = max(size.cy, pgh); + // icon size higher then preedit text + int yoffset = (STATUS_ICON_SIZE >= szy && ShouldDisplayStatusIcon()) + ? (STATUS_ICON_SIZE - szy) / 2 + : 0; + _preeditRect.SetRect(w, height + yoffset, w + size.cx, + height + yoffset + size.cy); + height += szy + 2 * yoffset + _style.spacing; + width = max(width, real_margin_x * 2 + size.cx + szx); + if (ShouldDisplayStatusIcon()) + width += STATUS_ICON_SIZE; + } + + /* Auxiliary */ + if (!_context.aux.str.empty()) { + size = GetPreeditSize(dc, _context.aux, pDWR->pPreeditTextFormat, pDWR); + // icon size higher then auxiliary text + int yoffset = (STATUS_ICON_SIZE >= size.cy && ShouldDisplayStatusIcon()) + ? (STATUS_ICON_SIZE - size.cy) / 2 + : 0; + _auxiliaryRect.SetRect(w, height + yoffset, w + size.cx, + height + yoffset + size.cy); + height += size.cy + 2 * yoffset + _style.spacing; + width = max(width, real_margin_x * 2 + size.cx); + } + + int row_cnt = 0; + int max_width_of_rows = 0; + int height_of_rows[MAX_CANDIDATES_COUNT] = {0}; // height of every row + int row_of_candidate[MAX_CANDIDATES_COUNT] = {0}; // row info of every cand + int mintop_of_rows[MAX_CANDIDATES_COUNT] = {0}; + // only when there are candidates + if (candidates_count) { + w = offsetX + real_margin_x; + for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) { + int current_cand_width = 0; + if (i > 0) + w += _style.candidate_spacing; + if (id == i) + w += base_offset; + /* Label */ + std::wstring label = + GetLabelText(labels, i, _style.label_text_format.c_str()); + GetTextSizeDW(label, label.length(), pDWR->pLabelTextFormat, pDWR, &size); + _candidateLabelRects[i].SetRect(w, height, w + size.cx * labelFontValid, + height + size.cy); + w += size.cx * labelFontValid; + current_cand_width += size.cx * labelFontValid; + + /* Text */ + w += _style.hilite_spacing; + const std::wstring& text = candidates.at(i).str; + GetTextSizeDW(text, text.length(), pDWR->pTextFormat, pDWR, &size); + _candidateTextRects[i].SetRect(w, height, w + size.cx * textFontValid, + height + size.cy); + w += size.cx * textFontValid; + current_cand_width += (size.cx + _style.hilite_spacing) * textFontValid; + + /* Comment */ + bool cmtFontNotTrans = + (i == id && (_style.hilited_comment_text_color & 0xff000000)) || + (i != id && (_style.comment_text_color & 0xff000000)); + if (!comments.at(i).str.empty() && cmtFontValid && cmtFontNotTrans) { + const std::wstring& comment = comments.at(i).str; + GetTextSizeDW(comment, comment.length(), pDWR->pCommentTextFormat, pDWR, + &size); + w += _style.hilite_spacing; + _candidateCommentRects[i].SetRect(w, height, w + size.cx * cmtFontValid, + height + size.cy); + w += size.cx * cmtFontValid; + current_cand_width += (size.cx + _style.hilite_spacing) * cmtFontValid; + } else /* Used for highlighted candidate calculation below */ + _candidateCommentRects[i].SetRect(w, height, w, height + size.cy); + + int base_left = (i == id) ? _candidateLabelRects[i].left - base_offset + : _candidateLabelRects[i].left; + // if not the first candidate of current row, and current candidate's + // right > _style.max_width + if (_style.max_width > 0 && (base_left > real_margin_x + offsetX) && + (_candidateCommentRects[i].right - offsetX + real_margin_x > + _style.max_width)) { + // max_width_of_rows current row + max_width_of_rows = + max(max_width_of_rows, _candidateCommentRects[i - 1].right); + w = offsetX + real_margin_x + (i == id ? base_offset : 0); + int ofx = w - _candidateLabelRects[i].left; + int ofy = height_of_rows[row_cnt] + _style.candidate_spacing; + // offset rects to next row + _candidateLabelRects[i].OffsetRect(ofx, ofy); + _candidateTextRects[i].OffsetRect(ofx, ofy); + _candidateCommentRects[i].OffsetRect(ofx, ofy); + // max width of next row, if it's the last candidate, make sure + // max_width_of_rows calc right + max_width_of_rows = + max(max_width_of_rows, _candidateCommentRects[i].right); + mintop_of_rows[row_cnt] = height; + height += ofy; + // re calc rect position, decrease offsetX for origin + w += current_cand_width; + row_cnt++; + } else + max_width_of_rows = max(max_width_of_rows, w); + // calculate height of current row is the max of three rects + mintop_of_rows[row_cnt] = height; + height_of_rows[row_cnt] = + max(height_of_rows[row_cnt], _candidateLabelRects[i].Height()); + height_of_rows[row_cnt] = + max(height_of_rows[row_cnt], _candidateTextRects[i].Height()); + height_of_rows[row_cnt] = + max(height_of_rows[row_cnt], _candidateCommentRects[i].Height()); + // set row info of current candidate + row_of_candidate[i] = row_cnt; + } + + // reposition for alignment, exp when rect height not equal to + // height_of_rows + for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) { + int base_left = (i == id) ? _candidateLabelRects[i].left - base_offset + : _candidateLabelRects[i].left; + _candidateRects[i].SetRect(base_left, mintop_of_rows[row_of_candidate[i]], + _candidateCommentRects[i].right, + mintop_of_rows[row_of_candidate[i]] + + height_of_rows[row_of_candidate[i]]); + int ol = 0, ot = 0, oc = 0; + if (_style.align_type == UIStyle::ALIGN_CENTER) { + ol = (height_of_rows[row_of_candidate[i]] - + _candidateLabelRects[i].Height()) / + 2; + ot = (height_of_rows[row_of_candidate[i]] - + _candidateTextRects[i].Height()) / + 2; + oc = (height_of_rows[row_of_candidate[i]] - + _candidateCommentRects[i].Height()) / + 2; + } else if (_style.align_type == UIStyle::ALIGN_BOTTOM) { + ol = (height_of_rows[row_of_candidate[i]] - + _candidateLabelRects[i].Height()); + ot = (height_of_rows[row_of_candidate[i]] - + _candidateTextRects[i].Height()); + oc = (height_of_rows[row_of_candidate[i]] - + _candidateCommentRects[i].Height()); + } + _candidateLabelRects[i].OffsetRect(0, ol); + _candidateTextRects[i].OffsetRect(0, ot); + _candidateCommentRects[i].OffsetRect(0, oc); + } + height = mintop_of_rows[row_cnt] + height_of_rows[row_cnt] - offsetY; + width = max(width, max_width_of_rows); + } else { + height -= _style.spacing + offsetY; + width += _style.hilite_spacing + _style.border; + } + + width += real_margin_x; + height += real_margin_y; + + if (!_context.preedit.str.empty() && candidates_count) { + width = max(width, _style.min_width); + height = max(height, _style.min_height); + } + if (candidates_count) { + for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) { + // make rightest candidate's rect right the same for better look + if ((i < candidates_count - 1 && + row_of_candidate[i] < row_of_candidate[i + 1]) || + (i == candidates_count - 1)) + _candidateRects[i].right = width - real_margin_x; + } + } + _highlightRect = _candidateRects[id]; + UpdateStatusIconLayout(&width, &height); + _contentSize.SetSize(width + offsetX, height + 2 * offsetY); + _contentRect.SetRect(0, 0, _contentSize.cx, _contentSize.cy); + + // calc page indicator + if (page_en && candidates_count && !_style.inline_preedit) { + int _prex = _contentSize.cx - offsetX - real_margin_x + + _style.hilite_padding_x - pgw; + int _prey = (_preeditRect.top + _preeditRect.bottom) / 2 - pgszl.cy / 2; + _prePageRect.SetRect(_prex, _prey, _prex + pgszl.cx, _prey + pgszl.cy); + _nextPageRect.SetRect(_prePageRect.right + _style.hilite_spacing, _prey, + _prePageRect.right + _style.hilite_spacing + pgszr.cx, + _prey + pgszr.cy); + if (ShouldDisplayStatusIcon()) { + _prePageRect.OffsetRect(-STATUS_ICON_SIZE, 0); + _nextPageRect.OffsetRect(-STATUS_ICON_SIZE, 0); + } + } + + // prepare temp rect _bgRect for roundinfo calculation + CopyRect(_bgRect, _contentRect); + _bgRect.DeflateRect(offsetX + 1, offsetY + 1); + // prepare round info for single row status, only for single row situation + _PrepareRoundInfo(dc); + // readjust for multi rows + if (row_cnt) // row_cnt > 0, at least 2 candidates + { + _roundInfo[0].IsBottomLeftNeedToRound = false; + _roundInfo[candidates_count - 1].IsTopRightNeedToRound = false; + for (auto i = 1; i < candidates_count; i++) { + _roundInfo[i].Hemispherical = _roundInfo[0].Hemispherical; + if (row_of_candidate[i] == row_cnt && + row_of_candidate[i - 1] == row_cnt - 1) + _roundInfo[i].IsBottomLeftNeedToRound = true; + if (row_of_candidate[i] == 0 && row_of_candidate[i + 1] == 1) + _roundInfo[i].IsTopRightNeedToRound = _style.inline_preedit; + } + } + // truely draw content size calculation + _contentRect.DeflateRect(offsetX, offsetY); } diff --git a/WeaselUI/HorizontalLayout.h b/WeaselUI/HorizontalLayout.h index 8facdc3d7..eb5110ec4 100644 --- a/WeaselUI/HorizontalLayout.h +++ b/WeaselUI/HorizontalLayout.h @@ -2,13 +2,13 @@ #include "StandardLayout.h" -namespace weasel -{ - class HorizontalLayout: public StandardLayout - { - public: - HorizontalLayout(const UIStyle &style, const Context &context, const Status &status) - : StandardLayout(style, context, status) {} - virtual void DoLayout(CDCHandle dc, PDWR pDWR = NULL); - }; +namespace weasel { +class HorizontalLayout : public StandardLayout { + public: + HorizontalLayout(const UIStyle& style, + const Context& context, + const Status& status) + : StandardLayout(style, context, status) {} + virtual void DoLayout(CDCHandle dc, PDWR pDWR = NULL); }; +}; // namespace weasel diff --git a/WeaselUI/Layout.cpp b/WeaselUI/Layout.cpp index 796fe6aeb..85719e9d2 100644 --- a/WeaselUI/Layout.cpp +++ b/WeaselUI/Layout.cpp @@ -2,80 +2,102 @@ #include "Layout.h" using namespace weasel; -Layout::Layout(const UIStyle& style, const Context& context, const Status& status) - : _style(style), _context(context), _status(status), - candidates(_context.cinfo.candies), - comments(_context.cinfo.comments), - labels(_context.cinfo.labels), - id(_context.cinfo.highlighted), - candidates_count(candidates.size()), - real_margin_x((abs(_style.margin_x) > _style.hilite_padding_x) ? abs(_style.margin_x) : _style.hilite_padding_x), - real_margin_y((abs(_style.margin_y) > _style.hilite_padding_y) ? abs(_style.margin_y) : _style.hilite_padding_y), - labelFontValid(!!(_style.label_font_point > 0)), - textFontValid(!!(_style.font_point > 0)), - cmtFontValid(!!(_style.comment_font_point > 0)) -{ - offsetX = offsetY = 0; - if(_style.shadow_radius != 0) - { - offsetX = abs(_style.shadow_offset_x) + _style.shadow_radius*2; - offsetY = abs(_style.shadow_offset_y) + _style.shadow_radius*2; - if ((_style.shadow_offset_x != 0) || (_style.shadow_offset_y != 0)) - { - offsetX -= _style.shadow_radius / 2; - offsetY -= _style.shadow_radius / 2; - } - } - offsetX += _style.border*2; - offsetY += _style.border*2; +Layout::Layout(const UIStyle& style, + const Context& context, + const Status& status) + : _style(style), + _context(context), + _status(status), + candidates(_context.cinfo.candies), + comments(_context.cinfo.comments), + labels(_context.cinfo.labels), + id(_context.cinfo.highlighted), + candidates_count(candidates.size()), + real_margin_x((abs(_style.margin_x) > _style.hilite_padding_x) + ? abs(_style.margin_x) + : _style.hilite_padding_x), + real_margin_y((abs(_style.margin_y) > _style.hilite_padding_y) + ? abs(_style.margin_y) + : _style.hilite_padding_y), + labelFontValid(!!(_style.label_font_point > 0)), + textFontValid(!!(_style.font_point > 0)), + cmtFontValid(!!(_style.comment_font_point > 0)) { + offsetX = offsetY = 0; + if (_style.shadow_radius != 0) { + offsetX = abs(_style.shadow_offset_x) + _style.shadow_radius * 2; + offsetY = abs(_style.shadow_offset_y) + _style.shadow_radius * 2; + if ((_style.shadow_offset_x != 0) || (_style.shadow_offset_y != 0)) { + offsetX -= _style.shadow_radius / 2; + offsetY -= _style.shadow_radius / 2; + } + } + offsetX += _style.border * 2; + offsetY += _style.border * 2; } -GraphicsRoundRectPath::GraphicsRoundRectPath(const CRect rc, int corner, bool roundTopLeft, bool roundTopRight, bool roundBottomRight, bool roundBottomLeft) -{ - if (!(roundTopLeft || roundTopRight || roundBottomRight || roundBottomLeft) || corner <= 0) { - Gdiplus::Rect& rcp = Gdiplus::Rect(rc.left, rc.top, rc.Width() , rc.Height()); - AddRectangle(rcp); - } - else { - int cnx = ((corner * 2 <= rc.Width()) ? corner : (rc.Width() / 2)); - int cny = ((corner * 2 <= rc.Height()) ? corner : (rc.Height() / 2)); - int elWid = 2 * cnx; - int elHei = 2 * cny; - AddArc(rc.left, rc.top, elWid * roundTopLeft, elHei * roundTopLeft, 180, 90); - AddLine(rc.left + cnx * roundTopLeft, rc.top, rc.right - cnx * roundTopRight, rc.top); +GraphicsRoundRectPath::GraphicsRoundRectPath(const CRect rc, + int corner, + bool roundTopLeft, + bool roundTopRight, + bool roundBottomRight, + bool roundBottomLeft) { + if (!(roundTopLeft || roundTopRight || roundBottomRight || roundBottomLeft) || + corner <= 0) { + Gdiplus::Rect& rcp = + Gdiplus::Rect(rc.left, rc.top, rc.Width(), rc.Height()); + AddRectangle(rcp); + } else { + int cnx = ((corner * 2 <= rc.Width()) ? corner : (rc.Width() / 2)); + int cny = ((corner * 2 <= rc.Height()) ? corner : (rc.Height() / 2)); + int elWid = 2 * cnx; + int elHei = 2 * cny; + AddArc(rc.left, rc.top, elWid * roundTopLeft, elHei * roundTopLeft, 180, + 90); + AddLine(rc.left + cnx * roundTopLeft, rc.top, + rc.right - cnx * roundTopRight, rc.top); - AddArc(rc.right - elWid * roundTopRight, rc.top, elWid * roundTopRight, elHei * roundTopRight, 270, 90); - AddLine(rc.right, rc.top + cny * roundTopRight, rc.right, rc.bottom - cny * roundBottomRight); + AddArc(rc.right - elWid * roundTopRight, rc.top, elWid * roundTopRight, + elHei * roundTopRight, 270, 90); + AddLine(rc.right, rc.top + cny * roundTopRight, rc.right, + rc.bottom - cny * roundBottomRight); - AddArc(rc.right - elWid * roundBottomRight, rc.bottom - elHei * roundBottomRight, elWid * roundBottomRight, elHei * roundBottomRight, 0, 90); - AddLine(rc.right - cnx * roundBottomRight, rc.bottom, rc.left + cnx * roundBottomLeft, rc.bottom); + AddArc(rc.right - elWid * roundBottomRight, + rc.bottom - elHei * roundBottomRight, elWid * roundBottomRight, + elHei * roundBottomRight, 0, 90); + AddLine(rc.right - cnx * roundBottomRight, rc.bottom, + rc.left + cnx * roundBottomLeft, rc.bottom); - AddArc(rc.left, rc.bottom - elHei * roundBottomLeft, elWid * roundBottomLeft, elHei * roundBottomLeft, 90, 90); - AddLine(rc.left, rc.top + cny * roundTopLeft, rc.left, rc.bottom - cny * roundBottomLeft); - } + AddArc(rc.left, rc.bottom - elHei * roundBottomLeft, + elWid * roundBottomLeft, elHei * roundBottomLeft, 90, 90); + AddLine(rc.left, rc.top + cny * roundTopLeft, rc.left, + rc.bottom - cny * roundBottomLeft); + } } -void GraphicsRoundRectPath::AddRoundRect(int left, int top, int width, int height, int cornerx, int cornery) -{ - if (cornery > 0 && cornerx > 0) { - int cnx = ((cornerx * 2 <= width) ? cornerx : (width / 2)); - int cny = ((cornery * 2 <= height) ? cornery : (height / 2)); - int elWid = 2 * cnx; - int elHei = 2 * cny; - AddArc(left, top, elWid, elHei, 180, 90); - AddLine(left + cnx, top, left + width - cnx, top); +void GraphicsRoundRectPath::AddRoundRect(int left, + int top, + int width, + int height, + int cornerx, + int cornery) { + if (cornery > 0 && cornerx > 0) { + int cnx = ((cornerx * 2 <= width) ? cornerx : (width / 2)); + int cny = ((cornery * 2 <= height) ? cornery : (height / 2)); + int elWid = 2 * cnx; + int elHei = 2 * cny; + AddArc(left, top, elWid, elHei, 180, 90); + AddLine(left + cnx, top, left + width - cnx, top); - AddArc(left + width - elWid, top, elWid, elHei, 270, 90); - AddLine(left + width, top + cny, left + width, top + height - cny); + AddArc(left + width - elWid, top, elWid, elHei, 270, 90); + AddLine(left + width, top + cny, left + width, top + height - cny); - AddArc(left + width - elWid, top + height - elHei, elWid, elHei, 0, 90); - AddLine(left + width - cnx, top + height, left + cnx, top + height); + AddArc(left + width - elWid, top + height - elHei, elWid, elHei, 0, 90); + AddLine(left + width - cnx, top + height, left + cnx, top + height); - AddArc(left, top + height - elHei, elWid, elHei, 90, 90); - AddLine(left, top + cny, left, top + height - cny); - } - else { - Gdiplus::Rect& rc = Gdiplus::Rect(left, top, width, height); - AddRectangle(rc); - } + AddArc(left, top + height - elHei, elWid, elHei, 90, 90); + AddLine(left, top + cny, left, top + height - cny); + } else { + Gdiplus::Rect& rc = Gdiplus::Rect(left, top, width, height); + AddRectangle(rc); + } } diff --git a/WeaselUI/Layout.h b/WeaselUI/Layout.h index 8fa700032..d1d660d6b 100644 --- a/WeaselUI/Layout.h +++ b/WeaselUI/Layout.h @@ -5,98 +5,119 @@ #include #pragma comment(lib, "gdiplus.lib") -#define IS_FULLSCREENLAYOUT(style) (style.layout_type == UIStyle::LAYOUT_VERTICAL_FULLSCREEN || style.layout_type == UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN) -#define NOT_FULLSCREENLAYOUT(style) (style.layout_type != UIStyle::LAYOUT_VERTICAL_FULLSCREEN && style.layout_type != UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN) +#define IS_FULLSCREENLAYOUT(style) \ + (style.layout_type == UIStyle::LAYOUT_VERTICAL_FULLSCREEN || \ + style.layout_type == UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN) +#define NOT_FULLSCREENLAYOUT(style) \ + (style.layout_type != UIStyle::LAYOUT_VERTICAL_FULLSCREEN && \ + style.layout_type != UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN) -namespace weasel -{ - class GraphicsRoundRectPath : public Gdiplus::GraphicsPath - { - public: - GraphicsRoundRectPath() {}; - GraphicsRoundRectPath(int left, int top, int width, int height, int cornerx, int cornery) : Gdiplus::GraphicsPath() - { - AddRoundRect(left, top, width, height, cornerx, cornery); - } - GraphicsRoundRectPath(const CRect rc, int corner) - { - if (corner > 0) AddRoundRect(rc.left, rc.top, rc.Width(), rc.Height(), corner, corner); - else AddRectangle(Gdiplus::Rect(rc.left, rc.top, rc.Width(), rc.Height())); - } +namespace weasel { +class GraphicsRoundRectPath : public Gdiplus::GraphicsPath { + public: + GraphicsRoundRectPath(){}; + GraphicsRoundRectPath(int left, + int top, + int width, + int height, + int cornerx, + int cornery) + : Gdiplus::GraphicsPath() { + AddRoundRect(left, top, width, height, cornerx, cornery); + } + GraphicsRoundRectPath(const CRect rc, int corner) { + if (corner > 0) + AddRoundRect(rc.left, rc.top, rc.Width(), rc.Height(), corner, corner); + else + AddRectangle(Gdiplus::Rect(rc.left, rc.top, rc.Width(), rc.Height())); + } - GraphicsRoundRectPath(const CRect rc, int corner, bool roundTopLeft, bool roundTopRight, bool roundBottomRight, bool roundBottomLeft); + GraphicsRoundRectPath(const CRect rc, + int corner, + bool roundTopLeft, + bool roundTopRight, + bool roundBottomRight, + bool roundBottomLeft); - public: - void AddRoundRect(int left, int top, int width, int height, int cornerx, int cornery); - }; + public: + void AddRoundRect(int left, + int top, + int width, + int height, + int cornerx, + int cornery); +}; + +struct IsToRoundStruct { + bool IsTopLeftNeedToRound; + bool IsBottomLeftNeedToRound; + bool IsTopRightNeedToRound; + bool IsBottomRightNeedToRound; + bool Hemispherical; + IsToRoundStruct() + : IsTopLeftNeedToRound(true), + IsTopRightNeedToRound(true), + IsBottomLeftNeedToRound(true), + IsBottomRightNeedToRound(true), + Hemispherical(false) {} +}; - struct IsToRoundStruct - { - bool IsTopLeftNeedToRound; - bool IsBottomLeftNeedToRound; - bool IsTopRightNeedToRound; - bool IsBottomRightNeedToRound; - bool Hemispherical; - IsToRoundStruct(): - IsTopLeftNeedToRound(true), - IsTopRightNeedToRound(true), - IsBottomLeftNeedToRound(true), - IsBottomRightNeedToRound(true), - Hemispherical(false) - {} - }; +class Layout { + public: + Layout(const UIStyle& style, const Context& context, const Status& status); - class Layout - { - public: - Layout(const UIStyle &style, const Context &context, const Status &status); + virtual void DoLayout(CDCHandle dc, PDWR pDWR = NULL) = 0; + /* All points in this class is based on the content area */ + /* The top-left corner of the content area is always (0, 0) */ + virtual CSize GetContentSize() const = 0; + virtual CRect GetPreeditRect() const = 0; + virtual CRect GetAuxiliaryRect() const = 0; + virtual CRect GetHighlightRect() const = 0; + virtual CRect GetCandidateLabelRect(int id) const = 0; + virtual CRect GetCandidateTextRect(int id) const = 0; + virtual CRect GetCandidateRect(int id) const = 0; + virtual CRect GetCandidateCommentRect(int id) const = 0; + virtual CRect GetStatusIconRect() const = 0; + virtual IsToRoundStruct GetRoundInfo(int id) = 0; + virtual IsToRoundStruct GetTextRoundInfo() = 0; + virtual CRect GetContentRect() = 0; + virtual CRect GetPrepageRect() = 0; + virtual CRect GetNextpageRect() = 0; + virtual weasel::TextRange GetPreeditRange() = 0; + virtual CSize GetBeforeSize() = 0; + virtual CSize GetHilitedSize() = 0; + virtual CSize GetAfterSize() = 0; - virtual void DoLayout(CDCHandle dc, PDWR pDWR = NULL) = 0; - /* All points in this class is based on the content area */ - /* The top-left corner of the content area is always (0, 0) */ - virtual CSize GetContentSize() const = 0; - virtual CRect GetPreeditRect() const = 0; - virtual CRect GetAuxiliaryRect() const = 0; - virtual CRect GetHighlightRect() const = 0; - virtual CRect GetCandidateLabelRect(int id) const = 0; - virtual CRect GetCandidateTextRect(int id) const = 0; - virtual CRect GetCandidateRect(int id) const = 0; - virtual CRect GetCandidateCommentRect(int id) const = 0; - virtual CRect GetStatusIconRect() const = 0; - virtual IsToRoundStruct GetRoundInfo(int id) = 0; - virtual IsToRoundStruct GetTextRoundInfo() = 0; - virtual CRect GetContentRect() = 0; - virtual CRect GetPrepageRect() = 0; - virtual CRect GetNextpageRect() = 0; - virtual weasel::TextRange GetPreeditRange() = 0; - virtual CSize GetBeforeSize() = 0; - virtual CSize GetHilitedSize() = 0; - virtual CSize GetAfterSize() = 0; + virtual std::wstring GetLabelText(const std::vector& labels, + int id, + const wchar_t* format) const = 0; + virtual bool IsInlinePreedit() const = 0; + virtual bool ShouldDisplayStatusIcon() const = 0; + virtual void GetTextSizeDW(const std::wstring text, + size_t nCount, + ComPtr pTextFormat, + PDWR pDWR, + LPSIZE lpSize) const = 0; - virtual std::wstring GetLabelText(const std::vector &labels, int id, const wchar_t *format) const = 0; - virtual bool IsInlinePreedit() const = 0; - virtual bool ShouldDisplayStatusIcon() const = 0; - virtual void GetTextSizeDW(const std::wstring text, size_t nCount, ComPtr pTextFormat, PDWR pDWR, LPSIZE lpSize) const = 0; - - int offsetX = 0; - int offsetY = 0; - int MARK_WIDTH = 4; - int MARK_GAP = 8; - int MARK_HEIGHT = 0; + int offsetX = 0; + int offsetY = 0; + int MARK_WIDTH = 4; + int MARK_GAP = 8; + int MARK_HEIGHT = 0; - protected: - const UIStyle &_style; - const Context &_context; - const Status &_status; - const std::vector &candidates; - const std::vector &comments; - const std::vector &labels; - const int &id; - const int candidates_count; - const int real_margin_x; - const int real_margin_y; - const int labelFontValid; - const int textFontValid; - const int cmtFontValid; - }; + protected: + const UIStyle& _style; + const Context& _context; + const Status& _status; + const std::vector& candidates; + const std::vector& comments; + const std::vector& labels; + const int& id; + const int candidates_count; + const int real_margin_x; + const int real_margin_y; + const int labelFontValid; + const int textFontValid; + const int cmtFontValid; }; +}; // namespace weasel diff --git a/WeaselUI/StandardLayout.cpp b/WeaselUI/StandardLayout.cpp index f610bf241..9fd30bf71 100644 --- a/WeaselUI/StandardLayout.cpp +++ b/WeaselUI/StandardLayout.cpp @@ -3,395 +3,401 @@ using namespace weasel; -std::wstring StandardLayout::GetLabelText(const std::vector &labels, int id, const wchar_t *format) const -{ - wchar_t buffer[128]; - swprintf_s<128>(buffer, format, labels.at(id).str.c_str()); - return std::wstring(buffer); +std::wstring StandardLayout::GetLabelText(const std::vector& labels, + int id, + const wchar_t* format) const { + wchar_t buffer[128]; + swprintf_s<128>(buffer, format, labels.at(id).str.c_str()); + return std::wstring(buffer); } -void weasel::StandardLayout::GetTextSizeDW(const std::wstring text, size_t nCount, ComPtr pTextFormat, PDWR pDWR, LPSIZE lpSize) const -{ - D2D1_SIZE_F sz; - HRESULT hr = S_OK; +void weasel::StandardLayout::GetTextSizeDW( + const std::wstring text, + size_t nCount, + ComPtr pTextFormat, + PDWR pDWR, + LPSIZE lpSize) const { + D2D1_SIZE_F sz; + HRESULT hr = S_OK; - if (pTextFormat == NULL) - { - lpSize->cx = 0; - lpSize->cy = 0; - return; - } - // ı - if (pTextFormat != NULL){ - if (_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) - hr = pDWR->CreateTextLayout(text.c_str(), nCount, pTextFormat.Get(), 0, _style.max_height); - else - hr = pDWR->CreateTextLayout(text.c_str(), nCount, pTextFormat.Get(), _style.max_width, 0); - } + if (pTextFormat == NULL) { + lpSize->cx = 0; + lpSize->cy = 0; + return; + } + // ı + if (pTextFormat != NULL) { + if (_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) + hr = pDWR->CreateTextLayout(text.c_str(), nCount, pTextFormat.Get(), 0, + _style.max_height); + else + hr = pDWR->CreateTextLayout(text.c_str(), nCount, pTextFormat.Get(), + _style.max_width, 0); + } - if (SUCCEEDED(hr)) - { - if (_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) - { - DWRITE_FLOW_DIRECTION flow = _style.vertical_text_left_to_right ? DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT : DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT; - pDWR->SetLayoutReadingDirection(DWRITE_READING_DIRECTION_TOP_TO_BOTTOM); - pDWR->SetLayoutFlowDirection(flow); - } - // ȡıߴ - DWRITE_TEXT_METRICS textMetrics; - hr = pDWR->GetLayoutMetrics(&textMetrics); - sz = D2D1::SizeF(ceil(textMetrics.widthIncludingTrailingWhitespace), ceil(textMetrics.height)); + if (SUCCEEDED(hr)) { + if (_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) { + DWRITE_FLOW_DIRECTION flow = _style.vertical_text_left_to_right + ? DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT + : DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT; + pDWR->SetLayoutReadingDirection(DWRITE_READING_DIRECTION_TOP_TO_BOTTOM); + pDWR->SetLayoutFlowDirection(flow); + } + // ȡıߴ + DWRITE_TEXT_METRICS textMetrics; + hr = pDWR->GetLayoutMetrics(&textMetrics); + sz = D2D1::SizeF(ceil(textMetrics.widthIncludingTrailingWhitespace), + ceil(textMetrics.height)); - lpSize->cx = (int)sz.width; - lpSize->cy = (int)sz.height; - pDWR->ResetLayout(); - - if(_style.layout_type != UIStyle::LAYOUT_VERTICAL_TEXT) - { - size_t max_width = _style.max_width == 0 ? textMetrics.widthIncludingTrailingWhitespace : _style.max_width; - hr = pDWR->CreateTextLayout(text.c_str(), nCount, pTextFormat.Get(), max_width, textMetrics.height); - } - else - { - size_t max_height = _style.max_height == 0 ? textMetrics.height : _style.max_height; - hr = pDWR->CreateTextLayout(text.c_str(), nCount, pTextFormat.Get(), textMetrics.widthIncludingTrailingWhitespace, max_height); - } + lpSize->cx = (int)sz.width; + lpSize->cy = (int)sz.height; + pDWR->ResetLayout(); - if (_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) - { - pDWR->SetLayoutReadingDirection(DWRITE_READING_DIRECTION_TOP_TO_BOTTOM); - pDWR->SetLayoutFlowDirection(DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT); - } - DWRITE_OVERHANG_METRICS overhangMetrics; - hr = pDWR->GetLayoutOverhangMetrics(&overhangMetrics); - { - if (overhangMetrics.left > 0) - lpSize->cx += overhangMetrics.left + 1; - if (overhangMetrics.right > 0) - lpSize->cx += overhangMetrics.right + 1; - if (overhangMetrics.top > 0) - lpSize->cy += overhangMetrics.top + 1; - if (overhangMetrics.bottom > 0) - lpSize->cy += overhangMetrics.bottom + 1; - } - } - pDWR->ResetLayout(); + if (_style.layout_type != UIStyle::LAYOUT_VERTICAL_TEXT) { + size_t max_width = _style.max_width == 0 + ? textMetrics.widthIncludingTrailingWhitespace + : _style.max_width; + hr = pDWR->CreateTextLayout(text.c_str(), nCount, pTextFormat.Get(), + max_width, textMetrics.height); + } else { + size_t max_height = + _style.max_height == 0 ? textMetrics.height : _style.max_height; + hr = pDWR->CreateTextLayout(text.c_str(), nCount, pTextFormat.Get(), + textMetrics.widthIncludingTrailingWhitespace, + max_height); + } + + if (_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) { + pDWR->SetLayoutReadingDirection(DWRITE_READING_DIRECTION_TOP_TO_BOTTOM); + pDWR->SetLayoutFlowDirection(DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT); + } + DWRITE_OVERHANG_METRICS overhangMetrics; + hr = pDWR->GetLayoutOverhangMetrics(&overhangMetrics); + { + if (overhangMetrics.left > 0) + lpSize->cx += overhangMetrics.left + 1; + if (overhangMetrics.right > 0) + lpSize->cx += overhangMetrics.right + 1; + if (overhangMetrics.top > 0) + lpSize->cy += overhangMetrics.top + 1; + if (overhangMetrics.bottom > 0) + lpSize->cy += overhangMetrics.bottom + 1; + } + } + pDWR->ResetLayout(); } -CSize StandardLayout::GetPreeditSize(CDCHandle dc, const weasel::Text& text, ComPtr pTextFormat, PDWR pDWR) -{ - const std::wstring& preedit = text.str; - const std::vector &attrs = text.attributes; - CSize size(0, 0); - if(!preedit.empty()) - { - weasel::TextRange range; - for (size_t j = 0; j < attrs.size(); ++j) - if (attrs[j].type == weasel::HIGHLIGHTED) - _range = attrs[j].range; - if(_range.start < _range.end) - { - std::wstring before_str = preedit.substr(0, _range.start); - std::wstring hilited_str = preedit.substr(_range.start, _range.end); - std::wstring after_str = preedit.substr(_range.end); - GetTextSizeDW(before_str, before_str.length(), pTextFormat, pDWR, &_beforesz); - GetTextSizeDW(hilited_str, hilited_str.length(), pTextFormat, pDWR, &_hilitedsz); - GetTextSizeDW(after_str, after_str.length(), pTextFormat, pDWR, &_aftersz); - auto width_max = 0, height_max = 0; - if(_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) - { - width_max = max(width_max, _beforesz.cx); - width_max = max(width_max, _hilitedsz.cx); - width_max = max(width_max, _aftersz.cx); - height_max += _beforesz.cy + (_beforesz.cy > 0) * _style.hilite_spacing; - height_max += _hilitedsz.cy + (_hilitedsz.cy > 0) * _style.hilite_spacing; - height_max += _aftersz.cy; - } - else - { - height_max = max(height_max, _beforesz.cy); - height_max = max(height_max, _hilitedsz.cy); - height_max = max(height_max, _aftersz.cy); - width_max += _beforesz.cx + (_beforesz.cx > 0) * _style.hilite_spacing; - width_max += _hilitedsz.cx + (_hilitedsz.cx > 0) * _style.hilite_spacing; - width_max += _aftersz.cx ; - } - size.cx = width_max; - size.cy = height_max; - } - else - GetTextSizeDW(preedit, preedit.length(), pTextFormat, pDWR, &size); - } - return size; +CSize StandardLayout::GetPreeditSize(CDCHandle dc, + const weasel::Text& text, + ComPtr pTextFormat, + PDWR pDWR) { + const std::wstring& preedit = text.str; + const std::vector& attrs = text.attributes; + CSize size(0, 0); + if (!preedit.empty()) { + weasel::TextRange range; + for (size_t j = 0; j < attrs.size(); ++j) + if (attrs[j].type == weasel::HIGHLIGHTED) + _range = attrs[j].range; + if (_range.start < _range.end) { + std::wstring before_str = preedit.substr(0, _range.start); + std::wstring hilited_str = preedit.substr(_range.start, _range.end); + std::wstring after_str = preedit.substr(_range.end); + GetTextSizeDW(before_str, before_str.length(), pTextFormat, pDWR, + &_beforesz); + GetTextSizeDW(hilited_str, hilited_str.length(), pTextFormat, pDWR, + &_hilitedsz); + GetTextSizeDW(after_str, after_str.length(), pTextFormat, pDWR, + &_aftersz); + auto width_max = 0, height_max = 0; + if (_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) { + width_max = max(width_max, _beforesz.cx); + width_max = max(width_max, _hilitedsz.cx); + width_max = max(width_max, _aftersz.cx); + height_max += _beforesz.cy + (_beforesz.cy > 0) * _style.hilite_spacing; + height_max += + _hilitedsz.cy + (_hilitedsz.cy > 0) * _style.hilite_spacing; + height_max += _aftersz.cy; + } else { + height_max = max(height_max, _beforesz.cy); + height_max = max(height_max, _hilitedsz.cy); + height_max = max(height_max, _aftersz.cy); + width_max += _beforesz.cx + (_beforesz.cx > 0) * _style.hilite_spacing; + width_max += + _hilitedsz.cx + (_hilitedsz.cx > 0) * _style.hilite_spacing; + width_max += _aftersz.cx; + } + size.cx = width_max; + size.cy = height_max; + } else + GetTextSizeDW(preedit, preedit.length(), pTextFormat, pDWR, &size); + } + return size; } // check if a candidate back path over _bgRect path -bool weasel::StandardLayout::_IsHighlightOverCandidateWindow(CRect& rc, CDCHandle& dc) -{ - GraphicsRoundRectPath bgPath(_bgRect, _style.round_corner_ex); - GraphicsRoundRectPath hlPath(rc, _style.round_corner); +bool weasel::StandardLayout::_IsHighlightOverCandidateWindow(CRect& rc, + CDCHandle& dc) { + GraphicsRoundRectPath bgPath(_bgRect, _style.round_corner_ex); + GraphicsRoundRectPath hlPath(rc, _style.round_corner); - Gdiplus::Region bgRegion(&bgPath); - Gdiplus::Region hlRegion(&hlPath); - Gdiplus::Region* tmpRegion = hlRegion.Clone(); + Gdiplus::Region bgRegion(&bgPath); + Gdiplus::Region hlRegion(&hlPath); + Gdiplus::Region* tmpRegion = hlRegion.Clone(); - tmpRegion->Xor(&bgRegion); - tmpRegion->Exclude(&bgRegion); + tmpRegion->Xor(&bgRegion); + tmpRegion->Exclude(&bgRegion); - Gdiplus::Graphics g(dc); - bool res = !tmpRegion->IsEmpty(&g); - delete tmpRegion; - tmpRegion = NULL; - return res; + Gdiplus::Graphics g(dc); + bool res = !tmpRegion->IsEmpty(&g); + delete tmpRegion; + tmpRegion = NULL; + return res; } // prepare Hemispherical rounding info -void weasel::StandardLayout::_PrepareRoundInfo(CDCHandle& dc) -{ - const int tmp[5]= { UIStyle::LAYOUT_VERTICAL, UIStyle::LAYOUT_HORIZONTAL, UIStyle::LAYOUT_VERTICAL_TEXT, UIStyle::LAYOUT_VERTICAL, UIStyle::LAYOUT_HORIZONTAL }; - int layout_type = tmp[_style.layout_type]; - bool textHemispherical = false, cand0Hemispherical = false; - if(!_style.inline_preedit) - { - CRect textRect(_preeditRect); - textRect.InflateRect(_style.hilite_padding_x, _style.hilite_padding_y); - textHemispherical = _IsHighlightOverCandidateWindow(textRect, dc); - const bool hilite_rd_info[3][2][4] = { - // vertical - { - {textHemispherical, textHemispherical && (!candidates_count), false, false}, - {true, true, true, true} - }, - // horizontal - { - {textHemispherical, textHemispherical && (!candidates_count), false, false}, - {true, true, true, true} - }, - // vertical text - { - {textHemispherical && (!candidates_count), false, textHemispherical, false}, - {true, true, true, true} - } - }; +void weasel::StandardLayout::_PrepareRoundInfo(CDCHandle& dc) { + const int tmp[5] = {UIStyle::LAYOUT_VERTICAL, UIStyle::LAYOUT_HORIZONTAL, + UIStyle::LAYOUT_VERTICAL_TEXT, UIStyle::LAYOUT_VERTICAL, + UIStyle::LAYOUT_HORIZONTAL}; + int layout_type = tmp[_style.layout_type]; + bool textHemispherical = false, cand0Hemispherical = false; + if (!_style.inline_preedit) { + CRect textRect(_preeditRect); + textRect.InflateRect(_style.hilite_padding_x, _style.hilite_padding_y); + textHemispherical = _IsHighlightOverCandidateWindow(textRect, dc); + const bool hilite_rd_info[3][2][4] = { + // vertical + {{textHemispherical, textHemispherical && (!candidates_count), false, + false}, + {true, true, true, true}}, + // horizontal + {{textHemispherical, textHemispherical && (!candidates_count), false, + false}, + {true, true, true, true}}, + // vertical text + {{textHemispherical && (!candidates_count), false, textHemispherical, + false}, + {true, true, true, true}}}; + + _textRoundInfo.IsTopLeftNeedToRound = + hilite_rd_info[layout_type][_style.inline_preedit][0]; + _textRoundInfo.IsBottomLeftNeedToRound = + hilite_rd_info[layout_type][_style.inline_preedit][1]; + _textRoundInfo.IsTopRightNeedToRound = + hilite_rd_info[layout_type][_style.inline_preedit][2]; + _textRoundInfo.IsBottomRightNeedToRound = + hilite_rd_info[layout_type][_style.inline_preedit][3]; + _textRoundInfo.Hemispherical = textHemispherical; + if (_style.vertical_text_left_to_right && + _style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) { + _textRoundInfo.IsTopLeftNeedToRound = + !_textRoundInfo.IsTopLeftNeedToRound; + _textRoundInfo.IsTopRightNeedToRound = + !_textRoundInfo.IsTopRightNeedToRound; + } + } - _textRoundInfo.IsTopLeftNeedToRound = hilite_rd_info[layout_type][_style.inline_preedit][0]; - _textRoundInfo.IsBottomLeftNeedToRound = hilite_rd_info[layout_type][_style.inline_preedit][1]; - _textRoundInfo.IsTopRightNeedToRound = hilite_rd_info[layout_type][_style.inline_preedit][2]; - _textRoundInfo.IsBottomRightNeedToRound = hilite_rd_info[layout_type][_style.inline_preedit][3]; - _textRoundInfo.Hemispherical = textHemispherical; - if ( _style.vertical_text_left_to_right && _style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT ) - { - _textRoundInfo.IsTopLeftNeedToRound = !_textRoundInfo.IsTopLeftNeedToRound; - _textRoundInfo.IsTopRightNeedToRound = !_textRoundInfo.IsTopRightNeedToRound; - } - } - - if(candidates_count) - { - CRect cand0Rect(_candidateRects[0]); - cand0Rect.InflateRect(_style.hilite_padding_x, _style.hilite_padding_y); - cand0Hemispherical = _IsHighlightOverCandidateWindow(cand0Rect, dc); - if(textHemispherical || cand0Hemispherical) - { - //if (current_hemispherical_dome_status) _textRoundInfo.Hemispherical = true; - // level 0: m_style.layout_type == UIStyle::LAYOUT_HORIZONTAL - // level 1: m_style.inline_preedit - // level 2: BackType - // level 3: IsTopLeftNeedToRound, IsBottomLeftNeedToRound, IsTopRightNeedToRound, IsBottomRightNeedToRound - const static bool is_to_round_corner[3][2][5][4] = - { - // LAYOUT_VERTICAL - { - // not inline_preedit - { - {false, false, false, false}, // FIRST_CAND - {false, false, false, false}, // MID_CAND - {false, true, false, true}, // LAST_CAND - {false, true, false, true}, // ONLY_CAND - } , - // inline_preedit - { - {true, false, true, false}, // FIRST_CAND - {false, false, false, false}, // MID_CAND - {false, true, false, true}, // LAST_CAND - {true, true, true, true}, // ONLY_CAND - } - } , - // LAYOUT_HORIZONTAL - { - // not inline_preedit - { - {false, true, false, false}, // FIRST_CAND - {false, false, false, false}, // MID_CAND - {false, false, false, true}, // LAST_CAND - {false, true, false, true}, // ONLY_CAND - } , - // inline_preedit - { - {true, true, false, false}, // FIRST_CAND - {false, false, false, false}, // MID_CAND - {false, false, true, true}, // LAST_CAND - {true, true, true, true}, // ONLY_CAND - } - }, - // LAYOUT_VERTICAL_TEXT - { - // not inline_preedit - { - {false, false, false, false}, // FIRST_CAND - {false, false, false, false}, // MID_CAND - {true, true, false, false}, // LAST_CAND - {false, false, true, true}, // ONLY_CAND - } , - // inline_preedit - { - {false, false, true, true}, // FIRST_CAND - {false, false, false, false}, // MID_CAND - {true, true, false, false}, // LAST_CAND - {true, true, true, true}, // ONLY_CAND - } - } , - }; - for (auto i = 0; i < candidates_count; i++) - { - CRect hilite_rect(_candidateRects[i]); - hilite_rect.InflateRect(_style.hilite_padding_x, _style.hilite_padding_y); - bool current_hemispherical_dome_status = _IsHighlightOverCandidateWindow(hilite_rect, dc); - int type = 0; // default FIRST_CAND - if (candidates_count == 1) // ONLY_CAND - type =3; - else if (i != 0 && i != candidates_count - 1) // MID_CAND - type = 1; - else if (i == candidates_count - 1) // LAST_CAND - type = 2; - _roundInfo[i].IsTopLeftNeedToRound = is_to_round_corner[layout_type][_style.inline_preedit][type][0]; - _roundInfo[i].IsBottomLeftNeedToRound = is_to_round_corner[layout_type][_style.inline_preedit][type][1]; - _roundInfo[i].IsTopRightNeedToRound = is_to_round_corner[layout_type][_style.inline_preedit][type][2]; - _roundInfo[i].IsBottomRightNeedToRound = is_to_round_corner[layout_type][_style.inline_preedit][type][3]; - _roundInfo[i].Hemispherical = current_hemispherical_dome_status; - } - // fix round info for vetical text layout when vertical_text_left_to_right is set - if ( _style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT && _style.vertical_text_left_to_right ) - { - if ( _style.inline_preedit ) - { - if(candidates_count > 1) - { - _roundInfo[candidates_count - 1].IsTopLeftNeedToRound = !_roundInfo[candidates_count - 1].IsTopLeftNeedToRound; - _roundInfo[candidates_count - 1].IsTopRightNeedToRound = !_roundInfo[candidates_count - 1].IsTopRightNeedToRound; - _roundInfo[candidates_count - 1].IsBottomLeftNeedToRound = !_roundInfo[candidates_count - 1].IsBottomLeftNeedToRound; - _roundInfo[candidates_count - 1].IsBottomRightNeedToRound = !_roundInfo[candidates_count - 1].IsBottomRightNeedToRound; - _roundInfo[0].IsTopLeftNeedToRound = !_roundInfo[0].IsTopLeftNeedToRound; - _roundInfo[0].IsTopRightNeedToRound = !_roundInfo[0].IsTopRightNeedToRound; - _roundInfo[0].IsBottomLeftNeedToRound = !_roundInfo[0].IsBottomLeftNeedToRound; - _roundInfo[0].IsBottomRightNeedToRound = !_roundInfo[0].IsBottomRightNeedToRound; - } - } - else - { - if(candidates_count > 1) - { - _roundInfo[candidates_count - 1].IsTopLeftNeedToRound = !_roundInfo[candidates_count - 1].IsTopLeftNeedToRound; - _roundInfo[candidates_count - 1].IsTopRightNeedToRound = !_roundInfo[candidates_count - 1].IsTopRightNeedToRound; - _roundInfo[candidates_count - 1].IsBottomLeftNeedToRound = !_roundInfo[candidates_count - 1].IsBottomLeftNeedToRound; - _roundInfo[candidates_count - 1].IsBottomRightNeedToRound = !_roundInfo[candidates_count - 1].IsBottomRightNeedToRound; - } - } - } - } - } + if (candidates_count) { + CRect cand0Rect(_candidateRects[0]); + cand0Rect.InflateRect(_style.hilite_padding_x, _style.hilite_padding_y); + cand0Hemispherical = _IsHighlightOverCandidateWindow(cand0Rect, dc); + if (textHemispherical || cand0Hemispherical) { + // if (current_hemispherical_dome_status) _textRoundInfo.Hemispherical = + // true; + // level 0: m_style.layout_type == UIStyle::LAYOUT_HORIZONTAL + // level 1: m_style.inline_preedit + // level 2: BackType + // level 3: IsTopLeftNeedToRound, IsBottomLeftNeedToRound, + // IsTopRightNeedToRound, IsBottomRightNeedToRound + const static bool is_to_round_corner[3][2][5][4] = { + // LAYOUT_VERTICAL + {// not inline_preedit + { + {false, false, false, false}, // FIRST_CAND + {false, false, false, false}, // MID_CAND + {false, true, false, true}, // LAST_CAND + {false, true, false, true}, // ONLY_CAND + }, + // inline_preedit + { + {true, false, true, false}, // FIRST_CAND + {false, false, false, false}, // MID_CAND + {false, true, false, true}, // LAST_CAND + {true, true, true, true}, // ONLY_CAND + }}, + // LAYOUT_HORIZONTAL + {// not inline_preedit + { + {false, true, false, false}, // FIRST_CAND + {false, false, false, false}, // MID_CAND + {false, false, false, true}, // LAST_CAND + {false, true, false, true}, // ONLY_CAND + }, + // inline_preedit + { + {true, true, false, false}, // FIRST_CAND + {false, false, false, false}, // MID_CAND + {false, false, true, true}, // LAST_CAND + {true, true, true, true}, // ONLY_CAND + }}, + // LAYOUT_VERTICAL_TEXT + {// not inline_preedit + { + {false, false, false, false}, // FIRST_CAND + {false, false, false, false}, // MID_CAND + {true, true, false, false}, // LAST_CAND + {false, false, true, true}, // ONLY_CAND + }, + // inline_preedit + { + {false, false, true, true}, // FIRST_CAND + {false, false, false, false}, // MID_CAND + {true, true, false, false}, // LAST_CAND + {true, true, true, true}, // ONLY_CAND + }}, + }; + for (auto i = 0; i < candidates_count; i++) { + CRect hilite_rect(_candidateRects[i]); + hilite_rect.InflateRect(_style.hilite_padding_x, + _style.hilite_padding_y); + bool current_hemispherical_dome_status = + _IsHighlightOverCandidateWindow(hilite_rect, dc); + int type = 0; // default FIRST_CAND + if (candidates_count == 1) // ONLY_CAND + type = 3; + else if (i != 0 && i != candidates_count - 1) // MID_CAND + type = 1; + else if (i == candidates_count - 1) // LAST_CAND + type = 2; + _roundInfo[i].IsTopLeftNeedToRound = + is_to_round_corner[layout_type][_style.inline_preedit][type][0]; + _roundInfo[i].IsBottomLeftNeedToRound = + is_to_round_corner[layout_type][_style.inline_preedit][type][1]; + _roundInfo[i].IsTopRightNeedToRound = + is_to_round_corner[layout_type][_style.inline_preedit][type][2]; + _roundInfo[i].IsBottomRightNeedToRound = + is_to_round_corner[layout_type][_style.inline_preedit][type][3]; + _roundInfo[i].Hemispherical = current_hemispherical_dome_status; + } + // fix round info for vetical text layout when vertical_text_left_to_right + // is set + if (_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT && + _style.vertical_text_left_to_right) { + if (_style.inline_preedit) { + if (candidates_count > 1) { + _roundInfo[candidates_count - 1].IsTopLeftNeedToRound = + !_roundInfo[candidates_count - 1].IsTopLeftNeedToRound; + _roundInfo[candidates_count - 1].IsTopRightNeedToRound = + !_roundInfo[candidates_count - 1].IsTopRightNeedToRound; + _roundInfo[candidates_count - 1].IsBottomLeftNeedToRound = + !_roundInfo[candidates_count - 1].IsBottomLeftNeedToRound; + _roundInfo[candidates_count - 1].IsBottomRightNeedToRound = + !_roundInfo[candidates_count - 1].IsBottomRightNeedToRound; + _roundInfo[0].IsTopLeftNeedToRound = + !_roundInfo[0].IsTopLeftNeedToRound; + _roundInfo[0].IsTopRightNeedToRound = + !_roundInfo[0].IsTopRightNeedToRound; + _roundInfo[0].IsBottomLeftNeedToRound = + !_roundInfo[0].IsBottomLeftNeedToRound; + _roundInfo[0].IsBottomRightNeedToRound = + !_roundInfo[0].IsBottomRightNeedToRound; + } + } else { + if (candidates_count > 1) { + _roundInfo[candidates_count - 1].IsTopLeftNeedToRound = + !_roundInfo[candidates_count - 1].IsTopLeftNeedToRound; + _roundInfo[candidates_count - 1].IsTopRightNeedToRound = + !_roundInfo[candidates_count - 1].IsTopRightNeedToRound; + _roundInfo[candidates_count - 1].IsBottomLeftNeedToRound = + !_roundInfo[candidates_count - 1].IsBottomLeftNeedToRound; + _roundInfo[candidates_count - 1].IsBottomRightNeedToRound = + !_roundInfo[candidates_count - 1].IsBottomRightNeedToRound; + } + } + } + } + } } -void StandardLayout::UpdateStatusIconLayout(int* width, int* height) -{ - // rule 1. status icon is middle-aligned with preedit text or auxiliary text, whichever comes first - // rule 2. there is a spacing between preedit/aux text and the status icon - // rule 3. status icon is right aligned in WeaselPanel, when [margin_x + width(preedit/aux) + spacing + width(icon) + margin_x] < style.min_width - if (ShouldDisplayStatusIcon()) - { - if(_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) - { - int top = 0, middle = 0; - if(!_preeditRect.IsRectNull()) - { - top = _preeditRect.bottom + _style.spacing; - middle = (_preeditRect.left + _preeditRect.right) / 2; - } - else if(!_auxiliaryRect.IsRectNull()) - { - top = _auxiliaryRect.bottom + _style.spacing; - middle = (_auxiliaryRect.left + _auxiliaryRect.right) / 2; - } - if(top && middle) - { - int bottom_alignment = *height - real_margin_y - STATUS_ICON_SIZE; - if( top > bottom_alignment ) - { - *height = top + STATUS_ICON_SIZE + real_margin_y; - } - else - { - top = bottom_alignment; - } - _statusIconRect.SetRect(middle - STATUS_ICON_SIZE / 2 + 1, top, middle + STATUS_ICON_SIZE, top + STATUS_ICON_SIZE / 2 + 1); - } - else - { - _statusIconRect.SetRect(0,0, STATUS_ICON_SIZE, STATUS_ICON_SIZE); - _statusIconRect.OffsetRect(offsetX, offsetY); - *width = STATUS_ICON_SIZE ; - *height = (_style.vertical_text_with_wrap? offsetY : 0) + STATUS_ICON_SIZE; - } - } - else - { - int left = 0, middle = 0; - if (!_preeditRect.IsRectNull()) - { - left = _preeditRect.right + _style.spacing; - middle = (_preeditRect.top + _preeditRect.bottom) / 2; - } - else if (!_auxiliaryRect.IsRectNull()) - { - left = _auxiliaryRect.right + _style.spacing; - middle = (_auxiliaryRect.top + _auxiliaryRect.bottom) / 2; - } - if (left && middle) - { - int right_alignment = *width - real_margin_x - STATUS_ICON_SIZE; - if (left > right_alignment) - { - *width = left + STATUS_ICON_SIZE + real_margin_x; - } - else - { - left = right_alignment; - } - _statusIconRect.SetRect(left, middle - STATUS_ICON_SIZE / 2 + 1, left + STATUS_ICON_SIZE, middle + STATUS_ICON_SIZE / 2 + 1); - } - else - { - _statusIconRect.SetRect(0, 0, STATUS_ICON_SIZE, STATUS_ICON_SIZE); - _statusIconRect.OffsetRect(offsetX, offsetY); - *width = *height = STATUS_ICON_SIZE; - } - } - } - if (IS_FULLSCREENLAYOUT(_style)) - _statusIconRect.OffsetRect(-_style.border, -_style.border); +void StandardLayout::UpdateStatusIconLayout(int* width, int* height) { + // rule 1. status icon is middle-aligned with preedit text or auxiliary text, + // whichever comes first rule 2. there is a spacing between preedit/aux text + // and the status icon rule 3. status icon is right aligned in WeaselPanel, + // when [margin_x + width(preedit/aux) + spacing + width(icon) + margin_x] < + // style.min_width + if (ShouldDisplayStatusIcon()) { + if (_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) { + int top = 0, middle = 0; + if (!_preeditRect.IsRectNull()) { + top = _preeditRect.bottom + _style.spacing; + middle = (_preeditRect.left + _preeditRect.right) / 2; + } else if (!_auxiliaryRect.IsRectNull()) { + top = _auxiliaryRect.bottom + _style.spacing; + middle = (_auxiliaryRect.left + _auxiliaryRect.right) / 2; + } + if (top && middle) { + int bottom_alignment = *height - real_margin_y - STATUS_ICON_SIZE; + if (top > bottom_alignment) { + *height = top + STATUS_ICON_SIZE + real_margin_y; + } else { + top = bottom_alignment; + } + _statusIconRect.SetRect(middle - STATUS_ICON_SIZE / 2 + 1, top, + middle + STATUS_ICON_SIZE, + top + STATUS_ICON_SIZE / 2 + 1); + } else { + _statusIconRect.SetRect(0, 0, STATUS_ICON_SIZE, STATUS_ICON_SIZE); + _statusIconRect.OffsetRect(offsetX, offsetY); + *width = STATUS_ICON_SIZE; + *height = + (_style.vertical_text_with_wrap ? offsetY : 0) + STATUS_ICON_SIZE; + } + } else { + int left = 0, middle = 0; + if (!_preeditRect.IsRectNull()) { + left = _preeditRect.right + _style.spacing; + middle = (_preeditRect.top + _preeditRect.bottom) / 2; + } else if (!_auxiliaryRect.IsRectNull()) { + left = _auxiliaryRect.right + _style.spacing; + middle = (_auxiliaryRect.top + _auxiliaryRect.bottom) / 2; + } + if (left && middle) { + int right_alignment = *width - real_margin_x - STATUS_ICON_SIZE; + if (left > right_alignment) { + *width = left + STATUS_ICON_SIZE + real_margin_x; + } else { + left = right_alignment; + } + _statusIconRect.SetRect(left, middle - STATUS_ICON_SIZE / 2 + 1, + left + STATUS_ICON_SIZE, + middle + STATUS_ICON_SIZE / 2 + 1); + } else { + _statusIconRect.SetRect(0, 0, STATUS_ICON_SIZE, STATUS_ICON_SIZE); + _statusIconRect.OffsetRect(offsetX, offsetY); + *width = *height = STATUS_ICON_SIZE; + } + } + } + if (IS_FULLSCREENLAYOUT(_style)) + _statusIconRect.OffsetRect(-_style.border, -_style.border); } -bool StandardLayout::IsInlinePreedit() const -{ - return _style.inline_preedit && (_style.client_caps & weasel::INLINE_PREEDIT_CAPABLE) != 0 && - _style.layout_type != UIStyle::LAYOUT_VERTICAL_FULLSCREEN && _style.layout_type != UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN; +bool StandardLayout::IsInlinePreedit() const { + return _style.inline_preedit && + (_style.client_caps & weasel::INLINE_PREEDIT_CAPABLE) != 0 && + _style.layout_type != UIStyle::LAYOUT_VERTICAL_FULLSCREEN && + _style.layout_type != UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN; } -bool StandardLayout::ShouldDisplayStatusIcon() const -{ - // rule 1. emphasis ascii mode - // rule 2. show status icon when switching mode - // rule 3. always show status icon with tips - // rule 4. rule 3 excluding tips FullScreenLayout with strings - return ((_status.ascii_mode && !_style.inline_preedit)|| !_status.composing || !_context.aux.empty()) && !((_style.layout_type == UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN || _style.layout_type == UIStyle::LAYOUT_VERTICAL_FULLSCREEN) && !_context.aux.empty()); +bool StandardLayout::ShouldDisplayStatusIcon() const { + // rule 1. emphasis ascii mode + // rule 2. show status icon when switching mode + // rule 3. always show status icon with tips + // rule 4. rule 3 excluding tips FullScreenLayout with strings + return ((_status.ascii_mode && !_style.inline_preedit) || + !_status.composing || !_context.aux.empty()) && + !((_style.layout_type == UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN || + _style.layout_type == UIStyle::LAYOUT_VERTICAL_FULLSCREEN) && + !_context.aux.empty()); } diff --git a/WeaselUI/StandardLayout.h b/WeaselUI/StandardLayout.h index 1212c0191..9fd504f56 100644 --- a/WeaselUI/StandardLayout.h +++ b/WeaselUI/StandardLayout.h @@ -6,67 +6,83 @@ #pragma comment(lib, "d2d1.lib") #pragma comment(lib, "dwrite.lib") -namespace weasel -{ - const int MAX_CANDIDATES_COUNT = 100; - const int STATUS_ICON_SIZE = GetSystemMetrics(SM_CXICON); +namespace weasel { +const int MAX_CANDIDATES_COUNT = 100; +const int STATUS_ICON_SIZE = GetSystemMetrics(SM_CXICON); - class StandardLayout: public Layout - { - public: - StandardLayout(const UIStyle &style, const Context &context, const Status &status) : Layout(style, context, status){} +class StandardLayout : public Layout { + public: + StandardLayout(const UIStyle& style, + const Context& context, + const Status& status) + : Layout(style, context, status) {} - /* Layout */ + /* Layout */ - virtual void DoLayout(CDCHandle dc, PDWR pDWR = NULL) = 0; - virtual CSize GetContentSize() const { return _contentSize; } - virtual CRect GetPreeditRect() const { return _preeditRect; } - virtual CRect GetAuxiliaryRect() const { return _auxiliaryRect; } - virtual CRect GetHighlightRect() const { return _highlightRect; } - virtual CRect GetCandidateLabelRect(int id) const { return _candidateLabelRects[id]; } - virtual CRect GetCandidateTextRect(int id) const { return _candidateTextRects[id]; } - virtual CRect GetCandidateCommentRect(int id) const { return _candidateCommentRects[id]; } - virtual CRect GetCandidateRect(int id) const { return _candidateRects[id]; } - virtual CRect GetStatusIconRect() const { return _statusIconRect; } - virtual std::wstring GetLabelText(const std::vector &labels, int id, const wchar_t *format) const; - virtual bool IsInlinePreedit() const; - virtual bool ShouldDisplayStatusIcon() const; - virtual IsToRoundStruct GetRoundInfo(int id) { return _roundInfo[id]; } - virtual IsToRoundStruct GetTextRoundInfo() { return _textRoundInfo; } - virtual CRect GetContentRect() { return _contentRect; } - virtual CRect GetPrepageRect() { return _prePageRect; } - virtual CRect GetNextpageRect() { return _nextPageRect; } - virtual CSize GetBeforeSize() { return _beforesz; } - virtual CSize GetHilitedSize() { return _hilitedsz; } - virtual CSize GetAfterSize() { return _aftersz; } - virtual weasel::TextRange GetPreeditRange() { return _range; } + virtual void DoLayout(CDCHandle dc, PDWR pDWR = NULL) = 0; + virtual CSize GetContentSize() const { return _contentSize; } + virtual CRect GetPreeditRect() const { return _preeditRect; } + virtual CRect GetAuxiliaryRect() const { return _auxiliaryRect; } + virtual CRect GetHighlightRect() const { return _highlightRect; } + virtual CRect GetCandidateLabelRect(int id) const { + return _candidateLabelRects[id]; + } + virtual CRect GetCandidateTextRect(int id) const { + return _candidateTextRects[id]; + } + virtual CRect GetCandidateCommentRect(int id) const { + return _candidateCommentRects[id]; + } + virtual CRect GetCandidateRect(int id) const { return _candidateRects[id]; } + virtual CRect GetStatusIconRect() const { return _statusIconRect; } + virtual std::wstring GetLabelText(const std::vector& labels, + int id, + const wchar_t* format) const; + virtual bool IsInlinePreedit() const; + virtual bool ShouldDisplayStatusIcon() const; + virtual IsToRoundStruct GetRoundInfo(int id) { return _roundInfo[id]; } + virtual IsToRoundStruct GetTextRoundInfo() { return _textRoundInfo; } + virtual CRect GetContentRect() { return _contentRect; } + virtual CRect GetPrepageRect() { return _prePageRect; } + virtual CRect GetNextpageRect() { return _nextPageRect; } + virtual CSize GetBeforeSize() { return _beforesz; } + virtual CSize GetHilitedSize() { return _hilitedsz; } + virtual CSize GetAfterSize() { return _aftersz; } + virtual weasel::TextRange GetPreeditRange() { return _range; } - void GetTextSizeDW(const std::wstring text, size_t nCount, ComPtr pTextFormat, PDWR pDWR, LPSIZE lpSize) const; + void GetTextSizeDW(const std::wstring text, + size_t nCount, + ComPtr pTextFormat, + PDWR pDWR, + LPSIZE lpSize) const; - protected: - /* Utility functions */ - CSize GetPreeditSize(CDCHandle dc, const weasel::Text& text, ComPtr pTextFormat = NULL, PDWR pDWR = NULL); - bool _IsHighlightOverCandidateWindow(CRect& rc, CDCHandle& dc); - void _PrepareRoundInfo(CDCHandle& dc); + protected: + /* Utility functions */ + CSize GetPreeditSize(CDCHandle dc, + const weasel::Text& text, + ComPtr pTextFormat = NULL, + PDWR pDWR = NULL); + bool _IsHighlightOverCandidateWindow(CRect& rc, CDCHandle& dc); + void _PrepareRoundInfo(CDCHandle& dc); - void UpdateStatusIconLayout(int* width, int* height); + void UpdateStatusIconLayout(int* width, int* height); - CSize _beforesz, _hilitedsz, _aftersz; - weasel::TextRange _range; - CSize _contentSize; - CRect _preeditRect, _auxiliaryRect, _highlightRect; - CRect _candidateRects[MAX_CANDIDATES_COUNT]; - CRect _candidateLabelRects[MAX_CANDIDATES_COUNT]; - CRect _candidateTextRects[MAX_CANDIDATES_COUNT]; - CRect _candidateCommentRects[MAX_CANDIDATES_COUNT]; - CRect _statusIconRect; - CRect _bgRect; - CRect _contentRect; - IsToRoundStruct _roundInfo[MAX_CANDIDATES_COUNT]; - IsToRoundStruct _textRoundInfo; - CRect _prePageRect; - CRect _nextPageRect; - const std::wstring pre = L"<"; - const std::wstring next = L">"; - }; + CSize _beforesz, _hilitedsz, _aftersz; + weasel::TextRange _range; + CSize _contentSize; + CRect _preeditRect, _auxiliaryRect, _highlightRect; + CRect _candidateRects[MAX_CANDIDATES_COUNT]; + CRect _candidateLabelRects[MAX_CANDIDATES_COUNT]; + CRect _candidateTextRects[MAX_CANDIDATES_COUNT]; + CRect _candidateCommentRects[MAX_CANDIDATES_COUNT]; + CRect _statusIconRect; + CRect _bgRect; + CRect _contentRect; + IsToRoundStruct _roundInfo[MAX_CANDIDATES_COUNT]; + IsToRoundStruct _textRoundInfo; + CRect _prePageRect; + CRect _nextPageRect; + const std::wstring pre = L"<"; + const std::wstring next = L">"; }; +}; // namespace weasel diff --git a/WeaselUI/VHorizontalLayout.cpp b/WeaselUI/VHorizontalLayout.cpp index bc7462693..c50f06bda 100644 --- a/WeaselUI/VHorizontalLayout.cpp +++ b/WeaselUI/VHorizontalLayout.cpp @@ -4,536 +4,565 @@ using namespace weasel; -void VHorizontalLayout::DoLayout(CDCHandle dc, PDWR pDWR ) -{ - if(_style.vertical_text_with_wrap) - { - DoLayoutWithWrap(dc, pDWR); - return; - } +void VHorizontalLayout::DoLayout(CDCHandle dc, PDWR pDWR) { + if (_style.vertical_text_with_wrap) { + DoLayoutWithWrap(dc, pDWR); + return; + } - CSize size; - int height = offsetY, width = offsetX + real_margin_x; - int h = offsetY + real_margin_y; + CSize size; + int height = offsetY, width = offsetX + real_margin_x; + int h = offsetY + real_margin_y; - if ((_style.hilited_mark_color & 0xff000000)) - { - CSize sg; - if(_style.mark_text.empty()) - GetTextSizeDW(L"|", 1, pDWR->pTextFormat, pDWR, &sg); - else - GetTextSizeDW(_style.mark_text, _style.mark_text.length(), pDWR->pTextFormat, pDWR, &sg); + if ((_style.hilited_mark_color & 0xff000000)) { + CSize sg; + if (_style.mark_text.empty()) + GetTextSizeDW(L"|", 1, pDWR->pTextFormat, pDWR, &sg); + else + GetTextSizeDW(_style.mark_text, _style.mark_text.length(), + pDWR->pTextFormat, pDWR, &sg); - MARK_WIDTH = sg.cx; - MARK_HEIGHT = sg.cy; - if(_style.mark_text.empty()) - MARK_HEIGHT /= 2; - MARK_GAP = (_style.mark_text.empty()) ? MARK_HEIGHT : MARK_HEIGHT + _style.hilite_spacing; - } - int base_offset = ((_style.hilited_mark_color & 0xff000000)) ? MARK_GAP : 0; + MARK_WIDTH = sg.cx; + MARK_HEIGHT = sg.cy; + if (_style.mark_text.empty()) + MARK_HEIGHT /= 2; + MARK_GAP = (_style.mark_text.empty()) ? MARK_HEIGHT + : MARK_HEIGHT + _style.hilite_spacing; + } + int base_offset = ((_style.hilited_mark_color & 0xff000000)) ? MARK_GAP : 0; - // calc page indicator - CSize pgszl, pgszr; - GetTextSizeDW(pre, pre.length(), pDWR->pPreeditTextFormat, pDWR, &pgszl); - GetTextSizeDW(next, next.length(), pDWR->pPreeditTextFormat, pDWR, &pgszr); - bool page_en = (_style.prevpage_color & 0xff000000) && (_style.nextpage_color & 0xff000000); - int pgh = page_en ? pgszl.cy + pgszr.cy + _style.hilite_spacing + _style.hilite_padding_y * 2 : 0; - int pgw = page_en ? max(pgszl.cx, pgszr.cx) : 0; + // calc page indicator + CSize pgszl, pgszr; + GetTextSizeDW(pre, pre.length(), pDWR->pPreeditTextFormat, pDWR, &pgszl); + GetTextSizeDW(next, next.length(), pDWR->pPreeditTextFormat, pDWR, &pgszr); + bool page_en = (_style.prevpage_color & 0xff000000) && + (_style.nextpage_color & 0xff000000); + int pgh = page_en ? pgszl.cy + pgszr.cy + _style.hilite_spacing + + _style.hilite_padding_y * 2 + : 0; + int pgw = page_en ? max(pgszl.cx, pgszr.cx) : 0; - /* Preedit */ - if (!IsInlinePreedit() && !_context.preedit.str.empty()) - { - size = GetPreeditSize(dc, _context.preedit, pDWR->pPreeditTextFormat, pDWR); - int szx = max(size.cx, pgw), szy = pgh; - // icon size wider then preedit text - int xoffset = (STATUS_ICON_SIZE >= szx && ShouldDisplayStatusIcon()) ? (STATUS_ICON_SIZE - szx) / 2 : 0; - _preeditRect.SetRect(width + xoffset, h, width + xoffset + size.cx, h + size.cy); - width += size.cx + xoffset * 2 + _style.spacing; - height = max(height, offsetY + real_margin_y + size.cy + szy); - if(ShouldDisplayStatusIcon()) height += STATUS_ICON_SIZE; - } + /* Preedit */ + if (!IsInlinePreedit() && !_context.preedit.str.empty()) { + size = GetPreeditSize(dc, _context.preedit, pDWR->pPreeditTextFormat, pDWR); + int szx = max(size.cx, pgw), szy = pgh; + // icon size wider then preedit text + int xoffset = (STATUS_ICON_SIZE >= szx && ShouldDisplayStatusIcon()) + ? (STATUS_ICON_SIZE - szx) / 2 + : 0; + _preeditRect.SetRect(width + xoffset, h, width + xoffset + size.cx, + h + size.cy); + width += size.cx + xoffset * 2 + _style.spacing; + height = max(height, offsetY + real_margin_y + size.cy + szy); + if (ShouldDisplayStatusIcon()) + height += STATUS_ICON_SIZE; + } - /* Auxiliary */ - if (!_context.aux.str.empty()) - { - size = GetPreeditSize(dc, _context.aux, pDWR->pPreeditTextFormat, pDWR); - // icon size wider then preedit text - int xoffset = (STATUS_ICON_SIZE >= size.cx && ShouldDisplayStatusIcon()) ? (STATUS_ICON_SIZE - size.cx) / 2 : 0; - _auxiliaryRect.SetRect(width + xoffset, h, width + xoffset + size.cx, h + size.cy); - width += size.cx + xoffset * 2 + _style.spacing; - height = max(height, offsetY + real_margin_y + size.cy); - } - /* Candidates */ - int wids[MAX_CANDIDATES_COUNT] = {0}; - int w = width; - int max_comment_heihgt = 0, max_content_height = 0; - if (candidates_count) - { - for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) - { - int wid = 0; - h = offsetY + real_margin_y + base_offset; - /* Label */ - std::wstring label = GetLabelText(labels, i, _style.label_text_format.c_str()); - GetTextSizeDW(label, label.length(), pDWR->pLabelTextFormat, pDWR, &size); - _candidateLabelRects[i].SetRect(w, h, w + size.cx * labelFontValid, h + size.cy); - h += size.cy * labelFontValid; - max_content_height = max(max_content_height, h); - wid = max(wid, size.cx); + /* Auxiliary */ + if (!_context.aux.str.empty()) { + size = GetPreeditSize(dc, _context.aux, pDWR->pPreeditTextFormat, pDWR); + // icon size wider then preedit text + int xoffset = (STATUS_ICON_SIZE >= size.cx && ShouldDisplayStatusIcon()) + ? (STATUS_ICON_SIZE - size.cx) / 2 + : 0; + _auxiliaryRect.SetRect(width + xoffset, h, width + xoffset + size.cx, + h + size.cy); + width += size.cx + xoffset * 2 + _style.spacing; + height = max(height, offsetY + real_margin_y + size.cy); + } + /* Candidates */ + int wids[MAX_CANDIDATES_COUNT] = {0}; + int w = width; + int max_comment_heihgt = 0, max_content_height = 0; + if (candidates_count) { + for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) { + int wid = 0; + h = offsetY + real_margin_y + base_offset; + /* Label */ + std::wstring label = + GetLabelText(labels, i, _style.label_text_format.c_str()); + GetTextSizeDW(label, label.length(), pDWR->pLabelTextFormat, pDWR, &size); + _candidateLabelRects[i].SetRect(w, h, w + size.cx * labelFontValid, + h + size.cy); + h += size.cy * labelFontValid; + max_content_height = max(max_content_height, h); + wid = max(wid, size.cx); - /* Text */ - h += _style.hilite_spacing * labelFontValid; - const std::wstring& text = candidates.at(i).str; - GetTextSizeDW(text, text.length(), pDWR->pTextFormat, pDWR, &size); - _candidateTextRects[i].SetRect(w, h, w + size.cx * textFontValid, h + size.cy); - h += size.cy * textFontValid; - max_content_height = max(max_content_height, h); - wid = max(wid, size.cx); + /* Text */ + h += _style.hilite_spacing * labelFontValid; + const std::wstring& text = candidates.at(i).str; + GetTextSizeDW(text, text.length(), pDWR->pTextFormat, pDWR, &size); + _candidateTextRects[i].SetRect(w, h, w + size.cx * textFontValid, + h + size.cy); + h += size.cy * textFontValid; + max_content_height = max(max_content_height, h); + wid = max(wid, size.cx); - /* Comment */ - bool cmtFontNotTrans = (i == id && (_style.hilited_comment_text_color & 0xff000000)) || - (i != id && (_style.comment_text_color & 0xff000000)); - if (!comments.at(i).str.empty() && cmtFontValid && cmtFontNotTrans) - { - h += _style.hilite_spacing; - const std::wstring& comment = comments.at(i).str; - GetTextSizeDW(comment, comment.length(), pDWR->pCommentTextFormat, pDWR, &size); - _candidateCommentRects[i].SetRect(w, 0, w + size.cx * cmtFontValid, size.cy * cmtFontValid); - h += size.cy * cmtFontValid; - wid = max(wid, size.cx); - } - else /* Used for highlighted candidate calculation below */ - { - _candidateCommentRects[i].SetRect(w, 0, w, 0); - wid = max(wid, size.cx); - } - wids[i] = wid; - max_comment_heihgt = max(max_comment_heihgt, _candidateCommentRects[i].Height()); - w += wid + _style.candidate_spacing; - } - w -= _style.candidate_spacing; - } + /* Comment */ + bool cmtFontNotTrans = + (i == id && (_style.hilited_comment_text_color & 0xff000000)) || + (i != id && (_style.comment_text_color & 0xff000000)); + if (!comments.at(i).str.empty() && cmtFontValid && cmtFontNotTrans) { + h += _style.hilite_spacing; + const std::wstring& comment = comments.at(i).str; + GetTextSizeDW(comment, comment.length(), pDWR->pCommentTextFormat, pDWR, + &size); + _candidateCommentRects[i].SetRect(w, 0, w + size.cx * cmtFontValid, + size.cy * cmtFontValid); + h += size.cy * cmtFontValid; + wid = max(wid, size.cx); + } else /* Used for highlighted candidate calculation below */ + { + _candidateCommentRects[i].SetRect(w, 0, w, 0); + wid = max(wid, size.cx); + } + wids[i] = wid; + max_comment_heihgt = + max(max_comment_heihgt, _candidateCommentRects[i].Height()); + w += wid + _style.candidate_spacing; + } + w -= _style.candidate_spacing; + } - width = max(width, w); - width += real_margin_x; + width = max(width, w); + width += real_margin_x; - // reposition candidates - if (candidates_count) - { - for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) - { - int ol = 0, ot = 0, oc = 0; - if(_style.align_type == UIStyle::ALIGN_CENTER) - { - ol = (wids[i] - _candidateLabelRects[i].Width()) / 2; - ot = (wids[i] - _candidateTextRects[i].Width()) / 2; - oc = (wids[i] - _candidateCommentRects[i].Width()) / 2; - } - else if((_style.align_type == UIStyle::ALIGN_BOTTOM) && _style.vertical_text_left_to_right) - { - ol = (wids[i] - _candidateLabelRects[i].Width()); - ot = (wids[i] - _candidateTextRects[i].Width()); - oc = (wids[i] - _candidateCommentRects[i].Width()); - } - else if((_style.align_type == UIStyle::ALIGN_TOP) && (!_style.vertical_text_left_to_right)) - { - ol = (wids[i] - _candidateLabelRects[i].Width()); - ot = (wids[i] - _candidateTextRects[i].Width()); - oc = (wids[i] - _candidateCommentRects[i].Width()); - } - // offset rects - _candidateLabelRects[i].OffsetRect(ol, 0); - _candidateTextRects[i].OffsetRect(ot, 0); - _candidateCommentRects[i].OffsetRect(oc, max_content_height + _style.hilite_spacing); - // define _candidateRects - _candidateRects[i].left = min(_candidateLabelRects[i].left, _candidateTextRects[i].left); - _candidateRects[i].left = min(_candidateRects[i].left, _candidateCommentRects[i].left); - _candidateRects[i].right = max(_candidateLabelRects[i].right, _candidateTextRects[i].right); - _candidateRects[i].right = max(_candidateRects[i].right, _candidateCommentRects[i].right); - _candidateRects[i].top = _candidateLabelRects[i].top - base_offset; - _candidateRects[i].bottom = _candidateCommentRects[i].top + max_comment_heihgt; - } - height = max(height, offsetY + _candidateRects[0].Height() + real_margin_y); - if((_candidateRects[0].top - real_margin_y + height) > _candidateRects[0].bottom) - for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) - _candidateRects[i].bottom = (_candidateRects[0].top - offsetY - real_margin_y + height); - if(!_style.vertical_text_left_to_right) - { - // re position right to left - int base_left; - if ((!IsInlinePreedit() && !_context.preedit.str.empty())) - base_left = _preeditRect.left; - else if( !_context.aux.str.empty()) - base_left = _auxiliaryRect.left; - else - base_left = _candidateRects[0].left; - for(int i = candidates_count - 1; i>=0 ; i --) - { - int offset; - if(i == candidates_count - 1) - offset = base_left - _candidateRects[i].left; - else - offset = _candidateRects[i+1].right + _style.candidate_spacing - _candidateRects[i].left; - _candidateRects[i].OffsetRect(offset, 0); - _candidateLabelRects[i].OffsetRect(offset, 0); - _candidateTextRects[i].OffsetRect(offset, 0); - _candidateCommentRects[i].OffsetRect(offset, 0); - } - if (!IsInlinePreedit() && !_context.preedit.str.empty()) - _preeditRect.OffsetRect(_candidateRects[0].right + _style.spacing - _preeditRect.left, 0); - if (!_context.aux.str.empty()) - _auxiliaryRect.OffsetRect(_candidateRects[0].right + _style.spacing - _auxiliaryRect.left, 0); - } - } - else - width -= _style.spacing; + // reposition candidates + if (candidates_count) { + for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) { + int ol = 0, ot = 0, oc = 0; + if (_style.align_type == UIStyle::ALIGN_CENTER) { + ol = (wids[i] - _candidateLabelRects[i].Width()) / 2; + ot = (wids[i] - _candidateTextRects[i].Width()) / 2; + oc = (wids[i] - _candidateCommentRects[i].Width()) / 2; + } else if ((_style.align_type == UIStyle::ALIGN_BOTTOM) && + _style.vertical_text_left_to_right) { + ol = (wids[i] - _candidateLabelRects[i].Width()); + ot = (wids[i] - _candidateTextRects[i].Width()); + oc = (wids[i] - _candidateCommentRects[i].Width()); + } else if ((_style.align_type == UIStyle::ALIGN_TOP) && + (!_style.vertical_text_left_to_right)) { + ol = (wids[i] - _candidateLabelRects[i].Width()); + ot = (wids[i] - _candidateTextRects[i].Width()); + oc = (wids[i] - _candidateCommentRects[i].Width()); + } + // offset rects + _candidateLabelRects[i].OffsetRect(ol, 0); + _candidateTextRects[i].OffsetRect(ot, 0); + _candidateCommentRects[i].OffsetRect( + oc, max_content_height + _style.hilite_spacing); + // define _candidateRects + _candidateRects[i].left = + min(_candidateLabelRects[i].left, _candidateTextRects[i].left); + _candidateRects[i].left = + min(_candidateRects[i].left, _candidateCommentRects[i].left); + _candidateRects[i].right = + max(_candidateLabelRects[i].right, _candidateTextRects[i].right); + _candidateRects[i].right = + max(_candidateRects[i].right, _candidateCommentRects[i].right); + _candidateRects[i].top = _candidateLabelRects[i].top - base_offset; + _candidateRects[i].bottom = + _candidateCommentRects[i].top + max_comment_heihgt; + } + height = max(height, offsetY + _candidateRects[0].Height() + real_margin_y); + if ((_candidateRects[0].top - real_margin_y + height) > + _candidateRects[0].bottom) + for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) + _candidateRects[i].bottom = + (_candidateRects[0].top - offsetY - real_margin_y + height); + if (!_style.vertical_text_left_to_right) { + // re position right to left + int base_left; + if ((!IsInlinePreedit() && !_context.preedit.str.empty())) + base_left = _preeditRect.left; + else if (!_context.aux.str.empty()) + base_left = _auxiliaryRect.left; + else + base_left = _candidateRects[0].left; + for (int i = candidates_count - 1; i >= 0; i--) { + int offset; + if (i == candidates_count - 1) + offset = base_left - _candidateRects[i].left; + else + offset = _candidateRects[i + 1].right + _style.candidate_spacing - + _candidateRects[i].left; + _candidateRects[i].OffsetRect(offset, 0); + _candidateLabelRects[i].OffsetRect(offset, 0); + _candidateTextRects[i].OffsetRect(offset, 0); + _candidateCommentRects[i].OffsetRect(offset, 0); + } + if (!IsInlinePreedit() && !_context.preedit.str.empty()) + _preeditRect.OffsetRect( + _candidateRects[0].right + _style.spacing - _preeditRect.left, 0); + if (!_context.aux.str.empty()) + _auxiliaryRect.OffsetRect( + _candidateRects[0].right + _style.spacing - _auxiliaryRect.left, 0); + } + } else + width -= _style.spacing; - height += real_margin_y; - _highlightRect = _candidateRects[id]; - UpdateStatusIconLayout(&width, &height); - _contentSize.SetSize(width + offsetX, height + offsetY); + height += real_margin_y; + _highlightRect = _candidateRects[id]; + UpdateStatusIconLayout(&width, &height); + _contentSize.SetSize(width + offsetX, height + offsetY); - // calc page indicator - if(page_en && candidates_count && !_style.inline_preedit) - { - int _prey = _contentSize.cy - offsetY - real_margin_y + _style.hilite_padding_y - pgh; - int _prex = (_preeditRect.left + _preeditRect.right) / 2 - pgszl.cx / 2; - _prePageRect.SetRect(_prex, _prey, _prex + pgszl.cx, _prey + pgszl.cy); - _nextPageRect.SetRect(_prex, _prePageRect.bottom + _style.hilite_spacing, - _prex + pgszr.cx, _prePageRect.bottom + _style.hilite_spacing + pgszr.cy); - if (ShouldDisplayStatusIcon()) - { - _prePageRect.OffsetRect(0, -STATUS_ICON_SIZE); - _nextPageRect.OffsetRect(0, -STATUS_ICON_SIZE); - } - } + // calc page indicator + if (page_en && candidates_count && !_style.inline_preedit) { + int _prey = _contentSize.cy - offsetY - real_margin_y + + _style.hilite_padding_y - pgh; + int _prex = (_preeditRect.left + _preeditRect.right) / 2 - pgszl.cx / 2; + _prePageRect.SetRect(_prex, _prey, _prex + pgszl.cx, _prey + pgszl.cy); + _nextPageRect.SetRect( + _prex, _prePageRect.bottom + _style.hilite_spacing, _prex + pgszr.cx, + _prePageRect.bottom + _style.hilite_spacing + pgszr.cy); + if (ShouldDisplayStatusIcon()) { + _prePageRect.OffsetRect(0, -STATUS_ICON_SIZE); + _nextPageRect.OffsetRect(0, -STATUS_ICON_SIZE); + } + } - _contentRect.SetRect(0, 0, _contentSize.cx, _contentSize.cy); - // background rect prepare for Hemispherical calculation - CopyRect(_bgRect, _contentRect); - _bgRect.DeflateRect(offsetX + 1, offsetY + 1); - // prepare round info - _PrepareRoundInfo(dc); + _contentRect.SetRect(0, 0, _contentSize.cx, _contentSize.cy); + // background rect prepare for Hemispherical calculation + CopyRect(_bgRect, _contentRect); + _bgRect.DeflateRect(offsetX + 1, offsetY + 1); + // prepare round info + _PrepareRoundInfo(dc); - // truely draw content size calculation - _contentRect.DeflateRect(offsetX, offsetY); + // truely draw content size calculation + _contentRect.DeflateRect(offsetX, offsetY); } -void VHorizontalLayout::DoLayoutWithWrap(CDCHandle dc, PDWR pDWR) -{ - CSize size; - int height = offsetY, width = offsetX + real_margin_x; - int h = offsetY + real_margin_y; +void VHorizontalLayout::DoLayoutWithWrap(CDCHandle dc, PDWR pDWR) { + CSize size; + int height = offsetY, width = offsetX + real_margin_x; + int h = offsetY + real_margin_y; - if ((_style.hilited_mark_color & 0xff000000)) - { - CSize sg; - if(_style.mark_text.empty()) - GetTextSizeDW(L"|", 1, pDWR->pTextFormat, pDWR, &sg); - else - GetTextSizeDW(_style.mark_text, _style.mark_text.length(), pDWR->pTextFormat, pDWR, &sg); + if ((_style.hilited_mark_color & 0xff000000)) { + CSize sg; + if (_style.mark_text.empty()) + GetTextSizeDW(L"|", 1, pDWR->pTextFormat, pDWR, &sg); + else + GetTextSizeDW(_style.mark_text, _style.mark_text.length(), + pDWR->pTextFormat, pDWR, &sg); - MARK_WIDTH = sg.cx; - MARK_HEIGHT = sg.cy; - if(_style.mark_text.empty()) - MARK_HEIGHT /= 2; - MARK_GAP = (_style.mark_text.empty()) ? MARK_HEIGHT : MARK_HEIGHT + _style.hilite_spacing; - } - int base_offset = ((_style.hilited_mark_color & 0xff000000)) ? MARK_GAP : 0; + MARK_WIDTH = sg.cx; + MARK_HEIGHT = sg.cy; + if (_style.mark_text.empty()) + MARK_HEIGHT /= 2; + MARK_GAP = (_style.mark_text.empty()) ? MARK_HEIGHT + : MARK_HEIGHT + _style.hilite_spacing; + } + int base_offset = ((_style.hilited_mark_color & 0xff000000)) ? MARK_GAP : 0; - // calc page indicator - CSize pgszl, pgszr; - GetTextSizeDW(pre, pre.length(), pDWR->pPreeditTextFormat, pDWR, &pgszl); - GetTextSizeDW(next, next.length(), pDWR->pPreeditTextFormat, pDWR, &pgszr); - bool page_en = (_style.prevpage_color & 0xff000000) && (_style.nextpage_color & 0xff000000); - int pgh = page_en ? pgszl.cy + pgszr.cy + _style.hilite_spacing + _style.hilite_padding_y * 2 : 0; - int pgw = page_en ? max(pgszl.cx, pgszr.cx) : 0; + // calc page indicator + CSize pgszl, pgszr; + GetTextSizeDW(pre, pre.length(), pDWR->pPreeditTextFormat, pDWR, &pgszl); + GetTextSizeDW(next, next.length(), pDWR->pPreeditTextFormat, pDWR, &pgszr); + bool page_en = (_style.prevpage_color & 0xff000000) && + (_style.nextpage_color & 0xff000000); + int pgh = page_en ? pgszl.cy + pgszr.cy + _style.hilite_spacing + + _style.hilite_padding_y * 2 + : 0; + int pgw = page_en ? max(pgszl.cx, pgszr.cx) : 0; - /* Preedit */ - if (!IsInlinePreedit() && !_context.preedit.str.empty()) - { - size = GetPreeditSize(dc, _context.preedit, pDWR->pPreeditTextFormat, pDWR); - size_t szx = max(size.cx, pgw), szy = pgh; - // icon size wider then preedit text - int xoffset = (STATUS_ICON_SIZE >= szx && ShouldDisplayStatusIcon()) ? (STATUS_ICON_SIZE - szx) / 2 : 0; - _preeditRect.SetRect(width + xoffset, h, width + xoffset + size.cx, h + size.cy); - width += size.cx + xoffset * 2 + _style.spacing; - height = max(height, offsetY + real_margin_y + size.cy + szy); - if(ShouldDisplayStatusIcon()) height += STATUS_ICON_SIZE; - } - /* Auxiliary */ - if (!_context.aux.str.empty()) - { - size = GetPreeditSize(dc, _context.aux, pDWR->pPreeditTextFormat, pDWR); - // icon size wider then auxiliary text - int xoffset = (STATUS_ICON_SIZE >= size.cx && ShouldDisplayStatusIcon()) ? (STATUS_ICON_SIZE - size.cx) / 2 : 0; - _auxiliaryRect.SetRect(width + xoffset, h, width + xoffset + size.cx, h + size.cy); - width += size.cx + xoffset * 2 + _style.spacing; - height = max(height, offsetY + real_margin_y + size.cy); - } - // candidates - int col_cnt = 0; - int max_height_of_cols = 0; - int width_of_cols[MAX_CANDIDATES_COUNT] = {0}; - int col_of_candidate[MAX_CANDIDATES_COUNT] = {0}; - int minleft_of_cols[MAX_CANDIDATES_COUNT] = {0}; - if( candidates_count ) - { - h = offsetY + real_margin_y; - for(auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; i++) - { - int current_cand_height = 0; - if( i > 0 ) h += _style.candidate_spacing; - if( id == i ) h += base_offset; - /* Label */ - std::wstring label = GetLabelText(labels, i, _style.label_text_format.c_str()); - GetTextSizeDW(label, label.length(), pDWR->pLabelTextFormat, pDWR, &size); - _candidateLabelRects[i].SetRect(width, h, width + size.cx, h + size.cy * labelFontValid); - h += size.cy * labelFontValid; - current_cand_height += size.cy * labelFontValid; + /* Preedit */ + if (!IsInlinePreedit() && !_context.preedit.str.empty()) { + size = GetPreeditSize(dc, _context.preedit, pDWR->pPreeditTextFormat, pDWR); + size_t szx = max(size.cx, pgw), szy = pgh; + // icon size wider then preedit text + int xoffset = (STATUS_ICON_SIZE >= szx && ShouldDisplayStatusIcon()) + ? (STATUS_ICON_SIZE - szx) / 2 + : 0; + _preeditRect.SetRect(width + xoffset, h, width + xoffset + size.cx, + h + size.cy); + width += size.cx + xoffset * 2 + _style.spacing; + height = max(height, offsetY + real_margin_y + size.cy + szy); + if (ShouldDisplayStatusIcon()) + height += STATUS_ICON_SIZE; + } + /* Auxiliary */ + if (!_context.aux.str.empty()) { + size = GetPreeditSize(dc, _context.aux, pDWR->pPreeditTextFormat, pDWR); + // icon size wider then auxiliary text + int xoffset = (STATUS_ICON_SIZE >= size.cx && ShouldDisplayStatusIcon()) + ? (STATUS_ICON_SIZE - size.cx) / 2 + : 0; + _auxiliaryRect.SetRect(width + xoffset, h, width + xoffset + size.cx, + h + size.cy); + width += size.cx + xoffset * 2 + _style.spacing; + height = max(height, offsetY + real_margin_y + size.cy); + } + // candidates + int col_cnt = 0; + int max_height_of_cols = 0; + int width_of_cols[MAX_CANDIDATES_COUNT] = {0}; + int col_of_candidate[MAX_CANDIDATES_COUNT] = {0}; + int minleft_of_cols[MAX_CANDIDATES_COUNT] = {0}; + if (candidates_count) { + h = offsetY + real_margin_y; + for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; i++) { + int current_cand_height = 0; + if (i > 0) + h += _style.candidate_spacing; + if (id == i) + h += base_offset; + /* Label */ + std::wstring label = + GetLabelText(labels, i, _style.label_text_format.c_str()); + GetTextSizeDW(label, label.length(), pDWR->pLabelTextFormat, pDWR, &size); + _candidateLabelRects[i].SetRect(width, h, width + size.cx, + h + size.cy * labelFontValid); + h += size.cy * labelFontValid; + current_cand_height += size.cy * labelFontValid; - /* Text */ - h += _style.hilite_spacing; - const std::wstring& text =candidates.at(i).str; - GetTextSizeDW(text, text.length(), pDWR->pTextFormat, pDWR, &size); - _candidateTextRects[i].SetRect(width, h, width + size.cx, h + size.cy * textFontValid); - h += size.cy * textFontValid; - current_cand_height += (size.cy + _style.hilite_spacing) * textFontValid; + /* Text */ + h += _style.hilite_spacing; + const std::wstring& text = candidates.at(i).str; + GetTextSizeDW(text, text.length(), pDWR->pTextFormat, pDWR, &size); + _candidateTextRects[i].SetRect(width, h, width + size.cx, + h + size.cy * textFontValid); + h += size.cy * textFontValid; + current_cand_height += (size.cy + _style.hilite_spacing) * textFontValid; - /* Comment */ - bool cmtFontNotTrans = (i == id && (_style.hilited_comment_text_color & 0xff000000)) || - (i != id && (_style.comment_text_color & 0xff000000)); - if (!comments.at(i).str.empty() && cmtFontValid && cmtFontNotTrans) - { - const std::wstring& comment = comments.at(i).str; - GetTextSizeDW(comment, comment.length(), pDWR->pCommentTextFormat, pDWR, &size); - h += _style.hilite_spacing; - _candidateCommentRects[i].SetRect(width, h, width + size.cx, h + size.cy * cmtFontValid); - h += size.cy * cmtFontValid; - current_cand_height += (size.cy + _style.hilite_spacing) * cmtFontValid; - } - else - _candidateCommentRects[i].SetRect(width, h, width + size.cx, h); - int base_top = (i == id) ? _candidateLabelRects[i].top - base_offset : _candidateLabelRects[i].top; - if( _style.max_height > 0 && (base_top > real_margin_y + offsetY) && (_candidateCommentRects[i].bottom - offsetY + real_margin_y > _style.max_height) ) - { - max_height_of_cols = max(max_height_of_cols, _candidateCommentRects[i-1].bottom); - h = offsetY + real_margin_y + (i==id? base_offset : 0); - int ofy = h - _candidateLabelRects[i].top; - int ofx = width_of_cols[col_cnt] + _style.candidate_spacing; - _candidateLabelRects[i].OffsetRect(ofx, ofy); - _candidateTextRects[i].OffsetRect(ofx, ofy); - _candidateCommentRects[i].OffsetRect(ofx, ofy); - max_height_of_cols = max(max_height_of_cols, _candidateCommentRects[i].bottom); - minleft_of_cols[col_cnt] = width; - width += ofx; - h += current_cand_height; - col_cnt ++; - } - else - max_height_of_cols = max(max_height_of_cols, h); - minleft_of_cols[col_cnt] = width; - width_of_cols[col_cnt] = max(width_of_cols[col_cnt], _candidateLabelRects[i].Width()); - width_of_cols[col_cnt] = max(width_of_cols[col_cnt], _candidateTextRects[i].Width()); - width_of_cols[col_cnt] = max(width_of_cols[col_cnt], _candidateCommentRects[i].Width()); - col_of_candidate[i] = col_cnt; - } + /* Comment */ + bool cmtFontNotTrans = + (i == id && (_style.hilited_comment_text_color & 0xff000000)) || + (i != id && (_style.comment_text_color & 0xff000000)); + if (!comments.at(i).str.empty() && cmtFontValid && cmtFontNotTrans) { + const std::wstring& comment = comments.at(i).str; + GetTextSizeDW(comment, comment.length(), pDWR->pCommentTextFormat, pDWR, + &size); + h += _style.hilite_spacing; + _candidateCommentRects[i].SetRect(width, h, width + size.cx, + h + size.cy * cmtFontValid); + h += size.cy * cmtFontValid; + current_cand_height += (size.cy + _style.hilite_spacing) * cmtFontValid; + } else + _candidateCommentRects[i].SetRect(width, h, width + size.cx, h); + int base_top = (i == id) ? _candidateLabelRects[i].top - base_offset + : _candidateLabelRects[i].top; + if (_style.max_height > 0 && (base_top > real_margin_y + offsetY) && + (_candidateCommentRects[i].bottom - offsetY + real_margin_y > + _style.max_height)) { + max_height_of_cols = + max(max_height_of_cols, _candidateCommentRects[i - 1].bottom); + h = offsetY + real_margin_y + (i == id ? base_offset : 0); + int ofy = h - _candidateLabelRects[i].top; + int ofx = width_of_cols[col_cnt] + _style.candidate_spacing; + _candidateLabelRects[i].OffsetRect(ofx, ofy); + _candidateTextRects[i].OffsetRect(ofx, ofy); + _candidateCommentRects[i].OffsetRect(ofx, ofy); + max_height_of_cols = + max(max_height_of_cols, _candidateCommentRects[i].bottom); + minleft_of_cols[col_cnt] = width; + width += ofx; + h += current_cand_height; + col_cnt++; + } else + max_height_of_cols = max(max_height_of_cols, h); + minleft_of_cols[col_cnt] = width; + width_of_cols[col_cnt] = + max(width_of_cols[col_cnt], _candidateLabelRects[i].Width()); + width_of_cols[col_cnt] = + max(width_of_cols[col_cnt], _candidateTextRects[i].Width()); + width_of_cols[col_cnt] = + max(width_of_cols[col_cnt], _candidateCommentRects[i].Width()); + col_of_candidate[i] = col_cnt; + } - - for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) - { - int base_top = (i == id) ? _candidateLabelRects[i].top - base_offset : _candidateLabelRects[i].top; - _candidateRects[i].SetRect(minleft_of_cols[col_of_candidate[i]], base_top, - minleft_of_cols[col_of_candidate[i]] + width_of_cols[col_of_candidate[i]], _candidateCommentRects[i].bottom); - int ol = 0, ot = 0, oc = 0; - if(_style.align_type == UIStyle::ALIGN_CENTER) - { - ol = (width_of_cols[col_of_candidate[i]] - _candidateLabelRects[i].Width()) / 2; - ot = (width_of_cols[col_of_candidate[i]] - _candidateTextRects[i].Width()) / 2; - oc = (width_of_cols[col_of_candidate[i]] - _candidateCommentRects[i].Width()) / 2; - } - else if((_style.align_type == UIStyle::ALIGN_BOTTOM) && _style.vertical_text_left_to_right) - { - ol = (width_of_cols[col_of_candidate[i]] - _candidateLabelRects[i].Width()); - ot = (width_of_cols[col_of_candidate[i]] - _candidateTextRects[i].Width()); - oc = (width_of_cols[col_of_candidate[i]] - _candidateCommentRects[i].Width()); - } - else if((_style.align_type == UIStyle::ALIGN_TOP) && (!_style.vertical_text_left_to_right)) - { - ol = (width_of_cols[col_of_candidate[i]] - _candidateLabelRects[i].Width()); - ot = (width_of_cols[col_of_candidate[i]] - _candidateTextRects[i].Width()); - oc = (width_of_cols[col_of_candidate[i]] - _candidateCommentRects[i].Width()); - } - _candidateLabelRects[i].OffsetRect(ol, 0); - _candidateTextRects[i].OffsetRect(ot, 0); - _candidateCommentRects[i].OffsetRect(oc, 0); - if (( i < candidates_count - 1 && col_of_candidate[i] < col_of_candidate[i+1] ) || ( i == candidates_count - 1 )) - _candidateRects[i].bottom = max(height, max_height_of_cols); - } - width = minleft_of_cols[col_cnt] + width_of_cols[col_cnt] - offsetX; - height = max(height, max_height_of_cols); - _highlightRect = _candidateRects[id]; - } - else - width -= _style.spacing + offsetX; - // reposition if not left to right - int first_cand_of_cols[MAX_CANDIDATES_COUNT] = {0}; - int offset_of_cols[MAX_CANDIDATES_COUNT] = {0}; - if(!_style.vertical_text_left_to_right) - { - // re position right to left - int base_left; - if ((!IsInlinePreedit() && !_context.preedit.str.empty())) - base_left = _preeditRect.left; - else if( !_context.aux.str.empty()) - base_left = _auxiliaryRect.left; - else if(candidates_count) - base_left = _candidateRects[0].left; - if(candidates_count) - { - // calc offset for each col - for(auto col_t = 0; col_t <= col_cnt; col_t++) - { - for(auto i = 0; i < candidates_count; i++ ) - { - if(col_of_candidate[i] == col_t) - { - first_cand_of_cols[col_t] = i; - break; - } - } - } - for(auto i = col_cnt; i >= 0; i-- ) - { - int offset ; - if(i == col_cnt) - offset = base_left - _candidateRects[first_cand_of_cols[i]].left; - else - offset = _candidateRects[first_cand_of_cols[i+1]].right + _style.candidate_spacing - _candidateRects[first_cand_of_cols[i]].left; - offset_of_cols[i] = offset; - _candidateRects[first_cand_of_cols[i]].OffsetRect(offset_of_cols[i], 0); - } - for(auto i = 0; i < candidates_count; i++ ) - { - if( i != first_cand_of_cols[col_of_candidate[i]] ) - _candidateRects[i].OffsetRect(offset_of_cols[col_of_candidate[i]], 0); - _candidateLabelRects[i].OffsetRect(offset_of_cols[col_of_candidate[i]], 0); - _candidateTextRects[i].OffsetRect(offset_of_cols[col_of_candidate[i]], 0); - _candidateCommentRects[i].OffsetRect(offset_of_cols[col_of_candidate[i]], 0); - } - _highlightRect = _candidateRects[id]; - if (!IsInlinePreedit() && !_context.preedit.str.empty()) - _preeditRect.OffsetRect(_candidateRects[0].right + _style.spacing - _preeditRect.left, 0); - if (!_context.aux.str.empty()) - _auxiliaryRect.OffsetRect(_candidateRects[0].right + _style.spacing - _auxiliaryRect.left, 0); - } - } + for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) { + int base_top = (i == id) ? _candidateLabelRects[i].top - base_offset + : _candidateLabelRects[i].top; + _candidateRects[i].SetRect(minleft_of_cols[col_of_candidate[i]], base_top, + minleft_of_cols[col_of_candidate[i]] + + width_of_cols[col_of_candidate[i]], + _candidateCommentRects[i].bottom); + int ol = 0, ot = 0, oc = 0; + if (_style.align_type == UIStyle::ALIGN_CENTER) { + ol = (width_of_cols[col_of_candidate[i]] - + _candidateLabelRects[i].Width()) / + 2; + ot = (width_of_cols[col_of_candidate[i]] - + _candidateTextRects[i].Width()) / + 2; + oc = (width_of_cols[col_of_candidate[i]] - + _candidateCommentRects[i].Width()) / + 2; + } else if ((_style.align_type == UIStyle::ALIGN_BOTTOM) && + _style.vertical_text_left_to_right) { + ol = (width_of_cols[col_of_candidate[i]] - + _candidateLabelRects[i].Width()); + ot = (width_of_cols[col_of_candidate[i]] - + _candidateTextRects[i].Width()); + oc = (width_of_cols[col_of_candidate[i]] - + _candidateCommentRects[i].Width()); + } else if ((_style.align_type == UIStyle::ALIGN_TOP) && + (!_style.vertical_text_left_to_right)) { + ol = (width_of_cols[col_of_candidate[i]] - + _candidateLabelRects[i].Width()); + ot = (width_of_cols[col_of_candidate[i]] - + _candidateTextRects[i].Width()); + oc = (width_of_cols[col_of_candidate[i]] - + _candidateCommentRects[i].Width()); + } + _candidateLabelRects[i].OffsetRect(ol, 0); + _candidateTextRects[i].OffsetRect(ot, 0); + _candidateCommentRects[i].OffsetRect(oc, 0); + if ((i < candidates_count - 1 && + col_of_candidate[i] < col_of_candidate[i + 1]) || + (i == candidates_count - 1)) + _candidateRects[i].bottom = max(height, max_height_of_cols); + } + width = minleft_of_cols[col_cnt] + width_of_cols[col_cnt] - offsetX; + height = max(height, max_height_of_cols); + _highlightRect = _candidateRects[id]; + } else + width -= _style.spacing + offsetX; + // reposition if not left to right + int first_cand_of_cols[MAX_CANDIDATES_COUNT] = {0}; + int offset_of_cols[MAX_CANDIDATES_COUNT] = {0}; + if (!_style.vertical_text_left_to_right) { + // re position right to left + int base_left; + if ((!IsInlinePreedit() && !_context.preedit.str.empty())) + base_left = _preeditRect.left; + else if (!_context.aux.str.empty()) + base_left = _auxiliaryRect.left; + else if (candidates_count) + base_left = _candidateRects[0].left; + if (candidates_count) { + // calc offset for each col + for (auto col_t = 0; col_t <= col_cnt; col_t++) { + for (auto i = 0; i < candidates_count; i++) { + if (col_of_candidate[i] == col_t) { + first_cand_of_cols[col_t] = i; + break; + } + } + } + for (auto i = col_cnt; i >= 0; i--) { + int offset; + if (i == col_cnt) + offset = base_left - _candidateRects[first_cand_of_cols[i]].left; + else + offset = _candidateRects[first_cand_of_cols[i + 1]].right + + _style.candidate_spacing - + _candidateRects[first_cand_of_cols[i]].left; + offset_of_cols[i] = offset; + _candidateRects[first_cand_of_cols[i]].OffsetRect(offset_of_cols[i], 0); + } + for (auto i = 0; i < candidates_count; i++) { + if (i != first_cand_of_cols[col_of_candidate[i]]) + _candidateRects[i].OffsetRect(offset_of_cols[col_of_candidate[i]], 0); + _candidateLabelRects[i].OffsetRect(offset_of_cols[col_of_candidate[i]], + 0); + _candidateTextRects[i].OffsetRect(offset_of_cols[col_of_candidate[i]], + 0); + _candidateCommentRects[i].OffsetRect( + offset_of_cols[col_of_candidate[i]], 0); + } + _highlightRect = _candidateRects[id]; + if (!IsInlinePreedit() && !_context.preedit.str.empty()) + _preeditRect.OffsetRect( + _candidateRects[0].right + _style.spacing - _preeditRect.left, 0); + if (!_context.aux.str.empty()) + _auxiliaryRect.OffsetRect( + _candidateRects[0].right + _style.spacing - _auxiliaryRect.left, 0); + } + } - width += real_margin_x; - height += real_margin_y; - if (!_context.preedit.str.empty() && !candidates_count) - { - width = max(width, _style.min_width); - height = max(height, _style.min_height); - } - UpdateStatusIconLayout(&width, &height); - _contentSize.SetSize(width + 2 * offsetX, height + offsetY); - _contentRect.SetRect(0, 0, _contentSize.cx, _contentSize.cy); + width += real_margin_x; + height += real_margin_y; + if (!_context.preedit.str.empty() && !candidates_count) { + width = max(width, _style.min_width); + height = max(height, _style.min_height); + } + UpdateStatusIconLayout(&width, &height); + _contentSize.SetSize(width + 2 * offsetX, height + offsetY); + _contentRect.SetRect(0, 0, _contentSize.cx, _contentSize.cy); - // calc page indicator - if(page_en && candidates_count && !_style.inline_preedit) - { - int _prey = _contentSize.cy - offsetY - real_margin_y + _style.hilite_padding_y - pgh; - int _prex = (_preeditRect.left + _preeditRect.right) / 2 - pgszl.cx / 2; - _prePageRect.SetRect(_prex, _prey, _prex + pgszl.cx, _prey + pgszl.cy); - _nextPageRect.SetRect(_prex, _prePageRect.bottom + _style.hilite_spacing, - _prex + pgszr.cx, _prePageRect.bottom + _style.hilite_spacing + pgszr.cy); - if (ShouldDisplayStatusIcon()) - { - _prePageRect.OffsetRect(0, -STATUS_ICON_SIZE); - _nextPageRect.OffsetRect(0, -STATUS_ICON_SIZE); - } - } + // calc page indicator + if (page_en && candidates_count && !_style.inline_preedit) { + int _prey = _contentSize.cy - offsetY - real_margin_y + + _style.hilite_padding_y - pgh; + int _prex = (_preeditRect.left + _preeditRect.right) / 2 - pgszl.cx / 2; + _prePageRect.SetRect(_prex, _prey, _prex + pgszl.cx, _prey + pgszl.cy); + _nextPageRect.SetRect( + _prex, _prePageRect.bottom + _style.hilite_spacing, _prex + pgszr.cx, + _prePageRect.bottom + _style.hilite_spacing + pgszr.cy); + if (ShouldDisplayStatusIcon()) { + _prePageRect.OffsetRect(0, -STATUS_ICON_SIZE); + _nextPageRect.OffsetRect(0, -STATUS_ICON_SIZE); + } + } - // prepare temp rect _bgRect for roundinfo calculation - CopyRect(_bgRect, _contentRect); - _bgRect.DeflateRect(offsetX + 1, offsetY + 1); - _PrepareRoundInfo(dc); - if(_style.vertical_text_left_to_right) - { - for(auto i = 0; i < candidates_count; i++) - { - _roundInfo[i].Hemispherical = _roundInfo[0].Hemispherical; - if(_roundInfo[0].Hemispherical) - { - if(col_of_candidate[i] == col_cnt) - { - _roundInfo[i].IsTopRightNeedToRound = false; - _roundInfo[i].IsBottomRightNeedToRound = false; - } - if(col_of_candidate[i] == 0) - { - _roundInfo[i].IsTopLeftNeedToRound = false; - _roundInfo[i].IsBottomLeftNeedToRound = false; - } - if(i==0) - { - _roundInfo[i].IsTopLeftNeedToRound = _style.inline_preedit; - if(col_cnt == 0) - _roundInfo[i].IsTopRightNeedToRound = true; - } - if(i==candidates_count - 1) - { - _roundInfo[i].IsBottomRightNeedToRound = true; - if(col_cnt == 0) - _roundInfo[i].IsBottomLeftNeedToRound = _style.inline_preedit; - } + // prepare temp rect _bgRect for roundinfo calculation + CopyRect(_bgRect, _contentRect); + _bgRect.DeflateRect(offsetX + 1, offsetY + 1); + _PrepareRoundInfo(dc); + if (_style.vertical_text_left_to_right) { + for (auto i = 0; i < candidates_count; i++) { + _roundInfo[i].Hemispherical = _roundInfo[0].Hemispherical; + if (_roundInfo[0].Hemispherical) { + if (col_of_candidate[i] == col_cnt) { + _roundInfo[i].IsTopRightNeedToRound = false; + _roundInfo[i].IsBottomRightNeedToRound = false; + } + if (col_of_candidate[i] == 0) { + _roundInfo[i].IsTopLeftNeedToRound = false; + _roundInfo[i].IsBottomLeftNeedToRound = false; + } + if (i == 0) { + _roundInfo[i].IsTopLeftNeedToRound = _style.inline_preedit; + if (col_cnt == 0) + _roundInfo[i].IsTopRightNeedToRound = true; + } + if (i == candidates_count - 1) { + _roundInfo[i].IsBottomRightNeedToRound = true; + if (col_cnt == 0) + _roundInfo[i].IsBottomLeftNeedToRound = _style.inline_preedit; + } - if(col_of_candidate[i] == col_cnt && col_cnt > 0 && col_of_candidate[i-1] == (col_cnt - 1)) - _roundInfo[i].IsTopRightNeedToRound = true; - if(col_of_candidate[i] == 0 && col_cnt > 0 && col_of_candidate[i+1] == 1) - _roundInfo[i].IsBottomLeftNeedToRound = _style.inline_preedit; - } - } - } - else - { - for(auto i = 0; i < candidates_count; i++) - { - _roundInfo[i].Hemispherical = _roundInfo[0].Hemispherical; - if(_roundInfo[0].Hemispherical) - { - if(col_of_candidate[i] == 0) - { - _roundInfo[i].IsTopRightNeedToRound = false; - _roundInfo[i].IsBottomRightNeedToRound = false; - } - if(col_of_candidate[i] == col_cnt) - { - _roundInfo[i].IsTopLeftNeedToRound = false; - _roundInfo[i].IsBottomLeftNeedToRound = false; - } - if(i==0) - { - _roundInfo[i].IsTopRightNeedToRound = _style.inline_preedit; - if(col_cnt ==0) - _roundInfo[i].IsTopLeftNeedToRound = true; - } - if(i==candidates_count - 1) - { - _roundInfo[i].IsBottomLeftNeedToRound = true; - if(col_cnt==0) - _roundInfo[i].IsBottomRightNeedToRound = _style.inline_preedit; - } - if(col_of_candidate[i] == col_cnt && col_cnt > 0 && col_of_candidate[i-1] == (col_cnt - 1)) - _roundInfo[i].IsTopLeftNeedToRound = true; - if(col_of_candidate[i] == 0 && col_cnt > 0 && col_of_candidate[i+1] == 1) - _roundInfo[i].IsBottomRightNeedToRound = _style.inline_preedit; - } - } - } + if (col_of_candidate[i] == col_cnt && col_cnt > 0 && + col_of_candidate[i - 1] == (col_cnt - 1)) + _roundInfo[i].IsTopRightNeedToRound = true; + if (col_of_candidate[i] == 0 && col_cnt > 0 && + col_of_candidate[i + 1] == 1) + _roundInfo[i].IsBottomLeftNeedToRound = _style.inline_preedit; + } + } + } else { + for (auto i = 0; i < candidates_count; i++) { + _roundInfo[i].Hemispherical = _roundInfo[0].Hemispherical; + if (_roundInfo[0].Hemispherical) { + if (col_of_candidate[i] == 0) { + _roundInfo[i].IsTopRightNeedToRound = false; + _roundInfo[i].IsBottomRightNeedToRound = false; + } + if (col_of_candidate[i] == col_cnt) { + _roundInfo[i].IsTopLeftNeedToRound = false; + _roundInfo[i].IsBottomLeftNeedToRound = false; + } + if (i == 0) { + _roundInfo[i].IsTopRightNeedToRound = _style.inline_preedit; + if (col_cnt == 0) + _roundInfo[i].IsTopLeftNeedToRound = true; + } + if (i == candidates_count - 1) { + _roundInfo[i].IsBottomLeftNeedToRound = true; + if (col_cnt == 0) + _roundInfo[i].IsBottomRightNeedToRound = _style.inline_preedit; + } + if (col_of_candidate[i] == col_cnt && col_cnt > 0 && + col_of_candidate[i - 1] == (col_cnt - 1)) + _roundInfo[i].IsTopLeftNeedToRound = true; + if (col_of_candidate[i] == 0 && col_cnt > 0 && + col_of_candidate[i + 1] == 1) + _roundInfo[i].IsBottomRightNeedToRound = _style.inline_preedit; + } + } + } - // truely draw content size calculation - _contentRect.DeflateRect(offsetX, offsetY); + // truely draw content size calculation + _contentRect.DeflateRect(offsetX, offsetY); } - diff --git a/WeaselUI/VHorizontalLayout.h b/WeaselUI/VHorizontalLayout.h index f7307099e..140a34a97 100644 --- a/WeaselUI/VHorizontalLayout.h +++ b/WeaselUI/VHorizontalLayout.h @@ -2,15 +2,16 @@ #include "StandardLayout.h" -namespace weasel -{ - class VHorizontalLayout: public StandardLayout - { - public: - VHorizontalLayout(const UIStyle &style, const Context &context, const Status &status) - : StandardLayout(style, context, status){} - virtual void DoLayout(CDCHandle dc, PDWR pDWR = NULL); - private: - void DoLayoutWithWrap(CDCHandle dc, PDWR pDWR = NULL); - }; +namespace weasel { +class VHorizontalLayout : public StandardLayout { + public: + VHorizontalLayout(const UIStyle& style, + const Context& context, + const Status& status) + : StandardLayout(style, context, status) {} + virtual void DoLayout(CDCHandle dc, PDWR pDWR = NULL); + + private: + void DoLayoutWithWrap(CDCHandle dc, PDWR pDWR = NULL); }; +}; // namespace weasel diff --git a/WeaselUI/VerticalLayout.cpp b/WeaselUI/VerticalLayout.cpp index 57cd3e6a4..bf611aa9a 100644 --- a/WeaselUI/VerticalLayout.cpp +++ b/WeaselUI/VerticalLayout.cpp @@ -3,211 +3,225 @@ using namespace weasel; -void weasel::VerticalLayout::DoLayout(CDCHandle dc, PDWR pDWR) -{ - const int space = _style.hilite_spacing; - int width = 0, height = real_margin_y; - - if ((_style.hilited_mark_color & 0xff000000)) - { - CSize sg; - if(_style.mark_text.empty()) - GetTextSizeDW(L"|", 1, pDWR->pTextFormat, pDWR, &sg); - else - GetTextSizeDW(_style.mark_text, _style.mark_text.length(), pDWR->pTextFormat, pDWR, &sg); - - MARK_WIDTH = sg.cx; - MARK_HEIGHT = sg.cy; - if(_style.mark_text.empty()) - MARK_WIDTH /= 2; - MARK_GAP = (_style.mark_text.empty()) ? MARK_WIDTH : MARK_WIDTH + _style.hilite_spacing; - } - int base_offset = ((_style.hilited_mark_color & 0xff000000)) ? MARK_GAP : 0; - - // calc page indicator - CSize pgszl, pgszr; - GetTextSizeDW(pre, pre.length(), pDWR->pPreeditTextFormat, pDWR, &pgszl); - GetTextSizeDW(next, next.length(), pDWR->pPreeditTextFormat, pDWR, &pgszr); - bool page_en = (_style.prevpage_color & 0xff000000) && (_style.nextpage_color & 0xff000000); - int pgw = page_en ? pgszl.cx + pgszr.cx + _style.hilite_spacing + _style.hilite_padding_x * 2 : 0; - int pgh = page_en ? max(pgszl.cy, pgszr.cy) : 0; - - /* preedit and auxiliary rectangle calc start */ - CSize size; - /* Preedit */ - if (!IsInlinePreedit() && !_context.preedit.str.empty()) - { - size = GetPreeditSize(dc, _context.preedit, pDWR->pPreeditTextFormat, pDWR); - int szx = pgw, szy = max(size.cy, pgh); - // icon size higher then preedit text - int yoffset = (STATUS_ICON_SIZE >= szy && ShouldDisplayStatusIcon()) ? (STATUS_ICON_SIZE - szy) / 2 : 0; - _preeditRect.SetRect(real_margin_x, height + yoffset, real_margin_x + size.cx, height + yoffset + size.cy); - height += szy + 2 * yoffset + _style.spacing; - width = max(width, real_margin_x * 2 + size.cx + szx); - if(ShouldDisplayStatusIcon()) width += STATUS_ICON_SIZE; - _preeditRect.OffsetRect(offsetX, offsetY); - } - - /* Auxiliary */ - if (!_context.aux.str.empty()) - { - size = GetPreeditSize(dc, _context.aux, pDWR->pPreeditTextFormat, pDWR); - // icon size higher then auxiliary text - int yoffset = (STATUS_ICON_SIZE >= size.cy && ShouldDisplayStatusIcon()) ? (STATUS_ICON_SIZE - size.cy) / 2 : 0; - _auxiliaryRect.SetRect(real_margin_x, height + yoffset, real_margin_x + size.cx, height + yoffset + size.cy); - height += size.cy + 2 * yoffset + _style.spacing; - width = max(width, real_margin_x * 2 + size.cx); - _auxiliaryRect.OffsetRect(offsetX, offsetY); - } - /* preedit and auxiliary rectangle calc end */ - - /* Candidates */ - int comment_shift_width = 0; /* distance to the left of the candidate text */ - int max_candidate_width = 0; /* label + text */ - int max_comment_width = 0; /* comment, or none */ - for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) - { - if (i > 0 ) - height += _style.candidate_spacing; - - int w = real_margin_x + base_offset, max_height_curren_candidate = 0; - int candidate_width = base_offset, comment_width = 0; - /* Label */ - std::wstring label = GetLabelText(labels, i, _style.label_text_format.c_str()); - GetTextSizeDW(label, label.length(), pDWR->pLabelTextFormat, pDWR, &size); - _candidateLabelRects[i].SetRect(w, height, w + size.cx * labelFontValid, height + size.cy); - _candidateLabelRects[i].OffsetRect(offsetX, offsetY); - w += (size.cx + space) * labelFontValid; - max_height_curren_candidate = max(max_height_curren_candidate, size.cy); - candidate_width += (size.cx + space) * labelFontValid; - - /* Text */ - const std::wstring& text = candidates.at(i).str; - GetTextSizeDW(text, text.length(), pDWR->pTextFormat, pDWR, &size); - _candidateTextRects[i].SetRect(w, height, w + size.cx * textFontValid, height + size.cy); - _candidateTextRects[i].OffsetRect(offsetX, offsetY); - w += size.cx * textFontValid; - max_height_curren_candidate = max(max_height_curren_candidate, size.cy); - candidate_width += size.cx * textFontValid; - max_candidate_width = max(max_candidate_width, candidate_width); - - /* Comment */ - bool cmtFontNotTrans = (i == id && (_style.hilited_comment_text_color & 0xff000000)) || - (i != id && (_style.comment_text_color & 0xff000000)); - if (!comments.at(i).str.empty() && cmtFontValid && cmtFontNotTrans) - { - w += space; - comment_shift_width = max(comment_shift_width, w); - - const std::wstring& comment = comments.at(i).str; - GetTextSizeDW(comment, comment.length(), pDWR->pCommentTextFormat, pDWR, &size); - _candidateCommentRects[i].SetRect(0, height, size.cx * cmtFontValid, height + size.cy); - _candidateCommentRects[i].OffsetRect(offsetX, offsetY); - w += size.cx * cmtFontValid; - max_height_curren_candidate = max(max_height_curren_candidate, size.cy); - comment_width += size.cx * cmtFontValid; - max_comment_width = max(max_comment_width, comment_width); - } - int ol = 0, ot = 0, oc = 0; - if (_style.align_type == UIStyle::ALIGN_CENTER) - { - ol = (max_height_curren_candidate - _candidateLabelRects[i].Height()) / 2; - ot = (max_height_curren_candidate - _candidateTextRects[i].Height()) / 2; - oc = (max_height_curren_candidate - _candidateCommentRects[i].Height()) / 2; - } - else if (_style.align_type == UIStyle::ALIGN_BOTTOM) - { - ol = (max_height_curren_candidate - _candidateLabelRects[i].Height()) ; - ot = (max_height_curren_candidate - _candidateTextRects[i].Height()) ; - oc = (max_height_curren_candidate - _candidateCommentRects[i].Height()) ; - } - _candidateLabelRects[i].OffsetRect(0, ol); - _candidateTextRects[i].OffsetRect(0, ot); - _candidateCommentRects[i].OffsetRect(0, oc); - - int hlTop = _candidateTextRects[i].top; - int hlBot = _candidateTextRects[i].bottom; - if (_candidateLabelRects[i].Height() > 0) - { - hlTop = min(_candidateLabelRects[i].top, hlTop); - hlBot = max(_candidateLabelRects[i].bottom, _candidateTextRects[i].bottom); - } - if (_candidateCommentRects[i].Height() > 0) - { - hlTop = min(hlTop, _candidateCommentRects[i].top); - hlBot = max(hlBot, _candidateCommentRects[i].bottom); - } - _candidateRects[i].SetRect(real_margin_x + offsetX, hlTop, width - real_margin_x + offsetX, hlBot); - - width = max(width, w); - height += max_height_curren_candidate; - } - /* comments are left-aligned to the right of the longest candidate who has a comment */ - int max_content_width = max(max_candidate_width, comment_shift_width + max_comment_width); - width = max(width, max_content_width + 2 * real_margin_x); - - /* Align comments */ - for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) - { - int hlTop = _candidateTextRects[i].top; - int hlBot = _candidateTextRects[i].bottom; - - _candidateCommentRects[i].OffsetRect(real_margin_x + comment_shift_width, 0); - if (_candidateLabelRects[i].Height() > 0) - { - hlTop = min(_candidateLabelRects[i].top, hlTop); - hlBot = max(_candidateLabelRects[i].bottom, _candidateTextRects[i].bottom); - } - if (_candidateCommentRects[i].Height() > 0) - { - hlTop = min(hlTop, _candidateCommentRects[i].top); - hlBot = max(hlBot, _candidateCommentRects[i].bottom); - } - - _candidateRects[i].SetRect(real_margin_x + offsetX, hlTop, width - real_margin_x + offsetX, hlBot); - } - - /* Trim the last spacing if no candidates */ - if(candidates_count == 0) height -= _style.spacing; - - height += real_margin_y; - - if (!_context.preedit.str.empty() && candidates_count) - { - width = max(width, _style.min_width); - height = max(height, _style.min_height); - } - UpdateStatusIconLayout(&width, &height); - // candidate rectangle always align to right side, margin_x to the right edge - for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) - _candidateRects[i].right = max(_candidateRects[i].right, _candidateRects[i].left - real_margin_x + width - real_margin_x); - - _contentSize.SetSize(width + offsetX * 2, height + offsetY * 2); - - /* Highlighted Candidate */ - - _highlightRect = _candidateRects[id]; - // calc page indicator - if(page_en && candidates_count && !_style.inline_preedit) - { - int _prex = _contentSize.cx - offsetX - real_margin_x + _style.hilite_padding_x - pgw; - int _prey = (_preeditRect.top + _preeditRect.bottom) / 2 - pgszl.cy / 2; - _prePageRect.SetRect(_prex, _prey, _prex + pgszl.cx, _prey + pgszl.cy); - _nextPageRect.SetRect(_prePageRect.right + _style.hilite_spacing, - _prey, _prePageRect.right + _style.hilite_spacing + pgszr.cx, _prey + pgszr.cy); - if (ShouldDisplayStatusIcon()) - { - _prePageRect.OffsetRect(-STATUS_ICON_SIZE, 0); - _nextPageRect.OffsetRect(-STATUS_ICON_SIZE, 0); - } - } - // calc roundings start - _contentRect.SetRect(0, 0, _contentSize.cx, _contentSize.cy); - // background rect prepare for Hemispherical calculation - CopyRect(_bgRect, _contentRect); - _bgRect.DeflateRect(offsetX + 1, offsetY + 1); - _PrepareRoundInfo(dc); - - // truely draw content size calculation - _contentRect.DeflateRect(offsetX, offsetY); +void weasel::VerticalLayout::DoLayout(CDCHandle dc, PDWR pDWR) { + const int space = _style.hilite_spacing; + int width = 0, height = real_margin_y; + + if ((_style.hilited_mark_color & 0xff000000)) { + CSize sg; + if (_style.mark_text.empty()) + GetTextSizeDW(L"|", 1, pDWR->pTextFormat, pDWR, &sg); + else + GetTextSizeDW(_style.mark_text, _style.mark_text.length(), + pDWR->pTextFormat, pDWR, &sg); + + MARK_WIDTH = sg.cx; + MARK_HEIGHT = sg.cy; + if (_style.mark_text.empty()) + MARK_WIDTH /= 2; + MARK_GAP = (_style.mark_text.empty()) ? MARK_WIDTH + : MARK_WIDTH + _style.hilite_spacing; + } + int base_offset = ((_style.hilited_mark_color & 0xff000000)) ? MARK_GAP : 0; + + // calc page indicator + CSize pgszl, pgszr; + GetTextSizeDW(pre, pre.length(), pDWR->pPreeditTextFormat, pDWR, &pgszl); + GetTextSizeDW(next, next.length(), pDWR->pPreeditTextFormat, pDWR, &pgszr); + bool page_en = (_style.prevpage_color & 0xff000000) && + (_style.nextpage_color & 0xff000000); + int pgw = page_en ? pgszl.cx + pgszr.cx + _style.hilite_spacing + + _style.hilite_padding_x * 2 + : 0; + int pgh = page_en ? max(pgszl.cy, pgszr.cy) : 0; + + /* preedit and auxiliary rectangle calc start */ + CSize size; + /* Preedit */ + if (!IsInlinePreedit() && !_context.preedit.str.empty()) { + size = GetPreeditSize(dc, _context.preedit, pDWR->pPreeditTextFormat, pDWR); + int szx = pgw, szy = max(size.cy, pgh); + // icon size higher then preedit text + int yoffset = (STATUS_ICON_SIZE >= szy && ShouldDisplayStatusIcon()) + ? (STATUS_ICON_SIZE - szy) / 2 + : 0; + _preeditRect.SetRect(real_margin_x, height + yoffset, + real_margin_x + size.cx, height + yoffset + size.cy); + height += szy + 2 * yoffset + _style.spacing; + width = max(width, real_margin_x * 2 + size.cx + szx); + if (ShouldDisplayStatusIcon()) + width += STATUS_ICON_SIZE; + _preeditRect.OffsetRect(offsetX, offsetY); + } + + /* Auxiliary */ + if (!_context.aux.str.empty()) { + size = GetPreeditSize(dc, _context.aux, pDWR->pPreeditTextFormat, pDWR); + // icon size higher then auxiliary text + int yoffset = (STATUS_ICON_SIZE >= size.cy && ShouldDisplayStatusIcon()) + ? (STATUS_ICON_SIZE - size.cy) / 2 + : 0; + _auxiliaryRect.SetRect(real_margin_x, height + yoffset, + real_margin_x + size.cx, height + yoffset + size.cy); + height += size.cy + 2 * yoffset + _style.spacing; + width = max(width, real_margin_x * 2 + size.cx); + _auxiliaryRect.OffsetRect(offsetX, offsetY); + } + /* preedit and auxiliary rectangle calc end */ + + /* Candidates */ + int comment_shift_width = 0; /* distance to the left of the candidate text */ + int max_candidate_width = 0; /* label + text */ + int max_comment_width = 0; /* comment, or none */ + for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) { + if (i > 0) + height += _style.candidate_spacing; + + int w = real_margin_x + base_offset, max_height_curren_candidate = 0; + int candidate_width = base_offset, comment_width = 0; + /* Label */ + std::wstring label = + GetLabelText(labels, i, _style.label_text_format.c_str()); + GetTextSizeDW(label, label.length(), pDWR->pLabelTextFormat, pDWR, &size); + _candidateLabelRects[i].SetRect(w, height, w + size.cx * labelFontValid, + height + size.cy); + _candidateLabelRects[i].OffsetRect(offsetX, offsetY); + w += (size.cx + space) * labelFontValid; + max_height_curren_candidate = max(max_height_curren_candidate, size.cy); + candidate_width += (size.cx + space) * labelFontValid; + + /* Text */ + const std::wstring& text = candidates.at(i).str; + GetTextSizeDW(text, text.length(), pDWR->pTextFormat, pDWR, &size); + _candidateTextRects[i].SetRect(w, height, w + size.cx * textFontValid, + height + size.cy); + _candidateTextRects[i].OffsetRect(offsetX, offsetY); + w += size.cx * textFontValid; + max_height_curren_candidate = max(max_height_curren_candidate, size.cy); + candidate_width += size.cx * textFontValid; + max_candidate_width = max(max_candidate_width, candidate_width); + + /* Comment */ + bool cmtFontNotTrans = + (i == id && (_style.hilited_comment_text_color & 0xff000000)) || + (i != id && (_style.comment_text_color & 0xff000000)); + if (!comments.at(i).str.empty() && cmtFontValid && cmtFontNotTrans) { + w += space; + comment_shift_width = max(comment_shift_width, w); + + const std::wstring& comment = comments.at(i).str; + GetTextSizeDW(comment, comment.length(), pDWR->pCommentTextFormat, pDWR, + &size); + _candidateCommentRects[i].SetRect(0, height, size.cx * cmtFontValid, + height + size.cy); + _candidateCommentRects[i].OffsetRect(offsetX, offsetY); + w += size.cx * cmtFontValid; + max_height_curren_candidate = max(max_height_curren_candidate, size.cy); + comment_width += size.cx * cmtFontValid; + max_comment_width = max(max_comment_width, comment_width); + } + int ol = 0, ot = 0, oc = 0; + if (_style.align_type == UIStyle::ALIGN_CENTER) { + ol = (max_height_curren_candidate - _candidateLabelRects[i].Height()) / 2; + ot = (max_height_curren_candidate - _candidateTextRects[i].Height()) / 2; + oc = (max_height_curren_candidate - _candidateCommentRects[i].Height()) / + 2; + } else if (_style.align_type == UIStyle::ALIGN_BOTTOM) { + ol = (max_height_curren_candidate - _candidateLabelRects[i].Height()); + ot = (max_height_curren_candidate - _candidateTextRects[i].Height()); + oc = (max_height_curren_candidate - _candidateCommentRects[i].Height()); + } + _candidateLabelRects[i].OffsetRect(0, ol); + _candidateTextRects[i].OffsetRect(0, ot); + _candidateCommentRects[i].OffsetRect(0, oc); + + int hlTop = _candidateTextRects[i].top; + int hlBot = _candidateTextRects[i].bottom; + if (_candidateLabelRects[i].Height() > 0) { + hlTop = min(_candidateLabelRects[i].top, hlTop); + hlBot = + max(_candidateLabelRects[i].bottom, _candidateTextRects[i].bottom); + } + if (_candidateCommentRects[i].Height() > 0) { + hlTop = min(hlTop, _candidateCommentRects[i].top); + hlBot = max(hlBot, _candidateCommentRects[i].bottom); + } + _candidateRects[i].SetRect(real_margin_x + offsetX, hlTop, + width - real_margin_x + offsetX, hlBot); + + width = max(width, w); + height += max_height_curren_candidate; + } + /* comments are left-aligned to the right of the longest candidate who has a + * comment */ + int max_content_width = + max(max_candidate_width, comment_shift_width + max_comment_width); + width = max(width, max_content_width + 2 * real_margin_x); + + /* Align comments */ + for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) { + int hlTop = _candidateTextRects[i].top; + int hlBot = _candidateTextRects[i].bottom; + + _candidateCommentRects[i].OffsetRect(real_margin_x + comment_shift_width, + 0); + if (_candidateLabelRects[i].Height() > 0) { + hlTop = min(_candidateLabelRects[i].top, hlTop); + hlBot = + max(_candidateLabelRects[i].bottom, _candidateTextRects[i].bottom); + } + if (_candidateCommentRects[i].Height() > 0) { + hlTop = min(hlTop, _candidateCommentRects[i].top); + hlBot = max(hlBot, _candidateCommentRects[i].bottom); + } + + _candidateRects[i].SetRect(real_margin_x + offsetX, hlTop, + width - real_margin_x + offsetX, hlBot); + } + + /* Trim the last spacing if no candidates */ + if (candidates_count == 0) + height -= _style.spacing; + + height += real_margin_y; + + if (!_context.preedit.str.empty() && candidates_count) { + width = max(width, _style.min_width); + height = max(height, _style.min_height); + } + UpdateStatusIconLayout(&width, &height); + // candidate rectangle always align to right side, margin_x to the right edge + for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) + _candidateRects[i].right = + max(_candidateRects[i].right, + _candidateRects[i].left - real_margin_x + width - real_margin_x); + + _contentSize.SetSize(width + offsetX * 2, height + offsetY * 2); + + /* Highlighted Candidate */ + + _highlightRect = _candidateRects[id]; + // calc page indicator + if (page_en && candidates_count && !_style.inline_preedit) { + int _prex = _contentSize.cx - offsetX - real_margin_x + + _style.hilite_padding_x - pgw; + int _prey = (_preeditRect.top + _preeditRect.bottom) / 2 - pgszl.cy / 2; + _prePageRect.SetRect(_prex, _prey, _prex + pgszl.cx, _prey + pgszl.cy); + _nextPageRect.SetRect(_prePageRect.right + _style.hilite_spacing, _prey, + _prePageRect.right + _style.hilite_spacing + pgszr.cx, + _prey + pgszr.cy); + if (ShouldDisplayStatusIcon()) { + _prePageRect.OffsetRect(-STATUS_ICON_SIZE, 0); + _nextPageRect.OffsetRect(-STATUS_ICON_SIZE, 0); + } + } + // calc roundings start + _contentRect.SetRect(0, 0, _contentSize.cx, _contentSize.cy); + // background rect prepare for Hemispherical calculation + CopyRect(_bgRect, _contentRect); + _bgRect.DeflateRect(offsetX + 1, offsetY + 1); + _PrepareRoundInfo(dc); + + // truely draw content size calculation + _contentRect.DeflateRect(offsetX, offsetY); } diff --git a/WeaselUI/VerticalLayout.h b/WeaselUI/VerticalLayout.h index d17eb8cb6..baed528e5 100644 --- a/WeaselUI/VerticalLayout.h +++ b/WeaselUI/VerticalLayout.h @@ -2,13 +2,13 @@ #include "StandardLayout.h" -namespace weasel -{ - class VerticalLayout: public StandardLayout - { - public: - VerticalLayout(const UIStyle &style, const Context &context, const Status &status) - : StandardLayout(style, context, status) {} - virtual void DoLayout(CDCHandle dc, PDWR pDWR = NULL); - }; +namespace weasel { +class VerticalLayout : public StandardLayout { + public: + VerticalLayout(const UIStyle& style, + const Context& context, + const Status& status) + : StandardLayout(style, context, status) {} + virtual void DoLayout(CDCHandle dc, PDWR pDWR = NULL); }; +}; // namespace weasel diff --git a/WeaselUI/WeaselPanel.cpp b/WeaselUI/WeaselPanel.cpp index f39839265..a8b2f41ef 100644 --- a/WeaselUI/WeaselPanel.cpp +++ b/WeaselUI/WeaselPanel.cpp @@ -11,1004 +11,1123 @@ // for IDI_ZH, IDI_EN #include -#define COLORTRANSPARENT(color) ((color & 0xff000000) == 0) -#define COLORNOTTRANSPARENT(color) ((color & 0xff000000) != 0) -#define TRANS_COLOR 0x00000000 -#define GDPCOLOR_FROM_COLORREF(color) Gdiplus::Color::MakeARGB(((color >> 24) & 0xff), GetRValue(color), GetGValue(color), GetBValue(color)) +#define COLORTRANSPARENT(color) ((color & 0xff000000) == 0) +#define COLORNOTTRANSPARENT(color) ((color & 0xff000000) != 0) +#define TRANS_COLOR 0x00000000 +#define GDPCOLOR_FROM_COLORREF(color) \ + Gdiplus::Color::MakeARGB(((color >> 24) & 0xff), GetRValue(color), \ + GetGValue(color), GetBValue(color)) #pragma comment(lib, "Shcore.lib") template inline void LoadIconNecessary(t0& a, t1& b, t2& c, int d) { - if(a == b) return; - a = b; - if (b.empty()) c.LoadIconW(d, STATUS_ICON_SIZE, STATUS_ICON_SIZE, LR_DEFAULTCOLOR); - else c = (HICON)LoadImage(NULL, b.c_str(), IMAGE_ICON, STATUS_ICON_SIZE, STATUS_ICON_SIZE, LR_LOADFROMFILE); + if (a == b) + return; + a = b; + if (b.empty()) + c.LoadIconW(d, STATUS_ICON_SIZE, STATUS_ICON_SIZE, LR_DEFAULTCOLOR); + else + c = (HICON)LoadImage(NULL, b.c_str(), IMAGE_ICON, STATUS_ICON_SIZE, + STATUS_ICON_SIZE, LR_LOADFROMFILE); } -static inline void ReconfigRoundInfo(IsToRoundStruct& rd, const int& i, const int& m_candidateCount) -{ - if(i == 0 && m_candidateCount > 1) { - std::swap(rd.IsTopLeftNeedToRound, rd.IsBottomLeftNeedToRound); - std::swap(rd.IsTopRightNeedToRound, rd.IsBottomRightNeedToRound); - } - if(i == m_candidateCount - 1) { - std::swap(rd.IsTopLeftNeedToRound, rd.IsBottomLeftNeedToRound); - std::swap(rd.IsTopRightNeedToRound, rd.IsBottomRightNeedToRound); - } +static inline void ReconfigRoundInfo(IsToRoundStruct& rd, + const int& i, + const int& m_candidateCount) { + if (i == 0 && m_candidateCount > 1) { + std::swap(rd.IsTopLeftNeedToRound, rd.IsBottomLeftNeedToRound); + std::swap(rd.IsTopRightNeedToRound, rd.IsBottomRightNeedToRound); + } + if (i == m_candidateCount - 1) { + std::swap(rd.IsTopLeftNeedToRound, rd.IsBottomLeftNeedToRound); + std::swap(rd.IsTopRightNeedToRound, rd.IsBottomRightNeedToRound); + } } WeaselPanel::WeaselPanel(weasel::UI& ui) - : m_layout(NULL), - m_ctx(ui.ctx()), - m_octx(ui.octx()), - m_status(ui.status()), - m_style(ui.style()), - m_ostyle(ui.ostyle()), - m_candidateCount(0), - m_current_zhung_icon(), - dpi(96), - hide_candidates(false), - pDWR(ui.pdwr()), - _UICallback(ui.uiCallback()), - _m_gdiplusToken(0) -{ - m_iconDisabled.LoadIconW(IDI_RELOAD, STATUS_ICON_SIZE, STATUS_ICON_SIZE, LR_DEFAULTCOLOR); - m_iconEnabled.LoadIconW(IDI_ZH, STATUS_ICON_SIZE, STATUS_ICON_SIZE, LR_DEFAULTCOLOR); - m_iconAlpha.LoadIconW(IDI_EN, STATUS_ICON_SIZE, STATUS_ICON_SIZE, LR_DEFAULTCOLOR); - m_iconFull.LoadIconW(IDI_FULL_SHAPE, STATUS_ICON_SIZE, STATUS_ICON_SIZE, LR_DEFAULTCOLOR); - m_iconHalf.LoadIconW(IDI_HALF_SHAPE, STATUS_ICON_SIZE, STATUS_ICON_SIZE, LR_DEFAULTCOLOR); - // for gdi+ drawings, initialization - GdiplusStartup(&_m_gdiplusToken, &_m_gdiplusStartupInput, NULL); - - _InitFontRes(); - m_ostyle = m_style; + : m_layout(NULL), + m_ctx(ui.ctx()), + m_octx(ui.octx()), + m_status(ui.status()), + m_style(ui.style()), + m_ostyle(ui.ostyle()), + m_candidateCount(0), + m_current_zhung_icon(), + dpi(96), + hide_candidates(false), + pDWR(ui.pdwr()), + _UICallback(ui.uiCallback()), + _m_gdiplusToken(0) { + m_iconDisabled.LoadIconW(IDI_RELOAD, STATUS_ICON_SIZE, STATUS_ICON_SIZE, + LR_DEFAULTCOLOR); + m_iconEnabled.LoadIconW(IDI_ZH, STATUS_ICON_SIZE, STATUS_ICON_SIZE, + LR_DEFAULTCOLOR); + m_iconAlpha.LoadIconW(IDI_EN, STATUS_ICON_SIZE, STATUS_ICON_SIZE, + LR_DEFAULTCOLOR); + m_iconFull.LoadIconW(IDI_FULL_SHAPE, STATUS_ICON_SIZE, STATUS_ICON_SIZE, + LR_DEFAULTCOLOR); + m_iconHalf.LoadIconW(IDI_HALF_SHAPE, STATUS_ICON_SIZE, STATUS_ICON_SIZE, + LR_DEFAULTCOLOR); + // for gdi+ drawings, initialization + GdiplusStartup(&_m_gdiplusToken, &_m_gdiplusStartupInput, NULL); + + _InitFontRes(); + m_ostyle = m_style; } -WeaselPanel::~WeaselPanel() -{ - Gdiplus::GdiplusShutdown(_m_gdiplusToken); - delete m_layout; - m_layout = NULL; - //pDWR.reset(); +WeaselPanel::~WeaselPanel() { + Gdiplus::GdiplusShutdown(_m_gdiplusToken); + delete m_layout; + m_layout = NULL; + // pDWR.reset(); } -void WeaselPanel::_ResizeWindow() -{ - CDCHandle dc = GetDC(); - CSize m_size = m_layout->GetContentSize(); - SetWindowPos(NULL, 0, 0, m_size.cx, m_size.cy, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW); - ReleaseDC(dc); +void WeaselPanel::_ResizeWindow() { + CDCHandle dc = GetDC(); + CSize m_size = m_layout->GetContentSize(); + SetWindowPos(NULL, 0, 0, m_size.cx, m_size.cy, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW); + ReleaseDC(dc); } -void WeaselPanel::_CreateLayout() -{ - if (m_layout != NULL) - delete m_layout; - - Layout* layout = NULL; - if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) - { - layout = new VHorizontalLayout(m_style, m_ctx, m_status); - } - else - { - if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL || m_style.layout_type == UIStyle::LAYOUT_VERTICAL_FULLSCREEN) - { - layout = new VerticalLayout(m_style, m_ctx, m_status); - } - else if (m_style.layout_type == UIStyle::LAYOUT_HORIZONTAL || m_style.layout_type == UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN) - { - layout = new HorizontalLayout(m_style, m_ctx, m_status); - } - - if (IS_FULLSCREENLAYOUT(m_style)) - { - layout = new FullScreenLayout(m_style, m_ctx, m_status, m_inputPos, layout); - } - } - m_layout = layout; +void WeaselPanel::_CreateLayout() { + if (m_layout != NULL) + delete m_layout; + + Layout* layout = NULL; + if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) { + layout = new VHorizontalLayout(m_style, m_ctx, m_status); + } else { + if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL || + m_style.layout_type == UIStyle::LAYOUT_VERTICAL_FULLSCREEN) { + layout = new VerticalLayout(m_style, m_ctx, m_status); + } else if (m_style.layout_type == UIStyle::LAYOUT_HORIZONTAL || + m_style.layout_type == UIStyle::LAYOUT_HORIZONTAL_FULLSCREEN) { + layout = new HorizontalLayout(m_style, m_ctx, m_status); + } + + if (IS_FULLSCREENLAYOUT(m_style)) { + layout = + new FullScreenLayout(m_style, m_ctx, m_status, m_inputPos, layout); + } + } + m_layout = layout; } -//更新界面 -void WeaselPanel::Refresh() -{ - bool should_show_icon = (m_status.ascii_mode || !m_status.composing || !m_ctx.aux.empty()); - m_candidateCount = (BYTE)m_ctx.cinfo.candies.size(); - // check if to hide candidates window - // show tips status, two kind of situation: 1) only aux strings, don't care icon status; 2)only icon(ascii mode switching) - bool show_tips = (!m_ctx.aux.empty() && m_ctx.cinfo.empty() && m_ctx.preedit.empty()) || (m_ctx.empty() && should_show_icon); - // show schema menu status: schema_id == L".default" - bool show_schema_menu = m_status.schema_id == L".default"; - bool margin_negative = (m_style.margin_x < 0 || m_style.margin_y < 0); - // when to hide_cadidates? - // 1. margin_negative, and not in show tips mode( ascii switching / half-full switching / simp-trad switching / error tips), and not in schema menu - // 2. inline preedit without candidates - bool inline_no_candidates = (m_style.inline_preedit && m_candidateCount == 0) && !show_tips; - hide_candidates = inline_no_candidates || (margin_negative && !show_tips && !show_schema_menu); - - // only RedrawWindow if no need to hide candidates window, or inline_no_candidates - if(!hide_candidates || inline_no_candidates) - { - _InitFontRes(); - _CreateLayout(); - - CDCHandle dc = GetDC(); - m_layout->DoLayout(dc, pDWR); - ReleaseDC(dc); - _ResizeWindow(); - _RepositionWindow(); - if(m_ctx != m_octx) { - m_octx = m_ctx; - RedrawWindow(); - } - } +// 更新界面 +void WeaselPanel::Refresh() { + bool should_show_icon = + (m_status.ascii_mode || !m_status.composing || !m_ctx.aux.empty()); + m_candidateCount = (BYTE)m_ctx.cinfo.candies.size(); + // check if to hide candidates window + // show tips status, two kind of situation: 1) only aux strings, don't care + // icon status; 2)only icon(ascii mode switching) + bool show_tips = + (!m_ctx.aux.empty() && m_ctx.cinfo.empty() && m_ctx.preedit.empty()) || + (m_ctx.empty() && should_show_icon); + // show schema menu status: schema_id == L".default" + bool show_schema_menu = m_status.schema_id == L".default"; + bool margin_negative = (m_style.margin_x < 0 || m_style.margin_y < 0); + // when to hide_cadidates? + // 1. margin_negative, and not in show tips mode( ascii switching / half-full + // switching / simp-trad switching / error tips), and not in schema menu + // 2. inline preedit without candidates + bool inline_no_candidates = + (m_style.inline_preedit && m_candidateCount == 0) && !show_tips; + hide_candidates = inline_no_candidates || + (margin_negative && !show_tips && !show_schema_menu); + + // only RedrawWindow if no need to hide candidates window, or + // inline_no_candidates + if (!hide_candidates || inline_no_candidates) { + _InitFontRes(); + _CreateLayout(); + + CDCHandle dc = GetDC(); + m_layout->DoLayout(dc, pDWR); + ReleaseDC(dc); + _ResizeWindow(); + _RepositionWindow(); + if (m_ctx != m_octx) { + m_octx = m_ctx; + RedrawWindow(); + } + } } -void WeaselPanel::_InitFontRes(bool forced) -{ - HMONITOR hMonitor = MonitorFromRect(m_inputPos, MONITOR_DEFAULTTONEAREST); - UINT dpiX = 96, dpiY = 96; - if (hMonitor) - GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); - // prepare d2d1 resources - // if style changed, or dpi changed, or pDWR NULL, re-initialize directwrite resources - if (forced || (pDWR == NULL) || (m_ostyle != m_style) || (dpiX != dpi)) - { - pDWR.reset(); - pDWR = std::make_shared< DirectWriteResources>(m_style, dpiX); - pDWR->pRenderTarget->SetTextAntialiasMode((D2D1_TEXT_ANTIALIAS_MODE)m_style.antialias_mode); - } - m_ostyle = m_style; - dpi = dpiX; +void WeaselPanel::_InitFontRes(bool forced) { + HMONITOR hMonitor = MonitorFromRect(m_inputPos, MONITOR_DEFAULTTONEAREST); + UINT dpiX = 96, dpiY = 96; + if (hMonitor) + GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); + // prepare d2d1 resources + // if style changed, or dpi changed, or pDWR NULL, re-initialize directwrite + // resources + if (forced || (pDWR == NULL) || (m_ostyle != m_style) || (dpiX != dpi)) { + pDWR.reset(); + pDWR = std::make_shared(m_style, dpiX); + pDWR->pRenderTarget->SetTextAntialiasMode( + (D2D1_TEXT_ANTIALIAS_MODE)m_style.antialias_mode); + } + m_ostyle = m_style; + dpi = dpiX; } -static HBITMAP CopyDCToBitmap(HDC hDC, LPRECT lpRect) -{ - if (!hDC || !lpRect || IsRectEmpty(lpRect)) return NULL; - HDC hMemDC; - HBITMAP hBitmap, hOldBitmap; - int nX, nY, nX2, nY2; - int nWidth, nHeight; - - nX = lpRect->left; - nY = lpRect->top; - nX2 = lpRect->right; - nY2 = lpRect->bottom; - nWidth = nX2 - nX; - nHeight = nY2 - nY; - - hMemDC = CreateCompatibleDC(hDC); - hBitmap = CreateCompatibleBitmap(hDC, nWidth, nHeight); - hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap); - StretchBlt(hMemDC, 0, 0, nWidth, nHeight, hDC, nX, nY, nWidth, nHeight, SRCCOPY); - hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap); - - DeleteDC(hMemDC); - DeleteObject(hOldBitmap); - return hBitmap; - } - -void WeaselPanel::_CaptureRect(CRect& rect) -{ - HDC ScreenDC = ::GetDC(NULL); - CRect rc; - GetWindowRect(&rc); - POINT WindowPosAtScreen = { rc.left, rc.top }; - rect.OffsetRect(WindowPosAtScreen); - // capture input window - if (OpenClipboard()) { - HBITMAP bmp = CopyDCToBitmap(ScreenDC, LPRECT(rect)); - EmptyClipboard(); - SetClipboardData(CF_BITMAP, bmp); - CloseClipboard(); - DeleteObject(bmp); - } - ReleaseDC(ScreenDC); +static HBITMAP CopyDCToBitmap(HDC hDC, LPRECT lpRect) { + if (!hDC || !lpRect || IsRectEmpty(lpRect)) + return NULL; + HDC hMemDC; + HBITMAP hBitmap, hOldBitmap; + int nX, nY, nX2, nY2; + int nWidth, nHeight; + + nX = lpRect->left; + nY = lpRect->top; + nX2 = lpRect->right; + nY2 = lpRect->bottom; + nWidth = nX2 - nX; + nHeight = nY2 - nY; + + hMemDC = CreateCompatibleDC(hDC); + hBitmap = CreateCompatibleBitmap(hDC, nWidth, nHeight); + hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap); + StretchBlt(hMemDC, 0, 0, nWidth, nHeight, hDC, nX, nY, nWidth, nHeight, + SRCCOPY); + hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap); + + DeleteDC(hMemDC); + DeleteObject(hOldBitmap); + return hBitmap; } -LRESULT WeaselPanel::OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) -{ - bHandled = true; - return MA_NOACTIVATE; +void WeaselPanel::_CaptureRect(CRect& rect) { + HDC ScreenDC = ::GetDC(NULL); + CRect rc; + GetWindowRect(&rc); + POINT WindowPosAtScreen = {rc.left, rc.top}; + rect.OffsetRect(WindowPosAtScreen); + // capture input window + if (OpenClipboard()) { + HBITMAP bmp = CopyDCToBitmap(ScreenDC, LPRECT(rect)); + EmptyClipboard(); + SetClipboardData(CF_BITMAP, bmp); + CloseClipboard(); + DeleteObject(bmp); + } + ReleaseDC(ScreenDC); } -LRESULT WeaselPanel::OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) -{ - int delta = GET_WHEEL_DELTA_WPARAM(wParam); - if(_UICallback && delta != 0) - { - bool nextpage = delta < 0; - _UICallback(NULL, NULL, NULL, &nextpage); - } - bHandled = true; - return 0; +LRESULT WeaselPanel::OnMouseActivate(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled) { + bHandled = true; + return MA_NOACTIVATE; } -LRESULT WeaselPanel::OnLeftClicked(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) -{ - if(hide_candidates) - { - bHandled = true; - return 0; - } - CPoint point; - point.x = GET_X_LPARAM(lParam); - point.y = GET_Y_LPARAM(lParam); - - // capture - if(m_style.click_to_capture) - { - CRect recth = m_layout->GetCandidateRect((int)m_ctx.cinfo.highlighted); - if(m_istorepos) recth.OffsetRect(0, m_offsetys[m_ctx.cinfo.highlighted]); - recth.InflateRect(m_style.hilite_padding_x, m_style.hilite_padding_y); - // capture widow - if (recth.PtInRect(point)) _CaptureRect(recth); - else { - // if shadow_color transparent, decrease the capture rectangle size - if(COLORTRANSPARENT(m_style.shadow_color) && m_style.shadow_radius != 0) { - CRect crc(rcw); - int shadow_gap = (m_style.shadow_offset_x ==0 && m_style.shadow_offset_y == 0) ? 2 * m_style.shadow_radius : m_style.shadow_radius + m_style.shadow_radius / 2; - int ofx = m_style.hilite_padding_x + abs(m_style.shadow_offset_x) + shadow_gap > abs(m_style.margin_x) ? - m_style.hilite_padding_x + abs(m_style.shadow_offset_x) + shadow_gap - abs(m_style.margin_x) : 0; - int ofy = m_style.hilite_padding_y + abs(m_style.shadow_offset_y) + shadow_gap > abs(m_style.margin_y) ? - m_style.hilite_padding_y + abs(m_style.shadow_offset_y) + shadow_gap - abs(m_style.margin_y) : 0; - crc.DeflateRect(m_layout->offsetX - ofx, m_layout->offsetY - ofy); - _CaptureRect(crc); - } else { - _CaptureRect(rcw); - } - } - } - // button response - { - if(!m_style.inline_preedit && m_candidateCount != 0 && COLORNOTTRANSPARENT(m_style.prevpage_color) && COLORNOTTRANSPARENT(m_style.nextpage_color)) { - // click prepage - if(m_ctx.cinfo.currentPage != 0 ) { - CRect prc = m_layout->GetPrepageRect(); - if(m_istorepos) prc.OffsetRect(0, m_offsety_preedit); - if(prc.PtInRect(point)) { - bool nextPage = false; - if(_UICallback) - _UICallback(NULL, NULL, &nextPage, NULL); - bHandled = true; - return 0; - } - } - // click nextpage - if(!m_ctx.cinfo.is_last_page) { - CRect prc = m_layout->GetNextpageRect(); - if(m_istorepos) prc.OffsetRect(0, m_offsety_preedit); - if(prc.PtInRect(point)) { - bool nextPage = true; - if(_UICallback) - _UICallback(NULL, NULL, &nextPage, NULL); - bHandled = true; - return 0; - } - } - } - // select by click - for (size_t i = 0; i < m_candidateCount && i < MAX_CANDIDATES_COUNT; ++i) { - CRect rect = m_layout->GetCandidateRect((int)i); - if(m_istorepos) rect.OffsetRect(0, m_offsetys[i]); - rect.InflateRect(m_style.hilite_padding_x, m_style.hilite_padding_y); - if (rect.PtInRect(point)) - { - if(_UICallback) - _UICallback(&i, NULL, NULL, NULL); - break; - } - } - } - bHandled = true; - return 0; +LRESULT WeaselPanel::OnMouseWheel(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled) { + int delta = GET_WHEEL_DELTA_WPARAM(wParam); + if (_UICallback && delta != 0) { + bool nextpage = delta < 0; + _UICallback(NULL, NULL, NULL, &nextpage); + } + bHandled = true; + return 0; } -LRESULT WeaselPanel::OnMouseHover(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) -{ - if(!m_style.mouse_hover_ms) return 0; - CPoint point; - point.x = GET_X_LPARAM(lParam); - point.y = GET_Y_LPARAM(lParam); - - for (size_t i = 0; i < m_candidateCount && i < MAX_CANDIDATES_COUNT; ++i) { - CRect rect = m_layout->GetCandidateRect((int)i); - if (m_istorepos) - rect.OffsetRect(0, m_offsetys[i]); - if (rect.PtInRect(point) && i != m_ctx.cinfo.highlighted) - { - if (_UICallback) - _UICallback(NULL, &i, NULL, NULL); - } - } - bHandled = true; - return 0; +LRESULT WeaselPanel::OnLeftClicked(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled) { + if (hide_candidates) { + bHandled = true; + return 0; + } + CPoint point; + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + // capture + if (m_style.click_to_capture) { + CRect recth = m_layout->GetCandidateRect((int)m_ctx.cinfo.highlighted); + if (m_istorepos) + recth.OffsetRect(0, m_offsetys[m_ctx.cinfo.highlighted]); + recth.InflateRect(m_style.hilite_padding_x, m_style.hilite_padding_y); + // capture widow + if (recth.PtInRect(point)) + _CaptureRect(recth); + else { + // if shadow_color transparent, decrease the capture rectangle size + if (COLORTRANSPARENT(m_style.shadow_color) && + m_style.shadow_radius != 0) { + CRect crc(rcw); + int shadow_gap = + (m_style.shadow_offset_x == 0 && m_style.shadow_offset_y == 0) + ? 2 * m_style.shadow_radius + : m_style.shadow_radius + m_style.shadow_radius / 2; + int ofx = m_style.hilite_padding_x + abs(m_style.shadow_offset_x) + + shadow_gap > + abs(m_style.margin_x) + ? m_style.hilite_padding_x + + abs(m_style.shadow_offset_x) + shadow_gap - + abs(m_style.margin_x) + : 0; + int ofy = m_style.hilite_padding_y + abs(m_style.shadow_offset_y) + + shadow_gap > + abs(m_style.margin_y) + ? m_style.hilite_padding_y + + abs(m_style.shadow_offset_y) + shadow_gap - + abs(m_style.margin_y) + : 0; + crc.DeflateRect(m_layout->offsetX - ofx, m_layout->offsetY - ofy); + _CaptureRect(crc); + } else { + _CaptureRect(rcw); + } + } + } + // button response + { + if (!m_style.inline_preedit && m_candidateCount != 0 && + COLORNOTTRANSPARENT(m_style.prevpage_color) && + COLORNOTTRANSPARENT(m_style.nextpage_color)) { + // click prepage + if (m_ctx.cinfo.currentPage != 0) { + CRect prc = m_layout->GetPrepageRect(); + if (m_istorepos) + prc.OffsetRect(0, m_offsety_preedit); + if (prc.PtInRect(point)) { + bool nextPage = false; + if (_UICallback) + _UICallback(NULL, NULL, &nextPage, NULL); + bHandled = true; + return 0; + } + } + // click nextpage + if (!m_ctx.cinfo.is_last_page) { + CRect prc = m_layout->GetNextpageRect(); + if (m_istorepos) + prc.OffsetRect(0, m_offsety_preedit); + if (prc.PtInRect(point)) { + bool nextPage = true; + if (_UICallback) + _UICallback(NULL, NULL, &nextPage, NULL); + bHandled = true; + return 0; + } + } + } + // select by click + for (size_t i = 0; i < m_candidateCount && i < MAX_CANDIDATES_COUNT; ++i) { + CRect rect = m_layout->GetCandidateRect((int)i); + if (m_istorepos) + rect.OffsetRect(0, m_offsetys[i]); + rect.InflateRect(m_style.hilite_padding_x, m_style.hilite_padding_y); + if (rect.PtInRect(point)) { + if (_UICallback) + _UICallback(&i, NULL, NULL, NULL); + break; + } + } + } + bHandled = true; + return 0; } -LRESULT WeaselPanel::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) -{ - if (m_mouse_entry == false && m_style.mouse_hover_ms) - { - TRACKMOUSEEVENT tme; - tme.cbSize = sizeof(TRACKMOUSEEVENT); - tme.dwFlags = TME_HOVER | TME_LEAVE; - tme.dwHoverTime = m_style.mouse_hover_ms; // unit: ms - tme.hwndTrack = m_hWnd; - TrackMouseEvent(&tme); - } - return 0; +LRESULT WeaselPanel::OnMouseHover(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled) { + if (!m_style.mouse_hover_ms) + return 0; + CPoint point; + point.x = GET_X_LPARAM(lParam); + point.y = GET_Y_LPARAM(lParam); + + for (size_t i = 0; i < m_candidateCount && i < MAX_CANDIDATES_COUNT; ++i) { + CRect rect = m_layout->GetCandidateRect((int)i); + if (m_istorepos) + rect.OffsetRect(0, m_offsetys[i]); + if (rect.PtInRect(point) && i != m_ctx.cinfo.highlighted) { + if (_UICallback) + _UICallback(NULL, &i, NULL, NULL); + } + } + bHandled = true; + return 0; } -LRESULT WeaselPanel::OnMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) -{ - m_mouse_entry = false; - return 0; +LRESULT WeaselPanel::OnMouseMove(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled) { + if (m_mouse_entry == false && m_style.mouse_hover_ms) { + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(TRACKMOUSEEVENT); + tme.dwFlags = TME_HOVER | TME_LEAVE; + tme.dwHoverTime = m_style.mouse_hover_ms; // unit: ms + tme.hwndTrack = m_hWnd; + TrackMouseEvent(&tme); + } + return 0; } -void WeaselPanel::_HighlightText(CDCHandle &dc, const CRect& rc, - const COLORREF& color, const COLORREF& shadowColor, const int& radius, - const BackType& type = BackType::TEXT, - const IsToRoundStruct& rd = IsToRoundStruct(), - const COLORREF& bordercolor=TRANS_COLOR) -{ - // Graphics obj with SmoothingMode - Gdiplus::Graphics g_back(dc); - g_back.SetSmoothingMode(Gdiplus::SmoothingMode::SmoothingModeHighQuality); - - // blur buffer - int blurMarginX = m_layout->offsetX; - int blurMarginY = m_layout->offsetY; - - GraphicsRoundRectPath* hiliteBackPath; - if (rd.Hemispherical && type!= BackType::BACKGROUND && NOT_FULLSCREENLAYOUT(m_style)) - hiliteBackPath = new GraphicsRoundRectPath(rc, m_style.round_corner_ex - (m_style.border%2 ? m_style.border / 2 : 0) , rd.IsTopLeftNeedToRound, rd.IsTopRightNeedToRound, rd.IsBottomRightNeedToRound, rd.IsBottomLeftNeedToRound); - else // background or current candidate background not out of window background - hiliteBackPath = new GraphicsRoundRectPath(rc, radius); - - // 必须shadow_color都是非完全透明色才做绘制, 全屏状态不绘制阴影保证响应速度 - if ( m_style.shadow_radius && COLORNOTTRANSPARENT(shadowColor) && NOT_FULLSCREENLAYOUT(m_style) ) { - CRect rect( - blurMarginX + m_style.shadow_offset_x, - blurMarginY + m_style.shadow_offset_y, - rc.Width() + blurMarginX + m_style.shadow_offset_x, - rc.Height() + blurMarginY + m_style.shadow_offset_y); - BYTE r = GetRValue(shadowColor); - BYTE g = GetGValue(shadowColor); - BYTE b = GetBValue(shadowColor); - BYTE alpha = (BYTE)((shadowColor >> 24) & 255); - Gdiplus::Color shadow_color = Gdiplus::Color::MakeARGB(alpha, r, g, b); - static Gdiplus::Bitmap* pBitmapDropShadow; - pBitmapDropShadow = new Gdiplus::Bitmap((INT)rc.Width() + blurMarginX * 2, (INT)rc.Height() + blurMarginY * 2, PixelFormat32bppPARGB); - - Gdiplus::Graphics g_shadow(pBitmapDropShadow); - g_shadow.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality); - // dropshadow, draw a roundrectangle to blur - if (m_style.shadow_offset_x != 0 || m_style.shadow_offset_y != 0) { - GraphicsRoundRectPath shadow_path(rect, radius); - Gdiplus::SolidBrush shadow_brush(shadow_color); - g_shadow.FillPath(&shadow_brush, &shadow_path); - } - // round shadow, draw multilines as base round line - else { - int step = alpha / m_style.shadow_radius / 2; - Gdiplus::Pen pen_shadow(shadow_color, (Gdiplus::REAL)1); - for (int i = 0; i < m_style.shadow_radius; i++) { - GraphicsRoundRectPath round_path(rect, radius + 1 + i); - g_shadow.DrawPath(&pen_shadow, &round_path); - shadow_color = Gdiplus::Color::MakeARGB(alpha - i * step, r, g, b); - pen_shadow.SetColor(shadow_color); - rect.InflateRect(1, 1); - } - } - DoGaussianBlur(pBitmapDropShadow, (float)m_style.shadow_radius, (float)m_style.shadow_radius); - - g_back.DrawImage(pBitmapDropShadow, rc.left - blurMarginX, rc.top - blurMarginY); - - // free memory - delete pBitmapDropShadow; - pBitmapDropShadow = NULL; - } - - // 必须back_color非完全透明才绘制 - if (COLORNOTTRANSPARENT(color)) { - Gdiplus::Color back_color = GDPCOLOR_FROM_COLORREF(color); - Gdiplus::SolidBrush back_brush(back_color); - g_back.FillPath(&back_brush, hiliteBackPath); - } - // draw border, for bordercolor not transparent and border valid - if(COLORNOTTRANSPARENT(bordercolor) && m_style.border > 0) - { - Gdiplus::Color border_color = GDPCOLOR_FROM_COLORREF(bordercolor); - Gdiplus::Pen gPenBorder(border_color, (Gdiplus::REAL)m_style.border); - // candidate window border - if (type == BackType::BACKGROUND) { - GraphicsRoundRectPath bgPath(rc, m_style.round_corner_ex); - g_back.DrawPath(&gPenBorder, &bgPath); - } - else if (type != BackType::TEXT) // hilited_candidate_border / candidate_border - g_back.DrawPath(&gPenBorder, hiliteBackPath); - } - // free memory - delete hiliteBackPath; - hiliteBackPath = NULL; +LRESULT WeaselPanel::OnMouseLeave(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled) { + m_mouse_entry = false; + return 0; +} + +void WeaselPanel::_HighlightText(CDCHandle& dc, + const CRect& rc, + const COLORREF& color, + const COLORREF& shadowColor, + const int& radius, + const BackType& type = BackType::TEXT, + const IsToRoundStruct& rd = IsToRoundStruct(), + const COLORREF& bordercolor = TRANS_COLOR) { + // Graphics obj with SmoothingMode + Gdiplus::Graphics g_back(dc); + g_back.SetSmoothingMode(Gdiplus::SmoothingMode::SmoothingModeHighQuality); + + // blur buffer + int blurMarginX = m_layout->offsetX; + int blurMarginY = m_layout->offsetY; + + GraphicsRoundRectPath* hiliteBackPath; + if (rd.Hemispherical && type != BackType::BACKGROUND && + NOT_FULLSCREENLAYOUT(m_style)) + hiliteBackPath = new GraphicsRoundRectPath( + rc, + m_style.round_corner_ex - (m_style.border % 2 ? m_style.border / 2 : 0), + rd.IsTopLeftNeedToRound, rd.IsTopRightNeedToRound, + rd.IsBottomRightNeedToRound, rd.IsBottomLeftNeedToRound); + else // background or current candidate background not out of window + // background + hiliteBackPath = new GraphicsRoundRectPath(rc, radius); + + // 必须shadow_color都是非完全透明色才做绘制, 全屏状态不绘制阴影保证响应速度 + if (m_style.shadow_radius && COLORNOTTRANSPARENT(shadowColor) && + NOT_FULLSCREENLAYOUT(m_style)) { + CRect rect(blurMarginX + m_style.shadow_offset_x, + blurMarginY + m_style.shadow_offset_y, + rc.Width() + blurMarginX + m_style.shadow_offset_x, + rc.Height() + blurMarginY + m_style.shadow_offset_y); + BYTE r = GetRValue(shadowColor); + BYTE g = GetGValue(shadowColor); + BYTE b = GetBValue(shadowColor); + BYTE alpha = (BYTE)((shadowColor >> 24) & 255); + Gdiplus::Color shadow_color = Gdiplus::Color::MakeARGB(alpha, r, g, b); + static Gdiplus::Bitmap* pBitmapDropShadow; + pBitmapDropShadow = new Gdiplus::Bitmap((INT)rc.Width() + blurMarginX * 2, + (INT)rc.Height() + blurMarginY * 2, + PixelFormat32bppPARGB); + + Gdiplus::Graphics g_shadow(pBitmapDropShadow); + g_shadow.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality); + // dropshadow, draw a roundrectangle to blur + if (m_style.shadow_offset_x != 0 || m_style.shadow_offset_y != 0) { + GraphicsRoundRectPath shadow_path(rect, radius); + Gdiplus::SolidBrush shadow_brush(shadow_color); + g_shadow.FillPath(&shadow_brush, &shadow_path); + } + // round shadow, draw multilines as base round line + else { + int step = alpha / m_style.shadow_radius / 2; + Gdiplus::Pen pen_shadow(shadow_color, (Gdiplus::REAL)1); + for (int i = 0; i < m_style.shadow_radius; i++) { + GraphicsRoundRectPath round_path(rect, radius + 1 + i); + g_shadow.DrawPath(&pen_shadow, &round_path); + shadow_color = Gdiplus::Color::MakeARGB(alpha - i * step, r, g, b); + pen_shadow.SetColor(shadow_color); + rect.InflateRect(1, 1); + } + } + DoGaussianBlur(pBitmapDropShadow, (float)m_style.shadow_radius, + (float)m_style.shadow_radius); + + g_back.DrawImage(pBitmapDropShadow, rc.left - blurMarginX, + rc.top - blurMarginY); + + // free memory + delete pBitmapDropShadow; + pBitmapDropShadow = NULL; + } + + // 必须back_color非完全透明才绘制 + if (COLORNOTTRANSPARENT(color)) { + Gdiplus::Color back_color = GDPCOLOR_FROM_COLORREF(color); + Gdiplus::SolidBrush back_brush(back_color); + g_back.FillPath(&back_brush, hiliteBackPath); + } + // draw border, for bordercolor not transparent and border valid + if (COLORNOTTRANSPARENT(bordercolor) && m_style.border > 0) { + Gdiplus::Color border_color = GDPCOLOR_FROM_COLORREF(bordercolor); + Gdiplus::Pen gPenBorder(border_color, (Gdiplus::REAL)m_style.border); + // candidate window border + if (type == BackType::BACKGROUND) { + GraphicsRoundRectPath bgPath(rc, m_style.round_corner_ex); + g_back.DrawPath(&gPenBorder, &bgPath); + } else if (type != + BackType::TEXT) // hilited_candidate_border / candidate_border + g_back.DrawPath(&gPenBorder, hiliteBackPath); + } + // free memory + delete hiliteBackPath; + hiliteBackPath = NULL; } // draw preedit text, text only -bool WeaselPanel::_DrawPreedit(const Text& text, CDCHandle dc, const CRect& rc) -{ - bool drawn = false; - std::wstring const& t = text.str; - IDWriteTextFormat1* txtFormat = pDWR->pPreeditTextFormat.Get(); - - if (!t.empty()) { - weasel::TextRange range = m_layout->GetPreeditRange(); - - if (range.start < range.end) { - std::wstring before_str = t.substr(0, range.start); - std::wstring hilited_str = t.substr(range.start, range.end); - std::wstring after_str = t.substr(range.end); - CSize beforeSz = m_layout->GetBeforeSize(); - CSize hilitedSz = m_layout->GetHilitedSize(); - CSize afterSz = m_layout->GetAfterSize(); - - int x = rc.left; - int y = rc.top; - - if (range.start > 0) { - // zzz - std::wstring str_before(t.substr(0, range.start)); - CRect rc_before; - if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) - rc_before = CRect(rc.left, y, rc.right, y + beforeSz.cy); - else - rc_before = CRect(x, rc.top, rc.left + beforeSz.cx, rc.bottom); - _TextOut(rc_before, str_before.c_str(), str_before.length(), m_style.text_color, txtFormat); - if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) - y += beforeSz.cy + m_style.hilite_spacing; - else - x += beforeSz.cx + m_style.hilite_spacing; - } - { - // zzz[yyy] - std::wstring str_highlight(t.substr(range.start, range.end - range.start)); - CRect rc_hi; - - if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) - rc_hi = CRect(rc.left, y, rc.right, y + hilitedSz.cy); - else - rc_hi = CRect(x, rc.top, x + hilitedSz.cx, rc.bottom); - _TextOut(rc_hi, str_highlight.c_str(), str_highlight.length(), m_style.hilited_text_color, txtFormat); - if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) - y += rc_hi.Height()+m_style.hilite_spacing; - else - x += rc_hi.Width()+m_style.hilite_spacing; - } - if (range.end < static_cast(t.length())) { - // zzz[yyy]xxx - std::wstring str_after(t.substr(range.end)); - CRect rc_after; - if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) - rc_after = CRect(rc.left, y, rc.right, y + afterSz.cy); - else - rc_after = CRect(x, rc.top, x + afterSz.cx, rc.bottom); - _TextOut(rc_after, str_after.c_str(), str_after.length(), m_style.text_color, txtFormat); - } - } - else { - CRect rcText(rc.left, rc.top, rc.right, rc.bottom); - _TextOut(rcText, t.c_str(), t.length(), m_style.text_color, txtFormat); - } - // draw pager mark if not inline_preedit if necessary - if(m_candidateCount && !m_style.inline_preedit && COLORNOTTRANSPARENT(m_style.prevpage_color) && COLORNOTTRANSPARENT(m_style.nextpage_color)) - { - const std::wstring pre = L"<"; - const std::wstring next = L">"; - CRect prc = m_layout->GetPrepageRect(); - // clickable color / disabled color - int color = m_ctx.cinfo.currentPage ? m_style.prevpage_color : m_style.text_color; - if(m_istorepos) prc.OffsetRect(0, m_offsety_preedit); - _TextOut(prc, pre.c_str(), pre.length(), color, txtFormat); - - CRect nrc = m_layout->GetNextpageRect(); - // clickable color / disabled color - color = m_ctx.cinfo.is_last_page ? m_style.text_color : m_style.nextpage_color; - if(m_istorepos) nrc.OffsetRect(0, m_offsety_preedit); - _TextOut(nrc, next.c_str(), next.length(), color, txtFormat); - } - drawn = true; - } - return drawn; +bool WeaselPanel::_DrawPreedit(const Text& text, + CDCHandle dc, + const CRect& rc) { + bool drawn = false; + std::wstring const& t = text.str; + IDWriteTextFormat1* txtFormat = pDWR->pPreeditTextFormat.Get(); + + if (!t.empty()) { + weasel::TextRange range = m_layout->GetPreeditRange(); + + if (range.start < range.end) { + std::wstring before_str = t.substr(0, range.start); + std::wstring hilited_str = t.substr(range.start, range.end); + std::wstring after_str = t.substr(range.end); + CSize beforeSz = m_layout->GetBeforeSize(); + CSize hilitedSz = m_layout->GetHilitedSize(); + CSize afterSz = m_layout->GetAfterSize(); + + int x = rc.left; + int y = rc.top; + + if (range.start > 0) { + // zzz + std::wstring str_before(t.substr(0, range.start)); + CRect rc_before; + if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) + rc_before = CRect(rc.left, y, rc.right, y + beforeSz.cy); + else + rc_before = CRect(x, rc.top, rc.left + beforeSz.cx, rc.bottom); + _TextOut(rc_before, str_before.c_str(), str_before.length(), + m_style.text_color, txtFormat); + if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) + y += beforeSz.cy + m_style.hilite_spacing; + else + x += beforeSz.cx + m_style.hilite_spacing; + } + { + // zzz[yyy] + std::wstring str_highlight( + t.substr(range.start, range.end - range.start)); + CRect rc_hi; + + if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) + rc_hi = CRect(rc.left, y, rc.right, y + hilitedSz.cy); + else + rc_hi = CRect(x, rc.top, x + hilitedSz.cx, rc.bottom); + _TextOut(rc_hi, str_highlight.c_str(), str_highlight.length(), + m_style.hilited_text_color, txtFormat); + if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) + y += rc_hi.Height() + m_style.hilite_spacing; + else + x += rc_hi.Width() + m_style.hilite_spacing; + } + if (range.end < static_cast(t.length())) { + // zzz[yyy]xxx + std::wstring str_after(t.substr(range.end)); + CRect rc_after; + if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) + rc_after = CRect(rc.left, y, rc.right, y + afterSz.cy); + else + rc_after = CRect(x, rc.top, x + afterSz.cx, rc.bottom); + _TextOut(rc_after, str_after.c_str(), str_after.length(), + m_style.text_color, txtFormat); + } + } else { + CRect rcText(rc.left, rc.top, rc.right, rc.bottom); + _TextOut(rcText, t.c_str(), t.length(), m_style.text_color, txtFormat); + } + // draw pager mark if not inline_preedit if necessary + if (m_candidateCount && !m_style.inline_preedit && + COLORNOTTRANSPARENT(m_style.prevpage_color) && + COLORNOTTRANSPARENT(m_style.nextpage_color)) { + const std::wstring pre = L"<"; + const std::wstring next = L">"; + CRect prc = m_layout->GetPrepageRect(); + // clickable color / disabled color + int color = + m_ctx.cinfo.currentPage ? m_style.prevpage_color : m_style.text_color; + if (m_istorepos) + prc.OffsetRect(0, m_offsety_preedit); + _TextOut(prc, pre.c_str(), pre.length(), color, txtFormat); + + CRect nrc = m_layout->GetNextpageRect(); + // clickable color / disabled color + color = m_ctx.cinfo.is_last_page ? m_style.text_color + : m_style.nextpage_color; + if (m_istorepos) + nrc.OffsetRect(0, m_offsety_preedit); + _TextOut(nrc, next.c_str(), next.length(), color, txtFormat); + } + drawn = true; + } + return drawn; } // draw hilited back color, back only -bool WeaselPanel::_DrawPreeditBack(const Text& text, CDCHandle dc, const CRect& rc) -{ - bool drawn = false; - std::wstring const& t = text.str; - IDWriteTextFormat1* txtFormat = pDWR->pPreeditTextFormat.Get(); - - if (!t.empty()) { - weasel::TextRange range = m_layout->GetPreeditRange(); - - if (range.start < range.end) { - CSize beforeSz = m_layout->GetBeforeSize(); - CSize hilitedSz = m_layout->GetHilitedSize(); - - int x = rc.left; - int y = rc.top; - - if (range.start > 0) { - if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) - y += beforeSz.cy + m_style.hilite_spacing; - else - x += beforeSz.cx + m_style.hilite_spacing; - } - { - CRect rc_hi; - if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) - rc_hi = CRect(rc.left, y, rc.right, y + hilitedSz.cy); - else - rc_hi = CRect(x, rc.top, x + hilitedSz.cx, rc.bottom); - // if preedit rect size smaller than icon, fill the gap to STATUS_ICON_SIZE - if(m_layout->ShouldDisplayStatusIcon()) - { - if((m_style.layout_type == UIStyle::LAYOUT_HORIZONTAL || m_style.layout_type == UIStyle::LAYOUT_VERTICAL) && hilitedSz.cy < STATUS_ICON_SIZE) - rc_hi.InflateRect(0, (STATUS_ICON_SIZE - hilitedSz.cy) / 2); - if(m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT && hilitedSz.cx < STATUS_ICON_SIZE) - rc_hi.InflateRect((STATUS_ICON_SIZE - hilitedSz.cx) / 2, 0); - } - - rc_hi.InflateRect(m_style.hilite_padding_x, m_style.hilite_padding_y); - IsToRoundStruct rd = m_layout->GetTextRoundInfo(); - if(m_istorepos) { - std::swap(rd.IsTopLeftNeedToRound, rd.IsBottomLeftNeedToRound); - std::swap(rd.IsTopRightNeedToRound, rd.IsBottomRightNeedToRound); - } - _HighlightText(dc, rc_hi, m_style.hilited_back_color, m_style.hilited_shadow_color, m_style.round_corner, BackType::TEXT, rd); - } - } - drawn = true; - } - return drawn; +bool WeaselPanel::_DrawPreeditBack(const Text& text, + CDCHandle dc, + const CRect& rc) { + bool drawn = false; + std::wstring const& t = text.str; + IDWriteTextFormat1* txtFormat = pDWR->pPreeditTextFormat.Get(); + + if (!t.empty()) { + weasel::TextRange range = m_layout->GetPreeditRange(); + + if (range.start < range.end) { + CSize beforeSz = m_layout->GetBeforeSize(); + CSize hilitedSz = m_layout->GetHilitedSize(); + + int x = rc.left; + int y = rc.top; + + if (range.start > 0) { + if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) + y += beforeSz.cy + m_style.hilite_spacing; + else + x += beforeSz.cx + m_style.hilite_spacing; + } + { + CRect rc_hi; + if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) + rc_hi = CRect(rc.left, y, rc.right, y + hilitedSz.cy); + else + rc_hi = CRect(x, rc.top, x + hilitedSz.cx, rc.bottom); + // if preedit rect size smaller than icon, fill the gap to + // STATUS_ICON_SIZE + if (m_layout->ShouldDisplayStatusIcon()) { + if ((m_style.layout_type == UIStyle::LAYOUT_HORIZONTAL || + m_style.layout_type == UIStyle::LAYOUT_VERTICAL) && + hilitedSz.cy < STATUS_ICON_SIZE) + rc_hi.InflateRect(0, (STATUS_ICON_SIZE - hilitedSz.cy) / 2); + if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT && + hilitedSz.cx < STATUS_ICON_SIZE) + rc_hi.InflateRect((STATUS_ICON_SIZE - hilitedSz.cx) / 2, 0); + } + + rc_hi.InflateRect(m_style.hilite_padding_x, m_style.hilite_padding_y); + IsToRoundStruct rd = m_layout->GetTextRoundInfo(); + if (m_istorepos) { + std::swap(rd.IsTopLeftNeedToRound, rd.IsBottomLeftNeedToRound); + std::swap(rd.IsTopRightNeedToRound, rd.IsBottomRightNeedToRound); + } + _HighlightText(dc, rc_hi, m_style.hilited_back_color, + m_style.hilited_shadow_color, m_style.round_corner, + BackType::TEXT, rd); + } + } + drawn = true; + } + return drawn; } -bool WeaselPanel::_DrawCandidates(CDCHandle &dc, bool back) -{ - bool drawn = false; - const std::vector &candidates(m_ctx.cinfo.candies); - const std::vector &comments(m_ctx.cinfo.comments); - const std::vector &labels(m_ctx.cinfo.labels); - // prevent all text format nullptr - if(pDWR->pTextFormat.Get() == nullptr - && pDWR->pLabelTextFormat.Get() == nullptr - && pDWR->pCommentTextFormat.Get() == nullptr) { - _InitFontRes(true); - } - ComPtr txtFormat = pDWR->pTextFormat; - ComPtr labeltxtFormat = pDWR->pLabelTextFormat; - ComPtr commenttxtFormat = pDWR->pCommentTextFormat; - BackType bkType = BackType::CAND; - - - CRect rect; - // draw back color and shadow color, with gdi+ - if (back) { - // if candidate_shadow_color not transparent, draw candidate shadow first - if (COLORNOTTRANSPARENT(m_style.candidate_shadow_color)) { - for (auto i = 0; i < m_candidateCount && i < MAX_CANDIDATES_COUNT; ++i) { - if (i == m_ctx.cinfo.highlighted) continue; // draw non hilited candidates only - rect = m_layout->GetCandidateRect((int)i); - IsToRoundStruct rd = m_layout->GetRoundInfo(i); - if(m_istorepos) { - rect.OffsetRect(0, m_offsetys[i]); - ReconfigRoundInfo(rd, i, m_candidateCount); - } - rect.InflateRect(m_style.hilite_padding_x, m_style.hilite_padding_y); - _HighlightText(dc, rect, 0x00000000, m_style.candidate_shadow_color, m_style.round_corner, bkType, rd); - drawn = true; - } - } - // draw non highlighted candidates, without shadow - if (COLORNOTTRANSPARENT(m_style.candidate_back_color) || COLORNOTTRANSPARENT(m_style.candidate_border_color) - ) // if transparent not to draw - { - for (auto i = 0; i < m_candidateCount && i < MAX_CANDIDATES_COUNT; ++i) { - if (i == m_ctx.cinfo.highlighted) continue; - rect = m_layout->GetCandidateRect((int)i); - IsToRoundStruct rd = m_layout->GetRoundInfo(i); - if(m_istorepos) { - rect.OffsetRect(0, m_offsetys[i]); - ReconfigRoundInfo(rd, i, m_candidateCount); - } - rect.InflateRect(m_style.hilite_padding_x, m_style.hilite_padding_y); - _HighlightText(dc, rect, m_style.candidate_back_color, 0x00000000, m_style.round_corner, bkType, rd, m_style.candidate_border_color); - drawn = true; - } - } - // draw highlighted back ground and shadow - { - rect = m_layout->GetHighlightRect(); - IsToRoundStruct rd = m_layout->GetRoundInfo(m_ctx.cinfo.highlighted); - if(m_istorepos) { - rect.OffsetRect(0, m_offsetys[m_ctx.cinfo.highlighted]); - ReconfigRoundInfo(rd, m_ctx.cinfo.highlighted, m_candidateCount); - } - rect.InflateRect(m_style.hilite_padding_x, m_style.hilite_padding_y); - _HighlightText(dc, rect, m_style.hilited_candidate_back_color, m_style.hilited_candidate_shadow_color, m_style.round_corner, bkType, rd, m_style.hilited_candidate_border_color); - if (m_style.mark_text.empty() && COLORNOTTRANSPARENT(m_style.hilited_mark_color)) - { - int height = min(rect.Height() - m_style.hilite_padding_y * 2, rect.Height() - m_style.round_corner * 2); - int width = min(rect.Width() - m_style.hilite_padding_x * 2, rect.Width() - m_style.round_corner * 2); - Gdiplus::Graphics g_back(dc); - g_back.SetSmoothingMode(Gdiplus::SmoothingMode::SmoothingModeHighQuality); - Gdiplus::Color mark_color = GDPCOLOR_FROM_COLORREF(m_style.hilited_mark_color); - Gdiplus::SolidBrush mk_brush(mark_color); - if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) - { - int x = rect.left + (rect.Width() - width)/2; - CRect mkrc{ x, rect.top, x + width, rect.top + m_layout->MARK_HEIGHT }; - GraphicsRoundRectPath mk_path(mkrc, 2); - g_back.FillPath(&mk_brush, &mk_path); - } - else - { - int y = rect.top + (rect.Height() - height)/2; - CRect mkrc{ rect.left, y, rect.left + m_layout->MARK_WIDTH, y + height }; - GraphicsRoundRectPath mk_path(mkrc, 2); - g_back.FillPath(&mk_brush, &mk_path); - } - } - drawn = true; - } - } - // draw text with direct write - else - { - // begin draw candidate texts - int label_text_color, candidate_text_color, comment_text_color; - for (auto i = 0; i < m_candidateCount && i < MAX_CANDIDATES_COUNT; ++i) { - if (i == m_ctx.cinfo.highlighted) - { - label_text_color = m_style.hilited_label_text_color; - candidate_text_color = m_style.hilited_candidate_text_color; - comment_text_color = m_style.hilited_comment_text_color; - } - else - { - label_text_color = m_style.label_text_color; - candidate_text_color = m_style.candidate_text_color; - comment_text_color = m_style.comment_text_color; - } - // Draw label - std::wstring label = m_layout->GetLabelText(labels, (int)i, m_style.label_text_format.c_str()); - if (!label.empty()) { - rect = m_layout->GetCandidateLabelRect((int)i); - if(m_istorepos) rect.OffsetRect(0, m_offsetys[i]); - _TextOut(rect, label.c_str(), label.length(), label_text_color, labeltxtFormat.Get()); - } - // Draw text - std::wstring text = candidates.at(i).str; - if (!text.empty()) { - rect = m_layout->GetCandidateTextRect((int)i); - if(m_istorepos) rect.OffsetRect(0, m_offsetys[i]); - _TextOut(rect, text.c_str(), text.length(), candidate_text_color, txtFormat.Get()); - } - // Draw comment - std::wstring comment = comments.at(i).str; - if (!comment.empty() && COLORNOTTRANSPARENT(comment_text_color)) { - rect = m_layout->GetCandidateCommentRect((int)i); - if(m_istorepos) rect.OffsetRect(0, m_offsetys[i]); - _TextOut(rect, comment.c_str(), comment.length(), comment_text_color, commenttxtFormat.Get()); - } - drawn = true; - } - // draw highlight mark - { - if (!m_style.mark_text.empty() && COLORNOTTRANSPARENT(m_style.hilited_mark_color)) - { - CRect rc = m_layout->GetHighlightRect(); - if(m_istorepos) rc.OffsetRect(0, m_offsetys[m_ctx.cinfo.highlighted]); - rc.InflateRect(m_style.hilite_padding_x, m_style.hilite_padding_y); - int vgap = m_layout->MARK_HEIGHT ? (rc.Height() - m_layout->MARK_HEIGHT) / 2 : 0; - int hgap = m_layout->MARK_WIDTH ? (rc.Width() - m_layout->MARK_WIDTH) / 2 : 0; - CRect hlRc; - if(m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) - hlRc = CRect(rc.left + hgap, - rc.top + m_style.hilite_padding_y, - rc.left + hgap + m_layout->MARK_WIDTH, - rc.top + m_style.hilite_padding_y + m_layout->MARK_HEIGHT); - else - hlRc = CRect(rc.left + m_style.hilite_padding_x, - rc.top + vgap, - rc.left + m_style.hilite_padding_x + m_layout->MARK_WIDTH, - rc.bottom - vgap); - _TextOut(hlRc, m_style.mark_text.c_str(), m_style.mark_text.length(), m_style.hilited_mark_color, pDWR->pTextFormat.Get()); - } - } - } - return drawn; +bool WeaselPanel::_DrawCandidates(CDCHandle& dc, bool back) { + bool drawn = false; + const std::vector& candidates(m_ctx.cinfo.candies); + const std::vector& comments(m_ctx.cinfo.comments); + const std::vector& labels(m_ctx.cinfo.labels); + // prevent all text format nullptr + if (pDWR->pTextFormat.Get() == nullptr && + pDWR->pLabelTextFormat.Get() == nullptr && + pDWR->pCommentTextFormat.Get() == nullptr) { + _InitFontRes(true); + } + ComPtr txtFormat = pDWR->pTextFormat; + ComPtr labeltxtFormat = pDWR->pLabelTextFormat; + ComPtr commenttxtFormat = pDWR->pCommentTextFormat; + BackType bkType = BackType::CAND; + + CRect rect; + // draw back color and shadow color, with gdi+ + if (back) { + // if candidate_shadow_color not transparent, draw candidate shadow first + if (COLORNOTTRANSPARENT(m_style.candidate_shadow_color)) { + for (auto i = 0; i < m_candidateCount && i < MAX_CANDIDATES_COUNT; ++i) { + if (i == m_ctx.cinfo.highlighted) + continue; // draw non hilited candidates only + rect = m_layout->GetCandidateRect((int)i); + IsToRoundStruct rd = m_layout->GetRoundInfo(i); + if (m_istorepos) { + rect.OffsetRect(0, m_offsetys[i]); + ReconfigRoundInfo(rd, i, m_candidateCount); + } + rect.InflateRect(m_style.hilite_padding_x, m_style.hilite_padding_y); + _HighlightText(dc, rect, 0x00000000, m_style.candidate_shadow_color, + m_style.round_corner, bkType, rd); + drawn = true; + } + } + // draw non highlighted candidates, without shadow + if (COLORNOTTRANSPARENT(m_style.candidate_back_color) || + COLORNOTTRANSPARENT( + m_style.candidate_border_color)) // if transparent not to draw + { + for (auto i = 0; i < m_candidateCount && i < MAX_CANDIDATES_COUNT; ++i) { + if (i == m_ctx.cinfo.highlighted) + continue; + rect = m_layout->GetCandidateRect((int)i); + IsToRoundStruct rd = m_layout->GetRoundInfo(i); + if (m_istorepos) { + rect.OffsetRect(0, m_offsetys[i]); + ReconfigRoundInfo(rd, i, m_candidateCount); + } + rect.InflateRect(m_style.hilite_padding_x, m_style.hilite_padding_y); + _HighlightText(dc, rect, m_style.candidate_back_color, 0x00000000, + m_style.round_corner, bkType, rd, + m_style.candidate_border_color); + drawn = true; + } + } + // draw highlighted back ground and shadow + { + rect = m_layout->GetHighlightRect(); + IsToRoundStruct rd = m_layout->GetRoundInfo(m_ctx.cinfo.highlighted); + if (m_istorepos) { + rect.OffsetRect(0, m_offsetys[m_ctx.cinfo.highlighted]); + ReconfigRoundInfo(rd, m_ctx.cinfo.highlighted, m_candidateCount); + } + rect.InflateRect(m_style.hilite_padding_x, m_style.hilite_padding_y); + _HighlightText(dc, rect, m_style.hilited_candidate_back_color, + m_style.hilited_candidate_shadow_color, + m_style.round_corner, bkType, rd, + m_style.hilited_candidate_border_color); + if (m_style.mark_text.empty() && + COLORNOTTRANSPARENT(m_style.hilited_mark_color)) { + int height = min(rect.Height() - m_style.hilite_padding_y * 2, + rect.Height() - m_style.round_corner * 2); + int width = min(rect.Width() - m_style.hilite_padding_x * 2, + rect.Width() - m_style.round_corner * 2); + Gdiplus::Graphics g_back(dc); + g_back.SetSmoothingMode( + Gdiplus::SmoothingMode::SmoothingModeHighQuality); + Gdiplus::Color mark_color = + GDPCOLOR_FROM_COLORREF(m_style.hilited_mark_color); + Gdiplus::SolidBrush mk_brush(mark_color); + if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) { + int x = rect.left + (rect.Width() - width) / 2; + CRect mkrc{x, rect.top, x + width, rect.top + m_layout->MARK_HEIGHT}; + GraphicsRoundRectPath mk_path(mkrc, 2); + g_back.FillPath(&mk_brush, &mk_path); + } else { + int y = rect.top + (rect.Height() - height) / 2; + CRect mkrc{rect.left, y, rect.left + m_layout->MARK_WIDTH, + y + height}; + GraphicsRoundRectPath mk_path(mkrc, 2); + g_back.FillPath(&mk_brush, &mk_path); + } + } + drawn = true; + } + } + // draw text with direct write + else { + // begin draw candidate texts + int label_text_color, candidate_text_color, comment_text_color; + for (auto i = 0; i < m_candidateCount && i < MAX_CANDIDATES_COUNT; ++i) { + if (i == m_ctx.cinfo.highlighted) { + label_text_color = m_style.hilited_label_text_color; + candidate_text_color = m_style.hilited_candidate_text_color; + comment_text_color = m_style.hilited_comment_text_color; + } else { + label_text_color = m_style.label_text_color; + candidate_text_color = m_style.candidate_text_color; + comment_text_color = m_style.comment_text_color; + } + // Draw label + std::wstring label = m_layout->GetLabelText( + labels, (int)i, m_style.label_text_format.c_str()); + if (!label.empty()) { + rect = m_layout->GetCandidateLabelRect((int)i); + if (m_istorepos) + rect.OffsetRect(0, m_offsetys[i]); + _TextOut(rect, label.c_str(), label.length(), label_text_color, + labeltxtFormat.Get()); + } + // Draw text + std::wstring text = candidates.at(i).str; + if (!text.empty()) { + rect = m_layout->GetCandidateTextRect((int)i); + if (m_istorepos) + rect.OffsetRect(0, m_offsetys[i]); + _TextOut(rect, text.c_str(), text.length(), candidate_text_color, + txtFormat.Get()); + } + // Draw comment + std::wstring comment = comments.at(i).str; + if (!comment.empty() && COLORNOTTRANSPARENT(comment_text_color)) { + rect = m_layout->GetCandidateCommentRect((int)i); + if (m_istorepos) + rect.OffsetRect(0, m_offsetys[i]); + _TextOut(rect, comment.c_str(), comment.length(), comment_text_color, + commenttxtFormat.Get()); + } + drawn = true; + } + // draw highlight mark + { + if (!m_style.mark_text.empty() && + COLORNOTTRANSPARENT(m_style.hilited_mark_color)) { + CRect rc = m_layout->GetHighlightRect(); + if (m_istorepos) + rc.OffsetRect(0, m_offsetys[m_ctx.cinfo.highlighted]); + rc.InflateRect(m_style.hilite_padding_x, m_style.hilite_padding_y); + int vgap = m_layout->MARK_HEIGHT + ? (rc.Height() - m_layout->MARK_HEIGHT) / 2 + : 0; + int hgap = + m_layout->MARK_WIDTH ? (rc.Width() - m_layout->MARK_WIDTH) / 2 : 0; + CRect hlRc; + if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) + hlRc = + CRect(rc.left + hgap, rc.top + m_style.hilite_padding_y, + rc.left + hgap + m_layout->MARK_WIDTH, + rc.top + m_style.hilite_padding_y + m_layout->MARK_HEIGHT); + else + hlRc = + CRect(rc.left + m_style.hilite_padding_x, rc.top + vgap, + rc.left + m_style.hilite_padding_x + m_layout->MARK_WIDTH, + rc.bottom - vgap); + _TextOut(hlRc, m_style.mark_text.c_str(), m_style.mark_text.length(), + m_style.hilited_mark_color, pDWR->pTextFormat.Get()); + } + } + } + return drawn; } -//draw client area -void WeaselPanel::DoPaint(CDCHandle dc) -{ - // turn off WS_EX_TRANSPARENT, for better resp performance - ModifyStyleEx(WS_EX_TRANSPARENT, WS_EX_LAYERED); - GetClientRect(&rcw); - // prepare memDC - CDCHandle hdc = ::GetDC(m_hWnd); - CDCHandle memDC = ::CreateCompatibleDC(hdc); - HBITMAP memBitmap = ::CreateCompatibleBitmap(hdc, rcw.Width(), rcw.Height()); - ::SelectObject(memDC, memBitmap); - ReleaseDC(hdc); - bool drawn = false; - if(!hide_candidates){ - CRect auxrc = m_layout->GetAuxiliaryRect(); - CRect preeditrc = m_layout->GetPreeditRect(); - if(m_istorepos) - { - CRect* rects = new CRect[m_candidateCount]; - int* btmys = new int[m_candidateCount]; - for (auto i = 0; i < m_candidateCount && i < MAX_CANDIDATES_COUNT; ++i) { - rects[i] = m_layout->GetCandidateRect(i); - btmys[i] = rects[i].bottom; - } - if (m_candidateCount) { - if (!m_layout->IsInlinePreedit() && !m_ctx.preedit.str.empty()) - m_offsety_preedit = rects[m_candidateCount - 1].bottom - preeditrc.bottom; - if (!m_ctx.aux.str.empty()) - m_offsety_aux = rects[m_candidateCount - 1].bottom - auxrc.bottom; - } - else { - m_offsety_preedit = 0; - m_offsety_aux = 0; - } - int base_gap = 0; - if (!m_ctx.aux.str.empty()) - base_gap = auxrc.Height() + m_style.spacing; - else if (!m_layout->IsInlinePreedit() && !m_ctx.preedit.str.empty()) - base_gap = preeditrc.Height() + m_style.spacing; - - for (auto i = 0; i < m_candidateCount && i < MAX_CANDIDATES_COUNT; ++i) { - if (i == 0) - m_offsetys[i] = btmys[m_candidateCount - i - 1] - base_gap - rects[i].bottom; - else - m_offsetys[i] = (rects[i - 1].top + m_offsetys[i - 1] - m_style.candidate_spacing) - rects[i].bottom; - } - delete[] rects; - delete[] btmys; - } - // background and candidates back, hilite back drawing start - if ((!m_ctx.empty() && !m_style.inline_preedit) || (m_style.inline_preedit && (m_candidateCount || !m_ctx.aux.empty() ))) { - CRect backrc = m_layout->GetContentRect(); - //if (!m_style.border) backrc.InflateRect(1,1); - _HighlightText(memDC, backrc, m_style.back_color, m_style.shadow_color, m_style.round_corner_ex, BackType::BACKGROUND, IsToRoundStruct(), m_style.border_color); - } - if (!m_ctx.aux.str.empty()) - { - if(m_istorepos) - auxrc.OffsetRect(0, m_offsety_aux); - drawn |= _DrawPreeditBack(m_ctx.aux, memDC, auxrc); - } - if (!m_layout->IsInlinePreedit() && !m_ctx.preedit.str.empty()) - { - if(m_istorepos) - preeditrc.OffsetRect(0, m_offsety_preedit); - drawn |= _DrawPreeditBack(m_ctx.preedit, memDC, preeditrc); - } - if (m_candidateCount) - drawn |= _DrawCandidates(memDC, true); - // background and candidates back, hilite back drawing end - - // begin texts drawing, if pRenderTarget failed, force to reinit directwrite resources - if (FAILED(pDWR->pRenderTarget->BindDC(memDC, &rcw))) { - _InitFontRes(true); - pDWR->pRenderTarget->BindDC(memDC, &rcw); - } - pDWR->pRenderTarget->BeginDraw(); - // draw auxiliary string - if (!m_ctx.aux.str.empty()) - drawn |= _DrawPreedit(m_ctx.aux, memDC, auxrc); - // draw preedit string - if (!m_layout->IsInlinePreedit() && !m_ctx.preedit.str.empty()) - drawn |= _DrawPreedit(m_ctx.preedit, memDC, preeditrc); - // draw candidates string - if(m_candidateCount) - drawn |= _DrawCandidates(memDC); - pDWR->pRenderTarget->EndDraw(); - // end texts drawing - - // status icon (I guess Metro IME stole my idea :) - if (m_layout->ShouldDisplayStatusIcon()) { - // decide if custom schema zhung icon to show - LoadIconNecessary(m_current_zhung_icon, m_style.current_zhung_icon, m_iconEnabled, IDI_ZH); - LoadIconNecessary(m_current_ascii_icon, m_style.current_ascii_icon, m_iconAlpha, IDI_EN); - LoadIconNecessary(m_current_half_icon, m_style.current_half_icon, m_iconHalf, IDI_HALF_SHAPE); - LoadIconNecessary(m_current_full_icon, m_style.current_full_icon, m_iconFull, IDI_FULL_SHAPE); - CRect iconRect(m_layout->GetStatusIconRect()); - if (m_istorepos && !m_ctx.aux.str.empty()) - iconRect.OffsetRect(0, m_offsety_aux); - else if (m_istorepos && !m_layout->IsInlinePreedit() && !m_ctx.preedit.str.empty()) - iconRect.OffsetRect(0, m_offsety_preedit); - - CIcon& icon(m_status.disabled ? m_iconDisabled : m_status.ascii_mode ? m_iconAlpha : - (m_status.type == SCHEMA ? m_iconEnabled : (m_status.full_shape ? m_iconFull : m_iconHalf)) ); - memDC.DrawIconEx(iconRect.left, iconRect.top, icon, 0, 0); - drawn = true; - } - /* Nothing drawn, hide candidate window */ - if (!drawn) - ShowWindow(SW_HIDE); - } - _LayerUpdate(rcw, memDC); - - // clean objs - ::DeleteDC(memDC); - ::DeleteObject(memBitmap); +// draw client area +void WeaselPanel::DoPaint(CDCHandle dc) { + // turn off WS_EX_TRANSPARENT, for better resp performance + ModifyStyleEx(WS_EX_TRANSPARENT, WS_EX_LAYERED); + GetClientRect(&rcw); + // prepare memDC + CDCHandle hdc = ::GetDC(m_hWnd); + CDCHandle memDC = ::CreateCompatibleDC(hdc); + HBITMAP memBitmap = ::CreateCompatibleBitmap(hdc, rcw.Width(), rcw.Height()); + ::SelectObject(memDC, memBitmap); + ReleaseDC(hdc); + bool drawn = false; + if (!hide_candidates) { + CRect auxrc = m_layout->GetAuxiliaryRect(); + CRect preeditrc = m_layout->GetPreeditRect(); + if (m_istorepos) { + CRect* rects = new CRect[m_candidateCount]; + int* btmys = new int[m_candidateCount]; + for (auto i = 0; i < m_candidateCount && i < MAX_CANDIDATES_COUNT; ++i) { + rects[i] = m_layout->GetCandidateRect(i); + btmys[i] = rects[i].bottom; + } + if (m_candidateCount) { + if (!m_layout->IsInlinePreedit() && !m_ctx.preedit.str.empty()) + m_offsety_preedit = + rects[m_candidateCount - 1].bottom - preeditrc.bottom; + if (!m_ctx.aux.str.empty()) + m_offsety_aux = rects[m_candidateCount - 1].bottom - auxrc.bottom; + } else { + m_offsety_preedit = 0; + m_offsety_aux = 0; + } + int base_gap = 0; + if (!m_ctx.aux.str.empty()) + base_gap = auxrc.Height() + m_style.spacing; + else if (!m_layout->IsInlinePreedit() && !m_ctx.preedit.str.empty()) + base_gap = preeditrc.Height() + m_style.spacing; + + for (auto i = 0; i < m_candidateCount && i < MAX_CANDIDATES_COUNT; ++i) { + if (i == 0) + m_offsetys[i] = + btmys[m_candidateCount - i - 1] - base_gap - rects[i].bottom; + else + m_offsetys[i] = (rects[i - 1].top + m_offsetys[i - 1] - + m_style.candidate_spacing) - + rects[i].bottom; + } + delete[] rects; + delete[] btmys; + } + // background and candidates back, hilite back drawing start + if ((!m_ctx.empty() && !m_style.inline_preedit) || + (m_style.inline_preedit && (m_candidateCount || !m_ctx.aux.empty()))) { + CRect backrc = m_layout->GetContentRect(); + // if (!m_style.border) backrc.InflateRect(1,1); + _HighlightText(memDC, backrc, m_style.back_color, m_style.shadow_color, + m_style.round_corner_ex, BackType::BACKGROUND, + IsToRoundStruct(), m_style.border_color); + } + if (!m_ctx.aux.str.empty()) { + if (m_istorepos) + auxrc.OffsetRect(0, m_offsety_aux); + drawn |= _DrawPreeditBack(m_ctx.aux, memDC, auxrc); + } + if (!m_layout->IsInlinePreedit() && !m_ctx.preedit.str.empty()) { + if (m_istorepos) + preeditrc.OffsetRect(0, m_offsety_preedit); + drawn |= _DrawPreeditBack(m_ctx.preedit, memDC, preeditrc); + } + if (m_candidateCount) + drawn |= _DrawCandidates(memDC, true); + // background and candidates back, hilite back drawing end + + // begin texts drawing, if pRenderTarget failed, force to reinit + // directwrite resources + if (FAILED(pDWR->pRenderTarget->BindDC(memDC, &rcw))) { + _InitFontRes(true); + pDWR->pRenderTarget->BindDC(memDC, &rcw); + } + pDWR->pRenderTarget->BeginDraw(); + // draw auxiliary string + if (!m_ctx.aux.str.empty()) + drawn |= _DrawPreedit(m_ctx.aux, memDC, auxrc); + // draw preedit string + if (!m_layout->IsInlinePreedit() && !m_ctx.preedit.str.empty()) + drawn |= _DrawPreedit(m_ctx.preedit, memDC, preeditrc); + // draw candidates string + if (m_candidateCount) + drawn |= _DrawCandidates(memDC); + pDWR->pRenderTarget->EndDraw(); + // end texts drawing + + // status icon (I guess Metro IME stole my idea :) + if (m_layout->ShouldDisplayStatusIcon()) { + // decide if custom schema zhung icon to show + LoadIconNecessary(m_current_zhung_icon, m_style.current_zhung_icon, + m_iconEnabled, IDI_ZH); + LoadIconNecessary(m_current_ascii_icon, m_style.current_ascii_icon, + m_iconAlpha, IDI_EN); + LoadIconNecessary(m_current_half_icon, m_style.current_half_icon, + m_iconHalf, IDI_HALF_SHAPE); + LoadIconNecessary(m_current_full_icon, m_style.current_full_icon, + m_iconFull, IDI_FULL_SHAPE); + CRect iconRect(m_layout->GetStatusIconRect()); + if (m_istorepos && !m_ctx.aux.str.empty()) + iconRect.OffsetRect(0, m_offsety_aux); + else if (m_istorepos && !m_layout->IsInlinePreedit() && + !m_ctx.preedit.str.empty()) + iconRect.OffsetRect(0, m_offsety_preedit); + + CIcon& icon( + m_status.disabled ? m_iconDisabled + : m_status.ascii_mode + ? m_iconAlpha + : (m_status.type == SCHEMA + ? m_iconEnabled + : (m_status.full_shape ? m_iconFull : m_iconHalf))); + memDC.DrawIconEx(iconRect.left, iconRect.top, icon, 0, 0); + drawn = true; + } + /* Nothing drawn, hide candidate window */ + if (!drawn) + ShowWindow(SW_HIDE); + } + _LayerUpdate(rcw, memDC); + + // clean objs + ::DeleteDC(memDC); + ::DeleteObject(memBitmap); } -void WeaselPanel::_LayerUpdate(const CRect& rc, CDCHandle dc) -{ - HDC ScreenDC = ::GetDC(NULL); - CRect rect; - GetWindowRect(&rect); - POINT WindowPosAtScreen = { rect.left, rect.top }; - POINT PointOriginal = { 0, 0 }; - SIZE sz = { rc.Width(), rc.Height() }; - - BLENDFUNCTION bf = {AC_SRC_OVER, 0, 0XFF, AC_SRC_ALPHA}; - UpdateLayeredWindow(m_hWnd, ScreenDC, &WindowPosAtScreen, &sz, dc, &PointOriginal, RGB(0,0,0), &bf, ULW_ALPHA); - ReleaseDC(ScreenDC); +void WeaselPanel::_LayerUpdate(const CRect& rc, CDCHandle dc) { + HDC ScreenDC = ::GetDC(NULL); + CRect rect; + GetWindowRect(&rect); + POINT WindowPosAtScreen = {rect.left, rect.top}; + POINT PointOriginal = {0, 0}; + SIZE sz = {rc.Width(), rc.Height()}; + + BLENDFUNCTION bf = {AC_SRC_OVER, 0, 0XFF, AC_SRC_ALPHA}; + UpdateLayeredWindow(m_hWnd, ScreenDC, &WindowPosAtScreen, &sz, dc, + &PointOriginal, RGB(0, 0, 0), &bf, ULW_ALPHA); + ReleaseDC(ScreenDC); } -LRESULT WeaselPanel::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) -{ - GetWindowRect(&m_inputPos); - Refresh(); - return TRUE; +LRESULT WeaselPanel::OnCreate(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled) { + GetWindowRect(&m_inputPos); + Refresh(); + return TRUE; } -LRESULT WeaselPanel::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) -{ - delete m_layout; - m_layout = NULL; - return 0; +LRESULT WeaselPanel::OnDestroy(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled) { + delete m_layout; + m_layout = NULL; + return 0; } -LRESULT WeaselPanel::OnDpiChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) -{ - Refresh(); - return LRESULT(); +LRESULT WeaselPanel::OnDpiChanged(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled) { + Refresh(); + return LRESULT(); } -void WeaselPanel::MoveTo(RECT const& rc) -{ - if(!m_layout) return; // avoid handling nullptr in _RepositionWindow - // if ascii_tip_follow_cursor set, move tip icon to mouse cursor - if(m_style.ascii_tip_follow_cursor && m_ctx.empty() - && (!m_status.composing) && m_layout->ShouldDisplayStatusIcon()) { - // ascii icon follow cursor - POINT p; - ::GetCursorPos(&p); - RECT irc{p.x-STATUS_ICON_SIZE, p.y-STATUS_ICON_SIZE, p.x, p.y}; - m_inputPos = irc; - _RepositionWindow(true); - RedrawWindow(); - } else if (!(rc.left == m_inputPos.left && rc.bottom != m_inputPos.bottom - && abs(rc.bottom - m_inputPos.bottom) < 6) || m_layout->ShouldDisplayStatusIcon()) { - // in some apps like word 2021, with inline_preedit set, - // bottom of rc would flicker 1 px or 2, make the candidate flickering - m_inputPos = rc; - m_inputPos.OffsetRect(0, 6); - // buffer current m_istorepos status - bool m_istorepos_buf = m_istorepos; - // with parameter to avoid vertical flicker - _RepositionWindow(true); - // m_istorepos status changed by _RepositionWindow, or tips to show, - // redrawing is required - if(m_istorepos != m_istorepos_buf || !m_ctx.aux.empty() || m_layout->ShouldDisplayStatusIcon()) - RedrawWindow(); - } +void WeaselPanel::MoveTo(RECT const& rc) { + if (!m_layout) + return; // avoid handling nullptr in _RepositionWindow + // if ascii_tip_follow_cursor set, move tip icon to mouse cursor + if (m_style.ascii_tip_follow_cursor && m_ctx.empty() && + (!m_status.composing) && m_layout->ShouldDisplayStatusIcon()) { + // ascii icon follow cursor + POINT p; + ::GetCursorPos(&p); + RECT irc{p.x - STATUS_ICON_SIZE, p.y - STATUS_ICON_SIZE, p.x, p.y}; + m_inputPos = irc; + _RepositionWindow(true); + RedrawWindow(); + } else if (!(rc.left == m_inputPos.left && rc.bottom != m_inputPos.bottom && + abs(rc.bottom - m_inputPos.bottom) < 6) || + m_layout->ShouldDisplayStatusIcon()) { + // in some apps like word 2021, with inline_preedit set, + // bottom of rc would flicker 1 px or 2, make the candidate flickering + m_inputPos = rc; + m_inputPos.OffsetRect(0, 6); + // buffer current m_istorepos status + bool m_istorepos_buf = m_istorepos; + // with parameter to avoid vertical flicker + _RepositionWindow(true); + // m_istorepos status changed by _RepositionWindow, or tips to show, + // redrawing is required + if (m_istorepos != m_istorepos_buf || !m_ctx.aux.empty() || + m_layout->ShouldDisplayStatusIcon()) + RedrawWindow(); + } } -void WeaselPanel::_RepositionWindow(const bool& adj) -{ - RECT rcWorkArea; - memset(&rcWorkArea, 0, sizeof(rcWorkArea)); - HMONITOR hMonitor = MonitorFromRect(m_inputPos, MONITOR_DEFAULTTONEAREST); - if (hMonitor) { - MONITORINFO info; - info.cbSize = sizeof(MONITORINFO); - if (GetMonitorInfo(hMonitor, &info)) { - rcWorkArea = info.rcWork; - } - } - RECT rcWindow; - GetWindowRect(&rcWindow); - int width = (rcWindow.right - rcWindow.left); - int height = (rcWindow.bottom - rcWindow.top); - // keep panel visible - rcWorkArea.right -= width; - rcWorkArea.bottom -= height; - int x = m_inputPos.left; - int y = m_inputPos.bottom; - if(m_style.shadow_radius) - { - x -= (m_style.shadow_offset_x >= 0 || COLORTRANSPARENT(m_style.shadow_color)) ? m_layout->offsetX : (m_layout->offsetX / 2); - if (adj) - y -= (m_style.shadow_offset_y > 0 || COLORTRANSPARENT(m_style.shadow_color)) ? m_layout->offsetY : (m_layout->offsetY / 2); - } - // for vertical text layout, flow right to left, make window left side - if(m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT && !m_style.vertical_text_left_to_right) - { - x += m_layout->offsetX - width; - if (m_style.shadow_offset_x < 0) - x += m_layout->offsetX; - } - if(adj) m_istorepos = false; - if (x > rcWorkArea.right) x = rcWorkArea.right; // over workarea right - if (x < rcWorkArea.left) x = rcWorkArea.left; // over workarea left - // show panel above the input focus if we're around the bottom - if (y > rcWorkArea.bottom) { - y = m_inputPos.top - height - 6; // over workarea bottom - if(m_style.shadow_radius && m_style.shadow_offset_y > 0) - y -= m_style.shadow_offset_y; - m_istorepos = (m_style.vertical_auto_reverse && m_style.layout_type == UIStyle::LAYOUT_VERTICAL); - if(m_style.shadow_radius > 0) - y += (m_style.shadow_offset_y < 0 || COLORTRANSPARENT(m_style.shadow_color)) ? m_layout->offsetY : (m_layout->offsetY / 2); - } - if (y < rcWorkArea.top) y = rcWorkArea.top; // over workarea top - // memorize adjusted position (to avoid window bouncing on height change) - m_inputPos.bottom = y; - SetWindowPos(HWND_TOPMOST, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW); +void WeaselPanel::_RepositionWindow(const bool& adj) { + RECT rcWorkArea; + memset(&rcWorkArea, 0, sizeof(rcWorkArea)); + HMONITOR hMonitor = MonitorFromRect(m_inputPos, MONITOR_DEFAULTTONEAREST); + if (hMonitor) { + MONITORINFO info; + info.cbSize = sizeof(MONITORINFO); + if (GetMonitorInfo(hMonitor, &info)) { + rcWorkArea = info.rcWork; + } + } + RECT rcWindow; + GetWindowRect(&rcWindow); + int width = (rcWindow.right - rcWindow.left); + int height = (rcWindow.bottom - rcWindow.top); + // keep panel visible + rcWorkArea.right -= width; + rcWorkArea.bottom -= height; + int x = m_inputPos.left; + int y = m_inputPos.bottom; + if (m_style.shadow_radius) { + x -= + (m_style.shadow_offset_x >= 0 || COLORTRANSPARENT(m_style.shadow_color)) + ? m_layout->offsetX + : (m_layout->offsetX / 2); + if (adj) + y -= (m_style.shadow_offset_y > 0 || + COLORTRANSPARENT(m_style.shadow_color)) + ? m_layout->offsetY + : (m_layout->offsetY / 2); + } + // for vertical text layout, flow right to left, make window left side + if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT && + !m_style.vertical_text_left_to_right) { + x += m_layout->offsetX - width; + if (m_style.shadow_offset_x < 0) + x += m_layout->offsetX; + } + if (adj) + m_istorepos = false; + if (x > rcWorkArea.right) + x = rcWorkArea.right; // over workarea right + if (x < rcWorkArea.left) + x = rcWorkArea.left; // over workarea left + // show panel above the input focus if we're around the bottom + if (y > rcWorkArea.bottom) { + y = m_inputPos.top - height - 6; // over workarea bottom + if (m_style.shadow_radius && m_style.shadow_offset_y > 0) + y -= m_style.shadow_offset_y; + m_istorepos = (m_style.vertical_auto_reverse && + m_style.layout_type == UIStyle::LAYOUT_VERTICAL); + if (m_style.shadow_radius > 0) + y += (m_style.shadow_offset_y < 0 || + COLORTRANSPARENT(m_style.shadow_color)) + ? m_layout->offsetY + : (m_layout->offsetY / 2); + } + if (y < rcWorkArea.top) + y = rcWorkArea.top; // over workarea top + // memorize adjusted position (to avoid window bouncing on height change) + m_inputPos.bottom = y; + SetWindowPos(HWND_TOPMOST, x, y, 0, 0, + SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW); } -void WeaselPanel::_TextOut(const CRect& rc, const std::wstring& psz, - const size_t& cch, const int& inColor, - IDWriteTextFormat1* const pTextFormat) -{ - if (pTextFormat == NULL) return; - float r = (float)(GetRValue(inColor))/255.0f; - float g = (float)(GetGValue(inColor))/255.0f; - float b = (float)(GetBValue(inColor))/255.0f; - float alpha = (float)((inColor >> 24) & 255) / 255.0f; - HRESULT hr = S_OK; - if (pDWR->pBrush == NULL) - { - hr = pDWR->CreateBrush(D2D1::ColorF(r, g, b, alpha)); - if (FAILED(hr)) MessageBox(L"Failed CreateBrush", L"Info"); - } - else - pDWR->SetBrushColor(D2D1::ColorF(r, g, b, alpha)); - - if (NULL != pDWR->pBrush && NULL != pTextFormat) { - pDWR->CreateTextLayout( psz.c_str(), (int)cch, pTextFormat, (float)rc.Width(), (float)rc.Height()); - if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) { - DWRITE_FLOW_DIRECTION flow = m_style.vertical_text_left_to_right ? DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT : DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT; - pDWR->SetLayoutReadingDirection(DWRITE_READING_DIRECTION_TOP_TO_BOTTOM); - pDWR->SetLayoutFlowDirection(flow); - } - - // offsetx for font glyph over left - float offsetx = (float)rc.left; - float offsety = (float)rc.top; - // prepare for space when first character overhanged - DWRITE_OVERHANG_METRICS omt; - pDWR->GetLayoutOverhangMetrics(&omt); - if (m_style.layout_type != UIStyle::LAYOUT_VERTICAL_TEXT && omt.left > 0) - offsetx += omt.left; - if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT && omt.top > 0) - offsety += omt.top; - - if (pDWR->pTextLayout != NULL) { - pDWR->DrawTextLayoutAt({ offsetx, offsety }); +void WeaselPanel::_TextOut(const CRect& rc, + const std::wstring& psz, + const size_t& cch, + const int& inColor, + IDWriteTextFormat1* const pTextFormat) { + if (pTextFormat == NULL) + return; + float r = (float)(GetRValue(inColor)) / 255.0f; + float g = (float)(GetGValue(inColor)) / 255.0f; + float b = (float)(GetBValue(inColor)) / 255.0f; + float alpha = (float)((inColor >> 24) & 255) / 255.0f; + HRESULT hr = S_OK; + if (pDWR->pBrush == NULL) { + hr = pDWR->CreateBrush(D2D1::ColorF(r, g, b, alpha)); + if (FAILED(hr)) + MessageBox(L"Failed CreateBrush", L"Info"); + } else + pDWR->SetBrushColor(D2D1::ColorF(r, g, b, alpha)); + + if (NULL != pDWR->pBrush && NULL != pTextFormat) { + pDWR->CreateTextLayout(psz.c_str(), (int)cch, pTextFormat, + (float)rc.Width(), (float)rc.Height()); + if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) { + DWRITE_FLOW_DIRECTION flow = m_style.vertical_text_left_to_right + ? DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT + : DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT; + pDWR->SetLayoutReadingDirection(DWRITE_READING_DIRECTION_TOP_TO_BOTTOM); + pDWR->SetLayoutFlowDirection(flow); + } + + // offsetx for font glyph over left + float offsetx = (float)rc.left; + float offsety = (float)rc.top; + // prepare for space when first character overhanged + DWRITE_OVERHANG_METRICS omt; + pDWR->GetLayoutOverhangMetrics(&omt); + if (m_style.layout_type != UIStyle::LAYOUT_VERTICAL_TEXT && omt.left > 0) + offsetx += omt.left; + if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT && omt.top > 0) + offsety += omt.top; + + if (pDWR->pTextLayout != NULL) { + pDWR->DrawTextLayoutAt({offsetx, offsety}); #if 0 D2D1_RECT_F rectf = D2D1::RectF(offsetx, offsety, offsetx + rc.Width(), offsety + rc.Height()); pDWR->DrawRect(&rectf); #endif - } - pDWR->ResetLayout(); - } + } + pDWR->ResetLayout(); + } } - diff --git a/WeaselUI/WeaselPanel.h b/WeaselUI/WeaselPanel.h index dbfc7f631..4fc75f543 100644 --- a/WeaselUI/WeaselPanel.h +++ b/WeaselUI/WeaselPanel.h @@ -10,103 +10,119 @@ using namespace weasel; -typedef CWinTraits CWeaselPanelTraits; - -enum class BackType -{ - TEXT = 0, - CAND = 1, - BACKGROUND = 2 // background +typedef CWinTraits + CWeaselPanelTraits; + +enum class BackType { + TEXT = 0, + CAND = 1, + BACKGROUND = 2 // background }; -class WeaselPanel : - public CWindowImpl, - CDoubleBufferImpl -{ -public: - BEGIN_MSG_MAP(WeaselPanel) - MESSAGE_HANDLER(WM_CREATE, OnCreate) - MESSAGE_HANDLER(WM_DESTROY, OnDestroy) - MESSAGE_HANDLER(WM_DPICHANGED, OnDpiChanged) - MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate) - MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLeftClicked) - MESSAGE_HANDLER(WM_MOUSEWHEEL, OnMouseWheel) - MESSAGE_HANDLER(WM_MOUSEHOVER, OnMouseHover) - MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) - MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave) - CHAIN_MSG_MAP(CDoubleBufferImpl) - END_MSG_MAP() - - LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); - LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); - LRESULT OnDpiChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); - LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); - LRESULT OnLeftClicked(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); - LRESULT OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); - LRESULT OnMouseHover(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); - LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); - LRESULT OnMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); - - WeaselPanel(weasel::UI &ui); - ~WeaselPanel(); - - void MoveTo(RECT const& rc); - void Refresh(); - void DoPaint(CDCHandle dc); - bool GetIsReposition(){ return m_istorepos; } - -private: - void _InitFontRes(bool forced = false); - void _CaptureRect(CRect& rect); - bool m_mouse_entry = false; - void _CreateLayout(); - void _ResizeWindow(); - void _RepositionWindow(const bool& adj = false); - bool _DrawPreedit(const Text& text, CDCHandle dc, const CRect& rc); - bool _DrawPreeditBack(const Text& text, CDCHandle dc, const CRect& rc); - bool _DrawCandidates(CDCHandle &dc, bool back = false); - void _HighlightText(CDCHandle &dc, const CRect& rc, const COLORREF& color, - const COLORREF& shadowColor, const int& radius, - const BackType& type, const IsToRoundStruct& rd, - const COLORREF& bordercolor); - void _TextOut(const CRect& rc, const std::wstring& psz, const size_t& cch, - const int& inColor, IDWriteTextFormat1* const pTextFormat = NULL); - - void _LayerUpdate(const CRect& rc, CDCHandle dc); - - weasel::Layout *m_layout; - weasel::Context &m_ctx; - weasel::Context &m_octx; - weasel::Status &m_status; - weasel::UIStyle &m_style; - weasel::UIStyle &m_ostyle; - - CRect m_inputPos; - int m_offsetys[MAX_CANDIDATES_COUNT]; // offset y for candidates when vertical layout over bottom - int m_offsety_preedit; - int m_offsety_aux; - bool m_istorepos; - - CIcon m_iconDisabled; - CIcon m_iconEnabled; - CIcon m_iconAlpha; - CIcon m_iconFull; - CIcon m_iconHalf; - std::wstring m_current_zhung_icon; - std::wstring m_current_ascii_icon; - std::wstring m_current_half_icon; - std::wstring m_current_full_icon; - // for gdiplus drawings - Gdiplus::GdiplusStartupInput _m_gdiplusStartupInput; - ULONG_PTR _m_gdiplusToken; - - UINT dpi; - - CRect rcw; - BYTE m_candidateCount; - - bool hide_candidates; - // for multi font_face & font_point - PDWR pDWR; - std::function& _UICallback; +class WeaselPanel + : public CWindowImpl, + CDoubleBufferImpl { + public: + BEGIN_MSG_MAP(WeaselPanel) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + MESSAGE_HANDLER(WM_DPICHANGED, OnDpiChanged) + MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate) + MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLeftClicked) + MESSAGE_HANDLER(WM_MOUSEWHEEL, OnMouseWheel) + MESSAGE_HANDLER(WM_MOUSEHOVER, OnMouseHover) + MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) + MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave) + CHAIN_MSG_MAP(CDoubleBufferImpl) + END_MSG_MAP() + + LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnDpiChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnMouseActivate(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled); + LRESULT OnLeftClicked(UINT uMsg, + WPARAM wParam, + LPARAM lParam, + BOOL& bHandled); + LRESULT OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnMouseHover(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + + WeaselPanel(weasel::UI& ui); + ~WeaselPanel(); + + void MoveTo(RECT const& rc); + void Refresh(); + void DoPaint(CDCHandle dc); + bool GetIsReposition() { return m_istorepos; } + + private: + void _InitFontRes(bool forced = false); + void _CaptureRect(CRect& rect); + bool m_mouse_entry = false; + void _CreateLayout(); + void _ResizeWindow(); + void _RepositionWindow(const bool& adj = false); + bool _DrawPreedit(const Text& text, CDCHandle dc, const CRect& rc); + bool _DrawPreeditBack(const Text& text, CDCHandle dc, const CRect& rc); + bool _DrawCandidates(CDCHandle& dc, bool back = false); + void _HighlightText(CDCHandle& dc, + const CRect& rc, + const COLORREF& color, + const COLORREF& shadowColor, + const int& radius, + const BackType& type, + const IsToRoundStruct& rd, + const COLORREF& bordercolor); + void _TextOut(const CRect& rc, + const std::wstring& psz, + const size_t& cch, + const int& inColor, + IDWriteTextFormat1* const pTextFormat = NULL); + + void _LayerUpdate(const CRect& rc, CDCHandle dc); + + weasel::Layout* m_layout; + weasel::Context& m_ctx; + weasel::Context& m_octx; + weasel::Status& m_status; + weasel::UIStyle& m_style; + weasel::UIStyle& m_ostyle; + + CRect m_inputPos; + int m_offsetys[MAX_CANDIDATES_COUNT]; // offset y for candidates when + // vertical layout over bottom + int m_offsety_preedit; + int m_offsety_aux; + bool m_istorepos; + + CIcon m_iconDisabled; + CIcon m_iconEnabled; + CIcon m_iconAlpha; + CIcon m_iconFull; + CIcon m_iconHalf; + std::wstring m_current_zhung_icon; + std::wstring m_current_ascii_icon; + std::wstring m_current_half_icon; + std::wstring m_current_full_icon; + // for gdiplus drawings + Gdiplus::GdiplusStartupInput _m_gdiplusStartupInput; + ULONG_PTR _m_gdiplusToken; + + UINT dpi; + + CRect rcw; + BYTE m_candidateCount; + + bool hide_candidates; + // for multi font_face & font_point + PDWR pDWR; + std::function& + _UICallback; }; diff --git a/WeaselUI/WeaselUI.cpp b/WeaselUI/WeaselUI.cpp index d1045a423..909cf9c6c 100644 --- a/WeaselUI/WeaselUI.cpp +++ b/WeaselUI/WeaselUI.cpp @@ -5,193 +5,171 @@ using namespace weasel; class weasel::UIImpl { -public: - WeaselPanel panel; - - UIImpl(weasel::UI &ui) - : panel(ui), shown(false) {} - ~UIImpl() {} - void Refresh() { - if (!panel.IsWindow()) return; - if (timer) - { - Hide(); - KillTimer(panel.m_hWnd, AUTOHIDE_TIMER); - timer = 0; - } - panel.Refresh(); - } - void Show(); - void Hide(); - void ShowWithTimeout(size_t millisec); - bool IsShown() const { return shown; } - - static VOID CALLBACK OnTimer( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ UINT_PTR idEvent, - _In_ DWORD dwTime - ); - static const int AUTOHIDE_TIMER = 20121220; - static UINT_PTR timer; - bool shown; + public: + WeaselPanel panel; + + UIImpl(weasel::UI& ui) : panel(ui), shown(false) {} + ~UIImpl() {} + void Refresh() { + if (!panel.IsWindow()) + return; + if (timer) { + Hide(); + KillTimer(panel.m_hWnd, AUTOHIDE_TIMER); + timer = 0; + } + panel.Refresh(); + } + void Show(); + void Hide(); + void ShowWithTimeout(size_t millisec); + bool IsShown() const { return shown; } + + static VOID CALLBACK OnTimer(_In_ HWND hwnd, + _In_ UINT uMsg, + _In_ UINT_PTR idEvent, + _In_ DWORD dwTime); + static const int AUTOHIDE_TIMER = 20121220; + static UINT_PTR timer; + bool shown; }; UINT_PTR UIImpl::timer = 0; -void UIImpl::Show() -{ - if (!panel.IsWindow()) return; - panel.ShowWindow(SW_SHOWNA); - shown = true; - if (timer) - { - KillTimer(panel.m_hWnd, AUTOHIDE_TIMER); - timer = 0; - } +void UIImpl::Show() { + if (!panel.IsWindow()) + return; + panel.ShowWindow(SW_SHOWNA); + shown = true; + if (timer) { + KillTimer(panel.m_hWnd, AUTOHIDE_TIMER); + timer = 0; + } } -void UIImpl::Hide() -{ - if (!panel.IsWindow()) return; - panel.ShowWindow(SW_HIDE); - shown = false; - if (timer) - { - KillTimer(panel.m_hWnd, AUTOHIDE_TIMER); - timer = 0; - } +void UIImpl::Hide() { + if (!panel.IsWindow()) + return; + panel.ShowWindow(SW_HIDE); + shown = false; + if (timer) { + KillTimer(panel.m_hWnd, AUTOHIDE_TIMER); + timer = 0; + } } -void UIImpl::ShowWithTimeout(size_t millisec) -{ - if (!panel.IsWindow()) return; - DLOG(INFO) << "ShowWithTimeout: " << millisec; - panel.ShowWindow(SW_SHOWNA); - shown = true; - SetTimer(panel.m_hWnd, AUTOHIDE_TIMER, millisec, &UIImpl::OnTimer); - timer = UINT_PTR(this); +void UIImpl::ShowWithTimeout(size_t millisec) { + if (!panel.IsWindow()) + return; + DLOG(INFO) << "ShowWithTimeout: " << millisec; + panel.ShowWindow(SW_SHOWNA); + shown = true; + SetTimer(panel.m_hWnd, AUTOHIDE_TIMER, millisec, &UIImpl::OnTimer); + timer = UINT_PTR(this); } -VOID CALLBACK UIImpl::OnTimer( - _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ UINT_PTR idEvent, - _In_ DWORD dwTime -) -{ - DLOG(INFO) << "OnTimer:"; - KillTimer(hwnd, idEvent); - UIImpl* self = (UIImpl*)timer; - timer = 0; - if (self) - { - self->Hide(); - self->shown = false; - } +VOID CALLBACK UIImpl::OnTimer(_In_ HWND hwnd, + _In_ UINT uMsg, + _In_ UINT_PTR idEvent, + _In_ DWORD dwTime) { + DLOG(INFO) << "OnTimer:"; + KillTimer(hwnd, idEvent); + UIImpl* self = (UIImpl*)timer; + timer = 0; + if (self) { + self->Hide(); + self->shown = false; + } } -bool UI::Create(HWND parent) -{ - if (pimpl_) - { - pimpl_->panel.Create(parent, 0, 0, WS_POPUP, WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOACTIVATE | WS_EX_TRANSPARENT, 0U, 0); - return true; - } - - pimpl_ = new UIImpl(*this); - if (!pimpl_) - return false; - - pimpl_->panel.Create(parent, 0, 0, WS_POPUP, WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOACTIVATE | WS_EX_TRANSPARENT, 0U, 0); - return true; +bool UI::Create(HWND parent) { + if (pimpl_) { + pimpl_->panel.Create( + parent, 0, 0, WS_POPUP, + WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOACTIVATE | WS_EX_TRANSPARENT, + 0U, 0); + return true; + } + + pimpl_ = new UIImpl(*this); + if (!pimpl_) + return false; + + pimpl_->panel.Create( + parent, 0, 0, WS_POPUP, + WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOACTIVATE | WS_EX_TRANSPARENT, + 0U, 0); + return true; } -void UI::Destroy(bool full) -{ - if (pimpl_) - { - // destroy panel - if (pimpl_->panel.IsWindow()) - { - pimpl_->panel.DestroyWindow(); - } - if(full) - { - delete pimpl_; - pimpl_ = 0; - pDWR.reset(); - } - } +void UI::Destroy(bool full) { + if (pimpl_) { + // destroy panel + if (pimpl_->panel.IsWindow()) { + pimpl_->panel.DestroyWindow(); + } + if (full) { + delete pimpl_; + pimpl_ = 0; + pDWR.reset(); + } + } } -bool UI::GetIsReposition() -{ - if( pimpl_ ) - return pimpl_->panel.GetIsReposition(); - else - return false; +bool UI::GetIsReposition() { + if (pimpl_) + return pimpl_->panel.GetIsReposition(); + else + return false; } -void UI::Show() -{ - if (pimpl_) - { - pimpl_->Show(); - } +void UI::Show() { + if (pimpl_) { + pimpl_->Show(); + } } -void UI::Hide() -{ - if (pimpl_) - { - pimpl_->Hide(); - } +void UI::Hide() { + if (pimpl_) { + pimpl_->Hide(); + } } -void UI::ShowWithTimeout(size_t millisec) -{ - if (pimpl_) - { - pimpl_->ShowWithTimeout(millisec); - } +void UI::ShowWithTimeout(size_t millisec) { + if (pimpl_) { + pimpl_->ShowWithTimeout(millisec); + } } -bool UI::IsCountingDown() const -{ - return pimpl_ && pimpl_->timer != 0; +bool UI::IsCountingDown() const { + return pimpl_ && pimpl_->timer != 0; } -bool UI::IsShown() const -{ - return pimpl_ && pimpl_->IsShown(); +bool UI::IsShown() const { + return pimpl_ && pimpl_->IsShown(); } -void UI::Refresh() -{ - if (pimpl_) - { - pimpl_->Refresh(); - } +void UI::Refresh() { + if (pimpl_) { + pimpl_->Refresh(); + } } -void UI::UpdateInputPosition(RECT const& rc) -{ - if (pimpl_ && pimpl_->panel.IsWindow()) - { - pimpl_->panel.MoveTo(rc); - } +void UI::UpdateInputPosition(RECT const& rc) { + if (pimpl_ && pimpl_->panel.IsWindow()) { + pimpl_->panel.MoveTo(rc); + } } -void UI::Update(const Context &ctx, const Status &status) -{ - ctx_ = ctx; - status_ = status; - if(style_.candidate_abbreviate_length > 0) { - for (auto& c : ctx_.cinfo.candies) { - if (c.str.length() > style_.candidate_abbreviate_length) { - c.str = c.str.substr(0, style_.candidate_abbreviate_length - 1) + L"..." + c.str.substr(c.str.length() - 1); - } - } - } - Refresh(); +void UI::Update(const Context& ctx, const Status& status) { + ctx_ = ctx; + status_ = status; + if (style_.candidate_abbreviate_length > 0) { + for (auto& c : ctx_.cinfo.candies) { + if (c.str.length() > style_.candidate_abbreviate_length) { + c.str = c.str.substr(0, style_.candidate_abbreviate_length - 1) + + L"..." + c.str.substr(c.str.length() - 1); + } + } + } + Refresh(); } diff --git a/include/PipeChannel.h b/include/PipeChannel.h index 28d394339..bebc73a08 100644 --- a/include/PipeChannel.h +++ b/include/PipeChannel.h @@ -7,179 +7,157 @@ namespace weasel { - class PipeChannelBase { - public: - using Stream = boost::interprocess::wbufferstream; - - PipeChannelBase(std::wstring &&pn_cmd, size_t bs, SECURITY_ATTRIBUTES *s); - PipeChannelBase(PipeChannelBase &&r); - ~PipeChannelBase(); - - protected: - - /* To ensure connection before operation */ - bool _Ensure(); - /* Connect pipe as client */ - HANDLE _Connect(const wchar_t *name); - /* To reconnect message pipe */ - void _Reconnect(); - /* Try to connect for one time */ - HANDLE _TryConnect(); - size_t _WritePipe(HANDLE p, size_t s, char *b); - void _FinalizePipe(HANDLE &p); - void _Receive(HANDLE pipe, LPVOID msg, size_t rec_len); - /* Try to get a connection from client */ - HANDLE _ConnectServerPipe(std::wstring &pn); - inline bool _Invalid(HANDLE p) const { return p == INVALID_HANDLE_VALUE; } - - protected: - std::wstring pname; - HANDLE hpipe; - - bool has_body; - const size_t buff_size; - std::unique_ptr buffer; - std::unique_ptr write_stream; - - private: - /* Security attributes */ - SECURITY_ATTRIBUTES *sa; - }; - - - /* Pipe based IPC channel */ - template< - typename _TyMsg, - typename _TyRes = DWORD, - size_t _MsgSize = sizeof(_TyMsg), - size_t _ResSize = sizeof(_TyRes)> - class PipeChannel : public PipeChannelBase - { - public: - - /* Type definitions */ - - using Ptr = std::shared_ptr; - using UPtr = std::unique_ptr; - using Msg = _TyMsg; - using Res = _TyRes; - - enum class ChannalCommand { - NEW_MSG_PIPE, - REFRESH - }; - - public: - PipeChannel(std::wstring &&pn_cmd, SECURITY_ATTRIBUTES *s = NULL, size_t bs = 64 * 1024) - : PipeChannelBase(std::move(pn_cmd), bs, s) - {} - - public: - /* Common pipe operations */ - - bool Connect() { return _Ensure(); } - bool Connected() const { return !_Invalid(hpipe); } - void Disconnect() { _FinalizePipe(hpipe); } - - /* Write data to buffer */ - - template - void Write(_TyWrite cnt) - { - has_body = true; - _BufferWriteStream() << cnt; - } - - /* Write data to buffer */ - template - PipeChannel& operator<<(_TyWrite cnt) - { - Write(cnt); - return *this; - } - - _TyRes Transact(Msg &msg) - { - _Ensure(); - _Send(hpipe, msg); - return _ReceiveResponse(); - } - - - void ClearBufferStream() - { - has_body = false; - if (write_stream != nullptr) { - delete write_stream.release(); - write_stream.reset(nullptr); - } - } - - char *SendBuffer() const { return buffer.get() + _MsgSize; } - - char *ReceiveBuffer() const { return buffer.get() + _ResSize; } - - template - bool HandleResponseData(_TyHandler const &handler) - { - if (!handler) { - return false; - } - - // Use whole buffer to receive data in client - return handler((LPWSTR)buffer.get(), (UINT)(buff_size * sizeof(char) / sizeof(wchar_t))); - } - - - protected: - - void _Send(HANDLE pipe, Msg &msg) - { - char *pbuff = buffer.get(); - DWORD lwritten = 0; - - *reinterpret_cast(pbuff) = msg; - size_t data_sz = has_body ? buff_size : _MsgSize; - - try { - _WritePipe(pipe, data_sz, pbuff); - } - catch (...) { - _Reconnect(); - _WritePipe(pipe, data_sz, pbuff); - } - ClearBufferStream(); - } - - _TyRes _ReceiveResponse() - { - _TyRes result; - _Receive(hpipe, &result, sizeof(result)); - return result; - } - - Stream& _BufferWriteStream() - { - if (write_stream == nullptr) { - char *pbuff = (char *)buffer.get() + _MsgSize; - memset(pbuff, 0, buff_size - _MsgSize); - write_stream = std::make_unique((wchar_t *)pbuff, _SendBufferSizeW()); - } - return *write_stream; - } - - private: - - inline size_t _SendBufferSizeW() const - { - return (buff_size - _MsgSize) * sizeof(char) / sizeof(wchar_t); - } - - inline size_t _ReceiveBufferSizeW() const - { - return (buff_size - _ResSize) * sizeof(char) / sizeof(wchar_t); - } - - }; +class PipeChannelBase { + public: + using Stream = boost::interprocess::wbufferstream; + + PipeChannelBase(std::wstring&& pn_cmd, size_t bs, SECURITY_ATTRIBUTES* s); + PipeChannelBase(PipeChannelBase&& r); + ~PipeChannelBase(); + + protected: + /* To ensure connection before operation */ + bool _Ensure(); + /* Connect pipe as client */ + HANDLE _Connect(const wchar_t* name); + /* To reconnect message pipe */ + void _Reconnect(); + /* Try to connect for one time */ + HANDLE _TryConnect(); + size_t _WritePipe(HANDLE p, size_t s, char* b); + void _FinalizePipe(HANDLE& p); + void _Receive(HANDLE pipe, LPVOID msg, size_t rec_len); + /* Try to get a connection from client */ + HANDLE _ConnectServerPipe(std::wstring& pn); + inline bool _Invalid(HANDLE p) const { return p == INVALID_HANDLE_VALUE; } + + protected: + std::wstring pname; + HANDLE hpipe; + + bool has_body; + const size_t buff_size; + std::unique_ptr buffer; + std::unique_ptr write_stream; + + private: + /* Security attributes */ + SECURITY_ATTRIBUTES* sa; }; +/* Pipe based IPC channel */ +template +class PipeChannel : public PipeChannelBase { + public: + /* Type definitions */ + + using Ptr = std::shared_ptr; + using UPtr = std::unique_ptr; + using Msg = _TyMsg; + using Res = _TyRes; + + enum class ChannalCommand { NEW_MSG_PIPE, REFRESH }; + + public: + PipeChannel(std::wstring&& pn_cmd, + SECURITY_ATTRIBUTES* s = NULL, + size_t bs = 64 * 1024) + : PipeChannelBase(std::move(pn_cmd), bs, s) {} + + public: + /* Common pipe operations */ + + bool Connect() { return _Ensure(); } + bool Connected() const { return !_Invalid(hpipe); } + void Disconnect() { _FinalizePipe(hpipe); } + + /* Write data to buffer */ + + template + void Write(_TyWrite cnt) { + has_body = true; + _BufferWriteStream() << cnt; + } + + /* Write data to buffer */ + template + PipeChannel& operator<<(_TyWrite cnt) { + Write(cnt); + return *this; + } + + _TyRes Transact(Msg& msg) { + _Ensure(); + _Send(hpipe, msg); + return _ReceiveResponse(); + } + + void ClearBufferStream() { + has_body = false; + if (write_stream != nullptr) { + delete write_stream.release(); + write_stream.reset(nullptr); + } + } + + char* SendBuffer() const { return buffer.get() + _MsgSize; } + + char* ReceiveBuffer() const { return buffer.get() + _ResSize; } + + template + bool HandleResponseData(_TyHandler const& handler) { + if (!handler) { + return false; + } + + // Use whole buffer to receive data in client + return handler((LPWSTR)buffer.get(), + (UINT)(buff_size * sizeof(char) / sizeof(wchar_t))); + } + + protected: + void _Send(HANDLE pipe, Msg& msg) { + char* pbuff = buffer.get(); + DWORD lwritten = 0; + + *reinterpret_cast(pbuff) = msg; + size_t data_sz = has_body ? buff_size : _MsgSize; + + try { + _WritePipe(pipe, data_sz, pbuff); + } catch (...) { + _Reconnect(); + _WritePipe(pipe, data_sz, pbuff); + } + ClearBufferStream(); + } + + _TyRes _ReceiveResponse() { + _TyRes result; + _Receive(hpipe, &result, sizeof(result)); + return result; + } + + Stream& _BufferWriteStream() { + if (write_stream == nullptr) { + char* pbuff = (char*)buffer.get() + _MsgSize; + memset(pbuff, 0, buff_size - _MsgSize); + write_stream = + std::make_unique((wchar_t*)pbuff, _SendBufferSizeW()); + } + return *write_stream; + } + + private: + inline size_t _SendBufferSizeW() const { + return (buff_size - _MsgSize) * sizeof(char) / sizeof(wchar_t); + } + + inline size_t _ReceiveBufferSizeW() const { + return (buff_size - _ResSize) * sizeof(char) / sizeof(wchar_t); + } +}; +}; // namespace weasel diff --git a/include/ResponseParser.h b/include/ResponseParser.h index a8a934616..c69c9c094 100644 --- a/include/ResponseParser.h +++ b/include/ResponseParser.h @@ -5,29 +5,30 @@ #include #include +namespace weasel { +class Deserializer; -namespace weasel -{ - class Deserializer; +// 解析server回應文本 +struct ResponseParser { + std::map > deserializers; - // 解析server回應文本 - struct ResponseParser - { - std::map > deserializers; + std::wstring* p_commit; + Context* p_context; + Status* p_status; + Config* p_config; + UIStyle* p_style; - std::wstring* p_commit; - Context* p_context; - Status* p_status; - Config* p_config; - UIStyle* p_style; + ResponseParser(std::wstring* commit, + Context* context = 0, + Status* status = 0, + Config* config = 0, + UIStyle* style = 0); - ResponseParser(std::wstring* commit, Context* context = 0, Status* status = 0, Config* config = 0, UIStyle* style = 0); + // 重載函數調用運算符, 以扮做ResponseHandler + bool operator()(LPWSTR buffer, UINT length); - // 重載函數調用運算符, 以扮做ResponseHandler - bool operator() (LPWSTR buffer, UINT length); + // 處理一行回應文本 + void Feed(const std::wstring& line); +}; - // 處理一行回應文本 - void Feed(const std::wstring& line); - }; - -} +} // namespace weasel diff --git a/include/RimeWithWeasel.h b/include/RimeWithWeasel.h index 45ced7081..1d0c7b6a5 100644 --- a/include/RimeWithWeasel.h +++ b/include/RimeWithWeasel.h @@ -7,91 +7,96 @@ #include struct CaseInsensitiveCompare { - bool operator()(const std::string& str1, const std::string& str2) const { - std::string str1Lower, str2Lower; - std::transform(str1.begin(), str1.end(), std::back_inserter(str1Lower), - [](char c) { return std::tolower(c); }); - std::transform(str2.begin(), str2.end(), std::back_inserter(str2Lower), - [](char c) { return std::tolower(c); }); - return str1Lower < str2Lower; - } + bool operator()(const std::string& str1, const std::string& str2) const { + std::string str1Lower, str2Lower; + std::transform(str1.begin(), str1.end(), std::back_inserter(str1Lower), + [](char c) { return std::tolower(c); }); + std::transform(str2.begin(), str2.end(), std::back_inserter(str2Lower), + [](char c) { return std::tolower(c); }); + return str1Lower < str2Lower; + } }; typedef std::map AppOptions; -typedef std::map AppOptionsByAppName; -struct SessionStatus -{ - SessionStatus() : style(weasel::UIStyle()), __synced(false) { RIME_STRUCT(RimeStatus, status); } - weasel::UIStyle style; - RimeStatus status; - bool __synced; +typedef std::map + AppOptionsByAppName; +struct SessionStatus { + SessionStatus() : style(weasel::UIStyle()), __synced(false) { + RIME_STRUCT(RimeStatus, status); + } + weasel::UIStyle style; + RimeStatus status; + bool __synced; }; typedef std::map SessionStatusMap; -class RimeWithWeaselHandler : - public weasel::RequestHandler -{ -public: - RimeWithWeaselHandler(weasel::UI *ui); - virtual ~RimeWithWeaselHandler(); - virtual void Initialize(); - virtual void Finalize(); - virtual UINT FindSession(UINT session_id); - virtual UINT AddSession(LPWSTR buffer, EatLine eat = 0); - virtual UINT RemoveSession(UINT session_id); - virtual BOOL ProcessKeyEvent(weasel::KeyEvent keyEvent, UINT session_id, EatLine eat); - virtual void CommitComposition(UINT session_id); - virtual void ClearComposition(UINT session_id); - virtual void SelectCandidateOnCurrentPage(size_t index, UINT session_id); - virtual bool HighlightCandidateOnCurrentPage(size_t index, UINT session_id, EatLine eat); - virtual bool ChangePage(bool backward, UINT session_id, EatLine eat); - virtual void FocusIn(DWORD param, UINT session_id); - virtual void FocusOut(DWORD param, UINT session_id); - virtual void UpdateInputPosition(RECT const& rc, UINT session_id); - virtual void StartMaintenance(); - virtual void EndMaintenance(); - virtual void SetOption(UINT session_id, const std::string &opt, bool val); - virtual void UpdateColorTheme(BOOL darkMode); +class RimeWithWeaselHandler : public weasel::RequestHandler { + public: + RimeWithWeaselHandler(weasel::UI* ui); + virtual ~RimeWithWeaselHandler(); + virtual void Initialize(); + virtual void Finalize(); + virtual UINT FindSession(UINT session_id); + virtual UINT AddSession(LPWSTR buffer, EatLine eat = 0); + virtual UINT RemoveSession(UINT session_id); + virtual BOOL ProcessKeyEvent(weasel::KeyEvent keyEvent, + UINT session_id, + EatLine eat); + virtual void CommitComposition(UINT session_id); + virtual void ClearComposition(UINT session_id); + virtual void SelectCandidateOnCurrentPage(size_t index, UINT session_id); + virtual bool HighlightCandidateOnCurrentPage(size_t index, + UINT session_id, + EatLine eat); + virtual bool ChangePage(bool backward, UINT session_id, EatLine eat); + virtual void FocusIn(DWORD param, UINT session_id); + virtual void FocusOut(DWORD param, UINT session_id); + virtual void UpdateInputPosition(RECT const& rc, UINT session_id); + virtual void StartMaintenance(); + virtual void EndMaintenance(); + virtual void SetOption(UINT session_id, const std::string& opt, bool val); + virtual void UpdateColorTheme(BOOL darkMode); - void OnUpdateUI(std::function const &cb); + void OnUpdateUI(std::function const& cb); -private: - void _Setup(); - bool _IsDeployerRunning(); - void _UpdateUI(UINT session_id); - void _LoadSchemaSpecificSettings(UINT session_id, const std::string& schema_id); - void _LoadAppInlinePreeditSet(UINT session_id, bool ignore_app_name = false); - bool _ShowMessage(weasel::Context& ctx, weasel::Status& status); - bool _Respond(UINT session_id, EatLine eat); - void _ReadClientInfo(UINT session_id, LPWSTR buffer); - void _GetCandidateInfo(weasel::CandidateInfo &cinfo, RimeContext &ctx); - void _GetStatus(weasel::Status &stat, UINT session_id, weasel::Context& ctx); - void _GetContext(weasel::Context &ctx, UINT session_id); - void _UpdateShowNotifications(RimeConfig* config, bool initialize = false); + private: + void _Setup(); + bool _IsDeployerRunning(); + void _UpdateUI(UINT session_id); + void _LoadSchemaSpecificSettings(UINT session_id, + const std::string& schema_id); + void _LoadAppInlinePreeditSet(UINT session_id, bool ignore_app_name = false); + bool _ShowMessage(weasel::Context& ctx, weasel::Status& status); + bool _Respond(UINT session_id, EatLine eat); + void _ReadClientInfo(UINT session_id, LPWSTR buffer); + void _GetCandidateInfo(weasel::CandidateInfo& cinfo, RimeContext& ctx); + void _GetStatus(weasel::Status& stat, UINT session_id, weasel::Context& ctx); + void _GetContext(weasel::Context& ctx, UINT session_id); + void _UpdateShowNotifications(RimeConfig* config, bool initialize = false); - bool _IsSessionTSF(UINT session_id); - void _UpdateInlinePreeditStatus(UINT session_id); + bool _IsSessionTSF(UINT session_id); + void _UpdateInlinePreeditStatus(UINT session_id); - AppOptionsByAppName m_app_options; - weasel::UI* m_ui; // reference - UINT m_active_session; - bool m_disabled; - std::string m_last_schema_id; - std::string m_last_app_name; - weasel::UIStyle m_base_style; - std::map m_show_notifications; - std::map m_show_notifications_base; - std::function _UpdateUICallback; + AppOptionsByAppName m_app_options; + weasel::UI* m_ui; // reference + UINT m_active_session; + bool m_disabled; + std::string m_last_schema_id; + std::string m_last_app_name; + weasel::UIStyle m_base_style; + std::map m_show_notifications; + std::map m_show_notifications_base; + std::function _UpdateUICallback; - static void OnNotify(void* context_object, - uintptr_t session_id, - const char* message_type, - const char* message_value); - static std::string m_message_type; - static std::string m_message_value; - static std::string m_message_label; - static std::string m_option_name; - SessionStatusMap m_session_status_map; - bool m_current_dark_mode; - bool m_global_ascii_mode; - int m_show_notifications_time; + static void OnNotify(void* context_object, + uintptr_t session_id, + const char* message_type, + const char* message_value); + static std::string m_message_type; + static std::string m_message_value; + static std::string m_message_label; + static std::string m_option_name; + SessionStatusMap m_session_status_map; + bool m_current_dark_mode; + bool m_global_ascii_mode; + int m_show_notifications_time; }; diff --git a/include/WeaselCommon.h b/include/WeaselCommon.h index 3f617058e..0e7257de3 100644 --- a/include/WeaselCommon.h +++ b/include/WeaselCommon.h @@ -1,7 +1,7 @@ #pragma once -//#include -//#include +// #include +// #include #include #include @@ -9,601 +9,522 @@ #define WEASEL_REG_KEY L"Software\\Rime\\Weasel" #define RIME_REG_KEY L"Software\\Rime" -//#define USE_SHARP_COLOR_CODE +// #define USE_SHARP_COLOR_CODE -//#define _DEBUG_ -namespace weasel -{ +// #define _DEBUG_ +namespace weasel { - enum TextAttributeType - { - NONE = 0, - HIGHLIGHTED, - LAST_TYPE - }; +enum TextAttributeType { NONE = 0, HIGHLIGHTED, LAST_TYPE }; - struct TextRange - { - TextRange() : start(0), end(0), cursor(-1) {} - TextRange(int _start, int _end, int _cursor) : start(_start), end(_end), cursor(_cursor) {} - bool operator==(const TextRange& tr) - { - return (start == tr.start && end == tr.end && cursor == tr.cursor); - } - bool operator!=(const TextRange& tr) - { - return (start != tr.start || end != tr.end || cursor != tr.cursor); - } - int start; - int end; - int cursor; - }; +struct TextRange { + TextRange() : start(0), end(0), cursor(-1) {} + TextRange(int _start, int _end, int _cursor) + : start(_start), end(_end), cursor(_cursor) {} + bool operator==(const TextRange& tr) { + return (start == tr.start && end == tr.end && cursor == tr.cursor); + } + bool operator!=(const TextRange& tr) { + return (start != tr.start || end != tr.end || cursor != tr.cursor); + } + int start; + int end; + int cursor; +}; - struct TextAttribute - { - TextAttribute() : type(NONE) {} - TextAttribute(int _start, int _end, TextAttributeType _type) : range(_start, _end, -1), type(_type) {} - bool operator==(const TextAttribute& ta) - { - return (range == ta.range && type == ta.type); - } - bool operator!=(const TextAttribute& ta) - { - return (range != ta.range || type != ta.type); - } - TextRange range; - TextAttributeType type; - }; +struct TextAttribute { + TextAttribute() : type(NONE) {} + TextAttribute(int _start, int _end, TextAttributeType _type) + : range(_start, _end, -1), type(_type) {} + bool operator==(const TextAttribute& ta) { + return (range == ta.range && type == ta.type); + } + bool operator!=(const TextAttribute& ta) { + return (range != ta.range || type != ta.type); + } + TextRange range; + TextAttributeType type; +}; - struct Text - { - Text() : str(L"") {} - Text(std::wstring const& _str) : str(_str) {} - void clear() - { - str.clear(); - attributes.clear(); - } - bool empty() const - { - return str.empty(); - } - bool operator==(const Text& txt) - { - if (str != txt.str || (attributes.size() != txt.attributes.size())) - return false; - for (size_t i = 0; i < attributes.size(); i++) - { - if ((attributes[i] != txt.attributes[i])) - return false; - } - return true; - } - bool operator!=(const Text& txt) - { - if (str != txt.str || (attributes.size() != txt.attributes.size())) - return true; - for (size_t i = 0; i < attributes.size(); i++) - { - if ((attributes[i] != txt.attributes[i])) - return true; - } - return false; - } - std::wstring str; - std::vector attributes; - }; +struct Text { + Text() : str(L"") {} + Text(std::wstring const& _str) : str(_str) {} + void clear() { + str.clear(); + attributes.clear(); + } + bool empty() const { return str.empty(); } + bool operator==(const Text& txt) { + if (str != txt.str || (attributes.size() != txt.attributes.size())) + return false; + for (size_t i = 0; i < attributes.size(); i++) { + if ((attributes[i] != txt.attributes[i])) + return false; + } + return true; + } + bool operator!=(const Text& txt) { + if (str != txt.str || (attributes.size() != txt.attributes.size())) + return true; + for (size_t i = 0; i < attributes.size(); i++) { + if ((attributes[i] != txt.attributes[i])) + return true; + } + return false; + } + std::wstring str; + std::vector attributes; +}; - struct CandidateInfo - { - CandidateInfo() - { - currentPage = 0; - totalPages = 0; - highlighted = 0; - is_last_page = false; - } - void clear() - { - currentPage = 0; - totalPages = 0; - highlighted = 0; - is_last_page = false; - candies.clear(); - labels.clear(); - } - bool empty() const - { - return candies.empty(); - } - bool operator==(const CandidateInfo& ci) - { - if (currentPage != ci.currentPage - || totalPages != ci.totalPages - || highlighted != ci.highlighted - || is_last_page != ci.is_last_page - || notequal(candies, ci.candies) - || notequal(comments, ci.comments) - || notequal(labels, ci.labels) - ) - return false; - return true; - } - bool operator!=(const CandidateInfo& ci) - { - if (currentPage != ci.currentPage - || totalPages != ci.totalPages - || highlighted != ci.highlighted - || is_last_page != ci.is_last_page - || notequal(candies, ci.candies) - || notequal(comments, ci.comments) - || notequal(labels, ci.labels) - ) - return true; - return false; - } - bool notequal(std::vector txtSrc, std::vector txtDst) - { - if (txtSrc.size() != txtDst.size()) return true; - for (size_t i = 0; i < txtSrc.size(); i++) - { - if (txtSrc[i] != txtDst[i]) - return true; - } - return false; - } - int currentPage; - bool is_last_page; - int totalPages; - int highlighted; - std::vector candies; - std::vector comments; - std::vector labels; - }; +struct CandidateInfo { + CandidateInfo() { + currentPage = 0; + totalPages = 0; + highlighted = 0; + is_last_page = false; + } + void clear() { + currentPage = 0; + totalPages = 0; + highlighted = 0; + is_last_page = false; + candies.clear(); + labels.clear(); + } + bool empty() const { return candies.empty(); } + bool operator==(const CandidateInfo& ci) { + if (currentPage != ci.currentPage || totalPages != ci.totalPages || + highlighted != ci.highlighted || is_last_page != ci.is_last_page || + notequal(candies, ci.candies) || notequal(comments, ci.comments) || + notequal(labels, ci.labels)) + return false; + return true; + } + bool operator!=(const CandidateInfo& ci) { + if (currentPage != ci.currentPage || totalPages != ci.totalPages || + highlighted != ci.highlighted || is_last_page != ci.is_last_page || + notequal(candies, ci.candies) || notequal(comments, ci.comments) || + notequal(labels, ci.labels)) + return true; + return false; + } + bool notequal(std::vector txtSrc, std::vector txtDst) { + if (txtSrc.size() != txtDst.size()) + return true; + for (size_t i = 0; i < txtSrc.size(); i++) { + if (txtSrc[i] != txtDst[i]) + return true; + } + return false; + } + int currentPage; + bool is_last_page; + int totalPages; + int highlighted; + std::vector candies; + std::vector comments; + std::vector labels; +}; - struct Context - { - Context() {} - void clear() - { - preedit.clear(); - aux.clear(); - cinfo.clear(); - } - bool empty() const - { - return preedit.empty() && aux.empty() && cinfo.empty(); - } - bool operator==(const Context& ctx) - { - if (preedit == ctx.preedit && aux == ctx.aux && cinfo == ctx.cinfo) - return true; - return false; - } - bool operator!=(const Context& ctx) - { - return !(operator==(ctx)); - } +struct Context { + Context() {} + void clear() { + preedit.clear(); + aux.clear(); + cinfo.clear(); + } + bool empty() const { return preedit.empty() && aux.empty() && cinfo.empty(); } + bool operator==(const Context& ctx) { + if (preedit == ctx.preedit && aux == ctx.aux && cinfo == ctx.cinfo) + return true; + return false; + } + bool operator!=(const Context& ctx) { return !(operator==(ctx)); } - bool operator!() - { - if (preedit.str.empty() - && aux.str.empty() - && cinfo.candies.empty() - && cinfo.labels.empty() - && cinfo.comments.empty()) - return true; - else - return false; - } - Text preedit; - Text aux; - CandidateInfo cinfo; - }; - // for icon type in tip - enum IconType{ - SCHEMA, - FULL_SHAPE - } ; - // 由ime管理 - struct Status - { - Status() : type(SCHEMA), ascii_mode(false), composing(false), disabled(false), full_shape(false) {} - void reset() - { - schema_name.clear(); - schema_id.clear(); - ascii_mode = false; - composing = false; - disabled = false; - full_shape = false; - type = SCHEMA; - } - // 輸入方案 - std::wstring schema_name; - // 輸入方案 id - std::wstring schema_id; - // 轉換開關 - bool ascii_mode; - // 寫作狀態 - bool composing; - // 維護模式(暫停輸入功能) - bool disabled; - // 全角状态 - bool full_shape; - // 图标类型, schema/full_shape - IconType type; - }; + bool operator!() { + if (preedit.str.empty() && aux.str.empty() && cinfo.candies.empty() && + cinfo.labels.empty() && cinfo.comments.empty()) + return true; + else + return false; + } + Text preedit; + Text aux; + CandidateInfo cinfo; +}; +// for icon type in tip +enum IconType { SCHEMA, FULL_SHAPE }; +// 由ime管理 +struct Status { + Status() + : type(SCHEMA), + ascii_mode(false), + composing(false), + disabled(false), + full_shape(false) {} + void reset() { + schema_name.clear(); + schema_id.clear(); + ascii_mode = false; + composing = false; + disabled = false; + full_shape = false; + type = SCHEMA; + } + // 輸入方案 + std::wstring schema_name; + // 輸入方案 id + std::wstring schema_id; + // 轉換開關 + bool ascii_mode; + // 寫作狀態 + bool composing; + // 維護模式(暫停輸入功能) + bool disabled; + // 全角状态 + bool full_shape; + // 图标类型, schema/full_shape + IconType type; +}; - // 用於向前端告知設置信息 - struct Config - { - Config() : inline_preedit(false) {} - void reset() - { - inline_preedit = false; - } - bool inline_preedit; - }; +// 用於向前端告知設置信息 +struct Config { + Config() : inline_preedit(false) {} + void reset() { inline_preedit = false; } + bool inline_preedit; +}; - struct UIStyle - { - enum AntiAliasMode - { - DEFAULT = 0, - CLEARTYPE = 1, - GRAYSCALE = 2, - ALIASED = 3, - FORCE_DWORD = 0xffffffff - }; +struct UIStyle { + enum AntiAliasMode { + DEFAULT = 0, + CLEARTYPE = 1, + GRAYSCALE = 2, + ALIASED = 3, + FORCE_DWORD = 0xffffffff + }; - enum PreeditType - { - COMPOSITION, - PREVIEW, - PREVIEW_ALL - }; + enum PreeditType { COMPOSITION, PREVIEW, PREVIEW_ALL }; - enum LayoutType - { - LAYOUT_VERTICAL = 0, - LAYOUT_HORIZONTAL, - LAYOUT_VERTICAL_TEXT, - LAYOUT_VERTICAL_FULLSCREEN, - LAYOUT_HORIZONTAL_FULLSCREEN, - LAYOUT_TYPE_LAST - }; + enum LayoutType { + LAYOUT_VERTICAL = 0, + LAYOUT_HORIZONTAL, + LAYOUT_VERTICAL_TEXT, + LAYOUT_VERTICAL_FULLSCREEN, + LAYOUT_HORIZONTAL_FULLSCREEN, + LAYOUT_TYPE_LAST + }; - enum LayoutAlignType - { - ALIGN_BOTTOM = 0, - ALIGN_CENTER, - ALIGN_TOP - }; + enum LayoutAlignType { ALIGN_BOTTOM = 0, ALIGN_CENTER, ALIGN_TOP }; - // font face and font point settings - std::wstring font_face; - std::wstring label_font_face; - std::wstring comment_font_face; - int font_point; - int label_font_point; - int comment_font_point; - int candidate_abbreviate_length; + // font face and font point settings + std::wstring font_face; + std::wstring label_font_face; + std::wstring comment_font_face; + int font_point; + int label_font_point; + int comment_font_point; + int candidate_abbreviate_length; - bool inline_preedit; - bool display_tray_icon; - bool ascii_tip_follow_cursor; - bool paging_on_scroll; - bool enhanced_position; - bool click_to_capture; - int mouse_hover_ms; - AntiAliasMode antialias_mode; - PreeditType preedit_type; - // custom icon settings - std::wstring current_zhung_icon; - std::wstring current_ascii_icon; - std::wstring current_half_icon; - std::wstring current_full_icon; - // label format and mark_text - std::wstring label_text_format; - std::wstring mark_text; - // layout relative parameters - LayoutType layout_type; - LayoutAlignType align_type; - bool vertical_text_left_to_right; - bool vertical_text_with_wrap; - // layout, with key name like style/layout/... - int min_width; - int max_width; - int min_height; - int max_height; - int border; - int margin_x; - int margin_y; - int spacing; - int candidate_spacing; - int hilite_spacing; - int hilite_padding_x; - int hilite_padding_y; - int round_corner; - int round_corner_ex; - int shadow_radius; - int shadow_offset_x; - int shadow_offset_y; - bool vertical_auto_reverse; - // color scheme - int text_color; - int candidate_text_color; - int candidate_back_color; - int candidate_shadow_color; - int candidate_border_color; - int label_text_color; - int comment_text_color; - int back_color; - int shadow_color; - int border_color; - int hilited_text_color; - int hilited_back_color; - int hilited_shadow_color; - int hilited_candidate_text_color; - int hilited_candidate_back_color; - int hilited_candidate_shadow_color; - int hilited_candidate_border_color; - int hilited_label_text_color; - int hilited_comment_text_color; - int hilited_mark_color; - int prevpage_color; - int nextpage_color; - // per client - int client_caps; + bool inline_preedit; + bool display_tray_icon; + bool ascii_tip_follow_cursor; + bool paging_on_scroll; + bool enhanced_position; + bool click_to_capture; + int mouse_hover_ms; + AntiAliasMode antialias_mode; + PreeditType preedit_type; + // custom icon settings + std::wstring current_zhung_icon; + std::wstring current_ascii_icon; + std::wstring current_half_icon; + std::wstring current_full_icon; + // label format and mark_text + std::wstring label_text_format; + std::wstring mark_text; + // layout relative parameters + LayoutType layout_type; + LayoutAlignType align_type; + bool vertical_text_left_to_right; + bool vertical_text_with_wrap; + // layout, with key name like style/layout/... + int min_width; + int max_width; + int min_height; + int max_height; + int border; + int margin_x; + int margin_y; + int spacing; + int candidate_spacing; + int hilite_spacing; + int hilite_padding_x; + int hilite_padding_y; + int round_corner; + int round_corner_ex; + int shadow_radius; + int shadow_offset_x; + int shadow_offset_y; + bool vertical_auto_reverse; + // color scheme + int text_color; + int candidate_text_color; + int candidate_back_color; + int candidate_shadow_color; + int candidate_border_color; + int label_text_color; + int comment_text_color; + int back_color; + int shadow_color; + int border_color; + int hilited_text_color; + int hilited_back_color; + int hilited_shadow_color; + int hilited_candidate_text_color; + int hilited_candidate_back_color; + int hilited_candidate_shadow_color; + int hilited_candidate_border_color; + int hilited_label_text_color; + int hilited_comment_text_color; + int hilited_mark_color; + int prevpage_color; + int nextpage_color; + // per client + int client_caps; - UIStyle() : font_face(), - label_font_face(), - comment_font_face(), - font_point(0), - label_font_point(0), - comment_font_point(0), - candidate_abbreviate_length(0), - inline_preedit(false), - display_tray_icon(false), - ascii_tip_follow_cursor(false), - paging_on_scroll(false), - enhanced_position(false), - click_to_capture(false), - mouse_hover_ms(0), - antialias_mode(DEFAULT), - preedit_type(COMPOSITION), - current_zhung_icon(), - current_ascii_icon(), - current_half_icon(), - current_full_icon(), - label_text_format(L"%s."), - mark_text(), - layout_type(LAYOUT_VERTICAL), - align_type(ALIGN_BOTTOM), - vertical_text_left_to_right(false), - vertical_text_with_wrap(false), - min_width(0), - max_width(0), - min_height(0), - max_height(0), - border(0), - margin_x(0), - margin_y(0), - spacing(0), - candidate_spacing(0), - hilite_spacing(0), - hilite_padding_x(0), - hilite_padding_y(0), - round_corner(0), - round_corner_ex(0), - shadow_radius(0), - shadow_offset_x(0), - shadow_offset_y(0), - vertical_auto_reverse(false), - text_color(0), - candidate_text_color(0), - candidate_back_color(0), - candidate_shadow_color(0), - candidate_border_color(0), - label_text_color(0), - comment_text_color(0), - back_color(0), - shadow_color(0), - border_color(0), - hilited_text_color(0), - hilited_back_color(0), - hilited_shadow_color(0), - hilited_candidate_text_color(0), - hilited_candidate_back_color(0), - hilited_candidate_shadow_color(0), - hilited_candidate_border_color(0), - hilited_label_text_color(0), - hilited_comment_text_color(0), - hilited_mark_color(0), - prevpage_color(0), - nextpage_color(0), - client_caps(0) {} - bool operator!=(const UIStyle& st) - { - return - ( - align_type != st.align_type - || antialias_mode != st.antialias_mode - || preedit_type != st.preedit_type - || layout_type != st.layout_type - || vertical_text_left_to_right != st.vertical_text_left_to_right - || vertical_text_with_wrap != st.vertical_text_with_wrap - || paging_on_scroll != st.paging_on_scroll - || font_face != st.font_face - || label_font_face != st.label_font_face - || comment_font_face != st.comment_font_face - || mouse_hover_ms != st.mouse_hover_ms - || font_point != st.font_point - || label_font_point != st.label_font_point - || comment_font_point != st.comment_font_point - || candidate_abbreviate_length != st.candidate_abbreviate_length - || inline_preedit != st.inline_preedit - || mark_text != st.mark_text - || display_tray_icon != st.display_tray_icon - || ascii_tip_follow_cursor != st.ascii_tip_follow_cursor - || current_zhung_icon != st.current_zhung_icon - || current_ascii_icon != st.current_ascii_icon - || current_half_icon != st.current_half_icon - || current_full_icon != st.current_full_icon - || enhanced_position != st.enhanced_position - || click_to_capture != st.click_to_capture - || label_text_format != st.label_text_format - || min_width != st.min_width - || max_width != st.max_width - || min_height != st.min_height - || max_height != st.max_height - || border != st.border - || margin_x != st.margin_x - || margin_y != st.margin_y - || spacing != st.spacing - || candidate_spacing != st.candidate_spacing - || hilite_spacing != st.hilite_spacing - || hilite_padding_x != st.hilite_padding_x - || hilite_padding_y != st.hilite_padding_y - || round_corner != st.round_corner - || round_corner_ex != st.round_corner_ex - || shadow_radius != st.shadow_radius - || shadow_offset_x != st.shadow_offset_x - || shadow_offset_y != st.shadow_offset_y - || vertical_auto_reverse != st.vertical_auto_reverse - || text_color != st.text_color - || candidate_text_color != st.candidate_text_color - || candidate_back_color != st.candidate_back_color - || candidate_shadow_color != st.candidate_shadow_color - || candidate_border_color != st.candidate_border_color - || hilited_candidate_border_color != st.hilited_candidate_border_color - || label_text_color != st.label_text_color - || comment_text_color != st.comment_text_color - || back_color != st.back_color - || shadow_color != st.shadow_color - || border_color != st.border_color - || hilited_text_color != st.hilited_text_color - || hilited_back_color != st.hilited_back_color - || hilited_shadow_color != st.hilited_shadow_color - || hilited_candidate_text_color != st.hilited_candidate_text_color - || hilited_candidate_back_color != st.hilited_candidate_back_color - || hilited_candidate_shadow_color != st.hilited_candidate_shadow_color - || hilited_label_text_color != st.hilited_label_text_color - || hilited_comment_text_color != st.hilited_comment_text_color - || hilited_mark_color != st.hilited_mark_color - || prevpage_color != st.prevpage_color - || nextpage_color != st.nextpage_color - ); - } - }; -} + UIStyle() + : font_face(), + label_font_face(), + comment_font_face(), + font_point(0), + label_font_point(0), + comment_font_point(0), + candidate_abbreviate_length(0), + inline_preedit(false), + display_tray_icon(false), + ascii_tip_follow_cursor(false), + paging_on_scroll(false), + enhanced_position(false), + click_to_capture(false), + mouse_hover_ms(0), + antialias_mode(DEFAULT), + preedit_type(COMPOSITION), + current_zhung_icon(), + current_ascii_icon(), + current_half_icon(), + current_full_icon(), + label_text_format(L"%s."), + mark_text(), + layout_type(LAYOUT_VERTICAL), + align_type(ALIGN_BOTTOM), + vertical_text_left_to_right(false), + vertical_text_with_wrap(false), + min_width(0), + max_width(0), + min_height(0), + max_height(0), + border(0), + margin_x(0), + margin_y(0), + spacing(0), + candidate_spacing(0), + hilite_spacing(0), + hilite_padding_x(0), + hilite_padding_y(0), + round_corner(0), + round_corner_ex(0), + shadow_radius(0), + shadow_offset_x(0), + shadow_offset_y(0), + vertical_auto_reverse(false), + text_color(0), + candidate_text_color(0), + candidate_back_color(0), + candidate_shadow_color(0), + candidate_border_color(0), + label_text_color(0), + comment_text_color(0), + back_color(0), + shadow_color(0), + border_color(0), + hilited_text_color(0), + hilited_back_color(0), + hilited_shadow_color(0), + hilited_candidate_text_color(0), + hilited_candidate_back_color(0), + hilited_candidate_shadow_color(0), + hilited_candidate_border_color(0), + hilited_label_text_color(0), + hilited_comment_text_color(0), + hilited_mark_color(0), + prevpage_color(0), + nextpage_color(0), + client_caps(0) {} + bool operator!=(const UIStyle& st) { + return ( + align_type != st.align_type || antialias_mode != st.antialias_mode || + preedit_type != st.preedit_type || layout_type != st.layout_type || + vertical_text_left_to_right != st.vertical_text_left_to_right || + vertical_text_with_wrap != st.vertical_text_with_wrap || + paging_on_scroll != st.paging_on_scroll || font_face != st.font_face || + label_font_face != st.label_font_face || + comment_font_face != st.comment_font_face || + mouse_hover_ms != st.mouse_hover_ms || font_point != st.font_point || + label_font_point != st.label_font_point || + comment_font_point != st.comment_font_point || + candidate_abbreviate_length != st.candidate_abbreviate_length || + inline_preedit != st.inline_preedit || mark_text != st.mark_text || + display_tray_icon != st.display_tray_icon || + ascii_tip_follow_cursor != st.ascii_tip_follow_cursor || + current_zhung_icon != st.current_zhung_icon || + current_ascii_icon != st.current_ascii_icon || + current_half_icon != st.current_half_icon || + current_full_icon != st.current_full_icon || + enhanced_position != st.enhanced_position || + click_to_capture != st.click_to_capture || + label_text_format != st.label_text_format || + min_width != st.min_width || max_width != st.max_width || + min_height != st.min_height || max_height != st.max_height || + border != st.border || margin_x != st.margin_x || + margin_y != st.margin_y || spacing != st.spacing || + candidate_spacing != st.candidate_spacing || + hilite_spacing != st.hilite_spacing || + hilite_padding_x != st.hilite_padding_x || + hilite_padding_y != st.hilite_padding_y || + round_corner != st.round_corner || + round_corner_ex != st.round_corner_ex || + shadow_radius != st.shadow_radius || + shadow_offset_x != st.shadow_offset_x || + shadow_offset_y != st.shadow_offset_y || + vertical_auto_reverse != st.vertical_auto_reverse || + text_color != st.text_color || + candidate_text_color != st.candidate_text_color || + candidate_back_color != st.candidate_back_color || + candidate_shadow_color != st.candidate_shadow_color || + candidate_border_color != st.candidate_border_color || + hilited_candidate_border_color != st.hilited_candidate_border_color || + label_text_color != st.label_text_color || + comment_text_color != st.comment_text_color || + back_color != st.back_color || shadow_color != st.shadow_color || + border_color != st.border_color || + hilited_text_color != st.hilited_text_color || + hilited_back_color != st.hilited_back_color || + hilited_shadow_color != st.hilited_shadow_color || + hilited_candidate_text_color != st.hilited_candidate_text_color || + hilited_candidate_back_color != st.hilited_candidate_back_color || + hilited_candidate_shadow_color != st.hilited_candidate_shadow_color || + hilited_label_text_color != st.hilited_label_text_color || + hilited_comment_text_color != st.hilited_comment_text_color || + hilited_mark_color != st.hilited_mark_color || + prevpage_color != st.prevpage_color || + nextpage_color != st.nextpage_color); + } +}; +} // namespace weasel namespace boost { - namespace serialization { - template - void serialize(Archive &ar, weasel::UIStyle &s, const unsigned int version) - { - ar & s.font_face; - ar & s.label_font_face; - ar & s.comment_font_face; - ar & s.mouse_hover_ms; - ar & s.font_point; - ar & s.label_font_point; - ar & s.comment_font_point; - ar & s.candidate_abbreviate_length; - ar & s.inline_preedit; - ar & s.align_type; - ar & s.antialias_mode; - ar & s.mark_text; - ar & s.preedit_type; - ar & s.display_tray_icon; - ar & s.ascii_tip_follow_cursor; - ar & s.current_zhung_icon; - ar & s.current_ascii_icon; - ar & s.current_half_icon; - ar & s.current_full_icon; - ar & s.enhanced_position; - ar & s.click_to_capture; - ar & s.label_text_format; - // layout - ar & s.layout_type; - ar & s.vertical_text_left_to_right; - ar & s.vertical_text_with_wrap; - ar & s.paging_on_scroll; - ar & s.min_width; - ar & s.max_width; - ar & s.min_height; - ar & s.max_height; - ar & s.border; - ar & s.margin_x; - ar & s.margin_y; - ar & s.spacing; - ar & s.candidate_spacing; - ar & s.hilite_spacing; - ar & s.hilite_padding_x; - ar & s.hilite_padding_y; - ar & s.round_corner; - ar & s.round_corner_ex; - ar & s.shadow_radius; - ar & s.shadow_offset_x; - ar & s.shadow_offset_y; - ar & s.vertical_auto_reverse; - // color scheme - ar & s.text_color; - ar & s.candidate_text_color; - ar & s.candidate_back_color; - ar & s.candidate_shadow_color; - ar & s.candidate_border_color; - ar & s.label_text_color; - ar & s.comment_text_color; - ar & s.back_color; - ar & s.shadow_color; - ar & s.border_color; - ar & s.hilited_text_color; - ar & s.hilited_back_color; - ar & s.hilited_shadow_color; - ar & s.hilited_candidate_text_color; - ar & s.hilited_candidate_back_color; - ar & s.hilited_candidate_shadow_color; - ar & s.hilited_candidate_border_color; - ar & s.hilited_label_text_color; - ar & s.hilited_comment_text_color; - ar & s.hilited_mark_color; - ar & s.prevpage_color; - ar & s.nextpage_color; - // per client - ar & s.client_caps; - } +namespace serialization { +template +void serialize(Archive& ar, weasel::UIStyle& s, const unsigned int version) { + ar & s.font_face; + ar & s.label_font_face; + ar & s.comment_font_face; + ar & s.mouse_hover_ms; + ar & s.font_point; + ar & s.label_font_point; + ar & s.comment_font_point; + ar & s.candidate_abbreviate_length; + ar & s.inline_preedit; + ar & s.align_type; + ar & s.antialias_mode; + ar & s.mark_text; + ar & s.preedit_type; + ar & s.display_tray_icon; + ar & s.ascii_tip_follow_cursor; + ar & s.current_zhung_icon; + ar & s.current_ascii_icon; + ar & s.current_half_icon; + ar & s.current_full_icon; + ar & s.enhanced_position; + ar & s.click_to_capture; + ar & s.label_text_format; + // layout + ar & s.layout_type; + ar & s.vertical_text_left_to_right; + ar & s.vertical_text_with_wrap; + ar & s.paging_on_scroll; + ar & s.min_width; + ar & s.max_width; + ar & s.min_height; + ar & s.max_height; + ar & s.border; + ar & s.margin_x; + ar & s.margin_y; + ar & s.spacing; + ar & s.candidate_spacing; + ar & s.hilite_spacing; + ar & s.hilite_padding_x; + ar & s.hilite_padding_y; + ar & s.round_corner; + ar & s.round_corner_ex; + ar & s.shadow_radius; + ar & s.shadow_offset_x; + ar & s.shadow_offset_y; + ar & s.vertical_auto_reverse; + // color scheme + ar & s.text_color; + ar & s.candidate_text_color; + ar & s.candidate_back_color; + ar & s.candidate_shadow_color; + ar & s.candidate_border_color; + ar & s.label_text_color; + ar & s.comment_text_color; + ar & s.back_color; + ar & s.shadow_color; + ar & s.border_color; + ar & s.hilited_text_color; + ar & s.hilited_back_color; + ar & s.hilited_shadow_color; + ar & s.hilited_candidate_text_color; + ar & s.hilited_candidate_back_color; + ar & s.hilited_candidate_shadow_color; + ar & s.hilited_candidate_border_color; + ar & s.hilited_label_text_color; + ar & s.hilited_comment_text_color; + ar & s.hilited_mark_color; + ar & s.prevpage_color; + ar & s.nextpage_color; + // per client + ar & s.client_caps; +} - template - void serialize(Archive &ar, weasel::CandidateInfo &s, const unsigned int version) - { - ar & s.currentPage; - ar & s.totalPages; - ar & s.highlighted; - ar & s.is_last_page; - ar & s.candies; - ar & s.comments; - ar & s.labels; - } - template - void serialize(Archive &ar, weasel::Text &s, const unsigned int version) - { - ar & s.str; - ar & s.attributes; - } - template - void serialize(Archive &ar, weasel::TextAttribute &s, const unsigned int version) - { - ar & s.range; - ar & s.type; - } - template - void serialize(Archive &ar, weasel::TextRange &s, const unsigned int version) - { - ar & s.start; - ar & s.end; - ar & s.cursor; - } - } // namespace serialization -} // namespace boost +template +void serialize(Archive& ar, + weasel::CandidateInfo& s, + const unsigned int version) { + ar & s.currentPage; + ar & s.totalPages; + ar & s.highlighted; + ar & s.is_last_page; + ar & s.candies; + ar & s.comments; + ar & s.labels; +} +template +void serialize(Archive& ar, weasel::Text& s, const unsigned int version) { + ar & s.str; + ar & s.attributes; +} +template +void serialize(Archive& ar, + weasel::TextAttribute& s, + const unsigned int version) { + ar & s.range; + ar & s.type; +} +template +void serialize(Archive& ar, weasel::TextRange& s, const unsigned int version) { + ar & s.start; + ar & s.end; + ar & s.cursor; +} +} // namespace serialization +} // namespace boost diff --git a/include/WeaselIPC.h b/include/WeaselIPC.h index 38eeb445d..770b51d00 100644 --- a/include/WeaselIPC.h +++ b/include/WeaselIPC.h @@ -11,181 +11,178 @@ #define WEASEL_IPC_METADATA_SIZE 1024 #define WEASEL_IPC_BUFFER_SIZE (4 * 1024) #define WEASEL_IPC_BUFFER_LENGTH (WEASEL_IPC_BUFFER_SIZE / sizeof(WCHAR)) -#define WEASEL_IPC_SHARED_MEMORY_SIZE (sizeof(PipeMessage) + WEASEL_IPC_BUFFER_SIZE) - -enum WEASEL_IPC_COMMAND -{ - WEASEL_IPC_ECHO = (WM_APP + 1), - WEASEL_IPC_START_SESSION, - WEASEL_IPC_END_SESSION, - WEASEL_IPC_PROCESS_KEY_EVENT, - WEASEL_IPC_SHUTDOWN_SERVER, - WEASEL_IPC_FOCUS_IN, - WEASEL_IPC_FOCUS_OUT, - WEASEL_IPC_UPDATE_INPUT_POS, - WEASEL_IPC_START_MAINTENANCE, - WEASEL_IPC_END_MAINTENANCE, - WEASEL_IPC_COMMIT_COMPOSITION, - WEASEL_IPC_CLEAR_COMPOSITION, - WEASEL_IPC_TRAY_COMMAND, - WEASEL_IPC_SELECT_CANDIDATE_ON_CURRENT_PAGE, - WEASEL_IPC_HIGHLIGHT_CANDIDATE_ON_CURRENT_PAGE, - WEASEL_IPC_CHANGE_PAGE, - WEASEL_IPC_LAST_COMMAND +#define WEASEL_IPC_SHARED_MEMORY_SIZE \ + (sizeof(PipeMessage) + WEASEL_IPC_BUFFER_SIZE) + +enum WEASEL_IPC_COMMAND { + WEASEL_IPC_ECHO = (WM_APP + 1), + WEASEL_IPC_START_SESSION, + WEASEL_IPC_END_SESSION, + WEASEL_IPC_PROCESS_KEY_EVENT, + WEASEL_IPC_SHUTDOWN_SERVER, + WEASEL_IPC_FOCUS_IN, + WEASEL_IPC_FOCUS_OUT, + WEASEL_IPC_UPDATE_INPUT_POS, + WEASEL_IPC_START_MAINTENANCE, + WEASEL_IPC_END_MAINTENANCE, + WEASEL_IPC_COMMIT_COMPOSITION, + WEASEL_IPC_CLEAR_COMPOSITION, + WEASEL_IPC_TRAY_COMMAND, + WEASEL_IPC_SELECT_CANDIDATE_ON_CURRENT_PAGE, + WEASEL_IPC_HIGHLIGHT_CANDIDATE_ON_CURRENT_PAGE, + WEASEL_IPC_CHANGE_PAGE, + WEASEL_IPC_LAST_COMMAND }; -namespace weasel -{ - struct PipeMessage { - WEASEL_IPC_COMMAND Msg; - UINT wParam; - UINT lParam; - }; - - struct IPCMetadata - { - enum { WINDOW_CLASS_LENGTH = 64 }; - UINT32 server_hwnd; - WCHAR server_window_class[WINDOW_CLASS_LENGTH]; - }; - - struct KeyEvent - { - UINT keycode : 16; - UINT mask : 16; - KeyEvent() : keycode(0), mask(0) {} - KeyEvent(UINT _keycode, UINT _mask) : keycode(_keycode), mask(_mask) {} - KeyEvent(UINT x) - { - *reinterpret_cast(this) = x; - } - operator UINT32 const() const - { - return *reinterpret_cast(this); - } - }; - - // 處理請求之物件 - struct RequestHandler - { - using EatLine = std::function; - RequestHandler() {} - virtual ~RequestHandler() {} - virtual void Initialize() {} - virtual void Finalize() {} - virtual UINT FindSession(UINT session_id) { return 0; } - virtual UINT AddSession(LPWSTR buffer, EatLine eat = 0) { return 0; } - virtual UINT RemoveSession(UINT session_id) { return 0; } - virtual BOOL ProcessKeyEvent(KeyEvent keyEvent, UINT session_id, EatLine eat) { return FALSE; } - virtual void CommitComposition(UINT session_id) {} - virtual void ClearComposition(UINT session_id) {} - virtual void SelectCandidateOnCurrentPage(size_t index, UINT session_id) {} - virtual bool HighlightCandidateOnCurrentPage(size_t index, UINT session_id, EatLine eat) {return false;} - virtual bool ChangePage(bool backward, UINT session_id, EatLine eat) {return false;} - virtual void FocusIn(DWORD param, UINT session_id) {} - virtual void FocusOut(DWORD param, UINT session_id) {} - virtual void UpdateInputPosition(RECT const& rc, UINT session_id) {} - virtual void StartMaintenance() {} - virtual void EndMaintenance() {} - virtual void SetOption(UINT session_id, const std::string &opt, bool val) {} - virtual void UpdateColorTheme(BOOL darkMode) {} - }; - - // 處理server端回應之物件 - typedef std::function ResponseHandler; - - // 事件處理函數 - typedef std::function CommandHandler; - - // 啟動服務進程之物件 - typedef CommandHandler ServerLauncher; - - - // IPC實現類聲明 - - class ClientImpl; - class ServerImpl; - - // IPC接口類 - - class Client - { - public: - - Client(); - virtual ~Client(); - - // 连接到服务,必要时启动服务进程 - bool Connect(ServerLauncher launcher = 0); - // 断开连接 - void Disconnect(); - // 终止服务 - void ShutdownServer(); - // 發起會話 - void StartSession(); - // 結束會話 - void EndSession(); - // 進入維護模式 - void StartMaintenance(); - // 退出維護模式 - void EndMaintenance(); - // 测试连接 - bool Echo(); - // 请求服务处理按键消息 - bool ProcessKeyEvent(KeyEvent const& keyEvent); - // 上屏正在編輯的文字 - bool CommitComposition(); - // 清除正在編輯的文字 - bool ClearComposition(); - // 选择当前页面编号为index的候选 - bool SelectCandidateOnCurrentPage(size_t index); - // 高亮当前页面编号为index的候选 - bool HighlightCandidateOnCurrentPage(size_t index); - // 翻页,backward = true 向前翻,false向后翻 - bool ChangePage(bool backward); - // 更新输入位置 - void UpdateInputPosition(RECT const& rc); - // 输入窗口获得焦点 - void FocusIn(); - // 输入窗口失去焦点 - void FocusOut(); - // 托盤菜單 - void TrayCommand(UINT menuId); - // 读取server返回的数据 - bool GetResponseData(ResponseHandler handler); - - private: - ClientImpl* m_pImpl; - }; - - class Server - { - public: - Server(); - virtual ~Server(); - - // 初始化服务 - int Start(); - // 结束服务 - int Stop(); - // 消息循环 - int Run(); - - void SetRequestHandler(RequestHandler* pHandler); - void AddMenuHandler(UINT uID, CommandHandler handler); - HWND GetHWnd(); - - private: - ServerImpl* m_pImpl; - }; - - inline std::wstring GetPipeName() - { - std::wstring pipe_name; - pipe_name += L"\\\\.\\pipe\\"; - pipe_name += getUsername(); - pipe_name += L"\\"; - pipe_name += WEASEL_IPC_PIPE_NAME; - return pipe_name; - } +namespace weasel { +struct PipeMessage { + WEASEL_IPC_COMMAND Msg; + UINT wParam; + UINT lParam; +}; + +struct IPCMetadata { + enum { WINDOW_CLASS_LENGTH = 64 }; + UINT32 server_hwnd; + WCHAR server_window_class[WINDOW_CLASS_LENGTH]; +}; + +struct KeyEvent { + UINT keycode : 16; + UINT mask : 16; + KeyEvent() : keycode(0), mask(0) {} + KeyEvent(UINT _keycode, UINT _mask) : keycode(_keycode), mask(_mask) {} + KeyEvent(UINT x) { *reinterpret_cast(this) = x; } + operator UINT32 const() const { + return *reinterpret_cast(this); + } +}; + +// 處理請求之物件 +struct RequestHandler { + using EatLine = std::function; + RequestHandler() {} + virtual ~RequestHandler() {} + virtual void Initialize() {} + virtual void Finalize() {} + virtual UINT FindSession(UINT session_id) { return 0; } + virtual UINT AddSession(LPWSTR buffer, EatLine eat = 0) { return 0; } + virtual UINT RemoveSession(UINT session_id) { return 0; } + virtual BOOL ProcessKeyEvent(KeyEvent keyEvent, + UINT session_id, + EatLine eat) { + return FALSE; + } + virtual void CommitComposition(UINT session_id) {} + virtual void ClearComposition(UINT session_id) {} + virtual void SelectCandidateOnCurrentPage(size_t index, UINT session_id) {} + virtual bool HighlightCandidateOnCurrentPage(size_t index, + UINT session_id, + EatLine eat) { + return false; + } + virtual bool ChangePage(bool backward, UINT session_id, EatLine eat) { + return false; + } + virtual void FocusIn(DWORD param, UINT session_id) {} + virtual void FocusOut(DWORD param, UINT session_id) {} + virtual void UpdateInputPosition(RECT const& rc, UINT session_id) {} + virtual void StartMaintenance() {} + virtual void EndMaintenance() {} + virtual void SetOption(UINT session_id, const std::string& opt, bool val) {} + virtual void UpdateColorTheme(BOOL darkMode) {} +}; + +// 處理server端回應之物件 +typedef std::function ResponseHandler; + +// 事件處理函數 +typedef std::function CommandHandler; + +// 啟動服務進程之物件 +typedef CommandHandler ServerLauncher; + +// IPC實現類聲明 + +class ClientImpl; +class ServerImpl; + +// IPC接口類 + +class Client { + public: + Client(); + virtual ~Client(); + + // 连接到服务,必要时启动服务进程 + bool Connect(ServerLauncher launcher = 0); + // 断开连接 + void Disconnect(); + // 终止服务 + void ShutdownServer(); + // 發起會話 + void StartSession(); + // 結束會話 + void EndSession(); + // 進入維護模式 + void StartMaintenance(); + // 退出維護模式 + void EndMaintenance(); + // 测试连接 + bool Echo(); + // 请求服务处理按键消息 + bool ProcessKeyEvent(KeyEvent const& keyEvent); + // 上屏正在編輯的文字 + bool CommitComposition(); + // 清除正在編輯的文字 + bool ClearComposition(); + // 选择当前页面编号为index的候选 + bool SelectCandidateOnCurrentPage(size_t index); + // 高亮当前页面编号为index的候选 + bool HighlightCandidateOnCurrentPage(size_t index); + // 翻页,backward = true 向前翻,false向后翻 + bool ChangePage(bool backward); + // 更新输入位置 + void UpdateInputPosition(RECT const& rc); + // 输入窗口获得焦点 + void FocusIn(); + // 输入窗口失去焦点 + void FocusOut(); + // 托盤菜單 + void TrayCommand(UINT menuId); + // 读取server返回的数据 + bool GetResponseData(ResponseHandler handler); + + private: + ClientImpl* m_pImpl; +}; + +class Server { + public: + Server(); + virtual ~Server(); + + // 初始化服务 + int Start(); + // 结束服务 + int Stop(); + // 消息循环 + int Run(); + + void SetRequestHandler(RequestHandler* pHandler); + void AddMenuHandler(UINT uID, CommandHandler handler); + HWND GetHWnd(); + + private: + ServerImpl* m_pImpl; +}; + +inline std::wstring GetPipeName() { + std::wstring pipe_name; + pipe_name += L"\\\\.\\pipe\\"; + pipe_name += getUsername(); + pipe_name += L"\\"; + pipe_name += WEASEL_IPC_PIPE_NAME; + return pipe_name; } +} // namespace weasel diff --git a/include/WeaselUI.h b/include/WeaselUI.h index 43e924e23..1ded6a29e 100644 --- a/include/WeaselUI.h +++ b/include/WeaselUI.h @@ -10,147 +10,163 @@ #include #include using namespace Microsoft::WRL; -namespace weasel -{ - - template void SafeRelease(T** ppT) - { - if (*ppT) - { - (*ppT)->Release(); - *ppT = NULL; - } - } - - enum ClientCapabilities - { - INLINE_PREEDIT_CAPABLE = 1, - }; - - class UIImpl; - class DirectWriteResources; - template - using an = std::shared_ptr; - - using PDWR = an; - // - // 输入法界面接口类 - // - class UI - { - public: - UI() : pimpl_(0) - { } - - virtual ~UI() - { - if (pimpl_) - Destroy(true); - if (pDWR) - { - pDWR.reset(); - } - } - - // 创建输入法界面 - bool Create(HWND parent); - - // 销毁界面 - void Destroy(bool full = false); - - // 界面显隐 - void Show(); - void Hide(); - void ShowWithTimeout(size_t millisec); - bool IsCountingDown() const; - bool IsShown() const; - - // 重绘界面 - void Refresh(); - - // 置输入焦点位置(光标跟随时移动候选窗)但不重绘 - void UpdateInputPosition(RECT const& rc); - - // 更新界面显示内容 - void Update(Context const& ctx, Status const& status); - - Context& ctx() { return ctx_; } - Context& octx() { return octx_; } - Status& status() { return status_; } - UIStyle& style() { return style_; } - UIStyle& ostyle() { return ostyle_; } - PDWR pdwr() { return pDWR; } - bool GetIsReposition(); - - std::function& uiCallback() { return _UICallback; } - void SetUICallBack(std::function const & func) { _UICallback = func; } - - private: - UIImpl* pimpl_; - PDWR pDWR; - - Context ctx_; - Context octx_; - Status status_; - UIStyle style_; - UIStyle ostyle_; - std::function _UICallback; - }; - - class DirectWriteResources - { - public: - DirectWriteResources(weasel::UIStyle& style, UINT dpi); - ~DirectWriteResources(); - - HRESULT InitResources(const std::wstring& label_font_face, const int& label_font_point, - const std::wstring& font_face, const int& font_point, - const std::wstring& comment_font_face, const int& comment_font_point, const bool& vertical_text = false); - HRESULT InitResources(const UIStyle& style, const UINT& dpi); - - HRESULT CreateTextLayout(const std::wstring& text, const int& nCount, IDWriteTextFormat1* const txtFormat, const float& width, const float& height) { - return pDWFactory->CreateTextLayout(text.c_str(), nCount, txtFormat, width, height, reinterpret_cast(pTextLayout.GetAddressOf())); - } - void DrawRect(D2D1_RECT_F* const rect,const float& strokeWidth=1.0f, ID2D1StrokeStyle* const sstyle=(ID2D1StrokeStyle*)0) { - pRenderTarget->DrawRectangle(rect, pBrush.Get(), strokeWidth, sstyle); - } - HRESULT GetLayoutOverhangMetrics(DWRITE_OVERHANG_METRICS* overhangMetrics) { - return pTextLayout->GetOverhangMetrics(overhangMetrics); - } - HRESULT GetLayoutMetrics(DWRITE_TEXT_METRICS* metrics) { - return pTextLayout->GetMetrics(metrics); - } - HRESULT SetLayoutReadingDirection(const DWRITE_READING_DIRECTION& direct) { - return pTextLayout->SetReadingDirection(direct); - } - HRESULT SetLayoutFlowDirection(const DWRITE_FLOW_DIRECTION& direct) { - return pTextLayout->SetFlowDirection(direct); - } - void DrawTextLayoutAt(const D2D1_POINT_2F& point) { - pRenderTarget->DrawTextLayout(point, pTextLayout.Get(), pBrush.Get(), D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT); - } - HRESULT CreateBrush(const D2D1_COLOR_F& color) { - return pRenderTarget->CreateSolidColorBrush(color, pBrush.GetAddressOf()); - } - void ResetLayout() { pTextLayout.Reset(); } - void SetBrushColor(const D2D1_COLOR_F& color) { - pBrush->SetColor(color); - } - void SetDpi(const UINT& dpi); - - float dpiScaleX_, dpiScaleY_; - ComPtr pD2d1Factory; - ComPtr pDWFactory; - ComPtr pRenderTarget; - ComPtr pPreeditTextFormat; - ComPtr pTextFormat; - ComPtr pLabelTextFormat; - ComPtr pCommentTextFormat; - ComPtr pTextLayout; - ComPtr pBrush; - private: - UIStyle& _style; - void _ParseFontFace(const std::wstring& fontFaceStr, DWRITE_FONT_WEIGHT& fontWeight, DWRITE_FONT_STYLE& fontStyle); - void _SetFontFallback(ComPtr pTextFormat, const std::vector& fontVector); - }; +namespace weasel { + +template +void SafeRelease(T** ppT) { + if (*ppT) { + (*ppT)->Release(); + *ppT = NULL; + } } + +enum ClientCapabilities { + INLINE_PREEDIT_CAPABLE = 1, +}; + +class UIImpl; +class DirectWriteResources; +template +using an = std::shared_ptr; + +using PDWR = an; +// +// 输入法界面接口类 +// +class UI { + public: + UI() : pimpl_(0) {} + + virtual ~UI() { + if (pimpl_) + Destroy(true); + if (pDWR) { + pDWR.reset(); + } + } + + // 创建输入法界面 + bool Create(HWND parent); + + // 销毁界面 + void Destroy(bool full = false); + + // 界面显隐 + void Show(); + void Hide(); + void ShowWithTimeout(size_t millisec); + bool IsCountingDown() const; + bool IsShown() const; + + // 重绘界面 + void Refresh(); + + // 置输入焦点位置(光标跟随时移动候选窗)但不重绘 + void UpdateInputPosition(RECT const& rc); + + // 更新界面显示内容 + void Update(Context const& ctx, Status const& status); + + Context& ctx() { return ctx_; } + Context& octx() { return octx_; } + Status& status() { return status_; } + UIStyle& style() { return style_; } + UIStyle& ostyle() { return ostyle_; } + PDWR pdwr() { return pDWR; } + bool GetIsReposition(); + + std::function& + uiCallback() { + return _UICallback; + } + void SetUICallBack( + std::function< + void(size_t* const, size_t* const, bool* const, bool* const)> const& + func) { + _UICallback = func; + } + + private: + UIImpl* pimpl_; + PDWR pDWR; + + Context ctx_; + Context octx_; + Status status_; + UIStyle style_; + UIStyle ostyle_; + std::function + _UICallback; +}; + +class DirectWriteResources { + public: + DirectWriteResources(weasel::UIStyle& style, UINT dpi); + ~DirectWriteResources(); + + HRESULT InitResources(const std::wstring& label_font_face, + const int& label_font_point, + const std::wstring& font_face, + const int& font_point, + const std::wstring& comment_font_face, + const int& comment_font_point, + const bool& vertical_text = false); + HRESULT InitResources(const UIStyle& style, const UINT& dpi); + + HRESULT CreateTextLayout(const std::wstring& text, + const int& nCount, + IDWriteTextFormat1* const txtFormat, + const float& width, + const float& height) { + return pDWFactory->CreateTextLayout( + text.c_str(), nCount, txtFormat, width, height, + reinterpret_cast(pTextLayout.GetAddressOf())); + } + void DrawRect(D2D1_RECT_F* const rect, + const float& strokeWidth = 1.0f, + ID2D1StrokeStyle* const sstyle = (ID2D1StrokeStyle*)0) { + pRenderTarget->DrawRectangle(rect, pBrush.Get(), strokeWidth, sstyle); + } + HRESULT GetLayoutOverhangMetrics(DWRITE_OVERHANG_METRICS* overhangMetrics) { + return pTextLayout->GetOverhangMetrics(overhangMetrics); + } + HRESULT GetLayoutMetrics(DWRITE_TEXT_METRICS* metrics) { + return pTextLayout->GetMetrics(metrics); + } + HRESULT SetLayoutReadingDirection(const DWRITE_READING_DIRECTION& direct) { + return pTextLayout->SetReadingDirection(direct); + } + HRESULT SetLayoutFlowDirection(const DWRITE_FLOW_DIRECTION& direct) { + return pTextLayout->SetFlowDirection(direct); + } + void DrawTextLayoutAt(const D2D1_POINT_2F& point) { + pRenderTarget->DrawTextLayout(point, pTextLayout.Get(), pBrush.Get(), + D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT); + } + HRESULT CreateBrush(const D2D1_COLOR_F& color) { + return pRenderTarget->CreateSolidColorBrush(color, pBrush.GetAddressOf()); + } + void ResetLayout() { pTextLayout.Reset(); } + void SetBrushColor(const D2D1_COLOR_F& color) { pBrush->SetColor(color); } + void SetDpi(const UINT& dpi); + + float dpiScaleX_, dpiScaleY_; + ComPtr pD2d1Factory; + ComPtr pDWFactory; + ComPtr pRenderTarget; + ComPtr pPreeditTextFormat; + ComPtr pTextFormat; + ComPtr pLabelTextFormat; + ComPtr pCommentTextFormat; + ComPtr pTextLayout; + ComPtr pBrush; + + private: + UIStyle& _style; + void _ParseFontFace(const std::wstring& fontFaceStr, + DWRITE_FONT_WEIGHT& fontWeight, + DWRITE_FONT_STYLE& fontStyle); + void _SetFontFallback(ComPtr pTextFormat, + const std::vector& fontVector); +}; +} // namespace weasel diff --git a/include/WeaselUtility.h b/include/WeaselUtility.h index dd0aec4d2..88cb0cfbd 100644 --- a/include/WeaselUtility.h +++ b/include/WeaselUtility.h @@ -2,79 +2,87 @@ #include #include -inline int utf8towcslen(const char* utf8_str, int utf8_len) -{ - return MultiByteToWideChar(CP_UTF8, 0, utf8_str, utf8_len, NULL, 0); +inline int utf8towcslen(const char* utf8_str, int utf8_len) { + return MultiByteToWideChar(CP_UTF8, 0, utf8_str, utf8_len, NULL, 0); } inline std::wstring getUsername() { - DWORD len = 0; - GetUserName(NULL, &len); + DWORD len = 0; + GetUserName(NULL, &len); - if (len <= 0) { - return L""; - } + if (len <= 0) { + return L""; + } - wchar_t *username = new wchar_t[len + 1]; + wchar_t* username = new wchar_t[len + 1]; - GetUserName(username, &len); - if (len <= 0) { - delete[] username; - return L""; - } - auto res = std::wstring(username); - delete[] username; - return res; + GetUserName(username, &len); + if (len <= 0) { + delete[] username; + return L""; + } + auto res = std::wstring(username); + delete[] username; + return res; } // data directories boost::filesystem::path WeaselSharedDataPath(); boost::filesystem::path WeaselUserDataPath(); -inline BOOL IsUserDarkMode() -{ - constexpr const LPCWSTR key = L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; - constexpr const LPCWSTR value = L"AppsUseLightTheme"; +inline BOOL IsUserDarkMode() { + constexpr const LPCWSTR key = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; + constexpr const LPCWSTR value = L"AppsUseLightTheme"; - DWORD type; - DWORD data; - DWORD size = sizeof(DWORD); - LSTATUS st = RegGetValue(HKEY_CURRENT_USER, key, value, RRF_RT_REG_DWORD, &type, &data, &size); + DWORD type; + DWORD data; + DWORD size = sizeof(DWORD); + LSTATUS st = RegGetValue(HKEY_CURRENT_USER, key, value, RRF_RT_REG_DWORD, + &type, &data, &size); - if (st == ERROR_SUCCESS && type == REG_DWORD) return data == 0; - return false; + if (st == ERROR_SUCCESS && type == REG_DWORD) + return data == 0; + return false; } -inline std::wstring string_to_wstring(const std::string& str, int code_page = CP_ACP) -{ - // support CP_ACP and CP_UTF8 only - if (code_page != 0 && code_page != CP_UTF8) return L""; - // calc len - int len = MultiByteToWideChar(code_page, 0, str.c_str(), (int)str.size(), NULL, 0); - if(len <= 0) return L""; - std::wstring res; - TCHAR* buffer = new TCHAR[len + 1]; - MultiByteToWideChar(code_page, 0, str.c_str(), (int)str.size(), buffer, len); - buffer[len] = '\0'; - res.append(buffer); - delete[] buffer; - return res; +inline std::wstring string_to_wstring(const std::string& str, + int code_page = CP_ACP) { + // support CP_ACP and CP_UTF8 only + if (code_page != 0 && code_page != CP_UTF8) + return L""; + // calc len + int len = + MultiByteToWideChar(code_page, 0, str.c_str(), (int)str.size(), NULL, 0); + if (len <= 0) + return L""; + std::wstring res; + TCHAR* buffer = new TCHAR[len + 1]; + MultiByteToWideChar(code_page, 0, str.c_str(), (int)str.size(), buffer, len); + buffer[len] = '\0'; + res.append(buffer); + delete[] buffer; + return res; } -inline std::string wstring_to_string(const std::wstring& wstr, int code_page = CP_ACP) -{ - // support CP_ACP and CP_UTF8 only - if (code_page != 0 && code_page != CP_UTF8) return ""; - int len = WideCharToMultiByte(code_page, 0, wstr.c_str(), (int)wstr.size(), NULL, 0, NULL, NULL); - if(len <= 0) return ""; - std::string res; - char* buffer = new char[len + 1]; - WideCharToMultiByte(code_page, 0, wstr.c_str(), (int)wstr.size(), buffer, len, NULL, NULL); - buffer[len] = '\0'; - res.append(buffer); - delete[] buffer; - return res; +inline std::string wstring_to_string(const std::wstring& wstr, + int code_page = CP_ACP) { + // support CP_ACP and CP_UTF8 only + if (code_page != 0 && code_page != CP_UTF8) + return ""; + int len = WideCharToMultiByte(code_page, 0, wstr.c_str(), (int)wstr.size(), + NULL, 0, NULL, NULL); + if (len <= 0) + return ""; + std::string res; + char* buffer = new char[len + 1]; + WideCharToMultiByte(code_page, 0, wstr.c_str(), (int)wstr.size(), buffer, len, + NULL, NULL); + buffer[len] = '\0'; + res.append(buffer); + delete[] buffer; + return res; } // resource -std::string GetCustomResource(const char *name, const char *type); +std::string GetCustomResource(const char* name, const char* type); diff --git a/include/WeaselVersion.h b/include/WeaselVersion.h index e547c9b99..b46a49622 100644 --- a/include/WeaselVersion.h +++ b/include/WeaselVersion.h @@ -1,7 +1,7 @@ #pragma once #define WEASEL_VERSION_STR "0.15.0.0" -#define WEASEL_VERSION_NUM 0,15,0,0 +#define WEASEL_VERSION_NUM 0, 15, 0, 0 #define WEASEL_CODE_NAME "Weasel" #define WEASEL_VERSION WEASEL_VERSION_STR diff --git a/include/no_logging.h b/include/no_logging.h index d4b734847..ddf69fd1f 100644 --- a/include/no_logging.h +++ b/include/no_logging.h @@ -11,19 +11,22 @@ class VoidLogger { VoidLogger& stream() { return *this; } template - VoidLogger& operator<< (const T& x) { return *this; } + VoidLogger& operator<<(const T& x) { + return *this; + } }; // to avoid compiler warnings class Voidify { public: Voidify() {} - void operator& (VoidLogger&) {} + void operator&(VoidLogger&) {} }; } // namespace rime -#define RIME_NO_LOG true ? (void) 0 : rime::Voidify() & rime::VoidLogger().stream() +#define RIME_NO_LOG \ + true ? (void)0 : rime::Voidify() & rime::VoidLogger().stream() #define LOG(severity) RIME_NO_LOG #define VLOG(verboselevel) RIME_NO_LOG @@ -32,7 +35,7 @@ class Voidify { #define LOG_IF_EVERY_N(severity, condition, n) RIME_NO_LOG #define LOG_ASSERT(condition) RIME_NO_LOG -#define RIME_NO_CHECK (void) 0 +#define RIME_NO_CHECK (void)0 #define CHECK(condition) RIME_NO_CHECK #define CHECK_EQ(val1, val2) RIME_NO_CHECK diff --git a/test/TestResponseParser/TestResponseParser.cpp b/test/TestResponseParser/TestResponseParser.cpp index e0eda9df7..643fd6782 100644 --- a/test/TestResponseParser/TestResponseParser.cpp +++ b/test/TestResponseParser/TestResponseParser.cpp @@ -6,102 +6,91 @@ #include #include -void test_1() -{ - WCHAR resp[] = - L"action=noop\n" - ; - DWORD len = wcslen(resp); - std::wstring commit; - weasel::Context ctx; - weasel::Status status; - weasel::ResponseParser parser(&commit, &ctx, &status); - parser(resp, len); - BOOST_TEST(commit.empty()); - BOOST_TEST(ctx.empty()); +void test_1() { + WCHAR resp[] = L"action=noop\n"; + DWORD len = wcslen(resp); + std::wstring commit; + weasel::Context ctx; + weasel::Status status; + weasel::ResponseParser parser(&commit, &ctx, &status); + parser(resp, len); + BOOST_TEST(commit.empty()); + BOOST_TEST(ctx.empty()); } -void test_2() -{ - WCHAR resp[] = - L"action=commit\n" - L"commit=教這句話上屏=3.14\n" - ; - DWORD len = wcslen(resp); - std::wstring commit; - weasel::Context ctx; - weasel::Status status; - ctx.aux.str = L"從前的值"; - weasel::ResponseParser parser(&commit, &ctx, &status); - parser(resp, len); - BOOST_TEST(commit == L"教這句話上屏=3.14"); - BOOST_TEST(ctx.preedit.empty()); - BOOST_TEST(ctx.aux.str == L"從前的值"); - BOOST_TEST(ctx.cinfo.candies.empty()); +void test_2() { + WCHAR resp[] = + L"action=commit\n" + L"commit=教這句話上屏=3.14\n"; + DWORD len = wcslen(resp); + std::wstring commit; + weasel::Context ctx; + weasel::Status status; + ctx.aux.str = L"從前的值"; + weasel::ResponseParser parser(&commit, &ctx, &status); + parser(resp, len); + BOOST_TEST(commit == L"教這句話上屏=3.14"); + BOOST_TEST(ctx.preedit.empty()); + BOOST_TEST(ctx.aux.str == L"從前的值"); + BOOST_TEST(ctx.cinfo.candies.empty()); } -void test_3() -{ - WCHAR resp[] = - L"action=ctx\n" - L"ctx.preedit=寫作串=3.14\n" - L"ctx.aux=sie'zuoh'chuan=3.14\n" - ; - DWORD len = wcslen(resp); - std::wstring commit; - weasel::Context ctx; - weasel::Status status; - weasel::ResponseParser parser(&commit, &ctx, &status); - parser(resp, len); - BOOST_TEST(commit.empty()); - BOOST_TEST(ctx.preedit.str == L"寫作串=3.14"); - BOOST_TEST(ctx.preedit.attributes.empty()); - BOOST_TEST(ctx.aux.str == L"sie'zuoh'chuan=3.14"); +void test_3() { + WCHAR resp[] = + L"action=ctx\n" + L"ctx.preedit=寫作串=3.14\n" + L"ctx.aux=sie'zuoh'chuan=3.14\n"; + DWORD len = wcslen(resp); + std::wstring commit; + weasel::Context ctx; + weasel::Status status; + weasel::ResponseParser parser(&commit, &ctx, &status); + parser(resp, len); + BOOST_TEST(commit.empty()); + BOOST_TEST(ctx.preedit.str == L"寫作串=3.14"); + BOOST_TEST(ctx.preedit.attributes.empty()); + BOOST_TEST(ctx.aux.str == L"sie'zuoh'chuan=3.14"); } -void test_4() -{ - WCHAR resp[] = - L"action=commit,ctx\n" - L"ctx.preedit=候選乙=3.14\n" - L"ctx.preedit.cursor=0,3\n" - L"ctx.cand.length=2\n" - L"ctx.cand.0=候選甲\n" - L"ctx.cand.1=候選乙\n" - L"ctx.cand.cursor=1\n" - L"ctx.cand.page=0/1\n" - ; - DWORD len = wcslen(resp); - std::wstring commit; - weasel::Context ctx; - weasel::Status status; - weasel::ResponseParser parser(&commit, &ctx, &status); - parser(resp, len); - BOOST_TEST(commit.empty()); - BOOST_TEST(ctx.preedit.str == L"候選乙=3.14"); - BOOST_ASSERT(1 == ctx.preedit.attributes.size()); - weasel::TextAttribute attr0 = ctx.preedit.attributes[0]; - BOOST_TEST_EQ(weasel::HIGHLIGHTED, attr0.type); - BOOST_TEST_EQ(0, attr0.range.start); - BOOST_TEST_EQ(3, attr0.range.end); - BOOST_TEST(ctx.aux.empty()); - weasel::CandidateInfo& c = ctx.cinfo; - BOOST_ASSERT(2 == c.candies.size()); - BOOST_TEST(c.candies[0].str == L"候選甲"); - BOOST_TEST(c.candies[1].str == L"候選乙"); - BOOST_TEST_EQ(1, c.highlighted); - BOOST_TEST_EQ(0, c.currentPage); - BOOST_TEST_EQ(1, c.totalPages); +void test_4() { + WCHAR resp[] = + L"action=commit,ctx\n" + L"ctx.preedit=候選乙=3.14\n" + L"ctx.preedit.cursor=0,3\n" + L"ctx.cand.length=2\n" + L"ctx.cand.0=候選甲\n" + L"ctx.cand.1=候選乙\n" + L"ctx.cand.cursor=1\n" + L"ctx.cand.page=0/1\n"; + DWORD len = wcslen(resp); + std::wstring commit; + weasel::Context ctx; + weasel::Status status; + weasel::ResponseParser parser(&commit, &ctx, &status); + parser(resp, len); + BOOST_TEST(commit.empty()); + BOOST_TEST(ctx.preedit.str == L"候選乙=3.14"); + BOOST_ASSERT(1 == ctx.preedit.attributes.size()); + weasel::TextAttribute attr0 = ctx.preedit.attributes[0]; + BOOST_TEST_EQ(weasel::HIGHLIGHTED, attr0.type); + BOOST_TEST_EQ(0, attr0.range.start); + BOOST_TEST_EQ(3, attr0.range.end); + BOOST_TEST(ctx.aux.empty()); + weasel::CandidateInfo& c = ctx.cinfo; + BOOST_ASSERT(2 == c.candies.size()); + BOOST_TEST(c.candies[0].str == L"候選甲"); + BOOST_TEST(c.candies[1].str == L"候選乙"); + BOOST_TEST_EQ(1, c.highlighted); + BOOST_TEST_EQ(0, c.currentPage); + BOOST_TEST_EQ(1, c.totalPages); } -int _tmain(int argc, _TCHAR* argv[]) -{ - test_1(); - test_2(); - test_3(); - test_4(); +int _tmain(int argc, _TCHAR* argv[]) { + test_1(); + test_2(); + test_3(); + test_4(); - system("pause"); - return boost::report_errors(); + system("pause"); + return boost::report_errors(); } - diff --git a/test/TestWeaselIPC/TestWeaselIPC.cpp b/test/TestWeaselIPC/TestWeaselIPC.cpp index 45e653ad4..13b245099 100644 --- a/test/TestWeaselIPC/TestWeaselIPC.cpp +++ b/test/TestWeaselIPC/TestWeaselIPC.cpp @@ -19,182 +19,164 @@ int server_main(); // usage: TestWeaselIPC.exe [/start | /stop | /console] -int _tmain(int argc, _TCHAR* argv[]) -{ - if (argc == 1) // no args - { - return client_main(); - } - else if(argc > 1 && !wcscmp(L"/start", argv[1])) - { - return server_main(); - } - else if (argc > 1 && !wcscmp(L"/stop", argv[1])) - { - weasel::Client client; - if (!client.Connect()) - { - std::cerr << "server not running." << std::endl; - return 0; - } - client.ShutdownServer(); - return 0; - } - else if (argc > 1 && !wcscmp(L"/console", argv[1])) - { - return console_main(); - return 0; - } - - return -1; +int _tmain(int argc, _TCHAR* argv[]) { + if (argc == 1) // no args + { + return client_main(); + } else if (argc > 1 && !wcscmp(L"/start", argv[1])) { + return server_main(); + } else if (argc > 1 && !wcscmp(L"/stop", argv[1])) { + weasel::Client client; + if (!client.Connect()) { + std::cerr << "server not running." << std::endl; + return 0; + } + client.ShutdownServer(); + return 0; + } else if (argc > 1 && !wcscmp(L"/console", argv[1])) { + return console_main(); + return 0; + } + + return -1; } -bool launch_server() -{ - int ret = (int)ShellExecute( NULL, L"open", L"TestWeaselIPC.exe", L"/start", NULL, SW_NORMAL); - if (ret <= 32) - { - std::cerr << "failed to launch server." << std::endl; - return false; - } - return true; +bool launch_server() { + int ret = (int)ShellExecute(NULL, L"open", L"TestWeaselIPC.exe", L"/start", + NULL, SW_NORMAL); + if (ret <= 32) { + std::cerr << "failed to launch server." << std::endl; + return false; + } + return true; } -bool read_buffer(LPWSTR buffer, UINT length, LPWSTR dest) -{ - wbufferstream bs(buffer, length); - bs.read(dest, WEASEL_IPC_BUFFER_LENGTH); - return bs.good(); +bool read_buffer(LPWSTR buffer, UINT length, LPWSTR dest) { + wbufferstream bs(buffer, length); + bs.read(dest, WEASEL_IPC_BUFFER_LENGTH); + return bs.good(); } -const char* wcstomb(const wchar_t* wcs) -{ - const int buffer_len = 8192; - static char buffer[buffer_len]; - WideCharToMultiByte(CP_OEMCP, NULL, wcs, -1, buffer, buffer_len, NULL, FALSE); - return buffer; +const char* wcstomb(const wchar_t* wcs) { + const int buffer_len = 8192; + static char buffer[buffer_len]; + WideCharToMultiByte(CP_OEMCP, NULL, wcs, -1, buffer, buffer_len, NULL, FALSE); + return buffer; } -int console_main() -{ - weasel::Client client; - if (!client.Connect()) - { - std::cerr << "failed to connect to server." << std::endl; - return -2; - } - client.StartSession(); - if (!client.Echo()) - { - std::cerr << "failed to start session." << std::endl; - return -3; - } - - while (std::cin.good()) - { - int ch = std::cin.get(); - if (!std::cin.good()) - break; - bool eaten = client.ProcessKeyEvent(weasel::KeyEvent(ch, 0)); - std::cout << "server replies: " << eaten << std::endl; - if (eaten) - { - WCHAR response[WEASEL_IPC_BUFFER_LENGTH]; - bool ret = client.GetResponseData(std::bind(read_buffer, std::placeholders::_1, std::placeholders::_2, std::ref(response))); - std::cout << "get response data: " << ret << std::endl; - std::cout << "buffer reads: " << std::endl << wcstomb(response) << std::endl; - } - } - - client.EndSession(); - - return 0; +int console_main() { + weasel::Client client; + if (!client.Connect()) { + std::cerr << "failed to connect to server." << std::endl; + return -2; + } + client.StartSession(); + if (!client.Echo()) { + std::cerr << "failed to start session." << std::endl; + return -3; + } + + while (std::cin.good()) { + int ch = std::cin.get(); + if (!std::cin.good()) + break; + bool eaten = client.ProcessKeyEvent(weasel::KeyEvent(ch, 0)); + std::cout << "server replies: " << eaten << std::endl; + if (eaten) { + WCHAR response[WEASEL_IPC_BUFFER_LENGTH]; + bool ret = client.GetResponseData( + std::bind(read_buffer, std::placeholders::_1, + std::placeholders::_2, std::ref(response))); + std::cout << "get response data: " << ret << std::endl; + std::cout << "buffer reads: " << std::endl + << wcstomb(response) << std::endl; + } + } + + client.EndSession(); + + return 0; } -int client_main() -{ - //launch_server(); - Sleep(1000); - weasel::Client client; - if (!client.Connect()) - { - std::cerr << "failed to connect to server." << std::endl; - return -2; - } - client.StartSession(); - if (!client.Echo()) - { - std::cerr << "failed to login." << std::endl; - return -3; - } - bool eaten = client.ProcessKeyEvent(weasel::KeyEvent(L'A', 0)); - std::cout << "server replies: " << eaten << std::endl; - if (eaten) - { - WCHAR response[WEASEL_IPC_BUFFER_LENGTH]; - bool ret = client.GetResponseData(std::bind(read_buffer, std::placeholders::_1, std::placeholders::_2, std::ref(response))); - std::cout << "get response data: " << ret << std::endl; - std::cout << "buffer reads: " << std::endl << wcstomb(response) << std::endl; - } - client.EndSession(); - - system("pause"); - return 0; +int client_main() { + // launch_server(); + Sleep(1000); + weasel::Client client; + if (!client.Connect()) { + std::cerr << "failed to connect to server." << std::endl; + return -2; + } + client.StartSession(); + if (!client.Echo()) { + std::cerr << "failed to login." << std::endl; + return -3; + } + bool eaten = client.ProcessKeyEvent(weasel::KeyEvent(L'A', 0)); + std::cout << "server replies: " << eaten << std::endl; + if (eaten) { + WCHAR response[WEASEL_IPC_BUFFER_LENGTH]; + bool ret = client.GetResponseData( + std::bind(read_buffer, std::placeholders::_1, + std::placeholders::_2, std::ref(response))); + std::cout << "get response data: " << ret << std::endl; + std::cout << "buffer reads: " << std::endl + << wcstomb(response) << std::endl; + } + client.EndSession(); + + system("pause"); + return 0; } -class TestRequestHandler : public weasel::RequestHandler -{ -public: - TestRequestHandler() : m_counter(0) - { - std::cerr << "handler ctor." << std::endl; - } - virtual ~TestRequestHandler() - { - std::cerr << "handler dtor: " << m_counter << std::endl; - } - virtual UINT FindSession(UINT session_id) - { - std::cerr << "FindSession: " << session_id << std::endl; - return (session_id <= m_counter ? session_id : 0); - } - virtual UINT AddSession(LPWSTR buffer) - { - std::cerr << "AddSession: " << m_counter + 1 << std::endl; - return ++m_counter; - } - virtual UINT RemoveSession(UINT session_id) - { - std::cerr << "RemoveClient: " << session_id << std::endl; - return 0; - } - virtual BOOL ProcessKeyEvent(weasel::KeyEvent keyEvent, UINT session_id, EatLine eat) { - std::cerr << "ProcessKeyEvent: " << session_id - << " keycode: " << keyEvent.keycode - << " mask: " << keyEvent.mask - << std::endl; - eat(std::wstring(L"Greeting=Hello, 小狼毫.\n")); - return TRUE; - } -private: - unsigned int m_counter; +class TestRequestHandler : public weasel::RequestHandler { + public: + TestRequestHandler() : m_counter(0) { + std::cerr << "handler ctor." << std::endl; + } + virtual ~TestRequestHandler() { + std::cerr << "handler dtor: " << m_counter << std::endl; + } + virtual UINT FindSession(UINT session_id) { + std::cerr << "FindSession: " << session_id << std::endl; + return (session_id <= m_counter ? session_id : 0); + } + virtual UINT AddSession(LPWSTR buffer) { + std::cerr << "AddSession: " << m_counter + 1 << std::endl; + return ++m_counter; + } + virtual UINT RemoveSession(UINT session_id) { + std::cerr << "RemoveClient: " << session_id << std::endl; + return 0; + } + virtual BOOL ProcessKeyEvent(weasel::KeyEvent keyEvent, + UINT session_id, + EatLine eat) { + std::cerr << "ProcessKeyEvent: " << session_id + << " keycode: " << keyEvent.keycode << " mask: " << keyEvent.mask + << std::endl; + eat(std::wstring(L"Greeting=Hello, 小狼毫.\n")); + return TRUE; + } + + private: + unsigned int m_counter; }; -int server_main() -{ - HRESULT hRes = _Module.Init(NULL, GetModuleHandle(NULL)); - ATLASSERT(SUCCEEDED(hRes)); - - weasel::Server server; - //weasel::UI ui; - //const std::unique_ptr handler(new RimeWithWeaselHandler(&ui)); - const std::unique_ptr handler(new TestRequestHandler); - - server.SetRequestHandler(handler.get()); - if (!server.Start()) - return -4; - std::cerr << "server running." << std::endl; - int ret = server.Run(); - std::cerr << "server quitting." << std::endl; - return ret; +int server_main() { + HRESULT hRes = _Module.Init(NULL, GetModuleHandle(NULL)); + ATLASSERT(SUCCEEDED(hRes)); + + weasel::Server server; + // weasel::UI ui; + // const std::unique_ptr handler(new + // RimeWithWeaselHandler(&ui)); + const std::unique_ptr handler(new TestRequestHandler); + + server.SetRequestHandler(handler.get()); + if (!server.Start()) + return -4; + std::cerr << "server running." << std::endl; + int ret = server.Run(); + std::cerr << "server quitting." << std::endl; + return ret; }