Skip to content

Commit ecd212c

Browse files
thedmdocornut
authored andcommitted
Backends: GLFW: Update to use io.AddEventKey() will full key map (#2625, #4858)
1 parent 746c9f7 commit ecd212c

2 files changed

Lines changed: 147 additions & 49 deletions

File tree

backends/imgui_impl_glfw.cpp

Lines changed: 145 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55

66
// Implemented features:
77
// [X] Platform: Clipboard support.
8+
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
89
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
910
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
10-
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
1111

1212
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1313
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -16,6 +16,7 @@
1616

1717
// CHANGELOG
1818
// (minor and older changes stripped away, please see git history for details)
19+
// 2022-01-10: Inputs: calling new io.AddKeyEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
1920
// 2022-01-05: Inputs: Converting GLFW untranslated keycodes back to translated keycodes (in the ImGui_ImplGlfw_KeyCallback() function) in order to match the behavior of every other backend, and facilitate the use of GLFW with lettered-shortcuts API.
2021
// 2021-08-17: *BREAKING CHANGE*: Now using glfwSetWindowFocusCallback() to calling io.AddFocusEvent(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() and forward it to the backend via ImGui_ImplGlfw_WindowFocusCallback().
2122
// 2021-07-29: *BREAKING CHANGE*: Now using glfwSetCursorEnterCallback(). MousePos is correctly reported when the host platform window is hovered but not focused. If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() callback and forward it to the backend via ImGui_ImplGlfw_CursorEnterCallback().
@@ -122,6 +123,119 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
122123
glfwSetClipboardString((GLFWwindow*)user_data, text);
123124
}
124125

126+
static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key)
127+
{
128+
switch (key)
129+
{
130+
case GLFW_KEY_TAB: return ImGuiKey_Tab;
131+
case GLFW_KEY_LEFT: return ImGuiKey_LeftArrow;
132+
case GLFW_KEY_RIGHT: return ImGuiKey_RightArrow;
133+
case GLFW_KEY_UP: return ImGuiKey_UpArrow;
134+
case GLFW_KEY_DOWN: return ImGuiKey_DownArrow;
135+
case GLFW_KEY_PAGE_UP: return ImGuiKey_PageUp;
136+
case GLFW_KEY_PAGE_DOWN: return ImGuiKey_PageDown;
137+
case GLFW_KEY_HOME: return ImGuiKey_Home;
138+
case GLFW_KEY_END: return ImGuiKey_End;
139+
case GLFW_KEY_INSERT: return ImGuiKey_Insert;
140+
case GLFW_KEY_DELETE: return ImGuiKey_Delete;
141+
case GLFW_KEY_BACKSPACE: return ImGuiKey_Backspace;
142+
case GLFW_KEY_SPACE: return ImGuiKey_Space;
143+
case GLFW_KEY_ENTER: return ImGuiKey_Enter;
144+
case GLFW_KEY_ESCAPE: return ImGuiKey_Escape;
145+
case GLFW_KEY_APOSTROPHE: return ImGuiKey_Apostrophe;
146+
case GLFW_KEY_COMMA: return ImGuiKey_Comma;
147+
case GLFW_KEY_MINUS: return ImGuiKey_Minus;
148+
case GLFW_KEY_PERIOD: return ImGuiKey_Period;
149+
case GLFW_KEY_SLASH: return ImGuiKey_Slash;
150+
case GLFW_KEY_SEMICOLON: return ImGuiKey_Semicolon;
151+
case GLFW_KEY_EQUAL: return ImGuiKey_Equal;
152+
case GLFW_KEY_LEFT_BRACKET: return ImGuiKey_LeftBracket;
153+
case GLFW_KEY_BACKSLASH: return ImGuiKey_Backslash;
154+
case GLFW_KEY_RIGHT_BRACKET: return ImGuiKey_RightBracket;
155+
case GLFW_KEY_GRAVE_ACCENT: return ImGuiKey_GraveAccent;
156+
case GLFW_KEY_CAPS_LOCK: return ImGuiKey_CapsLock;
157+
case GLFW_KEY_SCROLL_LOCK: return ImGuiKey_ScrollLock;
158+
case GLFW_KEY_NUM_LOCK: return ImGuiKey_NumLock;
159+
case GLFW_KEY_PRINT_SCREEN: return ImGuiKey_PrintScreen;
160+
case GLFW_KEY_PAUSE: return ImGuiKey_Pause;
161+
case GLFW_KEY_KP_0: return ImGuiKey_Keypad0;
162+
case GLFW_KEY_KP_1: return ImGuiKey_Keypad1;
163+
case GLFW_KEY_KP_2: return ImGuiKey_Keypad2;
164+
case GLFW_KEY_KP_3: return ImGuiKey_Keypad3;
165+
case GLFW_KEY_KP_4: return ImGuiKey_Keypad4;
166+
case GLFW_KEY_KP_5: return ImGuiKey_Keypad5;
167+
case GLFW_KEY_KP_6: return ImGuiKey_Keypad6;
168+
case GLFW_KEY_KP_7: return ImGuiKey_Keypad7;
169+
case GLFW_KEY_KP_8: return ImGuiKey_Keypad8;
170+
case GLFW_KEY_KP_9: return ImGuiKey_Keypad9;
171+
case GLFW_KEY_KP_DECIMAL: return ImGuiKey_KeypadDecimal;
172+
case GLFW_KEY_KP_DIVIDE: return ImGuiKey_KeypadDivide;
173+
case GLFW_KEY_KP_MULTIPLY: return ImGuiKey_KeypadMultiply;
174+
case GLFW_KEY_KP_SUBTRACT: return ImGuiKey_KeypadSubtract;
175+
case GLFW_KEY_KP_ADD: return ImGuiKey_KeypadAdd;
176+
case GLFW_KEY_KP_ENTER: return ImGuiKey_KeypadEnter;
177+
case GLFW_KEY_KP_EQUAL: return ImGuiKey_KeypadEqual;
178+
case GLFW_KEY_LEFT_SHIFT: return ImGuiKey_LeftShift;
179+
case GLFW_KEY_LEFT_CONTROL: return ImGuiKey_LeftControl;
180+
case GLFW_KEY_LEFT_ALT: return ImGuiKey_LeftAlt;
181+
case GLFW_KEY_LEFT_SUPER: return ImGuiKey_LeftSuper;
182+
case GLFW_KEY_RIGHT_SHIFT: return ImGuiKey_RightShift;
183+
case GLFW_KEY_RIGHT_CONTROL: return ImGuiKey_RightControl;
184+
case GLFW_KEY_RIGHT_ALT: return ImGuiKey_RightAlt;
185+
case GLFW_KEY_RIGHT_SUPER: return ImGuiKey_RightSuper;
186+
case GLFW_KEY_MENU: return ImGuiKey_Menu;
187+
case GLFW_KEY_0: return ImGuiKey_0;
188+
case GLFW_KEY_1: return ImGuiKey_1;
189+
case GLFW_KEY_2: return ImGuiKey_2;
190+
case GLFW_KEY_3: return ImGuiKey_3;
191+
case GLFW_KEY_4: return ImGuiKey_4;
192+
case GLFW_KEY_5: return ImGuiKey_5;
193+
case GLFW_KEY_6: return ImGuiKey_6;
194+
case GLFW_KEY_7: return ImGuiKey_7;
195+
case GLFW_KEY_8: return ImGuiKey_8;
196+
case GLFW_KEY_9: return ImGuiKey_9;
197+
case GLFW_KEY_A: return ImGuiKey_A;
198+
case GLFW_KEY_B: return ImGuiKey_B;
199+
case GLFW_KEY_C: return ImGuiKey_C;
200+
case GLFW_KEY_D: return ImGuiKey_D;
201+
case GLFW_KEY_E: return ImGuiKey_E;
202+
case GLFW_KEY_F: return ImGuiKey_F;
203+
case GLFW_KEY_G: return ImGuiKey_G;
204+
case GLFW_KEY_H: return ImGuiKey_H;
205+
case GLFW_KEY_I: return ImGuiKey_I;
206+
case GLFW_KEY_J: return ImGuiKey_J;
207+
case GLFW_KEY_K: return ImGuiKey_K;
208+
case GLFW_KEY_L: return ImGuiKey_L;
209+
case GLFW_KEY_M: return ImGuiKey_M;
210+
case GLFW_KEY_N: return ImGuiKey_N;
211+
case GLFW_KEY_O: return ImGuiKey_O;
212+
case GLFW_KEY_P: return ImGuiKey_P;
213+
case GLFW_KEY_Q: return ImGuiKey_Q;
214+
case GLFW_KEY_R: return ImGuiKey_R;
215+
case GLFW_KEY_S: return ImGuiKey_S;
216+
case GLFW_KEY_T: return ImGuiKey_T;
217+
case GLFW_KEY_U: return ImGuiKey_U;
218+
case GLFW_KEY_V: return ImGuiKey_V;
219+
case GLFW_KEY_W: return ImGuiKey_W;
220+
case GLFW_KEY_X: return ImGuiKey_X;
221+
case GLFW_KEY_Y: return ImGuiKey_Y;
222+
case GLFW_KEY_Z: return ImGuiKey_Z;
223+
case GLFW_KEY_F1: return ImGuiKey_F1;
224+
case GLFW_KEY_F2: return ImGuiKey_F2;
225+
case GLFW_KEY_F3: return ImGuiKey_F3;
226+
case GLFW_KEY_F4: return ImGuiKey_F4;
227+
case GLFW_KEY_F5: return ImGuiKey_F5;
228+
case GLFW_KEY_F6: return ImGuiKey_F6;
229+
case GLFW_KEY_F7: return ImGuiKey_F7;
230+
case GLFW_KEY_F8: return ImGuiKey_F8;
231+
case GLFW_KEY_F9: return ImGuiKey_F9;
232+
case GLFW_KEY_F10: return ImGuiKey_F10;
233+
case GLFW_KEY_F11: return ImGuiKey_F11;
234+
case GLFW_KEY_F12: return ImGuiKey_F12;
235+
default: return ImGuiKey_None;
236+
}
237+
}
238+
125239
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
126240
{
127241
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
@@ -143,12 +257,8 @@ void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yo
143257
io.MouseWheel += (float)yoffset;
144258
}
145259

146-
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
260+
static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode)
147261
{
148-
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
149-
if (bd->PrevUserCallbackKey != NULL && window == bd->Window)
150-
bd->PrevUserCallbackKey(window, key, scancode, action, mods);
151-
152262
#if GLFW_HAS_GET_KEY_NAME
153263
// GLFW 3.1+ attempts to "untranslate" keys, which goes the opposite of what every other framework does, making using lettered shortcuts difficult.
154264
// (It had reasons to do so: namely GLFW is/was more likely to be used for WASD-type game controls rather than lettered shortcuts, but IHMO the 3.1 change could have been done differently)
@@ -167,25 +277,24 @@ void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int a
167277
}
168278
// if (action == GLFW_PRESS) printf("key %d scancode %d name '%s'\n", key, scancode, key_name);
169279
#endif
280+
return key;
281+
}
170282

171-
ImGuiIO& io = ImGui::GetIO();
172-
if (key >= 0 && key < IM_ARRAYSIZE(io.KeysDown))
173-
{
174-
if (action == GLFW_PRESS)
175-
io.KeysDown[key] = true;
176-
if (action == GLFW_RELEASE)
177-
io.KeysDown[key] = false;
178-
}
283+
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, int action, int mods)
284+
{
285+
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
286+
if (bd->PrevUserCallbackKey != NULL && window == bd->Window)
287+
bd->PrevUserCallbackKey(window, keycode, scancode, action, mods);
179288

180-
// Modifiers are not reliable across systems
181-
io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
182-
io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
183-
io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
184-
#ifdef _WIN32
185-
io.KeySuper = false;
186-
#else
187-
io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
188-
#endif
289+
if (action != GLFW_PRESS && action != GLFW_RELEASE)
290+
return;
291+
292+
keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode);
293+
294+
ImGuiIO& io = ImGui::GetIO();
295+
ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode);
296+
io.AddKeyEvent(imgui_key, (action == GLFW_PRESS));
297+
io.SetKeyEventNativeData(imgui_key, keycode, scancode); // To support legacy indexing (<1.87 user code)
189298
}
190299

191300
void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
@@ -240,30 +349,6 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
240349
bd->Window = window;
241350
bd->Time = 0.0;
242351

243-
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
244-
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
245-
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
246-
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
247-
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
248-
io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
249-
io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
250-
io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
251-
io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
252-
io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
253-
io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
254-
io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
255-
io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
256-
io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
257-
io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
258-
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
259-
io.KeyMap[ImGuiKey_KeypadEnter] = GLFW_KEY_KP_ENTER;
260-
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
261-
io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
262-
io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
263-
io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
264-
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
265-
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
266-
267352
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
268353
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
269354
io.ClipboardUserData = bd->Window;
@@ -455,6 +540,16 @@ static void ImGui_ImplGlfw_UpdateGamepads()
455540
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
456541
}
457542

543+
static void ImGui_ImplGlfw_UpdateKeyModifiers()
544+
{
545+
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
546+
ImGuiIO& io = ImGui::GetIO();
547+
io.KeyShift = ((glfwGetKey(bd->Window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) || (glfwGetKey(bd->Window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS));
548+
io.KeyCtrl = ((glfwGetKey(bd->Window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) || (glfwGetKey(bd->Window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS));
549+
io.KeyAlt = ((glfwGetKey(bd->Window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS) || (glfwGetKey(bd->Window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS));
550+
io.KeySuper = ((glfwGetKey(bd->Window, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS) || (glfwGetKey(bd->Window, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS));
551+
}
552+
458553
void ImGui_ImplGlfw_NewFrame()
459554
{
460555
ImGuiIO& io = ImGui::GetIO();
@@ -475,6 +570,9 @@ void ImGui_ImplGlfw_NewFrame()
475570
io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
476571
bd->Time = current_time;
477572

573+
// Update key modifiers
574+
ImGui_ImplGlfw_UpdateKeyModifiers();
575+
478576
ImGui_ImplGlfw_UpdateMousePosAndButtons();
479577
ImGui_ImplGlfw_UpdateMouseCursor();
480578

backends/imgui_impl_glfw.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
// Implemented features:
66
// [X] Platform: Clipboard support.
7+
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
78
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
8-
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
9-
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
9+
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
1010

1111
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1212
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.

0 commit comments

Comments
 (0)