// dear imgui: Platform Backend for Universal Windows Platform (standard windows API for 32-bits AND 64-bits applications) // This needs to be used along with a Renderer (e.g. DirectX11, DirectX12, SDL2..) // Implemented features: // [X] Platform: Clipboard support (for Win32 & UWP this is actually part of core dear imgui) // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. // [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). // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. // Read online: https://github.com/ocornut/imgui/tree/master/docs #include "imgui.h" #include "imgui_impl_uwp.h" #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #include #include //WinRT #include #include #include #include using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; // Disabling XInput on older SDKs that didn't allow LoadLibrary for the Application Family #if (NTDDI_VERSION < NTDDI_WIN10_CO) #define IMGUI_IMPL_UWP_DISABLE_GAMEPAD #endif // Using XInput for gamepad (will load DLL dynamically) #ifndef IMGUI_IMPL_UWP_DISABLE_GAMEPAD #include typedef DWORD (WINAPI *PFN_XInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES*); typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*); #endif // From CoreWindow.h typedef HRESULT(_cdecl* PFN_CreateControlInput)(_In_ REFIID riid, _COM_Outptr_ void** ppv); typedef HRESULT(_cdecl* PFN_CreateControlInputEx)(_In_ IUnknown* pCoreWindow, _In_ REFIID riid, _COM_Outptr_ void** ppv); MIDL_INTERFACE("40BFE3E3-B75A-4479-AC96-475365749BB8") ISystemCoreInputInterop : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE SetInputSource(__RPC__in_opt ::IUnknown * value) PURE; virtual HRESULT STDMETHODCALLTYPE put_MessageHandled(boolean value) PURE; }; // Clipboard support #if !defined(IMGUI_DISABLE_UWP_DEFAULT_CLIPBOARD_FUNCTIONS) #include "imgui_internal.h" #include static const char* ImGui_ImplUwp_GetClipboardTextFn(void* user_data_ctx); static void ImGui_ImplUwp_SetClipboardTextFn(void* user_data_ctx, const char* text); #endif struct ImGui_ImplUwp_Data { ABI::Windows::UI::Core::ICoreWindow* CoreWindow; ABI::Windows::UI::Xaml::Controls::ISwapChainPanel* SwapChainPanel; ABI::Windows::UI::Xaml::IFrameworkElement* SwapChainPanelElement; ABI::Windows::UI::Core::ICorePointerInputSource* PointerInputSource; ABI::Windows::UI::Core::ICoreKeyboardInputSource* KeyboardInputSource; int MouseTrackedArea; // 0: not tracked, 1: client area, 2: non-client area int MouseButtonsDown; INT64 Time; INT64 TicksPerSecond; ImGuiMouseCursor LastMouseCursor; ::EventRegistrationToken PointerMovedToken; ::EventRegistrationToken PointerExitedToken; ::EventRegistrationToken KeyDownToken; ::EventRegistrationToken KeyUpToken; ::EventRegistrationToken CharacterReceivedToken; ::EventRegistrationToken PointerWheelChangedToken; ::EventRegistrationToken WindowActivatedToken; ::EventRegistrationToken PointerPressedToken; ::EventRegistrationToken PointerReleasedToken; #ifndef IMGUI_IMPL_UWP_DISABLE_GAMEPAD bool HasGamepad; bool WantUpdateHasGamepad; HMODULE XInputDLL; PFN_XInputGetCapabilities XInputGetCapabilities; PFN_XInputGetState XInputGetState; #endif ImGui_ImplUwp_Data() { memset((void*)this, 0, sizeof(*this)); } }; typedef ABI::Windows::Foundation::ITypedEventHandler<::IInspectable*, ABI::Windows::UI::Core::PointerEventArgs*> PointerMoved_Callback; typedef ABI::Windows::Foundation::ITypedEventHandler<::IInspectable*, ABI::Windows::UI::Core::PointerEventArgs*> PointerExited_Callback; typedef ABI::Windows::Foundation::ITypedEventHandler<::IInspectable*, ABI::Windows::UI::Core::KeyEventArgs*> KeyDown_Callback; typedef ABI::Windows::Foundation::ITypedEventHandler<::IInspectable*, ABI::Windows::UI::Core::CharacterReceivedEventArgs*> CharacterReceived_Callback; typedef ABI::Windows::Foundation::ITypedEventHandler<::IInspectable*, ABI::Windows::UI::Core::PointerEventArgs*> PointerWheelChanged_Callback; typedef ABI::Windows::Foundation::ITypedEventHandler<::IInspectable*, ABI::Windows::UI::Core::PointerEventArgs*> PointerPressed_Callback; typedef ABI::Windows::Foundation::ITypedEventHandler<::IInspectable*, ABI::Windows::UI::Core::PointerEventArgs*> PointerReleased_Callback; int PointerMoved(::IInspectable*, ABI::Windows::UI::Core::IPointerEventArgs*); int PointerExited(::IInspectable*, ABI::Windows::UI::Core::IPointerEventArgs*); int KeyDown(::IInspectable*, ABI::Windows::UI::Core::IKeyEventArgs*); int KeyUp(::IInspectable*, ABI::Windows::UI::Core::IKeyEventArgs*); int CharacterReceived(::IInspectable*, ABI::Windows::UI::Core::ICharacterReceivedEventArgs*); int PointerWheelChanged(::IInspectable*, ABI::Windows::UI::Core::IPointerEventArgs*); int PointerPressed(::IInspectable*, ABI::Windows::UI::Core::IPointerEventArgs*); int PointerReleased(::IInspectable*, ABI::Windows::UI::Core::IPointerEventArgs*); typedef ABI::Windows::Foundation::ITypedEventHandler WindowPointerMoved_Callback; typedef ABI::Windows::Foundation::ITypedEventHandler WindowPointerExited_Callback; typedef ABI::Windows::Foundation::ITypedEventHandler WindowKeyDown_Callback; typedef ABI::Windows::Foundation::ITypedEventHandler WindowCharacterReceived_Callback; typedef ABI::Windows::Foundation::ITypedEventHandler WindowPointerWheelChanged_Callback; typedef ABI::Windows::Foundation::ITypedEventHandler WindowPointerPressed_Callback; typedef ABI::Windows::Foundation::ITypedEventHandler WindowPointerReleased_Callback; typedef ABI::Windows::Foundation::ITypedEventHandler WindowActivated_Callback; int WindowActivated(ABI::Windows::UI::Core::ICoreWindow*, ABI::Windows::UI::Core::IWindowActivatedEventArgs*); // Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts // It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. // FIXME: multi-context support is not well tested and probably dysfunctional in this backend. // FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context. static ImGui_ImplUwp_Data* ImGui_ImplUwp_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplUwp_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr; } static ABI::Windows::UI::Core::ICoreWindow* ImGui_ImplUwp_GetCoreWindowForCurrentThread() { ComPtr windowStatic; ABI::Windows::UI::Core::ICoreWindow* window = nullptr; Windows::Foundation::GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Core_CoreWindow).Get(), &windowStatic); if (windowStatic->GetForCurrentThread(&window) != S_OK) return nullptr; return window; } // Functions static bool ImGui_ImplUwp_InitEx(ABI::Windows::UI::Core::ICoreWindow* core_window, ABI::Windows::UI::Xaml::Controls::ISwapChainPanel* swapchain_panel, bool is_for_current_view) { ImGuiIO& io = ImGui::GetIO(); IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); INT64 perf_frequency, perf_counter; if (!::QueryPerformanceFrequency((LARGE_INTEGER*)&perf_frequency)) return false; if (!::QueryPerformanceCounter((LARGE_INTEGER*)&perf_counter)) return false; // Setup backend capabilities flags ImGui_ImplUwp_Data* bd = IM_NEW(ImGui_ImplUwp_Data)(); io.BackendPlatformUserData = (void*)bd; io.BackendPlatformName = "imgui_impl_uwp"; io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) // Clipboard support #if !defined(IMGUI_DISABLE_UWP_DEFAULT_CLIPBOARD_FUNCTIONS) io.GetClipboardTextFn = ImGui_ImplUwp_GetClipboardTextFn; io.SetClipboardTextFn = ImGui_ImplUwp_SetClipboardTextFn; #endif if (core_window && !is_for_current_view) core_window->AddRef(); if (swapchain_panel) { swapchain_panel->AddRef(); swapchain_panel->QueryInterface(&bd->SwapChainPanelElement); } bd->CoreWindow = core_window; bd->SwapChainPanel = swapchain_panel; bd->TicksPerSecond = perf_frequency; bd->Time = perf_counter; bd->LastMouseCursor = ImGuiMouseCursor_COUNT; // Set platform dependent data in viewport ImGui::GetMainViewport()->PlatformHandleRaw = (void*)core_window; // Dynamically load XInput library #ifndef IMGUI_IMPL_UWP_DISABLE_GAMEPAD bd->WantUpdateHasGamepad = true; const char* xinput_dll_names[] = { "xinput1_4.dll", // Windows 8+ "xinput1_3.dll", // DirectX SDK "xinput9_1_0.dll", // Windows Vista, Windows 7 "xinput1_2.dll", // DirectX SDK "xinput1_1.dll", // DirectX SDK "xinputuap.dll" // OneCoreUAP }; for (int n = 0; n < IM_ARRAYSIZE(xinput_dll_names); n++) if (HMODULE dll = ::LoadLibraryA(xinput_dll_names[n])) { bd->XInputDLL = dll; bd->XInputGetCapabilities = (PFN_XInputGetCapabilities)::GetProcAddress(dll, "XInputGetCapabilities"); bd->XInputGetState = (PFN_XInputGetState)::GetProcAddress(dll, "XInputGetState"); break; } #endif // IMGUI_IMPL_UWP_DISABLE_GAMEPAD /*ComPtr<::IUnknown> controlInput; auto winUI = LoadLibraryW(L"Windows.UI.dll"); auto SystemCreateControlInput = (PFN_CreateControlInput)GetProcAddress(winUI, "CreateControlInput"); auto SystemCreateControlInputEx = (PFN_CreateControlInputEx)GetProcAddress(winUI, "CreateControlInputEx"); if (core_window) { bd->CoreWindow->add_Activated(Callback(WindowActivated).Get(), &bd->WindowActivatedToken); SystemCreateControlInputEx(core_window, ABI::Windows::UI::Core::IID_ICoreInputSourceBase, &controlInput); }*/ if (core_window) { bd->CoreWindow->add_PointerMoved(Callback(PointerMoved).Get(), &bd->PointerMovedToken); bd->CoreWindow->add_PointerExited(Callback(PointerExited).Get(), &bd->PointerExitedToken); bd->CoreWindow->add_PointerWheelChanged(Callback(PointerWheelChanged).Get(), &bd->PointerWheelChangedToken); bd->CoreWindow->add_PointerPressed(Callback(PointerPressed).Get(), &bd->PointerPressedToken); bd->CoreWindow->add_PointerReleased(Callback(PointerReleased).Get(), &bd->PointerReleasedToken); bd->CoreWindow->add_KeyDown(Callback(KeyDown).Get(), &bd->KeyDownToken); bd->CoreWindow->add_KeyUp(Callback(KeyUp).Get(), &bd->KeyUpToken); bd->CoreWindow->add_CharacterReceived(Callback(CharacterReceived).Get(), &bd->CharacterReceivedToken); bd->CoreWindow->add_Activated(Callback(WindowActivated).Get(), &bd->WindowActivatedToken); } else if (swapchain_panel) { ComPtr controlInput; auto winUI = LoadLibraryW(L"Windows.UI.dll"); auto SystemCreateControlInput = (PFN_CreateControlInput)GetProcAddress(winUI, "CreateControlInput"); HRESULT result = SystemCreateControlInput(ABI::Windows::UI::Core::IID_ICoreInputSourceBase, &controlInput); if (SUCCEEDED(result)) { controlInput->put_IsInputEnabled(true); ComPtr coreInputInterop; if (SUCCEEDED(controlInput.As(&coreInputInterop))) { ComPtr elementCompositionPreviewStatics; result = Windows::Foundation::GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Xaml_Hosting_ElementCompositionPreview).Get(), &elementCompositionPreviewStatics); if (SUCCEEDED(result)) { ComPtr uiElement; swapchain_panel->QueryInterface(uiElement.GetAddressOf()); ComPtr visual; elementCompositionPreviewStatics->GetElementVisual(uiElement.Get(), visual.GetAddressOf()); result = coreInputInterop->SetInputSource(visual.Get()); if ( SUCCEEDED(result) && SUCCEEDED(controlInput->QueryInterface(&bd->PointerInputSource)) && SUCCEEDED(controlInput->QueryInterface(&bd->KeyboardInputSource)) ) { bd->PointerInputSource->add_PointerMoved(Callback(PointerMoved).Get(), &bd->PointerMovedToken); bd->PointerInputSource->add_PointerExited(Callback(PointerExited).Get(), &bd->PointerExitedToken); bd->PointerInputSource->add_PointerWheelChanged(Callback(PointerWheelChanged).Get(), &bd->PointerWheelChangedToken); bd->PointerInputSource->add_PointerPressed(Callback(PointerPressed).Get(), &bd->PointerPressedToken); bd->PointerInputSource->add_PointerReleased(Callback(PointerReleased).Get(), &bd->PointerReleasedToken); //bd->KeyboardInputSource->add_KeyDown(Callback(KeyDown).Get(), &bd->KeyDownToken); //bd->KeyboardInputSource->add_KeyUp(Callback(KeyUp).Get(), &bd->KeyUpToken); //bd->KeyboardInputSource->add_CharacterReceived(Callback(CharacterReceived).Get(), &bd->CharacterReceivedToken); ComPtr window = ImGui_ImplUwp_GetCoreWindowForCurrentThread(); if (window.Get()) { window->add_KeyDown(Callback(KeyDown).Get(), &bd->KeyDownToken); window->add_KeyUp(Callback(KeyUp).Get(), &bd->KeyUpToken); window->add_CharacterReceived(Callback(CharacterReceived).Get(), &bd->CharacterReceivedToken); } } } } } } return true; } IMGUI_IMPL_API bool ImGui_ImplUwp_Init(void* core_window) { return ImGui_ImplUwp_InitEx((ABI::Windows::UI::Core::ICoreWindow*)core_window, nullptr, false); } IMGUI_IMPL_API bool ImGui_ImplUwp_InitForCurrentView() { auto window = ImGui_ImplUwp_GetCoreWindowForCurrentThread(); if (!window) return false; return ImGui_ImplUwp_InitEx(window, nullptr, true); } IMGUI_IMPL_API bool ImGui_ImplUwp_InitForSwapChainPanel(void* swapchain_panel) { return ImGui_ImplUwp_InitEx(nullptr, (ABI::Windows::UI::Xaml::Controls::ISwapChainPanel*)swapchain_panel, false); } void ImGui_ImplUwp_Shutdown() { ImGui_ImplUwp_Data* bd = ImGui_ImplUwp_GetBackendData(); IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); // Unload XInput library #ifndef IMGUI_IMPL_UWP_DISABLE_GAMEPAD if (bd->XInputDLL) ::FreeLibrary(bd->XInputDLL); #endif // IMGUI_IMPL_UWP_DISABLE_GAMEPAD io.BackendPlatformName = nullptr; io.BackendPlatformUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad); if (bd->CoreWindow) { bd->CoreWindow->Release(); bd->CoreWindow->remove_PointerMoved(bd->PointerMovedToken); bd->CoreWindow->remove_PointerExited(bd->PointerExitedToken); bd->CoreWindow->remove_KeyDown(bd->KeyDownToken); bd->CoreWindow->remove_KeyUp(bd->KeyUpToken); bd->CoreWindow->remove_CharacterReceived(bd->CharacterReceivedToken); bd->CoreWindow->remove_PointerWheelChanged(bd->PointerWheelChangedToken); bd->CoreWindow->remove_Activated(bd->WindowActivatedToken); bd->CoreWindow->remove_PointerPressed(bd->PointerPressedToken); bd->CoreWindow->remove_PointerReleased(bd->PointerReleasedToken); } else if (bd->SwapChainPanel) { bd->PointerInputSource->remove_PointerMoved(bd->PointerMovedToken); bd->PointerInputSource->remove_PointerExited(bd->PointerExitedToken); bd->PointerInputSource->remove_PointerWheelChanged(bd->PointerWheelChangedToken); bd->PointerInputSource->remove_PointerPressed(bd->PointerPressedToken); bd->PointerInputSource->remove_PointerReleased(bd->PointerReleasedToken); //bd->KeyboardInputSource->remove_KeyDown(bd->KeyDownToken); //bd->KeyboardInputSource->remove_KeyUp(bd->KeyUpToken); //bd->KeyboardInputSource->remove_CharacterReceived(bd->CharacterReceivedToken); ComPtr window = ImGui_ImplUwp_GetCoreWindowForCurrentThread(); if (window.Get()) { window->remove_KeyDown(bd->KeyDownToken); window->remove_KeyUp(bd->KeyUpToken); window->remove_CharacterReceived(bd->CharacterReceivedToken); } bd->PointerInputSource->Release(); bd->KeyboardInputSource->Release(); bd->SwapChainPanel->Release(); bd->SwapChainPanelElement->Release(); } IM_DELETE(bd); } static bool ImGui_ImplUwp_UpdateMouseCursor() { ImGui_ImplUwp_Data* bd = ImGui_ImplUwp_GetBackendData(); 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 if (bd->CoreWindow) bd->CoreWindow->put_PointerCursor(nullptr); else if (bd->PointerInputSource) bd->PointerInputSource->put_PointerCursor(nullptr); } else { // Show OS mouse cursor ComPtr cursor; ComPtr cursorFactory; Windows::Foundation::GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Core_CoreCursor).Get(), &cursorFactory); HRESULT result = 0; switch (imgui_cursor) { case ImGuiMouseCursor_Arrow: result = cursorFactory->CreateCursor(ABI::Windows::UI::Core::CoreCursorType_Arrow, 0, &cursor); break; case ImGuiMouseCursor_TextInput: result = cursorFactory->CreateCursor(ABI::Windows::UI::Core::CoreCursorType_IBeam, 0, &cursor); break; case ImGuiMouseCursor_ResizeAll: result = cursorFactory->CreateCursor(ABI::Windows::UI::Core::CoreCursorType_SizeAll, 0, &cursor); break; case ImGuiMouseCursor_ResizeEW: result = cursorFactory->CreateCursor(ABI::Windows::UI::Core::CoreCursorType_SizeWestEast, 0, &cursor); break; case ImGuiMouseCursor_ResizeNS: result = cursorFactory->CreateCursor(ABI::Windows::UI::Core::CoreCursorType_SizeNorthSouth, 0, &cursor); break; case ImGuiMouseCursor_ResizeNESW: result = cursorFactory->CreateCursor(ABI::Windows::UI::Core::CoreCursorType_SizeNortheastSouthwest, 0, &cursor); break; case ImGuiMouseCursor_ResizeNWSE: result = cursorFactory->CreateCursor(ABI::Windows::UI::Core::CoreCursorType_SizeNorthwestSoutheast, 0, &cursor); break; case ImGuiMouseCursor_Hand: result = cursorFactory->CreateCursor(ABI::Windows::UI::Core::CoreCursorType_Hand, 0, &cursor); break; case ImGuiMouseCursor_NotAllowed: result = cursorFactory->CreateCursor(ABI::Windows::UI::Core::CoreCursorType_UniversalNo, 0, &cursor); break; } if (result == S_OK) { if (bd->CoreWindow) bd->CoreWindow->put_PointerCursor(cursor.Get()); else if (bd->PointerInputSource) bd->PointerInputSource->put_PointerCursor(cursor.Get()); } } return true; } static bool IsVkDown(int vk) { ImGui_ImplUwp_Data* bd = ImGui_ImplUwp_GetBackendData(); ABI::Windows::UI::Core::CoreVirtualKeyStates states = ABI::Windows::UI::Core::CoreVirtualKeyStates::CoreVirtualKeyStates_None; if (bd->CoreWindow) bd->CoreWindow->GetKeyState((ABI::Windows::System::VirtualKey)vk, &states); else if (bd->KeyboardInputSource) bd->KeyboardInputSource->GetCurrentKeyState((ABI::Windows::System::VirtualKey)vk, &states); return (states & ABI::Windows::UI::Core::CoreVirtualKeyStates::CoreVirtualKeyStates_Down) != 0; } static void ImGui_ImplUwp_AddKeyEvent(ImGuiKey key, bool down, int native_keycode, int native_scancode = -1) { ImGuiIO& io = ImGui::GetIO(); io.AddKeyEvent(key, down); io.SetKeyEventNativeData(key, native_keycode, native_scancode); // To support legacy indexing (<1.87 user code) IM_UNUSED(native_scancode); } static void ImGui_ImplUwp_ProcessKeyEventsWorkarounds() { // Left & right Shift keys: when both are pressed together, Windows tend to not generate the WM_KEYUP event for the first released one. if (ImGui::IsKeyDown(ImGuiKey_LeftShift) && !IsVkDown(VK_LSHIFT)) ImGui_ImplUwp_AddKeyEvent(ImGuiKey_LeftShift, false, VK_LSHIFT); if (ImGui::IsKeyDown(ImGuiKey_RightShift) && !IsVkDown(VK_RSHIFT)) ImGui_ImplUwp_AddKeyEvent(ImGuiKey_RightShift, false, VK_RSHIFT); // Sometimes WM_KEYUP for Win key is not passed down to the app (e.g. for Win+V on some setups, according to GLFW). if (ImGui::IsKeyDown(ImGuiKey_LeftSuper) && !IsVkDown(VK_LWIN)) ImGui_ImplUwp_AddKeyEvent(ImGuiKey_LeftSuper, false, VK_LWIN); if (ImGui::IsKeyDown(ImGuiKey_RightSuper) && !IsVkDown(VK_RWIN)) ImGui_ImplUwp_AddKeyEvent(ImGuiKey_RightSuper, false, VK_RWIN); } static void ImGui_ImplUwp_UpdateKeyModifiers() { ImGuiIO& io = ImGui::GetIO(); io.AddKeyEvent(ImGuiMod_Ctrl, IsVkDown(VK_CONTROL)); io.AddKeyEvent(ImGuiMod_Shift, IsVkDown(VK_SHIFT)); io.AddKeyEvent(ImGuiMod_Alt, IsVkDown(VK_MENU)); io.AddKeyEvent(ImGuiMod_Super, IsVkDown(VK_APPS)); } static void ImGui_ImplUwp_UpdateMouseData() { ImGui_ImplUwp_Data* bd = ImGui_ImplUwp_GetBackendData(); ImGuiIO& io = ImGui::GetIO(); //IM_ASSERT(bd->CoreWindow != 0); if (bd->CoreWindow) { bool is_app_focused; ComPtr coreWindow5; HRESULT hr = bd->CoreWindow->QueryInterface(coreWindow5.GetAddressOf()); if (hr == S_OK) { ABI::Windows::UI::Core::CoreWindowActivationMode mode; coreWindow5->get_ActivationMode(&mode); is_app_focused = mode == ABI::Windows::UI::Core::CoreWindowActivationMode::CoreWindowActivationMode_ActivatedInForeground; } else { boolean inputEnabled; boolean visible; bd->CoreWindow->get_IsInputEnabled(&inputEnabled); bd->CoreWindow->get_Visible(&visible); is_app_focused = visible && inputEnabled; } if (is_app_focused) { // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) if (io.WantSetMousePos) { ComPtr coreWindow2; hr = bd->CoreWindow->QueryInterface(coreWindow2.GetAddressOf()); if (hr == S_OK) { ABI::Windows::Foundation::Point pos = { (int)io.MousePos.x / io.DisplayFramebufferScale.x, (int)io.MousePos.y / io.DisplayFramebufferScale.y }; coreWindow2->put_PointerPosition(pos); } } } } } // Gamepad navigation mapping static void ImGui_ImplUwp_UpdateGamepads() { #ifndef IMGUI_IMPL_UWP_DISABLE_GAMEPAD ImGuiIO& io = ImGui::GetIO(); ImGui_ImplUwp_Data* bd = ImGui_ImplUwp_GetBackendData(); //if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. // 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 (bd->WantUpdateHasGamepad) { XINPUT_CAPABILITIES caps = {}; bd->HasGamepad = bd->XInputGetCapabilities ? (bd->XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) : false; bd->WantUpdateHasGamepad = false; } io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; XINPUT_STATE xinput_state; XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad; if (!bd->HasGamepad || bd->XInputGetState == nullptr || bd->XInputGetState(0, &xinput_state) != ERROR_SUCCESS) return; io.BackendFlags |= ImGuiBackendFlags_HasGamepad; #define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V) #define MAP_BUTTON(KEY_NO, BUTTON_ENUM) { io.AddKeyEvent(KEY_NO, (gamepad.wButtons & BUTTON_ENUM) != 0); } #define MAP_ANALOG(KEY_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); io.AddKeyAnalogEvent(KEY_NO, vn > 0.10f, IM_SATURATE(vn)); } MAP_BUTTON(ImGuiKey_GamepadStart, XINPUT_GAMEPAD_START); MAP_BUTTON(ImGuiKey_GamepadBack, XINPUT_GAMEPAD_BACK); MAP_BUTTON(ImGuiKey_GamepadFaceLeft, XINPUT_GAMEPAD_X); MAP_BUTTON(ImGuiKey_GamepadFaceRight, XINPUT_GAMEPAD_B); MAP_BUTTON(ImGuiKey_GamepadFaceUp, XINPUT_GAMEPAD_Y); MAP_BUTTON(ImGuiKey_GamepadFaceDown, XINPUT_GAMEPAD_A); MAP_BUTTON(ImGuiKey_GamepadDpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); MAP_BUTTON(ImGuiKey_GamepadDpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); MAP_BUTTON(ImGuiKey_GamepadDpadUp, XINPUT_GAMEPAD_DPAD_UP); MAP_BUTTON(ImGuiKey_GamepadDpadDown, XINPUT_GAMEPAD_DPAD_DOWN); MAP_BUTTON(ImGuiKey_GamepadL1, XINPUT_GAMEPAD_LEFT_SHOULDER); MAP_BUTTON(ImGuiKey_GamepadR1, XINPUT_GAMEPAD_RIGHT_SHOULDER); MAP_ANALOG(ImGuiKey_GamepadL2, gamepad.bLeftTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255); MAP_ANALOG(ImGuiKey_GamepadR2, gamepad.bRightTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255); MAP_BUTTON(ImGuiKey_GamepadL3, XINPUT_GAMEPAD_LEFT_THUMB); MAP_BUTTON(ImGuiKey_GamepadR3, XINPUT_GAMEPAD_RIGHT_THUMB); MAP_ANALOG(ImGuiKey_GamepadLStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); MAP_ANALOG(ImGuiKey_GamepadLStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); MAP_ANALOG(ImGuiKey_GamepadLStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); MAP_ANALOG(ImGuiKey_GamepadLStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); MAP_ANALOG(ImGuiKey_GamepadRStickLeft, gamepad.sThumbRX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); MAP_ANALOG(ImGuiKey_GamepadRStickRight, gamepad.sThumbRX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); MAP_ANALOG(ImGuiKey_GamepadRStickUp, gamepad.sThumbRY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); MAP_ANALOG(ImGuiKey_GamepadRStickDown, gamepad.sThumbRY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); #undef MAP_BUTTON #undef MAP_ANALOG #endif // #ifndef IMGUI_IMPL_UWP_DISABLE_GAMEPAD } void ImGui_ImplUwp_NewFrame() { ImGuiIO& io = ImGui::GetIO(); ImGui_ImplUwp_Data* bd = ImGui_ImplUwp_GetBackendData(); IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplUwp_Init()?"); // Setup display size (every frame to accommodate for window resizing) if (bd->CoreWindow) { ABI::Windows::Foundation::Rect rect = { 0, 0, 0, 0 }; bd->CoreWindow->get_Bounds(&rect); io.DisplaySize = ImVec2(rect.Width * io.DisplayFramebufferScale.x, rect.Height * io.DisplayFramebufferScale.y); } else if (bd->SwapChainPanelElement) { DOUBLE w, h; bd->SwapChainPanelElement->get_ActualHeight(&h); bd->SwapChainPanelElement->get_ActualWidth(&w); io.DisplaySize = ImVec2(w * io.DisplayFramebufferScale.x, h * io.DisplayFramebufferScale.y); } // Setup time step INT64 current_time = 0; ::QueryPerformanceCounter((LARGE_INTEGER*)¤t_time); io.DeltaTime = (float)(current_time - bd->Time) / bd->TicksPerSecond; bd->Time = current_time; // Update OS mouse position ImGui_ImplUwp_UpdateMouseData(); // Process workarounds for known Windows key handling issues ImGui_ImplUwp_ProcessKeyEventsWorkarounds(); // Update OS mouse cursor with the cursor requested by imgui ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor(); if (bd->LastMouseCursor != mouse_cursor) { bd->LastMouseCursor = mouse_cursor; ImGui_ImplUwp_UpdateMouseCursor(); } // Update game controllers (if enabled and available) ImGui_ImplUwp_UpdateGamepads(); } // There is no distinct VK_xxx for keypad enter, instead it is VK_RETURN + KF_EXTENDED, we assign it an arbitrary value to make code more readable (VK_ codes go up to 255) #define IM_VK_KEYPAD_ENTER (VK_RETURN + 256) // Map VK_xxx to ImGuiKey_xxx. static ImGuiKey ImGui_ImplUwp_VirtualKeyToImGuiKey(WPARAM wParam) { switch (wParam) { case VK_TAB: return ImGuiKey_Tab; case VK_LEFT: return ImGuiKey_LeftArrow; case VK_RIGHT: return ImGuiKey_RightArrow; case VK_UP: return ImGuiKey_UpArrow; case VK_DOWN: return ImGuiKey_DownArrow; case VK_PRIOR: return ImGuiKey_PageUp; case VK_NEXT: return ImGuiKey_PageDown; case VK_HOME: return ImGuiKey_Home; case VK_END: return ImGuiKey_End; case VK_INSERT: return ImGuiKey_Insert; case VK_DELETE: return ImGuiKey_Delete; case VK_BACK: return ImGuiKey_Backspace; case VK_SPACE: return ImGuiKey_Space; case VK_RETURN: return ImGuiKey_Enter; case VK_ESCAPE: return ImGuiKey_Escape; case VK_OEM_7: return ImGuiKey_Apostrophe; case VK_OEM_COMMA: return ImGuiKey_Comma; case VK_OEM_MINUS: return ImGuiKey_Minus; case VK_OEM_PERIOD: return ImGuiKey_Period; case VK_OEM_2: return ImGuiKey_Slash; case VK_OEM_1: return ImGuiKey_Semicolon; case VK_OEM_PLUS: return ImGuiKey_Equal; case VK_OEM_4: return ImGuiKey_LeftBracket; case VK_OEM_5: return ImGuiKey_Backslash; case VK_OEM_6: return ImGuiKey_RightBracket; case VK_OEM_3: return ImGuiKey_GraveAccent; case VK_CAPITAL: return ImGuiKey_CapsLock; case VK_SCROLL: return ImGuiKey_ScrollLock; case VK_NUMLOCK: return ImGuiKey_NumLock; case VK_SNAPSHOT: return ImGuiKey_PrintScreen; case VK_PAUSE: return ImGuiKey_Pause; case VK_NUMPAD0: return ImGuiKey_Keypad0; case VK_NUMPAD1: return ImGuiKey_Keypad1; case VK_NUMPAD2: return ImGuiKey_Keypad2; case VK_NUMPAD3: return ImGuiKey_Keypad3; case VK_NUMPAD4: return ImGuiKey_Keypad4; case VK_NUMPAD5: return ImGuiKey_Keypad5; case VK_NUMPAD6: return ImGuiKey_Keypad6; case VK_NUMPAD7: return ImGuiKey_Keypad7; case VK_NUMPAD8: return ImGuiKey_Keypad8; case VK_NUMPAD9: return ImGuiKey_Keypad9; case VK_DECIMAL: return ImGuiKey_KeypadDecimal; case VK_DIVIDE: return ImGuiKey_KeypadDivide; case VK_MULTIPLY: return ImGuiKey_KeypadMultiply; case VK_SUBTRACT: return ImGuiKey_KeypadSubtract; case VK_ADD: return ImGuiKey_KeypadAdd; case IM_VK_KEYPAD_ENTER: return ImGuiKey_KeypadEnter; case VK_LSHIFT: return ImGuiKey_LeftShift; case VK_LCONTROL: return ImGuiKey_LeftCtrl; case VK_LMENU: return ImGuiKey_LeftAlt; case VK_LWIN: return ImGuiKey_LeftSuper; case VK_RSHIFT: return ImGuiKey_RightShift; case VK_RCONTROL: return ImGuiKey_RightCtrl; case VK_RMENU: return ImGuiKey_RightAlt; case VK_RWIN: return ImGuiKey_RightSuper; case VK_APPS: return ImGuiKey_Menu; case '0': return ImGuiKey_0; case '1': return ImGuiKey_1; case '2': return ImGuiKey_2; case '3': return ImGuiKey_3; case '4': return ImGuiKey_4; case '5': return ImGuiKey_5; case '6': return ImGuiKey_6; case '7': return ImGuiKey_7; case '8': return ImGuiKey_8; case '9': return ImGuiKey_9; case 'A': return ImGuiKey_A; case 'B': return ImGuiKey_B; case 'C': return ImGuiKey_C; case 'D': return ImGuiKey_D; case 'E': return ImGuiKey_E; case 'F': return ImGuiKey_F; case 'G': return ImGuiKey_G; case 'H': return ImGuiKey_H; case 'I': return ImGuiKey_I; case 'J': return ImGuiKey_J; case 'K': return ImGuiKey_K; case 'L': return ImGuiKey_L; case 'M': return ImGuiKey_M; case 'N': return ImGuiKey_N; case 'O': return ImGuiKey_O; case 'P': return ImGuiKey_P; case 'Q': return ImGuiKey_Q; case 'R': return ImGuiKey_R; case 'S': return ImGuiKey_S; case 'T': return ImGuiKey_T; case 'U': return ImGuiKey_U; case 'V': return ImGuiKey_V; case 'W': return ImGuiKey_W; case 'X': return ImGuiKey_X; case 'Y': return ImGuiKey_Y; case 'Z': return ImGuiKey_Z; case VK_F1: return ImGuiKey_F1; case VK_F2: return ImGuiKey_F2; case VK_F3: return ImGuiKey_F3; case VK_F4: return ImGuiKey_F4; case VK_F5: return ImGuiKey_F5; case VK_F6: return ImGuiKey_F6; case VK_F7: return ImGuiKey_F7; case VK_F8: return ImGuiKey_F8; case VK_F9: return ImGuiKey_F9; case VK_F10: return ImGuiKey_F10; case VK_F11: return ImGuiKey_F11; case VK_F12: return ImGuiKey_F12; default: return ImGuiKey_None; } } static ImGuiMouseSource GetMouseSourceFromDevice(ABI::Windows::Devices::Input::IPointerDevice* device) { ABI::Windows::Devices::Input::PointerDeviceType type; device->get_PointerDeviceType(&type); if (type == ABI::Windows::Devices::Input::PointerDeviceType::PointerDeviceType_Pen) return ImGuiMouseSource_Pen; if (type == ABI::Windows::Devices::Input::PointerDeviceType::PointerDeviceType_Touch) return ImGuiMouseSource_TouchScreen; return ImGuiMouseSource_Mouse; } int PointerMoved(::IInspectable* sender, ABI::Windows::UI::Core::IPointerEventArgs* args) { if (ImGui::GetCurrentContext() == nullptr) return 0; ImGuiIO& io = ImGui::GetIO(); ABI::Windows::Foundation::Point point; ComPtr pointerPoint; ComPtr pointerDevice; if (args->get_CurrentPoint(&pointerPoint) != S_OK) return 0; if (pointerPoint->get_PointerDevice(&pointerDevice) != S_OK) return 0; pointerPoint->get_Position(&point); ImGuiMouseSource mouse_source = GetMouseSourceFromDevice(pointerDevice.Get()); io.AddMouseSourceEvent(mouse_source); io.AddMousePosEvent(point.X * io.DisplayFramebufferScale.x, point.Y * io.DisplayFramebufferScale.y); return 0; } int PointerExited(::IInspectable* sender, ABI::Windows::UI::Core::IPointerEventArgs* args) { if (ImGui::GetCurrentContext() == nullptr) return 0; ImGuiIO& io = ImGui::GetIO(); ImGui_ImplUwp_Data* bd = ImGui_ImplUwp_GetBackendData(); bd->MouseTrackedArea = 0; io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); return 0; } int KeyDown(::IInspectable* sender, ABI::Windows::UI::Core::IKeyEventArgs* args) { if (ImGui::GetCurrentContext() == nullptr) return 0; ImGuiIO& io = ImGui::GetIO(); ABI::Windows::System::VirtualKey key; ABI::Windows::UI::Core::CorePhysicalKeyStatus keyStatus; args->get_VirtualKey(&key); args->get_KeyStatus(&keyStatus); const bool is_key_down = true; if (key < 256) { // Submit modifiers ImGui_ImplUwp_UpdateKeyModifiers(); int vk = (int)key; if ((key == VK_RETURN) && keyStatus.IsExtendedKey) vk = IM_VK_KEYPAD_ENTER; // Submit key event const ImGuiKey key = ImGui_ImplUwp_VirtualKeyToImGuiKey(vk); const int scancode = keyStatus.ScanCode; if (key != ImGuiKey_None) ImGui_ImplUwp_AddKeyEvent(key, is_key_down, vk, scancode); // Submit individual left/right modifier events if (vk == VK_SHIFT) { // Important: Shift keys tend to get stuck when pressed together, missing key-up events are corrected in ImGui_ImplUwp_ProcessKeyEventsWorkarounds() if (IsVkDown(VK_LSHIFT) == is_key_down) { ImGui_ImplUwp_AddKeyEvent(ImGuiKey_LeftShift, is_key_down, VK_LSHIFT, scancode); } if (IsVkDown(VK_RSHIFT) == is_key_down) { ImGui_ImplUwp_AddKeyEvent(ImGuiKey_RightShift, is_key_down, VK_RSHIFT, scancode); } } else if (vk == VK_CONTROL) { if (IsVkDown(VK_LCONTROL) == is_key_down) { ImGui_ImplUwp_AddKeyEvent(ImGuiKey_LeftCtrl, is_key_down, VK_LCONTROL, scancode); } if (IsVkDown(VK_RCONTROL) == is_key_down) { ImGui_ImplUwp_AddKeyEvent(ImGuiKey_RightCtrl, is_key_down, VK_RCONTROL, scancode); } } else if (vk == VK_MENU || keyStatus.IsMenuKeyDown) { if (IsVkDown(VK_LMENU) == is_key_down) { ImGui_ImplUwp_AddKeyEvent(ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode); } if (IsVkDown(VK_RMENU) == is_key_down) { ImGui_ImplUwp_AddKeyEvent(ImGuiKey_RightAlt, is_key_down, VK_RMENU, scancode); } if (!IsVkDown(VK_LMENU) && !IsVkDown(VK_RMENU)) { ImGui_ImplUwp_AddKeyEvent(ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode); } } } return 0; } int KeyUp(::IInspectable* sender, ABI::Windows::UI::Core::IKeyEventArgs* args) { if (ImGui::GetCurrentContext() == nullptr) return 0; ImGuiIO& io = ImGui::GetIO(); ABI::Windows::System::VirtualKey key; ABI::Windows::UI::Core::CorePhysicalKeyStatus keyStatus; args->get_VirtualKey(&key); args->get_KeyStatus(&keyStatus); const bool is_key_down = false; if (key < 256) { // Submit modifiers ImGui_ImplUwp_UpdateKeyModifiers(); int vk = (int)key; if ((key == VK_RETURN) && keyStatus.IsExtendedKey) vk = IM_VK_KEYPAD_ENTER; // Submit key event const ImGuiKey key = ImGui_ImplUwp_VirtualKeyToImGuiKey(vk); const int scancode = keyStatus.ScanCode; if (key != ImGuiKey_None) ImGui_ImplUwp_AddKeyEvent(key, is_key_down, vk, scancode); // Submit individual left/right modifier events if (vk == VK_SHIFT) { // Important: Shift keys tend to get stuck when pressed together, missing key-up events are corrected in ImGui_ImplUwp_ProcessKeyEventsWorkarounds() if (IsVkDown(VK_LSHIFT) == is_key_down) { ImGui_ImplUwp_AddKeyEvent(ImGuiKey_LeftShift, is_key_down, VK_LSHIFT, scancode); } if (IsVkDown(VK_RSHIFT) == is_key_down) { ImGui_ImplUwp_AddKeyEvent(ImGuiKey_RightShift, is_key_down, VK_RSHIFT, scancode); } } else if (vk == VK_CONTROL) { if (IsVkDown(VK_LCONTROL) == is_key_down) { ImGui_ImplUwp_AddKeyEvent(ImGuiKey_LeftCtrl, is_key_down, VK_LCONTROL, scancode); } if (IsVkDown(VK_RCONTROL) == is_key_down) { ImGui_ImplUwp_AddKeyEvent(ImGuiKey_RightCtrl, is_key_down, VK_RCONTROL, scancode); } } else if (vk == VK_MENU || !keyStatus.IsMenuKeyDown) { if (IsVkDown(VK_LMENU) == is_key_down) { ImGui_ImplUwp_AddKeyEvent(ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode); } if (IsVkDown(VK_RMENU) == is_key_down) { ImGui_ImplUwp_AddKeyEvent(ImGuiKey_RightAlt, is_key_down, VK_RMENU, scancode); } if (!IsVkDown(VK_LMENU) && !IsVkDown(VK_RMENU)) { ImGui_ImplUwp_AddKeyEvent(ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode); } } } return 0; } unsigned short UTF32ToUTF16(UINT32 utf32) { unsigned int h, l; if (utf32 < 0x10000) { h = 0; l = utf32; return utf32; } unsigned int t = utf32 - 0x10000; h = (((t << 12) >> 22) + 0xD800); l = (((t << 22) >> 22) + 0xDC00); unsigned short ret = ((h << 16) | (l & 0x0000FFFF)); return ret; } int CharacterReceived(::IInspectable* sender, ABI::Windows::UI::Core::ICharacterReceivedEventArgs* args) { if (ImGui::GetCurrentContext() == nullptr) return 0; ImGuiIO& io = ImGui::GetIO(); UINT32 code; args->get_KeyCode(&code); io.AddInputCharacterUTF16(UTF32ToUTF16(code)); return 0; } int PointerWheelChanged(::IInspectable* sender, ABI::Windows::UI::Core::IPointerEventArgs* args) { if (ImGui::GetCurrentContext() == nullptr) return 0; ImGuiIO& io = ImGui::GetIO(); INT32 mouseWheelDelta; boolean isHorizontalMouseWheel; ComPtr pointerPoint; ComPtr pointerPointProps; if (args->get_CurrentPoint(&pointerPoint) != S_OK) return 0; if (pointerPoint->get_Properties(&pointerPointProps) != S_OK) return 0; pointerPointProps->get_IsHorizontalMouseWheel(&isHorizontalMouseWheel); pointerPointProps->get_MouseWheelDelta(&mouseWheelDelta); if (isHorizontalMouseWheel) io.AddMouseWheelEvent(-(float) mouseWheelDelta / (float)WHEEL_DELTA, 0.0f); else io.AddMouseWheelEvent(0.0f, (float)mouseWheelDelta / (float)WHEEL_DELTA); return 0; } int WindowActivated(ABI::Windows::UI::Core::ICoreWindow* sender, ABI::Windows::UI::Core::IWindowActivatedEventArgs* args) { if (ImGui::GetCurrentContext() == nullptr) return 0; ImGuiIO& io = ImGui::GetIO(); ABI::Windows::UI::Core::CoreWindowActivationState state; args->get_WindowActivationState(&state); io.AddFocusEvent(state != ABI::Windows::UI::Core::CoreWindowActivationState::CoreWindowActivationState_Deactivated); return 0; } int PointerPressed(::IInspectable* sender, ABI::Windows::UI::Core::IPointerEventArgs* args) { if (ImGui::GetCurrentContext() == nullptr) return 0; ImGuiIO& io = ImGui::GetIO(); ImGui_ImplUwp_Data* bd = ImGui_ImplUwp_GetBackendData(); ComPtr pointerPoint; ComPtr pointerDevice; ComPtr pointerPointProps; boolean lBtn; boolean rBtn; boolean mBtn; boolean x1Btn; boolean x2Btn; if (args->get_CurrentPoint(&pointerPoint) != S_OK) return 0; if (pointerPoint->get_Properties(&pointerPointProps) != S_OK) return 0; if (pointerPoint->get_PointerDevice(&pointerDevice) != S_OK) return 0; pointerPointProps->get_IsLeftButtonPressed(&lBtn); pointerPointProps->get_IsRightButtonPressed(&rBtn); pointerPointProps->get_IsMiddleButtonPressed(&mBtn); pointerPointProps->get_IsXButton1Pressed(&x1Btn); pointerPointProps->get_IsXButton2Pressed(&x2Btn); int button = 0; if (x2Btn && (bd->MouseButtonsDown & (1 << 4)) == 0) button = 4; if (x1Btn && (bd->MouseButtonsDown & (1 << 3)) == 0) button = 3; if (mBtn && (bd->MouseButtonsDown & (1 << 2)) == 0) button = 2; if (rBtn && (bd->MouseButtonsDown & (1 << 1)) == 0) button = 1; if (lBtn && (bd->MouseButtonsDown & (1 << 0)) == 0) button = 0; ImGuiMouseSource mouse_source = GetMouseSourceFromDevice(pointerDevice.Get()); bd->MouseButtonsDown |= 1 << button; io.AddMouseSourceEvent(mouse_source); io.AddMouseButtonEvent(button, true); return 0; } int PointerReleased(::IInspectable* sender, ABI::Windows::UI::Core::IPointerEventArgs* args) { if (ImGui::GetCurrentContext() == nullptr) return 0; ImGuiIO& io = ImGui::GetIO(); ImGui_ImplUwp_Data* bd = ImGui_ImplUwp_GetBackendData(); ComPtr pointerPoint; ComPtr pointerDevice; ComPtr pointerPointProps; boolean lBtn; boolean rBtn; boolean mBtn; boolean x1Btn; boolean x2Btn; if (args->get_CurrentPoint(&pointerPoint) != S_OK) return 0; if (pointerPoint->get_Properties(&pointerPointProps) != S_OK) return 0; if (pointerPoint->get_PointerDevice(&pointerDevice) != S_OK) return 0; pointerPointProps->get_IsLeftButtonPressed(&lBtn); pointerPointProps->get_IsRightButtonPressed(&rBtn); pointerPointProps->get_IsMiddleButtonPressed(&mBtn); pointerPointProps->get_IsXButton1Pressed(&x1Btn); pointerPointProps->get_IsXButton2Pressed(&x2Btn); int button = 0; if (!x2Btn && (bd->MouseButtonsDown & (1 << 4)) != 0) button = 4; if (!x1Btn && (bd->MouseButtonsDown & (1 << 3)) != 0) button = 3; if (!mBtn && (bd->MouseButtonsDown & (1 << 2)) != 0) button = 2; if (!rBtn && (bd->MouseButtonsDown & (1 << 1)) != 0) button = 1; if (!lBtn && (bd->MouseButtonsDown & (1 << 0)) != 0) button = 0; ImGuiMouseSource mouse_source = GetMouseSourceFromDevice(pointerDevice.Get()); bd->MouseButtonsDown &= ~(1 << button); io.AddMouseSourceEvent(mouse_source); io.AddMouseButtonEvent(button, false); return 0; } // UWP clipboard implementation #if !defined(IMGUI_DISABLE_UWP_DEFAULT_CLIPBOARD_FUNCTIONS) static const char* ImGui_ImplUwp_GetClipboardTextFn(void* user_data_ctx) { ImGuiContext& g = *(ImGuiContext*)user_data_ctx; g.ClipboardHandlerData.clear(); Microsoft::WRL::ComPtr clipboardStatics; Microsoft::WRL::ComPtr standardDataFormats; Microsoft::WRL::ComPtr dataPkgView; Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_Clipboard).Get(), &clipboardStatics); Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_StandardDataFormats).Get(), &standardDataFormats); if (clipboardStatics->GetContent(&dataPkgView) != S_OK) return NULL; Microsoft::WRL::Wrappers::HString hstr; boolean containsText; standardDataFormats->get_Text(hstr.GetAddressOf()); dataPkgView->Contains(hstr.Get(), &containsText); hstr.Release(); if (!containsText) return NULL; Microsoft::WRL::Wrappers::HString text; Microsoft::WRL::ComPtr> operation; if (dataPkgView->GetTextAsync(operation.GetAddressOf()) != S_OK) return NULL; HRESULT hr; Microsoft::WRL::Wrappers::Event opCompleted(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS)); Microsoft::WRL::ComPtr> cb = Microsoft::WRL::Callback, ABI::Windows::Foundation::IAsyncOperationCompletedHandler, Microsoft::WRL::FtmBase>>( [&opCompleted](ABI::Windows::Foundation::IAsyncOperation* asyncOperation, AsyncStatus status)->HRESULT { SetEvent(opCompleted.Get()); return S_OK; }); operation->put_Completed(cb.Get()); WaitForSingleObject(opCompleted.Get(), INFINITE); hr = operation->GetResults(text.GetAddressOf()); if (hr != S_OK) { text.Release(); return NULL; } if (const WCHAR* wbuf_global = (const WCHAR*)text.GetRawBuffer(NULL)) { int buf_len = ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, NULL, 0, NULL, NULL); g.ClipboardHandlerData.resize(buf_len); ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, g.ClipboardHandlerData.Data, buf_len, NULL, NULL); } text.Release(); return g.ClipboardHandlerData.Data; } static void ImGui_ImplUwp_SetClipboardTextFn(void*, const char* text) { Microsoft::WRL::ComPtr dataPkg; Microsoft::WRL::ComPtr clipboardStatics; Windows::Foundation::ActivateInstance(Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_DataPackage).Get(), &dataPkg); Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_Clipboard).Get(), &clipboardStatics); HRESULT hr = dataPkg->put_RequestedOperation(ABI::Windows::ApplicationModel::DataTransfer::DataPackageOperation_Copy); if (hr != S_OK) return; const int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0); HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR)); if (wbuf_handle == NULL) return; WCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle); ::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length); ::GlobalUnlock(wbuf_handle); if (dataPkg->SetText(Microsoft::WRL::Wrappers::HStringReference(wbuf_global).Get()) != S_OK) { ::GlobalFree(wbuf_handle); return; } clipboardStatics->SetContent(dataPkg.Get()); ::GlobalFree(wbuf_handle); } #endif //---------------------------------------------------------------------------------------------------------