Skip to content

Commit

Permalink
Set IME position to the caret during text editing on the Windows back…
Browse files Browse the repository at this point in the history
…end. #303 #305

Co-authored-by: liulun <[email protected]>
  • Loading branch information
mikke89 and xland committed Jun 2, 2022
1 parent 987c7d0 commit 89a357b
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 39 deletions.
26 changes: 26 additions & 0 deletions Backends/RmlUi_Platform_Win32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
#include <RmlUi/Core/SystemInterface.h>
#include <string.h>

// Used to interact with the input method editor (IME). Users of MinGW should manually link to this.
#ifdef _MSC_VER
#pragma comment(lib, "imm32")
#endif

SystemInterface_Win32::SystemInterface_Win32()
{
LARGE_INTEGER time_ticks_per_second;
Expand Down Expand Up @@ -141,6 +146,27 @@ void SystemInterface_Win32::GetClipboardText(Rml::String& text)
}
}

void SystemInterface_Win32::ActivateKeyboard(Rml::Vector2f caret_position, float /*line_height*/)
{
// Adjust the position of the input method editor (IME) to the caret.
if (HIMC himc = ImmGetContext(window_handle))
{
COMPOSITIONFORM comp = {};
comp.ptCurrentPos.x = (LONG)caret_position.x;
comp.ptCurrentPos.y = (LONG)caret_position.y;
comp.dwStyle = CFS_FORCE_POSITION;
ImmSetCompositionWindow(himc, &comp);

CANDIDATEFORM cand = {};
cand.dwStyle = CFS_CANDIDATEPOS;
cand.ptCurrentPos.x = (LONG)caret_position.x;
cand.ptCurrentPos.y = (LONG)caret_position.y;
ImmSetCandidateWindow(himc, &cand);

ImmReleaseContext(window_handle, himc);
}
}

Rml::String RmlWin32::ConvertToUTF8(const std::wstring& wstr)
{
const int count = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.length(), NULL, 0, NULL, NULL);
Expand Down
4 changes: 3 additions & 1 deletion Backends/RmlUi_Platform_Win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class SystemInterface_Win32 : public Rml::SystemInterface {
public:
SystemInterface_Win32();

// Optionally, provide or change the window to be used for setting the mouse cursors and clipboard text.
// Optionally, provide or change the window to be used for setting the mouse cursor, clipboard text and IME position.
void SetWindow(HWND window_handle);

// -- Inherited from Rml::SystemInterface --
Expand All @@ -51,6 +51,8 @@ class SystemInterface_Win32 : public Rml::SystemInterface {
void SetClipboardText(const Rml::String& text) override;
void GetClipboardText(Rml::String& text) override;

void ActivateKeyboard(Rml::Vector2f caret_position, float line_height) override;

private:
HWND window_handle = nullptr;

Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ if(BUILD_SAMPLES OR BUILD_TESTING)

# Add OS dependencies.
if (WIN32)
target_link_libraries(shell PRIVATE shlwapi)
target_link_libraries(shell PRIVATE shlwapi imm32)
elseif(APPLE)
target_link_libraries(shell PRIVATE "-framework Cocoa")
elseif(UNIX AND NOT APPLE AND NOT EMSCRIPTEN)
Expand Down
8 changes: 5 additions & 3 deletions Include/RmlUi/Core/SystemInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,12 @@ class RMLUICORE_API SystemInterface : public NonCopyMoveable
/// @param[out] text Retrieved text from clipboard.
virtual void GetClipboardText(String& text);

/// Activate keyboard (for touchscreen devices)
virtual void ActivateKeyboard();
/// Activate keyboard (for touchscreen devices).
/// @param[in] caret_position Position of the caret in absolute window coordinates.
/// @param[in] line_height Height of the current line being edited.
virtual void ActivateKeyboard(Rml::Vector2f caret_position, float line_height);

/// Deactivate keyboard (for touchscreen devices)
/// Deactivate keyboard (for touchscreen devices).
virtual void DeactivateKeyboard();
};

Expand Down
24 changes: 15 additions & 9 deletions Source/Core/Elements/WidgetTextInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -899,9 +899,6 @@ void WidgetTextInput::ShowCursor(bool show, bool move_to_cursor)
if (show)
{
cursor_visible = true;
SetKeyboardActive(true);
keyboard_showed = true;

cursor_timer = CURSOR_BLINK_TIME;
last_update_time = GetSystemInterface()->GetElapsedTime();

Expand All @@ -923,6 +920,9 @@ void WidgetTextInput::ShowCursor(bool show, bool move_to_cursor)
scroll_offset.x = parent->GetScrollLeft();
scroll_offset.y = parent->GetScrollTop();
}

SetKeyboardActive(true);
keyboard_showed = true;
}
else
{
Expand Down Expand Up @@ -1265,16 +1265,22 @@ void WidgetTextInput::GetLineSelection(String& pre_selection, String& selection,

void WidgetTextInput::SetKeyboardActive(bool active)
{
SystemInterface* system = GetSystemInterface();
if (system) {
if (active)
if (SystemInterface* system = GetSystemInterface())
{
if (active)
{
system->ActivateKeyboard();
} else
// Activate the keyboard and submit the cursor position and line height to enable clients to adjust the input method editor (IME). Note
// that the cursor is extended by one pixel along the top and bottom, we reverse this extension here.
const Vector2f element_offset = parent->GetAbsoluteOffset() - scroll_offset;
const Vector2f absolute_cursor_position = element_offset + cursor_position + Vector2f(0, 1);
const float line_height = cursor_size.y - 2.f;
system->ActivateKeyboard(absolute_cursor_position, line_height);
}
else
{
system->DeactivateKeyboard();
}
}
}

} // namespace Rml
15 changes: 4 additions & 11 deletions Source/Core/SystemInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ int SystemInterface::TranslateString(String& translated, const String& input)
return 0;
}

// Joins the path of an RML or RCSS file with the path of a resource specified within the file.
void SystemInterface::JoinPath(String& translated_path, const String& document_path, const String& path)
{
// If the path is absolute, strip the leading / and return it.
Expand Down Expand Up @@ -137,15 +136,9 @@ void SystemInterface::JoinPath(String& translated_path, const String& document_p
URL url(Replace(translated_path, ':', '|') + Replace(path, '\\', '/'));
translated_path = Replace(url.GetPathedFileName(), '|', ':');
}

// Activate keyboard (for touchscreen devices)
void SystemInterface::ActivateKeyboard()
{
}

// Deactivate keyboard (for touchscreen devices)
void SystemInterface::DeactivateKeyboard()
{
}

void SystemInterface::ActivateKeyboard(Rml::Vector2f /*caret_position*/, float /*line_height*/) {}

void SystemInterface::DeactivateKeyboard() {}

} // namespace Rml
17 changes: 6 additions & 11 deletions Source/Debugger/DebuggerSystemInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,12 @@ void DebuggerSystemInterface::GetClipboardText(String& text)
application_interface->GetClipboardText(text);
}

// Activate keyboard (for touchscreen devices)
void DebuggerSystemInterface::ActivateKeyboard()
void DebuggerSystemInterface::ActivateKeyboard(Rml::Vector2f caret_position, float line_height)
{
application_interface->ActivateKeyboard();
}

// Deactivate keyboard (for touchscreen devices)
void DebuggerSystemInterface::DeactivateKeyboard()
{
application_interface->DeactivateKeyboard();
application_interface->ActivateKeyboard(caret_position, line_height);
}

}
}
void DebuggerSystemInterface::DeactivateKeyboard() { application_interface->DeactivateKeyboard(); }

} // namespace Debugger
} // namespace Rml
6 changes: 3 additions & 3 deletions Source/Debugger/DebuggerSystemInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@ class DebuggerSystemInterface : public Rml::SystemInterface
/// @param[out] text Retrieved text from clipboard.
void GetClipboardText(String& text) override;

/// Activate keyboard (for touchscreen devices)
void ActivateKeyboard() override;
/// Activate keyboard (for touchscreen devices).
void ActivateKeyboard(Rml::Vector2f caret_position, float line_height) override;

/// Deactivate keyboard (for touchscreen devices)
/// Deactivate keyboard (for touchscreen devices).
void DeactivateKeyboard() override;
private:
Rml::SystemInterface* application_interface;
Expand Down
5 changes: 5 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ The `<textarea>` and `<input type="text">` elements have been improved in severa
- Fixed several issues where the text cursor would be offset from the text editing operations. In particular after word wrapping, or when suppressed characters were present in the text field's value. #313
- Fixed an issue where Windows newline endings (\r\n) would produce an excessive space character.
- Fixed operation of page up/down numpad keys being swapped.
- The input method editor (IME) is now positioned at the caret during text editing on the Windows backend. #303 #305 (thanks @xland)

### Lua plugin

Expand All @@ -53,6 +54,10 @@ The `<textarea>` and `<input type="text">` elements have been improved in severa
- Win32 backend: Fix slow input handling especially with CJK input. #311
- Logging a message without an installed system interface will now be written to cout instead of crashing the application.

### Breaking changes

- Changed the signature of the keyboard activation in the system interface, it now passes the caret position and line height: `SystemInterface::ActivateKeyboard(Rml::Vector2f caret_position, float line_height)`.


## RmlUi 4.4

Expand Down

0 comments on commit 89a357b

Please sign in to comment.