이준곤(LeeChen)님이 작성하신 IME 관련 내용 풀 소스로 만들어본것입니다.
뭐 큰 변경은 없지만 잘잘한 것 조금 변경했습니다.
#pragma comment(lib,"imm32.lib")
#include <windows.h>
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
HINSTANCE g_hInst;
HWND hWndMain;
LPCTSTR lpszClass=TEXT("Ime1");
void putstring(HWND hWnd);
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_IBEAM);
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);
putstring(hWnd);
}
return (int)Message.wParam;
}
#include <imm.h>
char Text[255]; // 텍스트를 저장하기위한 변수
char Cstr[10]; // 조합중인 문자!!
char CanText[200]; // 특수문자를 위한 변수
int CNumber=0; // 현제의 특수문자 위치
int CanMax=0; // 현제 특수문자 목록의 최대 겟수
//WinAPI창에 출력
void putstring(HWND hWnd){
//더블버퍼링 준비(백버퍼생성)
HDC hDC = GetDC(hWnd);
HDC hDCMem;
RECT rect;
HBITMAP BitMem, OldBitMap;
hDCMem = CreateCompatibleDC(hDC);
GetClientRect(hWnd, &rect);
BitMem = CreateCompatibleBitmap(hDC, rect.right-rect.left, rect.bottom - rect.top);
OldBitMap = (HBITMAP)SelectObject(hDCMem, BitMem);
FillRect(hDCMem, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH)); // 전체를 하얗게
//문자열 작성
char Text1[255];
memset(Text1,0,255);
TextOut(hDCMem,0,60,CanText,strlen(CanText)); // 특수문자가 있음 찍어주기;.
strcpy(Text1,Text);
if(Cstr[0] != 0 ){
strcpy(Text1 + strlen(Text), Cstr);
}
strcpy(Text1 + strlen(Text1), "_");
TextOut(hDCMem,0,0,Text1,strlen(Text1));
//ReleaseDC(hWnd,hDCMem);
//백버퍼를 메인버퍼로 옮김
BitBlt(hDC, rect.left,rect.top,rect.right - rect.left,rect.bottom - rect.top,hDCMem,0,0,SRCCOPY);
BitMem = (HBITMAP)SelectObject(hDCMem, OldBitMap);
//사용한 핸들 반환
DeleteDC(hDCMem);
ReleaseDC(hWnd, hDC);
DeleteObject(BitMem);
}
//특수문자 처리
void GetCandi(HWND hWnd, WPARAM wParam, LPARAM lParam,int Number)
{
DWORD dwBufLen; // 버퍼길이
LPCANDIDATELIST lpCandList; // 특수문자 리스트
char aa[255];
int i;
LPCANDIDATELIST m_CandList;
HIMC m_hIMC = ImmGetContext(hWnd);
switch (wParam) {
case IMN_OPENCANDIDATE: // 처음 열렸을때.;;;;
memset(CanText,0,100); // 특수문자가 들어갈 변수 초기화
if(!(dwBufLen = ImmGetCandidateList(m_hIMC, 0, NULL,0)))break;//lpCandList, 0)))break;
// 리스트의 길이 받기..
m_CandList = (LPCANDIDATELIST)new char[dwBufLen]; // 길이만큼 메모리 얻기
lpCandList = m_CandList;
ImmGetCandidateList(m_hIMC, 0, lpCandList, dwBufLen);
// 할당받은 데로 리스트를 받는다.
// 아까도 그랬지만 인자에 따라서 같은 함수가 용도가 달라짐;;...
CanMax=lpCandList->dwCount;
// 특수문자 목록의 겟수를 넣는다!
for(i=Number;i<Number+9; i++) // 한번에 9개만 보이니까 9개만받는다.
{
if(i>=lpCandList->dwCount) break;
// 모두 알다시피 더크면 뽀로롱~ 나간다!
LPSTR lpStr = (LPSTR)lpCandList + lpCandList->dwOffset[i];
// 문자얻기;.
strcpy(CanText + strlen(CanText), lpStr);
// 특수문자 문자열에 넣는다;.
// 근데 왜 두번이나 지나서 넣는거지? -_-;.
}
delete m_CandList; // 만든걸 날린다!
m_CandList=NULL; // 널을 넣는다;.(안넣어도 무방하다;.)
CNumber = 0; // 현제의 특수문자 번호를 0으로 만든다;.
break;
case IMN_CHANGECANDIDATE: // 딴 키를 눌러서 새로운 목록으로 바꾸기라면
memset(CanText,0,100); // 또 다 날린다!
if(!(dwBufLen = ImmGetCandidateList(m_hIMC, 0, NULL, 0)))break;// 길이를 얻는다
m_CandList = (LPCANDIDATELIST)new char[dwBufLen]; // 또 메모리 할당한다;.
lpCandList = m_CandList;// 역시 위와 마찬가지로 어느날 이렇게;;.
ImmGetCandidateList(m_hIMC, 0, lpCandList, dwBufLen);
// lpCandList에 목록을 얻는다;.
for(i=Number;i<Number+9; i++) // 한번에 9개만 보이니까 9개만받는다.
{
if(i>=lpCandList->dwCount) break; // 역시 더크면 뾰로롱 나간다~
LPSTR lpStr = (LPSTR)lpCandList + lpCandList->dwOffset[i]; // 위처럼 lpStr에 문자를 넣고..
strcpy(CanText + strlen(CanText), lpStr);
}
delete m_CandList; // 역시 할당한것을 날리고
m_CandList=NULL; // 리스트에 널을 넣는다.
break; // 빠져나온다..
case IMN_CLOSECANDIDATE: // 목록 리스트가 닫힐경우.
CanText[0]=0; // CanText젤 앞에 0을 넣어버린다;;.
break;
}
ImmReleaseContext(hWnd, m_hIMC);
}
int GetText(HWND hWnd,UINT msg,WPARAM wparam, LPARAM lparam)
{
int len; // 그냥 여기저기서 써먹을 변수!
HIMC m_hIMC=NULL; // IME 핸들
switch (msg){
case WM_IME_COMPOSITION: // 글씨조합중
m_hIMC = ImmGetContext(hWnd); //현재윈도우핸들이 ime핸들을 얻는다.
if(lparam & GCS_RESULTSTR) //조합이 완료되면
{
len = ImmGetCompositionString(m_hIMC,GCS_RESULTSTR,NULL,0);//현재 IME의(조합중인) 스트링 길이를 얻는다.
if(len >0)
{
ImmGetCompositionString(m_hIMC,GCS_RESULTSTR,Cstr, len);//Cstr에 조합중인 문자열을 받아낸다,.
Cstr[len] = 0; //젤 끝에 0을 붙여서 끝을 표시한다.
//조합중인 문자는 완료된 상태이기때문에 최종 문자저장소에 넣는다.
//strcpy(Text+strlen(Text),Cstr); //전체 내용(실제 보일 텍스트) 뒤에 붙여준다.
strcpy(Text+strlen(Text),Cstr);
memset(Cstr,0,10); //지움
}
}
else if (lparam & GCS_COMPSTR){ // 조합중이면;.
len = ImmGetCompositionString(m_hIMC, GCS_COMPSTR, NULL, 0);// 조합중인 길이를 얻는다.
ImmGetCompositionString(m_hIMC, GCS_COMPSTR, Cstr, len); // str에 조합중인 문자를 얻는다.
Cstr[len] = 0;// 뒤에 0을 붙인다.
// 이렇게 해두시고 글씨 찍을때 Text + Cstr 하셔서 찍어주시면 된다
// 이건 쫌있다가 찍는 예제를 하나 보여드리죠!
}
ImmReleaseContext(hWnd, m_hIMC);// IME 핸들 반환!!
return 0;
case WM_CHAR: // 한글 이외의 나머지 글은 이리로 들어옵니다. ^^;.
if(wparam == 8 ){ // 만약 8번(빽스페이스)라면..
if(strlen(Text) > 0){ // 길이가 0보다 길면
//isDBCSLeadByte //한글의 첫번째 바이트라면 true 두번째 바이트나 영어라면 false;로 체크
if(strlen(Text)>1 && IsDBCSLeadByteEx(949,Text[strlen(Text)-1])) // 949 means Hangul code page
{
//if(!IsDBCSLeadByteEx(0,Text[strlen(Text)-1])) //만약 특수키체크(특수키 '\' '?'등등);
//{
// Text[strlen(Text)-1] = '\0'; // 한자를 지운
//}else
{
Text[strlen(Text)-2] = '\0'; // 한자를 지운다;.
}
}
else //영어
{
Text[strlen(Text)-1] = '\0'; // 한자를 지운다;.
}
memset(Cstr,0,10); // 조합중문자를 초기화..(왜했지? 기억이.)
// 만약 글자 조합중 일때 빽스페이스가 들어오면 이리 메세지로 안들어
// 오고 조합중이란 메세지로 들어오니 염려 놓으시길;;..
}
}else{ // 빽스페이스가 아니면..
len = strlen(Text);
Text[len] = wparam & 0xff; // 넘어온 문자를 문자열에 넣기..
//Text[len+1] = 0; // 뒤에 0붙이깃!!
}
return 0;
case WM_IME_NOTIFY: // 한자입력...
GetCandi(hWnd,wparam,lparam,CNumber);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc=BeginPaint(hWnd,&ps);
EndPaint(hWnd,&ps);
return 0;
}
case WM_KEYDOWN: // 키다운..
if(CanText[0]==0) break;
// 특수문자에 글씨가 없뜨면;;..
// 그러니까 창이 안열여뜨면!
if(wparam == VK_PROCESSKEY){
// 프로세스키로 들어가는거면..
// 특수문자 창이 열렸을경우 이렇게 // 들어가요;;..
if((lparam & 0xff0000) == 4915200){ // 왼쪽이면
if(CNumber >0)CNumber-=9;
break;
}
if((lparam & 0xff0000) == 5046272){ // 오른쪽이면;;..
if(CNumber+9 < CanMax)CNumber+=9;// 구더하기..
break;
}
}
break;
}
return 1;
}
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
if(GetText(hWnd, iMessage,wParam, lParam) == 0)return 0;
switch(iMessage) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}