From 7e2e0535dd4261f7a9102f9a776f0dd7a5357b45 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 20 Feb 2018 13:55:09 +0100 Subject: [PATCH] Examples: DirectX 9,10,11: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling). (#1495) --- .../directx10_example/imgui_impl_dx10.cpp | 51 +++++++++++++++++-- examples/directx10_example/main.cpp | 2 +- .../directx11_example/imgui_impl_dx11.cpp | 51 +++++++++++++++++-- examples/directx11_example/main.cpp | 2 +- examples/directx9_example/imgui_impl_dx9.cpp | 50 ++++++++++++++++-- examples/directx9_example/main.cpp | 2 +- 6 files changed, 141 insertions(+), 17 deletions(-) diff --git a/examples/directx10_example/imgui_impl_dx10.cpp b/examples/directx10_example/imgui_impl_dx10.cpp index 10da969e..ed1efeef 100644 --- a/examples/directx10_example/imgui_impl_dx10.cpp +++ b/examples/directx10_example/imgui_impl_dx10.cpp @@ -10,6 +10,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling). // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX10_RenderDrawData() in the .h file so you can call it yourself. // 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-02-06: Inputs: Added mapping for ImGuiKey_Space. @@ -32,11 +33,13 @@ #define DIRECTINPUT_VERSION 0x0800 #include -// Data +// Win32 Data +static HWND g_hWnd = 0; static INT64 g_Time = 0; static INT64 g_TicksPerSecond = 0; +static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_Count_; -static HWND g_hWnd = 0; +// DirectX data static ID3D10Device* g_pd3dDevice = NULL; static ID3D10Buffer* g_pVB = NULL; static ID3D10Buffer* g_pIB = NULL; @@ -240,6 +243,33 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release(); } +static void ImGui_ImplWin32_UpdateMouseCursor() +{ + ImGuiIO& io = ImGui::GetIO(); + ImGuiMouseCursor imgui_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor(); + if (imgui_cursor == ImGuiMouseCursor_None) + { + // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor + ::SetCursor(NULL); + } + else + { + // Hardware cursor type + 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; + } + ::SetCursor(::LoadCursor(NULL, win32_cursor)); + } +} + // 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. @@ -306,6 +336,13 @@ IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wPa if (wParam > 0 && wParam < 0x10000) io.AddInputCharacter((unsigned short)wParam); return 0; + case WM_SETCURSOR: + if (LOWORD(lParam) == HTCLIENT) + { + ImGui_ImplWin32_UpdateMouseCursor(); + return 1; + } + return 0; } return 0; } @@ -618,9 +655,13 @@ void ImGui_ImplDX10_NewFrame() SetCursorPos(pos.x, pos.y); } - // Hide OS mouse cursor if ImGui is drawing it - if (io.MouseDrawCursor) - SetCursor(NULL); + // 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(); + } // Start the frame. This call will update the io.WantCaptureMouse, io.WantCaptureKeyboard flag that you can use to dispatch inputs (or not) to your application. ImGui::NewFrame(); diff --git a/examples/directx10_example/main.cpp b/examples/directx10_example/main.cpp index f20f6881..4edf8be6 100644 --- a/examples/directx10_example/main.cpp +++ b/examples/directx10_example/main.cpp @@ -103,7 +103,7 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) int main(int, char**) { // Create application window - WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, LoadCursor(NULL, IDC_ARROW), NULL, NULL, _T("ImGui Example"), NULL }; + WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("ImGui Example"), NULL }; RegisterClassEx(&wc); HWND hwnd = CreateWindow(_T("ImGui Example"), _T("ImGui DirectX10 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index a0e9d7f3..84dcdbee 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -10,6 +10,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling). // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX11_RenderDrawData() in the .h file so you can call it yourself. // 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-02-06: Inputs: Added mapping for ImGuiKey_Space. @@ -31,11 +32,13 @@ #define DIRECTINPUT_VERSION 0x0800 #include -// Data +// Win32 data +static HWND g_hWnd = 0; static INT64 g_Time = 0; static INT64 g_TicksPerSecond = 0; +static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_Count_; -static HWND g_hWnd = 0; +// DirectX data static ID3D11Device* g_pd3dDevice = NULL; static ID3D11DeviceContext* g_pd3dDeviceContext = NULL; static ID3D11Buffer* g_pVB = NULL; @@ -247,6 +250,33 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release(); } +static void ImGui_ImplWin32_UpdateMouseCursor() +{ + ImGuiIO& io = ImGui::GetIO(); + ImGuiMouseCursor imgui_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor(); + if (imgui_cursor == ImGuiMouseCursor_None) + { + // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor + ::SetCursor(NULL); + } + else + { + // Hardware cursor type + 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; + } + ::SetCursor(::LoadCursor(NULL, win32_cursor)); + } +} + // 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. @@ -313,6 +343,13 @@ IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wPa if (wParam > 0 && wParam < 0x10000) io.AddInputCharacter((unsigned short)wParam); return 0; + case WM_SETCURSOR: + if (LOWORD(lParam) == HTCLIENT) + { + ImGui_ImplWin32_UpdateMouseCursor(); + return 1; + } + return 0; } return 0; } @@ -621,9 +658,13 @@ void ImGui_ImplDX11_NewFrame() SetCursorPos(pos.x, pos.y); } - // Hide OS mouse cursor if ImGui is drawing it - if (io.MouseDrawCursor) - SetCursor(NULL); + // 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(); + } // Start the frame. This call will update the io.WantCaptureMouse, io.WantCaptureKeyboard flag that you can use to dispatch inputs (or not) to your application. ImGui::NewFrame(); diff --git a/examples/directx11_example/main.cpp b/examples/directx11_example/main.cpp index f6dc6f74..2ded0a90 100644 --- a/examples/directx11_example/main.cpp +++ b/examples/directx11_example/main.cpp @@ -106,7 +106,7 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) int main(int, char**) { // Create application window - WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, LoadCursor(NULL, IDC_ARROW), NULL, NULL, _T("ImGui Example"), NULL }; + WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("ImGui Example"), NULL }; RegisterClassEx(&wc); HWND hwnd = CreateWindow(_T("ImGui Example"), _T("ImGui DirectX11 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index e960b7c5..194752fb 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -10,6 +10,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling). // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself. // 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-02-06: Inputs: Added mapping for ImGuiKey_Space. @@ -22,10 +23,13 @@ #define DIRECTINPUT_VERSION 0x0800 #include -// Data +// Win32 data static HWND g_hWnd = 0; static INT64 g_Time = 0; static INT64 g_TicksPerSecond = 0; +static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_Count_; + +// DirectX data static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; static LPDIRECT3DINDEXBUFFER9 g_pIB = NULL; @@ -178,6 +182,33 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) d3d9_state_block->Release(); } +static void ImGui_ImplWin32_UpdateMouseCursor() +{ + ImGuiIO& io = ImGui::GetIO(); + ImGuiMouseCursor imgui_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor(); + if (imgui_cursor == ImGuiMouseCursor_None) + { + // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor + ::SetCursor(NULL); + } + else + { + // Hardware cursor type + 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; + } + ::SetCursor(::LoadCursor(NULL, win32_cursor)); + } +} + // 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. @@ -244,6 +275,13 @@ IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wPa if (wParam > 0 && wParam < 0x10000) io.AddInputCharacter((unsigned short)wParam); return 0; + case WM_SETCURSOR: + if (LOWORD(lParam) == HTCLIENT) + { + ImGui_ImplWin32_UpdateMouseCursor(); + return 1; + } + return 0; } return 0; } @@ -387,9 +425,13 @@ void ImGui_ImplDX9_NewFrame() SetCursorPos(pos.x, pos.y); } - // Hide OS mouse cursor if ImGui is drawing it - if (io.MouseDrawCursor) - SetCursor(NULL); + // 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(); + } // Start the frame. This call will update the io.WantCaptureMouse, io.WantCaptureKeyboard flag that you can use to dispatch inputs (or not) to your application. ImGui::NewFrame(); diff --git a/examples/directx9_example/main.cpp b/examples/directx9_example/main.cpp index 16482b3a..f4c7a9f0 100644 --- a/examples/directx9_example/main.cpp +++ b/examples/directx9_example/main.cpp @@ -46,7 +46,7 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) int main(int, char**) { // Create application window - WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, LoadCursor(NULL, IDC_ARROW), NULL, NULL, _T("ImGui Example"), NULL }; + WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("ImGui Example"), NULL }; RegisterClassEx(&wc); HWND hwnd = CreateWindow(_T("ImGui Example"), _T("ImGui DirectX9 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);