- notepad2 컴파일 삽질기 7 : 한글 IME 패치 재작성
- 컴퓨터야그/notepad2
- 2009. 10. 9. 23:55
Notepad2에서 한글을 정상적으로 입력할 수 있도록 하기 위해 다음과 같은 패치를 공개했다.
이 패치의 가장 큰 문제는 너무 복잡하다는 점이다.
그런데, 또 하나의 문제가 있다. 바로 한글 IME 외의 IME에서 완벽하게 동작하지 않는다는 것...
사실, 모든 IME에서 완벽하게 동작하게 만들기 위해 이리저리 손을 많이 대었는데, 알고 보니 한글 IME만 엉망인 거다. OTL
이 문제를 한꺼번에 해결하고, 좀 더 간결한 패치를 유지하기 위해 다시 패치를 해봤다.
참고로, 이 패치는 기본적으로 행복한고니 님의 패치를 기본으로 작성했다. 1
이 패치를 하려면, 위의 세 패치는 안한 셈 치고 처음부터 다시 시작해야 한다.
패치할 대상은 ScintillaWin.cxx 하나다. (얏호! 드디어 정상적인 패치를 만든 거다!)
1. WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) 수정
2. ScintillaWin::HandleComposition(uptr_t wParam, sptr_t lParam) 대체
덧1. 드디어 완전체를 만들었다는 생각에 뿌듯함도 잠시... Scintilla 라이브러리가 그 사이에 2.x로 업데이트 되었다.
바뀐 부분의 코드를 읽어보니... 다중선택시 입력을 하면 전체 선택영역에 똑같은 내용을 출력하는 기능이 있더라.
이건 대체 어케 패치해야 되는 거냐... OTL
덧2. 한글날이 지나가기 전에 패치를 공개하기 위해 고군분투했다.
패치의 버그를 찾기 위해 열심히 뛰어주신 okto 님께 감사드린다.
이 패치의 가장 큰 문제는 너무 복잡하다는 점이다.
그런데, 또 하나의 문제가 있다. 바로 한글 IME 외의 IME에서 완벽하게 동작하지 않는다는 것...
사실, 모든 IME에서 완벽하게 동작하게 만들기 위해 이리저리 손을 많이 대었는데, 알고 보니 한글 IME만 엉망인 거다. OTL
한글 외의 일본어, 중국어 IME는 원래부터 정상적으로 동작했음
이 문제를 한꺼번에 해결하고, 좀 더 간결한 패치를 유지하기 위해 다시 패치를 해봤다.
참고로, 이 패치는 기본적으로 행복한고니 님의 패치를 기본으로 작성했다. 1
이 패치를 하려면, 위의 세 패치는 안한 셈 치고 처음부터 다시 시작해야 한다.
패치할 대상은 ScintillaWin.cxx 하나다. (얏호! 드디어 정상적인 패치를 만든 거다!)
1. WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) 수정
WM_IME_STARTCOMPOSITION: 을 찾아 아래와 같이 수정한다.
이 부분은 정확히는 행복한고니 님이 참고한 sixman님의 패치(헥헥 길다)에서 그대로 가져온 것이다.
이 부분은 정확히는 행복한고니 님이 참고한 sixman님의 패치(헥헥 길다)에서 그대로 가져온 것이다.
case WM_IME_STARTCOMPOSITION: // dbcs
ImeStartComposition();
// added from here-------------------------------------------------
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;
}
// added to here-------------------------------------------------
return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
2. ScintillaWin::HandleComposition(uptr_t wParam, sptr_t lParam) 대체
HandleComposition()을 찾아 아래 내용으로 대체한다.
삽입/덮어쓰기/행의 끝에서 덮어쓰기에서 각각 다르게 동작하도록 작성했다.
따라서, 행복한고니 님 패치의 버그는 발생하지 않는다. 2
삽입/덮어쓰기/행의 끝에서 덮어쓰기에서 각각 다르게 동작하도록 작성했다.
따라서, 행복한고니 님 패치의 버그는 발생하지 않는다. 2
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;
static bool bEndOfLine, bOverstrike;
static bool wasSelection = false;
bool bKoreanIME = LOWORD(GetKeyboardLayout(0))==MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN);
if (bKoreanIME && (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) {
//comp==false 이면 최초 진입
//undo를 마비시키기 전에 삭제할 글자/블럭 삭제
if (!comp)
{
wasSelection = currentPos != anchor;
if (wasSelection && anchor<currentPos) selBegin = anchor;
ClearSelection();
bEndOfLine = (selBegin == pdoc->Length()) || IsEOLChar(pdoc->CharAt(selBegin));
bOverstrike = inOverstrike;
if (bOverstrike && !wasSelection && !bEndOfLine && !RangeContainsProtected(selBegin, selBegin + 1)) DelChar();
}
if (cs < 0 && !bOverstrike) {
cs = vs.caretStyle;
vs.caretStyle = CARETSTYLE_BLOCK;
}
if (undo < 0) {
undo = pdoc->IsCollectingUndo()?1:0;
pdoc->SetUndoCollection(false);
}
if (!comp) {
comp = true;
} else {
DelChar();
}
} else {
//조합 중 조합중인 글자를 다 지운 경우
if (cs >= 0) {
vs.caretStyle = cs;
cs = -1;
}
if (comp) {
comp = false;
DelChar();
}
if (undo >= 0) {
pdoc->SetUndoCollection(undo==1);
undo = -1;
}
}
inOverstrike = false;
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<size; i++)
AddChar(dbcsval[i]);
}
inOverstrike = bOverstrike;
MovePositionTo(selBegin);
}
}
if (lParam & GCS_RESULTSTR) {
//앞의 if문 6개는 모두 한글 입력기에서만 동작
//다른 언어 IME에서는 패스
if (comp) {
comp = false;
DelChar();
}
if (cs >= 0) {
vs.caretStyle = cs;
cs = -1;
}
if (undo >= 0){
pdoc->SetUndoCollection(undo==1);
undo = -1;
}
//덮어쓰기에서 한글 조합 중 마지막에 숫자나 기호를 붙인 경우 한 글자 더 삭제(가9)
bool bKoreanPlusOneMore = false;
if (bKoreanIME && bOverstrike)
{
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;
char dbcsval[maxLenInputIME * 2];
int size = ::WideCharToMultiByte(InputCodePage(),
0, wcs, wides, dbcsval, sizeof(dbcsval) - 1, 0, 0);
bKoreanPlusOneMore = (size==3);
::ImmReleaseContext(MainHWND(), hIMC);
}
}
if (bKoreanPlusOneMore) DelChar();
if (bKoreanIME) inOverstrike = false;
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<size; i++)
AddChar(dbcsval[i]);
}
// Set new position after converted
Point pos = LocationFromPosition(currentPos);
COMPOSITIONFORM CompForm;
CompForm.dwStyle = CFS_POINT;
CompForm.ptCurrentPos.x = pos.x;
CompForm.ptCurrentPos.y = pos.y;
::ImmSetCompositionWindow(hIMC, &CompForm);
::ImmReleaseContext(MainHWND(), hIMC);
}
if (bKoreanIME) inOverstrike = bOverstrike;
return 0;
}
return ::DefWindowProc(MainHWND(), WM_IME_COMPOSITION, wParam, lParam);
#endif
}
덧1. 드디어 완전체를 만들었다는 생각에 뿌듯함도 잠시... Scintilla 라이브러리가 그 사이에 2.x로 업데이트 되었다.
바뀐 부분의 코드를 읽어보니... 다중선택시 입력을 하면 전체 선택영역에 똑같은 내용을 출력하는 기능이 있더라.
이건 대체 어케 패치해야 되는 거냐... OTL
덧2. 한글날이 지나가기 전에 패치를 공개하기 위해 고군분투했다.
패치의 버그를 찾기 위해 열심히 뛰어주신 okto 님께 감사드린다.
'컴퓨터야그 > notepad2' 카테고리의 다른 글
notepad2 컴파일 삽질기 부록#10 : 시간/날짜 삽입 순서 변경 (5) | 2009.11.14 |
---|---|
Notepad2 4.0.23 정식버전 관련 패치 모음 (11) | 2009.10.13 |
notepad2 컴파일 삽질기 6 : 일본어 IME도 정상적으로 사용이 가능하도록 수정 (2) | 2009.08.07 |
Notepad2 4.0.22 정식버전이 떴다 (6) | 2009.07.30 |
notepad2 컴파일 삽질기 5 : 스크롤 시 캐럿 출력 버그 수정 (2) | 2009.07.10 |
Recent comment