step6. 일본어 IME 메시지도 잘 처리하도록 수정
모 포럼에서 notepad2를 일본어 윈도우에서 돌려보니 IME 쪽에서 문제가 발생했다는 버그 리포트가 들어왔다.
(notepad2를 일본어 윈도우에서 돌려볼 생각도 해본 적이 없었음)
한글의 경우 한 순간에 조합되고 있는 글자의 수가 무조건 하나인데, 수정된 방식은 이 상황에 최적화되어있어 발생한 버그이다.
하지만, 일본어의 경우 아주 많은 글자가 동시에 입력되는 상황이 발생할 수 있다는 것이다.
일본어 윈도우에서도 notepad2를 무난하게 사용하려면 아래와 같이 수정하면 된다.
(일본어 윈도우를 쓸 일이 없다면 이 수정은 당연히 무의미하다)
수정 대상 파일은 ScintillaWin.cxx 하나이다.
1. ScintillaWin 클래스 선언부에서 메쏘드 및 변수 추가
ScintillaWin 클래스의 선언부에 아래와 같이 메쏘드 및 변수를 추가한다.
선언부 맨 끝부분에 추가하면 된다.
선언부 맨 끝부분에 추가하면 된다.
private:
void DelCharBacks(int iCount);
int GetCompositioningStrLen(DWORD index);
long lCompositioningLenOld, lCompositioningLen;
2. HandleComposition() 메쏘드 수정
IME에서 글자를 입력중일 때 메시지를 처리하는 메쏘드가 바로 HandleComposition() 이다.
따라서, 뭘 바꾸든 이 메쏘드가 바뀔 가능성은 백푸로다.
이번에는(에효... 또냐... ㅡ.ㅡ;) 아래와 같은 내용으로 통째로 바꿔준다.
따라서, 뭘 바꾸든 이 메쏘드가 바뀔 가능성은 백푸로다.
이번에는(에효... 또냐... ㅡ.ㅡ;) 아래와 같은 내용으로 통째로 바꿔준다.
sptr_t ScintillaWin::HandleComposition(uptr_t wParam, sptr_t lParam) {
#ifdef __DMC__
// Digital Mars compiler does not include Imm library
return 0;
#else
ClearSelection();
if (!inOverstrike) pdoc->cb.uh.EnableUndoAction(false);
if (lParam & GCS_COMPSTR)
{
if (inComposition) DelCharBacks(lCompositioningLenOld);
if (inOverstrike) bCompositioning = true;
inComposition = !(AddImeCompositionString(GCS_COMPSTR) == 0);
}
else if (lParam & GCS_RESULTSTR)
{
if (inComposition) DelCharBacks(lCompositioningLenOld);
if (inOverstrike) bCompositioning = false;
else pdoc->cb.uh.EnableUndoAction(true);
AddImeCompositionString(GCS_RESULTSTR);
inComposition = FALSE;
lCompositioningLenOld = 0;
}
UpdateSystemCaret();
return 0;
#endif
}
3. ImeStartComposition() 메쏘드 수정
ImeStartComposition() 메쏘드를 찾는다.
이 메쏘드의 앞부분은 아래와 같은 모양이다.
여기에 한 줄을 추가해서 아래와 같이 바꿔준다.
중간에 한 줄(4행)이 추가된 것 외엔 바뀐 부분은 없다.
이 메쏘드의 앞부분은 아래와 같은 모양이다.
void ScintillaWin::ImeStartComposition() {
#ifndef __DMC__
// Digital Mars compiler does not include Imm library
if (caret.active) {
// Move IME Window to current caret position
HIMC hIMC = ::ImmGetContext(MainHWND());
여기에 한 줄을 추가해서 아래와 같이 바꿔준다.
void ScintillaWin::ImeStartComposition() {
#ifndef __DMC__
// Digital Mars compiler does not include Imm library
lCompositioningLenOld = 0;
if (caret.active) {
// Move IME Window to current caret position
HIMC hIMC = ::ImmGetContext(MainHWND());
중간에 한 줄(4행)이 추가된 것 외엔 바뀐 부분은 없다.
4. AddImeCompositionString() 메쏘드 수정
ImeStartComposition() 메쏘드를 찾는다.
이 메쏘드를 아래의 내용으로 통째로 바꿔준다.
내부적으로만 사용되던 문자의 개수(wides)를 멤버변수(lCompositionLenOld)로 바꿔주는 것이다.
이 메쏘드를 아래의 내용으로 통째로 바꿔준다.
내부적으로만 사용되던 문자의 개수(wides)를 멤버변수(lCompositionLenOld)로 바꿔주는 것이다.
LONG ScintillaWin::AddImeCompositionString(DWORD index)
{
const int maxImeBuf = 200;
wchar_t wcs[maxImeBuf];
LONG bytes = GetCompositionString(index, wcs, (maxImeBuf-1)*2);
lCompositioningLenOld = bytes/2;
if(bytes == 0)
return bytes;
if (IsUnicodeMode()) {
char utfval[maxImeBuf * 3];
unsigned int len = UTF8Length(wcs, lCompositioningLenOld);
UTF8FromUTF16(wcs, lCompositioningLenOld, utfval, len);
utfval[len] = '\0';
AddCharUTF(utfval, len);
} else {
char dbcsval[maxImeBuf * 2];
int size = ::WideCharToMultiByte(InputCodePage()
, 0
, wcs
, lCompositioningLenOld
, dbcsval
, sizeof(dbcsval) - 1
, 0
, 0);
AddCharUTF(dbcsval, size);
}
return bytes;
}
5. GetCaretSize() 메쏘드 수정
GetCaretSize() 메쏘드에서 아래와 같은 부분을 찾는다.
위에 하일라이트된 4행을 아래와 같이 수정한다.
한글이란 가정 하에 길이를 무조건 2로 설정하지 않고, 조합중인 글자 수로 설정하는 수정이다.
if(inComposition)
{
Point end = LocationFromPosition(currentPos);
Point start = LocationFromPosition(currentPos-2);
cs.x = end.x - start.x;
cs.y = vs.lineHeight;
}
위에 하일라이트된 4행을 아래와 같이 수정한다.
if(inComposition)
{
Point end = LocationFromPosition(currentPos);
Point start = LocationFromPosition(currentPos - lCompositioningLen);
cs.x = end.x - start.x;
cs.y = vs.lineHeight;
}
한글이란 가정 하에 길이를 무조건 2로 설정하지 않고, 조합중인 글자 수로 설정하는 수정이다.
6. 메쏘드 2개 추가
수정중인 ScintillaWin.cxx의 맨 끝부분에 아래와 같이 새로운 메쏘드 2개를 추가한다.
int ScintillaWin::GetCompositioningStrLen(DWORD index)
{
HIMC hIMC = ::ImmGetContext(MainHWND());
if (hIMC) {
const int maxLenInputIME = 200;
wchar_t wcs[maxLenInputIME];
LONG bytes = ::ImmGetCompositionStringW(hIMC,
index, wcs, (maxLenInputIME-1)*2);
int wides = bytes / 2;
return wides;
}
return 0;
}
void ScintillaWin::DelCharBacks(int iCount)
{
DestroySystemCaret();
while (iCount--) DelCharBack(false);
CreateSystemCaret();
}
이렇게 수정하면 일본어 IME에서도 정상적인 문자의 입력이 가능하다.
XPMode + 일본어 Win XP에서 입력중인 모습
덜덜덜 일어도 입력하실일이 있으신건가요 -ㅁ-!
답글삭제@구차니 - 2009/08/07 09:43
답글삭제그것보단 IME 버그 패치 정도로 생각하심이... ㅎㅎㅎ
trackback from: 메모장2 (4.0.22)
답글삭제3.1.21 버전 나온지 얼마 되지도 않았는데 그새 또 나왔다. 그래서 BLUE'nLIVE님께서 또 고생해 주셨고, 옥토씨도 숟가락 언능 얹었다. 지금의 메모장2가 있기까지 도움주신 분들은 이 글의 앞부분에 소개되어 있고, 이번에 BLUE'nLIVE님께서 적용하신 패치 내역은 이 글에 나와 있다.추가- 2009/8/12BLUE'nLIVE님께서 한국어 및 일본어 IME를 모두 패치해 주셨다. 이제 일본어 입력도 잘 된다.일본어 윈도우즈나 일본어 IM...