Skip to content

Commit

Permalink
[ImGui, Emscripten]: Impoved event handling
Browse files Browse the repository at this point in the history
  • Loading branch information
MikhailGorobets committed Aug 28, 2024
1 parent d80f824 commit fe0d63d
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 42 deletions.
4 changes: 2 additions & 2 deletions Imgui/interface/ImGuiImplEmscripten.hpp
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -64,7 +64,7 @@ class ImGuiImplEmscripten final : public ImGuiImplDiligent


private:
std::chrono::time_point<std::chrono::high_resolution_clock> m_LastTimestamp = {};
std::chrono::high_resolution_clock::time_point m_LastTimestamp = {};
};

} // namespace Diligent
189 changes: 149 additions & 40 deletions Imgui/src/ImGuiImplEmscripten.cpp
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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> ImGuiImplEmscripten::Create(const ImGuiDiligentCreateInfo& CI)
{
return std::make_unique<ImGuiImplEmscripten>(CI);
Expand All @@ -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()
Expand All @@ -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<std::chrono::duration<float>>(now - m_LastTimestamp);
m_LastTimestamp = now;
auto& io = ImGui::GetIO();
io.DeltaTime = static_cast<float>(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);
}
Expand All @@ -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

0 comments on commit fe0d63d

Please sign in to comment.