Win32 API 의 장점 중 하나는 멀티 태스킹 환경을 지원한다는 것. 입력이 들어오면 포커스(입력 초점)을 가진 프로그램에 키보드 메세지를 보내게 되고, 프로그램은 키보드 메세지를 받아 입력을 처리한다.
-> 포커스를 가진 컨트롤만 키보드 입력을 받을 수 있고, 이와 관련한 메세지도 포커스를 가진 컨트롤에게만 전달.
포커스 : 입력 초점(입력이 들어올것 타이핑시 문자 입력 초점에 커서가 깜빡이는 것 등)
컨트롤 : 인터페이스를 통해 사용자로부터 명령과 입력을 받고 출력 결과를 보여주는 과정속 사용되는 입출력 도구(메세지 박스, 버튼 등 사용자와 상호작용하며 입출력하는 것)
1. 키보드 입력
TranslateMessage 함수를 통해 문자 정보를 확인해 WM_CHAR 메세지로 변환해서 DispatchMessage 함수를 통해서 윈도우 프로시저(WndProc)로 전달.
WndProc 함수의 3,4 번째 매개변수의 경우
WPARAM wParam : 입력 받은 문자 정보(어떤 키를 입력했는가)
LPARAM lParam : 부가 정보 (키 반복 횟수, 이전 키 상태 등)
2. 문자열이 static 인 이유
개발 목적에 따라 스페이스바가 입력되기 전까지 입력한 문자를 화면에 출력해야 한다.
-> static을 사용하지 않을 경우 메세지를 처리하고 나서 함수가 종료된다면 해당 문자열은 지역변수이기 때문에 메모리에서 없어지게 된다.
-> static을 사용해 전역 변수의 성격를 띌 수 있도록 작성한다. -> WndProc 함수에서만 접근할 수 있지만 함수가 종료되어도 메모리에서 사라지지 않는다.
-> WndProc 함수가 종료되어도 입력된 문자를 저장한 채 계속해서 출력할 수 있는 것.
3. WM_CHAR
WinMain 에서 TranslateMessage 함수를 통해서 발생한 WM_CHAR 메세지가 들어오면, wParam 에 저장된 문자 정보를 통해서 문자코드를 처리한다.
if (wParam == 32) // 입력한 문자에 따른 메세지 처리
{
str[0] = 0;
}
32 는 스페이스바 이다
문자열 첫 번째 인덱스에 0을 넣음으로써, 문자열에 아무것도 없다고 눈속임 하는것.
스페이스 이외의 문자가 들어온 경우 _tcslen 함수로 문자열의 길이 확인.
_tcslen 함수는 0번째 인덱스 부터 NULL값 까지의 길이를 확인한다.
-> 해당 인덱스에 문자를 넣고 그 다음 인덱스에 0 을 넣어서 방금 입력된 문자까지 출력하게 한다.
현재까지는 문자 배열의 값만 변경되었을 뿐이고 화면상 변화는 없다.
따라서, 윈도우에 변화가 있다는 것을 알릴 필요가 있다. 이때 사용하는 것이 InvalidateRect 함수이다.
4. InvalidateRect 함수 무효 영역(Invalid Region)
- 무효 영역이란 다른 응용 프로그램에 의해 일부 가려져 있는 부분이다.
- WM_CHAR 메세지를 처리하는 것과 같이 내부적인 문자 입력은 운영체제가 판단할 수 없다.(화면에 보여지는지, 단순 계산인지, 전송인지 등)
- 이 때, InvalidateRect 또는 IncalidateRgn 함수를 사용해서 윈도우의 작업 영역을 무효화하여 운영체제로 하여금 WM_PAINT 메세지를 해당 윈도우로 보내도록 한다.
- InvalidateRect 원형
HWND hWnd : 무효화 시킬 윈도우(윈도우의 핸들)
const RECT *lpRect : 무효화할 영역 지정(NULL이면 전체 영역 무효화)
BOOL bErase : TRUE 이면 지우고 다시 그리고, FALSE 이면 지우지 않고 덮어쓴다
-> 2번째 인수로 일부 영역만 다시 그릴 수 있고, 3번째 인수를 활용하여 아예 지우고 다시 그리거나 기존의 것에 덮어 씌울 수 있다.
- 결론 : InvalidateRect 함수를 통해서 화면의 변화가 있다고 운영체제에게 알린 뒤, WM_PAINT 메세지가 발생해 화면에 문자열을 출력하는 것.
5. 백스페이스 추가
6. WM_KEYDOWN
문자 이외의 키를 입력 받으려면 WM_CHAR 만으로는 입력을 받을 수 없다. 이때 WM_KEYDOWN을 사용한다.
WM_KEYDOWN 메시지는 wParam에 문자 코드가 아닌 가상 키코드 라는 것을 전달해 준다.
가상 키코드(Virtual Key Code) : 시스템에 장착된 키보드의 종류에 상관없이 키를 입력받기 위해 만들어지 코드 값
6-1 사각형을 화면에 띄우고 방향키로 이동
// 움직일 객체 설정
class NemoPlayer
{
private :
POINT ptPos; // POINT는 x, y 를 각 long 자료형으로 가지는 구조체
POINT ptSize;
public:
void SetPos(int _x, int _y)
{
ptPos.x = _x;
ptPos.y = _y;
}
void SetSize(int _x, int _y)
{
ptSize.x = _x;
ptSize.y = _y;
}
POINT GetPos() { return ptPos; }
POINT GetSize() { return ptSize; }
public:
NemoPlayer()
: ptPos{}
, ptSize{}
{}
~NemoPlayer(){}
};
NemoPlayer Nemo1;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
switch (message)
{
case WM_CREATE:
Nemo1.SetPos(1920 / 2, 1080 / 2);
Nemo1.SetSize(100, 100);
DefWindowProc(hWnd, message, wParam, lParam); // ...?
break;
case WM_KEYDOWN:
{
POINT ptPos = Nemo1.GetPos();
switch (wParam)
{
case VK_RIGHT:
ptPos.x += 10;
break;
case VK_LEFT:
ptPos.x -= 10;
break;
case VK_UP:
ptPos.y -= 10;
break;
case VK_DOWN:
ptPos.y += 10;
break;
}
Nemo1.SetPos(ptPos.x, ptPos.y);
InvalidateRect(hWnd, nullptr, TRUE); // 인자( 목표가 되는 창 id, 그 창의 페인트할 영역(nullptr 이면 전체를 무효화 포인트로 잡음), 기존의 비트맵 그림을 어떻게 할 것인가(false: 남아있음, true 삭제)
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
Nemo1.GetPos().x - Nemo1.GetSize().x;
Rectangle(hdc, Nemo1.GetPos().x - Nemo1.GetSize().x / 2
, Nemo1.GetPos().y - Nemo1.GetSize().y / 2
, Nemo1.GetPos().x + Nemo1.GetSize().x / 2
, Nemo1.GetPos().y + Nemo1.GetSize().y / 2);
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
이상으로 하나의 객체를 키보드의 입력으로 움직이는 것까지 진행하였다. 하지만 하나의 키를 지속해서 누르는 경우 객체가 즉시 일정하게 움직이는 것이 아닌 정지 했다가 어느 시점이후로 일정하게 움직이는 것을 확인 할 수 있었다. 그것에 대해서는 추후에 설명하는 방법으로 해결한다.
'assortrock > Win32 API' 카테고리의 다른 글
Win32 API - 마우스 입력 (0) | 2022.07.07 |
---|---|
Win32 API - 메세지 박스 출력 (0) | 2022.07.04 |
Win32 API - 도형 출력 (0) | 2022.07.04 |
Win32 API - DC (Device Context) (0) | 2022.07.04 |
Win32 API 배경 지식 - 핸들(Handle) (0) | 2022.06.30 |