Enable IME text reconversion in editor view#3214
Conversation
There was a problem hiding this comment.
Pull request overview
Adds IME reconversion support to CrystalEdit’s CCrystalTextView by handling WM_IME_REQUEST and constructing RECONVERTSTRING data from the current line / single-line selection context.
Changes:
- Add
WM_IME_REQUESTmessage handling forIMR_RECONVERTSTRING,IMR_CONFIRMRECONVERTSTRING, andIMR_DOCUMENTFEED. - Introduce a
BuildReconvertStringhelper to centralizeRECONVERTSTRINGconstruction. - Constrain reconversion to single-line selections.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| Externals/crystaledit/editlib/ccrystaltextview.h | Adds forward declaration and declares new IME reconversion handler/helper methods. |
| Externals/crystaledit/editlib/ccrystaltextview.cpp | Hooks WM_IME_REQUEST and implements reconversion/document-feed handling via RECONVERTSTRING. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| switch (wParam) | ||
| { | ||
| case IMR_RECONVERTSTRING: | ||
| { | ||
| CEPoint ptCursor = GetCursorPos(); | ||
| int nLineIndex = ptCursor.y; | ||
| DWORD dwOffset = static_cast<DWORD>(ptCursor.x); | ||
| DWORD dwLen = 0; | ||
|
|
||
| if (IsSelection()) | ||
| { | ||
| CEPoint s, e; | ||
| GetSelection(s, e); | ||
| if (s.y != e.y) | ||
| return 0; | ||
| nLineIndex = s.y; | ||
| dwOffset = static_cast<DWORD>(s.x); | ||
| dwLen = static_cast<DWORD>(e.x - s.x); | ||
| } | ||
|
|
||
| return BuildReconvertString( | ||
| reinterpret_cast<RECONVERTSTRING*>(lParam), nLineIndex, dwOffset, dwLen); | ||
| } | ||
|
|
||
| case IMR_CONFIRMRECONVERTSTRING: | ||
| { | ||
| RECONVERTSTRING* pReconv = reinterpret_cast<RECONVERTSTRING*>(lParam); | ||
| if (pReconv == nullptr) | ||
| return FALSE; | ||
|
|
||
| DWORD dwCompCharOffset = pReconv->dwCompStrOffset / sizeof(tchar_t); | ||
| DWORD dwCompCharLen = pReconv->dwCompStrLen; | ||
|
|
||
| CEPoint ptCursor = GetCursorPos(); | ||
| int nLineIndex = ptCursor.y; | ||
|
|
||
| if (IsSelection()) | ||
| { | ||
| CEPoint ptSelStart, ptSelEnd; | ||
| GetSelection(ptSelStart, ptSelEnd); | ||
| if (ptSelStart.y != ptSelEnd.y) | ||
| return FALSE; // Multi-line selection not supported | ||
| nLineIndex = ptSelStart.y; | ||
| } | ||
|
|
||
| // IME adjusted the range but resulted in zero length - reject this | ||
| int nLineLen = GetLineLength(nLineIndex); | ||
| if (dwCompCharLen == 0) | ||
| return FALSE; | ||
| if (dwCompCharOffset >= static_cast<DWORD>(nLineLen)) | ||
| return FALSE; | ||
| if (dwCompCharOffset + dwCompCharLen > static_cast<DWORD>(nLineLen)) | ||
| return FALSE; | ||
|
|
||
| CEPoint ptNewStart(static_cast<int>(dwCompCharOffset), nLineIndex); | ||
| CEPoint ptNewEnd(static_cast<int>(dwCompCharOffset + dwCompCharLen), nLineIndex); | ||
| SetSelection(ptNewStart, ptNewEnd); | ||
| SetCursorPos(ptNewStart); | ||
| EnsureVisible(ptNewStart); | ||
| UpdateCompositionWindowPos(); | ||
|
|
||
| return TRUE; | ||
| } | ||
|
|
||
| case IMR_DOCUMENTFEED: | ||
| { | ||
| CEPoint ptCursor = GetCursorPos(); | ||
| return BuildReconvertString( | ||
| reinterpret_cast<RECONVERTSTRING*>(lParam), ptCursor.y, static_cast<DWORD>(ptCursor.x), 0); | ||
| } | ||
| } |
Check notice
Code scanning / CodeQL
Long switch case Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 17 days ago
To fix the problem, we should extract the body of the long IMR_CONFIRMRECONVERTSTRING case into a dedicated helper method on CCrystalTextView. The switch will then simply call this helper and return its result, keeping the case short while preserving all existing behavior.
Concretely:
- Introduce a private (or member‑scope) helper method, e.g.
LRESULT CCrystalTextView::HandleImeConfirmReconvertString(LPARAM lParam), near the existing IME-related methods (BuildReconvertString,OnImeRequest) to keep related logic together. - Move all of the logic currently inside
case IMR_CONFIRMRECONVERTSTRING:(lines 6878–6913) into this new method, adjusting the earlyreturnstatements to behave exactly as before. - In the
switch (wParam)insideOnImeRequest, replace the long case body with a singlereturn HandleImeConfirmReconvertString(lParam);. - No new headers or external libraries are needed; we only use existing types and methods (
RECONVERTSTRING,CEPoint,GetCursorPos,IsSelection,GetSelection,GetLineLength,SetSelection,SetCursorPos,EnsureVisible,UpdateCompositionWindowPos).
This change keeps the functionality identical, shortens the long case, and improves readability.
This PR adds IME reconversion support to CrystalEdit via WM_IME_REQUEST.
It implements handling for IMR_RECONVERTSTRING, IMR_CONFIRMRECONVERTSTRING,
and IMR_DOCUMENTFEED, allowing IMEs to perform text reconversion using the
current line as context.
Common RECONVERTSTRING construction logic is refactored into a helper
function to reduce duplication and improve readability.
Reconversion is limited to single-line ranges by design.
This enables standard IME reconversion behavior without impacting existing
input handling.