한글 IME (Input Method Editing)를 구현
이 내용은 "한컴 프레스"에서 나온 "따라해보세요 Visual C++ 6" 에서 가져온 내용입니다.
![]()
IME를 구현한다고 해서 직접 IME를 만들어보자는 것은 아니고, 위의 그림처럼 상태바에 한글/영문 상태를 구별할 수 있도록 출력하자는 것이다.
미국 MS에서 만든 Visual C++ 6.0은 기본적으로 한글 IME 기능을 제공하지 않기 때문에 개발자 스스로 한글 IME에서 발생되는 메시지를 뷰에서 잡아 처리해야 한다. 한글 비주얼 베이직 5.0과 6.0에서는 기본으로 한글 IME 기능이 기본으로 제공되고 있다.
여기서는 한/영 키를 누르면 한글과 영문이 바뀌며 출력되고, 그 페인 위에서 마우스 왼쪽 버튼을 눌러도 한영이 바뀌도록 구현한다.
1. StdAfx.h 파일에 다음과 같이 Imm.h 파일을 인클루드 한다.
#include <afxwin.h> //
MFC core and standard components
#include <afxext.h> //
MFC extensions
#include <afxdisp.h> //
MFC Automation classes
#include <afxdtctl.h> //
MFC support for Internet Explorer 4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include
<afxcmn.h> //
MFC support for Windows Common Controls
#include <Imm.h>
#endif
// _AFX_NO_AFXCMN_SUPPORT
2. 뷰의 헤더파일을 연다. 클래스 위저드에서 지원하지 않기 때문에 다음처럼 직접 코드를 기술한다.
// Generated message map functions
protected:
//{{AFX_MSG(CImmTestView)
//}}AFX_MSG
afx_msg
LRESULT OnIMENotify(WPARAM wParam, LPARAM LParam); // 추가
DECLARE_MESSAGE_MAP()
};
3. 뷰의 cpp 파일에도 다음처럼 한 줄을 추가한다.
IMPLEMENT_DYNCREATE(CImmTestView, CView)
BEGIN_MESSAGE_MAP(CImmTestView,
CView)
//{{AFX_MSG_MAP(CImmTestView)
//}}AFX_MSG_MAP
ON_MESSAGE(WM_IME_NOTIFY,
OnIMENotify) // 추가
//
Standard printing commands
ON_COMMAND(ID_FILE_PRINT,
CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT,
CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW,
CView::OnFilePrintPreview)
END_MESSAGE_MAP()
4. 위에서처럼 추가한 메시지에 대한 핸들러 코드를 뷰의 cpp 파일에 작성한다.
LRESULT CImmTestView::OnIMENotify(WPARAM wParam, LPARAM lParam)
{
if(wParam
== IMN_SETCONVERSIONMODE) {
HIMC
hIMC = ::ImmGetContext(m_hWnd);
DWORD
dwConversion;
DWORD
dwSetence;
::ImmGetConversionStatus(hIMC,
&dwConversion, &dwSetence);
CString
strMode;
if(dwConversion
& IME_CMODE_NATIVE)
strMode
= "한글";
else
strMode
= "영문";
BOOL
bRet = ::ImmReleaseContext(m_hWnd, hIMC);
((CMainFrame
*)AfxGetMainWnd())->m_wndStatusBar.SetPaneText(2, strMode);
}
return
Default();
}
5. 4번에서 메인 프레임 클래스에 접근하기 위해서 뷰의 cpp 파일에 다음처럼 메인 프레임의 헤더파일을 인클루드 한다.
#include "MainFrm.h"
그리고 m_wndStatusBar에 접근하기 위해 MainFrm.h 파일에 정의되어 있는 CStatusBar의 변수 m_wndStatusBar를 private에서 public으로 변경한다.
6. 5번까지 작성한 상태로 컴파일을 하면 초기에 한/영 이 출력되지 않다가 한/영 키를 누른 다음부터 제대로 동작하는 것을 알 수 있다.
이것을 해결하기 위해 뷰의 OnInitialUpdate() 함수에 OnIMENotify() 함수의 내용을 한번 더 적는다.
void CImmTestView::OnInitialUpdate()
{
CView::OnInitialUpdate();
//
TODO: Add your specialized code here and/or call the base class
//
처음 시작할 때 한영 상태표시를 위해 OnIMENotify 함수와
//
같은 코드를 한번 더 써준다.
HIMC
hIMC = ::ImmGetContext(m_hWnd);
DWORD
dwConversion;
DWORD dwSetence;
::ImmGetConversionStatus(hIMC,
&dwConversion, &dwSetence);
CString
strMode;
if(dwConversion
& IME_CMODE_NATIVE)
strMode
= "한글";
else
strMode
= "영문";
BOOL
bRet = ::ImmReleaseContext(m_hWnd, hIMC);
((CMainFrame
*)AfxGetMainWnd())->m_wndStatusBar.SetPaneText(2, strMode);
}
7. 상태바의 한/영 페인을 마우스의 왼쪽버튼을 누를 때마다 바뀌도록 만들기 위해 몇 가지 작업을 해야 하겠다. 우선 CStatusBar에서 파생된 CMyStatusBar 클래스를 새로 만든다. 클래스 위저드에서 CStatusBar를 베이스 클래스로 지원하지 않기 때문에 CStatusBarCtrl에서 파생시킨 후 CStatusBarCtrl을 CStatusBar로 모두 바꾼다. (헤더파일과 cpp 파일 모두)
그러다음 WM_LBUTTONDOWN 메시지를 오버라이드한다.
void CMyStatusBar::OnLButtonDown(UINT nFlags, CPoint point)
{
//
TODO: Add your message handler code here and/or call default
HIMC
hIMC = ::ImmGetContext(this->m_hWnd);
CString
strHangulMode("한글"), strAphaMode("영문");
CRect
rect;
this->GetItemRect(2,
&rect);
if(rect.PtInRect(point))
{
BOOL
nMode = ::ImmGetOpenStatus(hIMC);
if(nMode
== 0)
::ImmSetConversionStatus(hIMC,
IME_CMODE_HANGEUL,
IME_SMODE_NONE);
if(nMode
== 1)
::ImmSetConversionStatus(hIMC,
IME_CMODE_ALPHANUMERIC,
IME_SMODE_NONE);
this->SetPaneText(2,
(nMode == 1) ? strAphaMode : strHangulMode);
}
BOOL
bRet = ::ImmReleaseContext(this->m_hWnd, hIMC);
CStatusBar::OnLButtonDown(nFlags,
point);
}
8. 한글 IME의 DLL인 imm32.dll을 임포트하기 위해 imm32.lib를 프로젝트에 추가한다.
![]()
참고사항
GetItemRect
설명 : 특정 상태바 창에 대한 바운딩 사각형을 얻는다.
구문 : void GetItemRect( int nIndex, LPRECT lpRect ) const;
파라미터
nIndex : 특정 상태바
창에 대한 바운딩 사각형을 얻는다.
lpRect
: 채워지는 사각형 구조체의 포인터
리턴값 : 없음.
참조 : CStatusBar::SetPaneInfo, CStatusBar::GetPaneInfo
(예제)
CRect rect;
pBar->GetItemRect(2, &rect); // 3번째 창에
대한 바운딩 사각형을 얻는다.
PtInRect
설명 : 기술한 위치가 CRect의 바운드 내에 있는가를 판단한다. 위치가 모두 4개 부분 내에 있거나 왼쪽이나 맨 윗 부분(맨 아래나 오른쪽은 아니다)에 있으면, 위치는 사각형 내에 있게 된다.
구문 : BOOL PtInRect( POINT point ) const;
파라미터
point : 검사하는 위치
리턴값 : 위치가 CRect 내에 있으면 TRUE, 그렇지 않으면 FALSE
참조 : ::PtInRect
(예제)
void CMyClass::OnLButtonDown(,,CPoint point)
{
CRect
screenRect(20, 20, 100, 100); //
화면의 관심있는 영역
if(screenRect.PtInRect(point))
{
//
사용자가 관심있는 영역에 마우스 단추를 누른다.
}
................
}
SetPaneText
설명 : 특정 상태바 창에 대해 텍스트를 설정한다.
구문 : BOOL SetPaneText( int nIndex, LPCTSTR lpszNewText, BOOL bUpdate = TRUE );
파라미터 :
nIndex :
특정 상태바 창을 나타내는 0에서 시작하는 인덱스
lpszNewText
: 새로운 창 텍스트
bUpdate :
상태바가 지금 갱신되어야 하면 TRUE, 그렇지 않으면 FALSE
리턴값 : 성공하면 TRUE, 그렇지 않으면 FALSE
참조 : CStatusBar::GetPaneInfo
- the end of this article -