Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adjust the position of the input method window so that it follows the caret #431

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
3 changes: 2 additions & 1 deletion lib/host/windows/key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}
3 changes: 3 additions & 0 deletions lib/include/elements/base_view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ namespace cycfi::elements

enum class key_code : int16_t
{
#ifdef WIN32
ime_process_key = -2,
#endif
unknown = -1,

// Printable keys
Expand Down
1 change: 1 addition & 0 deletions lib/include/elements/element/text.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
64 changes: 64 additions & 0 deletions lib/src/element/text.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<basic_text_box*>(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
Expand Down
Loading