키보드로 이벤트를 발생시키면 WndProc()에 전달되는데

 

전달변수는

 

1. Msg : 키보드 메세지 ex) WM_KEYDOWN, WM_CHAR 등

 

2. wParam : 가상키값 ex ) A, B, C, 1, 2, 3, VK_BACK,VK_RETURN ...

 

가상키값은 우리가 알고있는 문자,특수문자는 아스키값으로 전달되며

 

방향키,Ctrl,Shift등의 값은 VK_LEFT,VK_CONTROL과 값은 값으로 전달된다. 자세한것은 

 

https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes

 

Virtual-Key Codes (Winuser.h) - Win32 apps

The following table shows the symbolic constant names, hexadecimal values, and mouse or keyboard equivalents for the virtual-key codes used by the system. The codes are listed in numeric order.

docs.microsoft.com

여기서 확인 할수 있다.

 

 

 

3. lParam : 부가정보 (키 반복횟수같은 내용이 담아있는듯 한데 중요하진 않은 것 같다.)

 

ex) 키를 눌렀을때 반응하는 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <windows.h>
#include <TCHAR.H> 
/* This is where all the input to the window goes to */
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
    
    HDC hdc;
    PAINTSTRUCT ps;
    RECT rect;
    switch(Message) {
        
        /* Upon destruction, tell the main thread to stop */
        case WM_CREATE:
            break
            
        
        case WM_CHAR:
            hdc = GetDC(hwnd);
            TextOut(hdc,0,0,_T("키를 눌렀을때 발생 "),21);
            ReleaseDC(hwnd,hdc);
            break;
        case WM_DESTROY: {
            PostQuitMessage(0);
            break;
        }
        
        /* All other messages (a lot of them) are processed using default procedures */
        default:
            return DefWindowProc(hwnd, Message, wParam, lParam);
    }
    return 0;
}
 
/* The 'main' function of Win32 GUI programs: this is where execution starts */
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    WNDCLASSEX wc; /* A properties struct of our window */
    HWND hwnd; /* A 'HANDLE', hence the H, or a pointer to our window */
    MSG msg; /* A temporary location for all messages */
 
    /* zero out the struct and set the stuff we want to modify */
    memset(&wc,0,sizeof(wc));
    wc.cbSize         = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc     = WndProc; /* This is where we will send messages to */
    wc.hInstance     = hInstance;
    wc.hCursor         = LoadCursor(NULL, IDC_IBEAM);
    
    /* White, COLOR_WINDOW is just a #define for a system color, try Ctrl+Clicking it */
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "Window Class Name";
    
    wc.hIcon         = LoadIcon(NULL, IDI_QUESTION); /* Load a standard icon */
    wc.hIconSm         = LoadIcon(NULL, IDI_QUESTION); /* use the name "A" to use the project icon */
 
    if(!RegisterClassEx(&wc)) {
        MessageBox(NULL"Window Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
        return 0;
    }
 
    hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,"Window Class Name","홍길동의 첫번째 윈도우 ",WS_VISIBLE|WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, /* x */
        CW_USEDEFAULT, /* y */
        CW_USEDEFAULT, /* width */
        CW_USEDEFAULT, /* height */
        NULL,NULL,hInstance,NULL);
 
    if(hwnd == NULL) {
        MessageBox(NULL"Window Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
        return 0;
    }
 
    /*
        This is the heart of our program where all input is processed and 
        sent to WndProc. Note that GetMessage blocks code flow until it receives something, so
        this loop will not produce unreasonably high CPU usage
    */
    while(GetMessage(&msg, NULL00> 0) { /* If no error is received... */
        TranslateMessage(&msg); /* Translate key codes to chars if present */
        DispatchMessage(&msg); /* Send it to WndProc */
    }
    return msg.wParam;
}
cs

 

실행 결과

 

 

 

 

 

키를 눌렀을때 어느 키를 눌렀는지 확인하는 코드

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <windows.h>
#include <TCHAR.H> 
/* This is where all the input to the window goes to */
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
    
    HDC hdc;
    static TCHAR str[2]; 
 
    switch(Message) {
        
        /* Upon destruction, tell the main thread to stop */
        case WM_CREATE:
            break
            
        
        case WM_CHAR:
            hdc = GetDC(hwnd);
            str[0]= wParam;
            str[1]= NULL;
            TextOut(hdc,0,0,str,_tcslen(str));
            ReleaseDC(hwnd,hdc);
            break;
        case WM_DESTROY: {
            PostQuitMessage(0);
            break;
        }
        
        /* All other messages (a lot of them) are processed using default procedures */
        default:
            return DefWindowProc(hwnd, Message, wParam, lParam);
    }
    return 0;
}
 
/* The 'main' function of Win32 GUI programs: this is where execution starts */
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    WNDCLASSEX wc; /* A properties struct of our window */
    HWND hwnd; /* A 'HANDLE', hence the H, or a pointer to our window */
    MSG msg; /* A temporary location for all messages */
 
    /* zero out the struct and set the stuff we want to modify */
    memset(&wc,0,sizeof(wc));
    wc.cbSize         = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc     = WndProc; /* This is where we will send messages to */
    wc.hInstance     = hInstance;
    wc.hCursor         = LoadCursor(NULL, IDC_IBEAM);
    
    /* White, COLOR_WINDOW is just a #define for a system color, try Ctrl+Clicking it */
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "Window Class Name";
    
    wc.hIcon         = LoadIcon(NULL, IDI_QUESTION); /* Load a standard icon */
    wc.hIconSm         = LoadIcon(NULL, IDI_QUESTION); /* use the name "A" to use the project icon */
 
    if(!RegisterClassEx(&wc)) {
        MessageBox(NULL"Window Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
        return 0;
    }
 
    hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,"Window Class Name","홍길동의 첫번째 윈도우 ",WS_VISIBLE|WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, /* x */
        CW_USEDEFAULT, /* y */
        CW_USEDEFAULT, /* width */
        CW_USEDEFAULT, /* height */
        NULL,NULL,hInstance,NULL);
 
    if(hwnd == NULL) {
        MessageBox(NULL"Window Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
        return 0;
    }
 
    /*
        This is the heart of our program where all input is processed and 
        sent to WndProc. Note that GetMessage blocks code flow until it receives something, so
        this loop will not produce unreasonably high CPU usage
    */
    while(GetMessage(&msg, NULL00> 0) { /* If no error is received... */
        TranslateMessage(&msg); /* Translate key codes to chars if present */
        DispatchMessage(&msg); /* Send it to WndProc */
    }
    return msg.wParam;
}
cs

 

 

 

하지만 위와 같은 코드에서는 창을 최소화하고 다시 켰을 때 입력한 값이 지워지는 현상을 볼 수있는데

 

원인 :

 

창을 최소화 하고 다시키면

 

화면을 깨끗이 지우고 WM_PAINT 메세지를 발생시키기 때문

 

 

해결 방법 : 

1. 먼저 출력할 변수를 지워지지 않게 전역변수나 static변수에 넣어둔다.

 

2. 그 이후 WM_PAINT에서 저장된 변수를 다시 그려버리면 깔끔하게 해결

 

 

 

 

ex)

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <windows.h>
#include <TCHAR.H> 
/* This is where all the input to the window goes to */
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
    
    HDC hdc;
    static TCHAR str[2]; 
    PAINTSTRUCT ps;
    switch(Message) {
        
        /* Upon destruction, tell the main thread to stop */
        case WM_CREATE:
            break
            
        case WM_PAINT:
            hdc = BeginPaint(hwnd,&ps);
            TextOut(hdc,0,0,str,_tcslen(str));
            EndPaint(hwnd,&ps);
            break;
        case WM_CHAR:
            hdc = GetDC(hwnd);
            str[0]= wParam;
            str[1]= NULL;
            TextOut(hdc,0,0,str,_tcslen(str));
            ReleaseDC(hwnd,hdc);
            break;
        case WM_DESTROY: {
            PostQuitMessage(0);
            break;
        }
        
        /* All other messages (a lot of them) are processed using default procedures */
        default:
            return DefWindowProc(hwnd, Message, wParam, lParam);
    }
    return 0;
}
 
/* The 'main' function of Win32 GUI programs: this is where execution starts */
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    WNDCLASSEX wc; /* A properties struct of our window */
    HWND hwnd; /* A 'HANDLE', hence the H, or a pointer to our window */
    MSG msg; /* A temporary location for all messages */
 
    /* zero out the struct and set the stuff we want to modify */
    memset(&wc,0,sizeof(wc));
    wc.cbSize         = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc     = WndProc; /* This is where we will send messages to */
    wc.hInstance     = hInstance;
    wc.hCursor         = LoadCursor(NULL, IDC_IBEAM);
    
    /* White, COLOR_WINDOW is just a #define for a system color, try Ctrl+Clicking it */
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "Window Class Name";
    
    wc.hIcon         = LoadIcon(NULL, IDI_QUESTION); /* Load a standard icon */
    wc.hIconSm         = LoadIcon(NULL, IDI_QUESTION); /* use the name "A" to use the project icon */
 
    if(!RegisterClassEx(&wc)) {
        MessageBox(NULL"Window Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
        return 0;
    }
 
    hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,"Window Class Name","홍길동의 첫번째 윈도우 ",WS_VISIBLE|WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, /* x */
        CW_USEDEFAULT, /* y */
        CW_USEDEFAULT, /* width */
        CW_USEDEFAULT, /* height */
        NULL,NULL,hInstance,NULL);
 
    if(hwnd == NULL) {
        MessageBox(NULL"Window Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
        return 0;
    }
 
    /*
        This is the heart of our program where all input is processed and 
        sent to WndProc. Note that GetMessage blocks code flow until it receives something, so
        this loop will not produce unreasonably high CPU usage
    */
    while(GetMessage(&msg, NULL00> 0) { /* If no error is received... */
        TranslateMessage(&msg); /* Translate key codes to chars if present */
        DispatchMessage(&msg); /* Send it to WndProc */
    }
    return msg.wParam;
}
cs

 

위 코드를 실행해보면 최소화후 다시 켜도 해당 문자가 저장되어 있음을 확인 할 수 있다.

 

하지만 이 코드도 다시한번 생각해보면 이런 현상을 막기 위해서 계속해서 WM_PAINT,WM_CHAR 에 모두 출력코드를 계속해서 적어야 한다.

 

이 문제를 해결하기 위해 InvalidateRgn() 함수를 사용하는데 이 함수의 역할은 윈도우를 최소화 시키지 않아도

강제로 WM_PAINT 메세지를 발생시킬 수 있다. 

즉, WM_PAINT에서만 출력코드를 사용하고 WM_CHAR 에서는 InvalidateRgn()함수만 호출하면 된다.

 

InvalidateRgn()함수는

 

BOOL InvalidateRgn(

    HWND hWnd,

    HRGN hRgn,

    BOOL bErase

);

 

 

hRgn : 수정 영역에 대한 핸들값 주로 NULL값을 쓴다 (클라이언트 영역 전체를 수정)

bErase : true면 모두 삭제하고 다시 그림(이경우 출력량이 많으면 화면이 깜빡꺼린다고 한다), false면 수정부분만 다시그림

 

ex)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <windows.h>
#include <TCHAR.H> 
/* This is where all the input to the window goes to */
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
    
    HDC hdc;
    static TCHAR str[2]; 
    PAINTSTRUCT ps;
    switch(Message) {
        
        /* Upon destruction, tell the main thread to stop */
        case WM_CREATE:
            break
            
        case WM_PAINT:
            hdc = BeginPaint(hwnd,&ps);
            TextOut(hdc,0,0,str,_tcslen(str));
            EndPaint(hwnd,&ps);
            break;
        case WM_CHAR:
            hdc = GetDC(hwnd);
            str[0]= wParam;
            str[1]= NULL;
            InvalidateRgn(hwnd,NULL,TRUE);
            ReleaseDC(hwnd,hdc);
            break;
        case WM_DESTROY: {
            PostQuitMessage(0);
            break;
        }
        
        /* All other messages (a lot of them) are processed using default procedures */
        default:
            return DefWindowProc(hwnd, Message, wParam, lParam);
    }
    return 0;
}
 
cs

 

 

 

출처 :

 

핵심 API로 배우는 윈도우 프로그래밍,   강경우 지음   출판사 : 한빛아카데미

+ Recent posts