'input'에 해당되는 글 12건

  1. 2010.07.18 WinApi WM_KEYDOWN
  2. 2010.07.17 WinApi input WM_CHAR
posted by nsakura 2010. 7. 18. 12:28

WM_CHAR 메세지를 이용하면 입력을 받을 수 있다는것을 알게 되었는데

한가지 문제가 있었다. 문자 이외에는 입력을 받지 않는다는 것이다.

그래서 ins,del키 기능키 는 문자키가 아니기 때문에 이런  키는 아무리 눌러봤자 WM_CHAR메세지에 전달이 안된다.

이럴 때는 WM_KEYDOWN을 사용한다. 단(ALT,한영키, 등 몇가지는 제외가 된다)

wParam에 전달되는 것은 문자 코드가 아니라 가상의 키코드가 간다 이 키도는 다음과 같이 정의 되어있다.

 가상 키코드  값  키 
 VK_LBUTTON  01  
 VK_RBUTTON  02  
 VK_CANCEL  03  ctrl-break
 VK_MBUTTON  04  
 VK_BACK  08  backspace
 VK_TAB  09  tab
 VK_CLEAR  0C  numlook이 꺼져 있을때 5
 VK_RETRUN  0D  entwer
 VK_SHIFT  10  shift
 VK_CONTROL  11  ctrl
 VK_MENU  12  alt
 VK_PAUSE  13  pause
 VK_CAPITAL  14  caps lock
 VK_ESCAPE  1B  esc
 VK_SPACE  20  space
 VK_PRIOR  21  pgup
 VK_NEXT  22  pgdn
 VK_END  23  end
 VK_HOME  24  home

 VK_LEFT  25  좌 화살표
 VK_UP  26  상 화살표
 VK_RIGHT  27  우 화살표
 VK_DOWN  28  하 화살표
 VK_SELECT  29  
 VK_PRINT  2A  
 VK_EXECUTE  2B  
 VK_SNAPSHOT  2C  print screen
 VK_INSERT  2D  insert
 VK_DELETE  2E  delete
 VK_HLEP  2F
 30~39
 41~5A
 
 숫자키 0~9
 영문자 A~Z
 VK_LWIN  5B  왼쪽 윈도우 키
 VK_RWIN  5C  오른쪽 윈도우키
 VK_APP  5D  Application 키
 VK_NUMPAD0~9  60~69  숫자패드 0~9
 VK_MULTIPLY  6A  숫자패드의 *
 VK_ADD  6B  숫자패드의 +
 VK_SEPARATOR  6C  
 VK_SUBTRACT  6D  숫자패드의 -
 VK_DECLMAL  6E  숫자패드의 .

 VK_DIVIDE  6F  숫자패드의 /
 VK_F1~F24  70~87  F1~F24키
 VK_NUMLOOK  90  NUMLOOK키
 VK_SCROOL  91  SCROLL LOCK


설마 이 표를 다 외울 생각을 하는 사람이 있는가? .. 있다면 할 필요 없다.

단순히 이런게 있다고만 기억하면 된다.

가상키는 현재는 물론 향후 나올지도 모르는 키에 대해서도 미리 정해두었다.

 WM_KEYDOWN 메세지 처리 루틴에서 wParam의 값과 가상 키코드값을 비교해 봄으로서 어떤 키가 눌렀는지 알아낼 수 있다.

그럼 예제를 한번보도록 하자.

#include <windows.h>

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE nsakura;

LPCTSTR windName=TEXT("GFP KeyDown");

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd){
 HWND hWnd;
 MSG Message;
 WNDCLASS WndClass;
 nsakura=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=windName;
 WndClass.lpszMenuName=NULL;
 WndClass.style=CS_HREDRAW|CS_VREDRAW;
 RegisterClass(&WndClass);

 hWnd=CreateWindow(windName,windName,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 xpos=400;
 static ypos=400;

 switch(iMessage){

 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;

 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  TextOut(hdc,xpos,ypos,TEXT("GFP"),3);
  EndPaint(hWnd,&ps);
  return 0;

 case WM_KEYDOWN:
  switch(wParam){

  case VK_UP:
   ypos-=8;
   break;

  case VK_DOWN:
   ypos+=8;
   break;

  case VK_RIGHT:
   xpos+=8;
   break;

  case VK_LEFT:
   xpos-=8;
   break;

  }
 
  InvalidateRect(hWnd,NULL,true);
 }
 
 return (DefWindowProc(hWnd,iMessage,wParam,lParam));
}


키보드의 방향키를 누르면 gfp 글씨가 움직일 것이다.

InvalidateRect(hWnd,NULL,true); 이것을 false로 바꿔서 해보자


이런식으로 이동시키게 되면 잔상이 남게 될것이다. 뭐 이건 어제 설명했으니 자세한 설명은 패스하도록 하겠습니다.

  자 위의 코드를 보고  스페이스바가 누르면 GFP글씨가 껌뻑이게 만들어보자.

방법은 자유.

본인이 사용한 방법은


TranslateMessage
 
그것을 아는가 키보드로부터 입력을 받으면 WM_KEYDOWN ->WM_CHAR->WM_KEYUP 순으로 메세지가 발생한다.

WM_KEYDOWN이 발생되면 내부적으로 그게 문자이면 WM_CHAR를 발생시키고 문자가 아닌경우 아무 일도 안하고

GetMeesage는 메세지큐에서 메세지를 꺼내고 TranslateMessage함수는 오로지 키보드로부터 문자키 입력 메세지인 WM_CHAR를

만들어내기 위한 것이다.

이 외에도 키보드 메세지들은

WM_SYSKEYDOWN,WM_SYSKEYUP, WM_SYSCHAR이 있는데

SYS(system)가 붙은건.  ALT가키와 함께 눌러지는 키보드 메세지들이다.

단 리턴을 할때는 DefWindowProc으로 보내줘야한다. 그렇지 않으면 alt esc,alt tap등의 화면전환 키까지 불능이 되버리기 때문이다.


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

WinApi 타이머  (0) 2010.07.18
WinApi 마우스 입력.  (0) 2010.07.18
WinApi input WM_CHAR  (0) 2010.07.17
WinApi MessageBox  (0) 2010.07.17
WinApi 여러가지 출력  (0) 2010.07.16
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