From e07640fb75a9543b23119a0258723f199bbd77a2 Mon Sep 17 00:00:00 2001 From: wangqr Date: Sun, 10 May 2020 18:32:54 -0400 Subject: [PATCH] Forward IME messages to ScintillaWX and handle them The handling code is copied from ScintillaWin Closes #18759 --- include/wx/stc/stc.h | 4 ++ src/stc/ScintillaWX.cpp | 134 ++++++++++++++++++++++++++++++++++++++++ src/stc/ScintillaWX.h | 9 +++ src/stc/stc.cpp | 20 ++++++ src/stc/stc.cpp.in | 20 ++++++ src/stc/stc.h.in | 4 ++ 6 files changed, 191 insertions(+) diff --git a/include/wx/stc/stc.h b/include/wx/stc/stc.h index 0bc3ea10d3..620743f186 100644 --- a/include/wx/stc/stc.h +++ b/include/wx/stc/stc.h @@ -5493,6 +5493,10 @@ protected: void NotifyChange(); void NotifyParent(SCNotification* scn); +#ifdef __WXMSW__ + virtual WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) wxOVERRIDE; +#endif // __WXMSW__ + private: wxDECLARE_EVENT_TABLE(); wxDECLARE_DYNAMIC_CLASS(wxStyledTextCtrl); diff --git a/src/stc/ScintillaWX.cpp b/src/stc/ScintillaWX.cpp index 7e7580518d..9ac400fdba 100644 --- a/src/stc/ScintillaWX.cpp +++ b/src/stc/ScintillaWX.cpp @@ -45,6 +45,7 @@ #include "ScintillaWX.h" #include "ExternalLexer.h" +#include "UniConversion.h" #include "wx/stc/stc.h" #include "wx/stc/private.h" #include "PlatWX.h" @@ -844,6 +845,31 @@ sptr_t ScintillaWX::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) case SCI_GETDIRECTPOINTER: return reinterpret_cast(this); +#ifdef __WXMSW__ + // ScintillaWin + case WM_IME_STARTCOMPOSITION: // dbcs + // TODO: We haven't ported WM_IME_COMPOSITION yet, so always use windowed IME to make it at least work + //if (KoreanIME() || imeInteraction == imeInline) { + if (false) { + return 0; + } + else { + ImeStartComposition(); + return stc->wxControl::MSWWindowProc(iMessage, wParam, lParam); + } + + case WM_IME_ENDCOMPOSITION: // dbcs + ImeEndComposition(); + return stc->wxControl::MSWWindowProc(iMessage, wParam, lParam); + + case WM_IME_KEYDOWN: + case WM_IME_REQUEST: + case WM_IME_COMPOSITION: + case WM_IME_SETCONTEXT: + // TODO: Port event handling from ScintillaWin + return stc->wxControl::MSWWindowProc(iMessage, wParam, lParam); +#endif + default: return ScintillaBase::WndProc(iMessage, wParam, lParam); } @@ -1407,6 +1433,114 @@ sptr_t ScintillaWX::DirectFunction( return swx->WndProc(iMessage, wParam, lParam); } +//---------------------------------------------------------------------- +// ScintillaWin + +#ifdef __WXMSW__ + +namespace { + +POINT POINTFromPoint(Point pt) wxNOEXCEPT { + POINT ret; + ret.x = static_cast(pt.x); + ret.y = static_cast(pt.y); + return ret; +} + +class IMContext { + HWND hwnd; +public: + HIMC hIMC; + IMContext(HWND hwnd_) wxNOEXCEPT : + hwnd(hwnd_), hIMC(::ImmGetContext(hwnd_)) { + } + ~IMContext() { + if (hIMC) + ::ImmReleaseContext(hwnd, hIMC); + } + + unsigned int GetImeCaretPos() const wxNOEXCEPT { + return ImmGetCompositionStringW(hIMC, GCS_CURSORPOS, wxNullPtr, 0); + } + + std::vector GetImeAttributes() { + const int attrLen = ::ImmGetCompositionStringW(hIMC, GCS_COMPATTR, wxNullPtr, 0); + std::vector attr(attrLen, 0); + ::ImmGetCompositionStringW(hIMC, GCS_COMPATTR, &attr[0], static_cast(attr.size())); + return attr; + } + + std::wstring GetCompositionString(DWORD dwIndex) { + const LONG byteLen = ::ImmGetCompositionStringW(hIMC, dwIndex, wxNullPtr, 0); + std::wstring wcs(byteLen / 2, 0); + ::ImmGetCompositionStringW(hIMC, dwIndex, &wcs[0], byteLen); + return wcs; + } +private: + // Private so IMContext objects can not be copied. + IMContext(const IMContext&); + IMContext& operator=(const IMContext&); +}; + +} + +HWND ScintillaWX::MainHWND() const wxNOEXCEPT { + return static_cast(wMain.GetID()); +} + +/** + * DBCS: support Input Method Editor (IME). + * Called when IME Window opened. + */ +void ScintillaWX::ImeStartComposition() { + if (caret.active) { + // Move IME Window to current caret position + IMContext imc(stc->GetHandle()); + const Point pos = PointMainCaret(); + COMPOSITIONFORM CompForm; + CompForm.dwStyle = CFS_POINT; + CompForm.ptCurrentPos = POINTFromPoint(pos); + + ::ImmSetCompositionWindow(imc.hIMC, &CompForm); + + // Set font of IME window to same as surrounded text. + if (stylesValid) { + // Since the style creation code has been made platform independent, + // The logfont for the IME is recreated here. + const int styleHere = pdoc->StyleIndexAt(sel.MainCaret()); + LOGFONTW lf = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L"" }; + int sizeZoomed = vs.styles[styleHere].size + vs.zoomLevel * SC_FONT_SIZE_MULTIPLIER; + if (sizeZoomed <= 2 * SC_FONT_SIZE_MULTIPLIER) // Hangs if sizeZoomed <= 1 + sizeZoomed = 2 * SC_FONT_SIZE_MULTIPLIER; + AutoSurface surface(this); + int deviceHeight = sizeZoomed; + if (surface) { + deviceHeight = (sizeZoomed * surface->LogPixelsY()) / 72; + } + // The negative is to allow for leading + lf.lfHeight = -(std::abs(deviceHeight / SC_FONT_SIZE_MULTIPLIER)); + lf.lfWeight = vs.styles[styleHere].weight; + lf.lfItalic = static_cast(vs.styles[styleHere].italic ? 1 : 0); + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfFaceName[0] = L'\0'; + if (vs.styles[styleHere].fontName) { + const char* fontName = vs.styles[styleHere].fontName; + UTF16FromUTF8(fontName, strlen(fontName)+1, lf.lfFaceName, LF_FACESIZE); + } + + ::ImmSetCompositionFontW(imc.hIMC, &lf); + } + // Caret is displayed in IME window. So, caret in Scintilla is useless. + DropCaret(); + } +} + +/** Called when IME Window closed. */ +void ScintillaWX::ImeEndComposition() { + ShowCaretAtCurrentPosition(); +} +#endif // __WXMSW__ + //---------------------------------------------------------------------- //---------------------------------------------------------------------- diff --git a/src/stc/ScintillaWX.h b/src/stc/ScintillaWX.h index 92079170e3..dfe97e1d4f 100644 --- a/src/stc/ScintillaWX.h +++ b/src/stc/ScintillaWX.h @@ -238,6 +238,15 @@ private: wxDataFormat m_clipRectTextFormat; #endif +#ifdef __WXMSW__ + // ScintillaWin + HWND MainHWND() const wxNOEXCEPT; + + // DBCS + void ImeStartComposition(); + void ImeEndComposition(); +#endif + friend class wxSTCCallTip; friend class wxSTCTimer; // To get access to TickReason declaration }; diff --git a/src/stc/stc.cpp b/src/stc/stc.cpp index 561379d7d3..2ae931b4e1 100644 --- a/src/stc/stc.cpp +++ b/src/stc/stc.cpp @@ -5674,6 +5674,26 @@ void wxStyledTextCtrl::NotifyParent(SCNotification* _scn) { GetEventHandler()->ProcessEvent(evt); } +#ifdef __WXMSW__ +WXLRESULT wxStyledTextCtrl::MSWWindowProc(WXUINT nMsg, + WXWPARAM wParam, + WXLPARAM lParam) +{ + switch(nMsg) { + // Forward IME messages to ScintillaWX + case WM_IME_KEYDOWN: + case WM_IME_REQUEST: + case WM_IME_STARTCOMPOSITION: + case WM_IME_ENDCOMPOSITION: + case WM_IME_COMPOSITION: + case WM_IME_SETCONTEXT: + return SendMsg(nMsg, wParam, lParam); + default: + return wxControl::MSWWindowProc(nMsg, wParam, lParam); + } +} +#endif + //---------------------------------------------------------------------- //---------------------------------------------------------------------- diff --git a/src/stc/stc.cpp.in b/src/stc/stc.cpp.in index d2a256e20c..63db3db362 100644 --- a/src/stc/stc.cpp.in +++ b/src/stc/stc.cpp.in @@ -1201,6 +1201,26 @@ void wxStyledTextCtrl::NotifyParent(SCNotification* _scn) { GetEventHandler()->ProcessEvent(evt); } +#ifdef __WXMSW__ +WXLRESULT wxStyledTextCtrl::MSWWindowProc(WXUINT nMsg, + WXWPARAM wParam, + WXLPARAM lParam) +{ + switch(nMsg) { + // Forward IME messages to ScintillaWX + case WM_IME_KEYDOWN: + case WM_IME_REQUEST: + case WM_IME_STARTCOMPOSITION: + case WM_IME_ENDCOMPOSITION: + case WM_IME_COMPOSITION: + case WM_IME_SETCONTEXT: + return SendMsg(nMsg, wParam, lParam); + default: + return wxControl::MSWWindowProc(nMsg, wParam, lParam); + } +} +#endif + //---------------------------------------------------------------------- //---------------------------------------------------------------------- diff --git a/src/stc/stc.h.in b/src/stc/stc.h.in index 925f4b9b1d..6011cf94c9 100644 --- a/src/stc/stc.h.in +++ b/src/stc/stc.h.in @@ -611,6 +611,10 @@ protected: void NotifyChange(); void NotifyParent(SCNotification* scn); +#ifdef __WXMSW__ + virtual WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) wxOVERRIDE; +#endif // __WXMSW__ + private: wxDECLARE_EVENT_TABLE(); wxDECLARE_DYNAMIC_CLASS(wxStyledTextCtrl);