. DefIme 예제

운영체제는 한글이 조립중일 때 응용 프로그램으로 IME 메시지를 보내준다. 그러나 이 메시지를 처리하지 않아도 완성된 문자를 WM_CHAR 메시지로 보내기 때문에 문자입력을 위해 IME 메시지를 반드시 처리할 필요는 없으며, 보통 IME 메시지는 무시한다. 설령 이 메시지를 처리하지 않더라도 에디트 컨트롤을 사용하면 문자열을 입력받는데 별 불편함이 없기 때문이다.

하지만 메인 윈도우가 직접 문자를 입력받아야 한다거나 아니면 에디트 컨트롤을 대체하기 위한 커스텀컨트롤을 만들고자 할 때는 상황이 조금 달라진다. IME 메시지를 전혀 처리하지 않고 문자를 입력받는 예제를 만들어보자. 비주얼 스튜디오 7.0을 실행하고 [파일-새로 만들기-프로젝트] 항목을 선택한다.

프로젝트 형식은 Visual C++ 프로젝트를 선택하고, 오른쪽의 템플릿에서는 Win32 프로젝트를 선택한다. 위치는 실습용으로 미리 준비해 둔 C:\ApiPractice\Ime 폴더를 지정하고 프로젝트 이름은 DefImef라 하자. 확인 버튼을 클릭하면, 다음 대화상자를 통해 프로젝트의 형식을 물어온다.

마법사가 만들어주는 코드를 사용하지 않고 처음부터 소스를 작성할 것이므로 빈 프로젝트 옵션을 선택하도록 하자. 그러면 아무 부속파일도 가지지 않는 비어 있는 프로젝트를 만들어 줄 것이다. 프로젝트를 만든 후 [프로젝트-새 항목 추가]를 선택하여 이 프로젝트에 DefIme.cpp 소스파일을 추가한다.

그리고 이 파일에 다음과 같이 소스를 입력한다. 이상은 비주얼 C++로 프로젝트를 만드는 일반적인 과정인데 다음 프로젝트부터 이 방식대로 계속 작성하면 된다. 비주얼 C++ 6.0을 사용할 경우도 대화상자의 모양이 조금 다를 뿐 프로젝트를 만드는 방법은 거의 동일하다.

 

#include <windows.h>

 

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE g_hInst;

HWND hWndMain;

LPCTSTR lpszClass=TEXT("DefIme");

 

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance

       ,LPSTR lpszCmdParam,int nCmdShow)

{

     HWND hWnd;

     MSG Message;

     WNDCLASS WndClass;

     g_hInst=hInstance;

    

     WndClass.cbClsExtra=0;

     WndClass.cbWndExtra=0;

     WndClass.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);

     WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);

     WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);

     WndClass.hInstance=hInstance;

     WndClass.lpfnWndProc=(WNDPROC)WndProc;

     WndClass.lpszClassName=lpszClass;

     WndClass.lpszMenuName=NULL;

     WndClass.style=CS_HREDRAW | CS_VREDRAW;

     RegisterClass(&WndClass);

 

     hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,

          CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,

          NULL,(HMENU)NULL,hInstance,NULL);

     ShowWindow(hWnd,nCmdShow);

     hWndMain=hWnd;

    

     while(GetMessage(&Message,0,0,0)) {

          TranslateMessage(&Message);

          DispatchMessage(&Message);

     }

     return (int)Message.wParam;

}

 

TCHAR *buf;

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

     HDC hdc;

     PAINTSTRUCT ps;

     int len;

 

     switch(iMessage) {

     case WM_CREATE:

          buf=(TCHAR *)malloc(65536);

          memset(buf,0,65536);

          return 0;

     case WM_CHAR:

          len=lstrlen(buf);

          buf[len]=(TCHAR)wParam;

          buf[len+1]=0;

          InvalidateRect(hWnd,NULL,TRUE);

          return 0;

     case WM_PAINT:

          hdc=BeginPaint(hWnd,&ps);

          TextOut(hdc,0,0,buf,lstrlen(buf));

          EndPaint(hWnd,&ps);

          return 0;

     case WM_DESTROY:

          PostQuitMessage(0);

          free(buf);

          return 0;

     }

     return(DefWindowProc(hWnd,iMessage,wParam,lParam));

}

 

입력된 문자들을 buf 배열에 모아 두었다가 WM_PAINT에서 TextOut으로 출력하는데 이 프로그램이 문자입력을 위해 처리하는 메시지는 WM_CHAR뿐이다. WM_CHAR 메시지를 받았을 때 wParam으로 전달된 문자코드를 buf 배열 끝에 누적시키기만 할 뿐인데 보다시피 한글도 잘 입력된다.

한글 모드에서 키보드를 누르면 IME가 먼저 이 키입력을 해석하여 한글조립을 처리한다. 그리고 한 음절이 완성되면 WM_CHAR 메시지를 보내 입력된 문자를 전달한다. 한글은 2바이트 문자이기 때문에 WM_CHAR 메시지가 두 번 오는데, 예를 들어 을 입력하면 199(0xc7), 209(0xd1)가 차례대로 절달된다. 어쨌든 WM_CHAR에서 이 두 문자코드를 버퍼에 모았다가 TextOut으로 출력하기만 하면 한글이 제대로 보인다.

WM_CHAR 메시지는 완성된 음절에 대해서만 전달되므로 조립중인 모양이 바로바로 보이지는 않는다. 기다림을 입력할 경우 키를 누르는 순서에 따라 메시지가 어떤 순서대로 전달되고 조립 윈도우와 화면에 문자들이 어떻게 보이는지 관찰해보자.

 

조립 윈도우

화면

메모장

메시지

 

 

 

 

 

 

기다

WM_CHAR ‘

 

기달

 

기다

기다리

WM_CHAR ‘

 

기다림

 

스페이스

 

기다림

기다림

WM_CHAR ‘

 

똑같은 문자열을 메모장으로 입력하면 조립중인 문자들을 제대로 보여주는데 에디트 컨트롤이 IME 메시지를 처리하고 있기 때문이다. DefIme 예제는 IME 메시지를 무시하고 WM_CHAR 메시지만 처리하므로 조립중인 문자는 보이지 않는다. 만약 조립중인 문자를 화면에 출력하고 싶다면 직접 IME 메시지를 처리해야 하며 그래서 텍스트 편집기를 만들기 전에 IME를 먼저 연구해야 하는 것이다.