diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index e84ca984..dd201719 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -348,9 +348,10 @@ if (WIN32 AND NOT MSVC) target_link_libraries(elements PUBLIC ws2_32) endif() -# Replace missing Shcore library removed by WIN32_LEAN_AND_MEAN +# 1.Replace missing Shcore library removed by WIN32_LEAN_AND_MEAN +# 2.IME requires Imm32 if (WIN32) - target_link_libraries(elements PUBLIC Shcore) + target_link_libraries(elements PUBLIC Shcore Imm32) endif() add_library(cycfi::elements ALIAS elements) diff --git a/lib/host/windows/key.cpp b/lib/host/windows/key.cpp index d02eb8e7..c1552843 100644 --- a/lib/host/windows/key.cpp +++ b/lib/host/windows/key.cpp @@ -72,7 +72,7 @@ namespace cycfi::elements { // IME notifies that keys have been filtered by setting the virtual // key-code to VK_PROCESSKEY - return key_code::unknown; + return key_code::ime_process_key; } unsigned int key = HIWORD(lparam) & 0x1FF; @@ -206,5 +206,6 @@ namespace cycfi::elements case 0x037: return key_code::kp_multiply; case 0x04a: return key_code::kp_subtract; } + return key_code::unknown; } } diff --git a/lib/include/elements/base_view.hpp b/lib/include/elements/base_view.hpp index 595ab8c5..0a81b49a 100644 --- a/lib/include/elements/base_view.hpp +++ b/lib/include/elements/base_view.hpp @@ -144,6 +144,9 @@ namespace cycfi::elements enum class key_code : int16_t { +#ifdef WIN32 + ime_process_key = -2, +#endif unknown = -1, // Printable keys diff --git a/lib/include/elements/element/text.hpp b/lib/include/elements/element/text.hpp index bd065c0d..647ae0fd 100644 --- a/lib/include/elements/element/text.hpp +++ b/lib/include/elements/element/text.hpp @@ -156,6 +156,7 @@ namespace cycfi::elements char const* caret_position(context const& ctx, point p); glyph_metrics glyph_info(context const& ctx, char const* s); + bool get_caret_position(context const& ctx, rect& caret_bounds); private: diff --git a/lib/src/element/text.cpp b/lib/src/element/text.cpp index 816b5730..a3720596 100644 --- a/lib/src/element/text.cpp +++ b/lib/src/element/text.cpp @@ -335,6 +335,34 @@ namespace cycfi::elements ) return false; +#ifdef WIN32 + if(k.key == key_code::ime_process_key) { + rect caret_bounds; + if(get_caret_position(ctx, caret_bounds)) { + if(HIMC imc = ImmGetContext(ctx.view.host())) { + const auto& tl = ctx.canvas.user_to_device(caret_bounds.top_left()); + const auto& br = ctx.canvas.user_to_device(caret_bounds.bottom_right()); + + COMPOSITIONFORM cf; + memset(&cf, 0, sizeof(COMPOSITIONFORM)); + cf.dwStyle = CFS_FORCE_POSITION; + cf.ptCurrentPos.x = tl.x + 1; + cf.ptCurrentPos.y = tl.y; + ImmSetCompositionWindow(imc, &cf); + + CANDIDATEFORM candf; + memset(&candf, 0, sizeof(CANDIDATEFORM)); + candf.dwIndex = 0; + candf.dwStyle = CFS_CANDIDATEPOS; + candf.ptCurrentPos.x = tl.x + 1; + candf.ptCurrentPos.y = br.y; + ImmSetCandidateWindow(imc, &candf); + + return true; + } + } + } +#endif _show_caret = true; bool move_caret = false; bool save_x = false; @@ -586,6 +614,42 @@ namespace cycfi::elements return true; } + bool basic_text_box::get_caret_position(context const& ctx, rect& caret_bounds) { + // Make sure _this_handle is initialized to this + if (!_this_handle) + _this_handle = std::make_shared(this); + + if (!editable() || _select_start == -1) + return false; + + if (!_is_focus) //No caret if not focused + return false; + + auto const& theme = get_theme(); + // Handle the case where text is empty + if (_text.empty()) + { + auto size = _layout.metrics(); + auto line_height = size.ascent + size.descent + size.leading; + auto width = theme.text_box_caret_width; + auto left = ctx.bounds.left; + auto top = ctx.bounds.top; + + caret_bounds = rect{left, top, left + width, top + line_height}; + return true; + } + else if (_select_start == _select_end) + { + auto start_info = glyph_info(ctx, _text.data() + _select_start); + auto width = theme.text_box_caret_width; + rect& caret = start_info.bounds; + + caret_bounds = rect{caret.left - 0.5f, caret.top, caret.left + width + 0.5f, caret.bottom}; + return true; + } + return false; + } + void basic_text_box::draw_caret(context const& ctx) { // Make sure _this_handle is initialized to this