PeriDyno 1.0.0
Loading...
Searching...
No Matches
imgui_impl_glfw.cpp
Go to the documentation of this file.
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+. Prefer GLFW 3.3+ or GLFW 3.4+ for full feature support.)
5
6// Implemented features:
7// [X] Platform: Clipboard support.
8// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only).
9// [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]
10// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
11// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
12
13// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
14// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
15// Learn about Dear ImGui:
16// - FAQ https://dearimgui.com/faq
17// - Getting Started https://dearimgui.com/getting-started
18// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
19// - Introduction, links and more at the top of imgui.cpp
20
21// CHANGELOG
22// (minor and older changes stripped away, please see git history for details)
23// 2023-12-19: Emscripten: Added ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback() to register canvas selector and auto-resize GLFW window.
24// 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys.
25// 2023-07-18: Inputs: Revert ignoring mouse data on GLFW_CURSOR_DISABLED as it can be used differently. User may set ImGuiConfigFLags_NoMouse if desired. (#5625, #6609)
26// 2023-06-12: Accept glfwGetTime() not returning a monotonically increasing value. This seems to happens on some Windows setup when peripherals disconnect, and is likely to also happen on browser + Emscripten. (#6491)
27// 2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen/ImGuiMouseSource_Pen on Windows ONLY, using a custom WndProc hook. (#2702)
28// 2023-03-16: Inputs: Fixed key modifiers handling on secondary viewports (docking branch). Broken on 2023/01/04. (#6248, #6034)
29// 2023-03-14: Emscripten: Avoid using glfwGetError() and glfwGetGamepadState() which are not correctly implemented in Emscripten emulation. (#6240)
30// 2023-02-03: Emscripten: Registering custom low-level mouse wheel handler to get more accurate scrolling impulses on Emscripten. (#4019, #6096)
31// 2023-01-04: Inputs: Fixed mods state on Linux when using Alt-GR text input (e.g. German keyboard layout), could lead to broken text input. Revert a 2022/01/17 change were we resumed using mods provided by GLFW, turns out they were faulty.
32// 2022-11-22: Perform a dummy glfwGetError() read to cancel missing names with glfwGetKeyName(). (#5908)
33// 2022-10-18: Perform a dummy glfwGetError() read to cancel missing mouse cursors errors. Using GLFW_VERSION_COMBINED directly. (#5785)
34// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
35// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
36// 2022-09-01: Inputs: Honor GLFW_CURSOR_DISABLED by not setting mouse position *EDIT* Reverted 2023-07-18.
37// 2022-04-30: Inputs: Fixed ImGui_ImplGlfw_TranslateUntranslatedKey() for lower case letters on OSX.
38// 2022-03-23: Inputs: Fixed a regression in 1.87 which resulted in keyboard modifiers events being reported incorrectly on Linux/X11.
39// 2022-02-07: Added ImGui_ImplGlfw_InstallCallbacks()/ImGui_ImplGlfw_RestoreCallbacks() helpers to facilitate user installing callbacks after initializing backend.
40// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
41// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
42// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
43// 2022-01-17: Inputs: always update key mods next and before key event (not in NewFrame) to fix input queue with very low framerates.
44// 2022-01-12: *BREAKING CHANGE*: Now using glfwSetCursorPosCallback(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetCursorPosCallback() and forward it to the backend via ImGui_ImplGlfw_CursorPosCallback().
45// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
46// 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.
47// 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().
48// 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().
49// 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).
50// 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors.
51// 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor).
52// 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown.
53// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
54// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
55// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
56// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
57// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
58// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
59// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
60// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
61// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
62// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()).
63// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
64// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
65// 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set.
66// 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
67// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
68// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
69// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
70// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
71
72#include "imgui.h"
73#ifndef IMGUI_DISABLE
74#include "imgui_impl_glfw.h"
75
76// Clang warnings with -Weverything
77#if defined(__clang__)
78#pragma clang diagnostic push
79#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
80#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
81#endif
82
83// GLFW
84#include <GLFW/glfw3.h>
85
86#ifdef _WIN32
87#undef APIENTRY
88#ifndef GLFW_EXPOSE_NATIVE_WIN32
89#define GLFW_EXPOSE_NATIVE_WIN32
90#endif
91#include <GLFW/glfw3native.h> // for glfwGetWin32Window()
92#endif
93#ifdef __APPLE__
94#ifndef GLFW_EXPOSE_NATIVE_COCOA
95#define GLFW_EXPOSE_NATIVE_COCOA
96#endif
97#include <GLFW/glfw3native.h> // for glfwGetCocoaWindow()
98#endif
99
100#ifdef __EMSCRIPTEN__
101#include <emscripten.h>
102#include <emscripten/html5.h>
103#endif
104
105// We gather version tests as define in order to easily see which features are version-dependent.
106#define GLFW_VERSION_COMBINED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION)
107#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?
108#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_COMBINED >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
109#else
110#define GLFW_HAS_NEW_CURSORS (0)
111#endif
112#define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetGamepadState() new api
113#define GLFW_HAS_GETKEYNAME (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwGetKeyName()
114#define GLFW_HAS_GETERROR (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetError()
115
116// GLFW data
123
125{
126 GLFWwindow* Window;
128 double Time;
129 GLFWwindow* MouseWindow;
130 GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT];
134#ifdef __EMSCRIPTEN__
135 const char* CanvasSelector;
136#endif
137
138 // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
139 GLFWwindowfocusfun PrevUserCallbackWindowFocus;
141 GLFWcursorenterfun PrevUserCallbackCursorEnter;
142 GLFWmousebuttonfun PrevUserCallbackMousebutton;
147#ifdef _WIN32
148 WNDPROC GlfwWndProc;
149#endif
150
151 ImGui_ImplGlfw_Data() { memset((void*)this, 0, sizeof(*this)); }
152};
153
154// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
155// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
156// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
157// - Because glfwPollEvents() process all windows and some events may be called outside of it, you will need to register your own callbacks
158// (passing install_callbacks=false in ImGui_ImplGlfw_InitXXX functions), set the current dear imgui context and then call our callbacks.
159// - 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.
160// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
162{
163 return ImGui::GetCurrentContext() ? (ImGui_ImplGlfw_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr;
164}
165
166// Functions
167static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
168{
169 return glfwGetClipboardString((GLFWwindow*)user_data);
170}
171
172static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
173{
174 glfwSetClipboardString((GLFWwindow*)user_data, text);
175}
176
177static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key)
178{
179 switch (key)
180 {
181 case GLFW_KEY_TAB: return ImGuiKey_Tab;
182 case GLFW_KEY_LEFT: return ImGuiKey_LeftArrow;
183 case GLFW_KEY_RIGHT: return ImGuiKey_RightArrow;
184 case GLFW_KEY_UP: return ImGuiKey_UpArrow;
185 case GLFW_KEY_DOWN: return ImGuiKey_DownArrow;
186 case GLFW_KEY_PAGE_UP: return ImGuiKey_PageUp;
187 case GLFW_KEY_PAGE_DOWN: return ImGuiKey_PageDown;
188 case GLFW_KEY_HOME: return ImGuiKey_Home;
189 case GLFW_KEY_END: return ImGuiKey_End;
190 case GLFW_KEY_INSERT: return ImGuiKey_Insert;
191 case GLFW_KEY_DELETE: return ImGuiKey_Delete;
192 case GLFW_KEY_BACKSPACE: return ImGuiKey_Backspace;
193 case GLFW_KEY_SPACE: return ImGuiKey_Space;
194 case GLFW_KEY_ENTER: return ImGuiKey_Enter;
195 case GLFW_KEY_ESCAPE: return ImGuiKey_Escape;
196 case GLFW_KEY_APOSTROPHE: return ImGuiKey_Apostrophe;
197 case GLFW_KEY_COMMA: return ImGuiKey_Comma;
198 case GLFW_KEY_MINUS: return ImGuiKey_Minus;
199 case GLFW_KEY_PERIOD: return ImGuiKey_Period;
200 case GLFW_KEY_SLASH: return ImGuiKey_Slash;
201 case GLFW_KEY_SEMICOLON: return ImGuiKey_Semicolon;
202 case GLFW_KEY_EQUAL: return ImGuiKey_Equal;
203 case GLFW_KEY_LEFT_BRACKET: return ImGuiKey_LeftBracket;
204 case GLFW_KEY_BACKSLASH: return ImGuiKey_Backslash;
205 case GLFW_KEY_RIGHT_BRACKET: return ImGuiKey_RightBracket;
206 case GLFW_KEY_GRAVE_ACCENT: return ImGuiKey_GraveAccent;
207 case GLFW_KEY_CAPS_LOCK: return ImGuiKey_CapsLock;
208 case GLFW_KEY_SCROLL_LOCK: return ImGuiKey_ScrollLock;
209 case GLFW_KEY_NUM_LOCK: return ImGuiKey_NumLock;
210 case GLFW_KEY_PRINT_SCREEN: return ImGuiKey_PrintScreen;
211 case GLFW_KEY_PAUSE: return ImGuiKey_Pause;
212 case GLFW_KEY_KP_0: return ImGuiKey_Keypad0;
213 case GLFW_KEY_KP_1: return ImGuiKey_Keypad1;
214 case GLFW_KEY_KP_2: return ImGuiKey_Keypad2;
215 case GLFW_KEY_KP_3: return ImGuiKey_Keypad3;
216 case GLFW_KEY_KP_4: return ImGuiKey_Keypad4;
217 case GLFW_KEY_KP_5: return ImGuiKey_Keypad5;
218 case GLFW_KEY_KP_6: return ImGuiKey_Keypad6;
219 case GLFW_KEY_KP_7: return ImGuiKey_Keypad7;
220 case GLFW_KEY_KP_8: return ImGuiKey_Keypad8;
221 case GLFW_KEY_KP_9: return ImGuiKey_Keypad9;
222 case GLFW_KEY_KP_DECIMAL: return ImGuiKey_KeypadDecimal;
223 case GLFW_KEY_KP_DIVIDE: return ImGuiKey_KeypadDivide;
224 case GLFW_KEY_KP_MULTIPLY: return ImGuiKey_KeypadMultiply;
225 case GLFW_KEY_KP_SUBTRACT: return ImGuiKey_KeypadSubtract;
226 case GLFW_KEY_KP_ADD: return ImGuiKey_KeypadAdd;
227 case GLFW_KEY_KP_ENTER: return ImGuiKey_KeypadEnter;
228 case GLFW_KEY_KP_EQUAL: return ImGuiKey_KeypadEqual;
229 case GLFW_KEY_LEFT_SHIFT: return ImGuiKey_LeftShift;
230 case GLFW_KEY_LEFT_CONTROL: return ImGuiKey_LeftCtrl;
231 case GLFW_KEY_LEFT_ALT: return ImGuiKey_LeftAlt;
232 case GLFW_KEY_LEFT_SUPER: return ImGuiKey_LeftSuper;
233 case GLFW_KEY_RIGHT_SHIFT: return ImGuiKey_RightShift;
234 case GLFW_KEY_RIGHT_CONTROL: return ImGuiKey_RightCtrl;
235 case GLFW_KEY_RIGHT_ALT: return ImGuiKey_RightAlt;
236 case GLFW_KEY_RIGHT_SUPER: return ImGuiKey_RightSuper;
237 case GLFW_KEY_MENU: return ImGuiKey_Menu;
238 case GLFW_KEY_0: return ImGuiKey_0;
239 case GLFW_KEY_1: return ImGuiKey_1;
240 case GLFW_KEY_2: return ImGuiKey_2;
241 case GLFW_KEY_3: return ImGuiKey_3;
242 case GLFW_KEY_4: return ImGuiKey_4;
243 case GLFW_KEY_5: return ImGuiKey_5;
244 case GLFW_KEY_6: return ImGuiKey_6;
245 case GLFW_KEY_7: return ImGuiKey_7;
246 case GLFW_KEY_8: return ImGuiKey_8;
247 case GLFW_KEY_9: return ImGuiKey_9;
248 case GLFW_KEY_A: return ImGuiKey_A;
249 case GLFW_KEY_B: return ImGuiKey_B;
250 case GLFW_KEY_C: return ImGuiKey_C;
251 case GLFW_KEY_D: return ImGuiKey_D;
252 case GLFW_KEY_E: return ImGuiKey_E;
253 case GLFW_KEY_F: return ImGuiKey_F;
254 case GLFW_KEY_G: return ImGuiKey_G;
255 case GLFW_KEY_H: return ImGuiKey_H;
256 case GLFW_KEY_I: return ImGuiKey_I;
257 case GLFW_KEY_J: return ImGuiKey_J;
258 case GLFW_KEY_K: return ImGuiKey_K;
259 case GLFW_KEY_L: return ImGuiKey_L;
260 case GLFW_KEY_M: return ImGuiKey_M;
261 case GLFW_KEY_N: return ImGuiKey_N;
262 case GLFW_KEY_O: return ImGuiKey_O;
263 case GLFW_KEY_P: return ImGuiKey_P;
264 case GLFW_KEY_Q: return ImGuiKey_Q;
265 case GLFW_KEY_R: return ImGuiKey_R;
266 case GLFW_KEY_S: return ImGuiKey_S;
267 case GLFW_KEY_T: return ImGuiKey_T;
268 case GLFW_KEY_U: return ImGuiKey_U;
269 case GLFW_KEY_V: return ImGuiKey_V;
270 case GLFW_KEY_W: return ImGuiKey_W;
271 case GLFW_KEY_X: return ImGuiKey_X;
272 case GLFW_KEY_Y: return ImGuiKey_Y;
273 case GLFW_KEY_Z: return ImGuiKey_Z;
274 case GLFW_KEY_F1: return ImGuiKey_F1;
275 case GLFW_KEY_F2: return ImGuiKey_F2;
276 case GLFW_KEY_F3: return ImGuiKey_F3;
277 case GLFW_KEY_F4: return ImGuiKey_F4;
278 case GLFW_KEY_F5: return ImGuiKey_F5;
279 case GLFW_KEY_F6: return ImGuiKey_F6;
280 case GLFW_KEY_F7: return ImGuiKey_F7;
281 case GLFW_KEY_F8: return ImGuiKey_F8;
282 case GLFW_KEY_F9: return ImGuiKey_F9;
283 case GLFW_KEY_F10: return ImGuiKey_F10;
284 case GLFW_KEY_F11: return ImGuiKey_F11;
285 case GLFW_KEY_F12: return ImGuiKey_F12;
286 case GLFW_KEY_F13: return ImGuiKey_F13;
287 case GLFW_KEY_F14: return ImGuiKey_F14;
288 case GLFW_KEY_F15: return ImGuiKey_F15;
289 case GLFW_KEY_F16: return ImGuiKey_F16;
290 case GLFW_KEY_F17: return ImGuiKey_F17;
291 case GLFW_KEY_F18: return ImGuiKey_F18;
292 case GLFW_KEY_F19: return ImGuiKey_F19;
293 case GLFW_KEY_F20: return ImGuiKey_F20;
294 case GLFW_KEY_F21: return ImGuiKey_F21;
295 case GLFW_KEY_F22: return ImGuiKey_F22;
296 case GLFW_KEY_F23: return ImGuiKey_F23;
297 case GLFW_KEY_F24: return ImGuiKey_F24;
298 default: return ImGuiKey_None;
299 }
300}
301
302// X11 does not include current pressed/released modifier key in 'mods' flags submitted by GLFW
303// See https://github.com/ocornut/imgui/issues/6034 and https://github.com/glfw/glfw/issues/1630
304static void ImGui_ImplGlfw_UpdateKeyModifiers(GLFWwindow* window)
305{
306 ImGuiIO& io = ImGui::GetIO();
307 io.AddKeyEvent(ImGuiMod_Ctrl, (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS));
308 io.AddKeyEvent(ImGuiMod_Shift, (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS));
309 io.AddKeyEvent(ImGuiMod_Alt, (glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS));
310 io.AddKeyEvent(ImGuiMod_Super, (glfwGetKey(window, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS));
311}
312
313static bool ImGui_ImplGlfw_ShouldChainCallback(GLFWwindow* window)
314{
316 return bd->CallbacksChainForAllWindows ? true : (window == bd->Window);
317}
318
319void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
320{
323 bd->PrevUserCallbackMousebutton(window, button, action, mods);
324
326
327 ImGuiIO& io = ImGui::GetIO();
328 if (button >= 0 && button < ImGuiMouseButton_COUNT)
329 io.AddMouseButtonEvent(button, action == GLFW_PRESS);
330}
331
332void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
333{
336 bd->PrevUserCallbackScroll(window, xoffset, yoffset);
337
338#ifdef __EMSCRIPTEN__
339 // Ignore GLFW events: will be processed in ImGui_ImplEmscripten_WheelCallback().
340 return;
341#endif
342
343 ImGuiIO& io = ImGui::GetIO();
344 io.AddMouseWheelEvent((float)xoffset, (float)yoffset);
345}
346
347static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode)
348{
349#if GLFW_HAS_GETKEYNAME && !defined(__EMSCRIPTEN__)
350 // GLFW 3.1+ attempts to "untranslate" keys, which goes the opposite of what every other framework does, making using lettered shortcuts difficult.
351 // (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)
352 // See https://github.com/glfw/glfw/issues/1502 for details.
353 // Adding a workaround to undo this (so our keys are translated->untranslated->translated, likely a lossy process).
354 // This won't cover edge cases but this is at least going to cover common cases.
355 if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_EQUAL)
356 return key;
357 GLFWerrorfun prev_error_callback = glfwSetErrorCallback(nullptr);
358 const char* key_name = glfwGetKeyName(key, scancode);
359 glfwSetErrorCallback(prev_error_callback);
360#if GLFW_HAS_GETERROR && !defined(__EMSCRIPTEN__) // Eat errors (see #5908)
361 (void)glfwGetError(nullptr);
362#endif
363 if (key_name && key_name[0] != 0 && key_name[1] == 0)
364 {
365 const char char_names[] = "`-=[]\\,;\'./";
366 const int char_keys[] = { GLFW_KEY_GRAVE_ACCENT, GLFW_KEY_MINUS, GLFW_KEY_EQUAL, GLFW_KEY_LEFT_BRACKET, GLFW_KEY_RIGHT_BRACKET, GLFW_KEY_BACKSLASH, GLFW_KEY_COMMA, GLFW_KEY_SEMICOLON, GLFW_KEY_APOSTROPHE, GLFW_KEY_PERIOD, GLFW_KEY_SLASH, 0 };
367 IM_ASSERT(IM_ARRAYSIZE(char_names) == IM_ARRAYSIZE(char_keys));
368 if (key_name[0] >= '0' && key_name[0] <= '9') { key = GLFW_KEY_0 + (key_name[0] - '0'); }
369 else if (key_name[0] >= 'A' && key_name[0] <= 'Z') { key = GLFW_KEY_A + (key_name[0] - 'A'); }
370 else if (key_name[0] >= 'a' && key_name[0] <= 'z') { key = GLFW_KEY_A + (key_name[0] - 'a'); }
371 else if (const char* p = strchr(char_names, key_name[0])) { key = char_keys[p - char_names]; }
372 }
373 // if (action == GLFW_PRESS) printf("key %d scancode %d name '%s'\n", key, scancode, key_name);
374#else
375 IM_UNUSED(scancode);
376#endif
377 return key;
378}
379
380void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, int action, int mods)
381{
383 if (bd->PrevUserCallbackKey != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
384 bd->PrevUserCallbackKey(window, keycode, scancode, action, mods);
385
386 if (action != GLFW_PRESS && action != GLFW_RELEASE)
387 return;
388
390
391 keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode);
392
393 ImGuiIO& io = ImGui::GetIO();
394 ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode);
395 io.AddKeyEvent(imgui_key, (action == GLFW_PRESS));
396 io.SetKeyEventNativeData(imgui_key, keycode, scancode); // To support legacy indexing (<1.87 user code)
397}
398
399void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
400{
403 bd->PrevUserCallbackWindowFocus(window, focused);
404
405 ImGuiIO& io = ImGui::GetIO();
406 io.AddFocusEvent(focused != 0);
407}
408
409void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y)
410{
413 bd->PrevUserCallbackCursorPos(window, x, y);
414
415 ImGuiIO& io = ImGui::GetIO();
416 io.AddMousePosEvent((float)x, (float)y);
417 bd->LastValidMousePos = ImVec2((float)x, (float)y);
418}
419
420// Workaround: X11 seems to send spurious Leave/Enter events which would make us lose our position,
421// so we back it up and restore on Leave/Enter (see https://github.com/ocornut/imgui/issues/4984)
422void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered)
423{
426 bd->PrevUserCallbackCursorEnter(window, entered);
427
428 ImGuiIO& io = ImGui::GetIO();
429 if (entered)
430 {
431 bd->MouseWindow = window;
432 io.AddMousePosEvent(bd->LastValidMousePos.x, bd->LastValidMousePos.y);
433 }
434 else if (!entered && bd->MouseWindow == window)
435 {
436 bd->LastValidMousePos = io.MousePos;
437 bd->MouseWindow = nullptr;
438 io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
439 }
440}
441
442void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
443{
445 if (bd->PrevUserCallbackChar != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
446 bd->PrevUserCallbackChar(window, c);
447
448 ImGuiIO& io = ImGui::GetIO();
449 io.AddInputCharacter(c);
450}
451
452void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
453{
454 // 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.
455}
456
457#ifdef __EMSCRIPTEN__
458static EM_BOOL ImGui_ImplEmscripten_WheelCallback(int, const EmscriptenWheelEvent* ev, void*)
459{
460 // Mimic Emscripten_HandleWheel() in SDL.
461 // Corresponding equivalent in GLFW JS emulation layer has incorrect quantizing preventing small values. See #6096
462 float multiplier = 0.0f;
463 if (ev->deltaMode == DOM_DELTA_PIXEL) { multiplier = 1.0f / 100.0f; } // 100 pixels make up a step.
464 else if (ev->deltaMode == DOM_DELTA_LINE) { multiplier = 1.0f / 3.0f; } // 3 lines make up a step.
465 else if (ev->deltaMode == DOM_DELTA_PAGE) { multiplier = 80.0f; } // A page makes up 80 steps.
466 float wheel_x = ev->deltaX * -multiplier;
467 float wheel_y = ev->deltaY * -multiplier;
468 ImGuiIO& io = ImGui::GetIO();
469 io.AddMouseWheelEvent(wheel_x, wheel_y);
470 //IMGUI_DEBUG_LOG("[Emsc] mode %d dx: %.2f, dy: %.2f, dz: %.2f --> feed %.2f %.2f\n", (int)ev->deltaMode, ev->deltaX, ev->deltaY, ev->deltaZ, wheel_x, wheel_y);
471 return EM_TRUE;
472}
473#endif
474
475#ifdef _WIN32
476// GLFW doesn't allow to distinguish Mouse vs TouchScreen vs Pen.
477// Add support for Win32 (based on imgui_impl_win32), because we rely on _TouchScreen info to trickle inputs differently.
478static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo()
479{
480 LPARAM extra_info = ::GetMessageExtraInfo();
481 if ((extra_info & 0xFFFFFF80) == 0xFF515700)
482 return ImGuiMouseSource_Pen;
483 if ((extra_info & 0xFFFFFF80) == 0xFF515780)
484 return ImGuiMouseSource_TouchScreen;
485 return ImGuiMouseSource_Mouse;
486}
487static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
488{
490 switch (msg)
491 {
492 case WM_MOUSEMOVE: case WM_NCMOUSEMOVE:
493 case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_LBUTTONUP:
494 case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: case WM_RBUTTONUP:
495 case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: case WM_MBUTTONUP:
496 case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: case WM_XBUTTONUP:
497 ImGui::GetIO().AddMouseSourceEvent(GetMouseSourceFromMessageExtraInfo());
498 break;
499 }
500 return ::CallWindowProcW(bd->GlfwWndProc, hWnd, msg, wParam, lParam);
501}
502#endif
503
504void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window)
505{
507 IM_ASSERT(bd->InstalledCallbacks == false && "Callbacks already installed!");
508 IM_ASSERT(bd->Window == window);
509
510 bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback);
511 bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback);
512 bd->PrevUserCallbackCursorPos = glfwSetCursorPosCallback(window, ImGui_ImplGlfw_CursorPosCallback);
513 bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
514 bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
515 bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
516 bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
517 bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
518 bd->InstalledCallbacks = true;
519}
520
521void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window)
522{
524 IM_ASSERT(bd->InstalledCallbacks == true && "Callbacks not installed!");
525 IM_ASSERT(bd->Window == window);
526
527 glfwSetWindowFocusCallback(window, bd->PrevUserCallbackWindowFocus);
528 glfwSetCursorEnterCallback(window, bd->PrevUserCallbackCursorEnter);
529 glfwSetCursorPosCallback(window, bd->PrevUserCallbackCursorPos);
530 glfwSetMouseButtonCallback(window, bd->PrevUserCallbackMousebutton);
531 glfwSetScrollCallback(window, bd->PrevUserCallbackScroll);
532 glfwSetKeyCallback(window, bd->PrevUserCallbackKey);
533 glfwSetCharCallback(window, bd->PrevUserCallbackChar);
534 glfwSetMonitorCallback(bd->PrevUserCallbackMonitor);
535 bd->InstalledCallbacks = false;
536 bd->PrevUserCallbackWindowFocus = nullptr;
537 bd->PrevUserCallbackCursorEnter = nullptr;
538 bd->PrevUserCallbackCursorPos = nullptr;
539 bd->PrevUserCallbackMousebutton = nullptr;
540 bd->PrevUserCallbackScroll = nullptr;
541 bd->PrevUserCallbackKey = nullptr;
542 bd->PrevUserCallbackChar = nullptr;
543 bd->PrevUserCallbackMonitor = nullptr;
544}
545
546// Set to 'true' to enable chaining installed callbacks for all windows (including secondary viewports created by backends or by user.
547// This is 'false' by default meaning we only chain callbacks for the main viewport.
548// We cannot set this to 'true' by default because user callbacks code may be not testing the 'window' parameter of their callback.
549// If you set this to 'true' your user callback code will need to make sure you are testing the 'window' parameter.
550void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows)
551{
553 bd->CallbacksChainForAllWindows = chain_for_all_windows;
554}
555
556static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
557{
558 ImGuiIO& io = ImGui::GetIO();
559 IMGUI_CHECKVERSION();
560 IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
561 //printf("GLFW_VERSION: %d.%d.%d (%d)", GLFW_VERSION_MAJOR, GLFW_VERSION_MINOR, GLFW_VERSION_REVISION, GLFW_VERSION_COMBINED);
562
563 // Setup backend capabilities flags
565 io.BackendPlatformUserData = (void*)bd;
566 io.BackendPlatformName = "imgui_impl_glfw";
567 io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
568 io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
569
570 bd->Window = window;
571 bd->Time = 0.0;
572
573 io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
574 io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
575 io.ClipboardUserData = bd->Window;
576
577 // Create mouse cursors
578 // (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
579 // GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
580 // Missing cursors will return nullptr and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
581 GLFWerrorfun prev_error_callback = glfwSetErrorCallback(nullptr);
582 bd->MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
583 bd->MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
584 bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
585 bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
586 bd->MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
587#if GLFW_HAS_NEW_CURSORS
588 bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
589 bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
590 bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
591 bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
592#else
593 bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
594 bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
595 bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
596 bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
597#endif
598 glfwSetErrorCallback(prev_error_callback);
599#if GLFW_HAS_GETERROR && !defined(__EMSCRIPTEN__) // Eat errors (see #5908)
600 (void)glfwGetError(nullptr);
601#endif
602
603 // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
604 if (install_callbacks)
606 // Register Emscripten Wheel callback to workaround issue in Emscripten GLFW Emulation (#6096)
607 // We intentionally do not check 'if (install_callbacks)' here, as some users may set it to false and call GLFW callback themselves.
608 // FIXME: May break chaining in case user registered their own Emscripten callback?
609#ifdef __EMSCRIPTEN__
610 emscripten_set_wheel_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, nullptr, false, ImGui_ImplEmscripten_WheelCallback);
611#endif
612
613 // Set platform dependent data in viewport
614 ImGuiViewport* main_viewport = ImGui::GetMainViewport();
615#ifdef _WIN32
616 main_viewport->PlatformHandleRaw = glfwGetWin32Window(bd->Window);
617#elif defined(__APPLE__)
618 main_viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(bd->Window);
619#else
620 IM_UNUSED(main_viewport);
621#endif
622
623 // Windows: register a WndProc hook so we can intercept some messages.
624#ifdef _WIN32
625 bd->GlfwWndProc = (WNDPROC)::GetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC);
626 IM_ASSERT(bd->GlfwWndProc != nullptr);
627 ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc);
628#endif
629
630 bd->ClientApi = client_api;
631 return true;
632}
633
634bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
635{
636 return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
637}
638
639bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
640{
641 return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
642}
643
644bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks)
645{
646 return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown);
647}
648
650{
652 IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
653 ImGuiIO& io = ImGui::GetIO();
654
655 if (bd->InstalledCallbacks)
657#ifdef __EMSCRIPTEN__
658 emscripten_set_wheel_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, nullptr, false, nullptr);
659#endif
660
661 for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
662 glfwDestroyCursor(bd->MouseCursors[cursor_n]);
663
664 // Windows: register a WndProc hook so we can intercept some messages.
665#ifdef _WIN32
666 ImGuiViewport* main_viewport = ImGui::GetMainViewport();
667 ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)bd->GlfwWndProc);
668 bd->GlfwWndProc = nullptr;
669#endif
670
671 io.BackendPlatformName = nullptr;
672 io.BackendPlatformUserData = nullptr;
673 io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad);
674 IM_DELETE(bd);
675}
676
678{
680 ImGuiIO& io = ImGui::GetIO();
681
682 // (those braces are here to reduce diff with multi-viewports support in 'docking' branch)
683 {
684 GLFWwindow* window = bd->Window;
685#ifdef __EMSCRIPTEN__
686 const bool is_window_focused = true;
687#else
688 const bool is_window_focused = glfwGetWindowAttrib(window, GLFW_FOCUSED) != 0;
689#endif
690 if (is_window_focused)
691 {
692 // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
693 if (io.WantSetMousePos)
694 glfwSetCursorPos(window, (double)io.MousePos.x, (double)io.MousePos.y);
695
696 // (Optional) Fallback to provide mouse position when focused (ImGui_ImplGlfw_CursorPosCallback already provides this when hovered or captured)
697 if (bd->MouseWindow == nullptr)
698 {
699 double mouse_x, mouse_y;
700 glfwGetCursorPos(window, &mouse_x, &mouse_y);
701 bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y);
702 io.AddMousePosEvent((float)mouse_x, (float)mouse_y);
703 }
704 }
705 }
706}
707
709{
710 ImGuiIO& io = ImGui::GetIO();
712 if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
713 return;
714
715 ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
716 // (those braces are here to reduce diff with multi-viewports support in 'docking' branch)
717 {
718 GLFWwindow* window = bd->Window;
719 if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
720 {
721 // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
722 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
723 }
724 else
725 {
726 // Show OS mouse cursor
727 // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
728 glfwSetCursor(window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
729 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
730 }
731 }
732}
733
734// Update gamepad inputs
735static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; }
737{
738 ImGuiIO& io = ImGui::GetIO();
739 if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs.
740 return;
741
742 io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
743#if GLFW_HAS_GAMEPAD_API && !defined(__EMSCRIPTEN__)
744 GLFWgamepadstate gamepad;
745 if (!glfwGetGamepadState(GLFW_JOYSTICK_1, &gamepad))
746 return;
747 #define MAP_BUTTON(KEY_NO, BUTTON_NO, _UNUSED) do { io.AddKeyEvent(KEY_NO, gamepad.buttons[BUTTON_NO] != 0); } while (0)
748 #define MAP_ANALOG(KEY_NO, AXIS_NO, _UNUSED, V0, V1) do { float v = gamepad.axes[AXIS_NO]; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0)
749#else
750 int axes_count = 0, buttons_count = 0;
751 const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
752 const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
753 if (axes_count == 0 || buttons_count == 0)
754 return;
755 #define MAP_BUTTON(KEY_NO, _UNUSED, BUTTON_NO) do { io.AddKeyEvent(KEY_NO, (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS)); } while (0)
756 #define MAP_ANALOG(KEY_NO, _UNUSED, AXIS_NO, V0, V1) do { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0)
757#endif
758 io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
759 MAP_BUTTON(ImGuiKey_GamepadStart, GLFW_GAMEPAD_BUTTON_START, 7);
760 MAP_BUTTON(ImGuiKey_GamepadBack, GLFW_GAMEPAD_BUTTON_BACK, 6);
761 MAP_BUTTON(ImGuiKey_GamepadFaceLeft, GLFW_GAMEPAD_BUTTON_X, 2); // Xbox X, PS Square
762 MAP_BUTTON(ImGuiKey_GamepadFaceRight, GLFW_GAMEPAD_BUTTON_B, 1); // Xbox B, PS Circle
763 MAP_BUTTON(ImGuiKey_GamepadFaceUp, GLFW_GAMEPAD_BUTTON_Y, 3); // Xbox Y, PS Triangle
764 MAP_BUTTON(ImGuiKey_GamepadFaceDown, GLFW_GAMEPAD_BUTTON_A, 0); // Xbox A, PS Cross
765 MAP_BUTTON(ImGuiKey_GamepadDpadLeft, GLFW_GAMEPAD_BUTTON_DPAD_LEFT, 13);
766 MAP_BUTTON(ImGuiKey_GamepadDpadRight, GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, 11);
767 MAP_BUTTON(ImGuiKey_GamepadDpadUp, GLFW_GAMEPAD_BUTTON_DPAD_UP, 10);
768 MAP_BUTTON(ImGuiKey_GamepadDpadDown, GLFW_GAMEPAD_BUTTON_DPAD_DOWN, 12);
769 MAP_BUTTON(ImGuiKey_GamepadL1, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER, 4);
770 MAP_BUTTON(ImGuiKey_GamepadR1, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER, 5);
771 MAP_ANALOG(ImGuiKey_GamepadL2, GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, 4, -0.75f, +1.0f);
772 MAP_ANALOG(ImGuiKey_GamepadR2, GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, 5, -0.75f, +1.0f);
773 MAP_BUTTON(ImGuiKey_GamepadL3, GLFW_GAMEPAD_BUTTON_LEFT_THUMB, 8);
774 MAP_BUTTON(ImGuiKey_GamepadR3, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, 9);
775 MAP_ANALOG(ImGuiKey_GamepadLStickLeft, GLFW_GAMEPAD_AXIS_LEFT_X, 0, -0.25f, -1.0f);
776 MAP_ANALOG(ImGuiKey_GamepadLStickRight, GLFW_GAMEPAD_AXIS_LEFT_X, 0, +0.25f, +1.0f);
777 MAP_ANALOG(ImGuiKey_GamepadLStickUp, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, -0.25f, -1.0f);
778 MAP_ANALOG(ImGuiKey_GamepadLStickDown, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, +0.25f, +1.0f);
779 MAP_ANALOG(ImGuiKey_GamepadRStickLeft, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, -0.25f, -1.0f);
780 MAP_ANALOG(ImGuiKey_GamepadRStickRight, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, +0.25f, +1.0f);
781 MAP_ANALOG(ImGuiKey_GamepadRStickUp, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, -0.25f, -1.0f);
782 MAP_ANALOG(ImGuiKey_GamepadRStickDown, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, +0.25f, +1.0f);
783 #undef MAP_BUTTON
784 #undef MAP_ANALOG
785}
786
788{
789 ImGuiIO& io = ImGui::GetIO();
791 IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplGlfw_InitForXXX()?");
792
793 // Setup display size (every frame to accommodate for window resizing)
794 int w, h;
795 int display_w, display_h;
796 glfwGetWindowSize(bd->Window, &w, &h);
797 glfwGetFramebufferSize(bd->Window, &display_w, &display_h);
798 io.DisplaySize = ImVec2((float)w, (float)h);
799 if (w > 0 && h > 0)
800 io.DisplayFramebufferScale = ImVec2((float)display_w / (float)w, (float)display_h / (float)h);
801
802 // Setup time step
803 // (Accept glfwGetTime() not returning a monotonically increasing value. Seems to happens on disconnecting peripherals and probably on VMs and Emscripten, see #6491, #6189, #6114, #3644)
804 double current_time = glfwGetTime();
805 if (current_time <= bd->Time)
806 current_time = bd->Time + 0.00001f;
807 io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
808 bd->Time = current_time;
809
812
813 // Update game controllers (if enabled and available)
815}
816
817#ifdef __EMSCRIPTEN__
818static EM_BOOL ImGui_ImplGlfw_OnCanvasSizeChange(int event_type, const EmscriptenUiEvent* event, void* user_data)
819{
821 double canvas_width, canvas_height;
822 emscripten_get_element_css_size(bd->CanvasSelector, &canvas_width, &canvas_height);
823 glfwSetWindowSize(bd->Window, (int)canvas_width, (int)canvas_height);
824 return true;
825}
826
827static EM_BOOL ImGui_ImplEmscripten_FullscreenChangeCallback(int event_type, const EmscriptenFullscreenChangeEvent* event, void* user_data)
828{
830 double canvas_width, canvas_height;
831 emscripten_get_element_css_size(bd->CanvasSelector, &canvas_width, &canvas_height);
832 glfwSetWindowSize(bd->Window, (int)canvas_width, (int)canvas_height);
833 return true;
834}
835
836// 'canvas_selector' is a CSS selector. The event listener is applied to the first element that matches the query.
837// STRING MUST PERSIST FOR THE APPLICATION DURATION. PLEASE USE A STRING LITERAL OR ENSURE POINTER WILL STAY VALID.
838void ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback(const char* canvas_selector)
839{
840 IM_ASSERT(canvas_selector != nullptr);
842 IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplGlfw_InitForXXX()?");
843
844 bd->CanvasSelector = canvas_selector;
845 emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, bd, false, ImGui_ImplGlfw_OnCanvasSizeChange);
846 emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, bd, false, ImGui_ImplEmscripten_FullscreenChangeCallback);
847
848 // Change the size of the GLFW window according to the size of the canvas
849 ImGui_ImplGlfw_OnCanvasSizeChange(EMSCRIPTEN_EVENT_RESIZE, {}, bd);
850}
851#endif
852
853//-----------------------------------------------------------------------------
854
855#if defined(__clang__)
856#pragma clang diagnostic pop
857#endif
858
859#endif // #ifndef IMGUI_DISABLE
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow *window, int button, int action, int mods)
void ImGui_ImplGlfw_NewFrame()
#define MAP_BUTTON(KEY_NO, _UNUSED, BUTTON_NO)
static bool ImGui_ImplGlfw_ShouldChainCallback(GLFWwindow *window)
void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow *window, int entered)
static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode)
bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow *window, bool install_callbacks)
static ImGui_ImplGlfw_Data * ImGui_ImplGlfw_GetBackendData()
static const char * ImGui_ImplGlfw_GetClipboardText(void *user_data)
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow *window, double xoffset, double yoffset)
static bool ImGui_ImplGlfw_Init(GLFWwindow *window, bool install_callbacks, GlfwClientApi client_api)
void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow *window, int focused)
void ImGui_ImplGlfw_KeyCallback(GLFWwindow *window, int keycode, int scancode, int action, int mods)
static void ImGui_ImplGlfw_UpdateGamepads()
void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow *window)
static float Saturate(float v)
static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key)
static void ImGui_ImplGlfw_UpdateMouseCursor()
void ImGui_ImplGlfw_Shutdown()
void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor *, int)
#define MAP_ANALOG(KEY_NO, _UNUSED, AXIS_NO, V0, V1)
void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow *window)
bool ImGui_ImplGlfw_InitForOther(GLFWwindow *window, bool install_callbacks)
static void ImGui_ImplGlfw_SetClipboardText(void *user_data, const char *text)
GlfwClientApi
@ GlfwClientApi_OpenGL
@ GlfwClientApi_Unknown
@ GlfwClientApi_Vulkan
static void ImGui_ImplGlfw_UpdateKeyModifiers(GLFWwindow *window)
bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow *window, bool install_callbacks)
static void ImGui_ImplGlfw_UpdateMouseData()
void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows)
void ImGui_ImplGlfw_CharCallback(GLFWwindow *window, unsigned int c)
void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow *window, double x, double y)
GLFWcursorenterfun PrevUserCallbackCursorEnter
GLFWscrollfun PrevUserCallbackScroll
GLFWmousebuttonfun PrevUserCallbackMousebutton
GLFWcharfun PrevUserCallbackChar
GLFWcursorposfun PrevUserCallbackCursorPos
GLFWmonitorfun PrevUserCallbackMonitor
GLFWwindowfocusfun PrevUserCallbackWindowFocus
GLFWcursor * MouseCursors[ImGuiMouseCursor_COUNT]