Scintilla 1.77 한국어 IME 패치

Scintilla 1.77 버전이 나왔는데, 아직 패치를 실행하신 분은 없는 듯 해서 직접 패치 후 컴파일 했습니다. 패치 방법은 codewiz님, BlUE'nLIVE님이 작성하신 방법도 있는데, 너무 수정할 게 많아서 sixmen님께 힌트를 얻어 제 나름대로 수정했습니다. 덕분에 토요일 오후가 사라졌네요. ;;

다루어야 하는 파일은 ScintillaWin.cxx 파일 하나뿐입니다. 패치방법을 기억하기 쉽도록 아래에 적어둡니다. 그냥 바이너리 파일만 필요하신 분은 바로 아래에 있는 링크에서 받으시면 됩니다. 하지만, 현재 이 DLL에는 버그가 있습니다. 사용상에 중대한 영향을 끼치는 것은 아니라고 생각하지만, 경우에 따라서는 중요해질 수도 있습니다. 꼭 이 글 제일 아래에 있는 버그를 확인 후 사용하세요. 저한테는 중요한 버그가 아니라 일단 그냥 쓰기로 했습니다. -_-;;

[download id="2"]

[adsense]

패치 과정

아래의 모든 과정은 ScintillaWin.cxx 파일에서 이루어집니다.

1. case WM_IME_STARTCOMPOSITION: 를 찾습니다.
아래의 소스를 다음과 같이 수정합니다. 한글 키보드일 때만 작동하도록 되어있으며 이 부분은 sixmen님 소스를 그대로 사용했습니다.

case WM_IME_STARTCOMPOSITION:// dbcs
	ImeStartComposition();
	// 여기부터
	if (LOWORD(GetKeyboardLayout(0))==MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN)) {
		// if the current IME is the Korean IME, do not show the default IME window
		return 0;
	}
	// 여기까지가 추가된 부분입니다.


2. ScintillaWin::HandleComposition을 찾습니다.
이 메소드를 다음과 같이 수정합니다. 소스는 길지만 원리를 설명하자면... 조합을 시작하기 전에, Undo 수집여부, 캐럿 스타일을 저장하고 조합이 끝나면 이를 원래대로 돌려주는 것입니다. 몇 시간을 투자했는데, 설명하고 보니 아무 것도 없네요. OTL

sptr_t ScintillaWin::HandleComposition(uptr_t wParam, sptr_t lParam) {
#ifdef __DMC__
	// Digital Mars compiler does not include Imm library
	return 0;
#else
	// 여기부터
	static int cs    = -1;
	static int undo  = -1;
	static bool comp = false;

	if (LOWORD(GetKeyboardLayout(0))==MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN) && (lParam & GCS_COMPSTR)) {
		HIMC hIMC = ::ImmGetContext(MainHWND());
		if (hIMC) {
			const int maxLenInputIME = 200;
			wchar_t wcs[maxLenInputIME];
			LONG bytes = ::ImmGetCompositionStringW(hIMC, GCS_COMPSTR, wcs, (maxLenInputIME-1)*2);
			int wides = bytes / 2;
			int selBegin = currentPos;
			if (bytes == 0) {
				if (cs >= 0) {
					vs.caretStyle = cs;
					cs = -1;
				}

				if (undo >= 0) {
					pdoc->SetUndoCollection(!!undo);
					undo = -1;
				}

				if (comp) {
					comp = false;
					DelChar();
				}
			} else {
				if (cs < 0) {
					cs = vs.caretStyle;
					vs.caretStyle = CARETSTYLE_BLOCK;
				}

				if (undo < 0) {
					undo = pdoc->IsCollectingUndo()?1:0;
					pdoc->SetUndoCollection(false);
				}

				if (!comp) {
					comp = true;
					if(inOverstrike) {
						pdoc->SetUndoCollection(undo);
						DelChar();
						pdoc->SetUndoCollection(false);
						pdoc->InsertChar(selBegin = currentPos, ' ');
						MovePositionTo(selBegin);
					}
				} else if(!inOverstrike) {
					DelChar();
				}
			}

			if (IsUnicodeMode()) {
				char utfval[maxLenInputIME * 3];
				unsigned int len = UTF8Length(wcs, wides);
				UTF8FromUTF16(wcs, wides, utfval, len);
				utfval[len] = '\0';
				AddCharUTF(utfval, len);
			} else {
				char dbcsval[maxLenInputIME * 2];
				int size = ::WideCharToMultiByte(InputCodePage(),
				    0, wcs, wides, dbcsval, sizeof(dbcsval) - 1, 0, 0);
				for (int i=0; i= 0) {
			vs.caretStyle = cs;
			cs = -1;
		}

		if (undo >= 0) {
			pdoc->SetUndoCollection(!!undo);
			undo = -1;
		}
		// 여기까지

		HIMC hIMC = ::ImmGetContext(MainHWND());
		if (hIMC) {
			const int maxLenInputIME = 200;
			wchar_t wcs[maxLenInputIME];
			LONG bytes = ::ImmGetCompositionStringW(hIMC,
				GCS_RESULTSTR, wcs, (maxLenInputIME-1)*2);
			int wides = bytes / 2;

			if (IsUnicodeMode()) {
				char utfval[maxLenInputIME * 3];
				unsigned int len = UTF8Length(wcs, wides);
				UTF8FromUTF16(wcs, wides, utfval, len);
				utfval[len] = '\0';
				AddCharUTF(utfval, len);
			} else {
				char dbcsval[maxLenInputIME * 2];
				int size = ::WideCharToMultiByte(InputCodePage(),
					0, wcs, wides, dbcsval, sizeof(dbcsval) - 1, 0, 0);
				for (int i=0; i

버그

겹쳐쓰기 모드에서 한글을 입력하면 undo가 정상적으로 작동하지 않는 버그가 있습니다.

  1. 이거보구
    Scintilla 2.2.6 에 적용해봄
    ----
    이것두역시
    겹쳐쓰기 모드에서 한글을 입력하면 undo가 정상적으로 작동하지 않는 버그가 있습니다
    -------
    sptr_t ScintillaWin::HandleComposition(uptr_t wParam, sptr_t lParam) {
    #ifdef __DMC__
    // Digital Mars compiler does not include Imm library
    return 0;
    #else
    #define maxLenInputIME 10
    static int caretStyle_IME_backup = 0;
    static bool flag_IME_first = true;
    static bool flag_IME_busy = false;

    if (lParam & GCS_COMPSTR) { ////IME busy
    HIMC hIMC = ::ImmGetContext(MainHWND());
    if (hIMC) {
    wchar_t wcs[maxLenInputIME];
    LONG bytes = ::ImmGetCompositionStringW(hIMC, GCS_COMPSTR, wcs, (maxLenInputIME-1)*2);
    ::ImmReleaseContext(MainHWND(), hIMC);
    wcs[bytes]=0;
    int wides = bytes / 2;
    if(flag_IME_first) {
    flag_IME_first = false;
    caretStyle_IME_backup = vs.caretStyle;
    vs.caretStyle = CARETSTYLE_BLOCK;
    pdoc->SetUndoCollection(false);
    }
    // pdoc->InsertChar(CurrentPosition(), ' ');
    // pdoc->InsertCString(insertPos, sz);
    // int startChar = pdoc->NextPosition(selBegin, -1);
    // pdoc->DeleteChars(startChar, pos - startChar);
    if (flag_IME_busy)
    pdoc->DeleteChars(CurrentPosition(), 2);
    flag_IME_busy = (wides != 0);
    if (IsUnicodeMode()) {
    char utfval[maxLenInputIME * 3];
    unsigned int len = UTF8Length(wcs, wides);
    UTF8FromUTF16(wcs, wides, utfval, len);
    utfval[len] = '';
    pdoc->InsertCString(CurrentPosition(), utfval);
    } else {
    char dbcsval[maxLenInputIME * 2];
    int size = ::WideCharToMultiByte(InputCodePage(),
    0, wcs, wides, dbcsval, sizeof(dbcsval) - 1, 0, 0);
    dbcsval[size] = '';
    pdoc->InsertCString(CurrentPosition(), dbcsval);
    }
    ShowCaretAtCurrentPosition();
    if(!bytes) {
    flag_IME_first = true;
    flag_IME_busy = false;
    vs.caretStyle = caretStyle_IME_backup;
    pdoc->SetUndoCollection(true);
    }
    }
    } else if (lParam & GCS_RESULTSTR) { //IME complete
    HIMC hIMC = ::ImmGetContext(MainHWND());
    if (hIMC) {
    wchar_t wcs[maxLenInputIME];
    LONG bytes = ::ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, wcs, (maxLenInputIME-1)*2);
    ::ImmReleaseContext(MainHWND(), hIMC);
    int wides = bytes / 2;
    if (!inOverstrike)
    pdoc->DeleteChars(CurrentPosition(), 2);
    if(!flag_IME_first) {
    flag_IME_first = true;
    flag_IME_busy = false;
    pdoc->SetUndoCollection(true);
    vs.caretStyle = caretStyle_IME_backup;
    }
    if (IsUnicodeMode()) {
    char utfval[maxLenInputIME * 3];
    unsigned int len = UTF8Length(wcs, wides);
    UTF8FromUTF16(wcs, wides, utfval, len);
    utfval[len] = '';
    AddCharUTF(utfval, len);
    } else {
    char dbcsval[maxLenInputIME * 2];
    int size = ::WideCharToMultiByte(InputCodePage(),
    0, wcs, wides, dbcsval, sizeof(dbcsval) - 1, 0, 0);
    for (int i=0; i<size; i++) {
    AddChar(dbcsval[i]);
    }
    }
    }
    return 0;
    }
    return ::DefWindowProc(MainHWND(), WM_IME_COMPOSITION, wParam, lParam);
    #undef maxLenInputIME
    #endif
    }

댓글을 남겨주세요

This site uses Akismet to reduce spam. Learn how your comment data is processed.