aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--win32/ScintillaWin.cxx218
1 files changed, 157 insertions, 61 deletions
diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx
index bd205e370..205d1d58e 100644
--- a/win32/ScintillaWin.cxx
+++ b/win32/ScintillaWin.cxx
@@ -103,6 +103,11 @@
#define SC_WIN_IDLE 5001
+#define SC_INDICATOR_INPUT INDIC_IME
+#define SC_INDICATOR_TARGET INDIC_IME+1
+#define SC_INDICATOR_CONVERTED INDIC_IME+2
+#define SC_INDICATOR_UNKNOWN INDIC_IME_MAX
+
typedef BOOL (WINAPI *TrackMouseEventSig)(LPTRACKMOUSEEVENT);
typedef UINT_PTR (WINAPI *SetCoalescableTimerSig)(HWND hwnd, UINT_PTR nIDEvent,
UINT uElapse, TIMERPROC lpTimerFunc, ULONG uToleranceDelay);
@@ -239,9 +244,14 @@ class ScintillaWin :
virtual bool DragThreshold(Point ptStart, Point ptNow);
virtual void StartDrag();
sptr_t WndPaint(uptr_t wParam);
- sptr_t HandleComposition(uptr_t wParam, sptr_t lParam);
+
+ sptr_t HandleCompositionWindowed(uptr_t wParam, sptr_t lParam);
+ sptr_t HandleCompositionInline(uptr_t wParam, sptr_t lParam);
static bool KoreanIME();
- sptr_t HandleCompositionKoreanIME(uptr_t wParam, sptr_t lParam);
+ void MoveImeCarets(int offset);
+ void DrawImeIndicator(int indicator, int len);
+ void SetCandidateWindowPos();
+
UINT CodePageOfDocument();
virtual bool ValidCodePage(int codePage) const;
virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
@@ -422,6 +432,10 @@ void ScintillaWin::Initialise() {
for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) {
timers[tr] = 0;
}
+ vs.indicators[SC_INDICATOR_UNKNOWN] = Indicator(INDIC_HIDDEN, ColourDesired(0, 0, 0xff));
+ vs.indicators[SC_INDICATOR_INPUT] = Indicator(INDIC_DOTS, ColourDesired(0, 0, 0xff));
+ vs.indicators[SC_INDICATOR_CONVERTED] = Indicator(INDIC_COMPOSITIONTHICK, ColourDesired(0, 0, 0xff));
+ vs.indicators[SC_INDICATOR_TARGET] = Indicator(INDIC_STRAIGHTBOX, ColourDesired(0, 0, 0xff));
}
void ScintillaWin::Finalise() {
@@ -705,7 +719,7 @@ LRESULT ScintillaWin::WndPaint(uptr_t wParam) {
return 0l;
}
-sptr_t ScintillaWin::HandleComposition(uptr_t wParam, sptr_t lParam) {
+sptr_t ScintillaWin::HandleCompositionWindowed(uptr_t wParam, sptr_t lParam) {
if (lParam & GCS_RESULTSTR) {
HIMC hIMC = ::ImmGetContext(MainHWND());
if (hIMC) {
@@ -746,22 +760,53 @@ bool ScintillaWin::KoreanIME() {
return codePage == 949 || codePage == 1361;
}
-sptr_t ScintillaWin::HandleCompositionKoreanIME(uptr_t, sptr_t lParam) {
+void ScintillaWin::MoveImeCarets(int offset) {
+ // Move carets relatively by bytes.
+ for (size_t r=0; r<sel.Count(); r++) {
+ int positionInsert = sel.Range(r).Start().Position();
+ sel.Range(r).caret.SetPosition(positionInsert + offset);
+ sel.Range(r).anchor.SetPosition(positionInsert + offset);
+ }
+}
+
+void ScintillaWin::DrawImeIndicator(int indicator, int len) {
+ // Emulate the visual style of IME characters with indicators.
+ // Draw an indicator on the character before caret by the character bytes of len
+ // so it should be called after addCharUTF().
+ // It does not affect caret positions.
+ if (indicator < 8 || indicator > INDIC_MAX) {
+ return;
+ }
+ pdoc->decorations.SetCurrentIndicator(indicator);
+ for (size_t r=0; r<sel.Count(); r++) {
+ int positionInsert = sel.Range(r).Start().Position();
+ pdoc->DecorationFillRange(positionInsert - len, 1, len);
+ }
+}
+
+void ScintillaWin::SetCandidateWindowPos() {
+ HIMC hIMC = ::ImmGetContext(MainHWND());
+ if (hIMC) {
+ 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);
+ ::ImmReleaseContext(MainHWND(), hIMC);
+ }
+}
- // 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
+sptr_t ScintillaWin::HandleCompositionInline(uptr_t, sptr_t lParam) {
+ // Copy & paste by johnsonj with a lot of helps of Neil.
+ // Great thanks for my foreruners, jiniya and BLUEnLIVE.
HIMC hIMC = ::ImmGetContext(MainHWND());
if (!hIMC) {
return 0;
}
- wchar_t wcs[maxLenInputIME];
- int wides = 0;
- bool compstrExist = false;
-
if (pdoc->TentativeActive()) {
pdoc->TentativeUndo();
} else {
@@ -774,61 +819,111 @@ sptr_t ScintillaWin::HandleCompositionKoreanIME(uptr_t, sptr_t lParam) {
}
view.imeCaretBlockOverride = false;
+
if (lParam & GCS_COMPSTR) {
+ wchar_t wcs[maxLenInputIME] = { 0 };
long bytes = ::ImmGetCompositionStringW
- (hIMC, GCS_COMPSTR, wcs, maxLenInputIME);
- wides = bytes / 2;
- compstrExist = (wides != 0);
- } else if (lParam & GCS_RESULTSTR) {
- long bytes = ::ImmGetCompositionStringW
- (hIMC, GCS_RESULTSTR, wcs, maxLenInputIME);
- wides = bytes / 2;
- compstrExist = (wides == 0);
- }
+ (hIMC, GCS_COMPSTR, wcs, maxLenInputIME);
+ unsigned int wcsLen = bytes / 2;
- if (wides >= 1) {
+ if ((wcsLen == 0) || (wcsLen >= maxLenInputIME)) {
+ ShowCaretAtCurrentPosition();
+ ::ImmReleaseContext(MainHWND(), hIMC);
+ return 0;
+ }
- char hanval[maxLenInputIME];
- unsigned int hanlen = 0;
+ pdoc->TentativeStart(); // TentativeActive from now on.
- 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';
+ // Get attribute information from composition string.
+ BYTE compAttr[maxLenInputIME] = { 0 };
+ unsigned int imeCursorPos = 0;
+
+ if (lParam & GCS_COMPATTR) {
+ ImmGetCompositionStringW(hIMC, GCS_COMPATTR, compAttr, sizeof(compAttr));
+ }
+ if (lParam & GCS_CURSORPOS) {
+ imeCursorPos = ImmGetCompositionStringW(hIMC, GCS_CURSORPOS, NULL, 0);
}
- if (compstrExist) {
- view.imeCaretBlockOverride = true;
+ // Display character by character.
+ int numBytes = 0;
+ int imeCharPos[maxLenInputIME + 1] = { 0 };
+
+ bool tmpRecordingMacro = recordingMacro;
+ recordingMacro = false;
+ for (unsigned int i = 0; i < wcsLen; i++) {
+ wchar_t uniChar[1] = { 0 };
+ char oneChar[UTF8MaxBytes + 1] = "\0\0\0\0"; // Maximum 4 bytes in utf8
+ unsigned int oneCharLen = 0;
- bool tmpRecordingMacro = recordingMacro;
- recordingMacro = false;
- pdoc->TentativeStart();
- AddCharUTF(hanval, hanlen);
- recordingMacro = tmpRecordingMacro;
+ uniChar[0] = wcs[i];
- 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);
+ if (IsUnicodeMode()) {
+ oneCharLen = UTF8Length(uniChar, 1);
+ UTF8FromUTF16(uniChar, 1, oneChar, oneCharLen);
+ oneChar[oneCharLen] = '\0';
+ } else {
+ oneCharLen = ::WideCharToMultiByte(InputCodePage(), 0,
+ uniChar, 1, oneChar, sizeof(oneChar)-1, 0, 0);
+ oneChar[oneCharLen] = '\0';
}
- } else {
- AddCharUTF(hanval, hanlen);
+
+ // Display a character.
+ AddCharUTF(oneChar, oneCharLen);
+
+ // Record compstr character positions for moving IME carets.
+ numBytes += oneCharLen;
+ imeCharPos[i + 1] = numBytes;
+
+ // Draw an indicator on the character.
+ int indicator = SC_INDICATOR_UNKNOWN;
+ switch ((int)compAttr[i]) {
+ case ATTR_INPUT:
+ indicator = SC_INDICATOR_INPUT;
+ break;
+ case ATTR_TARGET_NOTCONVERTED:
+ case ATTR_TARGET_CONVERTED:
+ indicator = SC_INDICATOR_TARGET;
+ break;
+ case ATTR_CONVERTED:
+ indicator = SC_INDICATOR_CONVERTED;
+ break;
+ }
+ DrawImeIndicator(indicator, oneCharLen);
}
- }
+ recordingMacro = tmpRecordingMacro;
- // 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);
+ // Move IME caret position.
+ MoveImeCarets(-imeCharPos[wcsLen] + imeCharPos[imeCursorPos]);
+ if (KoreanIME()) {
+ view.imeCaretBlockOverride = true;
+ }
+ } else if (lParam & GCS_RESULTSTR) {
+ wchar_t wcs[maxLenInputIME] = { 0 };
+ long bytes = ::ImmGetCompositionStringW
+ (hIMC, GCS_RESULTSTR, wcs, maxLenInputIME);
+ unsigned int wcsLen = bytes / 2;
+
+ for (unsigned int i = 0; i < wcsLen; i++) {
+ wchar_t uniChar[1] = { 0 };
+ char oneChar[UTF8MaxBytes+1] = "\0\0\0\0"; // Maximum 4 bytes in UTF-8.
+ unsigned int oneCharLen = 0;
+ uniChar[0] = wcs[i];
+
+ if (IsUnicodeMode()) {
+ oneCharLen = UTF8Length(uniChar, 1);
+ UTF8FromUTF16(uniChar, 1, oneChar, oneCharLen);
+ oneChar[oneCharLen] = '\0';
+ } else {
+ oneCharLen = ::WideCharToMultiByte(InputCodePage(), 0,
+ uniChar, 1, oneChar, sizeof(oneChar)-1, 0, 0);
+ oneChar[oneCharLen] = '\0';
+ }
+ AddCharUTF(oneChar, oneCharLen);
+ }
+ }
+ SetCandidateWindowPos();
ShowCaretAtCurrentPosition();
::ImmReleaseContext(MainHWND(), hIMC);
return 0;
@@ -1278,21 +1373,22 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam
break;
case WM_IME_STARTCOMPOSITION: // dbcs
- if (KoreanIME()) {
+ if (KoreanIME() || imeInteraction == imeInline) {
return 0;
+ } else {
+ ImeStartComposition();
+ return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
}
- ImeStartComposition();
- return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
case WM_IME_ENDCOMPOSITION: // dbcs
ImeEndComposition();
return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
case WM_IME_COMPOSITION:
- if (KoreanIME()) {
- return HandleCompositionKoreanIME(wParam, lParam);
+ if (KoreanIME() || imeInteraction == imeInline) {
+ return HandleCompositionInline(wParam, lParam);
} else {
- return HandleComposition(wParam, lParam);
+ return HandleCompositionWindowed(wParam, lParam);
}
case WM_IME_CHAR: {
@@ -1330,7 +1426,7 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam
return 0;
case WM_IME_SETCONTEXT:
- if (KoreanIME()) {
+ if (KoreanIME() || imeInteraction == imeInline) {
if (wParam) {
LPARAM NoImeWin = lParam;
NoImeWin = NoImeWin & (~ISC_SHOWUICOMPOSITIONWINDOW);