Forward IME messages to ScintillaWX and handle them

The handling code is copied from ScintillaWin

Closes #18759
This commit is contained in:
wangqr
2020-05-10 18:32:54 -04:00
parent 30079ad0e6
commit e07640fb75
6 changed files with 191 additions and 0 deletions

View File

@@ -5493,6 +5493,10 @@ protected:
void NotifyChange(); void NotifyChange();
void NotifyParent(SCNotification* scn); void NotifyParent(SCNotification* scn);
#ifdef __WXMSW__
virtual WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) wxOVERRIDE;
#endif // __WXMSW__
private: private:
wxDECLARE_EVENT_TABLE(); wxDECLARE_EVENT_TABLE();
wxDECLARE_DYNAMIC_CLASS(wxStyledTextCtrl); wxDECLARE_DYNAMIC_CLASS(wxStyledTextCtrl);

View File

@@ -45,6 +45,7 @@
#include "ScintillaWX.h" #include "ScintillaWX.h"
#include "ExternalLexer.h" #include "ExternalLexer.h"
#include "UniConversion.h"
#include "wx/stc/stc.h" #include "wx/stc/stc.h"
#include "wx/stc/private.h" #include "wx/stc/private.h"
#include "PlatWX.h" #include "PlatWX.h"
@@ -844,6 +845,31 @@ sptr_t ScintillaWX::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam)
case SCI_GETDIRECTPOINTER: case SCI_GETDIRECTPOINTER:
return reinterpret_cast<sptr_t>(this); return reinterpret_cast<sptr_t>(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: default:
return ScintillaBase::WndProc(iMessage, wParam, lParam); return ScintillaBase::WndProc(iMessage, wParam, lParam);
} }
@@ -1407,6 +1433,114 @@ sptr_t ScintillaWX::DirectFunction(
return swx->WndProc(iMessage, wParam, lParam); return swx->WndProc(iMessage, wParam, lParam);
} }
//----------------------------------------------------------------------
// ScintillaWin
#ifdef __WXMSW__
namespace {
POINT POINTFromPoint(Point pt) wxNOEXCEPT {
POINT ret;
ret.x = static_cast<LONG>(pt.x);
ret.y = static_cast<LONG>(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<BYTE> GetImeAttributes() {
const int attrLen = ::ImmGetCompositionStringW(hIMC, GCS_COMPATTR, wxNullPtr, 0);
std::vector<BYTE> attr(attrLen, 0);
::ImmGetCompositionStringW(hIMC, GCS_COMPATTR, &attr[0], static_cast<DWORD>(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<HWND>(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<BYTE>(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__
//---------------------------------------------------------------------- //----------------------------------------------------------------------
//---------------------------------------------------------------------- //----------------------------------------------------------------------

View File

@@ -238,6 +238,15 @@ private:
wxDataFormat m_clipRectTextFormat; wxDataFormat m_clipRectTextFormat;
#endif #endif
#ifdef __WXMSW__
// ScintillaWin
HWND MainHWND() const wxNOEXCEPT;
// DBCS
void ImeStartComposition();
void ImeEndComposition();
#endif
friend class wxSTCCallTip; friend class wxSTCCallTip;
friend class wxSTCTimer; // To get access to TickReason declaration friend class wxSTCTimer; // To get access to TickReason declaration
}; };

View File

@@ -5674,6 +5674,26 @@ void wxStyledTextCtrl::NotifyParent(SCNotification* _scn) {
GetEventHandler()->ProcessEvent(evt); 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
//---------------------------------------------------------------------- //----------------------------------------------------------------------
//---------------------------------------------------------------------- //----------------------------------------------------------------------

View File

@@ -1201,6 +1201,26 @@ void wxStyledTextCtrl::NotifyParent(SCNotification* _scn) {
GetEventHandler()->ProcessEvent(evt); 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
//---------------------------------------------------------------------- //----------------------------------------------------------------------
//---------------------------------------------------------------------- //----------------------------------------------------------------------

View File

@@ -611,6 +611,10 @@ protected:
void NotifyChange(); void NotifyChange();
void NotifyParent(SCNotification* scn); void NotifyParent(SCNotification* scn);
#ifdef __WXMSW__
virtual WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) wxOVERRIDE;
#endif // __WXMSW__
private: private:
wxDECLARE_EVENT_TABLE(); wxDECLARE_EVENT_TABLE();
wxDECLARE_DYNAMIC_CLASS(wxStyledTextCtrl); wxDECLARE_DYNAMIC_CLASS(wxStyledTextCtrl);