ocornut / imgui_club

Nice things to use along dear imgui

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Contextual key binding

pvmm opened this issue · comments

It would be a great improvement if the memory editor could consume key presses like up, down, left, right, Home, End, PgUp and PgDown when the widget has the focus (contextual key binding).

Steps to reproduce:

  1. Open game that uses the memory editor;
  2. Click on the memory editor window to set focus;
  3. Navigate through the window using keys up, down, Home, End, PgUp, PgDown;

Current behaviour:
Keys trigger navigation actions (right), but also game/app actions (wrong).

Expected behaviour:
Any key event that is handle by a window should be consumed and not passed on to the main window.

This is actually pertaining to this OpenMSX issue but I will take a look.

Is your app properly respecting the io.WantCaptureKeyboard flag ?

Yes, it is.

Is there a way to tell if a ImGui widget used the key event it received? If there is, I could make the event go back to the application if it wasn't used. I think this would solve the problem.

commented

Keys trigger navigation actions (right), but also game/app actions (wrong).

I'm missing details to understand your situation and properly answer your question.

Can you clarify what "game/app" stands for, what it is doing to access keys? (call order, API, tests performed etc)

Can you clarify what "game/app" stands for, what it is doing to access keys? (call order, API, tests performed etc)

OpenMSX uses Dear ImGui to display its debugger, but some navigation keys like PgDown can be used by both Dear ImGui widgets (like the memory editor that inspects the emulated machine) and by the emulator (the app). In this case, if the memory editor has focus, it should capture the PgDown key event because it is mapped to the widget, but in some circumstances an F2 key event should be a "global hotkey" and go directly to the app, ignoring the Dear ImGui widget. Don't know if this is useful, but OpenMSX uses imgui_impl_sdl2.

commented

I am trying to understand how eg the emulator is using the PageDown key. Is it gated by some logic or focus test? Is it using dear imgui key api or your own? Do you want it to process when the background (behind all imgui windows) is unfocused, aka all imgui windows unfocused, or do you want it to process if other imgui windows that are not using the same key are focused? Or do you want to process it when a certain window is focused?

What criteria do you think would give priority to the memory editor over the app/emulator?

The input routing / shortcut system is designed to handle that sorts of things but I can’t give you precise pointers without understanding your setup. Presumably the memory editor may need to be using the shortcut system to register the keys it uses.

commented

I think it would be better for tracking if you open an issue in imgui/ repository but I'd need answers to those question. Perhaps a screenshots or code links would help. If there is a need to make a change to imgui_memory_editor I'll make it, but the topic of input routing is complex and it's hard to provide answers without seeing the big picture, and the discussion is more general to dear imgui.

commented

For the likely scenario, can you try this:

  1. Change the code in memory editor from:
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)) && (ptrdiff_t)DataEditingAddr >= (ptrdiff_t)Cols)                     { data_editing_addr_next = DataEditingAddr - Cols; }
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)) && (ptrdiff_t)DataEditingAddr < (ptrdiff_t)mem_size - Cols)    { data_editing_addr_next = DataEditingAddr + Cols; }
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)) && (ptrdiff_t)DataEditingAddr > (ptrdiff_t)0)                  { data_editing_addr_next = DataEditingAddr - 1; }
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)) && (ptrdiff_t)DataEditingAddr < (ptrdiff_t)mem_size - 1)      { data_editing_addr_next = DataEditingAddr + 1; }

to

ImGuiInputFlags shortcut_flags = ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteFocused;
if (ImGui::Shortcut(ImGuiKey_UpArrow, 0, shortcut_flags) && (ptrdiff_t)DataEditingAddr >= (ptrdiff_t)Cols)             { data_editing_addr_next = DataEditingAddr - Cols; }
if (ImGui::Shortcut(ImGuiKey_DownArrow, 0, shortcut_flags) && (ptrdiff_t)DataEditingAddr < (ptrdiff_t)mem_size - Cols) { data_editing_addr_next = DataEditingAddr + Cols; }
if (ImGui::Shortcut(ImGuiKey_LeftArrow, 0, shortcut_flags) && (ptrdiff_t)DataEditingAddr > (ptrdiff_t)0)               { data_editing_addr_next = DataEditingAddr - 1; }
if (ImGui::Shortcut(ImGuiKey_RightArrow, 0, shortcut_flags) && (ptrdiff_t)DataEditingAddr < (ptrdiff_t)mem_size - 1)   { data_editing_addr_next = DataEditingAddr + 1; }

(note: it is actually important to remove the else, it is called Shortcut and not IsShortcutPressed because it has side effects of registering key routing)

  1. Then assuming your app/emu uses ImGui to poll keys:

One strategy is to read keys when not owned:

if (ImGui::IsKeyDown(ImGuiKey_UpArrow, ImGuiKeyOwner_None))
   ImGui::GetForegroundDrawList()->AddRectFilled(ImGui::GetMainViewport()->Pos, ImGui::GetMainViewport()->Pos + ImVec2(20, 20), IM_COL32(255, 0, 0, 255));

Or you can registered your input as well (in case you have multiple layers of this):

if (ImGui::Shortcut(ImGuiKey_UpArrow, 0, ImGuiInputFlags_RouteGlobalLow))
    ImGui::GetForegroundDrawList()->AddRectFilled(ImGui::GetMainViewport()->Pos, ImGui::GetMainViewport()->Pos + ImVec2(20, 20), IM_COL32(255, 0, 0, 255));

But this is a "pressed" event only.
I may need want to introduce a "ShortcutDown()is something, but need to understandShortcut()` has side effect of registering an input route.

Both will need you to include imgui_internal.h as the routing/ownership system is not public yet, but I think it should be public API soon, and your feedback is welcome.