From c9cd6adf53186102bb5f58699a3a45a97eb2ad57 Mon Sep 17 00:00:00 2001 From: netdex Date: Sat, 12 Sep 2020 14:58:28 -0400 Subject: [PATCH] twinhook: extract imgui_impl_win32 and remove XInput dependency #26 deps: shuffle dependency wrapper projects into another directory --- twinhook/gfx/imgui_impl_win32.cpp | 276 ++++++++++++++++++ twinhook/gfx/imgui_impl_win32.h | 21 ++ twinhook/twinhook.vcxproj | 14 +- twinhook/twinhook.vcxproj.filters | 6 + twinject.sln | 4 +- twinject/twinject.vcxproj | 6 +- {Detours => vcxproj/Detours}/Detours.props | 0 {Detours => vcxproj/Detours}/Detours.vcxproj | 30 +- .../Detours}/Detours.vcxproj.filters | 50 ++-- {ImGui => vcxproj/ImGui}/ImGui.props | 0 {ImGui => vcxproj/ImGui}/ImGui.vcxproj | 18 +- .../ImGui}/ImGui.vcxproj.filters | 30 +- 12 files changed, 390 insertions(+), 65 deletions(-) create mode 100644 twinhook/gfx/imgui_impl_win32.cpp create mode 100644 twinhook/gfx/imgui_impl_win32.h rename {Detours => vcxproj/Detours}/Detours.props (100%) rename {Detours => vcxproj/Detours}/Detours.vcxproj (77%) rename {Detours => vcxproj/Detours}/Detours.vcxproj.filters (59%) rename {ImGui => vcxproj/ImGui}/ImGui.props (100%) rename {ImGui => vcxproj/ImGui}/ImGui.vcxproj (86%) rename {ImGui => vcxproj/ImGui}/ImGui.vcxproj.filters (61%) diff --git a/twinhook/gfx/imgui_impl_win32.cpp b/twinhook/gfx/imgui_impl_win32.cpp new file mode 100644 index 0000000..2075ad8 --- /dev/null +++ b/twinhook/gfx/imgui_impl_win32.cpp @@ -0,0 +1,276 @@ +// 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: +// [X] Platform: Clipboard support (for Win32 this is actually part of core imgui) +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE). +// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. + +#include "imgui.h" +#include "imgui_impl_win32.h" +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include + +// CHANGELOG +// (minor and older changes stripped away, please see git history for details) +// 2019-05-11: Inputs: Don't filter value from WM_CHAR before calling AddInputCharacter(). +// 2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent. +// 2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages. +// 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application). +// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. +// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. +// 2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads). +// 2018-06-08: Misc: Extracted imgui_impl_win32.cpp/.h away from the old combined DX9/DX10/DX11/DX12 examples. +// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag. +// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling). +// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space. +// 2018-02-06: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set). +// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. +// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support. +// 2018-01-08: Inputs: Added mapping for ImGuiKey_Insert. +// 2018-01-05: Inputs: Added WM_LBUTTONDBLCLK double-click handlers for window classes with the CS_DBLCLKS flag. +// 2017-10-23: Inputs: Added WM_SYSKEYDOWN / WM_SYSKEYUP handlers so e.g. the VK_MENU key can be read. +// 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging. +// 2016-11-12: Inputs: Only call Win32 ::SetCursor(NULL) when io.MouseDrawCursor is set. + +// Win32 Data +static HWND g_hWnd = 0; +static INT64 g_Time = 0; +static INT64 g_TicksPerSecond = 0; +static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT; +static bool g_HasGamepad = false; +static bool g_WantUpdateHasGamepad = true; + +// Functions +bool ImGui_ImplWin32_Init(void* hwnd) +{ + if (!::QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond)) + return false; + if (!::QueryPerformanceCounter((LARGE_INTEGER *)&g_Time)) + return false; + + // Setup back-end capabilities flags + g_hWnd = (HWND)hwnd; + 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_win32"; + io.ImeWindowHandle = hwnd; + + // 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] = VK_TAB; + io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; + io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; + io.KeyMap[ImGuiKey_UpArrow] = VK_UP; + io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN; + io.KeyMap[ImGuiKey_PageUp] = VK_PRIOR; + io.KeyMap[ImGuiKey_PageDown] = VK_NEXT; + io.KeyMap[ImGuiKey_Home] = VK_HOME; + io.KeyMap[ImGuiKey_End] = VK_END; + io.KeyMap[ImGuiKey_Insert] = VK_INSERT; + io.KeyMap[ImGuiKey_Delete] = VK_DELETE; + io.KeyMap[ImGuiKey_Backspace] = VK_BACK; + io.KeyMap[ImGuiKey_Space] = VK_SPACE; + io.KeyMap[ImGuiKey_Enter] = VK_RETURN; + io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE; + io.KeyMap[ImGuiKey_A] = 'A'; + io.KeyMap[ImGuiKey_C] = 'C'; + io.KeyMap[ImGuiKey_V] = 'V'; + io.KeyMap[ImGuiKey_X] = 'X'; + io.KeyMap[ImGuiKey_Y] = 'Y'; + io.KeyMap[ImGuiKey_Z] = 'Z'; + + return true; +} + +void ImGui_ImplWin32_Shutdown() +{ + g_hWnd = (HWND)0; +} + +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); + POINT pos; + if (HWND active_window = ::GetForegroundWindow()) + if (active_window == g_hWnd || ::IsChild(active_window, g_hWnd)) + if (::GetCursorPos(&pos) && ::ScreenToClient(g_hWnd, &pos)) + io.MousePos = ImVec2((float)pos.x, (float)pos.y); +} + +// Gamepad navigation mapping +static void ImGui_ImplWin32_UpdateGamepads() +{ + ImGuiIO& io = ImGui::GetIO(); + IM_ASSERT(!(io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad)); +} + +void ImGui_ImplWin32_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) + RECT rect; + ::GetClientRect(g_hWnd, &rect); + 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(); +} + +// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions. +#ifndef WM_MOUSEHWHEEL +#define WM_MOUSEHWHEEL 0x020E +#endif +#ifndef DBT_DEVNODES_CHANGED +#define DBT_DEVNODES_CHANGED 0x0007 +#endif + +// 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 LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (ImGui::GetCurrentContext() == NULL) + return 0; + + ImGuiIO& io = ImGui::GetIO(); + switch (msg) + { + case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: + case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: + case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: + case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: + { + int button = 0; + if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; } + if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; } + if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; } + if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; } + if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL) + ::SetCapture(hwnd); + io.MouseDown[button] = true; + return 0; + } + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case WM_XBUTTONUP: + { + int button = 0; + if (msg == WM_LBUTTONUP) { button = 0; } + if (msg == WM_RBUTTONUP) { button = 1; } + if (msg == WM_MBUTTONUP) { button = 2; } + if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; } + io.MouseDown[button] = false; + if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd) + ::ReleaseCapture(); + return 0; + } + case WM_MOUSEWHEEL: + io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA; + return 0; + case WM_MOUSEHWHEEL: + io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA; + return 0; + 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_SETCURSOR: + if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor()) + return 1; + return 0; + case WM_DEVICECHANGE: + if ((UINT)wParam == DBT_DEVNODES_CHANGED) + g_WantUpdateHasGamepad = true; + return 0; + } + return 0; +} + diff --git a/twinhook/gfx/imgui_impl_win32.h b/twinhook/gfx/imgui_impl_win32.h new file mode 100644 index 0000000..7616186 --- /dev/null +++ b/twinhook/gfx/imgui_impl_win32.h @@ -0,0 +1,21 @@ +// 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: +// [X] Platform: Clipboard support (for Win32 this is actually part of core imgui) +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE). +// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. + +#pragma once + +IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd); +IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame(); + +// Handler for Win32 messages, update mouse/keyboard data. +// You may or not need this for your implementation, but it can serve as reference for handling inputs. +// Intentionally commented out to avoid dragging dependencies on types. You can COPY this line into your .cpp code instead. +/* +IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +*/ diff --git a/twinhook/twinhook.vcxproj b/twinhook/twinhook.vcxproj index dbbb4fb..2cd01f4 100644 --- a/twinhook/twinhook.vcxproj +++ b/twinhook/twinhook.vcxproj @@ -39,13 +39,13 @@ - - + + - - + + @@ -149,6 +149,7 @@ + @@ -193,6 +194,7 @@ + @@ -241,10 +243,10 @@ - + {66ec5a9d-6965-4557-87c8-821a089bb8c8} - + {df399789-7f8c-404a-beff-b93671197597} diff --git a/twinhook/twinhook.vcxproj.filters b/twinhook/twinhook.vcxproj.filters index c602f3d..a8e3a70 100644 --- a/twinhook/twinhook.vcxproj.filters +++ b/twinhook/twinhook.vcxproj.filters @@ -135,6 +135,9 @@ Source Files + + Source Files + @@ -287,5 +290,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/twinject.sln b/twinject.sln index 77f1f2b..24fcd1d 100644 --- a/twinject.sln +++ b/twinject.sln @@ -10,9 +10,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "twinject", "twinject\twinje EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "twinhook", "twinhook\twinhook.vcxproj", "{A47B2FB1-6209-46DC-AA46-17F03164F7D8}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImGui", "ImGui\ImGui.vcxproj", "{DF399789-7F8C-404A-BEFF-B93671197597}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImGui", "vcxproj\ImGui\ImGui.vcxproj", "{DF399789-7F8C-404A-BEFF-B93671197597}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Detours", "Detours\Detours.vcxproj", "{66EC5A9D-6965-4557-87C8-821A089BB8C8}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Detours", "vcxproj\Detours\Detours.vcxproj", "{66EC5A9D-6965-4557-87C8-821A089BB8C8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/twinject/twinject.vcxproj b/twinject/twinject.vcxproj index 81fd5d8..6558cfd 100644 --- a/twinject/twinject.vcxproj +++ b/twinject/twinject.vcxproj @@ -38,11 +38,11 @@ - + - + @@ -103,7 +103,7 @@ - + {66ec5a9d-6965-4557-87c8-821a089bb8c8} diff --git a/Detours/Detours.props b/vcxproj/Detours/Detours.props similarity index 100% rename from Detours/Detours.props rename to vcxproj/Detours/Detours.props diff --git a/Detours/Detours.vcxproj b/vcxproj/Detours/Detours.vcxproj similarity index 77% rename from Detours/Detours.vcxproj rename to vcxproj/Detours/Detours.vcxproj index c2a2548..fdc6ca3 100644 --- a/Detours/Detours.vcxproj +++ b/vcxproj/Detours/Detours.vcxproj @@ -59,24 +59,26 @@ nmake clean - - - - - - - - - - - + + + + - - + - + + + + + + + + + + + diff --git a/Detours/Detours.vcxproj.filters b/vcxproj/Detours/Detours.vcxproj.filters similarity index 59% rename from Detours/Detours.vcxproj.filters rename to vcxproj/Detours/Detours.vcxproj.filters index 8da6222..7b4e5c8 100644 --- a/Detours/Detours.vcxproj.filters +++ b/vcxproj/Detours/Detours.vcxproj.filters @@ -15,49 +15,55 @@ - + + Source Files + + + Source Files + + + Header Files + + + Header Files + + + + + + + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - - - Header Files - - - Header Files - - - - - \ No newline at end of file diff --git a/ImGui/ImGui.props b/vcxproj/ImGui/ImGui.props similarity index 100% rename from ImGui/ImGui.props rename to vcxproj/ImGui/ImGui.props diff --git a/ImGui/ImGui.vcxproj b/vcxproj/ImGui/ImGui.vcxproj similarity index 86% rename from ImGui/ImGui.vcxproj rename to vcxproj/ImGui/ImGui.vcxproj index dedc86b..36b5e61 100644 --- a/ImGui/ImGui.vcxproj +++ b/vcxproj/ImGui/ImGui.vcxproj @@ -72,15 +72,19 @@ - - - - - - + - + + + + + + + + + + diff --git a/ImGui/ImGui.vcxproj.filters b/vcxproj/ImGui/ImGui.vcxproj.filters similarity index 61% rename from ImGui/ImGui.vcxproj.filters rename to vcxproj/ImGui/ImGui.vcxproj.filters index 5210d95..be67a63 100644 --- a/ImGui/ImGui.vcxproj.filters +++ b/vcxproj/ImGui/ImGui.vcxproj.filters @@ -15,26 +15,34 @@ - - Source Files - - + + + + + Header Files + + + Header Files + + + Header Files + + + + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - - - \ No newline at end of file