diff options
-rw-r--r-- | win32/ScintillaWin.cxx | 135 |
1 files changed, 133 insertions, 2 deletions
diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index 67fddd1cb..1f2c354f5 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -205,6 +205,9 @@ class ScintillaWin : static HINSTANCE hInstance; + int tmpCaretStyle; + bool compstrExist; + #if defined(USE_D2D) ID2D1HwndRenderTarget *pRenderTarget; bool renderTargetValid; @@ -236,6 +239,8 @@ class ScintillaWin : virtual void StartDrag(); sptr_t WndPaint(uptr_t wParam); sptr_t HandleComposition(uptr_t wParam, sptr_t lParam); + static bool KoreanIME(); + sptr_t HandleCompositionKoreanIME(uptr_t wParam, sptr_t lParam); UINT CodePageOfDocument(); virtual bool ValidCodePage(int codePage) const; virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); @@ -343,6 +348,9 @@ ScintillaWin::ScintillaWin(HWND hwnd) { TrackMouseEventFn = 0; SetCoalescableTimerFn = 0; + tmpCaretStyle = 0; + compstrExist = false; + linesPerScroll = 0; wheelDelta = 0; // Wheel delta from roll @@ -703,6 +711,105 @@ sptr_t ScintillaWin::HandleComposition(uptr_t wParam, sptr_t lParam) { return ::DefWindowProc(MainHWND(), WM_IME_COMPOSITION, wParam, lParam); } +bool ScintillaWin::KoreanIME() { + const int codePage = InputCodePage(); + return codePage == 949 || codePage == 1361; +} + +sptr_t ScintillaWin::HandleCompositionKoreanIME(uptr_t, sptr_t lParam) { + + // copy & paste by johnsonj + // Great thanks to + // jiniya from http://www.jiniya.net/tt/494 for DBCS input with AddCharUTF() + // BLUEnLIVE from http://zockr.tistory.com/1118 for UNDO and inOverstrike + + HIMC hIMC = ::ImmGetContext(MainHWND()); + if (!hIMC) { + return 0; + } + + const int maxLenInputIME = 4; + wchar_t wcs[maxLenInputIME]; + int wides = 0; + + // for avoiding inOverstrike condition in AddCharUTF() + bool tmpOverstrike = inOverstrike; + + if (pdoc->TentativeActive()) { + pdoc->TentativeUndo(); + } else { + // No tentative undo means start of this composition so + // fill in any virtual spaces. + AddCharUTF("", 0, false); + } + + if (lParam & GCS_COMPSTR) { + long bytes = ::ImmGetCompositionStringW + (hIMC, GCS_COMPSTR, wcs, maxLenInputIME); + wides = bytes / 2; + inOverstrike = inOverstrike && (!compstrExist); + compstrExist = (wides != 0); + } else if (lParam & GCS_RESULTSTR) { + long bytes = ::ImmGetCompositionStringW + (hIMC, GCS_RESULTSTR, wcs, maxLenInputIME); + wides = bytes / 2; + compstrExist = (wides == 0); + inOverstrike = inOverstrike && (wides >= 2); + } + + if (wides >= 1) { + + char hanval[maxLenInputIME]; + unsigned int hanlen = 0; + + if (IsUnicodeMode()) { + hanlen = UTF8Length(wcs, wides); + UTF8FromUTF16(wcs, wides, hanval, hanlen); + hanval[hanlen] = '\0'; + } else { + hanlen = ::WideCharToMultiByte(InputCodePage(), 0, + wcs, wides, hanval, sizeof(hanval) - 1, 0, 0); + hanval[hanlen] = '\0'; + } + + if (compstrExist) { + vs.caretStyle = CARETSTYLE_BLOCK; + + bool tmpRecordingMacro = recordingMacro; + recordingMacro = false; + pdoc->TentativeStart(); + AddCharUTF(hanval, hanlen, true); + recordingMacro = tmpRecordingMacro; + + //NotifyChar() in AddCharUTF() may not know comprStr is deleted by undo. + Editor::NotifyChar((static_cast<unsigned char>(hanval[0]) << 8) | + static_cast<unsigned char>(hanval[1])); + + for (size_t r = 0; r < sel.Count(); r++) { // for block caret + int positionInsert = sel.Range(r).Start().Position(); + sel.Range(r).caret.SetPosition(positionInsert - hanlen); + sel.Range(r).anchor.SetPosition(positionInsert - hanlen); + } + } else { + AddCharUTF(hanval, hanlen, true); + } + } + + // set the candidate window position for HANJA while composing. + Point pos = PointMainCaret(); + CANDIDATEFORM CandForm; + CandForm.dwIndex = 0; + CandForm.dwStyle = CFS_CANDIDATEPOS; + CandForm.ptCurrentPos.x = static_cast<int>(pos.x); + CandForm.ptCurrentPos.y = static_cast<int>(pos.y + vs.lineHeight); + ::ImmSetCandidateWindow(hIMC, &CandForm); + + ShowCaretAtCurrentPosition(); + inOverstrike = tmpOverstrike; + ::ImmReleaseContext(MainHWND(), hIMC); + return 0; +} + // Translate message IDs from WM_* and EM_* to SCI_* so can partly emulate Windows Edit control static unsigned int SciMessageFromEM(unsigned int iMessage) { switch (iMessage) { @@ -1140,15 +1247,30 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam break; case WM_IME_STARTCOMPOSITION: // dbcs + if (KoreanIME()) { + tmpCaretStyle = vs.caretStyle; + if (vs.caretStyle > CARETSTYLE_BLOCK) { + vs.caretStyle= CARETSTYLE_LINE; + } + return 0; + } ImeStartComposition(); return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); case WM_IME_ENDCOMPOSITION: // dbcs + if (KoreanIME()) { + vs.caretStyle = tmpCaretStyle; + return 0; + } ImeEndComposition(); return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); case WM_IME_COMPOSITION: - return HandleComposition(wParam, lParam); + if (KoreanIME()) { + return HandleCompositionKoreanIME(wParam, lParam); + } else { + return HandleComposition(wParam, lParam); + } case WM_IME_CHAR: { AddCharBytes(HIBYTE(wParam), LOBYTE(wParam)); @@ -1184,6 +1306,16 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam capturedMouse = false; return 0; + case WM_IME_SETCONTEXT: + if (KoreanIME()) { + if (wParam) { + LPARAM NoImeWin = lParam; + NoImeWin = NoImeWin & (~ISC_SHOWUICOMPOSITIONWINDOW); + return ::DefWindowProc(MainHWND(), iMessage, wParam, NoImeWin); + } + } + return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam); + // These are not handled in Scintilla and its faster to dispatch them here. // Also moves time out to here so profile doesn't count lots of empty message calls. @@ -1194,7 +1326,6 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam case WM_NCPAINT: case WM_NCMOUSEMOVE: case WM_NCLBUTTONDOWN: - case WM_IME_SETCONTEXT: case WM_IME_NOTIFY: case WM_SYSCOMMAND: case WM_WINDOWPOSCHANGING: |