From fe0d63d5fb4b08fc92e318a11d070351b8343fc8 Mon Sep 17 00:00:00 2001 From: Mikhail Gorobets Date: Wed, 28 Aug 2024 23:01:09 +0600 Subject: [PATCH] [ImGui, Emscripten]: Impoved event handling --- Imgui/interface/ImGuiImplEmscripten.hpp | 4 +- Imgui/src/ImGuiImplEmscripten.cpp | 189 +++++++++++++++++++----- 2 files changed, 151 insertions(+), 42 deletions(-) diff --git a/Imgui/interface/ImGuiImplEmscripten.hpp b/Imgui/interface/ImGuiImplEmscripten.hpp index 25a830b5..3a2f0749 100644 --- a/Imgui/interface/ImGuiImplEmscripten.hpp +++ b/Imgui/interface/ImGuiImplEmscripten.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2019-2023 Diligent Graphics LLC + * Copyright 2019-2024 Diligent Graphics LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -64,7 +64,7 @@ class ImGuiImplEmscripten final : public ImGuiImplDiligent private: - std::chrono::time_point m_LastTimestamp = {}; + std::chrono::high_resolution_clock::time_point m_LastTimestamp = {}; }; } // namespace Diligent diff --git a/Imgui/src/ImGuiImplEmscripten.cpp b/Imgui/src/ImGuiImplEmscripten.cpp index 6560baca..2899a641 100644 --- a/Imgui/src/ImGuiImplEmscripten.cpp +++ b/Imgui/src/ImGuiImplEmscripten.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2019-2023 Diligent Graphics LLC + * Copyright 2019-2024 Diligent Graphics LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,131 @@ namespace Diligent { +struct KeyMapping +{ + ImGuiKey KeyCode; + bool IsConsume; +}; + +static KeyMapping ImGuiKeyMap[256] = { + {ImGuiKey_None, false}}; + +static void InitializeImGuiKeyMap() +{ + ImGuiKeyMap[DOM_VK_BACK_SPACE] = {ImGuiKey_Backspace, true}; + ImGuiKeyMap[DOM_VK_TAB] = {ImGuiKey_Tab, true}; + ImGuiKeyMap[DOM_VK_RETURN] = {ImGuiKey_Enter, true}; + ImGuiKeyMap[DOM_VK_SHIFT] = {ImGuiKey_LeftShift, true}; + ImGuiKeyMap[DOM_VK_CONTROL] = {ImGuiKey_LeftCtrl, true}; + ImGuiKeyMap[DOM_VK_ALT] = {ImGuiKey_LeftAlt, true}; + ImGuiKeyMap[DOM_VK_CAPS_LOCK] = {ImGuiKey_CapsLock, true}; + ImGuiKeyMap[DOM_VK_ESCAPE] = {ImGuiKey_Escape, true}; + ImGuiKeyMap[DOM_VK_SPACE] = {ImGuiKey_Space, false}; + ImGuiKeyMap[DOM_VK_PAGE_UP] = {ImGuiKey_PageUp, true}; + ImGuiKeyMap[DOM_VK_PAGE_DOWN] = {ImGuiKey_PageDown, true}; + ImGuiKeyMap[DOM_VK_END] = {ImGuiKey_End, true}; + ImGuiKeyMap[DOM_VK_HOME] = {ImGuiKey_Home, true}; + ImGuiKeyMap[DOM_VK_LEFT] = {ImGuiKey_LeftArrow, true}; + ImGuiKeyMap[DOM_VK_UP] = {ImGuiKey_UpArrow, true}; + ImGuiKeyMap[DOM_VK_RIGHT] = {ImGuiKey_RightArrow, true}; + ImGuiKeyMap[DOM_VK_DOWN] = {ImGuiKey_DownArrow, true}; + ImGuiKeyMap[DOM_VK_INSERT] = {ImGuiKey_Insert, true}; + ImGuiKeyMap[DOM_VK_DELETE] = {ImGuiKey_Delete, true}; + ImGuiKeyMap[DOM_VK_0] = {ImGuiKey_0, false}; + ImGuiKeyMap[DOM_VK_1] = {ImGuiKey_1, false}; + ImGuiKeyMap[DOM_VK_2] = {ImGuiKey_2, false}; + ImGuiKeyMap[DOM_VK_3] = {ImGuiKey_3, false}; + ImGuiKeyMap[DOM_VK_4] = {ImGuiKey_4, false}; + ImGuiKeyMap[DOM_VK_5] = {ImGuiKey_5, false}; + ImGuiKeyMap[DOM_VK_6] = {ImGuiKey_6, false}; + ImGuiKeyMap[DOM_VK_7] = {ImGuiKey_7, false}; + ImGuiKeyMap[DOM_VK_8] = {ImGuiKey_8, false}; + ImGuiKeyMap[DOM_VK_9] = {ImGuiKey_9, false}; + ImGuiKeyMap[DOM_VK_SEMICOLON] = {ImGuiKey_Semicolon, false}; + ImGuiKeyMap[DOM_VK_EQUALS] = {ImGuiKey_Equal, false}; + ImGuiKeyMap[DOM_VK_A] = {ImGuiKey_A, false}; + ImGuiKeyMap[DOM_VK_B] = {ImGuiKey_B, false}; + ImGuiKeyMap[DOM_VK_C] = {ImGuiKey_C, false}; + ImGuiKeyMap[DOM_VK_D] = {ImGuiKey_D, false}; + ImGuiKeyMap[DOM_VK_E] = {ImGuiKey_E, false}; + ImGuiKeyMap[DOM_VK_F] = {ImGuiKey_F, false}; + ImGuiKeyMap[DOM_VK_G] = {ImGuiKey_G, false}; + ImGuiKeyMap[DOM_VK_H] = {ImGuiKey_H, false}; + ImGuiKeyMap[DOM_VK_I] = {ImGuiKey_I, false}; + ImGuiKeyMap[DOM_VK_J] = {ImGuiKey_J, false}; + ImGuiKeyMap[DOM_VK_K] = {ImGuiKey_K, false}; + ImGuiKeyMap[DOM_VK_L] = {ImGuiKey_L, false}; + ImGuiKeyMap[DOM_VK_M] = {ImGuiKey_M, false}; + ImGuiKeyMap[DOM_VK_N] = {ImGuiKey_N, false}; + ImGuiKeyMap[DOM_VK_O] = {ImGuiKey_O, false}; + ImGuiKeyMap[DOM_VK_P] = {ImGuiKey_P, false}; + ImGuiKeyMap[DOM_VK_Q] = {ImGuiKey_Q, false}; + ImGuiKeyMap[DOM_VK_R] = {ImGuiKey_R, false}; + ImGuiKeyMap[DOM_VK_S] = {ImGuiKey_S, false}; + ImGuiKeyMap[DOM_VK_T] = {ImGuiKey_T, false}; + ImGuiKeyMap[DOM_VK_U] = {ImGuiKey_U, false}; + ImGuiKeyMap[DOM_VK_V] = {ImGuiKey_V, false}; + ImGuiKeyMap[DOM_VK_W] = {ImGuiKey_W, false}; + ImGuiKeyMap[DOM_VK_X] = {ImGuiKey_X, false}; + ImGuiKeyMap[DOM_VK_Y] = {ImGuiKey_Y, false}; + ImGuiKeyMap[DOM_VK_Z] = {ImGuiKey_Z, false}; + ImGuiKeyMap[DOM_VK_WIN] = {ImGuiKey_LeftSuper, true}; + ImGuiKeyMap[DOM_VK_CONTEXT_MENU] = {ImGuiKey_Menu, true}; + ImGuiKeyMap[DOM_VK_NUMPAD0] = {ImGuiKey_Keypad0, false}; + ImGuiKeyMap[DOM_VK_NUMPAD1] = {ImGuiKey_Keypad1, false}; + ImGuiKeyMap[DOM_VK_NUMPAD2] = {ImGuiKey_Keypad2, false}; + ImGuiKeyMap[DOM_VK_NUMPAD3] = {ImGuiKey_Keypad3, false}; + ImGuiKeyMap[DOM_VK_NUMPAD4] = {ImGuiKey_Keypad4, false}; + ImGuiKeyMap[DOM_VK_NUMPAD5] = {ImGuiKey_Keypad5, false}; + ImGuiKeyMap[DOM_VK_NUMPAD6] = {ImGuiKey_Keypad6, false}; + ImGuiKeyMap[DOM_VK_NUMPAD7] = {ImGuiKey_Keypad7, false}; + ImGuiKeyMap[DOM_VK_NUMPAD8] = {ImGuiKey_Keypad8, false}; + ImGuiKeyMap[DOM_VK_NUMPAD9] = {ImGuiKey_Keypad9, false}; + ImGuiKeyMap[DOM_VK_MULTIPLY] = {ImGuiKey_KeypadMultiply, false}; + ImGuiKeyMap[DOM_VK_ADD] = {ImGuiKey_KeypadAdd, false}; + ImGuiKeyMap[DOM_VK_SUBTRACT] = {ImGuiKey_KeypadSubtract, false}; + ImGuiKeyMap[DOM_VK_DECIMAL] = {ImGuiKey_KeypadDecimal, false}; + ImGuiKeyMap[DOM_VK_DIVIDE] = {ImGuiKey_KeypadDivide, false}; + ImGuiKeyMap[DOM_VK_F1] = {ImGuiKey_F1, true}; + ImGuiKeyMap[DOM_VK_F2] = {ImGuiKey_F2, true}; + ImGuiKeyMap[DOM_VK_F3] = {ImGuiKey_F3, true}; + ImGuiKeyMap[DOM_VK_F4] = {ImGuiKey_F4, true}; + ImGuiKeyMap[DOM_VK_F5] = {ImGuiKey_F5, true}; + ImGuiKeyMap[DOM_VK_F6] = {ImGuiKey_F6, true}; + ImGuiKeyMap[DOM_VK_F7] = {ImGuiKey_F7, true}; + ImGuiKeyMap[DOM_VK_F8] = {ImGuiKey_F8, true}; + ImGuiKeyMap[DOM_VK_F9] = {ImGuiKey_F9, true}; + ImGuiKeyMap[DOM_VK_F10] = {ImGuiKey_F10, true}; + ImGuiKeyMap[DOM_VK_F11] = {ImGuiKey_F11, false}; + ImGuiKeyMap[DOM_VK_F12] = {ImGuiKey_F12, false}; + ImGuiKeyMap[DOM_VK_NUM_LOCK] = {ImGuiKey_NumLock, true}; + ImGuiKeyMap[DOM_VK_SCROLL_LOCK] = {ImGuiKey_ScrollLock, true}; + ImGuiKeyMap[DOM_VK_HYPHEN_MINUS] = {ImGuiKey_Minus, false}; + ImGuiKeyMap[DOM_VK_SEMICOLON] = {ImGuiKey_Semicolon, false}; + ImGuiKeyMap[DOM_VK_EQUALS] = {ImGuiKey_Equal, false}; + ImGuiKeyMap[DOM_VK_COMMA] = {ImGuiKey_Comma, false}; + ImGuiKeyMap[DOM_VK_HYPHEN_MINUS] = {ImGuiKey_Minus, false}; + ImGuiKeyMap[DOM_VK_PERIOD] = {ImGuiKey_Period, false}; + ImGuiKeyMap[DOM_VK_SLASH] = {ImGuiKey_Slash, false}; + ImGuiKeyMap[DOM_VK_BACK_QUOTE] = {ImGuiKey_GraveAccent, false}; + ImGuiKeyMap[DOM_VK_OPEN_BRACKET] = {ImGuiKey_LeftBracket, false}; + ImGuiKeyMap[DOM_VK_BACK_SLASH] = {ImGuiKey_Backslash, false}; + ImGuiKeyMap[DOM_VK_CLOSE_BRACKET] = {ImGuiKey_RightBracket, false}; + ImGuiKeyMap[DOM_VK_QUOTE] = {ImGuiKey_Apostrophe, false}; + ImGuiKeyMap[DOM_VK_META] = {ImGuiKey_LeftSuper, true}; +} + +static ImGuiKey RemapKeyCodeToImGuiKey(Int32 KeyCode, bool* IsConsume) +{ + if (KeyCode < 0 || KeyCode >= 256) + { + *IsConsume = false; + return ImGuiKey_None; + } + *IsConsume = ImGuiKeyMap[KeyCode].IsConsume; + return ImGuiKeyMap[KeyCode].KeyCode; +} + std::unique_ptr ImGuiImplEmscripten::Create(const ImGuiDiligentCreateInfo& CI) { return std::make_unique(CI); @@ -44,26 +169,8 @@ ImGuiImplEmscripten::ImGuiImplEmscripten(const ImGuiDiligentCreateInfo& CI) : { ImGuiIO& io = ImGui::GetIO(); io.BackendPlatformName = "Diligent-ImGuiImplEmscripten"; - - io.KeyMap[ImGuiKey_Tab] = DOM_VK_TAB; - io.KeyMap[ImGuiKey_LeftArrow] = DOM_VK_LEFT; - io.KeyMap[ImGuiKey_RightArrow] = DOM_VK_RIGHT; - io.KeyMap[ImGuiKey_UpArrow] = DOM_VK_UP; - io.KeyMap[ImGuiKey_DownArrow] = DOM_VK_DOWN; - io.KeyMap[ImGuiKey_PageUp] = DOM_VK_PAGE_UP; - io.KeyMap[ImGuiKey_PageDown] = DOM_VK_PAGE_DOWN; - io.KeyMap[ImGuiKey_Home] = DOM_VK_HOME; - io.KeyMap[ImGuiKey_End] = DOM_VK_END; - io.KeyMap[ImGuiKey_Delete] = DOM_VK_DELETE; - io.KeyMap[ImGuiKey_Backspace] = DOM_VK_BACK_SPACE; - io.KeyMap[ImGuiKey_Enter] = DOM_VK_ENTER; - io.KeyMap[ImGuiKey_Escape] = DOM_VK_ESCAPE; - io.KeyMap[ImGuiKey_A] = DOM_VK_A; - io.KeyMap[ImGuiKey_C] = DOM_VK_C; - io.KeyMap[ImGuiKey_V] = DOM_VK_V; - io.KeyMap[ImGuiKey_X] = DOM_VK_X; - io.KeyMap[ImGuiKey_Y] = DOM_VK_Y; - io.KeyMap[ImGuiKey_Z] = DOM_VK_Z; + m_LastTimestamp = std::chrono::high_resolution_clock::now(); + InitializeImGuiKeyMap(); } ImGuiImplEmscripten::~ImGuiImplEmscripten() @@ -75,10 +182,10 @@ void ImGuiImplEmscripten::NewFrame(Uint32 RenderSurfaceWidth, SURFACE_TRANSFORM SurfacePreTransform) { auto now = std::chrono::high_resolution_clock::now(); - auto elapsed_ns = now - m_LastTimestamp; + auto elapsed_ns = std::chrono::duration_cast>(now - m_LastTimestamp); m_LastTimestamp = now; auto& io = ImGui::GetIO(); - io.DeltaTime = static_cast(elapsed_ns.count() / 1e+9); + io.DeltaTime = elapsed_ns.count(); io.DisplaySize = ImVec2(RenderSurfaceWidth / io.DisplayFramebufferScale.x, RenderSurfaceHeight / io.DisplayFramebufferScale.y); ImGuiImplDiligent::NewFrame(RenderSurfaceWidth, RenderSurfaceHeight, SurfacePreTransform); } @@ -90,47 +197,49 @@ void ImGuiImplEmscripten::Render(IDeviceContext* pCtx) bool ImGuiImplEmscripten::OnMouseEvent(int32_t EventType, const EmscriptenMouseEvent* Event) { - auto& io = ImGui::GetIO(); - io.MousePos = ImVec2(Event->targetX, Event->targetY); - io.MouseDown[0] = Event->buttons & 1; - io.MouseDown[1] = Event->buttons & 2; - io.MouseDown[2] = Event->buttons & 4; + auto& io = ImGui::GetIO(); + io.AddMousePosEvent(Event->targetX, Event->targetY); + io.AddMouseButtonEvent(0, Event->buttons & 1); + io.AddMouseButtonEvent(1, Event->buttons & 2); + io.AddMouseButtonEvent(2, Event->buttons & 4); return io.WantCaptureMouse; } bool ImGuiImplEmscripten::OnWheelEvent(int32_t EventType, const EmscriptenWheelEvent* Event) { auto& io = ImGui::GetIO(); - io.MouseWheelH += -0.1f * Event->deltaX; - io.MouseWheel += -0.1f * Event->deltaY; + io.AddMouseWheelEvent(float(Event->deltaX / +120.0f), float(Event->deltaY / -120.0f)); return io.WantCaptureMouse; } bool ImGuiImplEmscripten::OnKeyEvent(int32_t EventType, const EmscriptenKeyboardEvent* Event) { - auto& io = ImGui::GetIO(); - io.KeyCtrl = Event->ctrlKey; - io.KeyShift = Event->shiftKey; - io.KeyAlt = Event->altKey; - io.KeySuper = Event->metaKey; + auto& io = ImGui::GetIO(); + io.AddKeyEvent(ImGuiKey_ModCtrl, Event->ctrlKey); + io.AddKeyEvent(ImGuiKey_ModShift, Event->shiftKey); + io.AddKeyEvent(ImGuiKey_ModAlt, Event->altKey); + io.AddKeyEvent(ImGuiKey_ModSuper, Event->metaKey); switch (EventType) { case EMSCRIPTEN_EVENT_KEYDOWN: - case EMSCRIPTEN_EVENT_KEYUP: { - bool IsPressed = EventType == EMSCRIPTEN_EVENT_KEYDOWN; - io.KeysDown[Event->which] = IsPressed; + bool IsConsume = false; + io.AddKeyEvent(RemapKeyCodeToImGuiKey(Event->keyCode, &IsConsume), true); + if (!IsConsume) + io.AddInputCharactersUTF8(Event->key); break; } - case EMSCRIPTEN_EVENT_KEYPRESS: + case EMSCRIPTEN_EVENT_KEYUP: { - io.AddInputCharactersUTF8(Event->key); + bool IsConsume = false; + io.AddKeyEvent(RemapKeyCodeToImGuiKey(Event->keyCode, &IsConsume), false); break; } default: break; } + return io.WantCaptureKeyboard; } } // namespace Diligent