posted by nsakura 2010. 7. 17. 22:08

WM_CHAR

자 친구들은 C언어하면 생각나는 입력함수가 뭐가 있는가? scanf,getch,gets 등의 함수들이 기억날것이다.

그런데 생각해보자 c언어에서 사용자 입력함수가 호출되는 시점에서 프로그램은 입력을 기다린다

즉 이 시간동안은 프로그램이 대기 한다.

그런데 윈도에서 어떤가. 입력을 기다린다고 프로그램 전체가 멈추는 경우가 있는가?

무슨 말인지 이해가 안간다면 당장 메모장을 켜놓고. 찾기 기능을 켜놓고 메모장에 글을 적어보자.

그럼 이해가 될것이다.

메모장을 예를들어서 이야기 하면 찾기기능에 입력은 안하지만 본문에 입력을 하고있다고 치자.

계속해서 프로그램은 돌아가는 중이고 탐색에서는 입력을 기다리는것이다.

탐색에서 입력이 되면 포커스를 가진 프로그램에서  메세지를 던져주면 되는 것이다. 그 것이 (WM_CHAR, WM_KEYDOWN)이다.

여기서 포커스는 입력 초점이라고 생각하면 된다.

그럼 한번 예제를 풀어보도록 하죵

#include <windows.h>
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE g_Inst;
LPCTSTR winName=TEXT("GFP INPUT");

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd){
 HWND hWnd;
 WNDCLASS WndClass;
 MSG Message;
 g_Inst=hInstance;

 WndClass.cbClsExtra=0;
 WndClass.cbWndExtra=0;
 WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
 WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
 WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
 WndClass.hInstance=hInstance;
 WndClass.lpfnWndProc=WndProc;
 WndClass.lpszClassName=winName;
 WndClass.lpszMenuName=NULL;
 WndClass.style=CS_HREDRAW|CS_VREDRAW;
 RegisterClass(&WndClass);

 hWnd=CreateWindow(winName,winName,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,(HMENU)NULL,hInstance,NULL);

 ShowWindow(hWnd,nShowCmd);

 while(GetMessage(&Message,NULL,0,0)){
  TranslateMessage(&Message);
  DispatchMessage(&Message);
 }
 return (int)Message.wParam;

}

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam){
 HDC hdc;
 PAINTSTRUCT ps;
 static TCHAR str[256];
 int len;
 
 switch(iMessage){
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 case WM_CHAR:
  len=lstrlen(str);
  str[len]=(TCHAR)wParam;
  str[len+1]=0;
  InvalidateRect(hWnd,NULL,FALSE);
  return 0;
 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  TextOut(hdc,100,100,str,lstrlen(str));
  EndPaint(hWnd,&ps);
  return 0;
 }
 return (DefWindowProc(hWnd,iMessage,wParam,lParam));
}

WM_CHAR 메세지에서 키보드에서 입력한 문자를 모은다.

str을 왜 정적으로 선을 했냐면 이유는 간단하다. 그냥선언되면 프록 함수가 다시 호출될때 변수가 초기화가 되기 때문이다.

그래서 정적으로 선언을 한것이다. 이해가 잘안되면 로컬변수와 전역변수에 대해 공부해보기 바란다.

static이 싫다면 그냥 전역변수로 선언해도 된다.

그런데. 이 프로그램을 보면 잠깐 생각해볼 문제가 있지 않나?

왜 문자을 입력해서 출력하는데 입력받은 문자를 저장을 하느냐?

이다..

이유는 문자를 입력을 받고 바로 출력을 하는게 아니라 입력과 출력을 할 시점이 분리되어있기 때문이다.

만일 입력과 출력을 분할하지 않으면 우리가 몇일전 글씨 출력에 일어나는 현 프로그램이 다른 프로그램 아래 깔렸을때(언커버)

글씨가 지워지는 현상 발생하기 때문이다. 그렇다면 다른 방법은 없는 것인가? 방법은 있다 그 방법은 차후에 설명하겠다.


WM_CHAR 메세지는 입력된 문자의 코드를 wParam으로 전달한다.

그래서    str[len]=(TCHAR)wParam; 이렇게 되는 것이다.

str[len+1]=0; 이부분은 문자열의 끝을 표현한것이다.

출력하는 부분은 DC를 얻어서 출력하는 방법인데.

WM_PAINT 부분이 담당한다. 그런데 이렇게만 쓴다고해서 자동으로 WM_PAPINT부분을 호출하지 않는다. 강제적으로 호출을 시켜야하는데.

InvalidateRect(hWnd,NULL,FALSE);

이 부분이 되겠다.

잠시 좀더 자세히 살펴보자

InvalidateRect는 강제적으로 WM_PAINT를 발생시키기위해 사용했다고했다. 그런데 전 예제를 잘 본사람이라면 WM_PAINT의 역활에 대해

언급 했었다. 바로 윈도 창을 다시그릴때 사용한다고 잠깐 언급을 했었다. 예를들어.


이런 상태라고 치자. 그렇다면 저기 겹쳐진 부분이 있는데 실제로는 카드 게임에는 무효화 영역이 있는 것이다.

이 상태에서 다시 그림판을 옮겨서 카드 게임을 100%다 보이게 했다. 그럼 카드게임 내부에서 WM_PAINT가 메세지를 받는데.

그럼 누가 보내준것일까? 바로 OS가 메세지를 던져주는것이다. "야 카드게임 너 윈도 다시 그려야해"

라고. 이건 외부적인 요인에 발생하는 변화는 이렇게 OS가 관여해주지만.

프로그램 내부의 변화는 OS가 관여하지 않는다. 왜냐하면 내부적인 프로그램의 주체는 프로그래머의 의해 결정이 되기 때문에

즉 OS가 판단을 할수가 없다는것이다. 그래서 관여를 안한다. 그래서 강제로 갱신을 해주기 위해서는 InvalidateRect

사용한다. 이 함수의 원형을 보자.

BOOL InvalidateRect(HWND hWnd, CONST RECT *lpRect, BOOL bErase);

첫 번째 인수는 무효화되는 대상을 말한다.

두 번째 인수 무효화할 영역을  지정하다 이 값을 NULL로 지정 하면 윈도우 전역이 무효화 된다.

무조건 NULL을 하게 되면 화면을 다시 그리는 시간이 다소 거릴수있다.[느끼지는 못하겠지만..]

세 번째 인수는 무효화 되기 전의 배경을 모두 지운후 다시 그릴 것인 아닌가 배겨을 지우지 않고 그릴 것인가를 지정한다.

잘 이해가 안된다고?

그렇다면 이렇게 테스트를 해보자

 case WM_CHAR:
  if((TCHAR)wParam==' '){
   str[0]=0; 
   }

  else{
   len=lstrlen(str);
   str[len]=(TCHAR)wParam;
   str[len+1]=0;
  }
  InvalidateRect(hWnd,NULL,TRUE);
  return 0;

이렇게 고쳐서.

InvalidateRect(hWnd,NULL,TRUE);

3번째 인자를 false로도 바꿔보고 true로도 한번 테스트를 해보자.

그럼 이해가 될 것이다.

위의 코드는 스페이스바를 누르면 모든 문자열을 지운다.

false로 하면.하면 덮어 씌어져서 써질것이다.

'Computer > Win API' 카테고리의 다른 글

WinApi 마우스 입력.  (0) 2010.07.18
WinApi WM_KEYDOWN  (0) 2010.07.18
WinApi MessageBox  (0) 2010.07.17
WinApi 여러가지 출력  (0) 2010.07.16
WinApi DrawText  (0) 2010.07.15