본문 바로가기

Application Programming Interface/Windows API

Windows DDK 문서 IMEIMES.DOC - 2. IME User Interface(IME 사용자 인터페이스)

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

IME 개발을 위한 Win32 다국어 IME 개요

버전 1.32
최종 수정일: 1998년 4월 1일, 번역: Luciano Jeong


IME 사용자 인터페이스

 IME 사용자 인터페이스는 IME 윈도우, UI 윈도우 및 UI 윈도우에 포함되는 구성요소로 이루어집니다.

특징

IME 클래스는 미리 정의된 전역 클래스로서 파생 가능합니다. IME 클래스의 일반적인 특징은 다른 공용 컨트롤과 같습니다. 윈도우 인스턴스는 CreateWindowEx로 생성 가능합니다. STATIC 컨트롤처럼 IME 클래스로 만들어진 윈도우도 사용자 입력 자체에는 반응하지 않지만 컨트롤이 받을 수 있는 다양한 메시지를 수신하여 IME 사용자 인터페이스가 반응할 수 있게 합니다. 어플리케이션은 이 IME 클래스를 이용해 직접 생성하거나 ImmGetDefaultIMEWnd 함수를 사용하여 시스템에서 기본으로 제공하는 IME 윈도우를 얻는 식으로 자기 자신의 IME 윈도우를 소유할 수 있습니다. 윈도우 3.1과 비교하였을 때, 윈도우 핸들을 이용해 IME를 제어하려 하는 어플리케이션(IME를 인식하는 어플리케이션)은 아래와 같은 이점을 얻을 수 있습니다.

  • 새로운 IME는 후보 목록 윈도우(Candidates Listing Window)를 가질 수 있습니다. 각각의 어플리케이션은 이러한 사용자 인터페이스의 윈도우 인스턴스를 가질 수 있고, 이를 통해 사용자는 다른 어플리케이션으로 전환하는 작업을 위해 입력 작동을 도중에 중지할 수 있습니다. Windows 3.1 일본어 버전에서 사용자는 다른 어플리케이션으로 전환하기 위해 현재의 입력 작업을 직접 중지해야 했습니다.
  • IME 사용자 인터페이스가 어플리케이션의 윈도우 핸들을 알고 있기 때문에 어플리케이션을 위한 기본 작동을 수행할 수 있습니다. 예를 들어 이 사용자 인터페이스는 IME 윈도우의 자동 위치 설정(repositioning)을 수행할 수 있고, 윈도우의 캐럿(caret, 커서) 위치를 추적할 수 있고, 각 어플리케이션의 상태를 확인할 수 있습니다.

 시스템이 하나의 IME 클래스만을 제공한다고 해도, 여기에는 두 종류의 IME 윈도우가 있습니다. 하나는 IME를 인식하지 않는 프로그램을 위해 DefWindowProc 함수로 시스템이 생성한 IME 윈도우입니다. DefWindowProc으로 생성한 IME 사용자 인터페이스는 IME를 인식하지 않는 모든 윈도우들이 하나의 스레드로 공유하며 이 문서에서는 '기본 IME 윈도우'라 명명하겠습니다. 다른 하나는 IME를 인식하는 어플리케이션이 자기 자신의 윈도우를 위해 생성한 IME 윈도우로서 이 문서에서는 '어플리케이션 IME 윈도우'라 명명하겠습니다.

기본 IME 윈도우와 어플리케이션 IME 윈도우

 시스템은 스레드 초기화 시간에 기본 IME 윈도우를 생성하여 해당 스레드에 자동으로 부여합니다. 이 윈도우는 IME를 인식하지 않는 어플리케이션에서 IME 사용자 인터페이스를 다루게 됩니다.

 IME 또는 IMM이 WM_IME_xxxx로 시작하는 메시지를 발생하였을 때, IME를 인식하지 않는 어플리케이션은 이 메시지를 DefWindowProc으로 전달합니다. 그리고 DefWindowProcB 함수는 기본 IME 윈도우로 필요한 메시지를 전달합니다. 기본 IME 윈도우는 IME를 인식하지 않는 이 어플리케이션을 위해 IME 기본 작동을 수행합니다. IME를 인식하는 어플리케이션 또한 IME로부터 메시지를 후킹하지 않는 한 이 기본 IME 윈도우를 사용합니다. 필요할 때 자신이 소유한 어플리케이션 IME 윈도우를 사용할 수 있습니다.

IME 클래스

  Win32 시스템은 자체적으로 IME 윈도우 클래스를 제공한다고 하였습니다. 이 클래스는 EDIT 클래스가 미리 정의될 때 함께 정의됩니다. 시스템 IME 클래스는 IME의 사용자 인터페이스 전체를 다룹니다. 또한 IME 관련하여 IME, IMM 및 컨트롤과 주고받는 전체 메시지를 담당합니다. 어플리케이션은 이 클래스를 사용해 자기 자신의 IME 사용자 인터페이스를 재정의하여 생성할 수 있습니다. 시스템 IME 클래스는 그 자체로 어떤 IME를 대체할 수는 없고 단지 미리 정의된 클래스로만 남아 있습니다.

 이 클래스는 WM_IME_SELECT 메시지를 처리할 수 있는 윈도우 프로시저를 가졌습니다. 이 메시지는 새로 선택된 IME의 hKL(Handle Keyboard Layout)을 가지고 있습니다. 시스템 IME 클래스는 이 hKL과 각 IME로 정의되어 클래스의 이름이 부여됩니다. 이 이름을 사용하여 시스템 IME 클래스는 현재 활성화된 IME에 대한 사용자 인터페이스 윈도우를 생성합니다.

IME의 사용자 인터페이스 클래스

 이 설계에서 모든 IME는 시스템에게 각자의 사용자 인터페이스 윈도우 클래스를 등록할 것으로 간주되었습니다. 각 IME에게 제공되는 사용자 인터페이스 윈도우 클래스는 IME 관련 기능에 특히 응답해야 합니다. IME는 프로세스가 시작될 때 그 자신이 사용할 윈도우 클래스들을 등록해야 하며 이 작업은 DllEntry 함수가 DLL_PROCESS_ATTACH 메시지로 호출되었을 때 수행됩니다. 그런 다음 IME는 사용자 인터페이스 윈도우 클래스의 이름을 ImeInquire 함수의 두 번째 매개변수인 lpszClassName에 지정해야 합니다.

 사용자 인터페이스 윈도우 클래스는 모든 어플리케이션이 IME 윈도우 클래스를 통해 이를 사용하도록 style 멤버에 CS_IME 속성이 부여되어야 합니다. NULL 문자로 끝나는 이 사용자 인터페이스 윈도우 클래스 이름은 최대 16글자로 구성되어야 하며 차기 버전에서는 증가될 수 있습니다.

 사용자 인터페이스 윈도우 클래스의 cbWndExtra 멤버는 항상 2 * sizeof(LONG)이어야 합니다. 이는 시스템에서 정의된 사항입니다. (예: IMMGWL_IMC, IMMGWL_PRIVATE)

 IME는 어플리케이션과 함께 작동되는 동안 어떤 윈도우 클래스든 등록할 수 있고 어떤 윈도우이든 생성할 수 있습니다.

 다음 예는 IME 사용자 인터페이스 윈도우 클래스를 어떻게 등록하는지를 보여줍니다.

/* 사용 예 */
HINSTANCE hInst = NULL;

BOOL WINAPI DLLEntry(HINSTANCE hInstDLL, DWORD dwFunction, LPVOID lpNot)
{
	WNDCLASS wc;
	switch(dwFunction)
	{
	case DLL_PROCESS_ATTACH:
		hInst= hInstDLL;

		wc.style          = CS_MYCLASSFLAG | CS_IME;
		wc.lpfnWndProc    = MyUIServerWndProc;
		wc.cbClsExtra     = 0;
		wc.cbWndExtra     = 2 * sizeof(LONG);
		wc.hInstance      = hInst;
		wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
		wc.hIcon          = NULL;
		wc.lpszMenuName   = (LPTSTR)NULL;
		wc.lpszClassName  = (LPTSTR)szUIClassName;
		wc.hbrBackground  = NULL;

		if(!RegisterClass(&wc)) return FALSE;

		wc.style          = CS_MYCLASSFLAG | CS_IME;
		wc.lpfnWndProc    = MyCompStringWndProc;
		wc.cbClsExtra     = 0;
		wc.cbWndExtra     = cbMyWndExtra;
		wc.hInstance      = hInst;
		wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
		wc.hIcon          = NULL;
		wc.lpszMenuName   = (LPTSTR)NULL;
		wc.lpszClassName  = (LPTSTR)szUICompStringClassName;
		wc.hbrBackground  = NULL;

		if(!RegisterClass(&wc)) return FALSE;

		break;

	case DLL_PROCESS_DETACH:
		UnregisterClass(szUIClassName, hInst);
		UnregisterClass(szUICompStringClassName, hInst);

		break;
	}
	return TRUE;
}

사용자 인터페이스 윈도우

 :IME 윈도우 클래스를 통한 IME 윈도우는 시스템 또는 어플리케이션에 의해 생성됩니다. IME 윈도우가 생성되면, IME 윈도우의 소유로 사용자 인터페이스 윈도우가 함께 생성됩니다.

 각각의 사용자 인터페이스 윈도우는 현재의 입력 컨텍스트를 포함합니다. 입력 컨텍스트는 사용자 인터페이스 윈도우가 WM_IME_xxxx 메시지를 받았을 때에 한해 IMMGWL_IMC를 통해 GetWindowLong 함수로 얻을 수 있습니다. 이 사용자 인터페이스는 입력 컨텍스트를 참조할 수 있고 관련 메시지를 다룰수 있습니다. IMMGWL_IMC와 함께 GetWindowLong 함수를 호출하여 얻은 입력 컨텍스트는 사용자 인터페이스 프로시저가 살아있는 동안 계속 유효합니다. 단, WM_CREATE 메시지를 받았을 때는 제외입니다.

 사용자 인터페이스 윈도우 클래스의 cbWndExtra 멤버는 IME에 의해 확장되지 않습니다. IME가 윈도우 인스턴스의 확장 공간을 사용하려 한다면, 사용자 윈도우는 IMMGWL_PRIVATE를 지정하여 SetWindowLongGetWindowLong 함수를 사용합니다. 이 IMMGWL_PRIVATE 속성은 윈도우 인스턴스의 확장 공간에 있는 LONG형 값을 반환하게 합니다. 사용자 인터페이스 윈도우가 기타 용도를 위해 1개의 LONG보다 큰 확장 공간을 사용하고 싶다면, IMMGWL_PRIVATE 영역에 메모리 블럭을 위한 핸들을 기억시킬 수 있습니다. 사용자 인터페이스 윈도우 프로시저는 DefWindowProc 함수를 사용할 수 있습니다만, WM_IME_xxxx 메시지는 전달할 수 없습니다. IME 관련 메시지가 사용자 인터페이스 윈도우 프로시저에서 처리되지 않는다 할지라도 DefWindowProc으로 전달은 할 수 없습니다.

 아래 예는 private 메모리 블럭을 할당하고 사용하는 방법에 대해 시연하고 있습니다.

/* 사용 예 */
LRESULT UIWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	HIMC hIMC;
	HGLOBAL hMyExtra;
 
	switch(msg)
	{
	case WM_CREATE:
		// Allocate the memory block for the window instance.
		hMyExtra = GlobalAlloc(GHND,size_of_MyExtra);
		if (!hMyExtra) MyError();
		// Set the memory handle into IMMGWL_PRIVATE
		SetWindowLong(hWnd, IMMGWL_PRIVATE, (LONG)hMyExtra);
		// (생략)
		break;
	case WM_IME_xxxx:
		// Get IMC;
		hIMC = GetWindowLong(hWnd,IMMGWL_IMC);
		// Get the memory handle for the window instance.
		hMyExtra = GetWindowLong(hWnd, IMMGWL_PRIVATE);
		lpMyExtra = GlobalLock(hMyExtra);
		// (생략)
		GlobalUnlock(hMyExtra);
		break; 
	case WM_DESTROY:
		// Get the memory handle for the window instance.
		hMyExtra = GetWindowLong(hWnd, IMMGWL_PRIVATE);
		// Free the memory block for the window instance.
		GlobalFree(hMyExtra);
		break;
	default:
		return DefWindowProc(hWnd, msg, wParam, lParam);
	}
}

 사용자 인터페이스 윈도우는 모든 태스크(task)에 대해 현재 선택된 입력 컨텍스트를 참조하며 작동되어야 합니다. 어플리케이션 윈도우가 활성화될 때 IME 사용자 인터페이스 윈도우는 현재의 입력 컨텍스트를 포함한 메시지를 수신합니다. 사용자 인터페이스 윈도우는 입력 컨텍스트를 사용합니다. 그러므로 입력 컨텍스트는 사용자 인터페이스가 조합 윈도우(Composition Window), 상태 윈도우(Status Window) 등을 표시하기 위한 모든 정보를 포함해야 합니다.

 사용자 인터페이스 윈도우는 입력 컨텍스트를 참조하지만, 그 참조 값을 업데이트 할 필요는 없습니다. 그러나 사용자 인터페이스 윈도우가 입력 컨텍스트를 업데이트하고자 한다면 IMM 함수를 호출하면 됩니다. 입력 컨텍스트는 IMM에 의해 관리되기 때문에 IME를 동반하는 IMM은 입력 컨텍스트가 변화될 때 그 사항을 통보받아야 합니다.

 예를 들어 사용자 인터페이스가 사용자의 마우스 클릭으로 때때로 입력 컨텍스트의 변환 모드를 바꾸고자 합니다. 이 때, 사용자 인터페이스 윈도우는 ImmSetConversionMode 함수를 호출해야 합니다. ImmSetConversionMode 함수는 NotifyIME 함수 호출에 필요하고 사용자 인터페이스의 WM_IME_NOTIFY 메시지에도 필요한 통지를 생성합니다. 사용자 인터페이스 윈도우가 변환 모드의 상태가 변화되었음을 화면으로 출력하고자 한다면 이 윈도우는 WM_IME_NOTIFY 메시지가 수신될때까지 기다려야 합니다.

사용자 인터페이스 윈도우의 구성요소

 사용자 인터페이스 윈도우는 현재의 입력 컨텍스트를 참조함으로써 조합 윈도우(Composition Window)와 상태 윈도우(Status Window)를 등록하고 보여줄 수 있습니다. 사용자 인터페이스 윈도우 클래스의 style 멤버는 반드시 CS_IME 속성을 가져야 합니다. 사용자 인터페이스 윈도우 인스턴스는 조합되는 문자열, 폰트, 위치에 대한 정보를 입력 컨텍스트로부터 얻습니다.

 어플리케이션의 윈도우가 focus될 때, 시스템은 입력 컨텍스트를 이 윈도우에 부여하고 이 입력 컨텍스트를 IME의 사용자 인터페이스 윈도우에 전달합니다. 이 때 WM_IME_SETCONTEXT 메시지가 입력 컨텍스트의 핸들과 함께 어플리케이션으로 전달됩니다. 어플리케이션은 이 메시지를 다시 IME의 사용자 인터페이스 윈도우에 전달할 것입니다.

 입력 컨텍스트가 다른 입력 컨텍스트로 대체된 경우 사용자 인터페이스 윈도우는 조합 윈도우를 다시 그러야 합니다. 현재의 입력 컨텍스트가 바뀌는 때마다 사용자 인터페이스는 해당 윈도우에 맞는 조합 윈도우를 보여주어야 하기 때문입니다. 그러므로 IME 상태는 보장(assured)됩니다.

 사용자 인터페이스 윈도우는 IME 상태, 조합중인 문자열, 또는 변환 후보 목록을 표시하기 위해 자식 윈도우 또는 팝업 윈도우를 생성할 수 있습니다. 그러나 이러한 윈도우들은 사용자 인터페이스 윈도우가 소유해야 하며 DISABLED 속성을 갖는 윈도우로 생성되어야 합니다. IME가 만든 윈도우는 포커스를 갖지 말아야 하기 때문입니다.