Notice
Recent Posts
관리 메뉴

Hacking Arts

키보드 입력 본문

Programing/API Programing

키보드 입력

Rakehell 2014. 10. 10. 23:53

- 키보드 입력 이벤트는 간단하게 WM_KEYDOWN,WM_KEYUP, WM_CHAR 이렇게다.


- WM_KEYDOWN : 키보드의 어느 키가 눌러지든 발생한다.

- WM_KEYUP : 키보드의 어느 키가 눌렸다가 떼는 과정에서 발생한다.

이 두개는 한쌍으로 발생한다.


- 가상 키코드 wParam으로 가상 키코드가 들어오게 되는데

카상키코드표 여기에 들어가면 볼 수 있다. 표에는 숫자와 영문자가 정의되어 있지 않은데 문자 키의 식별은 아스키 코드를 비교하여 식별 하면 되고, 그 외의 키는 정의된 가상 키 코드를 가지고 식별하면 된다.

[ 그림 1 key 이벤트 발생 ]


-아래 와 같은 소스를 통해 위 그림 1의 이벤트 발생 시킬 수 있다

	case WM_KEYDOWN:
		switch (wParam)
		{
		case VK_HOME:
			MessageBox(hWnd, L"HOME 키를 누름", L"HOME", MB_OK);
			return 0;
		case VK_END:
			MessageBox(hWnd, L"END 키를 누름", L"END", MB_OK);
			return 0;
		}
		return 0;


- 그렇다면 WM_CHAR는 어떻게 발생하는가? WM_CHAR의 경우 wParam으로 아스키코드표에 맞는 문자가 오게 된다.

아래소스 코드를 실행하게되면 그림 처럼 z 키와 home키를 구분해서 받는 것을 확인 할 수 있다.

[ 그림 2 key 이벤트 발생 ]

	static TCHAR strChar[MAX_PATH];
	int nlen = 0;
	HDC hdc;
	PAINTSTRUCT ps;

	switch (iMessage)
	{
	case WM_KEYDOWN:
		switch (wParam)
		{
		case VK_HOME:
			MessageBox(hWnd, L"HOME 키를 누름", L"HOME", MB_OK);
			return 0;
		case VK_END:
			MessageBox(hWnd, L"END 키를 누름", L"END", MB_OK);
			return 0;
		}
		return 0;
	case WM_CHAR:
		nlen = strlen((char *)strChar);
		strChar[nlen] = (char)wParam;
		strChar[nlen + 1] = 0;
		InvalidateRect(hWnd, NULL, FALSE);
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		TextOut(hdc, 100, 100, strChar, strlen((char*)strChar));
		EndPaint(hWnd, &ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}


- 키보드 입력시 부가 정보

- wParam을 통해서 키 값은 모두 전달된다. 영문자 및 숫자와 같은 문자 키일 경우에는 아스키코드 값이 문자 키가 아닌 경우에는 가상 키코드 값이 들어온다

- lParam의 경우는  이렇게 쓰이는데 중요하지는 않다. 보는 정도로 넘어가자

 비트 번호

설명 

 0 - 15

 키의 반복되는 카운트

 16 - 23

 스캔 코드

 24

 확장키가 눌러졌을 때 1이 된다.

 25 - 28

 사용 안함

 29

 Alt 키가 눌려졌을 때 1

 30

 메시지를 보내기 전에 키가 눌려져 있으면 1

 31

 키가 눌려지면 1, 키가 떼어지면 0


- TranslateMessage 함수

이전에 WM_KEYDOWN은 무조건 발생하기 때문에 Translate함수가 중요하다. 문자와 문자가 아닌 키의 구별을 위한 함수이다. 아래 그림과 같은 처리과정을 거치게 된다. 왼쪽이 문자 오른쪽이 문자가 아닌 키이다.

[ 그림 3 키보드 이벤트 처리 과정 ]


- 캐럿 : 커서라고도 부르는 깜빡이면서 대기하는 것이다. 

[ 그림 4 캐럿 처리 단계]


- 포커스 : 여러 윈도우중 현재 사용하고 있는 윈도우에 포커를 맞추게 된다. 내가 지금 이 글을 쓰는 동안에는 브라우져가 포커스를 가지게 된다. 


-WM_SETFOCUS : 이 메시지는 윈도우가 키보드 포커스를 받은 후에 전달 된다. 즉 키보드 포커스의 이동 완료 후에 바로 이메시지가 발생한다. 결국 이 메시지가 발생 시 캐럿을 생성하고 보여주고, 위치를 설정해 준다.


- WM_KILLFOCUS : 캐럿은 시스템 전역적으로 사용하는 유일한 자원이므로 윈도우가 포커스를 잃으면사용 중인 캐럿을 파괴해야된다. 이 메시지를 이용해 파괴 하면 된다.



[ 그림 5 캐럿]


- 아래 그림처럼 캐럿 생성과 포커스의 설명을 볼 수 있다.

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
	static TCHAR strChar[MAX_PATH];
	int nlen = 0;
	static int pos = 0;
	SIZE size;
	HDC hdc;
	PAINTSTRUCT ps;

	switch (iMessage)
	{
	case WM_CREATE:
		strcpy((char *)strChar, "");
		return 0;
	case WM_CHAR:
		nlen = strlen((char *)strChar);
		strChar[nlen] = (char)wParam;
		strChar[nlen + 1] = 0;
		pos++;
		hdc = GetDC(hWnd);
		GetTextExtentPoint(hdc, strChar, pos, &size);
		ReleaseDC(hWnd, hdc);
		SetCaretPos(size.cx + 100, 100);
		InvalidateRect(hWnd, NULL, FALSE);
		return 0;
	case WM_SETFOCUS:
		hdc = GetDC(hWnd);
		CreateCaret(hWnd, NULL, 2, 14);
		ShowCaret(hWnd);
		SetCaretPos(100, 100);
		return 0;
	case WM_KILLFOCUS:
		HideCaret(hWnd);
		DestroyCaret();
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		TextOut(hdc, 100, 100, strChar, strlen((char*)strChar));
		EndPaint(hWnd, &ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}

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

resource (icon/cursor)  (0) 2014.11.04
타이머  (0) 2014.10.11
마우스 입력  (0) 2014.10.10
문자열 / 점 / 선 / 사각형 / 원 / 다각형 / 메시지 박스  (0) 2014.10.10
출력 / GDI / DC  (0) 2014.10.10