diff --git a/modules/assets/shader.cppm b/modules/assets/shader.cppm index 0421b36..e2e9700 100644 --- a/modules/assets/shader.cppm +++ b/modules/assets/shader.cppm @@ -88,8 +88,7 @@ constexpr auto total_metadata_size = // + sizeof(BlobMetadata::compressed_size) // + sizeof(BlobMetadata::uncompressed_size); -ShaderAsset::ShaderAsset(const std::filesystem::path &path) - : m_stream(path, std::ios::beg | std::ios::binary) +ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path, std::ios::binary) { ensure(m_stream.is_open(), "Failed to open shader asset at: {}", path.string()); const auto read = [this](auto &field) { diff --git a/modules/logger/logger.cppm b/modules/logger/logger.cppm index 826b0b4..a5b106a 100644 --- a/modules/logger/logger.cppm +++ b/modules/logger/logger.cppm @@ -70,6 +70,7 @@ struct [[maybe_unused]] print case warn : return "\033[1;33m| wrn |\033[0m"; case error : return "\033[1;31m| err |\033[0m"; case critical: return "\033[1;41m| crt |\033[0m"; + case test: /* testing framework's logs will never have location */ case off: return "off"; } // clang-format on diff --git a/modules/sandbox/sandbox.cpp b/modules/sandbox/sandbox.cpp index c99398c..354a0c4 100644 --- a/modules/sandbox/sandbox.cpp +++ b/modules/sandbox/sandbox.cpp @@ -6,6 +6,8 @@ import renderer.frontend; import surface.system; import surface.events; import surface.requests; +import ecs.entity; +import input.codes; import ecs.registry; import memory.scope; import memory.reference; @@ -83,7 +85,6 @@ try debug_callback_info, } }; - registry.add_ auto should_close = false; const auto visitor = overloads { diff --git a/modules/surface/components.cppm b/modules/surface/components.cppm index b290fac..fbcb69b 100644 --- a/modules/surface/components.cppm +++ b/modules/surface/components.cppm @@ -2,6 +2,8 @@ module; #if defined(LIGHT_PLATFORM_LINUX) struct wl_display; struct wl_surface; +struct xdg_surface; +struct xdg_toplevel; #else defined(LIGHT_PLATFORM_WINDOWS) #include #endif @@ -46,6 +48,10 @@ public: wl_display *display; wl_surface *surface; + + xdg_surface *shell_surface; + + xdg_toplevel *shell_toplevel; }; #elif defined(LIGHT_PLATFORM_WINDOWS) struct NativeData @@ -62,7 +68,7 @@ public: // TODO(Light): add `screen_mode` flag (windowed/full_screen/windowed_full_screen) struct CreateInfo { - std::string_view title; + std::string title; math::vec2_i32 position; @@ -73,7 +79,7 @@ public: bool visible; }; - [[nodiscard]] auto get_title() const -> std::string_view + [[nodiscard]] auto get_title() const -> std::string // yes copy the title, whatever... { return m_title; } diff --git a/modules/surface/system.cppm b/modules/surface/system.cppm index cc7cf47..244732a 100644 --- a/modules/surface/system.cppm +++ b/modules/surface/system.cppm @@ -169,8 +169,6 @@ private: void modify_visibility(SurfaceComponent &surface, const ModifyVisibilityRequest &request); - void set_visibility(ecs::EntityId surface_entity, bool visible); - memory::Ref m_registry; app::TickResult m_last_tick_result {}; @@ -207,8 +205,17 @@ private: module :private; namespace lt::surface { + #if defined(LIGHT_PLATFORM_LINUX) +template +struct overloads: Ts... +{ + using Ts::operator()...; +}; + +void ensure_component_sanity(const SurfaceComponent &component); + void handle_shell_ping(void *data, xdg_wm_base *shell, u32 serial) { ignore = data; @@ -222,6 +229,7 @@ void handle_shell_surface_configure(void *data, xdg_surface *shell_surface, u32 { ignore = data; + log::test("Surface configure: {}", (i32)serial); xdg_surface_ack_configure(shell_surface, serial); } const auto shell_surface_listener = xdg_surface_listener { @@ -237,7 +245,9 @@ void handle_toplevel_configure( ) { // TODO(Light): handle resizing + log::test("Toplevel configure: {}x{}", (i32)width, (i32)height); } + void handle_toplevel_close(void *data, xdg_toplevel *toplevel) { // TODO(Light): handle quitting @@ -325,6 +335,7 @@ void wayland_pointer_leave_listener( u32 state ) { + log::debug("Pointer button"); } /* static */ void System::wayland_pointer_axis_listener( @@ -335,6 +346,7 @@ void wayland_pointer_leave_listener( wl_fixed_t value ) { + log::debug("Pointer axis listener"); } /* static */ void System::wayland_pointer_axis_source_listener( @@ -343,6 +355,7 @@ void wayland_pointer_leave_listener( u32 axis_source ) { + log::debug("Pointer axis source listener"); } /* static */ void System::wayland_pointer_axis_stop_listener( @@ -352,6 +365,7 @@ void wayland_pointer_leave_listener( u32 axis_source ) { + log::debug("Pointer axis stop listener"); } /* static */ void System::wayland_pointer_axis_discrete_listener( @@ -361,6 +375,7 @@ void wayland_pointer_leave_listener( i32 discrete ) { + log::debug("Pointer axis discrete listener"); } /* static */ void System::wayland_pointer_frame_listener(void *data, wl_pointer *pointer) @@ -451,7 +466,8 @@ System::System(memory::Ref registry) } ) { - // NOLINTNEXTLINE + ensure(m_registry, "Failed to construct surface::System: null ecs::Registry"); + m_wl_display = wl_display_connect({}); ensure(m_wl_display, "Failed to connect to Wayland display"); @@ -477,6 +493,29 @@ System::~System() { return; } + + try + { + /** @todo(Light): make registry.remove not invalidate iterators */ + auto entities_to_remove = std::vector {}; + for (auto &[entity, surface] : m_registry->view()) + { + entities_to_remove.emplace_back(entity); + } + + for (auto entity : entities_to_remove) + { + m_registry->remove(entity); + } + + m_registry->disconnect_on_construct(); + m_registry->disconnect_on_destruct(); + } + catch (const std::exception &exp) + { + log::error("Uncaught exception in surface::~System:"); + log::error("\twhat: {}", exp.what()); + } } void System::on_register() @@ -490,15 +529,18 @@ void System::on_unregister() } void System::create_surface_component(ecs::EntityId entity, SurfaceComponent::CreateInfo info) +try { auto &component = m_registry->add(entity, info); + ensure_component_sanity(component); + auto &surface = m_registry->get(entity); const auto &resolution = surface.get_resolution(); const auto &position = surface.get_position(); auto *wayland_surface = (wl_surface *)nullptr; - auto *shell_surface = (xdg_surface *)nullptr; auto *shell_toplevel = (xdg_toplevel *)nullptr; + auto *shell_surface = (xdg_surface *)nullptr; wayland_surface = wl_compositor_create_surface(m_wl_compositor); ensure(wayland_surface, "Failed to create Wayland surface"); @@ -511,7 +553,7 @@ void System::create_surface_component(ecs::EntityId entity, SurfaceComponent::Cr ensure(shell_toplevel, "Failed to get XDG-shell toplevel"); xdg_toplevel_add_listener(shell_toplevel, &toplevel_listener, {}); - xdg_toplevel_set_title(shell_toplevel, "Wayland Vulkan Example"); + xdg_toplevel_set_title(shell_toplevel, info.title.c_str()); xdg_toplevel_set_app_id(shell_toplevel, "Wayland Vulkan Example"); wl_surface_commit(wayland_surface); @@ -520,11 +562,136 @@ void System::create_surface_component(ecs::EntityId entity, SurfaceComponent::Cr surface.m_native_data.surface = wayland_surface; surface.m_native_data.display = m_wl_display; + surface.m_native_data.shell_surface = shell_surface; + surface.m_native_data.shell_toplevel = shell_toplevel; +} +catch (const std::exception &exp) +{ + log::error("Exception thrown when on_constructing surface component"); + log::error("\tentity: {}", u32 { entity }); + log::error("\twhat: {}", exp.what()); + + m_registry->remove(entity); } void System::tick(app::TickInfo tick) { + ignore = tick; + wl_display_roundtrip(m_wl_display); + + for (auto &[id, surface] : m_registry->view()) + { + handle_requests(surface); + handle_events(surface); + } + + const auto now = std::chrono::steady_clock::now(); + m_last_tick_result = app::TickResult { + .info = tick, + .duration = now - tick.start_time, + .end_time = now, + }; +} + +void System::handle_events(SurfaceComponent &surface) +{ + // WIP(Light) + ignore = surface; + + auto &queue = surface.m_event_queue; + queue.clear(); + + const auto roundtrip = wl_display_roundtrip(m_wl_display); + ensure(roundtrip != -1, "Wayland roundtrip error"); // WIP(Light) + + + if (roundtrip != 0) + { + log::debug("Roundtrip: {}", (int)roundtrip); + } +} + +void System::handle_requests(SurfaceComponent &surface) +{ + const auto visitor = overloads { + [&](const ModifyTitleRequest &request) { modify_title(surface, request); }, + [&](const ModifyResolutionRequest &request) { modify_resolution(surface, request); }, + [&](const ModifyPositionRequest &request) { modify_position(surface, request); }, + [&](const ModifyVisibilityRequest &request) { modify_visibility(surface, request); } + }; + + for (const auto &request : surface.peek_requests()) + { + std::visit(visitor, request); + } + + wl_display_roundtrip(m_wl_display); + + surface.m_requests.clear(); +} + +void System::modify_title(SurfaceComponent &surface, const ModifyTitleRequest &request) +{ + auto *toplevel = surface.m_native_data.shell_toplevel; + ensure(toplevel, "Failed to modify surface title: null shell toplevel"); + ensure(!request.title.empty(), "Failed to modify surface title: null titlle"); + + xdg_toplevel_set_title(toplevel, request.title.c_str()); + wl_surface_commit(surface.m_native_data.surface); + surface.m_title = request.title; +} + +void System::modify_resolution(SurfaceComponent &surface, const ModifyResolutionRequest &request) +{ + auto *toplevel = surface.m_native_data.shell_toplevel; + const auto [width, height] = request.resolution; + + ensure(width, "Failed to modify resolution: invalid width: {}", width); + ensure(height, "Failed to modify resolution: invalid height: {}", height); + + log::test("Modifying res: {}x{}", (u32)width, (u32)height); + + xdg_toplevel_set_min_size(toplevel, width, height); + xdg_toplevel_set_max_size(toplevel, width, height); +} + +void System::modify_position(SurfaceComponent &surface, const ModifyPositionRequest &request) +{ +} + +void System::modify_visibility(SurfaceComponent &surface, const ModifyVisibilityRequest &request) +{ +} + +void ensure_component_sanity(const SurfaceComponent &component) +{ + const auto [width, height] = component.get_resolution(); + + ensure(width != 0u, "Received bad values for surface component: width({}) == 0", width); + + ensure(height != 0u, "Received bad values for surface component: height({}) == 0", height); + + ensure( + width < SurfaceComponent::max_dimension, + "Received bad values for surface component: width({}) > max_dimension({})", + width, + SurfaceComponent::max_dimension + ); + + ensure( + height < SurfaceComponent::max_dimension, + "Received bad values for surface component: height({}) > max_dimension({})", + height, + SurfaceComponent::max_dimension + ); + + ensure( + component.get_title().size() < SurfaceComponent::max_title_length, + "Received bad values for surface component: title.size({}) > max_title_length({})", + component.get_title().size(), + SurfaceComponent::max_title_length + ); } #endif @@ -575,7 +742,7 @@ System::~System() try { - // TODO(Light): make registry.remove not invalidate iterators + /** @todo(Light): make registry.remove not invalidate iterators */ auto entities_to_remove = std::vector {}; for (auto &[entity, surface] : m_registry->view()) { @@ -731,9 +898,7 @@ void System::handle_requests(SurfaceComponent &surface) [&](const ModifyTitleRequest &request) { modify_title(surface, request); }, [&](const ModifyResolutionRequest &request) { modify_resolution(surface, request); }, [&](const ModifyPositionRequest &request) { modify_position(surface, request); }, - [&](const ModifyVisibilityRequest &request) { - modify_visibility(surface, request); - } + [&](const ModifyVisibilityRequest &request) { modify_visibility(surface, request); } }; for (const auto &request : surface.peek_requests()) diff --git a/modules/surface/system.test.cpp b/modules/surface/system.test.cpp index be2bd7e..1430c8b 100644 --- a/modules/surface/system.test.cpp +++ b/modules/surface/system.test.cpp @@ -1,3 +1,5 @@ +/** @todo(Light): test pointer-invalidation of ecs using this system-> (?) */ + #if defined(LIGHT_PLATFORM_LINUX) #elif defined(LIGHT_PLATFORM_WINDOWS) #include @@ -55,8 +57,14 @@ public: return m_registry; } + + [[nodiscard]] auto system() -> lt::memory::Ref + { + return m_system; + } + auto create_component( - SurfaceComponent::CreateInfo info = SurfaceComponent::CreateInfo { + const SurfaceComponent::CreateInfo &info = SurfaceComponent::CreateInfo { .title = title, .position = { position_x, position_y }, .resolution = { width, height }, @@ -66,7 +74,7 @@ public: ) -> std::optional { auto entity = m_registry->create_entity(); - m_system.create_surface_component(entity, info); + m_system->create_surface_component(entity, info); return &m_registry->get(entity); } @@ -88,13 +96,13 @@ public: private: lt::memory::Ref m_registry = lt::memory::create_ref(); - System m_system { m_registry }; + lt::memory::Ref m_system = lt::memory::create_ref(m_registry); }; Suite raii = "raii"_suite = [] { Case { "happy paths" } = [] { auto fixture = Fixture {}; - auto system = System { fixture.registry() }; + auto system = fixture.system(); }; Case { "unhappy paths" } = [] { @@ -103,16 +111,17 @@ Suite raii = "raii"_suite = [] { Case { "many" } = [] { auto fixture = Fixture {}; + for (auto idx : std::views::iota(0, 250)) { ignore = idx; - ignore = System { fixture.registry() }; + ignore = fixture.system(); } }; Case { "post construct has correct state" } = [] { auto fixture = Fixture {}; - auto system = System { fixture.registry() }; + auto system = fixture.system(); expect_eq(fixture.registry()->view().get_size(), 0); }; @@ -131,18 +140,18 @@ Suite raii = "raii"_suite = [] { Suite system_events = "system_events"_suite = [] { Case { "on_register won't throw" } = [] { auto fixture = Fixture {}; - auto system = System { fixture.registry() }; + auto system = fixture.system(); - system.on_register(); + system->on_register(); expect_eq(fixture.registry()->view().get_size(), 0); }; Case { "on_unregister won't throw" } = [] { auto fixture = Fixture {}; - auto system = System { fixture.registry() }; + auto system = fixture.system(); - system.on_register(); - system.on_unregister(); + system->on_register(); + system->on_unregister(); expect_eq(fixture.registry()->view().get_size(), 0); }; }; @@ -150,25 +159,25 @@ Suite system_events = "system_events"_suite = [] { Suite registry_events = "registry_events"_suite = [] { Case { "on_construct initializes component" } = [] { auto fixture = Fixture {}; - auto system = System { fixture.registry() }; + auto system = fixture.system(); - system.tick({}); - system.tick({}); + system->tick({}); + system->tick({}); const auto &component = fixture.create_component(); - system.tick({}); - system.tick({}); - system.tick({}); + system->tick({}); + system->tick({}); + system->tick({}); expect_eq(fixture.registry()->view().get_size(), 1); - system.tick({}); - system.tick({}); - system.tick({}); + system->tick({}); + system->tick({}); + system->tick({}); fixture.check_values(*component); }; Case { "unhappy on_construct throws" } = [] { auto fixture = Fixture {}; - auto system = System { fixture.registry() }; + auto system = fixture.system(); expect_throw([&] { fixture.create_component({ .resolution = { width, 0 } }); }); @@ -195,7 +204,7 @@ Suite registry_events = "registry_events"_suite = [] { Case { "unhappy on_construct removes component" } = [] { auto fixture = Fixture {}; - auto system = System { fixture.registry() }; + auto system = fixture.system(); expect_throw([&] { fixture.create_component({ .resolution = { width, 0 } }); }); expect_eq(fixture.registry()->view().get_size(), 0); @@ -217,24 +226,24 @@ Suite registry_events = "registry_events"_suite = [] { Suite tick = "ticking"_suite = [] { Case { "on empty registry won't throw" } = [] { auto fixture = Fixture {}; - System { fixture.registry() }.tick(tick_info()); + fixture.system()->tick(tick_info()); }; Case { "on non-empty registry won't throw" } = [] { auto fixture = Fixture {}; - auto system = System { fixture.registry() }; + auto system = fixture.system(); fixture.create_component(); - system.tick(tick_info()); + system->tick(tick_info()); }; Case { "clears previous tick's events" } = [] { auto fixture = Fixture {}; - auto system = System { fixture.registry() }; + auto system = fixture.system(); auto &surface = **fixture.create_component(); // flush window-creation events - system.tick(tick_info()); + system->tick(tick_info()); expect_eq(surface.peek_events().size(), 0); surface.push_event(lt::surface::MovedEvent({}, {})); @@ -243,13 +252,13 @@ Suite tick = "ticking"_suite = [] { surface.push_event(lt::surface::KeyPressedEvent({})); expect_eq(surface.peek_events().size(), 2); - system.tick(tick_info()); + system->tick(tick_info()); expect_eq(surface.peek_events().size(), 0); }; Case { "clears requests" } = [] { auto fixture = Fixture {}; - auto system = System { fixture.registry() }; + auto system = fixture.system(); auto &surface = **fixture.create_component(); const auto new_title = std::string { title } + std::string { "_" }; @@ -260,7 +269,7 @@ Suite tick = "ticking"_suite = [] { surface.push_request(lt::surface::ModifyVisibilityRequest(true)); expect_eq(surface.peek_requests().size(), 1); - system.tick(tick_info()); + system->tick(tick_info()); expect_eq(surface.peek_requests().size(), 0); surface.push_request(lt::surface::ModifyTitleRequest(new_title)); @@ -275,7 +284,7 @@ Suite tick = "ticking"_suite = [] { surface.push_request(lt::surface::ModifyVisibilityRequest(false)); expect_eq(surface.peek_requests().size(), 1 + 2 + 3); - system.tick(tick_info()); + system->tick(tick_info()); expect_eq(surface.peek_requests().size(), 0); }; }; @@ -287,14 +296,14 @@ Suite requests = "requests"_suite = [] { using ::lt::surface::ModifyVisibilityRequest; auto fixture = Fixture {}; - auto system = System { fixture.registry() }; + auto system = fixture.system(); auto &surface = **fixture.create_component(); Case { "ModifyTitleRequest" } = [&] { const auto new_title = std::string { title } + std::string { "_" }; surface.push_request({ ModifyTitleRequest { new_title } }); - system.tick({}); + system->tick({}); expect_eq(surface.get_title(), new_title); }; @@ -302,7 +311,7 @@ Suite requests = "requests"_suite = [] { constexpr auto new_resolution = lt::math::vec2_u32 { width + 50, height + 50 }; surface.push_request({ ModifyResolutionRequest { new_resolution } }); - system.tick({}); + system->tick({}); expect_eq(surface.get_resolution(), new_resolution); }; @@ -310,17 +319,17 @@ Suite requests = "requests"_suite = [] { constexpr auto new_position = lt::math::vec2_i32 { position_x + 50, position_y + 50 }; surface.push_request({ ModifyPositionRequest { new_position } }); - system.tick({}); + system->tick({}); expect_eq(surface.get_position(), new_position); }; Case { "ModifyVisibilityRequest" } = [&] { surface.push_request({ ModifyVisibilityRequest { .visible = false } }); - system.tick({}); + system->tick({}); expect_eq(surface.is_visible(), false); surface.push_request({ ModifyVisibilityRequest { .visible = true } }); - system.tick({}); + system->tick({}); expect_eq(surface.is_visible(), true); }; }; @@ -329,12 +338,12 @@ Suite requests = "requests"_suite = [] { Suite windows_window_proc = "windows_window_proc"_suite = [] { auto fixture = Fixture {}; - auto system = System { fixture.registry() }; + auto system = fixture.system(); auto &surface = **fixture.create_component(); auto [hwnd] = surface.get_native_data(); const auto &events = surface.peek_events(); - system.tick({}); + system->tick({}); Case { "WM_SETFOCUS" } = [&] { expect_eq(events.size(), 0u); ::SendMessage(hwnd, WM_SETFOCUS, {}, {}); @@ -344,7 +353,7 @@ Suite windows_window_proc = "windows_window_proc"_suite = [] { ::lt::log::trace("{}", event.to_string()); // make sure it's not optimized away? }; - system.tick({}); + system->tick({}); Case { "WM_KILLFOCUS" } = [&] { expect_eq(events.size(), 0u); ::SendMessage(hwnd, WM_KILLFOCUS, {}, {}); @@ -354,7 +363,7 @@ Suite windows_window_proc = "windows_window_proc"_suite = [] { ::lt::log::trace("{}", event.to_string()); // make sure it's not optimized away? }; - system.tick({}); + system->tick({}); Case { "WM_SIZE" } = [&] { const auto new_width = width + 50; const auto new_height = height + 60; @@ -371,7 +380,7 @@ Suite windows_window_proc = "windows_window_proc"_suite = [] { expect_eq(surface.get_resolution().y, new_height); }; - system.tick({}); + system->tick({}); Case { "WM_MOVE" } = [&] { const auto new_x = position_x + 120; const auto new_y = position_y + 150; @@ -388,7 +397,7 @@ Suite windows_window_proc = "windows_window_proc"_suite = [] { expect_eq(surface.get_position().y, new_y); }; - system.tick({}); + system->tick({}); Case { "WM_MOUSEWHEEL" } = [&] { expect_eq(events.size(), 0u); ::SendMessage(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(0, WHEEL_DELTA), {}); @@ -405,7 +414,7 @@ Suite windows_window_proc = "windows_window_proc"_suite = [] { expect_eq(std::get(events[3]).get_key(), Key::wheel_down); }; - system.tick({}); + system->tick({}); Case { "WM_LBUTTONDOWN" } = [&] { expect_eq(events.size(), 0u); ::SendMessage(hwnd, WM_LBUTTONDOWN, {}, {}); @@ -415,7 +424,7 @@ Suite windows_window_proc = "windows_window_proc"_suite = [] { expect_eq(std::get(events[0]).get_key(), Key::left_button); }; - system.tick({}); + system->tick({}); Case { "WM_LBUTTONUP" } = [&] { expect_eq(events.size(), 0u); ::SendMessage(hwnd, WM_LBUTTONUP, {}, {}); @@ -425,7 +434,7 @@ Suite windows_window_proc = "windows_window_proc"_suite = [] { expect_eq(std::get(events[0]).get_key(), Key::left_button); }; - system.tick({}); + system->tick({}); Case { "WM_RBUTTONDOWN" } = [&] { expect_eq(events.size(), 0u); ::SendMessage(hwnd, WM_RBUTTONDOWN, {}, {}); @@ -435,7 +444,7 @@ Suite windows_window_proc = "windows_window_proc"_suite = [] { expect_eq(std::get(events[0]).get_key(), Key::right_button); }; - system.tick({}); + system->tick({}); Case { "WM_RBUTTONUP" } = [&] { expect_eq(events.size(), 0u); ::SendMessage(hwnd, WM_RBUTTONUP, {}, {}); @@ -445,7 +454,7 @@ Suite windows_window_proc = "windows_window_proc"_suite = [] { expect_eq(std::get(events[0]).get_key(), Key::right_button); }; - system.tick({}); + system->tick({}); Case { "WM_MBUTTONDOWN" } = [&] { expect_eq(events.size(), 0u); ::SendMessage(hwnd, WM_MBUTTONDOWN, {}, {}); @@ -455,7 +464,7 @@ Suite windows_window_proc = "windows_window_proc"_suite = [] { expect_eq(std::get(events[0]).get_key(), Key::middle_button); }; - system.tick({}); + system->tick({}); Case { "WM_MBUTTONUP" } = [&] { expect_eq(events.size(), 0u); ::SendMessage(hwnd, WM_MBUTTONUP, {}, {}); @@ -466,7 +475,7 @@ Suite windows_window_proc = "windows_window_proc"_suite = [] { }; - system.tick({}); + system->tick({}); Case { "WM_XBUTTONDOWN" } = [&] { expect_eq(events.size(), 0u); ::SendMessage(hwnd, WM_XBUTTONDOWN, MAKEWPARAM(0, XBUTTON1), {}); @@ -478,7 +487,7 @@ Suite windows_window_proc = "windows_window_proc"_suite = [] { expect_eq(std::get(events[1]).get_key(), Key::x_button_2); }; - system.tick({}); + system->tick({}); Case { "WM_XBUTTONUP" } = [&] { expect_eq(events.size(), 0u); ::SendMessage(hwnd, WM_XBUTTONUP, MAKEWPARAM(0, XBUTTON1), {}); @@ -490,7 +499,7 @@ Suite windows_window_proc = "windows_window_proc"_suite = [] { expect_eq(std::get(events[1]).get_key(), Key::x_button_2); }; - system.tick({}); + system->tick({}); Case { "WM_KEYDOWN" } = [&] { expect_eq(events.size(), 0u); ::SendMessage(hwnd, WM_KEYDOWN, System::to_native_key(Key::escape), {}); @@ -499,7 +508,7 @@ Suite windows_window_proc = "windows_window_proc"_suite = [] { expect_eq(std::get(events[0]).get_key(), Key::escape); }; - system.tick({}); + system->tick({}); Case { "WM_KEYUP" } = [&] { expect_eq(events.size(), 0u); ::SendMessage(hwnd, WM_KEYUP, System::to_native_key(Key::escape), {}); @@ -508,7 +517,7 @@ Suite windows_window_proc = "windows_window_proc"_suite = [] { expect_eq(std::get(events[0]).get_key(), Key::escape); }; - system.tick({}); + system->tick({}); Case { "WM_CLOSE" } = [&] { expect_eq(events.size(), 0u); ::SendMessage(hwnd, WM_CLOSE, {}, {});