Programming/C/C++

IME 관련

blueasa 2010. 9. 10. 17:14

이준곤(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));

}

[출처] IME 관련|작성자 찐남자

반응형