From 461e7cfee6c229d5924880a822fb9f7e0c83304c Mon Sep 17 00:00:00 2001 From: RH Date: Mon, 10 Oct 2022 13:16:19 +1100 Subject: [PATCH] Fix to UI touch location and add keyboard support for ImGui on Android (#910) * Committing genbindings changes * Fix for X position calculation not factoring in X origin. Reduce code duplication. * Add keyboard input support --- extensions/ImGui/imgui_impl_ax_android.cpp | 110 ++++++++++++++------- 1 file changed, 75 insertions(+), 35 deletions(-) diff --git a/extensions/ImGui/imgui_impl_ax_android.cpp b/extensions/ImGui/imgui_impl_ax_android.cpp index eb71b10164..1d1af4981b 100644 --- a/extensions/ImGui/imgui_impl_ax_android.cpp +++ b/extensions/ImGui/imgui_impl_ax_android.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include "base/CCIMEDelegate.h" USING_NS_AX; using namespace backend; @@ -20,7 +22,35 @@ using namespace backend; #endif #endif -// GLFW +// Text handling +class KeyboardInputDelegate : public IMEDelegate +{ +protected: + bool canAttachWithIME() override + { + return true; + } + + bool canDetachWithIME() override + { + return true; + } + + void controlKey(EventKeyboard::KeyCode keyCode) override + { + // Not handled at the moment + } + + void insertText(const char* text, size_t len) override + { + ImGuiIO& io = ImGui::GetIO(); + for (int i = 0; i < len && text[i] != 0; ++i) + { + io.AddInputCharacter(text[i]); + } + } +}; + // Android data static char g_LogTag[] = "ImGuiAndroid"; @@ -80,6 +110,8 @@ struct ImGui_ImplAndroid_Data SavedRenderStateData SavedRenderState{}; Vec2 ViewResolution = Vec2(1920, 1080); + + KeyboardInputDelegate KeyboardInputDelegate; }; // Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts @@ -91,6 +123,17 @@ static ImGui_ImplAndroid_Data* ImGui_ImplAndroid_GetBackendData() // Forward Declarations static void ImGui_ImplAndroid_ShutdownPlatformInterface(); +static ax::Vec2 convertToUICoordinates(const Vec2& pos) +{ + auto* bd = ImGui_ImplAndroid_GetBackendData(); + ImGuiIO& io = ImGui::GetIO(); + auto origin = bd->Window->getVisibleOrigin(); + auto uiX = ((pos.x - origin.x) * bd->Window->getScaleX()) / io.DisplayFramebufferScale.x; + auto uiY = ((pos.y - origin.y) * bd->Window->getScaleY()) / io.DisplayFramebufferScale.y; + + return Vec2(uiX, uiY); +} + // Functions static bool ImGui_ImplAndroid_Init(GLView* window, bool install_callbacks) { @@ -121,19 +164,20 @@ static bool ImGui_ImplAndroid_Init(GLView* window, bool install_callbacks) touchListener->retain(); bd->TouchListener = touchListener; - touchListener->onTouchBegan = [](Touch* touch, Event* /*event*/) -> bool { + touchListener->onTouchBegan = [](Touch* touch, Event* event) -> bool { ImGuiIO& io = ImGui::GetIO(); ImGui_ImplAndroid_Data* bd = ImGui_ImplAndroid_GetBackendData(); - auto location = touch->getLocationInView(); - auto origin = bd->Window->getVisibleOrigin(); - auto realX = location.x * bd->Window->getScaleX(); - auto realY = (location.y - origin.y) * bd->Window->getScaleY(); - realX /= io.DisplayFramebufferScale.x; - realY /= io.DisplayFramebufferScale.y; - io.AddMousePosEvent(realX, realY); - bd->LastValidMousePos = ImVec2(realX, realY); + auto location = convertToUICoordinates(touch->getLocationInView()); + io.AddMousePosEvent(location.x, location.y); + bd->LastValidMousePos = ImVec2(location.x, location.y); io.AddMouseButtonEvent(0, true); + ImGui::UpdateHoveredWindowAndCaptureFlags(); + if (ImGui::GetIO().WantCaptureMouse) + { + event->stopPropagation(); + } + // We can't check if we're actually hovering over a ImGui element, since the // AddMousePosEvent is not instant, it's queued. So, just return true here // to indicate that we're handling this event. @@ -143,41 +187,37 @@ static bool ImGui_ImplAndroid_Init(GLView* window, bool install_callbacks) touchListener->onTouchMoved = [](Touch* touch, Event* /*event*/) { ImGuiIO& io = ImGui::GetIO(); ImGui_ImplAndroid_Data* bd = ImGui_ImplAndroid_GetBackendData(); - auto location = touch->getLocationInView(); - auto origin = bd->Window->getVisibleOrigin(); - auto realX = location.x * bd->Window->getScaleX(); - auto realY = (location.y - origin.y) * bd->Window->getScaleY(); - realX /= io.DisplayFramebufferScale.x; - realY /= io.DisplayFramebufferScale.y; - io.AddMousePosEvent(realX, realY); - bd->LastValidMousePos = ImVec2(realX, realY);; + auto location = convertToUICoordinates(touch->getLocationInView()); + io.AddMousePosEvent(location.x, location.y); + bd->LastValidMousePos = ImVec2(location.x, location.y); }; - touchListener->onTouchEnded = [](Touch* touch, Event* /*event*/) { + touchListener->onTouchEnded = [](Touch* touch, Event* event) { ImGuiIO& io = ImGui::GetIO(); ImGui_ImplAndroid_Data* bd = ImGui_ImplAndroid_GetBackendData(); - auto location = touch->getLocationInView(); - auto origin = bd->Window->getVisibleOrigin(); - auto realX = location.x * bd->Window->getScaleX(); - auto realY = (location.y - origin.y) * bd->Window->getScaleY(); - realX /= io.DisplayFramebufferScale.x; - realY /= io.DisplayFramebufferScale.y; - io.AddMousePosEvent(realX, realY); - bd->LastValidMousePos = ImVec2(realX, realY);; + auto location = convertToUICoordinates(touch->getLocationInView()); + io.AddMousePosEvent(location.x, location.y); + bd->LastValidMousePos = ImVec2(location.x, location.y); io.AddMouseButtonEvent(0, false); + + if (ImGui::GetIO().WantTextInput) + { + bd->KeyboardInputDelegate.attachWithIME(); + bd->Window->setIMEKeyboardState(true); + } + else + { + bd->KeyboardInputDelegate.detachWithIME(); + bd->Window->setIMEKeyboardState(false); + } }; touchListener->onTouchCancelled = [](Touch* touch, Event* /*event*/) { ImGuiIO& io = ImGui::GetIO(); ImGui_ImplAndroid_Data* bd = ImGui_ImplAndroid_GetBackendData(); - auto location = touch->getLocationInView(); - auto origin = bd->Window->getVisibleOrigin(); - auto realX = location.x * bd->Window->getScaleX(); - auto realY = (location.y - origin.y) * bd->Window->getScaleY(); - realX /= io.DisplayFramebufferScale.x; - realY /= io.DisplayFramebufferScale.y; - io.AddMousePosEvent(realX, realY); - bd->LastValidMousePos = ImVec2(realX, realY); + auto location = convertToUICoordinates(touch->getLocationInView()); + io.AddMousePosEvent(location.x, location.y); + bd->LastValidMousePos = ImVec2(location.x, location.y); io.AddMouseButtonEvent(0, false); };