Files
WinDurango/thirdparty/imgui_impl_uwp.cpp

1170 lines
51 KiB
C++

// 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 <windows.h>
#include <sdkddkver.h>
#include <tchar.h>
#include <wrl.h>
//WinRT
#include <Windows.UI.Core.h>
#include <CoreWindow.h>
#include <Windows.UI.Xaml.Controls.h>
#include <Windows.UI.Xaml.Hosting.h>
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 <xinput.h>
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 <windows.applicationmodel.datatransfer.h>
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<ABI::Windows::UI::Core::CoreWindow*, ABI::Windows::UI::Core::PointerEventArgs*> WindowPointerMoved_Callback;
typedef ABI::Windows::Foundation::ITypedEventHandler<ABI::Windows::UI::Core::CoreWindow*, ABI::Windows::UI::Core::PointerEventArgs*> WindowPointerExited_Callback;
typedef ABI::Windows::Foundation::ITypedEventHandler<ABI::Windows::UI::Core::CoreWindow*, ABI::Windows::UI::Core::KeyEventArgs*> WindowKeyDown_Callback;
typedef ABI::Windows::Foundation::ITypedEventHandler<ABI::Windows::UI::Core::CoreWindow*, ABI::Windows::UI::Core::CharacterReceivedEventArgs*> WindowCharacterReceived_Callback;
typedef ABI::Windows::Foundation::ITypedEventHandler<ABI::Windows::UI::Core::CoreWindow*, ABI::Windows::UI::Core::PointerEventArgs*> WindowPointerWheelChanged_Callback;
typedef ABI::Windows::Foundation::ITypedEventHandler<ABI::Windows::UI::Core::CoreWindow*, ABI::Windows::UI::Core::PointerEventArgs*> WindowPointerPressed_Callback;
typedef ABI::Windows::Foundation::ITypedEventHandler<ABI::Windows::UI::Core::CoreWindow*, ABI::Windows::UI::Core::PointerEventArgs*> WindowPointerReleased_Callback;
typedef ABI::Windows::Foundation::ITypedEventHandler<ABI::Windows::UI::Core::CoreWindow*, ABI::Windows::UI::Core::WindowActivatedEventArgs*> 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<ABI::Windows::UI::Core::ICoreWindowStatic> 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_Callback>(WindowActivated).Get(), &bd->WindowActivatedToken);
SystemCreateControlInputEx(core_window, ABI::Windows::UI::Core::IID_ICoreInputSourceBase, &controlInput);
}*/
if (core_window)
{
bd->CoreWindow->add_PointerMoved(Callback<WindowPointerMoved_Callback>(PointerMoved).Get(), &bd->PointerMovedToken);
bd->CoreWindow->add_PointerExited(Callback<WindowPointerExited_Callback>(PointerExited).Get(), &bd->PointerExitedToken);
bd->CoreWindow->add_PointerWheelChanged(Callback<WindowPointerWheelChanged_Callback>(PointerWheelChanged).Get(), &bd->PointerWheelChangedToken);
bd->CoreWindow->add_PointerPressed(Callback<WindowPointerPressed_Callback>(PointerPressed).Get(), &bd->PointerPressedToken);
bd->CoreWindow->add_PointerReleased(Callback<WindowPointerReleased_Callback>(PointerReleased).Get(), &bd->PointerReleasedToken);
bd->CoreWindow->add_KeyDown(Callback<WindowKeyDown_Callback>(KeyDown).Get(), &bd->KeyDownToken);
bd->CoreWindow->add_KeyUp(Callback<WindowKeyDown_Callback>(KeyUp).Get(), &bd->KeyUpToken);
bd->CoreWindow->add_CharacterReceived(Callback<WindowCharacterReceived_Callback>(CharacterReceived).Get(), &bd->CharacterReceivedToken);
bd->CoreWindow->add_Activated(Callback<WindowActivated_Callback>(WindowActivated).Get(), &bd->WindowActivatedToken);
}
else if (swapchain_panel)
{
ComPtr<ABI::Windows::UI::Core::ICoreInputSourceBase> 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<ISystemCoreInputInterop> coreInputInterop;
if (SUCCEEDED(controlInput.As(&coreInputInterop)))
{
ComPtr<ABI::Windows::UI::Xaml::Hosting::IElementCompositionPreviewStatics> elementCompositionPreviewStatics;
result = Windows::Foundation::GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Xaml_Hosting_ElementCompositionPreview).Get(), &elementCompositionPreviewStatics);
if (SUCCEEDED(result))
{
ComPtr<ABI::Windows::UI::Xaml::IUIElement> uiElement;
swapchain_panel->QueryInterface(uiElement.GetAddressOf());
ComPtr<ABI::Windows::UI::Composition::IVisual> 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_Callback>(PointerMoved).Get(), &bd->PointerMovedToken);
bd->PointerInputSource->add_PointerExited(Callback<PointerExited_Callback>(PointerExited).Get(), &bd->PointerExitedToken);
bd->PointerInputSource->add_PointerWheelChanged(Callback<PointerWheelChanged_Callback>(PointerWheelChanged).Get(), &bd->PointerWheelChangedToken);
bd->PointerInputSource->add_PointerPressed(Callback<PointerPressed_Callback>(PointerPressed).Get(), &bd->PointerPressedToken);
bd->PointerInputSource->add_PointerReleased(Callback<PointerReleased_Callback>(PointerReleased).Get(), &bd->PointerReleasedToken);
//bd->KeyboardInputSource->add_KeyDown(Callback<KeyDown_Callback>(KeyDown).Get(), &bd->KeyDownToken);
//bd->KeyboardInputSource->add_KeyUp(Callback<KeyDown_Callback>(KeyUp).Get(), &bd->KeyUpToken);
//bd->KeyboardInputSource->add_CharacterReceived(Callback<CharacterReceived_Callback>(CharacterReceived).Get(), &bd->CharacterReceivedToken);
ComPtr<ABI::Windows::UI::Core::ICoreWindow> window = ImGui_ImplUwp_GetCoreWindowForCurrentThread();
if (window.Get())
{
window->add_KeyDown(Callback<WindowKeyDown_Callback>(KeyDown).Get(), &bd->KeyDownToken);
window->add_KeyUp(Callback<WindowKeyDown_Callback>(KeyUp).Get(), &bd->KeyUpToken);
window->add_CharacterReceived(Callback<WindowCharacterReceived_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<ABI::Windows::UI::Core::ICoreWindow> 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<ABI::Windows::UI::Core::ICoreCursor> cursor;
ComPtr<ABI::Windows::UI::Core::ICoreCursorFactory> 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<ABI::Windows::UI::Core::ICoreWindow5> 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<ABI::Windows::UI::Core::ICoreWindow2> 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*)&current_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<ABI::Windows::UI::Input::IPointerPoint> pointerPoint;
ComPtr<ABI::Windows::Devices::Input::IPointerDevice> 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<ABI::Windows::UI::Input::IPointerPoint> pointerPoint;
ComPtr<ABI::Windows::UI::Input::IPointerPointProperties> 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<ABI::Windows::UI::Input::IPointerPoint> pointerPoint;
ComPtr<ABI::Windows::Devices::Input::IPointerDevice> pointerDevice;
ComPtr<ABI::Windows::UI::Input::IPointerPointProperties> 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<ABI::Windows::UI::Input::IPointerPoint> pointerPoint;
ComPtr<ABI::Windows::Devices::Input::IPointerDevice> pointerDevice;
ComPtr<ABI::Windows::UI::Input::IPointerPointProperties> 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<ABI::Windows::ApplicationModel::DataTransfer::IClipboardStatics> clipboardStatics;
Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::DataTransfer::IStandardDataFormatsStatics> standardDataFormats;
Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::DataTransfer::IDataPackageView> 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<ABI::Windows::Foundation::IAsyncOperation<HSTRING>> 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<ABI::Windows::Foundation::IAsyncOperationCompletedHandler<HSTRING>> cb
= Microsoft::WRL::Callback<Microsoft::WRL::Implements<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, ABI::Windows::Foundation::IAsyncOperationCompletedHandler<HSTRING>, Microsoft::WRL::FtmBase>>(
[&opCompleted](ABI::Windows::Foundation::IAsyncOperation<HSTRING>* 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<ABI::Windows::ApplicationModel::DataTransfer::IDataPackage> dataPkg;
Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::DataTransfer::IClipboardStatics> 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
//---------------------------------------------------------------------------------------------------------