Nav: Keyboard is now automatically mapped based on io.KeyDown[]. (#787)

This commit is contained in:
omar 2018-02-06 19:54:30 +01:00
parent 9e3a807813
commit 3171f90a1a
8 changed files with 59 additions and 99 deletions

View File

@ -2,7 +2,6 @@
// Implemented features:
// [X] User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// [X] Keyboard navigation mapping. Enable with 'io.NavFlags |= ImGuiNavFlags_EnableKeyboard'.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown().
@ -609,26 +608,6 @@ void ImGui_ImplDX11_NewFrame()
// io.MouseDown : filled by WM_*BUTTON* events
// io.MouseWheel : filled by WM_MOUSEWHEEL events
// Gamepad/keyboard navigation mapping [BETA]
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if (io.NavFlags & ImGuiNavFlags_EnableKeyboard)
{
// Update keyboard
// FIXME-NAV: We are still using some of the ImGuiNavInput_PadXXX enums as keyboard support is incomplete.
#define MAP_KEY(NAV_NO, KEY_NO) { if (io.KeysDown[KEY_NO]) io.NavInputs[NAV_NO] = 1.0f; }
MAP_KEY(ImGuiNavInput_KeyLeft, VK_LEFT);
MAP_KEY(ImGuiNavInput_KeyRight, VK_RIGHT);
MAP_KEY(ImGuiNavInput_KeyUp, VK_UP);
MAP_KEY(ImGuiNavInput_KeyDown, VK_DOWN);
MAP_KEY(ImGuiNavInput_KeyMenu, VK_MENU);
MAP_KEY(ImGuiNavInput_PadActivate, VK_SPACE);
MAP_KEY(ImGuiNavInput_PadCancel, VK_ESCAPE);
MAP_KEY(ImGuiNavInput_PadInput, VK_RETURN);
MAP_KEY(ImGuiNavInput_PadTweakFast, VK_SHIFT);
MAP_KEY(ImGuiNavInput_PadTweakSlow, VK_CONTROL);
#undef MAP_KEY
}
// Set OS mouse position if requested last frame by io.WantMoveMouse flag (used when io.NavMovesTrue is enabled by user and using directional navigation)
if (io.WantMoveMouse)
{

View File

@ -2,7 +2,6 @@
// Implemented features:
// [X] User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// [X] Keyboard navigation mapping. Enable with 'io.NavFlags |= ImGuiNavFlags_EnableKeyboard'.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown().

View File

@ -4,7 +4,6 @@
// Implemented features:
// [X] User texture binding. Cast 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// [X] Keyboard navigation mapping. Enable with 'io.NavFlags |= ImGuiNavFlags_EnableKeyboard'.
// [X] Gamepad navigation mapping. Enable with 'io.NavFlags |= ImGuiNavFlags_EnableGamepad'.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
@ -416,27 +415,8 @@ void ImGui_ImplGlfwGL3_NewFrame()
// Hide OS mouse cursor if ImGui is drawing it
glfwSetInputMode(g_Window, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL);
// Gamepad/keyboard navigation mapping [BETA]
// Gamepad navigation mapping [BETA]
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if (io.NavFlags & ImGuiNavFlags_EnableKeyboard)
{
// Update keyboard
// FIXME-NAV: We are still using some of the ImGuiNavInput_PadXXX enums as keyboard support is incomplete.
#define MAP_KEY(NAV_NO, KEY_NO) { if (io.KeysDown[KEY_NO]) io.NavInputs[NAV_NO] = 1.0f; }
MAP_KEY(ImGuiNavInput_KeyLeft, GLFW_KEY_LEFT);
MAP_KEY(ImGuiNavInput_KeyRight, GLFW_KEY_RIGHT);
MAP_KEY(ImGuiNavInput_KeyUp, GLFW_KEY_UP);
MAP_KEY(ImGuiNavInput_KeyDown, GLFW_KEY_DOWN);
MAP_KEY(ImGuiNavInput_KeyMenu, GLFW_KEY_LEFT_ALT);
MAP_KEY(ImGuiNavInput_PadActivate, GLFW_KEY_SPACE);
MAP_KEY(ImGuiNavInput_PadCancel, GLFW_KEY_ESCAPE);
MAP_KEY(ImGuiNavInput_PadInput, GLFW_KEY_ENTER);
MAP_KEY(ImGuiNavInput_PadTweakSlow, GLFW_KEY_LEFT_ALT);
MAP_KEY(ImGuiNavInput_PadTweakSlow, GLFW_KEY_RIGHT_ALT);
MAP_KEY(ImGuiNavInput_PadTweakFast, GLFW_KEY_LEFT_SHIFT);
MAP_KEY(ImGuiNavInput_PadTweakFast, GLFW_KEY_RIGHT_SHIFT);
#undef MAP_KEY
}
if (io.NavFlags & ImGuiNavFlags_EnableGamepad)
{
// Update gamepad inputs
@ -453,10 +433,10 @@ void ImGui_ImplGlfwGL3_NewFrame()
MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right
MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up
MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down
MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L Trigger
MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R Trigger
MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L Trigger
MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R Trigger
MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB
MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB
MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB
MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB
MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f);
MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f);
MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f);

View File

@ -4,7 +4,6 @@
// Implemented features:
// [X] User texture binding. Cast 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// [X] Keyboard navigation mapping. Enable with 'io.NavFlags |= ImGuiNavFlags_EnableKeyboard'.
// [X] Gamepad navigation mapping. Enable with 'io.NavFlags |= ImGuiNavFlags_EnableGamepad'.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.

View File

@ -4,7 +4,6 @@
// Implemented features:
// [X] User texture binding. Cast 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// [X] Keyboard navigation mapping. Enable with 'io.NavFlags |= ImGuiNavFlags_EnableKeyboard'.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown().
@ -414,29 +413,6 @@ void ImGui_ImplSdlGL3_NewFrame(SDL_Window* window)
// Hide OS mouse cursor if ImGui is drawing it
SDL_ShowCursor(io.MouseDrawCursor ? 0 : 1);
// Gamepad/keyboard navigation mapping [BETA]
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if (io.NavFlags & ImGuiNavFlags_EnableKeyboard)
{
// Update keyboard
// FIXME-NAV: We are still using some of the ImGuiNavInput_PadXXX enums as keyboard support is incomplete.
#define MAP_KEY(NAV_NO, KEY_NO) { if (io.KeysDown[KEY_NO]) io.NavInputs[NAV_NO] = 1.0f; }
MAP_KEY(ImGuiNavInput_KeyLeft, SDL_SCANCODE_LEFT);
MAP_KEY(ImGuiNavInput_KeyRight, SDL_SCANCODE_RIGHT);
MAP_KEY(ImGuiNavInput_KeyUp, SDL_SCANCODE_UP);
MAP_KEY(ImGuiNavInput_KeyDown, SDL_SCANCODE_DOWN);
MAP_KEY(ImGuiNavInput_KeyMenu, SDL_SCANCODE_LALT);
MAP_KEY(ImGuiNavInput_KeyMenu, SDL_SCANCODE_RALT);
MAP_KEY(ImGuiNavInput_PadActivate, SDL_SCANCODE_SPACE);
MAP_KEY(ImGuiNavInput_PadCancel, SDL_SCANCODE_ESCAPE);
MAP_KEY(ImGuiNavInput_PadInput, SDL_SCANCODE_RETURN);
MAP_KEY(ImGuiNavInput_PadTweakSlow, SDL_SCANCODE_LALT);
MAP_KEY(ImGuiNavInput_PadTweakSlow, SDL_SCANCODE_LALT);
MAP_KEY(ImGuiNavInput_PadTweakFast, SDL_SCANCODE_LSHIFT);
MAP_KEY(ImGuiNavInput_PadTweakFast, SDL_SCANCODE_RSHIFT);
#undef MAP_KEY
}
// Start the frame. This call will update the io.WantCaptureMouse, io.WantCaptureKeyboard flag that you can use to dispatch inputs (or not) to your application.
ImGui::NewFrame();
}

View File

@ -4,7 +4,6 @@
// Implemented features:
// [X] User texture binding. Cast 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// [X] Keyboard navigation mapping. Enable with 'io.NavFlags |= ImGuiNavFlags_EnableKeyboard'.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown().

View File

@ -2927,6 +2927,28 @@ static void ImGui::NavUpdate()
if (g.NavScoringCount > 0) printf("[%05d] NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
#endif
// Update Keyboard->Nav inputs mapping
memset(g.IO.NavInputs + ImGuiNavInput_InternalStart_, 0, (ImGuiNavInput_COUNT - ImGuiNavInput_InternalStart_) * sizeof(g.IO.NavInputs[0]));
if (g.IO.NavFlags & ImGuiNavFlags_EnableKeyboard)
{
#define NAV_MAP_KEY(_KEY, _NAV_INPUT) if (g.IO.KeyMap[_KEY] != -1 && IsKeyDown(g.IO.KeyMap[_KEY])) g.IO.NavInputs[_NAV_INPUT] = 1.0f;
NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate );
NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input );
NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel );
NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ );
NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_);
NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_ );
NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ );
if (g.IO.KeyCtrl) g.IO.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
if (g.IO.KeyShift) g.IO.NavInputs[ImGuiNavInput_TweakFast] = 1.0f;
if (g.IO.KeyAlt) g.IO.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f;
#undef NAV_MAP_KEY
}
memcpy(g.IO.NavInputsDownDurationPrev, g.IO.NavInputsDownDuration, sizeof(g.IO.NavInputsDownDuration));
for (int i = 0; i < IM_ARRAYSIZE(g.IO.NavInputs); i++)
g.IO.NavInputsDownDuration[i] = (g.IO.NavInputs[i] > 0.0f) ? (g.IO.NavInputsDownDuration[i] < 0.0f ? 0.0f : g.IO.NavInputsDownDuration[i] + g.IO.DeltaTime) : -1.0f;
// Process navigation init request (select first/default focus)
if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove))
{
@ -3182,6 +3204,10 @@ void ImGui::NewFrame()
for (int n = 0; n < ImGuiKey_COUNT; n++)
IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)");
// Do a simple check for required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was super recently added in 1.54 WIP)
if (g.IO.NavFlags & ImGuiNavFlags_EnableKeyboard)
IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation.");
// Initialize on first frame
if (!g.Initialized)
Initialize();
@ -3235,11 +3261,8 @@ void ImGui::NewFrame()
memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration));
for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++)
g.IO.KeysDownDuration[i] = g.IO.KeysDown[i] ? (g.IO.KeysDownDuration[i] < 0.0f ? 0.0f : g.IO.KeysDownDuration[i] + g.IO.DeltaTime) : -1.0f;
memcpy(g.IO.NavInputsDownDurationPrev, g.IO.NavInputsDownDuration, sizeof(g.IO.NavInputsDownDuration));
for (int i = 0; i < IM_ARRAYSIZE(g.IO.NavInputs); i++)
g.IO.NavInputsDownDuration[i] = (g.IO.NavInputs[i] > 0.0f) ? (g.IO.NavInputsDownDuration[i] < 0.0f ? 0.0f : g.IO.NavInputsDownDuration[i] + g.IO.DeltaTime) : -1.0f;
// Update directional navigation which may override MousePos if ImGuiNavFlags_MoveMouse is enabled.
// Update gamepad/keyboard directional navigation
NavUpdate();
// Update mouse input state
@ -3952,6 +3975,7 @@ void ImGui::EndFrame()
// Clear Input data for next frame
g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f;
memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters));
memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs));
g.FrameCountEnded = g.FrameCount;
}

48
imgui.h
View File

@ -704,45 +704,49 @@ enum ImGuiKey_
};
// [BETA] Gamepad/Keyboard directional navigation
// Fill ImGuiIO.NavInputs[] float array every frame to feed gamepad/keyboard navigation inputs.
// 0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks.
// ImGui uses a simple >0.0f for activation testing, and won't attempt to test for a dead-zone.
// Your code passing analog gamepad values is likely to want to transform your raw inputs, using a dead-zone and maybe a power curve.
// Keyboard:
// - io.NavInputs[] is automatically filled in by NewFrame() if you set io.NavFlags |= ImGuiNavFlags_EnableKeyboard.
// Gamepad:
// - Fill io.NavInputs[] every frame with your gamepad inputs. Note that io.NavInputs[] is _cleared_ in EndFrame().
// 0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks.
// - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone.
// Your code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, maybe a power curve, etc.).
enum ImGuiNavInput_
{
// Gamepad Mapping
ImGuiNavInput_Activate, // activate / open / toggle / tweak value // e.g. Circle (PS4), A (Xbox), B (Switch)
ImGuiNavInput_Cancel, // cancel / close / exit // e.g. Cross (PS4), B (Xbox), A (Switch)
ImGuiNavInput_Input, // text input / on-screen keyboard // e.g. Triang.(PS4), Y (Xbox), X (Switch)
ImGuiNavInput_Menu, // tap: toggle menu / hold: focus, move, resize // e.g. Square (PS4), X (Xbox), Y (Switch)
ImGuiNavInput_DpadLeft, // move / tweak / resize window (w/ PadMenu) // e.g. D-pad Left/Right/Up/Down
ImGuiNavInput_Activate, // activate / open / toggle / tweak value // e.g. Circle (PS4), A (Xbox), B (Switch), Space (Keyboard)
ImGuiNavInput_Cancel, // cancel / close / exit // e.g. Cross (PS4), B (Xbox), A (Switch), Escape (Keyboard)
ImGuiNavInput_Input, // text input / on-screen keyboard // e.g. Triang.(PS4), Y (Xbox), X (Switch), Return (Keyboard)
ImGuiNavInput_Menu, // tap: toggle menu / hold: focus, move, resize // e.g. Square (PS4), X (Xbox), Y (Switch), Alt (Keyboard)
ImGuiNavInput_DpadLeft, // move / tweak / resize window (w/ PadMenu) // e.g. D-pad Left/Right/Up/Down (Gamepads), Arrow keys (Keyboard)
ImGuiNavInput_DpadRight, //
ImGuiNavInput_DpadUp, //
ImGuiNavInput_DpadDown, //
ImGuiNavInput_LStickLeft, // scroll / move window (w/ PadMenu) // e.g. Left Analog Stick Left/Right/Up/Down
ImGuiNavInput_LStickLeft, // scroll / move window (w/ PadMenu) // e.g. Left Analog Stick Left/Right/Up/Down
ImGuiNavInput_LStickRight, //
ImGuiNavInput_LStickUp, //
ImGuiNavInput_LStickDown, //
ImGuiNavInput_FocusPrev, // next window (w/ PadMenu) // e.g. L1 (PS4), LB (Xbox), L (Switch)
ImGuiNavInput_FocusNext, // prev window (w/ PadMenu) // e.g. R1 (PS4), RB (Xbox), R (Switch)
ImGuiNavInput_TweakSlow, // slower tweaks // e.g. L2 (PS4), LT (Xbox), ZL (Switch), Analog
ImGuiNavInput_TweakFast, // faster tweaks // e.g. R2 (PS4), RT (Xbox), ZR (Switch), Analog
// Keyboard Mapping
// [BETA] To use keyboard control you currently need to map keys to those gamepad inputs: PadActivate (Enter), PadCancel (Escape), PadInput (Enter).
// Will add specialized keyboard mappings as we add features and clarify the input interface.
ImGuiNavInput_KeyMenu_, // toggle menu // e.g. Alt
ImGuiNavInput_KeyLeft_, // move left // e.g. Arrow keys
ImGuiNavInput_FocusPrev, // next window (w/ PadMenu) // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch)
ImGuiNavInput_FocusNext, // prev window (w/ PadMenu) // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch)
ImGuiNavInput_TweakSlow, // slower tweaks // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch)
ImGuiNavInput_TweakFast, // faster tweaks // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch)
// [Internal] Don't use directly! This is used internally to differentiate keyboard from gamepad inputs for behaviors that require to differentiate them.
// Keyboard behavior that have no corresponding gamepad mapping (e.g. CTRL+TAB) may be directly reading from io.KeyDown[] instead of io.NavInputs[].
ImGuiNavInput_KeyMenu_, // toggle menu // = io.KeyAlt
ImGuiNavInput_KeyLeft_, // move left // = Arrow keys
ImGuiNavInput_KeyRight_, // move right
ImGuiNavInput_KeyUp_, // move up
ImGuiNavInput_KeyDown_, // move down
ImGuiNavInput_COUNT,
ImGuiNavInput_InternalStart_ = ImGuiNavInput_KeyMenu_
};
// [BETA] Gamepad/Keyboard directional navigation options
enum ImGuiNavFlags_
{
ImGuiNavFlags_EnableGamepad = 1 << 0, // Master gamepad navigation enable flag. This is mostly to instruct your imgui binding whether to fill in gamepad navigation inputs.
ImGuiNavFlags_EnableKeyboard = 1 << 1, // Master keyboard navigation enable flag. This is mostly to instruct your imgui binding whether to fill in keyboard navigation inputs.
ImGuiNavFlags_EnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. NewFrame() will automatically fill io.NavInputs[] based on io.KeyDown[].
ImGuiNavFlags_EnableGamepad = 1 << 1, // Master gamepad navigation enable flag. This is mostly to instruct your imgui back-end to fill io.NavInputs[].
ImGuiNavFlags_MoveMouse = 1 << 2, // Request navigation to allow moving the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantMoveMouse=true. If enabled you MUST honor io.WantMoveMouse requests in your binding, otherwise ImGui will react as if the mouse is jumping around back and forth.
ImGuiNavFlags_NoCaptureKeyboard = 1 << 3 // Do not set the io.WantCaptureKeyboard flag with io.NavActive is set.
};
@ -1011,7 +1015,7 @@ struct ImGuiIO
bool KeySuper; // Keyboard modifier pressed: Cmd/Super/Windows
bool KeysDown[512]; // Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys).
ImWchar InputCharacters[16+1]; // List of characters input (translated by user from keypress+keyboard state). Fill using AddInputCharacter() helper.
float NavInputs[ImGuiNavInput_COUNT];
float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs (keyboard keys will be auto-mapped and be written here by ImGui::NewFrame)
// Functions
IMGUI_API void AddInputCharacter(ImWchar c); // Add new character into InputCharacters[]