// dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications) // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) // Implemented features: // [?] Platform: Clipboard support // [?] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [?] Platform: Keyboard arrays indexed using // [?] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. #include "imgui.h" #include "imgui_impl_x11.h" #include #include #include #include // CHANGELOG // (minor and older changes stripped away, please see git history for details) // 2019-08-31: Initial X11 implementation // X11 Data static Display* g_Display = nullptr; static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT; static bool g_HasGamepad = false; static bool g_WantUpdateHasGamepad = true; // Functions bool ImGui_ImplX11_Init(void *display) { //if (!::QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond)) // return false; //if (!::QueryPerformanceCounter((LARGE_INTEGER *)&g_Time)) // return false; // Setup back-end capabilities flags g_Display = reinterpret_cast(display); ImGuiIO& io = ImGui::GetIO(); io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) io.BackendPlatformName = "imgui_impl_x11"; io.ImeWindowHandle = nullptr; // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime. io.KeyMap[ImGuiKey_Tab] = -1; io.KeyMap[ImGuiKey_LeftArrow] = -1; io.KeyMap[ImGuiKey_RightArrow] = -1; io.KeyMap[ImGuiKey_UpArrow] = -1; io.KeyMap[ImGuiKey_DownArrow] = -1; io.KeyMap[ImGuiKey_PageUp] = -1; io.KeyMap[ImGuiKey_PageDown] = -1; io.KeyMap[ImGuiKey_Home] = -1; io.KeyMap[ImGuiKey_End] = -1; io.KeyMap[ImGuiKey_Insert] = -1; io.KeyMap[ImGuiKey_Delete] = -1; io.KeyMap[ImGuiKey_Backspace] = -1; io.KeyMap[ImGuiKey_Space] = -1; io.KeyMap[ImGuiKey_Enter] = -1; io.KeyMap[ImGuiKey_Escape] = -1; io.KeyMap[ImGuiKey_A] = -1; io.KeyMap[ImGuiKey_C] = -1; io.KeyMap[ImGuiKey_V] = -1; io.KeyMap[ImGuiKey_X] = -1; io.KeyMap[ImGuiKey_Y] = -1; io.KeyMap[ImGuiKey_Z] = -1; return true; } void ImGui_ImplX11_Shutdown() { g_Display = nullptr; } static bool ImGui_ImplWin32_UpdateMouseCursor() { /* ImGuiIO& io = ImGui::GetIO(); if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) return false; ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) { // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor ::SetCursor(NULL); } else { // Show OS mouse cursor LPTSTR win32_cursor = IDC_ARROW; switch (imgui_cursor) { case ImGuiMouseCursor_Arrow: win32_cursor = IDC_ARROW; break; case ImGuiMouseCursor_TextInput: win32_cursor = IDC_IBEAM; break; case ImGuiMouseCursor_ResizeAll: win32_cursor = IDC_SIZEALL; break; case ImGuiMouseCursor_ResizeEW: win32_cursor = IDC_SIZEWE; break; case ImGuiMouseCursor_ResizeNS: win32_cursor = IDC_SIZENS; break; case ImGuiMouseCursor_ResizeNESW: win32_cursor = IDC_SIZENESW; break; case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break; case ImGuiMouseCursor_Hand: win32_cursor = IDC_HAND; break; } ::SetCursor(::LoadCursor(NULL, win32_cursor)); } */ return true; } static void ImGui_ImplWin32_UpdateMousePos() { ImGuiIO& io = ImGui::GetIO(); // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) //if (io.WantSetMousePos) //{ // POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y }; // ::ClientToScreen(g_hWnd, &pos); // ::SetCursorPos(pos.x, pos.y); //} // Set mouse position io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); } /* TODO: support linux gamepad ? #ifdef _MSC_VER #pragma comment(lib, "xinput") #endif // Gamepad navigation mapping static void ImGui_ImplWin32_UpdateGamepads() { ImGuiIO& io = ImGui::GetIO(); memset(io.NavInputs, 0, sizeof(io.NavInputs)); if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) return; // Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow. // Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE. if (g_WantUpdateHasGamepad) { XINPUT_CAPABILITIES caps; g_HasGamepad = (XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS); g_WantUpdateHasGamepad = false; } XINPUT_STATE xinput_state; io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; if (g_HasGamepad && XInputGetState(0, &xinput_state) == ERROR_SUCCESS) { const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad; io.BackendFlags |= ImGuiBackendFlags_HasGamepad; #define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; } #define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; } MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767); #undef MAP_BUTTON #undef MAP_ANALOG } } */ void ImGui_ImplX11_NewFrame() { ImGuiIO& io = ImGui::GetIO(); IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); // Setup display size (every frame to accommodate for window resizing) Window rootWnd = DefaultRootWindow(g_Display); // Todo: use X11 to get this value GLint m_viewport[4]; glGetIntegerv( GL_VIEWPORT, m_viewport ); io.DisplaySize.x = m_viewport[2]; io.DisplaySize.y = m_viewport[3]; /* io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top)); // Setup time step INT64 current_time; ::QueryPerformanceCounter((LARGE_INTEGER *)¤t_time); io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond; g_Time = current_time; // Read keyboard modifiers inputs io.KeyCtrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0; io.KeyShift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0; io.KeyAlt = (::GetKeyState(VK_MENU) & 0x8000) != 0; io.KeySuper = false; // io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below. // Update OS mouse position ImGui_ImplWin32_UpdateMousePos(); // Update OS mouse cursor with the cursor requested by imgui ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor(); if (g_LastMouseCursor != mouse_cursor) { g_LastMouseCursor = mouse_cursor; ImGui_ImplWin32_UpdateMouseCursor(); } */ // Update game controllers (if enabled and available) //ImGui_ImplWin32_UpdateGamepads(); } // Process Win32 mouse/keyboard inputs. // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. // PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds. // PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag. IMGUI_IMPL_API int ImGui_ImplX11_EventHandler(XEvent &event) { if (ImGui::GetCurrentContext() == NULL) return 0; ImGuiIO& io = ImGui::GetIO(); switch (event.type) { case ButtonPress: switch(event.xbutton.button ) { case Button1: case Button2: case Button3: io.MouseDown[event.xbutton.button-1] = true; break; case Button4: // Mouse wheel up event.xbutton.button = Button4; //io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA; return 0; case Button5: // Mouse wheel down event.xbutton.button = Button5; //io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA; return 0; } break; case ButtonRelease: switch(event.xbutton.button ) { case Button1: case Button2: case Button3: io.MouseDown[event.xbutton.button-1] = false; break; } break; case KeyPress: case KeyRelease: break; case MotionNotify: io.MousePos.x = event.xmotion.x; io.MousePos.y = event.xmotion.y; break; } /* case WM_KEYDOWN: case WM_SYSKEYDOWN: if (wParam < 256) io.KeysDown[wParam] = 1; return 0; case WM_KEYUP: case WM_SYSKEYUP: if (wParam < 256) io.KeysDown[wParam] = 0; return 0; case WM_CHAR: // You can also use ToAscii()+GetKeyboardState() to retrieve characters. io.AddInputCharacter((unsigned int)wParam); return 0; case WM_DEVICECHANGE: if ((UINT)wParam == DBT_DEVNODES_CHANGED) g_WantUpdateHasGamepad = true; return 0; } */ return 0; }