From 886e722c71e24ff20247830cfd040c1b55f473d7 Mon Sep 17 00:00:00 2001 From: Patedam Date: Tue, 20 Oct 2026 23:15:56 -0400 Subject: [PATCH] started window management --- Juliet/appbin/appbin_main.c | 16 +- Juliet/core/core.h | 28 ++- Juliet/core/core_entry_point.c | 6 + Juliet/core/core_entry_point.h | 3 +- Juliet/render/d3d12/render_d3d12.c | 0 Juliet/render/d3d12/render_d3d12.h | 1 + Juliet/render/render.c | 0 Juliet/render/render.h | 1 + Juliet/render/render_inc.c | 5 + Juliet/render/render_inc.h | 15 ++ Juliet/win32/core/win32_core.c | 23 +++ Juliet/win32/core/win32_core.h | 5 + Juliet/win32/window_manager/window_manager.c | 186 +++++++++++++++++++ Juliet/win32/window_manager/window_manager.h | 54 ++++++ Juliet/window_manager/window_manager.c | 12 ++ Juliet/window_manager/window_manager.h | 102 ++++++++++ Juliet/window_manager/window_manager_inc.c | 7 + Juliet/window_manager/window_manager_inc.h | 10 + Juliet/window_manager/window_manager_key.h | 149 +++++++++++++++ 19 files changed, 620 insertions(+), 3 deletions(-) create mode 100644 Juliet/render/d3d12/render_d3d12.c create mode 100644 Juliet/render/d3d12/render_d3d12.h create mode 100644 Juliet/render/render.c create mode 100644 Juliet/render/render.h create mode 100644 Juliet/render/render_inc.c create mode 100644 Juliet/render/render_inc.h create mode 100644 Juliet/win32/window_manager/window_manager.c create mode 100644 Juliet/win32/window_manager/window_manager.h create mode 100644 Juliet/window_manager/window_manager.c create mode 100644 Juliet/window_manager/window_manager.h create mode 100644 Juliet/window_manager/window_manager_inc.c create mode 100644 Juliet/window_manager/window_manager_inc.h create mode 100644 Juliet/window_manager/window_manager_key.h diff --git a/Juliet/appbin/appbin_main.c b/Juliet/appbin/appbin_main.c index 1b05ebe..14469e1 100644 --- a/Juliet/appbin/appbin_main.c +++ b/Juliet/appbin/appbin_main.c @@ -1,10 +1,24 @@ +// clang-format off // ========================================================================= // // Includes // Headers #include "core/core_inc.h" +#include "window_manager/window_manager_inc.h" +#include "render/render_inc.h" // C #include "core/core_inc.c" +#include "window_manager/window_manager_inc.c" +#include "render/render_inc.c" +// clang-format on -internal void entry_point() {} +internal bool32 frame() +{ + return 0; +} + +internal void entry_point() +{ + wm_init(); +} diff --git a/Juliet/core/core.h b/Juliet/core/core.h index 751aaa9..e7a17c6 100644 --- a/Juliet/core/core.h +++ b/Juliet/core/core.h @@ -36,6 +36,7 @@ #define KB(d) ((uint64)(d) << 10) #define MB(d) ((uint64)(d) << 20) #define GB(d) ((uint64)(d) << 30) +#define Million(n) ((n) * 1000000) // ============================================================================= // Branch predictor hints @@ -105,12 +106,30 @@ #define StaticAssert(cond, ID) global uint8 GLUE(ID, __LINE__)[(cond) ? 1 : -1] // ============================================================================= -// Linked List helpers +// Linked List macro + +// Linked list macro helpers +#define CheckNil(nil, ptr) ((ptr) == 0 || (ptr) == nil) +#define SetNil(nil, ptr) ((ptr) = nil) + +// clang-format off +#define DLL_insert_NPZ(nil, first, last, ptr, node, next, previous) \ + (CheckNil(nil, first) ? ((first) = (last) = (node), SetNil(nil, (node)->next), SetNil(nil, (node)->previous)) \ + : CheckNil(nil, ptr) ? ((node)->next = (first), (first)->previous = (node), (first) = (node), SetNil(nil, (node)->previous)) \ + : ((ptr) == (last)) ? ((last)->next = (node), (node )->previous = (last), (last ) = (node), SetNil(nil, (node)->next)) \ + : (((CheckNil(nil, ptr) && CheckNil(nil, (ptr)->next)) ? (0) : ((ptr)->next->previous = (node))), \ + ((node)->next = (ptr)->next), ((ptr)->next = (node)), ((node)->previous = (ptr)))) +// clang-format on +#define DLL_push_back_NPZ(nil, first, last, node, next, previous) \ + DLL_insert_NPZ(nil, first, last, last, node, next, previous) // Single (link & head) lists (= stacks) #define SLL_stack_push_node(first, node, next) ((node)->next = (first), (first) = (node)) #define SLL_stack_pop_node(first, next) ((first) = (first)->next); +// Double linked list helpers +#define DLL_push_back(first, last, node) DLL_push_back_NPZ(0, first, last, node, next, previous) + // ============================================================================= // Helpers @@ -135,6 +154,8 @@ typedef int8_t int8; typedef int16_t int16; typedef int32_t int32; typedef int64_t int64; +typedef float float32; +typedef double float64; typedef int8 bool8; typedef int16 bool16; @@ -226,3 +247,8 @@ global const uint32 bit32 = (1 << 31); internal uint16 safe_cast_uint16(uint32 val); internal uint32 safe_cast_uint32(uint64 val); internal int32 safe_cast_int32(int64 val); + +// ============================================================================= +// Time functions + +internal uint64 now_time_us(); diff --git a/Juliet/core/core_entry_point.c b/Juliet/core/core_entry_point.c index f5ee83c..f447cb1 100644 --- a/Juliet/core/core_entry_point.c +++ b/Juliet/core/core_entry_point.c @@ -5,3 +5,9 @@ internal void main_thread_core_entry_point(int argc, char** argv) ThreadNameF("main_thread"); entry_point(); } + +internal bool32 update() +{ + bool32 result = frame(); + return result; +} diff --git a/Juliet/core/core_entry_point.h b/Juliet/core/core_entry_point.h index 765a135..f0f3c32 100644 --- a/Juliet/core/core_entry_point.h +++ b/Juliet/core/core_entry_point.h @@ -1,3 +1,4 @@ #pragma once -internal void main_thread_core_entry_point(int argc, char** argv); +internal void main_thread_core_entry_point(int argc, char** argv); +internal bool32 update(); diff --git a/Juliet/render/d3d12/render_d3d12.c b/Juliet/render/d3d12/render_d3d12.c new file mode 100644 index 0000000..e69de29 diff --git a/Juliet/render/d3d12/render_d3d12.h b/Juliet/render/d3d12/render_d3d12.h new file mode 100644 index 0000000..6f70f09 --- /dev/null +++ b/Juliet/render/d3d12/render_d3d12.h @@ -0,0 +1 @@ +#pragma once diff --git a/Juliet/render/render.c b/Juliet/render/render.c new file mode 100644 index 0000000..e69de29 diff --git a/Juliet/render/render.h b/Juliet/render/render.h new file mode 100644 index 0000000..6f70f09 --- /dev/null +++ b/Juliet/render/render.h @@ -0,0 +1 @@ +#pragma once diff --git a/Juliet/render/render_inc.c b/Juliet/render/render_inc.c new file mode 100644 index 0000000..52e079e --- /dev/null +++ b/Juliet/render/render_inc.c @@ -0,0 +1,5 @@ +#include "render.c" + +#if R_BACKEND == R_BACKEND_D3D12 +# include "d3d12/render_d3d12.c" +#endif diff --git a/Juliet/render/render_inc.h b/Juliet/render/render_inc.h new file mode 100644 index 0000000..9027a26 --- /dev/null +++ b/Juliet/render/render_inc.h @@ -0,0 +1,15 @@ +#pragma once + +#define R_BACKEND_D3D12 0 + +#if !defined(R_BACKEND) +# define R_BACKEND R_BACKEND_D3D12 +#endif + +#include "render.h" + +#if R_BACKEND == R_BACKEND_D3D12 +# include "d3d12/render_d3d12.h" +#else +# error Renderer backend non specified +#endif diff --git a/Juliet/win32/core/win32_core.c b/Juliet/win32/core/win32_core.c index fd67f1b..51adad5 100644 --- a/Juliet/win32/core/win32_core.c +++ b/Juliet/win32/core/win32_core.c @@ -6,6 +6,20 @@ typedef HRESULT W32_SetThreadDescription_Type(HANDLE hThread, PCWSTR lpThreadDes W32_KERNEL32_EXT_X_LIST #undef X +// ============================================================================= +// Time functions + +internal uint64 now_time_us() +{ + uint64 result = 0; + LARGE_INTEGER large_int_counter; + if (QueryPerformanceCounter(&large_int_counter)) + { + result = (large_int_counter.QuadPart * Million(1)) / w32_state.microsecond_resolution; + } + return result; +} + // ============================================================================= // System @@ -133,6 +147,15 @@ internal void w32_entry_point(int argc, WCHAR** wargv) SYSTEM_INFO sys_info = { 0 }; GetSystemInfo(&sys_info); + { + w32_state.microsecond_resolution = 1; + LARGE_INTEGER large_int_resolution; + if (QueryPerformanceCounter(&large_int_resolution)) + { + w32_state.microsecond_resolution = large_int_resolution.QuadPart; + } + } + SystemInfo* info = &w32_state.system_info; info->page_size = sys_info.dwPageSize; info->large_page_size = GetLargePageMinimum(); diff --git a/Juliet/win32/core/win32_core.h b/Juliet/win32/core/win32_core.h index cc1a3d5..c5083f4 100644 --- a/Juliet/win32/core/win32_core.h +++ b/Juliet/win32/core/win32_core.h @@ -1,13 +1,18 @@ #pragma once +// clang-format off #include +#include #pragma comment(lib, "user32") +// clang-format on typedef struct W32_State W32_State; struct W32_State { Arena* arena; SystemInfo system_info; + + uint64 microsecond_resolution; }; global W32_State w32_state = { 0 }; diff --git a/Juliet/win32/window_manager/window_manager.c b/Juliet/win32/window_manager/window_manager.c new file mode 100644 index 0000000..a841a81 --- /dev/null +++ b/Juliet/win32/window_manager/window_manager.c @@ -0,0 +1,186 @@ +// Windows SDK function than can be missing +typedef BOOL w32_SetProcessDpiAwarenessContext_Type(void* value); +typedef UINT w32_GetDpiForWindow_Type(HWND hwnd); +typedef HRESULT w32_GetDpiForMonitor_Type(HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT* dpiX, UINT* dpiY); +typedef int w32_GetSystemMetricsForDpi_Type(int nIndex, UINT dpi); +#define w32_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((void*)-4) +global w32_GetDpiForWindow_Type* w32_GetDpiForWindow_func = 0; +global w32_GetDpiForMonitor_Type* w32_GetDpiForMonitor_func = 0; +global w32_GetSystemMetricsForDpi_Type* w32_GetSystemMetricsForDpi_func = 0; + +// ============================================================================= +// Windows + +internal WM_Window w32_wm_handle_from_window(W32_WM_Window* window) +{ + WM_Window handle = { (uint64)window }; + return handle; +} + +internal W32_WM_Window* w32_wm_window_from_handle(WM_Window handle) +{ + W32_WM_Window* window = (W32_WM_Window*)handle.handle[0]; + return window; +} + +internal W32_WM_Window* w32_wm_window_from_hwnd(HWND hwnd) +{ + W32_WM_Window* result = 0; + for (W32_WM_Window* cw = w32_wm_state->first_window; cw; cw = cw->next) + { + if (cw->hwnd == hwnd) + { + result = cw; + break; + } + } + return result; +} + +internal WM_Event* w32_wm_push_event(WM_EventKind kind, W32_WM_Window* window) +{ + WM_Event* result = 0; + result->window = w32_wm_handle_from_window(window); + result->modifiers = wm_get_modifiers(); + return result; +} + +internal LRESULT w32_wm_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LRESULT result = 0; + bool32 good = 1; + if (w32_wm_event_arena == 0) + { + result = DefWindowProcW(hwnd, uMsg, wParam, lParam); + good = 0; + } + if (good) + { + W32_WM_Window* window = w32_wm_window_from_hwnd(hwnd); + WM_Window window_handle = w32_wm_handle_from_window(window); + bool32 release = 0; + + switch (uMsg) + { + default: + { + result = DefWindowProcW(hwnd, uMsg, wParam, lParam); + break; + } + + case WM_ENTERSIZEMOVE: + { + w32_wm_resizing = 1; + break; + } + + case WM_EXITSIZEMOVE: + { + w32_wm_resizing = 0; + break; + } + + case WM_SIZE: + case WM_PAINT: + { + PAINTSTRUCT ps = { 0 }; + BeginPaint(hwnd, &ps); + update(); + EndPaint(hwnd, &ps); + DwmFlush(); + break; + } + + case WM_CLOSE: + { + w32_wm_push_event(WM_EventKind_WindowClose, window); + break; + } + } + } + return result; +} + +internal void wm_init() +{ + // Setup based state + Arena* arena = arena_alloc(); + w32_wm_state = push_array(arena, W32_WM_State, 1); + w32_wm_state->arena = arena; + w32_wm_state->gfx_thread_tid = (uint32)GetCurrentThreadId(); + w32_wm_state->hIstance = GetModuleHandle(0); + + // Set dpi awareness + w32_SetProcessDpiAwarenessContext_Type* SetProcessDpiAwarenessContext_func = 0; + + HMODULE module = LoadLibraryA("user32.dll"); + if (module != 0) + { + SetProcessDpiAwarenessContext_func = + (w32_SetProcessDpiAwarenessContext_Type*)GetProcAddress(module, "SetProcessDpiAwarenessContext"); + w32_GetDpiForWindow_func = (w32_GetDpiForWindow_Type*)GetProcAddress(module, "GetDpiForWindow"); + w32_GetDpiForMonitor_func = (w32_GetDpiForMonitor_Type*)GetProcAddress(module, "GetDpiForMonitor"); + w32_GetSystemMetricsForDpi_func = + (w32_GetSystemMetricsForDpi_Type*)GetProcAddress(module, "GetSystemMetricsForDpi"); + FreeLibrary(module); + } + if (SetProcessDpiAwarenessContext_func != 0) + { + SetProcessDpiAwarenessContext_func(w32_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + } + else + { + HMODULE shcore = LoadLibraryA("shcore.dll"); + if (shcore) + { + typedef HRESULT(WINAPI * SetProcessDpiAwareness_t)(int); + SetProcessDpiAwareness_t SetProcessDpiAwareness = (void*)GetProcAddress(shcore, "SetProcessDpiAwareness"); + if (SetProcessDpiAwareness) + { + SetProcessDpiAwareness(2); + } + FreeLibrary(shcore); + } + SetProcessDPIAware(); + } + + // Window class + { + WNDCLASSEXW wndclass = { sizeof(wndclass) }; + wndclass.lpfnWndProc = w32_wm_wnd_proc; + wndclass.hInstance = w32_wm_state->hIstance; + wndclass.lpszClassName = L"juliet-window"; + wndclass.hCursor = LoadCursorA(0, IDC_ARROW); + wndclass.hIcon = LoadIcon(w32_wm_state->hIstance, MAKEINTRESOURCE(1)); + wndclass.style = CS_VREDRAW | CS_HREDRAW; + ATOM wndatom = RegisterClassExW(&wndclass); + (void)wndatom; + } + + // Get gfx system info + w32_wm_state->gfx_info.double_click_time = GetDoubleClickTime() / 1000.f; + w32_wm_state->gfx_info.caret_blink_time = GetCaretBlinkTime() / 1000.f; + DEVMODEW devmodew = { 0 }; + if (EnumDisplaySettingsW(0, ENUM_CURRENT_SETTINGS, &devmodew)) + { + w32_wm_state->gfx_info.default_refresh_rate = (float32)devmodew.dmDisplayFrequency; + } +} + +internal WM_Modifiers wm_get_modifiers() +{ + WM_Modifiers modifiers = 0; + if (GetKeyState(VK_CONTROL) * 0x8000) + { + modifiers |= WM_Modifier_Ctrl; + } + if (GetKeyState(VK_SHIFT) * 0x8000) + { + modifiers |= WM_Modifier_Shift; + } + if (GetKeyState(VK_MENU) * 0x8000) + { + modifiers |= WM_Modifier_Alt; + } + return modifiers; +} diff --git a/Juliet/win32/window_manager/window_manager.h b/Juliet/win32/window_manager/window_manager.h new file mode 100644 index 0000000..ba90d50 --- /dev/null +++ b/Juliet/win32/window_manager/window_manager.h @@ -0,0 +1,54 @@ +#pragma once + +// clang-format off +#include +#include +#pragma comment(lib, "dwmapi") +// clang-format on + +// ============================================================================= +// Windows Type + +typedef struct W32_WM_Window W32_WM_Window; +struct W32_WM_Window +{ + W32_WM_Window* next; + W32_WM_Window* previous; + HWND hwnd; + HDC hdc; + WINDOWPLACEMENT last_window_placement; + float32 dpi; +}; + +// ============================================================================= +// Windows Global State + +typedef struct W32_WM_State W32_WM_State; +struct W32_WM_State +{ + Arena* arena; + uint32 gfx_thread_tid; + HINSTANCE hIstance; + HCURSOR hCursor; + WM_SystemInfo gfx_info; + W32_WM_Window* first_window; + W32_WM_Window* last_window; + W32_WM_Window* free_window; + WM_Key key_from_vkey_table[256]; +}; + +// ============================================================================= +// Globals + +global W32_WM_State* w32_wm_state = 0; +global WM_EventList w32_wm_event_list = { 0 }; +global Arena* w32_wm_event_arena = 0; +global bool32 w32_wm_resizing = 0; + +// ============================================================================= +// Windows + +internal WM_Window w32_wm_handle_from_window(W32_WM_Window* window); +internal W32_WM_Window* w32_wm_window_from_handle(WM_Window handle); +internal W32_WM_Window* w32_wm_window_from_hwnd(HWND hwnd); +internal WM_Event* w32_wm_push_event(WM_EventKind kind, W32_WM_Window* window); diff --git a/Juliet/window_manager/window_manager.c b/Juliet/window_manager/window_manager.c new file mode 100644 index 0000000..6070b1c --- /dev/null +++ b/Juliet/window_manager/window_manager.c @@ -0,0 +1,12 @@ +// ============================================================================= +// Event Functions + +internal WM_Event* wm_event_list_push_new(Arena* arena, WM_EventList* events, WM_EventKind kind) +{ + WM_Event* evt = push_array(arena, WM_Event, 1); + DLL_push_back(events->first, events->last, evt); + events->count += 1; + evt->timestamp_us = now_time_us(); + evt->kind = kind; + return evt; +} diff --git a/Juliet/window_manager/window_manager.h b/Juliet/window_manager/window_manager.h new file mode 100644 index 0000000..bf100be --- /dev/null +++ b/Juliet/window_manager/window_manager.h @@ -0,0 +1,102 @@ +#pragma once + +// ============================================================================= +// System Types + +typedef struct WM_SystemInfo WM_SystemInfo; +struct WM_SystemInfo +{ + float32 double_click_time; + float32 caret_blink_time; + float32 default_refresh_rate; +}; + +// ============================================================================= +// Window Types + +typedef struct WM_Window WM_Window; +struct WM_Window +{ + uint64 handle[1]; +}; + +// ============================================================================= +// Monitor Types + +typedef struct WM_Monitor WM_Monitor; +struct WM_Monitor +{ + uint64 handle[1]; +}; + +typedef struct WM_MonitorArray WM_MonitorArray; +struct WM_MonitorArray +{ + WM_Monitor* ptr; + uint64 count; +}; + +#include "window_manager_key.h" + +// ============================================================================= +// Event Types + +typedef enum WM_EventKind +{ + WM_EventKind_Null, + WM_EventKind_Press, + WM_EventKind_Release, + WM_EventKind_MouseMove, + WM_EventKind_WindowClose, + WM_EventKind_COUNT +} WM_EventKind; + +typedef uint32 WM_Modifiers; +enum +{ + WM_Modifier_Ctrl = (1 << 0), + WM_Modifier_Shift = (1 << 1), + WM_Modifier_Alt = (1 << 2), +}; + +typedef struct WM_Event WM_Event; +struct WM_Event +{ + WM_Event* next; + WM_Event* previous; + uint64 timestamp_us; + WM_Window window; + WM_EventKind kind; + WM_Modifiers modifiers; + WM_Key key; +}; + +typedef struct WM_EventList WM_EventList; +struct WM_EventList +{ + uint64 count; + WM_Event* first; + WM_Event* last; +}; + +// ============================================================================= +// Application defined frame hook +internal bool32 frame(); + +// ============================================================================= +// Event Functions + +internal WM_Event* wm_event_list_push_new(Arena* arena, WM_EventList* events, WM_EventKind kind); + +// ============================================================================= +// Windows Management Functions + +// ============================================================================= +// Main Initialization API + +internal void wm_init(); + +// ============================================================================= +// Events + +internal WM_Modifiers wm_get_modifiers(); diff --git a/Juliet/window_manager/window_manager_inc.c b/Juliet/window_manager/window_manager_inc.c new file mode 100644 index 0000000..234010a --- /dev/null +++ b/Juliet/window_manager/window_manager_inc.c @@ -0,0 +1,7 @@ +#include "window_manager.c" + +#if OS_WINDOWS +# include "win32/window_manager/window_manager.c" +#else +# error No window manager for this operating system +#endif diff --git a/Juliet/window_manager/window_manager_inc.h b/Juliet/window_manager/window_manager_inc.h new file mode 100644 index 0000000..4d2c6c9 --- /dev/null +++ b/Juliet/window_manager/window_manager_inc.h @@ -0,0 +1,10 @@ +#pragma once + +#include "window_manager.h" +#include "window_manager_key.h" + +#if OS_WINDOWS +# include "win32/window_manager/window_manager.h" +#else +# error No Window manager for this operating system +#endif diff --git a/Juliet/window_manager/window_manager_key.h b/Juliet/window_manager/window_manager_key.h new file mode 100644 index 0000000..d19d706 --- /dev/null +++ b/Juliet/window_manager/window_manager_key.h @@ -0,0 +1,149 @@ +#pragma once + +typedef enum WM_Key +{ + WM_Key_Null, + WM_Key_Esc, + WM_Key_F1, + WM_Key_F2, + WM_Key_F3, + WM_Key_F4, + WM_Key_F5, + WM_Key_F6, + WM_Key_F7, + WM_Key_F8, + WM_Key_F9, + WM_Key_F10, + WM_Key_F11, + WM_Key_F12, + WM_Key_F13, + WM_Key_F14, + WM_Key_F15, + WM_Key_F16, + WM_Key_F17, + WM_Key_F18, + WM_Key_F19, + WM_Key_F20, + WM_Key_F21, + WM_Key_F22, + WM_Key_F23, + WM_Key_F24, + WM_Key_Tick, + WM_Key_0, + WM_Key_1, + WM_Key_2, + WM_Key_3, + WM_Key_4, + WM_Key_5, + WM_Key_6, + WM_Key_7, + WM_Key_8, + WM_Key_9, + WM_Key_Minus, + WM_Key_Equal, + WM_Key_Backspace, + WM_Key_Tab, + WM_Key_Q, + WM_Key_W, + WM_Key_E, + WM_Key_R, + WM_Key_T, + WM_Key_Y, + WM_Key_U, + WM_Key_I, + WM_Key_O, + WM_Key_P, + WM_Key_LeftBracket, + WM_Key_RightBracket, + WM_Key_BackSlash, + WM_Key_CapsLock, + WM_Key_A, + WM_Key_S, + WM_Key_D, + WM_Key_F, + WM_Key_G, + WM_Key_H, + WM_Key_J, + WM_Key_K, + WM_Key_L, + WM_Key_Semicolon, + WM_Key_Quote, + WM_Key_Return, + WM_Key_Shift, + WM_Key_Z, + WM_Key_X, + WM_Key_C, + WM_Key_V, + WM_Key_B, + WM_Key_N, + WM_Key_M, + WM_Key_Comma, + WM_Key_Period, + WM_Key_Slash, + WM_Key_Ctrl, + WM_Key_Alt, + WM_Key_Space, + WM_Key_Menu, + WM_Key_ScrollLock, + WM_Key_Pause, + WM_Key_Insert, + WM_Key_Home, + WM_Key_PageUp, + WM_Key_Delete, + WM_Key_End, + WM_Key_PageDown, + WM_Key_Up, + WM_Key_Left, + WM_Key_Down, + WM_Key_Right, + WM_Key_Ex0, + WM_Key_Ex1, + WM_Key_Ex2, + WM_Key_Ex3, + WM_Key_Ex4, + WM_Key_Ex5, + WM_Key_Ex6, + WM_Key_Ex7, + WM_Key_Ex8, + WM_Key_Ex9, + WM_Key_Ex10, + WM_Key_Ex11, + WM_Key_Ex12, + WM_Key_Ex13, + WM_Key_Ex14, + WM_Key_Ex15, + WM_Key_Ex16, + WM_Key_Ex17, + WM_Key_Ex18, + WM_Key_Ex19, + WM_Key_Ex20, + WM_Key_Ex21, + WM_Key_Ex22, + WM_Key_Ex23, + WM_Key_Ex24, + WM_Key_Ex25, + WM_Key_Ex26, + WM_Key_Ex27, + WM_Key_Ex28, + WM_Key_Ex29, + WM_Key_NumLock, + WM_Key_NumSlash, + WM_Key_NumStar, + WM_Key_NumMinus, + WM_Key_NumPlus, + WM_Key_NumPeriod, + WM_Key_Num0, + WM_Key_Num1, + WM_Key_Num2, + WM_Key_Num3, + WM_Key_Num4, + WM_Key_Num5, + WM_Key_Num6, + WM_Key_Num7, + WM_Key_Num8, + WM_Key_Num9, + WM_Key_LeftMouseButton, + WM_Key_MiddleMouseButton, + WM_Key_RightMouseButton, + WM_Key_COUNT, +} WM_Key;