1// dear imgui: Platform Backend for GLFW
2// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
3// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
4// (Requires: GLFW 3.1+)
5
6// Implemented features:
7// [X] Platform: Clipboard support.
8// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
9// [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).
11
12// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
13// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
14// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
15// Read online: https://github.com/ocornut/imgui/tree/master/docs
16
17// CHANGELOG
18// (minor and older changes stripped away, please see git history for details)
19// 2021-07-29: *BREAKING CHANGE*: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using glfwSetCursorEnterCallback). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install the glfwSetCursorEnterCallback() callback and the forward to the backend via ImGui_ImplGlfw_CursorEnterCallback().
20// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
21// 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors.
22// 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor).
23// 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown.
24// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
25// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
26// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
27// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
28// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
29// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
30// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
31// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
32// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
33// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()).
34// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
35// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
36// 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set.
37// 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
38// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
39// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
40// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
41// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
42
43#include "imgui.h"
44#include "imgui_impl_glfw.h"
45
46// GLFW
47#include <GLFW/glfw3.h>
48#ifdef _WIN32
49#undef APIENTRY
50#define GLFW_EXPOSE_NATIVE_WIN32
51#include <GLFW/glfw3native.h> // for glfwGetWin32Window
52#endif
53#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING
54#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED
55#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity
56#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale
57#define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface
58#ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
59#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
60#else
61#define GLFW_HAS_NEW_CURSORS (0)
62#endif
63
64// GLFW data
65enum GlfwClientApi
66{
67 GlfwClientApi_Unknown,
68 GlfwClientApi_OpenGL,
69 GlfwClientApi_Vulkan
70};
71
72struct ImGui_ImplGlfw_Data
73{
74 GLFWwindow* Window;
75 GlfwClientApi ClientApi;
76 double Time;
77 GLFWwindow* MouseWindow;
78 bool MouseJustPressed[ImGuiMouseButton_COUNT];
79 GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT];
80 bool InstalledCallbacks;
81
82 // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
83 GLFWcursorenterfun PrevUserCallbackCursorEnter;
84 GLFWmousebuttonfun PrevUserCallbackMousebutton;
85 GLFWscrollfun PrevUserCallbackScroll;
86 GLFWkeyfun PrevUserCallbackKey;
87 GLFWcharfun PrevUserCallbackChar;
88 GLFWmonitorfun PrevUserCallbackMonitor;
89
90 ImGui_ImplGlfw_Data() { memset(this, 0, sizeof(*this)); }
91};
92
93// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
94// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
95// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
96// - Because glfwPollEvents() process all windows and some events may be called outside of it, you will need to register your own callbacks
97// (passing install_callbacks=false in ImGui_ImplGlfw_InitXXX functions), set the current dear imgui context and then call our callbacks.
98// - Otherwise we may need to store a GLFWWindow* -> ImGuiContext* map and handle this in the backend, adding a little bit of extra complexity to it.
99// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
100static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData()
101{
102 return ImGui::GetCurrentContext() ? (ImGui_ImplGlfw_Data*)ImGui::GetIO().BackendPlatformUserData : NULL;
103}
104
105// Functions
106static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
107{
108 return glfwGetClipboardString((GLFWwindow*)user_data);
109}
110
111static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
112{
113 glfwSetClipboardString((GLFWwindow*)user_data, text);
114}
115
116void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
117{
118 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
119 if (bd->PrevUserCallbackMousebutton != NULL && window == bd->Window)
120 bd->PrevUserCallbackMousebutton(window, button, action, mods);
121
122 if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(bd->MouseJustPressed))
123 bd->MouseJustPressed[button] = true;
124}
125
126void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
127{
128 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
129 if (bd->PrevUserCallbackScroll != NULL && window == bd->Window)
130 bd->PrevUserCallbackScroll(window, xoffset, yoffset);
131
132 ImGuiIO& io = ImGui::GetIO();
133 io.MouseWheelH += (float)xoffset;
134 io.MouseWheel += (float)yoffset;
135}
136
137void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
138{
139 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
140 if (bd->PrevUserCallbackKey != NULL && window == bd->Window)
141 bd->PrevUserCallbackKey(window, key, scancode, action, mods);
142
143 ImGuiIO& io = ImGui::GetIO();
144 if (key >= 0 && key < IM_ARRAYSIZE(io.KeysDown))
145 {
146 if (action == GLFW_PRESS)
147 io.KeysDown[key] = true;
148 if (action == GLFW_RELEASE)
149 io.KeysDown[key] = false;
150 }
151
152 // Modifiers are not reliable across systems
153 io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
154 io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
155 io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
156#ifdef _WIN32
157 io.KeySuper = false;
158#else
159 io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
160#endif
161}
162
163void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered)
164{
165 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
166 if (bd->PrevUserCallbackCursorEnter != NULL)
167 bd->PrevUserCallbackCursorEnter(window, entered);
168 if (entered)
169 bd->MouseWindow = window;
170 if (!entered && bd->MouseWindow == window)
171 bd->MouseWindow = NULL;
172}
173
174void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
175{
176 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
177 if (bd->PrevUserCallbackChar != NULL && window == bd->Window)
178 bd->PrevUserCallbackChar(window, c);
179
180 ImGuiIO& io = ImGui::GetIO();
181 io.AddInputCharacter(c);
182}
183
184void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
185{
186 // Unused in 'master' branch but 'docking' branch will use this, so we declare it ahead of it so if you have to install callbacks you can install this one too.
187}
188
189static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
190{
191 ImGuiIO& io = ImGui::GetIO();
192 IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
193
194 // Setup backend capabilities flags
195 ImGui_ImplGlfw_Data* bd = IM_NEW(ImGui_ImplGlfw_Data)();
196 io.BackendPlatformUserData = (void*)bd;
197 io.BackendPlatformName = "imgui_impl_glfw";
198 io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
199 io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
200
201 bd->Window = window;
202 bd->Time = 0.0;
203
204 // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
205 io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
206 io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
207 io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
208 io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
209 io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
210 io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
211 io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
212 io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
213 io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
214 io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
215 io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
216 io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
217 io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
218 io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
219 io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
220 io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER;
221 io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
222 io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
223 io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
224 io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
225 io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
226 io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
227
228 io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
229 io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
230 io.ClipboardUserData = bd->Window;
231#if defined(_WIN32)
232 io.ImeWindowHandle = (void*)glfwGetWin32Window(bd->Window);
233#endif
234
235 // Create mouse cursors
236 // (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
237 // GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
238 // Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
239 GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL);
240 bd->MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
241 bd->MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
242 bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
243 bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
244 bd->MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
245#if GLFW_HAS_NEW_CURSORS
246 bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
247 bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
248 bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
249 bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
250#else
251 bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
252 bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
253 bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
254 bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
255#endif
256 glfwSetErrorCallback(prev_error_callback);
257
258 // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
259 bd->PrevUserCallbackMousebutton = NULL;
260 bd->PrevUserCallbackScroll = NULL;
261 bd->PrevUserCallbackKey = NULL;
262 bd->PrevUserCallbackChar = NULL;
263 bd->PrevUserCallbackMonitor = NULL;
264 if (install_callbacks)
265 {
266 bd->InstalledCallbacks = true;
267 bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback);
268 bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
269 bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
270 bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
271 bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
272 bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
273 }
274
275 bd->ClientApi = client_api;
276 return true;
277}
278
279bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
280{
281 return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
282}
283
284bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
285{
286 return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
287}
288
289bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks)
290{
291 return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown);
292}
293
294void ImGui_ImplGlfw_Shutdown()
295{
296 ImGuiIO& io = ImGui::GetIO();
297 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
298
299 if (bd->InstalledCallbacks)
300 {
301 glfwSetCursorEnterCallback(bd->Window, bd->PrevUserCallbackCursorEnter);
302 glfwSetMouseButtonCallback(bd->Window, bd->PrevUserCallbackMousebutton);
303 glfwSetScrollCallback(bd->Window, bd->PrevUserCallbackScroll);
304 glfwSetKeyCallback(bd->Window, bd->PrevUserCallbackKey);
305 glfwSetCharCallback(bd->Window, bd->PrevUserCallbackChar);
306 glfwSetMonitorCallback(bd->PrevUserCallbackMonitor);
307 }
308
309 for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
310 glfwDestroyCursor(bd->MouseCursors[cursor_n]);
311
312 io.BackendPlatformName = NULL;
313 io.BackendPlatformUserData = NULL;
314 IM_DELETE(bd);
315}
316
317static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
318{
319 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
320 ImGuiIO& io = ImGui::GetIO();
321
322 const ImVec2 mouse_pos_prev = io.MousePos;
323 io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
324
325 // Update mouse buttons
326 // (if a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame)
327 for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
328 {
329 io.MouseDown[i] = bd->MouseJustPressed[i] || glfwGetMouseButton(bd->Window, i) != 0;
330 bd->MouseJustPressed[i] = false;
331 }
332
333#ifdef __EMSCRIPTEN__
334 const bool focused = true;
335#else
336 const bool focused = glfwGetWindowAttrib(bd->Window, GLFW_FOCUSED) != 0;
337#endif
338 GLFWwindow* mouse_window = (bd->MouseWindow == bd->Window || focused) ? bd->Window : NULL;
339
340 // Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
341 if (io.WantSetMousePos && focused)
342 glfwSetCursorPos(bd->Window, (double)mouse_pos_prev.x, (double)mouse_pos_prev.y);
343
344 // Set Dear ImGui mouse position from OS position
345 if (mouse_window != NULL)
346 {
347 double mouse_x, mouse_y;
348 glfwGetCursorPos(mouse_window, &mouse_x, &mouse_y);
349 io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
350 }
351}
352
353static void ImGui_ImplGlfw_UpdateMouseCursor()
354{
355 ImGuiIO& io = ImGui::GetIO();
356 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
357 if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
358 return;
359
360 ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
361 if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
362 {
363 // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
364 glfwSetInputMode(bd->Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
365 }
366 else
367 {
368 // Show OS mouse cursor
369 // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
370 glfwSetCursor(bd->Window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
371 glfwSetInputMode(bd->Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
372 }
373}
374
375static void ImGui_ImplGlfw_UpdateGamepads()
376{
377 ImGuiIO& io = ImGui::GetIO();
378 memset(io.NavInputs, 0, sizeof(io.NavInputs));
379 if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
380 return;
381
382 // Update gamepad inputs
383 #define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; }
384 #define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; }
385 int axes_count = 0, buttons_count = 0;
386 const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
387 const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
388 MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A
389 MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B
390 MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X
391 MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y
392 MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left
393 MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right
394 MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up
395 MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down
396 MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB
397 MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB
398 MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB
399 MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB
400 MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f);
401 MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f);
402 MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f);
403 MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f);
404 #undef MAP_BUTTON
405 #undef MAP_ANALOG
406 if (axes_count > 0 && buttons_count > 0)
407 io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
408 else
409 io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
410}
411
412void ImGui_ImplGlfw_NewFrame()
413{
414 ImGuiIO& io = ImGui::GetIO();
415 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
416 IM_ASSERT(bd != NULL && "Did you call ImGui_ImplGlfw_InitForXXX()?");
417
418 // Setup display size (every frame to accommodate for window resizing)
419 int w, h;
420 int display_w, display_h;
421 glfwGetWindowSize(bd->Window, &w, &h);
422 glfwGetFramebufferSize(bd->Window, &display_w, &display_h);
423 io.DisplaySize = ImVec2((float)w, (float)h);
424 if (w > 0 && h > 0)
425 io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
426
427 // Setup time step
428 double current_time = glfwGetTime();
429 io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
430 bd->Time = current_time;
431
432 ImGui_ImplGlfw_UpdateMousePosAndButtons();
433 ImGui_ImplGlfw_UpdateMouseCursor();
434
435 // Update game controllers (if enabled and available)
436 ImGui_ImplGlfw_UpdateGamepads();
437}
438