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
This commit is contained in:
RH 2022-10-10 13:16:19 +11:00 committed by GitHub
parent 34094038d5
commit 461e7cfee6
1 changed files with 75 additions and 35 deletions

View File

@ -6,6 +6,8 @@
#include <android/input.h> #include <android/input.h>
#include <android/keycodes.h> #include <android/keycodes.h>
#include <android/log.h> #include <android/log.h>
#include <imgui_internal.h>
#include "base/CCIMEDelegate.h"
USING_NS_AX; USING_NS_AX;
using namespace backend; using namespace backend;
@ -20,7 +22,35 @@ using namespace backend;
#endif #endif
#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 // Android data
static char g_LogTag[] = "ImGuiAndroid"; static char g_LogTag[] = "ImGuiAndroid";
@ -80,6 +110,8 @@ struct ImGui_ImplAndroid_Data
SavedRenderStateData SavedRenderState{}; SavedRenderStateData SavedRenderState{};
Vec2 ViewResolution = Vec2(1920, 1080); Vec2 ViewResolution = Vec2(1920, 1080);
KeyboardInputDelegate KeyboardInputDelegate;
}; };
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts // 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 // Forward Declarations
static void ImGui_ImplAndroid_ShutdownPlatformInterface(); 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 // Functions
static bool ImGui_ImplAndroid_Init(GLView* window, bool install_callbacks) 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(); touchListener->retain();
bd->TouchListener = touchListener; bd->TouchListener = touchListener;
touchListener->onTouchBegan = [](Touch* touch, Event* /*event*/) -> bool { touchListener->onTouchBegan = [](Touch* touch, Event* event) -> bool {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
ImGui_ImplAndroid_Data* bd = ImGui_ImplAndroid_GetBackendData(); ImGui_ImplAndroid_Data* bd = ImGui_ImplAndroid_GetBackendData();
auto location = touch->getLocationInView(); auto location = convertToUICoordinates(touch->getLocationInView());
auto origin = bd->Window->getVisibleOrigin(); io.AddMousePosEvent(location.x, location.y);
auto realX = location.x * bd->Window->getScaleX(); bd->LastValidMousePos = ImVec2(location.x, location.y);
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);
io.AddMouseButtonEvent(0, true); 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 // 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 // AddMousePosEvent is not instant, it's queued. So, just return true here
// to indicate that we're handling this event. // 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*/) { touchListener->onTouchMoved = [](Touch* touch, Event* /*event*/) {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
ImGui_ImplAndroid_Data* bd = ImGui_ImplAndroid_GetBackendData(); ImGui_ImplAndroid_Data* bd = ImGui_ImplAndroid_GetBackendData();
auto location = touch->getLocationInView(); auto location = convertToUICoordinates(touch->getLocationInView());
auto origin = bd->Window->getVisibleOrigin(); io.AddMousePosEvent(location.x, location.y);
auto realX = location.x * bd->Window->getScaleX(); bd->LastValidMousePos = ImVec2(location.x, location.y);
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);;
}; };
touchListener->onTouchEnded = [](Touch* touch, Event* /*event*/) { touchListener->onTouchEnded = [](Touch* touch, Event* event) {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
ImGui_ImplAndroid_Data* bd = ImGui_ImplAndroid_GetBackendData(); ImGui_ImplAndroid_Data* bd = ImGui_ImplAndroid_GetBackendData();
auto location = touch->getLocationInView(); auto location = convertToUICoordinates(touch->getLocationInView());
auto origin = bd->Window->getVisibleOrigin(); io.AddMousePosEvent(location.x, location.y);
auto realX = location.x * bd->Window->getScaleX(); bd->LastValidMousePos = ImVec2(location.x, location.y);
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);;
io.AddMouseButtonEvent(0, false); 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*/) { touchListener->onTouchCancelled = [](Touch* touch, Event* /*event*/) {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
ImGui_ImplAndroid_Data* bd = ImGui_ImplAndroid_GetBackendData(); ImGui_ImplAndroid_Data* bd = ImGui_ImplAndroid_GetBackendData();
auto location = touch->getLocationInView(); auto location = convertToUICoordinates(touch->getLocationInView());
auto origin = bd->Window->getVisibleOrigin(); io.AddMousePosEvent(location.x, location.y);
auto realX = location.x * bd->Window->getScaleX(); bd->LastValidMousePos = ImVec2(location.x, location.y);
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);
io.AddMouseButtonEvent(0, false); io.AddMouseButtonEvent(0, false);
}; };