module; #include #include #include export module VUI:PlatformWindow; import :Window; import :Ref; namespace VUI::Windowing { const char *CLASS_NAME = "VUI"; bool s_windowInit = false; struct Win32Window : Window { Win32Window(); ~Win32Window() override; void pullEvents() override; void close() override; void resize(uint32_t width, uint32_t height) override; void updateTitle(const std::string &title) override; static LRESULT CALLBACK WindowProc(HWND, UINT uMsg, WPARAM, LPARAM); protected: void createWindow() override; void handleEvent(HWND, UINT message, WPARAM, LPARAM); private: HWND m_Window{nullptr}; HINSTANCE m_Instance{nullptr}; friend Window; }; export Ref CreateWindowRef() { return Ref(new Win32Window()); } Win32Window::Win32Window() : Window() { m_Instance = GetModuleHandle(nullptr); } Win32Window::~Win32Window() { DestroyWindow(m_Window); } void Win32Window::pullEvents() { MSG msg; while (PeekMessage(&msg, m_Window, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } void Win32Window::close() { CloseWindow(m_Window); m_IsOpen = false; } void Win32Window::resize(uint32_t width, uint32_t height) { m_Specification.width = width; m_Specification.height = height; SetWindowPos(m_Window, nullptr, static_cast(m_WindowPosition.x), static_cast(m_WindowPosition.y), static_cast(m_Specification.width), static_cast(m_Specification.height), 0); } void Win32Window::updateTitle(const std::string &title) { m_Specification.title = title; SetWindowText(m_Window, title.c_str()); } LRESULT CALLBACK Win32Window::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (uMsg == WM_CREATE) { auto *pCreate = reinterpret_cast(lParam); SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast( static_cast(pCreate->lpCreateParams))); return TRUE; } auto impl = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); if (impl != nullptr) { impl->handleEvent(hwnd, uMsg, wParam, lParam); return DefWindowProcA(hwnd, uMsg, wParam, lParam); } return DefWindowProc(hwnd, uMsg, wParam, lParam); } void registerClass(HINSTANCE hInstance) { WNDCLASS wc = {}; wc.lpfnWndProc = Win32Window::WindowProc; wc.hInstance = hInstance; wc.lpszClassName = CLASS_NAME; RegisterClass(&wc); } void Win32Window::createWindow() { if (!s_windowInit) { registerClass(m_Instance); s_windowInit = true; } m_Window = CreateWindowEx(0, CLASS_NAME, m_Specification.title.c_str(), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, m_Instance, this); m_IsOpen = m_Window != nullptr; if (m_Window == nullptr) { throw std::runtime_error("Failed to create window."); } resize(m_Specification.width, m_Specification.height); ShowWindow(m_Window, SW_NORMAL); } void Win32Window::handleEvent(HWND, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_MOVE: { m_WindowPosition.x = LOWORD(lParam); m_WindowPosition.y = HIWORD(lParam); break; } case WM_SIZE: { m_Specification.width = LOWORD(lParam); m_Specification.height = HIWORD(lParam); break; } case WM_KEYDOWN: case WM_KEYUP: { uint32_t scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff)); if (scancode == 0) scancode = MapVirtualKeyW(static_cast(wParam), MAPVK_VK_TO_VSC); switch (scancode) { case 0x54: scancode = 0x137; break; case 0x146: scancode = 0x45; break; case 0x136: scancode = 0x36; break; default: break; } UpdateKey(scancode, message == WM_KEYDOWN); break; } case WM_MOUSEMOVE: { // TODO: Handle MouseMove Point rect(static_cast(GET_X_LPARAM(lParam)), static_cast(GET_Y_LPARAM(lParam))); break; } case WM_CLOSE: { this->m_IsOpen = false; break; } case WM_DESTROY: PostQuitMessage(0); default: break; } } } // namespace VUI::Windows