블로그 이미지
Every unexpected event is a path to learning for you. blueasa

카테고리

분류 전체보기 (2797)
Unity3D (853)
Programming (479)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (185)
협업 (61)
3DS Max (3)
Game (12)
Utility (68)
Etc (98)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (55)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday

HIMC ImmGetContext(HWND); -> IME 를 가져온다.

BOOL ImmGetOpenStatus(HIMC ); ->return 값이 1이면 한글 0이면 영문

< 예제 >

HIMC hIMC;
int hanFlag=-1;

hIMC = ImmGetContext(wnd->m_hWnd);


// 한영상태를 얻는다.
// hanFlag가 1이면 한글 0이면 영문
hanFlag=ImmGetOpenStatus(hIMC );


if(hanFlag)
{
m_imm.SetWindowText((LPCTSTR)"H");
}
else
{
m_imm.SetWindowText((LPCTSTR)"E");
}

반응형

'Programming > C#' 카테고리의 다른 글

[C#] xml 파싱  (0) 2011.10.25
C#으로 xml 처리하기  (0) 2011.10.25
C# 경로(Path) 요소 분리하기  (0) 2011.09.16
C# XML 다루는 간단한 소스  (0) 2011.09.16
DLL 파일을 별도 폴더에서 관리하자  (0) 2011.09.14
Posted by blueasa
, |

IME 소스 (한글)

Programming/C/C++ / 2010. 11. 26. 21:58



ime 뭉탱이(module)  날읽어(README) ver 0.01

                     안노라군.
                 TEAM TRINITY.
             http://anoa.wo.to 
             kjm37@hanmail.net
//---------------------------------------------------------------------
적은 허접한 맨트와.. 버그있는 소스로 ime 강좌(같지도 않은)를 써서 
초보 IMER (ime + er)분 들을 나락의 길(?)로 빠트렸던 anoa 군입니다.;

아직도 몇몇 군데의 웹페이지들에 그 글들이 있길래. 너무도 죄송한(이라고 
쓰고 쪽팔린 이라고 읽는다.) 마음에.. 최종버전 소스를 정리해서 올립니다.


이번엔 강좌대신 상세한 주석(이라고 쓰고 게으름이라고 읽는다)으로 때웁니다.


          2003. 2. 16.
           class 청소부.  아노아군.

//---------------------------------------------------------------------
 소스
//---------------------------------------------------------------------
 프로젝트  : vc.net (vc 7.0) 
 마지막 업데이트 : 2003 년 2월 17일.
 소스의 기능  : IME 입력 및.. 특수문자(한자)의 목록 얻어내기.
      커서 기능 추가. (멀티라인은 지원하지 않습니다.)
 프로젝트구성 : ime
      +- BASE
       +- Error.h  // 에러 메세지용 헤더
       +- Main.cpp  // WinMain 및 프록시져.
       +- Main.h
       +- stdafx.cpp
       +- stdafx.h  // 프리컴파일헤더
      +- IME
       +- ImeBox.cpp // 각각의 ImeBox.
       +- ImeBox.h
       +- Ime.cpp  // ImeBase
       +- Ime.h
      +- Document
       +- ReadMe.txt // 지금 이문서.

//---------------------------------------------------------------------
 사용방법.
file://---------------------------------------------------------------------

 . 주석을 읽기가 귀찮으신분은 ImeBox.cpp ImeBox.h ime.cpp ime.h 를 그대로
가져다 쓰시고 main.cpp 부분을 참고하셔서 붙이시길 바랍니다.

 . 한국어외의 다른 ime 입력을 보장하지 않습니다.. (수고하세요)
 
 . ime 특유의.. 입력 오류시 띵띵~ 거리는 소리를 없에실 좋은 아이디어가 있
    으신 분은 연락을 주세요.

 . 소스를 편집 및 재배포 할시에는 연락을(홈페이지) 해주세용~♡ 재배포시
  에는 본문서에 하나의 파트를 만드시고.. 소스의 구성이나 편집한 부분.
  아직 해야할부분. 작성자 등을 남겨주세요.


//---------------------------------------------------------------------
 버전(버진 아님. -//-)
file://---------------------------------------------------------------------
v 0.1    kwonil 님의 도움으로.. 조합중이던 문자를 날렸음. - _-)V



출처 : http://blog.naver.com/cpp2angel?Redirect=Log&logNo=100007002652

[출처] IME 소스 (한글)|작성자 아발롱


반응형

'Programming > C/C++' 카테고리의 다른 글

ifdef, if defined, ifndef, if !defined  (0) 2011.03.04
enum, 보다 나은 enum  (0) 2011.01.13
[C++] 형변환 (Typecasting) - const_cast, reinterpret_cast, static_cast, dynamic_cast  (0) 2010.09.28
GameLoop (번역)  (0) 2010.09.16
IME 관련  (0) 2010.09.10
Posted by blueasa
, |

IME 관련

Programming/C/C++ / 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 관련|작성자 찐남자

반응형

'Programming > C/C++' 카테고리의 다른 글

[C++] 형변환 (Typecasting) - const_cast, reinterpret_cast, static_cast, dynamic_cast  (0) 2010.09.28
GameLoop (번역)  (0) 2010.09.16
TLS (Thread Local Strorage)  (0) 2010.08.30
TCHAR을쓰면 바뀌는 함수들  (0) 2010.07.27
TCHAR printf  (0) 2010.07.12
Posted by blueasa
, |

C# - C++/CLI - C++ 연결 후,
IME 때문에 일주일여간 삽질한 걸 잊지 않기 위해 Log 남김.(혼잣말)

1) C# 툴에 C++ 클라이언트를 렌더링하게 클라이언트를 수정(exe를 Lib로 만들어버림)
2) 뜨긴 떴는데..한글이 안먹힘..
3) 디버깅 해보니 한글 변환 메시지가 안들어옴
   (WM_IME_NOTIFY는 들어오는데, IMN_SETCONVERSIONMODE 메시지가 안들어옴)
4) 좀 더 확인해보니 툴의 핸들로 IMC를 Get 하려고 했지만 NULL값이 돌아옴..-_-
5) 클라만 따로 돌리면 IMC 획득 잘하고 , 한/영 변환 잘됨.
6) 일주일여간의 온갖 경우의 수를 생각하며, 인터넷 뒤지며(IME 관련 자료 찾기힘듬..) 삽질..
7) 결국, 마지막으로 한 짓은..
    C#의 IME를 죽이고, IME를 직접 생성해서 사용했음. -_-;
    이것도 임시방편 같기도 하고..맞는건지..
    우선 되니깐..진행..


[사용한 IME 관련 API 함수]
        [DllImport("imm32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr ImmGetContext(IntPtr hWnd);

        [DllImport("imm32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr ImmReleaseContext(IntPtr hWnd, IntPtr hImc);

        [DllImport("imm32.dll", CharSet = CharSet.Auto)]
        public static extern bool ImmGetConversionStatus(IntPtr hImc, out int fdwConversion, out int fdwSentence);

        [DllImport("imm32.dll")]
        public static extern bool ImmSetConversionStatus(IntPtr hIMC, int fdwConversion, int fdwSentence);

[아래는 IME 생성관련 API 함수]
        [DllImport("imm32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr ImmCreateContext();

        [DllImport("imm32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hImc);

        [DllImport("imm32.dll", CharSet = CharSet.Auto)]
        public static extern bool ImmDestroyContext(IntPtr hImc);

반응형
Posted by blueasa
, |

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace QEControls
{
/// <summary>
/// Summary description for FlickerFreeRichEditTextBox.
/// </summary>
public class FlickerFreeRichEditTextBox : RichTextBox
{

// #define WM_PAINT 0x000F

const short WM_PAINT = 0x00f;
const short WM_IME_NOTIFY = 0x0282;
const int IME_CMODE_NATIVE = 0x1;
//const short IMN_SETCONVERSIONMODE = 0x06;
private IntPtr IMN_SETCONVERSIONMODE = new IntPtr(0x06);

public FlickerFreeRichEditTextBox()
{
//
// TODO: Add constructor logic here
//
//SetStyle(ControlStyles.AllPaintingInWmPaint, true);
//SetStyle(ControlStyles.DoubleBuffer , true);
//SetStyle(ControlStyles.UserPaint , true);
_Paint = true;
this.ScrollBars = RichTextBoxScrollBars.Both;
}

[DllImport ("imm32.dll", CharSet=CharSet.Auto)]
public static extern int ImmGetContext (int hWnd);

[DllImport ("imm32.dll", CharSet=CharSet.Auto)]
public static extern int ImmReleaseContext (int hWnd, int hImc);

[DllImport ("imm32.dll", CharSet=CharSet.Auto)]
public static extern int ImmGetConversionStatus (int hImc, out int
fdwConversion, out int fdwSentence);

private bool _isHangulMode = false;
public bool IsHangulMode
{
get { return _isHangulMode; }
}

public bool _Paint = true;
public bool IsPainting
{
get
{
return _Paint;
}
}
protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg == WM_PAINT)
{
if (_Paint)
base.WndProc(ref m);
else
m.Result = IntPtr.Zero;
}
else if ( m.Msg == WM_IME_NOTIFY )
{
if ( m.WParam == IMN_SETCONVERSIONMODE )
{
int hImc, dwConversion = 0, dwSentense = 0;
hImc = ImmGetContext(this.Handle.ToInt32());
ImmGetConversionStatus(hImc, out dwConversion, out dwSentense);
if ( (dwConversion & IME_CMODE_NATIVE) == 1 )
{ // 한글모드
//System.Diagnostics.Trace.WriteLine("한글모드");
_isHangulMode = true;
}
else
{
//System.Diagnostics.Trace.WriteLine("English Mode");
_isHangulMode = false;
}
ImmReleaseContext(this.Handle.ToInt32(), hImc);
}
}
else
{
base.WndProc (ref m);
}
}

public void BeginUpdate()
{
_Paint = false;
}

public void EndUpdate()
{
_Paint = true;
}
}
}

출처 : http://www.ms-news.net/f2235/iso-8859-1-b-cmljahrlehrcb3i-oscw-mfrimh6ua7a1ltptnku-5396626.html
반응형
Posted by blueasa
, |

Hello :)

I'm working on a bit of a 2D engine and want it to work with the IME.  Now, normally with a desktop app you don't need any particularly special IME support for an IME to work with your app, you can just start typing in a text box and voila, asian characters (for the most part).  What's actually happening when you're typing asian characters is the IME is drawing windows above your application's window that contains these characters, as I understand it.  In a fullscreen game without typical input widgets, the IME has no idea where to display these windows, and even if it knew where to display those widgets, they wouldn't show up in your fullscreen app.  This means you need to read and send information to the IME directly and take any information you get from it and duplicate what it would've done by itself had you been making a regular desktop app (meaning, draw your own character candidate display, composition display, etc)

My
 2D engine thus far is in .NET 2.0 C# Managed DX.  In the August 2006 SDK, the VC++ DX utility classes contain an example textbox class that contains IME support.  The Managed DX utility classes do not contain any IME support example.  Most of the information I've found by researching around is only for desktop apps that want to extend their support for IMEs beyond the default, rather than support for fullscreen apps.


First I'll lay out what information I've found to be useful in this endeavor:

MSDN: Using an Input Method Editor in a Game (this helps to explain the VC++ DX textbox IME example)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/Using_an_Input_Method_Editor_in_a_Game.asp

MSDN: Input Method Editor Function Reference
http://msdn.microsoft.com/library/en-us/intl/ime_038z.asp

Header file containing actual enumeration values I didn't find anywhere else
http://www.rpi.edu/dept/cis/software/yesterday/g77-mingw32/include/imm.h

August 2006 SDK C++ DXUT class containing textbox with IME support
C:\Program Files\Microsoft DirectX SDK (August 2006)\Samples\C++\DXUT\Optional\DXUTgui.cpp

Some IME Reference Stuff
http://www.osronline.com/ddkx/appendix/imeimes2_35ph.htm
http://www.osronline.com/ddkx/appendix/imeimes_0h2s.htm

Misc IME Related C# Code
http://www.koders.com/csharp/fidEB8980C0605213D81D1D8364B00F09538F1DF83D.aspx
http://tsuge.astgate.biz/witchgarden/?C%23+Tips%2FWitchPaper%A4%C7%BC%C2%C1%F5%A4%B7%A4%BFIME%C0%A9%B8%E6
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=7712&forum=7

.NET Win32 API Reference Stuff (since you need to use external functions in imm32.dll and user32.dll)
http://www.dotnetwire.com/frame_redirect.asp?newsid=5368
http://www.pinvoke.net/
http://custom.programming-in.net/


So, that's where I'm coming from.  Here's where I'm at.  If you are familiar with the IME language bar, the floating toolbar allows you to select which input language you'd like to use at the moment, along with the input mode.  This input language and other details that you select are context sensitive and will only be used for the window/thread you set them in.  So if you open up Notepad.exe and switch to Japanese input, you'll have Japanese input available in Notepad, but if you switch to another Notepad.exe that you happened to have open, you'll still be in English language mode (until you set it to Japanese also).

Now, if you click somewhere on an app that isn't a textbox, so you have no text entry area selected while you're in Japanese input mode, you'll notice all of the icons on the IME language bar go disabled, naturally, because you can't input anything, so it won't bother trying to handle any input or send any characters.  The second you select a text entry area, bam, those icons become available again.

When I run my 2D engine in windowed mode and watch the IME language bar, I can use the ALT+SHIFT hotkey to switch language modes and receive that window message via WndProc, allowing me to spew text in my engine that says what the current input language is set to, but all of the language bar icons are disabled.  This is common sense and is expected.

The problem is, so far I have had no luck in getting the IME to recognize the input context and accept my commands to it to switch the ConversionStatus or even to begin it's composition string for me to detect. I'm not sure if I have to tell it to start a composition string and then it notifies the window back that it's starting, or if I just wait, but it won't bother starting any composition string until it's even in the right conversion mode (I imagine).

So now, I will refer to an area of the MSDN: Using an Input Method Editor in a Game (link above) article that has been stuck in my head.

"A full-screen application must properly handle the following IME-related messages:

"
I am handling WM_INPUTLANGCHANGE(via the .NET built in OnInputLanguageChange) and WM_IME_SETCONTEXT.  The other messages I won't receive until the IME is ready to do something, and so far I haven't gotten the IME to be ready to actually do anything :). I am sure there's more I need to do than just get these basic messages and respond to them, because it doesn't seem to be doing much.  If anyone knows anyone who might be able to point me in the right direction, it would be magically delicious.


For now, here is some of the code.  I have created a namespace called External that has a class called IME in it.  So IME.Something is referring to stuff in this class.  I have all of the dll imports and struct values contained in it.

// Incoming Window Message Events
protected override void WndProc(ref Message m) {
   switch ((IME.Message)m.Msg) {
      case IME.Message.WM_IME_SETCONTEXT:
         IME.imcHandle = IME.ImmGetContext(this.Handle);
         USER32.SendMessage(IME.imcHandle, m.Msg, m.WParam, IntPtr.Zero);
         IME.ImmReleaseContext(this.Handle, IME.imcHandle);
         break;
   }

   base.WndProc(ref m);
}

// OnInputLanguageChanged Event
protected override void OnInputLanguageChanged(InputLanguageChangedEventArgs e) {

   // Get IMC Handle
   IME.imcHandle = IME.ImmGetContext(this.Handle);

   // Get language and layout details
  
keys.languageFullName = e.InputLanguage.Culture.EnglishName;
   keys.languageShortName = e.InputLanguage.Culture.TwoLetterISOLanguageName;
   keys.layoutID = e.InputLanguage.Culture.KeyboardLayoutId;

   // Get current Conversion and Sentence Modes into IME.current*
  
IME.ImmGetConversionStatus(IME.imcHandle,ref IME.currentConversionMode,ref IME.currentSentenceMode);

   if (IME.currentConversionMode == 0 && keys.languageShortName == "ja") {
      IME.currentConversionMode = (int) IME.ConversionMode.IME_CMODE_NATIVE;
      IME.currentSentenceMode = (int) IME.SentenceMode.IME_SMODE_AUTOMATIC;

      IME.ImmSetConversionStatus(IME.imcHandle,(int)IME.ConversionMode.IME_CMODE_NATIVE | (int) IME.ConversionMode.IME_CMODE_FULLSHAPE, (int)IME.SentenceMode.IME_SMODE_AUTOMATIC);

   }

   if (IME.currentConversionMode != 0 && keys.languageShortName == "en") {
      IME.currentConversionMode = 0;
      IME.currentSentenceMode = (int) IME.SentenceMode.IME_SMODE_NONE;

      IME.ImmSetConversionStatus(IME.imcHandle, (int) IME.ConversionMode.IME_CMODE_ALPHANUMERIC, (int) IME.SentenceMode.IME_SMODE_NONE);

   }

   // Release IMC Handle
   IME.ImmReleaseContext(this.Handle, IME.imcHandle);

   base.OnInputLanguageChanged(e);

}


Of course that is only a very small portion of code that will be necessary for this whole thing to work when it's complete.  I'll also restate, I do not expect this code to do what I'm after, I'm looking for info on what to do next in order to achieve the desired result.  I've tried a couple things, but if anyone has done this before or has further insight, it would sure speed things up.  I imagine it's something very simple.

-Crache


출처 : http://social.msdn.microsoft.com/forums/en-US/gametechnologiesdirectx101/thread/32e53d65-4f99-4e47-9207-7254a96af33e/

반응형
Posted by blueasa
, |

기본적인 키보드 메시지

윈도우즈에서 한글을 고려하지 않고 키보드 입력을 다루는 방법은 정말 쉽다.

Windows는 키보드 입력이 들어올 때 마다 현재 입력 포커스를 가지고 있는 윈도우에게로 아래 메시지를 보내준다.

메시지

내용

WPARAM

LPARAM

WM_CHAR

문자가 조합된 경우

조합된 글자
(TCHAR형으로 넘어옴)

0~15: 반복 횟수
16~23: 스캔 코드
24: 확장 키가 눌렸는가?
29: alt키가 눌려졌는가
30: 이전에 눌려진 상태로 있었는가?
31: 아직 눌려진 상태로 있는가?

WM_KEYDOWN

키보드에서 키가 눌려짐

눌러진 virtual key

동일

WM_KEYUP

키보드에서 키가 눌려졌다 떼어짐

떼어진 virtual key

동일

WM_SYSKEYDOWN

Alt키가 눌려진 상태에서 키가 눌려짐

눌러진 virtual key

동일, 29번 비트는 항상 1

WM_SYSKEYUP

Alt키가 눌려진 상태에서 키가 떼어짐

떼어진 virtual key

동일, 29번 비트는 항상 1

위의 표에서 대부분은 자명한 것이다. 이 중 몇 가지 사항만 짚고 넘어가면 된다.

가장 먼저 이야기 해야 할 것이 WM_CHAR 메세지 이다. 이 메시지는 메인 루프의 TranslateMessage(&msg)에 의해 생겨나는 것이다. 이 함수는 MSG msg 구조체 내의 message, wParam, lParam 멤버와 time멤버를 분석하여 WM_KEYDOWN과 WM_KEYUP으로부터 적당한 갯수의 WM_CHAR를 만들어 낸다. 이 때, 제어판에서 설정한 키 입력 반복 속도 정보가 사용된다.

다음으로 기억해야 할 것은 TCHAR형이다. TCHAR를 알기 전에 WCHAR를 알아야 한다. Win32 API는 유니코드를 지원한다. 2바이트 유니코드 문자 한개를 저장하는 자료형이 WCHAR이다. 다음은 각각 유니코드를 사용하지 않는 소스 코드와(이러한 방식의 한글 표현을 Double Bytes Character Set, DBCS라고 한다) 유니코드를 사용하는 소스 코드를 보여준다.

DBCS 방식

	char a[] = "안녕하세요";
	cout << strlen(a); /* 아마 10이 출력될 것이다 */

유니 코드 방식

	WCHAR w[] = L"안녕하세요";
	cout << wcslen(w); /* 아마 5가 출력될 것이다 */

만일 DBCS 방식으로 작성된 코드를 아시아권 국가에 배포하기 위해 유니코드 방식으로 바꾸려면 어떻게 하면 될까? 혹은 유니코드를 지원하는 소스 코드를 유니코드를 필요로 하지 않는 사용자들을 위해(대신 코드는 가벼워질 것이다) DBCS 방식으로 바꾸려면 어떻게 하면 될까? 아래와 같이 코딩하면 이를 간단히 할 수 있다.

	#define _UNICODE /* 만일 유니코드를 사용하고 싶으면 이 문장을 추가하고 아니면 이 문장을 빼시오 */
	TCHAR w[] = _T("안녕하세요");
	cout << _tcslen(w); 

만일 유니코드를 사용하고 싶지 않으면 #define _UNICODE를 지우면 된다. 이것은 의 구현이다. 내부적으로는 다음과 같이 구현되어 있다.

	#ifdef _UNICODE 
		typedef WCHAR TCHAR;
		#define _T(x) L##x
		#define _tcslen wcslen
	#else
		typedef char TCHAR;
		#define _T(x) x
		#define _tcslen strlen
	#endif

_T(x) 매크로를 정의할 때 ANSI C의 토큰 페이스트 ##가 사용되었다. 이 매크로는 "abc"를 L"abc"로 바꾸어야 하지만(떼어서 쓰면 안되고 반드시 붙여서 써야함), #define _T(x) Lx라고 할 수 도 없지 않은가? ##기호는 L과 x가 서로 다른 기호라는 것을 알려준다.

_T 매크로 대신 __TEXT, _TEXT, TEXT, __T를 사용하여도 동일한 결과를 얻을 수 있으며, 실제로는 _tcslen보다 Windows API 함수인 lstrlen, lstrcmp, lstrcpy 등이 훨씬 많이 사용된다.

정리하면 우리가 _UNICODE를 define 했는가 아닌가에 따라서 윈도우즈는 때때로 char형을, 때때로 WCHAR 형을 WM_CHAR 메세지의 wParam으로 넘겨줄 것이다.

마지막으로 virtual key에 대해 이야기해 보자. 각각의 키보드는 눌려지거나 떼어졌을 때 컴퓨터로 눌려지거나 떼어진 키 번호를 보낸다. 이 키 번호를 'scan code'라고 한다.^^;; 그러나 scan code는 키보드 종류에 따라 다르다. 따라서 윈도우즈는 응용 프로그램 제작자들의 편의를 위해 이 스캔 코드를 virtual key로 바꾸어준다.

이러한 서비스는 아주 편리하다. 분명히 모든 키보드에에서 현재 내 오른쪽 새끼손가락 근처에 있는 엔터키와 Numpad에 있는 엔터키의 스캔 코드는 다르다. 그러나 어느 경우나 WM_KEYDOWN 메시지에는 VK_RETURN으로 들어올 것이다.(그리고 WM_CHAR 메시지에는 '\r' 문자가 들어올 것이다)

키 코드

내용

실제 값

VK_CANCEL

Ctrl+Break를 눌렀을때

03

VK_BACK

Backspace 키

08

VK_TAB

Tab키

09

VK_RETURN

Enter 키

13

VK_SHIFT

Shift키

16

VK_CONTROL

Ctrl 키

17

VK_MENU

Alt 키

18

VK_CAPITAL

Caps Lock 키

20

VK_ESCAPE

Esc 키

27

VK_SPACE

Space 바

32

VK_PRIOR

Page Up 키

33

VK_NEXT

Page Down 키

34

VK_END

End 키

35

VK_HOME

Home 키

36

VK_LEFT

좌측 화살표

37

VK_UP

위쪽 화살표

38

VK_RIGHT

우측 화살표

39

VK_DOWN

아랫쪽 화살표

40

VK_INSERT

Insert키

45

VK_DELETE

Delete키

46

VK_F1 ~ VKF10

F1~F10

112-121

VK_NUMLOCK

Num Lock

144

VK_SCROLL

Scroll Lock

145

Windows에 운영체제의 성능에 대해서 못마땅해 하는 사람들은, 이러한 다대일 대응이 문제를 일으키기를 기대할 수 도 있다. 예를 들어 Numpad의 4, 6, 8, 2는 게임등에서 왼쪽, 오른쪽, 위, 아래를 나타내는데 사용될 수 있지만, 이것이 키보드의 숫자가 눌려졌을 때도 작동한다는 것은 비극적인 일이다. 그러나 설마 그 정도로 어정쩡 하겠는가? 전자의 경우 lParam의 24번째 비트(확장 키가 눌렸는가?)는 1이 되고, 후자의 경우는 0이 된다.

캐럿

캐럿과 관련되어 용어상 분명히 해 두어야 할 것이 있다. 캐럿은 커서가 아니다. 여러분이 워드 프로세서나 메모장 등을 띄웠을 때 여러분의 입력을 기다리는 깜박이는 것이 캐럿이다. 그렇다면 커서는 무엇이란 말인가? 여러분이 책상 위에서 마우스를 움직일 때 모니터 상에서 따라 움직이는 화살표가 바로 커서이다. WNDCLASS를 만들 때 LoadCursor(NULL, IDC_ARROW);를 했던 사실을 잊었는가?

Win32에서 캐럿을 다루는 함수는 다음과 같다.

  • 캐럿을 생성: CreateCaret(HWND hwnd, HBITMAP hBitmap, int width, int height)
  • 캐럿을 보임: ShowCaret(HWND hwnd)
  • 캐럿의 이동: SetCaretPos(int x, int y)
  • 캐럿을 숨김: HideCaret(HWND hwnd)
  • 캐럿을 파괴: DestroyCaret()

응용 프로그램 범위에서 캐럿을 단 한 개만 생성할 수 있음에 주의하라. 오직 하나의 윈도우만이 캐럿을 가져야 한다. 가장 좋은 방법은 WM_SETFOCUS에서 캐럿을 생성하고, WM_KILLFOCUS에서 캐럿을 삭제 하는 것이다. 이 두 메시지는 반드시 쌍으로 불려지므로 메모리상을 둥둥 떠다니는 캐럿을 걱정할 필요는 없다.

또한 HideCaret을 10번 호출했으면, ShowCaret을 10번 호출해야 캐럿을 볼 수 있음을 주의하라. 캐럿은 암기력이 좋은 친구이다.

IME 메시지

한글 Windows를 비롯한 DBCS을 사용하는 국가의 윈도우즈에는 여러개의 키보드 입력이 한 개의 글자를 만드는 일을 관리해 주는 IMM(Input Method Manager)이 내장되어 있다. 키보드에서 문자가 입력되면 IMM이 여러분의 입력을 가로채서 한 글자가 완성되었을 때 비로소 WM_CHAR 메시지를 보내준다.

여러분의 프로그램이 IMM을 무시한채, 단지 WM_CAHR 만을 처리하더라도, 여러분의 프로그램은 대부분의 경우에 잘 작동할 것이다.(잠시후에 왜 잘 작동하는가를 알게 된다)그러나 한 글자가 완성되었을 때 비로소 화면에 나타나는 그런 프로그램이 아니라 한 개의 자모 단위로 입력되고 지워지는 과정을 전부 처리할 수 있는 프로그램을 작성하고 싶다면, IMM이 보내는 IME(Input Method Editor) 메시지들을 핸들링하라.

이 절에서는 IME 메시지들을 알아보고 다음 절에서 한글 타자 연습 프로그램을 만들 것이다. 만일 여러분이 프로그램에서 IMM을 다루고 싶다면, Project 메뉴의 Setting에서 imm32.lib를 링크에 추가하고 소스 코드에는 를 include 해야 한다.

다음은 기본적인 IME 메시지들이다.

메시지

내용

WM_IME_KEYDOWN

쉬프트+스페이스나 한글키와 같은 IME 관련 키가 눌려졌을 때 IMM에의해 보내지는 메시지이다. 이 메시지 DefWndProc에 넘기면 그에 해당하는 WM_KEYDOWN이 불린다.

WM_IME_KEYUP

쉬프트+스페이스나 한글키와 같은 IME 관련 키가 떼어졌을 때 IMM에의해 보내지는 메시지이다. 이 메시지를 DefWndProc에 넘기면 그에 해당하는 WM_KEYUP이 불린다.

WM_IME_CHAR

문자가 조합이 끝났을 때 IMM에의해 보내지는 메시지이다.

만일 _UNICODE가 #define되어 있다면 WM_IME_CHAR는 디폴트 동작으로 한번의 WM_CHAR를 발생시키고 wParam에 WCHAR형의 글자를 넘긴다. 만일 _UNICODE가 #define되어있지 않다면, WM_IME_CHAR는 디폴트 동작으로 두 번의 WM_CHAR를 발생시키고 wParam으로는 상위바이트, 하위바이트를 차례대로 넘긴다.

만일 입력이 들어오면 배열에 문자를 저장하는 코드가 있다면, 이 코드가 한글과같은 Double Bytes Character를 고려하지 않고 작성되었더라도, 한글이 입력되었을 때는 두 번의 WM_CHAR가 차례로 상위바이트, 하위 바이트를 넘기므로, 아무런 문제 없이 작동할 것이다. 많은 외국 회사에서 작성한 에디터나 텔넷 프로그램들이 한글 Windows에서 그렇게 작동하고 있는 것이다.

그러나 위에 소개한 세 개의 IME 메시지보다 더 중요한 메시지들이 있다.

메시지

의미

WM_IME_STARTCOMPOSITION

문자가 조합이 시작

WM_IME_COMPOSITION

문자가 조합 중

WM_IME_ENDCOMPOSITION

문자가 조합이 끝남

WM_IME_STARTCOMPOSITION과 WM_IME_ENDCOMPOSITION 메시지는 한글 조합이 시작할 때와 끝났을 때 알려주는 메시지이며, 필요하지 않으면 대게의 경우 DefWndProc로 넘겨진다. 그러나 WM_IME_COMPOSITION 메세지는 한글모드에서 한글이 조합되는 중 발생하므로 만일 완전한 조합이 되지 않은 글자의 출력을 원한다면 반드시 처리해야 한다.

WM_IME_COMPOSITION이 발생하면 lParam의 값을 검사해서 현재 글자가 확정되었는지 확정되지 않았는지 알수 있다. 이 때 wParam으로는 새로 추가된 글자가 넘어오지만 대부분의 경우 ImmGetCompositionString 함수를 호출하여 현재까지의 변경된 버퍼 상태를 얻어오는 것이 일반적이다. 다음은 키보드 입력에 따른 Composition 버퍼의 내용이다.

입력순서 lParam의 내용 Composition 버퍼의 내용
GCS_COMPSTR
GCS_COMPSTR
GCS_COMPSTR
GCS_RESULTSTR
GCS_COMPSTR
GCS_COMPSTR
GCS_RESULTSTR
GCS_COMPSTR
3 GCS_RESULTSTR 다3

다음은 사용자가 backspace를 눌러 조합중인 음소를 지우는 경우이다.

입력순서 lParam의 내용 Composition 버퍼의 내용
GCS_COMPSTR
GCS_COMPSTR
Back Space GCS_COMPSTR
Back Space GCS_COMPSTR NULL (길이 0)

위의 표를 잘 분석해 보면, 우리는 lParam에 GCS_COMPSTR이 들어올 때는 캐럿 위치를 증가시키지 않고 단지 Composition 버퍼의 내용을 현재 캐럿 위치에 출력하고, lParam에 GCS_RESULTSTR이 들어오면 이 때는 WM_CHAR 또한 불릴 것이므로 WM_CHAR에서 글자를 출력하고 캐럿 위치를 이동하여야 함을 알 수 있다.

마지막으로 IMM의 상태가 변경되었을 때 우리에게 알려주는 메시지를 알아보고 이 절을 마치도록 하자.

메시지

내용

wParam

WM_IME_NOTIFY

IMM의 상태가 바뀔 때

글자 입력창 관련

IMN_OPENCANDIDATE
IMN_CHANGECANDIDATE
IMN_SETCANDIDATEPOS
IMN_CLOSECANDIDATE

상태 창 관련

IMN_OPENSTATUSWINDOW
IMN_SETOPENSTATUS
IMN_SETSTATUSWINDOWPOS
IMN_CLOSE_STATUSWINDOW

문자 조합 관련

IMN_SETCOMPOSITIONFONT
IMN_SETCOMPOSITIONWINDOW

모드 관련

IMN_SETCONVERSIONMODE
IMN_SETSENTENCEMODE

예를 들어 한/영 상태가 변경될 때 마다 상태바에 한/영 상태를 표시해 주고 싶다면 WM_IME_NOTIFY에서 wParam이 IMN_SETCONVERSIONMODE가 들어올 때 현재 IME 상태를 얻어 상태바에 표시해 주면 된다. 다음은 현재 IME 상태를 얻어오는 코드이다.

	DWORD dwConversion, dwSentence; /* 현재의 IME 상태가 저장될 곳이다 */
	HIMC himc = ImmGetContext(hwnd); /* 현재 input context의 핸들을 얻어 온다 */
	ImmGetConversionStatus(himc, &dwConversion, &dwSentence); /* 현재 IME 상태를 얻어 온다. */
	ImmReleaseContext(hwnd, himc); /* input context의 핸들을 반납한다 */

출처 : http://cafe.naver.com/cyberzone.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=400
반응형

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

윈도우 투명  (0) 2011.10.30
한영키 누름 윈도우 메세지 확인 관련  (2) 2010.09.06
IME 영문만 입력가능하게 하기  (0) 2010.09.03
IME  (0) 2010.09.02
getClienteRect 와 getWindowRect  (0) 2010.08.31
Posted by blueasa
, |

출처 : GPG스터디 http://www.gpgstudy.com/forum/viewtopic.php?t=8137&highlight=ime+%C7%D1%B1%DB

 

윈도우 메시지 프로시저로 IME의 컨버전 모드가 변경 되었을 경우 아래와 같이 메시지가 옵니다.

코드:
  if (WM_IME_NOTIFY == Message)
  {
    switch (wParam)
    {
    case IMN_SETCONVERSIONMODE:
      {
        //한영키가 눌렸는가 검사
        HIMC hIMC = NULL;  

        if (hIMC = ImmGetContext(this->GetWindowHandle()))  
        {  
          DWORD fdwConversion, fdwSentence;  

          BOOL bRet = ImmGetConversionStatus(hIMC, &fdwConversion, &fdwSentence);  

          if(bRet) 
          {  
            bRet = (fdwConversion & IME_CMODE_NATIVE ? TRUE : FALSE);  

            if (bRet)
            {
              //한글 모드임!
            }
            else
            {
              //영문 모드임!
            }
          }

          ImmReleaseContext(this->GetWindowHandle(), hIMC);
        }  

      }
    
    }


이렇게 알아 낸 후 컨버전 모드를 변경하고 싶다면 아래와 같이 하면 됩니다

코드:
//영문으로 변경하고 싶다면..
DWORD dwMode = IME_CMODE_ALPHANUMERIC;

//한글로 변경하고 싶다면..
DWORD dwMode = IME_CMODE_NATIVE;

ImmSetConversionStatus(hImc, dwMode, NULL);


대략 무조건 영문으로 고정을 시키시고 싶으신듯 하니.. 아래와 같이 간편화가 될듯 합니다.

코드:
if (WM_IME_NOTIFY == Message)
  {
    switch (wParam)
    {
    case IMN_SETCONVERSIONMODE:
      {
        //한영키가 눌렸는가 검사
        HIMC hIMC = NULL;  

        if (hIMC = ImmGetContext(this->GetWindowHandle()))  
        {  
           ImmSetConversionStatus(hImc, IME_CMODE_ALPHANUMERIC, NULL);
        }

          ImmReleaseContext(this->GetWindowHandle(), hIMC);
        }  

      }
    
    }
반응형

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

한영키 누름 윈도우 메세지 확인 관련  (2) 2010.09.06
Keyboard 입력 받기  (0) 2010.09.03
IME  (0) 2010.09.02
getClienteRect 와 getWindowRect  (0) 2010.08.31
mfc, api 의 HINSTANCE 구하기 GetModuleHandle(NULL)  (0) 2010.06.03
Posted by blueasa
, |

IME

Programming/Win32API / 2010. 9. 2. 17:07

먼저 IME를 사용하려면 프로젝트에 Imm32.lib를 추가하고, imm.h를 인클루드 해야한다.



IME 메시지

WM_IME_STARTCOMPOSITION 
    IME가 조립 문자열을 만들기 직전에 보냄. WPARAM, LPARAM의 값은 없음. 이 메시지를 DefWindowProc으로
    보내지 않으면 조립윈도우가 나타나지 않는다.

WM_IME_ENDCOMPOSITION
    조립이 끝났다는 통지 메시지. 인수와 리턴값 없음. 커스텀 IME 윈도우를 작성하지 않는다면 무시해도 무방함.

WM_IME_COMPOSITION
    조립 상태가 변경될때마다 보내진다. 
    WPARAM - 조립중의 문자의 코드가 전달, 이 코드는 2byte의 DBCS문자로 조립중인 중간 문자코드이다.
    LPARAM - 조립상태가 어떻게 변경되었는지, 이 문자를 어떻게 처리해야 하는지를 나타내는 플래그의 집합.
                    한글의 경우 다음 두 플래그가 특히 중요함.
                        GCS_COMPSTR : 아직 문자를 조립중이라는 뜻, 즉 아직 한 음절이 완성되지는 않았음.
                        GCS_RESULTSTR : 한 음절을 완전히 조립했다는 뜻.
                    이 플래그들이 있는지 살펴보면 문자가 완성된 것인지, 조립중인지 알 수 있음.

WM_IME_CHAR
    문자 하나가 완성되었을때 보내짐.
    WPARAM - 완성된 문자의 코드가 전달. 1byte만 전달되는 WM_CHAR과는 달리 DBCS일 수 있음.
                     (단, 유니코드 윈도우에서는 WM_CHAR, WM_IME_CHAR 모두 2byte이다.)
    이 메시지를 무시하면 한글 한 문자에 대해 WM_CHAR 메시지를 두번 받게 된다.

WM_IME_SETCONTEXT
    응용프로그램이 활성/비활성화될 때 보내진다. WPARAM이 TRUE이면 활성, FALSE이면 비활성화 되었다는 뜻이다.

WM_IME_NOTIFY
    IME 윈도우가 변경되었다는 통지 메시지이다. WPARAM으로 어떤 변경인지 통보됨.한글 입력, 영문 입력모드를
    변경할 때도 이 메시지가 전달된다.



Input Context 생성, 해제

Input Context(입력 컨텍스트) : IME가 내부적으로 사용하는 구조체이며 조립 문자열, 변환모드, IME 윈도우의 위치 등 IME의 현재 상태에 대한 정보들이 저장됨.


Input Context의 핸들을 얻는 함수

HIMC ImmGetContext(void); 
BOOL ImmReleaseContext(HWND hWnd, HIMC hIMC); 

Input Context를 조작하는 함수

BOOL ImmGetConversionStatus(HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence); 
BOOL ImmSetConversionStatus(HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence); 

    입력모드를 한글로 변환하고 싶으면
ImmSetConversionStatus(hImc, IME_CMODE_NATIVE, IME_SMODE_NONE); 

    입력모드를 영어로 변환하고 싶으면
ImmSetConversionStatus(hImc, 0, IME_SMODE_NONE); 
를 호출하면 된다.

    하지만 시스템이 만드는 Default Input Context는 스레드 내의 모든 윈도우가 공유하기 때문에 한글이나 영문으로 변경시
    모든 입력모드가 통일되게 변경된다. 만약 각각의 컨트롤에서 다른 입력모드를 주고 싶다면 윈도우별로 InputContext를
    생성, 해제하여 연결시키면 된다.


Input Context를 생성, 해제하는 함수

// InputContext를 위한 메모리를 할당하고, 그 핸들을 리턴 HIMC ImmCreateContext(void); 
// 특정 윈도우와 연결 HIMC ImmAssociateContext(HWND hWnd, HIMC hIMC); 
// InputContext를 메모리에서 해제 BOOL ImmDestroyContext(HIMC hIMC); 

    InputContext를 생성, 해제할 경우에는 Pen, Brush를 생성, 해제할때와 같은 방법으로 한다.
 
 
 
 
 
 
 
 
 
---
 
 
IME 활성, 비활성 제어 ( 출처 : http://smilewjp.springnote.com/pages/3182684 )
 

IME 관련 작업을 하다보면 IME의 활성/비활성 상태를 강제로 조정해야할 필요가 생깁니다.

관련 자료를 찾기 위해 인터넷을 검색하다보니 비밀번호나 아이디로 영문만 입력받고자 할때 많이 사용하더군요.

 

저같은 경우에는 중국어 관련해서 사설 IME를 사용하는데 문제가 생겨서 사용했습니다.

사설IME에서 입력을 받으면 안되는 상황에서 입력을 받고있어서 문제가 발생했습니다.

그래서 IME를 비활성 시키는 구문을 찾아서 넣었습니다.

  1. HIMC ImmAssociateContext( HWND hWnd, HIMC hImc );

MSDN의 ImmAssociateContext()를 살펴보면 이 API는 윈도우 별로 입력 컨텍스트를 만들었을때 컨텍스트를

지정하는데 사용할 수 있지만 hImc의 값에 NULL을 줄 경우, 해당 윈도우 창의 IME 포커스를 죽이게 됩니다.

따라서 관련된 IME는 동작하지 않게 되고, 사설 IME역시 동작을 하지 않습니다.

 

하지만 중요하게 알고 있어야 하는것은 ImmAssociateContext()를 할 경우 리턴값으로 기존의 HIMC값이 반환되기 때문에

나중에 사용을 위해서는 저장해 두어야합니다.

  1. void SetActive( BOOL isActive )
    {
       if( isActive )
       {
          // 기존의 값으로 IME를 다시 설정합니다.
          ImmAsscociateContext( hWnd, _oldhImc );
       }
       else
       {
          _oldhImc = ImmAssociateContext( hWnd, NULL );
          // IME를 비활성 시킵니다.
          // _oldhImc는 값을 저장하고 있어야 합니다.
       }
    }

출처 : Tong - race0203님의 C++통

반응형

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

Keyboard 입력 받기  (0) 2010.09.03
IME 영문만 입력가능하게 하기  (0) 2010.09.03
getClienteRect 와 getWindowRect  (0) 2010.08.31
mfc, api 의 HINSTANCE 구하기 GetModuleHandle(NULL)  (0) 2010.06.03
Virtual Keys, Standard Set  (0) 2010.04.21
Posted by blueasa
, |