본문 바로가기

Programming/API

IME를 사용해서 한글입력기를 만들잣!

출처 : 하이텔 게제동 강좌란

              IME를 사용해서 한글입력기를 만들잣! -_-;;.

                                                          (천리안:kjm37 나우:kjm37 하이털:puriat)
                                                                          홈피주소 : http://anoa.wo.to
-----------------------------------------------------------------------------
자 생일맞이 대 이벤뚜!! 초간단 IME 강좌를 시작합니닷!! 와아~ 짝짝짝~(박수웃)

p.s 강좌내에서는 존칭은 사양합니다;.

. IME란 무엇인가?
IME란 Input Method Editor의 약자로 한국 중국 일본어등 조합을 해야 사용할수
있는 언어 계열을 위한 에디터를 말한다고 한다.(배낀거다;. -_-;.)

. 어떻게 써야하는가?
IME란걸 직접 써보니 별것 아니였다;. 물론 어떤 부분에서 막혀서 몇일을 허비하
긴 했지만.. 일반적으로 들어오는 문자는 WM_CHAR 에서 받고.. 조합중인 글자만
IME함수를 사용해서 얻어오면 그뿐이다. 그리고 한자키 누르면 특수문자및 한자를
얻어와서 화면에 9개 찍어주면 그뿐이다.

. 왜 이런 허접강좌를 쓰게 됐는가?
내가알기론 소스는 널렸는데 강좌가 없어서;. 나처럼 강좌 없인 아무것도 할수없는
사람들을 위해서 자판을 들었다;. (-_-)~d 원츄!  (바로 이것이 원츄정신!)

어차피 윈도우 메세지를 가지고 조작하는것이기 때문에 메세지 루틴안의 가공이
필요로 하다. 하지만 그렇게하면 뽀대도 안나고 하니 함수를 하나 만들어서 빼돌
리자! 저 함수는 메세지 루틴안에서 메세지 루틴안에 들어가기 전에 돌려 줘야한다
착한 주명군은 예제 소스까지;;..


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

       if(GetText( hWnd, msg, wParam, lParam)==0) return 0;

       switch(msg){
   ..
       .
       .
       .
}

이런식으로 해주시면 됍니당.; imm32.lib  를 링크 해주셔야하구요..


char Text[255];     // 텍스트를 저장하기위한 변수
char Cstr[10];      // 조합중인 문자!!
char CanText[200];   // 특수문자를 위한 변수
int CNumber=0;        // 현제의 특수문자 위치
int CanMax=0;         // 현제 특수문자 목록의 최대 겟수

int GetText(HWND hWnd,UINT msg,WPARAM wparam, LPARAM lparam){
       int len;     // 그냥 여기저기서 써먹을 변수!
       HIMC        m_hIMC=NULL;   // IME 핸들


       switch (msg){

               case WM_IME_COMPOSITION:   //글씨조합중
                       return 0;

               case WM_CHAR:            // 문자 넘어오기
                       return 0;

               case WM_IME_NOTIFY:  // 한자입력...
                       return 0;

               case WM_KEYDOWN:    // 키다운..
                       return 0;

               case WM_KEYDOWN:
                       break;
       }
       return 1;
}


자 주석대롭니다. 텍스트를 저장하기 위한 변수엔 말그대로 글이 들어가구요.
조합중인 문자라던가 특수문자를 위한 변수라던가 전부다 주석 그대로의 용도에
쓰입니다. 저 길이는요 제가 막 넣었던건데 왜 제가 저렇게 넣었는지 지금은 기억이
안납니다요;. 조합중인 문자
의 길이는4바이트 정도만 있어도 돼는걸로 기억하는데 제가 왜 10으로 했었죠?
-_-;. 어째뜬 넘어감돠~

 저 글씨 조합중이란 메세지는 말그대로 글씨 조합중일때를 의미합니다 그땐. IME
함수를 사용해서 조합중인 글씨를 얻어오는거죠. 그리고 WM_CHAR는 영어면 그냥 넘
어오고 한글이라면 한글자가 완성이 되면 뿅~ 하고 넘어오게 돼는거죠. ^^;.  그리
고 그 아래에 있는 저 메세지는 한자키를 눌렸을때 나오는 메세지구요. 그 아래껀
한자키를 눌러서 나온 그 특수문자 박스의 왼쪽 오른쪽 이동(?)을 위해 사용합니다
(먼말인지 잘 모르시겠으면 지금 당장 아무 에디터에서나 가 라고 치고 한자키를
눌르셔서 왼쪽키 오른쪽키 눌러보시면 아시게 될껍니다)


case WM_IME_COMPOSITION:   // 메때지 처리루틴;;.

m_hIMC = ImmGetContext(hWnd);
  // ime핸들을 얻는것 ime 함수를 쓰려면 꼭 얻어야해요!

if (lparam & GCS_RESULTSTR){   // 까먹었음;. 완성되면과 비슷한;...
       if ((len = ImmGetCompositionString(m_hIMC, GCS_RESULTSTR, NULL, 0)) >
0){
             // 현제 IME의 스트링 길이를 얻는다;.(조합중인이라 생각하심이)

               ImmGetCompositionString(m_hIMC, GCS_RESULTSTR, Cstr, len);
             // Cstr에 조합중인 문자열을 받아낸다.
             // 함수명은 똑같구 인자에 저게 붙으면 넘어온다는;;..

               Cstr[len] = 0;
             // 젤 끝에 0을 붙여서 깨끗히 해준돠!!

               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 핸들 반환!!


* 주석 대롭니다;;..  case WM_IME_COMPOSITION: 메세지 안에 넣어주심 됩니다.



case WM_CHAR:        // 한글 이외의 나머지 글은 이리로 들어옵니다. ^^;.


if(wparam == 8 ){      // 만약 8번(빽스페이스)라면..

       if(strlen(Text) > 0){   // 길이가 0보다 길면

               if(strlen(Text) < 0){       // 지울께 0보다 작으면(확장코드면;.)
            // 완성형에서 한글 앞잔지 뒷잔지 알려주는 함수가있긴한데
            // 귀찮아서 이걸로 때움;. -_-;.

                       Text[strlen(Text)-1] = 0;  // 한자를 지운다. 뒤에서 또지우니
                                                           // 2바이트지우는셈..
               }

               Text[strlen(Text)-1] = 0;   // 한자를 지운다;.

               memset(Cstr,0,10);         // 조합중문자를 초기화..(왜했지? 기억이.)
       // 만약 글자 조합중 일때 빽스페이스가 들어오면 이리 메세지로 안들어
       // 오고 조합중이란 메세지로 들어오니 염려 놓으시길;;..
       }
}else{  // 빽스페이스가 아니면..
       len = strlen(Text);
       Text[len] = wparam & 0xff;   //  넘어온 문자를 문자열에 넣기..
       Text[len] = 0;            //  뒤에 0붙이깃!!
}


* 자 이것도 별거 없었죠? ^^;. 다음 메세지로 넘어가기 전에 화면에 찍기부터
보여 드림덩!!


void putstring(HWND hWnd){

       char Text1[255];
       memset(Text1,0,255);

       HDC hDC = GetDC(hWnd);

       TextOut(hDC,0,60,CanText,strlen(CanText));        // 특수문자가 있음 찍어주기;.

       strcpy(Text1,Text);
       if(Cstr[0] != 0 ){
               strcpy(Text1 + strlen(Text), Cstr);
       }
       strcpy(Text1 + strlen(Text1), "_");

       TextOut(hDC,0,0,Text1,strlen(Text1));

       ReleaseDC(hWnd,hDC);
}


// 자 찍기~ 주석필요 없이 간단하죠? -_-;. 알아서 꾸며주심 됩니다.; 여기까지만
해도 그냥 한글 입력은 이미 다 돼신 거에요.. 그럼 다음 메세지로 넘어가죠!



case WM_IME_NOTIFY:  // 한자입력...
       GetCandi(hWnd,wparam,lparam,0);
        // 이건 좀 기니까 따로 함수로 빼놨습니다.;
       break;




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, 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=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, lpCandList, 0)))break;
                                  // 길이를 얻는다

                       m_CandList = (LPCANDIDATELIST)new char[dwBufLen];
                       // 또 메모리 할당한다;.

                       lpCandList = m_CandList;
                       // 역시 위와 마찬가지로 어느날  이렇게;;.

                       ImmGetCandidateList(m_hIMC, 0, lpCandList, dwBufLen);
                       //lpCandList에 목록을 얻는다;.

                       for(i=CNumber;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);
}



* 쿨럭 길군요; -_-;. 젤 구조화도 안돼있고 왜 저렇게 짰는지 이해가 안가는 부분
이 많은 함수;;... 어쩨뜬 이제 마지막 메세지 처리할 WM_KEYDOWN 함수만 남았군뇨
^^;.




case WM_KEYDOWN:    // 키가 눌렸을때..

                       if(CanText[0]==0) break;
                                // 특수문자에 글씨가 없뜨면;;..
                                // 그러니까 창이 안열여뜨면!

                       if(wParam == VK_PROCESSKEY){
                                // 프로세스키로 들어가는거면..
                                // 특수문자 창이 열렸을경우 이렇게
                                // 들어가요;;..

                               if((lParam & 0xff0000) == 4915200) // 왼쪽이면;;. -_-;.
                               {  
                                       if(CNumber >0)CNumber -= 9; // 0보다 크면 9빼기

                                       GetCandi(hWnd,wParam, lParam,CNumber);
                                       break;
                               }

                               if((lParam & 0xff0000) == 5046272)  // 오른쪽이면;;..
                               { 
                                       if(CNumber+9 < CanMax)CNumber += 9;  // 구더하기..

                                       GetCandi(hWnd,wParam, lParam,CNumber);
                                       break;
                               }
                       }
                       break;

'Programming > API' 카테고리의 다른 글

WM_CHAR 메시지와 WM_KEYDOWN 메시지  (0) 2013.08.08
가상키코드  (0) 2013.08.08
멀티바이트와 유니코드  (0) 2013.08.06
메세지 박스  (0) 2013.08.05
char*, LPCTSTR, TCHAR 의 차이  (0) 2013.07.25