1#ifdef MAYAFLUX_PLATFORM_WINDOWS
4#include "KeyMapping.hpp"
16static constexpr const wchar_t* k_class_name =
L"MayaFluxWindow";
18static void register_window_class(HINSTANCE hinstance)
20 static std::once_flag s_flag;
21 std::call_once(s_flag, [&]() {
23 wc.cbSize =
sizeof(wc);
24 wc.style = CS_HREDRAW | CS_VREDRAW;
25 wc.lpfnWndProc = Win32Window::wnd_proc;
26 wc.hInstance = hinstance;
27 wc.hCursor = LoadCursor(
nullptr, IDC_ARROW);
28 wc.lpszClassName = k_class_name;
29 RegisterClassExW(&wc);
37Win32Window::Win32Window(
const WindowCreateInfo& create_info,
38 const GlobalGraphicsConfig& graphics_config)
39 : m_create_info(create_info)
40 , m_key_repeat_config(graphics_config.key_repeat_config)
42 m_hinstance = GetModuleHandleW(
nullptr);
44 m_ui_thread = std::thread([
this]() { ui_thread_main(); });
46 m_hwnd_ready.wait(
false);
49Win32Window::~Win32Window()
58void Win32Window::ui_thread_main()
60 register_window_class(m_hinstance);
62 auto wtitle = std::wstring(m_create_info.title.begin(), m_create_info.title.end());
64 m_hwnd = CreateWindowExW(
69 CW_USEDEFAULT, CW_USEDEFAULT,
70 static_cast<int>(m_create_info.width),
71 static_cast<int>(m_create_info.height),
72 nullptr,
nullptr, m_hinstance,
nullptr);
74 SetWindowLongPtrW(m_hwnd, GWLP_USERDATA,
reinterpret_cast<LONG_PTR
>(
this));
76 m_hwnd_ready.store(
true);
77 m_hwnd_ready.notify_all();
80 while (GetMessageW(&msg,
nullptr, 0, 0)) {
81 TranslateMessage(&msg);
82 DispatchMessageW(&msg);
90LRESULT
CALLBACK Win32Window::wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
92 auto* self =
reinterpret_cast<Win32Window*
>(GetWindowLongPtrW(hwnd, GWLP_USERDATA));
95 return DefWindowProcW(hwnd, msg, wp, lp);
99 self->m_should_close.store(
true);
102 ev.type = WindowEventType::WINDOW_CLOSED;
104 self->push_event(ev);
114 auto w =
static_cast<uint32_t
>(LOWORD(lp));
115 auto h =
static_cast<uint32_t
>(HIWORD(lp));
116 self->m_state.current_width =
static_cast<int>(w);
117 self->m_state.current_height =
static_cast<int>(
h);
119 ev.type = WindowEventType::WINDOW_RESIZED;
121 ev.data = WindowEvent::ResizeData { .width = w, .height =
h };
122 self->push_event(ev);
127 self->m_state.is_focused =
true;
129 ev.type = WindowEventType::WINDOW_FOCUS_GAINED;
131 self->push_event(ev);
136 self->m_state.is_focused =
false;
138 ev.type = WindowEventType::WINDOW_FOCUS_LOST;
140 self->push_event(ev);
145 case WM_SYSKEYDOWN: {
149 const uint32_t scancode =
static_cast<uint32_t
>(HIWORD(lp) & 0x1FF);
150 IO::Keys key = from_win32_scancode(scancode);
151 if (key == IO::Keys::Unknown)
152 key = from_win32_key(wp);
154 const WindowEvent::KeyData kd {
155 .key =
static_cast<int16_t
>(key),
156 .scancode =
static_cast<int32_t
>(scancode),
160 self->m_held_keys_ui[kd.key] = kd;
161 self->m_keys_dirty.store(
true, std::memory_order_release);
163 ev.type = WindowEventType::KEY_PRESSED;
166 self->push_event(ev);
172 const uint32_t scancode =
static_cast<uint32_t
>(HIWORD(lp) & 0x1FF);
173 IO::Keys key = from_win32_scancode(scancode);
174 if (key == IO::Keys::Unknown)
175 key = from_win32_key(wp);
177 const WindowEvent::KeyData kd {
178 .key =
static_cast<int16_t
>(key),
179 .scancode =
static_cast<int32_t
>(scancode),
183 self->m_held_keys_ui.erase(kd.key);
184 self->m_keys_dirty.store(
true, std::memory_order_release);
186 ev.type = WindowEventType::KEY_RELEASED;
189 self->push_event(ev);
195 ev.type = WindowEventType::MOUSE_MOTION;
197 ev.data = WindowEvent::MousePosData {
198 .x =
static_cast<double>(GET_X_LPARAM(lp)),
199 .y =
static_cast<double>(GET_Y_LPARAM(lp))
201 self->push_event(ev);
207 case WM_MBUTTONDOWN: {
208 IO::MouseButtons btn = (msg == WM_LBUTTONDOWN) ? IO::MouseButtons::Left
212 ev.type = WindowEventType::MOUSE_BUTTON_PRESSED;
214 ev.data = WindowEvent::MouseButtonData {
215 .button =
static_cast<int8_t
>(btn),
218 self->push_event(ev);
225 IO::MouseButtons btn = (msg == WM_LBUTTONUP) ? IO::MouseButtons::Left
229 ev.type = WindowEventType::MOUSE_BUTTON_RELEASED;
231 ev.data = WindowEvent::MouseButtonData {
232 .button =
static_cast<int8_t
>(btn),
235 self->push_event(ev);
239 case WM_MOUSEWHEEL: {
240 double delta =
static_cast<double>(GET_WHEEL_DELTA_WPARAM(wp)) / WHEEL_DELTA;
242 ev.type = WindowEventType::MOUSE_SCROLLED;
244 ev.data = WindowEvent::ScrollData { .x_offset = 0.0, .y_offset = delta };
245 self->push_event(ev);
253 return DefWindowProcW(hwnd, msg, wp, lp);
260void Win32Window::push_event(WindowEvent ev)
262 (void)m_event_queue.push(ev);
269void Win32Window::poll()
271 if (m_keys_dirty.exchange(
false, std::memory_order_acq_rel)) {
272 const bool was_empty = m_held_keys.empty();
273 m_held_keys = m_held_keys_ui;
274 if (was_empty && !m_held_keys.empty())
275 m_repeat_next_tick = GetTickCount64() + m_key_repeat_config.initial_delay_ms;
278 while (
auto ev = m_event_queue.pop()) {
279 m_event_source.signal(*ev);
280 if (m_event_callback)
281 m_event_callback(*ev);
284 const ULONGLONG now = GetTickCount64();
285 if (!m_held_keys.empty() && now >= m_repeat_next_tick) {
286 m_repeat_next_tick = now + m_key_repeat_config.interval_ms;
287 for (
const auto& [k, kd] : m_held_keys) {
289 rev.type = WindowEventType::KEY_REPEAT;
292 m_event_source.signal(rev);
293 if (m_event_callback)
294 m_event_callback(rev);
303void Win32Window::show()
306 ShowWindow(m_hwnd, SW_SHOW);
309void Win32Window::hide()
312 ShowWindow(m_hwnd, SW_HIDE);
315void Win32Window::destroy()
318 PostMessageW(m_hwnd, WM_CLOSE, 0, 0);
321 if (m_ui_thread.joinable())
325bool Win32Window::should_close()
const
327 return m_should_close.load();
330void Win32Window::set_event_callback(WindowEventCallback callback)
332 m_event_callback = std::move(callback);
335void Win32Window::set_title(
const std::string& title)
337 m_create_info.title = title;
339 auto wt = std::wstring(title.begin(), title.end());
340 SetWindowTextW(m_hwnd, wt.c_str());
344void Win32Window::set_size(uint32_t
width, uint32_t height)
346 m_create_info.width =
width;
347 m_create_info.height = height;
349 SetWindowPos(m_hwnd,
nullptr, 0, 0,
350 static_cast<int>(
width),
static_cast<int>(height),
351 SWP_NOMOVE | SWP_NOZORDER);
354void Win32Window::set_position(uint32_t x, uint32_t y)
357 SetWindowPos(m_hwnd,
nullptr,
358 static_cast<int>(x),
static_cast<int>(y),
359 0, 0, SWP_NOSIZE | SWP_NOZORDER);
362void Win32Window::set_color(
const std::array<float, 4>& color)
364 m_create_info.clear_color = color;
371void Win32Window::register_rendering_buffer(std::shared_ptr<Buffers::VKBuffer> buffer)
373 std::lock_guard lock(m_render_tracking_mutex);
374 m_rendering_buffers.push_back(buffer);
377void Win32Window::unregister_rendering_buffer(std::shared_ptr<Buffers::VKBuffer> buffer)
379 std::lock_guard lock(m_render_tracking_mutex);
380 std::erase_if(m_rendering_buffers,
381 [&buffer](
const auto& wp) {
383 return !sp || sp == buffer;
387void Win32Window::track_frame_command(uint64_t cmd_id)
389 m_frame_commands.push_back(cmd_id);
392const std::vector<uint64_t>& Win32Window::get_frame_commands()
const
394 return m_frame_commands;
397void Win32Window::clear_frame_commands()
399 m_frame_commands.clear();
402std::vector<std::shared_ptr<Buffers::VKBuffer>> Win32Window::get_rendering_buffers()
const
404 std::lock_guard lock(m_render_tracking_mutex);
405 std::vector<std::shared_ptr<Buffers::VKBuffer>> out;
406 out.reserve(m_rendering_buffers.size());
407 for (
auto& wp : m_rendering_buffers) {
408 if (
auto sp = wp.lock())
MouseButtons
Enumeration for mouse buttons.
@ IO
Networking, file handling, streaming.
@ CALLBACK
Use callback for custom transition.