지난 시간에 이어서 윈도우 메세지를 계속 다뤄보자.
시작하기에 앞서, 윈도우 MSDN에는 메세지 하나하나에 대한 개별적인 항목은 있으나 메세지들의 목록이 없어 불편하기 때문에, 대신 사용할 수 있는 사이트 하나를 기재한다.
https://wiki.winehq.org/List_Of_Windows_Messages
다만 여기에는 목록만 있을 뿐 어떤게 자주 쓰이는지에 대한 정보는 없기 때문에, 편의를 위해 우리의 커스텀 WndProc이 어떤 메세지를 수신할 때마다 그 메세지의 이름과 lParam, wParam을 출력해주는 WindowsMessageMap이라는 객체를 만들어 사용하자.
또 이 객체에는 자주 쓰는 메세지들에 대해서는 메세지 int와 메세지 이름을 맵핑시켜주어 출력될 수 있게 만들자.
구현에 어려운 게 없어 코드만 첨부한다.
// WindowsMessageMap.h
#pragma once
#include <unordered_map>
#include <Windows.h>
class WindowsMessageMap
{
public:
WindowsMessageMap();
std::string operator()( DWORD msg,LPARAM lp,WPARAM wp ) const;
private:
std::unordered_map<DWORD,std::string> map;
};
#include "WindowsMessageMap.h"
#include <Windows.h>
#include <string>
#include <sstream>
#include <iomanip>
// secret messages
#define WM_UAHDESTROYWINDOW 0x0090
#define WM_UAHDRAWMENU 0x0091
#define WM_UAHDRAWMENUITEM 0x0092
#define WM_UAHINITMENU 0x0093
#define WM_UAHMEASUREMENUITEM 0x0094
#define WM_UAHNCPAINTMENUPOPUP 0x0095
#define REGISTER_MESSAGE(msg){msg,#msg}
WindowsMessageMap::WindowsMessageMap()
:
map( {
REGISTER_MESSAGE( WM_CREATE ),
REGISTER_MESSAGE( WM_DESTROY ),
REGISTER_MESSAGE( WM_MOVE ),
REGISTER_MESSAGE( WM_SIZE ),
REGISTER_MESSAGE( WM_ACTIVATE ),
REGISTER_MESSAGE( WM_SETFOCUS ),
REGISTER_MESSAGE( WM_KILLFOCUS ),
REGISTER_MESSAGE( WM_ENABLE ),
REGISTER_MESSAGE( WM_SETREDRAW ),
REGISTER_MESSAGE( WM_SETTEXT ),
REGISTER_MESSAGE( WM_GETTEXT ),
REGISTER_MESSAGE( WM_GETTEXTLENGTH ),
REGISTER_MESSAGE( WM_PAINT ),
REGISTER_MESSAGE( WM_CLOSE ),
REGISTER_MESSAGE( WM_QUERYENDSESSION ),
REGISTER_MESSAGE( WM_QUIT ),
REGISTER_MESSAGE( WM_QUERYOPEN ),
REGISTER_MESSAGE( WM_ERASEBKGND ),
REGISTER_MESSAGE( WM_SYSCOLORCHANGE ),
REGISTER_MESSAGE( WM_ENDSESSION ),
REGISTER_MESSAGE( WM_SHOWWINDOW ),
REGISTER_MESSAGE( WM_CTLCOLORMSGBOX ),
REGISTER_MESSAGE( WM_CTLCOLOREDIT ),
REGISTER_MESSAGE( WM_CTLCOLORLISTBOX ),
REGISTER_MESSAGE( WM_CTLCOLORBTN ),
REGISTER_MESSAGE( WM_CTLCOLORDLG ),
REGISTER_MESSAGE( WM_CTLCOLORSCROLLBAR ),
REGISTER_MESSAGE( WM_CTLCOLORSTATIC ),
REGISTER_MESSAGE( WM_WININICHANGE ),
REGISTER_MESSAGE( WM_SETTINGCHANGE ),
REGISTER_MESSAGE( WM_DEVMODECHANGE ),
REGISTER_MESSAGE( WM_ACTIVATEAPP ),
REGISTER_MESSAGE( WM_FONTCHANGE ),
REGISTER_MESSAGE( WM_TIMECHANGE ),
REGISTER_MESSAGE( WM_CANCELMODE ),
REGISTER_MESSAGE( WM_SETCURSOR ),
REGISTER_MESSAGE( WM_MOUSEACTIVATE ),
REGISTER_MESSAGE( WM_CHILDACTIVATE ),
REGISTER_MESSAGE( WM_QUEUESYNC ),
REGISTER_MESSAGE( WM_GETMINMAXINFO ),
REGISTER_MESSAGE( WM_ICONERASEBKGND ),
REGISTER_MESSAGE( WM_NEXTDLGCTL ),
REGISTER_MESSAGE( WM_SPOOLERSTATUS ),
REGISTER_MESSAGE( WM_DRAWITEM ),
REGISTER_MESSAGE( WM_MEASUREITEM ),
REGISTER_MESSAGE( WM_DELETEITEM ),
REGISTER_MESSAGE( WM_VKEYTOITEM ),
REGISTER_MESSAGE( WM_CHARTOITEM ),
REGISTER_MESSAGE( WM_SETFONT ),
REGISTER_MESSAGE( WM_GETFONT ),
REGISTER_MESSAGE( WM_QUERYDRAGICON ),
REGISTER_MESSAGE( WM_COMPAREITEM ),
REGISTER_MESSAGE( WM_COMPACTING ),
REGISTER_MESSAGE( WM_NCCREATE ),
REGISTER_MESSAGE( WM_NCDESTROY ),
REGISTER_MESSAGE( WM_NCCALCSIZE ),
REGISTER_MESSAGE( WM_NCHITTEST ),
REGISTER_MESSAGE( WM_NCPAINT ),
REGISTER_MESSAGE( WM_NCACTIVATE ),
REGISTER_MESSAGE( WM_GETDLGCODE ),
REGISTER_MESSAGE( WM_NCMOUSEMOVE ),
REGISTER_MESSAGE( WM_NCLBUTTONDOWN ),
REGISTER_MESSAGE( WM_NCLBUTTONUP ),
REGISTER_MESSAGE( WM_NCLBUTTONDBLCLK ),
REGISTER_MESSAGE( WM_NCRBUTTONDOWN ),
REGISTER_MESSAGE( WM_NCRBUTTONUP ),
REGISTER_MESSAGE( WM_NCRBUTTONDBLCLK ),
REGISTER_MESSAGE( WM_NCMBUTTONDOWN ),
REGISTER_MESSAGE( WM_NCMBUTTONUP ),
REGISTER_MESSAGE( WM_NCMBUTTONDBLCLK ),
REGISTER_MESSAGE( WM_KEYDOWN ),
REGISTER_MESSAGE( WM_KEYUP ),
REGISTER_MESSAGE( WM_CHAR ),
REGISTER_MESSAGE( WM_DEADCHAR ),
REGISTER_MESSAGE( WM_SYSKEYDOWN ),
REGISTER_MESSAGE( WM_SYSKEYUP ),
REGISTER_MESSAGE( WM_SYSCHAR ),
REGISTER_MESSAGE( WM_SYSDEADCHAR ),
REGISTER_MESSAGE( WM_KEYLAST ),
REGISTER_MESSAGE( WM_INITDIALOG ),
REGISTER_MESSAGE( WM_COMMAND ),
REGISTER_MESSAGE( WM_SYSCOMMAND ),
REGISTER_MESSAGE( WM_TIMER ),
REGISTER_MESSAGE( WM_HSCROLL ),
REGISTER_MESSAGE( WM_VSCROLL ),
REGISTER_MESSAGE( WM_INITMENU ),
REGISTER_MESSAGE( WM_INITMENUPOPUP ),
REGISTER_MESSAGE( WM_MENUSELECT ),
REGISTER_MESSAGE( WM_MENUCHAR ),
REGISTER_MESSAGE( WM_ENTERIDLE ),
REGISTER_MESSAGE( WM_MOUSEWHEEL ),
REGISTER_MESSAGE( WM_MOUSEMOVE ),
REGISTER_MESSAGE( WM_LBUTTONDOWN ),
REGISTER_MESSAGE( WM_LBUTTONUP ),
REGISTER_MESSAGE( WM_LBUTTONDBLCLK ),
REGISTER_MESSAGE( WM_RBUTTONDOWN ),
REGISTER_MESSAGE( WM_RBUTTONUP ),
REGISTER_MESSAGE( WM_RBUTTONDBLCLK ),
REGISTER_MESSAGE( WM_MBUTTONDOWN ),
REGISTER_MESSAGE( WM_MBUTTONUP ),
REGISTER_MESSAGE( WM_MBUTTONDBLCLK ),
REGISTER_MESSAGE( WM_PARENTNOTIFY ),
REGISTER_MESSAGE( WM_MDICREATE ),
REGISTER_MESSAGE( WM_MDIDESTROY ),
REGISTER_MESSAGE( WM_MDIACTIVATE ),
REGISTER_MESSAGE( WM_MDIRESTORE ),
REGISTER_MESSAGE( WM_MDINEXT ),
REGISTER_MESSAGE( WM_MDIMAXIMIZE ),
REGISTER_MESSAGE( WM_MDITILE ),
REGISTER_MESSAGE( WM_MDICASCADE ),
REGISTER_MESSAGE( WM_MDIICONARRANGE ),
REGISTER_MESSAGE( WM_MDIGETACTIVE ),
REGISTER_MESSAGE( WM_MDISETMENU ),
REGISTER_MESSAGE( WM_CUT ),
REGISTER_MESSAGE( WM_COPYDATA ),
REGISTER_MESSAGE( WM_COPY ),
REGISTER_MESSAGE( WM_PASTE ),
REGISTER_MESSAGE( WM_CLEAR ),
REGISTER_MESSAGE( WM_UNDO ),
REGISTER_MESSAGE( WM_RENDERFORMAT ),
REGISTER_MESSAGE( WM_RENDERALLFORMATS ),
REGISTER_MESSAGE( WM_DESTROYCLIPBOARD ),
REGISTER_MESSAGE( WM_DRAWCLIPBOARD ),
REGISTER_MESSAGE( WM_PAINTCLIPBOARD ),
REGISTER_MESSAGE( WM_VSCROLLCLIPBOARD ),
REGISTER_MESSAGE( WM_SIZECLIPBOARD ),
REGISTER_MESSAGE( WM_ASKCBFORMATNAME ),
REGISTER_MESSAGE( WM_CHANGECBCHAIN ),
REGISTER_MESSAGE( WM_HSCROLLCLIPBOARD ),
REGISTER_MESSAGE( WM_QUERYNEWPALETTE ),
REGISTER_MESSAGE( WM_PALETTEISCHANGING ),
REGISTER_MESSAGE( WM_PALETTECHANGED ),
REGISTER_MESSAGE( WM_DDE_INITIATE ),
REGISTER_MESSAGE( WM_DDE_TERMINATE ),
REGISTER_MESSAGE( WM_DDE_ADVISE ),
REGISTER_MESSAGE( WM_DDE_UNADVISE ),
REGISTER_MESSAGE( WM_DDE_ACK ),
REGISTER_MESSAGE( WM_DDE_DATA ),
REGISTER_MESSAGE( WM_DDE_REQUEST ),
REGISTER_MESSAGE( WM_DDE_POKE ),
REGISTER_MESSAGE( WM_DDE_EXECUTE ),
REGISTER_MESSAGE( WM_DROPFILES ),
REGISTER_MESSAGE( WM_POWER ),
REGISTER_MESSAGE( WM_WINDOWPOSCHANGED ),
REGISTER_MESSAGE( WM_WINDOWPOSCHANGING ),
REGISTER_MESSAGE( WM_HELP ),
REGISTER_MESSAGE( WM_NOTIFY ),
REGISTER_MESSAGE( WM_CONTEXTMENU ),
REGISTER_MESSAGE( WM_TCARD ),
REGISTER_MESSAGE( WM_MDIREFRESHMENU ),
REGISTER_MESSAGE( WM_MOVING ),
REGISTER_MESSAGE( WM_STYLECHANGED ),
REGISTER_MESSAGE( WM_STYLECHANGING ),
REGISTER_MESSAGE( WM_SIZING ),
REGISTER_MESSAGE( WM_SETHOTKEY ),
REGISTER_MESSAGE( WM_PRINT ),
REGISTER_MESSAGE( WM_PRINTCLIENT ),
REGISTER_MESSAGE( WM_POWERBROADCAST ),
REGISTER_MESSAGE( WM_HOTKEY ),
REGISTER_MESSAGE( WM_GETICON ),
REGISTER_MESSAGE( WM_EXITMENULOOP ),
REGISTER_MESSAGE( WM_ENTERMENULOOP ),
REGISTER_MESSAGE( WM_DISPLAYCHANGE ),
REGISTER_MESSAGE( WM_STYLECHANGED ),
REGISTER_MESSAGE( WM_STYLECHANGING ),
REGISTER_MESSAGE( WM_GETICON ),
REGISTER_MESSAGE( WM_SETICON ),
REGISTER_MESSAGE( WM_SIZING ),
REGISTER_MESSAGE( WM_MOVING ),
REGISTER_MESSAGE( WM_CAPTURECHANGED ),
REGISTER_MESSAGE( WM_DEVICECHANGE ),
REGISTER_MESSAGE( WM_PRINT ),
REGISTER_MESSAGE( WM_PRINTCLIENT ),
REGISTER_MESSAGE( WM_IME_SETCONTEXT ),
REGISTER_MESSAGE( WM_IME_NOTIFY ),
REGISTER_MESSAGE( WM_NCMOUSELEAVE ),
REGISTER_MESSAGE( WM_EXITSIZEMOVE ),
REGISTER_MESSAGE( WM_UAHDESTROYWINDOW ),
REGISTER_MESSAGE( WM_DWMNCRENDERINGCHANGED ),
REGISTER_MESSAGE( WM_ENTERSIZEMOVE ),
} )
{}
std::string WindowsMessageMap::operator()( DWORD msg,LPARAM lp,WPARAM wp ) const
{
constexpr int firstColWidth = 25;
const auto i = map.find( msg );
std::ostringstream oss;
if( i != map.end() )
{
oss << std::left << std::setw( firstColWidth ) << i->second << std::right;
}
else
{
std::ostringstream padss;
padss << "Unknown message: 0x" << std::hex << msg;
oss << std::left << std::setw( firstColWidth ) << padss.str() << std::right;
}
oss << " LP: 0x" << std::hex << std::setfill( '0' ) << std::setw( 8 ) << lp;
oss << " WP: 0x" << std::hex << std::setfill( '0' ) << std::setw( 8 ) << wp << std::endl;
return oss.str();
}
이후 프로그램을 실행하면 딱히 나의 (=클라이언트의) 입력이 없어도 여러 메세지들이 먼저 처리되는 것을 볼 수 있다.
그중에는 WM_CREATE와 같이 창을 생성하는 과정들도 포함되어있다.
메세지들중 NC라는 접두사를 붙이고 있는 것들이 있는데 이는 Non-Client의 약자로, 윈도우의 창은 클라이언트부(client region)와 논클라이언트부로 나뉜다.
클라이언트부는 창 내부(파란색 동그라미)이고, 논클라이언트부는 그 밖의 버튼들을 포함한 외곽 부분들을 의미한다.
창을 키고 F랑 D를 누르면 WM_KEYDOWN 메세지에서 wParam값이 0x46에서 0x44로 바뀌는 걸 볼 수 있는데, 이는 당연하게도 누른 버튼 키 자체에 대한 정보를 담고 있다.
이 값들은 Virtual-Key Codes라고 하며 엔터나 F1키같은 값들도 Virtual key codes가 있으니 아스키 코드랑 착각하지는 말자.
키코드들의 목록이나 WM_KEYDOWN의 다른 파라미터를 알고 싶다면 MSDN을 참고하자.
이렇게 배운 내용으로 F를 누르는 동안 특정 이벤트를 실행하게 하고 F키를 떼는 순간 다른 메세지로 변하게 할 수 있다.
'computer graphics > DirectX' 카테고리의 다른 글
[D3D Engine] 7. Window framework (0) | 2023.03.19 |
---|---|
[D3D Engine] 6. WM_CHAR, Mouse (0) | 2023.03.19 |
[D3D Engine] 4. Message loop, WinProc (0) | 2023.03.19 |
[D3D Engine] 3. Window Creation (0) | 2023.03.19 |
[D3D Engine] 2. WinMain (0) | 2023.03.19 |