관리 메뉴

ㄴrㅎnㅂrㄹrㄱi

[강좌 5] 입력부분 본문

API 관련/API 강좌모음

[강좌 5] 입력부분

님투 2007. 10. 26. 03:38
반응형

[API]강좌(5)<-- 입력부분






이번에는 입력부분에 대해 알아보도록 합시다. 앞 부분에서 이미 약간 언급을
했지만 용어 하나를 잘 기억하고 있어야 합니다. 바로 커서와 캐럿이라는 용어인
데 커서는 마우스의 화살표 모양을 의미하는 것이고 입력을 받기 위해서 깜박이는
것을 캐럿이라고 합니다. 도스에서는 바로 이 캐럿을 커서라고 정의했을 겁니다.
자 먼저 디바이스 컨텍스트 핸들을 얻는 방법부터 알아봅시다. 어! 위에서 이미
했는데 또 하나라고 생각할지도 모르지만 좀 다릅니다. WM_PAINT 메시지하에서
출력을 하려면 BeginPaint() 함수를 이용해서 핸들을 얻으면 되지만 다른 메시지
하에서 출력을 하기 위해 핸들을 얻으려면 GetDC()라는 함수를 이용해서 얻어야
합니다.
HDC GetDC(
HWND hwnd
);
핸들을 반환할때에는 ReleaseDC() 함수를 사용하면 됩니다.
int ReleaseDC(
HWND hwnd,
HDC hdc
);
우리는 출력하는 함수에 대해 이미 위에서 배웠을 겁니다. 추가로 폰트를 선택해서
출력하는 부분도 보도록 합시다. GetStockObject()라는 함수를 기억합니까? 한참
위에서 배웠죠? 이 함수를 이용해서 시스템 고정 폰트를 얻고 그 핸들을 디바이스
컨텍스트 핸들에 선택되게 해 주면 그 디바이스 컨텍스트 핸들을 이용해서 출력할
때 그 고정폰트로 출력됩니다.
HGDIOBJ SelectObject(
HDC hdc,
HGDIOBJ hgdiobj
);
어떤 객체의 핸들을 디바이스 컨텍스트 핸들에 선택되게 해주는 함수입니다. 우리
는 이번 예제에서 폰트 객체를 사용할 겁니다.
BOOL GetTextMetrics(
HDC hdc, // handle of device context
LPTEXTMETRIC lptm // address of text metrics structure
);
위 함수는 우리가 받은 디바이스 컨텍스트 핸들을 이용해서 문자(폰트)에 대한 정
보를 얻을때 사용합니다. 입력을 받는 예제에 대해서 알아 보는데 이 함수가 왜
필요할까요?
이렇게 생각하면 간단합니다. 좌표 (0, 0)에 캐럿이 깜박이고 있는데 여기서
우리가 A라는 문자를 입력했다고 합시다. 그러면 A라는 문자가 그 좌표에 찍혀야
겠죠? 그리고 캐럿은 다음 좌표로 이동해야 하구요. 우리가 윈도우에서 사용하는
좌표는 도스에서의 그래픽 좌표와 같습니다. A라는 문자가 찍히고 난후의 그 다음
좌표가 (1, 0)이아니라 A라는 문자의
가로 넓이 만큼 X좌표를 이동해 주어야 하는 것입니다. 그렇다면 A라는 글자의
가로 넓이를 알아야 하는데 이때 위 함수를 이용해서 넓이를 알아낼수 있습니다.
Y좌표도 그런식으로 계산해 주어야 합니다. 다음은 두번째 파라미터의 원형입니다.
typedef struct _TEXTMETRIC { // tm
LONG tmHeight;
LONG tmAscent;
LONG tmDescent;
LONG tmInternalLeading;
LONG tmExternalLeading;
LONG tmAveCharWidth;
LONG tmMaxCharWidth;
LONG tmWeight;
LONG tmOverhang;
LONG tmDigitizedAspectX;
LONG tmDigitizedAspectY;
BCHAR tmFirstChar;
BCHAR tmLastChar;
BCHAR tmDefaultChar;
BCHAR tmBreakChar;
BYTE tmItalic;
BYTE tmUnderlined;
BYTE tmStruckOut;
BYTE tmPitchAndFamily;
BYTE tmCharSet;
} TEXTMETRIC;
tmHeight가 선택된 문자의 높이를 저장할 멤버이고 tmAveCharWidth가 넓이를 저장
할 멤버를
의미합니다.
캐럿이 원하는 죄표에 깜박이려면 먼저 캐럿을 생성해 주어야 하는데 캐럿을 생성
할때는 아래 함수를 이용해서 하면 됩니다.
BOOL CreateCaret(
HWND hwnd,
HBITMAP hbmp,
int nWidth,
int nHeight
);
두번째 파라미터에 보면 비트맵 핸들을 지정하게 되어 있는데 이 값을 NULL로 해주
면 그냥 일반적인 캐럿 모양을 생성하고 그림 핸들을 지정해 주면 그 그림의 모양
으로 캐럿의 모양이 결정됩니다. 세번째, 네번째 파라미터는 캐럿의 크기를 의미하
는 것입니다.
캐럿을 원하는 좌표에 놓을때에는 아래 함수를 사용하면 됩니다.
BOOL SetCaretPos(
int nX,
int nY
);
파라미터 차례로 x, y좌표를 의미합니다.
실제적으로 생성하고 어느곳에 위치한 캐럿을 눈에 보이려면 아래 함수를 사용합
니다.
BOOL ShowCaret(
HWND hwnd
);
캐럿을 보이지 않게 하려면 아래 함수를 이용하면 되구요.
BOOL HideCaret(
HWND hwnd
);
자 대략적으로 이번 예제에서 사용할 함수에 대해 알아 보았는데 그러면 실제로
소스를 보도록 합시다. 아래 예제는 간단한 에디터를 구현한것인데 화면 스크롤
같은 것은 처리하지 않은 것입니다. 단지 유저가 입력하는 문자를 화면에 보여주
기만 합니다.
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASS WndClass;
char szAppName[] = "This program is to input string";
WndClass.style = NULL;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = szAppName;
if(!RegisterClass(&WndClass)) return NULL;
hWnd = CreateWindow(
szAppName,
szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg, WPARAM wParam, LPARAM lParam)
{
HDC hDC;
TEXTMETRIC tm;
char cChar;
static int cxChar, cyChar, nX, nY;
switch(mesg)
{
case WM_CREATE :
nX = nY = 0;
hDC = GetDC(hWnd);
SelectObject(hDC, GetStockObject(SYSTEM_FIXED_FONT));
GetTextMetrics(hDC, &tm);
ReleaseDC(hWnd, hDC);
cxChar = tm.tmAveCharWidth;
cyChar = tm.tmHeight;
return FALSE;
case WM_SETFOCUS :
CreateCaret(hWnd, NULL, cxChar, cyChar);
SetCaretPos(cxChar*nX, cyChar*nY);
ShowCaret(hWnd);
return FALSE;
case WM_KILLFOCUS :
HideCaret(hWnd);
DestroyCaret();
return FALSE;
case WM_CHAR :
HideCaret(hWnd);
hDC = GetDC(hWnd);
if(LOWORD(wParam) != '\r')
{
cChar = (char)wParam;
TextOut(hDC, cxChar*nX, cyChar*nY, &cChar, 1);
nX++;
}
ReleaseDC(hWnd, hDC);
SetCaretPos(cxChar*nX, cyChar*nY);
ShowCaret(hWnd);
return FALSE;
case WM_KEYDOWN :
if(LOWORD(wParam) == VK_RETURN)
{
HideCaret(hWnd);
nY++;
nX = 0;
SetCaretPos(cxChar*nX, cyChar*nY);
ShowCaret(hWnd);
}
return FALSE;
case WM_DESTROY :
PostQuitMessage(0);
return FALSE;
}
return DefWindowProc(hWnd, mesg, wParam, lParam);
}
자 그러면 구체적으로 각 메시지에서 어떤 직업들을 하는지 알아 봅시다.
먼저 윈도우가 생성될때 입니다.
case WM_CREATE :
nX = nY = 0;
초기 좌표를 (0, 0)으로 초기화 하는 작업입니다.
hDC = GetDC(hWnd);
SelectObject(hDC, GetStockObject(SYSTEM_FIXED_FONT));
GetTextMetrics(hDC, &tm);
ReleaseDC(hWnd, hDC);
cxChar = tm.tmAveCharWidth;
cyChar = tm.tmHeight;
return FALSE;
디바이스 컨텍스트 핸들을 얻어 고정 폰트를 선택하고 그 고정 폰트에 대한
문자 길이와 넓이를 얻는 과정입니다.
case WM_SETFOCUS :
흠 못보던 메시지가 있군요. 위 메시지는 윈도우가 입력 포커스를 얻었다는 것
을 알리는 메시지입니다. 메시지를 생성하고 보이는 루틴을 이 이하에 작성해
주면 되죠.
CreateCaret(hWnd, NULL, cxChar, cyChar);
SetCaretPos(cxChar*nX, cyChar*nY);
ShowCaret(hWnd);
return FALSE;
캐럿을 현재 고정 폰트의 크기만큼 생성하고 해당 좌표에 위치시켜 보이게 하는
작업을 하고 있습니다.
case WM_KILLFOCUS :
윈도우가 입력 포커스를 잃어 버렸을때 위 메시지가 발생됩니다.
HideCaret(hWnd);
DestroyCaret();
return FALSE;
캐럿을 보이지 않게 하고 없애는 구문이 들어가 있군요. DestroyCaret()함수는
위 설명에서 하지 않았습니다. 사용방법은 위와 같습니다.
case WM_CHAR :
자 이번에는 중요한 메시지에 대해 알아 봅시다. WM_CHAR 메시지는 유저가 시스
템 키를 제외한 문자키를 눌렀을때 발생하는 메시지입니다. 예를들어서 유저가
A키를 누르거나 숫자키 8을 눌렀을때 이 메시지가 발생되는죠. 그러면 구체적
으로 그 눌린키가 어떤것인지 어떻게 알수 있을까요? 그 구체적인 키값은 wParam
메시지에 들어가게 되는 것입니다.
HideCaret(hWnd);
hDC = GetDC(hWnd);
if(LOWORD(wParam) != '\r')
{
cChar = (char)wParam;
TextOut(hDC, cxChar*nX, cyChar*nY, &cChar, 1);
nX++;
}
눌린키값을 화면에 출력해주는 구문입니다. 그렇게 특별한 것은 없고 다지 조건문
을 잘보기 바랍니다. 한번 위 조건문을 사용하지 않고 프로그램을 컴파일해서 실
행시켜 보면 왜 위와 같은 처리 작업이 필요한지 알수 있을 겁니다.
ReleaseDC(hWnd, hDC);
SetCaretPos(cxChar*nX, cyChar*nY);
ShowCaret(hWnd);
return FALSE;
문자를 출력했으니 그 다음 좌표로 캐럿을 이동해야 겠죠? 바로 그 작업입니다.
case WM_KEYDOWN :
위에서도 몇번 언급을 했지만 일반키외에 특수키가 눌리면 WM_KEYDOWN이라는
메시지가 발생됩니다. 구체적으로 어떤 특수키인지는 wParam에 저장되죠. 특수키
를 구분할때에는 윈도우에 예약되어 있는 값으로 구분하는데 그 값은 아래에 정리
해 두었습니다.
if(LOWORD(wParam) == VK_RETURN)
{
HideCaret(hWnd);
nY++;
nX = 0;
SetCaretPos(cxChar*nX, cyChar*nY);
ShowCaret(hWnd);
}
return FALSE;
Enter키가 눌리면 Y좌표를 증가하고 X좌표를 0으로 해주는 작업입니다. 물론 캐럿
의 위치도 바뀌어야 겠죠.
VK_CANCEL Ctrl+Break
VK_BACK 백 스페이스
VK_TAB 탭키
VK_RETURN Enter키
VK_SHIFT Shift키
VK_CONTROL Ctrl키
VK_MENU Alt키
VK_PAUSE Pause키
VK_CAPITAL Caps Lock키
VK_ESCAPE Esc키
VK_SPACE Space키
VK_PRIOR PageUp키
VK_NEXT PageDown키
VK_END End키
VK_HOME Hone키
VK_LEFT 방향키 왼쪽
VK_RIGHT 방향키 오른쪽
VK_UP 방향키 위
VK_DOWN 방향키 아래
VK_INSERT Insert키
VK_DELETE Delete키
VK_F1 F1키
.
.
VK_F12F12키
반응형

'API 관련 > API 강좌모음' 카테고리의 다른 글

[강좌 7] 마우스, 타이머  (0) 2007.10.26
[강좌 6] 출력부분  (0) 2007.10.26
[강좌 4] 문자열 출력  (0) 2007.10.26
[강좌 3] 윈도우의 생성과 다루기  (0) 2007.10.26
[강좌 2] 윈도우의 생성과 다루기  (0) 2007.10.26
Comments