diff options
Diffstat (limited to 'win32/ScintillaWin.cxx')
-rw-r--r-- | win32/ScintillaWin.cxx | 157 |
1 files changed, 86 insertions, 71 deletions
diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index c05dbd8fc..3975846f0 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -261,23 +261,30 @@ public: class IMContext { HWND hwnd; -public: HIMC hIMC; +public: + explicit IMContext(HWND hwnd_) noexcept : hwnd(hwnd_), hIMC(::ImmGetContext(hwnd_)) { } + // Deleted so IMContext objects can not be copied. IMContext(const IMContext &) = delete; IMContext(IMContext &&) = delete; IMContext &operator=(const IMContext &) = delete; IMContext &operator=(IMContext &&) = delete; + ~IMContext() { if (hIMC) ::ImmReleaseContext(hwnd, hIMC); } + [[nodiscard]] explicit operator bool() const noexcept { + return hIMC != HIMC{}; + } + [[nodiscard]] unsigned int GetImeCaretPos() const noexcept { - return ImmGetCompositionStringW(hIMC, GCS_CURSORPOS, nullptr, 0); + return ::ImmGetCompositionStringW(hIMC, GCS_CURSORPOS, nullptr, 0); } [[nodiscard]] std::vector<BYTE> GetImeAttributes() const { @@ -298,6 +305,59 @@ public: ::ImmGetCompositionStringW(hIMC, dwIndex, wcs.data(), byteLen); return wcs; } + + BOOL SetCompositionString(DWORD dwIndex, LPVOID lpComp, DWORD dwCompLen) const noexcept { + return ::ImmSetCompositionStringW(hIMC, dwIndex, lpComp, dwCompLen, nullptr, 0); + } + + void SetCompositionWindow(Point pos) const noexcept { + COMPOSITIONFORM CompForm{}; + CompForm.dwStyle = CFS_POINT; + CompForm.ptCurrentPos = POINTFromPoint(pos); + ::ImmSetCompositionWindow(hIMC, &CompForm); + } + + void SetCandidateWindowPos(Point pos, PRectangle rcClient, int lineHeight) const noexcept { + CANDIDATEFORM CandForm{}; + CandForm.dwIndex = 0; + CandForm.dwStyle = CFS_EXCLUDE; + CandForm.ptCurrentPos.x = static_cast<int>(pos.x); + CandForm.ptCurrentPos.y = static_cast<int>(pos.y + std::max(4, lineHeight / 4)); + // Exclude the area of the whole caret line + CandForm.rcArea.top = static_cast<int>(pos.y); + CandForm.rcArea.bottom = static_cast<int>(pos.y + lineHeight); + CandForm.rcArea.left = static_cast<int>(rcClient.left); + CandForm.rcArea.right = static_cast<int>(rcClient.right); + ::ImmSetCandidateWindow(hIMC, &CandForm); + } + + void SetCompositionFont(const ViewStyle &vs, int style, UINT dpi) const { + LOGFONTW lf{}; + int sizeZoomed = vs.styles[style].size + (vs.zoomLevel * FontSizeMultiplier); + if (sizeZoomed <= 2 * FontSizeMultiplier) // Hangs if sizeZoomed <= 1 + sizeZoomed = 2 * FontSizeMultiplier; + // The negative is to allow for leading + lf.lfHeight = -::MulDiv(sizeZoomed, dpi, pointsPerInch * FontSizeMultiplier); + lf.lfWeight = static_cast<LONG>(vs.styles[style].weight); + lf.lfItalic = vs.styles[style].italic ? 1 : 0; + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfFaceName[0] = L'\0'; + if (vs.styles[style].fontName) { + const char *fontName = vs.styles[style].fontName; + UTF16FromUTF8(std::string_view(fontName), lf.lfFaceName, LF_FACESIZE); + } + + ::ImmSetCompositionFontW(hIMC, &lf); + } + + void Notify(bool complete) const noexcept { + ::ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, complete ? CPS_COMPLETE : CPS_CANCEL, 0); + } + + LRESULT Escape(HKL hkl, UINT uEscape, LPVOID lpv) const noexcept { + return ::ImmEscapeW(hkl, hIMC, uEscape, lpv); + } + }; class GlobalMemory; @@ -1306,16 +1366,11 @@ sptr_t ScintillaWin::WndPaint() { sptr_t ScintillaWin::HandleCompositionWindowed(uptr_t wParam, sptr_t lParam) { if (lParam & GCS_RESULTSTR) { - IMContext imc(MainHWND()); - if (imc.hIMC) { + if (IMContext imc{ MainHWND() }) { AddWString(imc.GetCompositionString(GCS_RESULTSTR), CharacterSource::ImeResult); // Set new position after converted - const Point pos = PointMainCaret(); - COMPOSITIONFORM CompForm {}; - CompForm.dwStyle = CFS_POINT; - CompForm.ptCurrentPos = POINTFromPoint(pos); - ::ImmSetCompositionWindow(imc.hIMC, &CompForm); + imc.SetCompositionWindow(PointMainCaret()); } return 0; } @@ -1328,21 +1383,8 @@ bool ScintillaWin::KoreanIME() noexcept { } void ScintillaWin::SetCandidateWindowPos() { - IMContext imc(MainHWND()); - if (imc.hIMC) { - const Point pos = PointMainCaret(); - const PRectangle rcClient = GetTextRectangle(); - CANDIDATEFORM CandForm{}; - CandForm.dwIndex = 0; - CandForm.dwStyle = CFS_EXCLUDE; - CandForm.ptCurrentPos.x = static_cast<int>(pos.x); - CandForm.ptCurrentPos.y = static_cast<int>(pos.y + std::max(4, vs.lineHeight/4)); - // Exclude the area of the whole caret line - CandForm.rcArea.top = static_cast<int>(pos.y); - CandForm.rcArea.bottom = static_cast<int>(pos.y + vs.lineHeight); - CandForm.rcArea.left = static_cast<int>(rcClient.left); - CandForm.rcArea.right = static_cast<int>(rcClient.right); - ::ImmSetCandidateWindow(imc.hIMC, &CandForm); + if (IMContext imc{ MainHWND() }) { + imc.SetCandidateWindowPos(PointMainCaret(), GetTextRectangle(), vs.lineHeight); } } @@ -1391,12 +1433,11 @@ void ScintillaWin::EscapeHanja() { std::wstring uniChar = StringDecode(oneChar, CodePageOfDocument()); - IMContext imc(MainHWND()); - if (imc.hIMC) { + if (IMContext imc{ MainHWND() }) { // Set the candidate box position since IME may show it. SetCandidateWindowPos(); // IME_ESC_HANJA_MODE appears to receive the first character only. - if (::ImmEscapeW(GetKeyboardLayout(0), imc.hIMC, IME_ESC_HANJA_MODE, uniChar.data())) { + if (imc.Escape(GetKeyboardLayout(0), IME_ESC_HANJA_MODE, uniChar.data())) { SetSelection(currentPos, currentPos + oneCharLen); } } @@ -1461,10 +1502,10 @@ sptr_t ScintillaWin::HandleCompositionInline(uptr_t, sptr_t lParam) { // Great thanks for my foreruners, jiniya and BLUEnLIVE. IMContext imc(MainHWND()); - if (!imc.hIMC) + if (!imc) return 0; if (pdoc->IsReadOnly() || SelectionContainsProtected()) { - ::ImmNotifyIME(imc.hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0); + imc.Notify(false); return 0; } @@ -1790,21 +1831,14 @@ void ScintillaWin::SizeWindow() { sptr_t ScintillaWin::MouseMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { switch (iMessage) { - case WM_LBUTTONDOWN: { - // For IME, set the composition string as the result string. - IMContext imc(MainHWND()); - if (imc.hIMC) { - ::ImmNotifyIME(imc.hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); - } - // - //Platform::DebugPrintf("Buttdown %d %x %x %x %x %x\n",iMessage, wParam, lParam, - // KeyboardIsKeyDown(VK_SHIFT), - // KeyboardIsKeyDown(VK_CONTROL), - // KeyboardIsKeyDown(VK_MENU)); - ::SetFocus(MainHWND()); - ButtonDownWithModifiers(PointFromLParam(lParam), ::GetMessageTime(), - MouseModifiers(wParam)); + case WM_LBUTTONDOWN: + // For IME, set the composition string as the result string. + if (IMContext imc{ MainHWND() }) { + imc.Notify(true); } + ::SetFocus(MainHWND()); + ButtonDownWithModifiers(PointFromLParam(lParam), ::GetMessageTime(), + MouseModifiers(wParam)); break; case WM_LBUTTONUP: @@ -1989,9 +2023,8 @@ sptr_t ScintillaWin::FocusMessage(unsigned int iMessage, uptr_t wParam, sptr_t) DestroySystemCaret(); } // Explicitly complete any IME composition - IMContext imc(MainHWND()); - if (imc.hIMC) { - ::ImmNotifyIME(imc.hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); + if (IMContext imc{ MainHWND() }) { + imc.Notify(true); } break; } @@ -3306,34 +3339,16 @@ void ScintillaWin::ImeStartComposition() { if (caret.active) { // Move IME Window to current caret position IMContext imc(MainHWND()); - const Point pos = PointMainCaret(); - COMPOSITIONFORM CompForm {}; - CompForm.dwStyle = CFS_POINT; - CompForm.ptCurrentPos = POINTFromPoint(pos); + if (!imc) + return; - ::ImmSetCompositionWindow(imc.hIMC, &CompForm); + imc.SetCompositionWindow(PointMainCaret()); // 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 * FontSizeMultiplier); - if (sizeZoomed <= 2 * FontSizeMultiplier) // Hangs if sizeZoomed <= 1 - sizeZoomed = 2 * FontSizeMultiplier; - // The negative is to allow for leading - lf.lfHeight = -::MulDiv(sizeZoomed, dpi, pointsPerInch*FontSizeMultiplier); - lf.lfWeight = static_cast<LONG>(vs.styles[styleHere].weight); - lf.lfItalic = 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(std::string_view(fontName), lf.lfFaceName, LF_FACESIZE); - } - - ::ImmSetCompositionFontW(imc.hIMC, &lf); + imc.SetCompositionFont(vs, pdoc->StyleIndexAt(sel.MainCaret()), dpi); } // Caret is displayed in IME window. So, caret in Scintilla is useless. DropCaret(); @@ -3389,10 +3404,10 @@ LRESULT ScintillaWin::ImeOnReconvert(LPARAM lParam) { rc->dwTargetStrOffset =rc->dwCompStrOffset; IMContext imc(MainHWND()); - if (!imc.hIMC) + if (!imc) return 0; - if (!::ImmSetCompositionStringW(imc.hIMC, SCS_QUERYRECONVERTSTRING, rc, rcSize, nullptr, 0)) + if (!imc.SetCompositionString(SCS_QUERYRECONVERTSTRING, rc, rcSize)) return 0; // No selection asks IME to fill target fields with its own value. @@ -3452,7 +3467,7 @@ LRESULT ScintillaWin::ImeOnDocumentFeed(LPARAM lParam) const { memcpy(rcFeedStart, rcFeed.data(), rcFeedLen); IMContext imc(MainHWND()); - if (!imc.hIMC) + if (!imc) return 0; DWORD compStrLen = 0; |