#include #include "platform_window/platform_window.h" #include #define WINDOW_HANDLE static_cast(window_handle_) bool mouse_tracking_ = FALSE; std::vector windows; platform_window* get_window_from_hwnd(const HWND hwnd) { for (const auto& window: windows) { if (window->get_window_handle() == hwnd) { return window; } } return nullptr; } LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { bool processed = false; // 窗口关闭事件 if (uMsg == WM_CLOSE) { std::erase_if(windows, [hwnd](platform_window* window) { if (window->get_window_handle() == hwnd) { window->close(); return true; } return false; }); processed = true; } // 窗口销毁事件 if (uMsg == WM_DESTROY) { PostQuitMessage(0); processed = true; } // 窗口移动事件 if (uMsg == WM_MOVE) { if (const auto window = get_window_from_hwnd(hwnd)) { window->on_move(LOWORD(lParam), HIWORD(lParam)); } processed = true; } // 窗口大小改变事件 if (uMsg == WM_SIZE) { if (const auto window = get_window_from_hwnd(hwnd)) { window->on_resize(LOWORD(lParam), HIWORD(lParam)); } processed = true; } // 鼠标移动事件 if (uMsg == WM_MOUSEMOVE) { if (const auto window = get_window_from_hwnd(hwnd)) { const int x = LOWORD(lParam); const int y = HIWORD(lParam); const Eigen::Vector2f pos(static_cast(x), static_cast(y)); window->handle_mouse_move(pos); } if (!mouse_tracking_) { TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_LEAVE; tme.hwndTrack = hwnd; tme.dwHoverTime = HOVER_DEFAULT; TrackMouseEvent(&tme); mouse_tracking_ = TRUE; } processed = true; } // 鼠标按键事件 const auto lmr_button = uMsg >= WM_LBUTTONDOWN && uMsg <= WM_MBUTTONDBLCLK; const auto x_button = uMsg >= WM_XBUTTONDOWN && uMsg <= WM_XBUTTONDBLCLK; if (lmr_button || x_button) { if (const auto window = get_window_from_hwnd(hwnd)) { const int x = LOWORD(lParam); const int y = HIWORD(lParam); const Eigen::Vector2f pos(static_cast(x), static_cast(y)); const auto action = platform_event_to_mouse_action(uMsg, wParam); const auto button = platform_event_to_mouse_button(uMsg, wParam); if (action == mouse_action::press) window->handle_mouse_button_down(pos, button); else if (action == mouse_action::release) window->handle_mouse_button_up(pos, button); else if (action == mouse_action::dbl_click) window->handle_mouse_dbl_click(pos, button); } processed = true; } // 鼠标滚轮事件 if (uMsg == WM_MOUSEWHEEL || uMsg == WM_MOUSEHWHEEL) { if (const auto window = get_window_from_hwnd(hwnd)) { const int x = LOWORD(lParam); const int y = HIWORD(lParam); const Eigen::Vector2f pos(static_cast(x), static_cast(y)); const auto delta = platform_event_to_wheel_event(uMsg, wParam, lParam); window->handle_mouse_wheel(pos, delta); } processed = true; } if (uMsg == WM_MOUSELEAVE) { mouse_tracking_ = FALSE; if (const auto window = get_window_from_hwnd(hwnd)) { window->handle_mouse_leave(); } processed = true; } if (processed) { return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); } platform_window::platform_window(int32_t in_width, int32_t in_height, const wchar_t* in_title) { WNDCLASS wc = {}; wc.lpfnWndProc = WindowProc; wc.hInstance = GetModuleHandle(nullptr); wc.lpszClassName = L"mirage_window_class"; wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); RegisterClass(&wc); RECT rect = { 0, 0, in_width, in_height }; AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); window_handle_ = (void*)CreateWindowW( L"mirage_window_class", in_title, WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, GetModuleHandleW(NULL), NULL ); if (!window_handle_) { std::cerr << "Failed to create window" << std::endl; return; } windows.push_back(this); } void platform_window::show() { ShowWindow(WINDOW_HANDLE, SW_SHOW); } void platform_window::hide() { ShowWindow(WINDOW_HANDLE, SW_HIDE); } void platform_window::close() { if (!window_handle_) { return; } on_close_delegate.broadcast(this); DestroyWindow(WINDOW_HANDLE); window_handle_ = nullptr; } void platform_window::maximize() { ShowWindow(WINDOW_HANDLE, SW_MAXIMIZE); } void platform_window::minimize() { ShowWindow(WINDOW_HANDLE, SW_MINIMIZE); } bool platform_window::is_visible() const { // 判断最小化和隐藏状态 return IsWindowVisible(WINDOW_HANDLE) && !IsIconic(WINDOW_HANDLE); } void platform_window::move(int x, int y) { RECT rect; GetWindowRect(WINDOW_HANDLE, &rect); MoveWindow(WINDOW_HANDLE, x, y, rect.right - rect.left, rect.bottom - rect.top, TRUE); on_move(x, y); } void platform_window::resize(int width, int height) { RECT rect; GetWindowRect(WINDOW_HANDLE, &rect); MoveWindow(WINDOW_HANDLE, rect.left, rect.top, width, height, TRUE); } Eigen::Vector2i platform_window::get_window_size() const { // 获取窗口大小, 包括边框和标题栏 RECT rect; if (GetWindowRect(WINDOW_HANDLE, &rect)) { int width = rect.right - rect.left; int height = rect.bottom - rect.top; return Eigen::Vector2i(width, height); } return Eigen::Vector2i(0, 0); } Eigen::Vector2i platform_window::get_window_frame_size() const { // 获取窗口大小, 不包括边框和标题栏 (客户区大小) RECT rect; if (GetClientRect(WINDOW_HANDLE, &rect)) { int width = rect.right - rect.left; int height = rect.bottom - rect.top; return Eigen::Vector2i(width, height); } return Eigen::Vector2i(0, 0); } float platform_window::get_window_dpi_scale() const { return 1.f; } Eigen::Vector2i platform_window::get_window_position() const { RECT rect; if (!GetWindowRect(WINDOW_HANDLE, &rect)) { return {}; } return { rect.left, rect.top }; } void* platform_window::get_window_handle() const { return window_handle_; } platform_window& platform_window::set_title(const wchar_t* title) { SetWindowText(WINDOW_HANDLE, title); return *this; } platform_window& platform_window::set_has_minimize_button(bool has_minimize_button) { auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE); if (has_minimize_button) { style |= WS_MINIMIZEBOX; } else { style &= ~WS_MINIMIZEBOX; } SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style); return *this; } platform_window& platform_window::set_has_maximize_button(bool has_maximize_button) { auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE); if (has_maximize_button) { style |= WS_MAXIMIZEBOX; } else { style &= ~WS_MAXIMIZEBOX; } SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style); return *this; } platform_window& platform_window::set_has_close_button(bool has_close_button) { auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE); if (has_close_button) { style |= WS_SYSMENU; } else { style &= ~WS_SYSMENU; } SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style); return *this; } platform_window& platform_window::set_has_border(bool has_border) { auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE); if (has_border) { style |= WS_BORDER; } else { style &= ~WS_BORDER; } SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style); return *this; } platform_window& platform_window::set_has_caption(bool has_caption) { auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE); if (has_caption) { style |= WS_CAPTION; } else { style &= ~WS_CAPTION; } SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style); return *this; } platform_window& platform_window::set_has_resizable_border(bool has_resizable_border) { auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE); if (has_resizable_border) { style |= WS_THICKFRAME; } else { style &= ~WS_THICKFRAME; } SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style); return *this; } platform_window& platform_window::set_topmost(bool is_topmost) { auto style = GetWindowLong(WINDOW_HANDLE, GWL_EXSTYLE); if (is_topmost) { style |= WS_EX_TOPMOST; } else { style &= ~WS_EX_TOPMOST; } SetWindowLong(WINDOW_HANDLE, GWL_EXSTYLE, style); return *this; } bool platform_window::poll_events() { MSG msg; bool has_messages = false; while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { has_messages = true; TranslateMessage(&msg); DispatchMessage(&msg); } return has_messages; } const std::vector& platform_window::get_windows() { return windows; }