IME(Input Method Editor)

C++ 2010. 9. 11. 05:48
비영어인 한글의 입력을 제어하기 위해서 IME의 메세지를 처리 합니다.
(EX: 조합중인 초,중,종성의 입력을 제어하는 경우..)

Visual C++ project 에서 환경 설정 2가지
  1. #include <imm.h>
  2. project properties에서 "Linker > Input > Additional Dependencies" 에 imm32.lib 추가


IME에 대해 처리 할 수 있는 메세지는 다음과 같습니다.
  WM_IME_SETCONTEXT       
  WM_IME_NOTIFY           
  WM_IME_CONTROL          
  WM_IME_COMPOSITIONFULL  
  WM_IME_SELECT           
  WM_IME_CHAR             
  WM_IME_REQUEST          
  WM_IME_KEYDOWN          
  WM_IME_KEYUP            
  WM_IME_STARTCOMPOSITION 
  WM_IME_ENDCOMPOSITION   
  WM_IME_COMPOSITION      
  WM_IME_KEYLAST          
이 중에 쓸만한 아이들은 다음과 같습니다.



WM_IME_STARTCOMPOSITION 
    문자 조립 직전의 메세지. 
    아무 값도 얻을 수 없으며 단순 통지용 메세지입니다.


WM_IME_ENDCOMPOSITION   
    문자 조립 직후의 메세지.
    아무 값도 얻을 수 없으며 단순 통지용 메세지입니다.


WM_IME_COMPOSITION
    문자 조립중인 경우의 메세지.
    조립중인 문자를 확인 할 수 있습니다.
    wParam에 조립중인 글자값이 들어오며
    lParam에 조립 상태를 나타내며 값은 다음과 같습니다.

<표. WM_IME_COMPOSITON의 lParam 값...>
ValueDescription
GCS_COMPATTR Retrieves or updates the attribute of the composition string.
GCS_COMPCLAUSE Retrieves or updates clause information of the composition string.
GCS_COMPREADATTR Retrieves or updates the attributes of the reading string of the current composition.
GCS_COMPREADCLAUSE Retrieves or updates the clause information of the reading string of the composition string.
GCS_COMPREADSTR Retrieves or updates the reading string of the current composition.
GCS_COMPSTR Retrieves or updates the current composition string.
GCS_CURSORPOS Retrieves or updates the cursor position in composition string.
GCS_DELTASTART Retrieves or updates the starting position of any changes in composition string.
GCS_RESULTCLAUSE Retrieves or updates clause information of the result string.
GCS_RESULTREADCLAUSE Retrieves or updates clause information of the reading string.
GCS_RESULTREADSTR Retrieves or updates the reading string.
GCS_RESULTSTR Retrieves or updates the string of the composition result.  

    이 중에서도 쓸만한 아이들은 아래 두 아이 입니다.
    GCS_COMPSTR 는 현재 조립중임을 나타내며
    GCS_RESULTSTR 는 조립이 완성되었음을 의미합니다.


WM_IME_CHAR
    하나의 문자가 완성되면 wParam으로 문자를 받습니다.
    유니코드 사용시 WM_CHAR와 동일한 기능이지만 유니코드가 아닐 경우 
    DBCS(Double Byte Character System)일 수 있으며 1 byte만 전달되는 WM_CHAR와 다르게 동작하게 됩니다.
    유니코드를 사용합시다.


WM_IME_SETCONTEXT
    wParam이 true일 경우 응용 프로그램의 활성화를 뜻합니다. false는 비활성화.
    커스텀 IME 윈도우 생성시 이 메세지를 받을 때 ImmIsUIMessage 함수를 호출하여 
    조립 윈도우와 후보 윈도우를 보이도록 해야 합니다. (네??.. 음..)


WM_IME_NOTIFY
    IME 윈도우 변경시를 알리는 메세지입니다.
    입력 모드(한글->영문) 변경시, 후보 윈도우 오픈, 후보 목록 변경 등의 이벤트를 얻을 수 있습니다.
    wParam로 다음과 같은 이벤트를 잡을 수 있습니다.
        IMN_CHANGECANDIDATE
        IMN_CLOSECANDIDATE
        IMN_CLOSESTATUSWINDOW
        IMN_GUIDELINE
        IMN_OPENCANDIDATE
        IMN_OPENSTATUSWINDOW
        IMN_SETCANDIDATEPOS
        IMN_SETCOMPOSITIONFONT
        IMN_SETCOMPOSITIONWINDOW
        IMN_SETCONVERSIONMODE
        IMN_SETOPENSTATUS
        IMN_SETSENTENCEMODE
        IMN_SETSTATUSWINDOWPOS 


메세지들이 참 많고 복잡해 보입니다. java가 참 아름다워 보입니다.
어쨋든, 
    WM_IME_COMPOSITION와 그 안의 GCS_COMPSTR, GCS_RESULTSTR
    WM_IME_CHAR
만 잘 써도 성공할 것 같습니다.





한글 입력 SAMPLE

단순히 버퍼도 고정(1024)되어있고 enter, backspace 등 처리는 안되어있는 심플한 소스입니다.
message craker(windowsx.h)를 사용하고 class 화 된 소스입니다.
LRESULT CTest::onMessage(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
switch (iMessage) {
HANDLE_MSG(hWnd, WM_CREATE, onCreate);
HANDLE_MSG(hWnd, WM_PAINT, onPaint);
//.. 생략 ..
case WM_IME_COMPOSITION:
return onImeComposition(hWnd, wParam, lParam);
case WM_IME_CHAR:
return onImeChar(hWnd, wParam, lParam);
case WM_IME_STARTCOMPOSITION:
return 0;
case WM_MOUSEWHEEL:
return 0;
}
return(DefWindowProc(hWnd,iMessage,wParam,lParam));
} 

TCHAR tmp[1024]; //입력받는 문자열을 담을 버퍼
bool bComposite; //입력 중이라 문자 조합 중인지 아닌지 판별하기 위한 변수
void CTest::onPaint(HWND hWnd){

HDC hdc;
PAINTSTRUCT ps;

hdc=BeginPaint(hWnd,&ps);
TextOut(hdc, 10, 10, tmp, lstrlen(tmp)); //입력되는 문자들 출력
EndPaint(hWnd,&ps);
}
bool CTest::onCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct){
bComposite = false;  //초기화
ZeroMemory(tmp, sizeof(tmp)); //초기화
return TRUE;
}

LRESULT CTest::onImeComposition(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
TCHAR inChar[2];
inChar[0] = wParam;
inChar[1] = 0;
HIMC hImc;
int pos = lstrlen(tmp);

if (lParam & GCS_COMPSTR) //조립중이라면..
{
if (bComposite) pos--;

hImc = ImmGetContext(hWnd); //IME 사용
int lenIMM = ImmGetCompositionString(hImc, GCS_COMPSTR, NULL, 0); //조합 중인 문자에 길이를 받습니다.
ImmReleaseContext(hWnd,hImc); //IME 자원 해제

//조합중에 backspace를 누르는 경우 길이가 0일 수 있습니다. 
//이런 경우가 없다면 ImmGetContext를 사용 안해도 될 것 같습니다.
if (0 == lenIMM) 
{
pos--;
bComposite = false;
}
else
{
bComposite = true;
}
memcpy(tmp+pos, inChar, (lstrlen(inChar)+1) * sizeof(TCHAR));
}

InvalidateRect(hWnd, NULL, TRUE);
return DefWindowProc(hWnd,WM_IME_COMPOSITION,wParam,lParam);
}

LRESULT CTest::onImeChar(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
int pos = lstrlen(tmp);
if (bComposite) pos--;

TCHAR szChar[2];
szChar[0] = wParam;
szChar[1] = 0;
memcpy(tmp+pos, inChar, (lstrlen(inChar)+1) * sizeof(TCHAR));
bComposite = false;

InvalidateRect(hWnd, NULL, TRUE);
return 0;
}


:D

'C++' 카테고리의 다른 글

Random 난수 생성하기  (0) 2010.10.13
SOCKET  (0) 2010.10.09
Windows Thread 와 Synchronization(동기화)  (0) 2010.10.06
자료구조  (0) 2010.09.30
VC++ 수행시간 체크  (1) 2010.09.15
Visual C++ : window 생성 template  (0) 2010.09.10
C++ 포인터 및 레퍼런스  (0) 2010.09.02
PE (portable executable) 파일  (0) 2010.08.20