From bbd81665a694b4438e5c17fbff3ad12801df6bc7 Mon Sep 17 00:00:00 2001 From: Dram27 Date: Tue, 12 May 2026 17:40:10 +0200 Subject: [PATCH] Fix multitouch on web --- misc/web/index.html | 4 ++ src/main_glfw.h | 102 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 99 insertions(+), 7 deletions(-) diff --git a/misc/web/index.html b/misc/web/index.html index 3cd04f9..c209fb2 100644 --- a/misc/web/index.html +++ b/misc/web/index.html @@ -22,6 +22,10 @@ width: 100vw; height: 100vh; display: block; + touch-action: none; + user-select: none; + -webkit-user-select: none; + -webkit-tap-highlight-color: transparent; } diff --git a/src/main_glfw.h b/src/main_glfw.h index 042c9fb..44295fd 100755 --- a/src/main_glfw.h +++ b/src/main_glfw.h @@ -16,7 +16,88 @@ #ifdef __EMSCRIPTEN__ #include #endif -static App* g_app = 0; +static App* g_app = 0; + +#ifdef __EMSCRIPTEN__ +static int g_touchPointerIds[Multitouch::MAX_POINTERS]; + +static void resetTouchPointerIds() { + for (int i = 0; i < Multitouch::MAX_POINTERS; ++i) { + g_touchPointerIds[i] = -1; + } +} + +static int getTouchPointerSlot(int touchId) { + for (int i = 0; i < Multitouch::MAX_POINTERS; ++i) { + if (g_touchPointerIds[i] == touchId) return i; + } + return -1; +} + +static int allocateTouchPointerSlot(int touchId) { + int slot = getTouchPointerSlot(touchId); + if (slot >= 0) return slot; + + for (int i = 0; i < Multitouch::MAX_POINTERS; ++i) { + if (g_touchPointerIds[i] < 0) { + g_touchPointerIds[i] = touchId; + return i; + } + } + + return -1; +} + +static void releaseTouchPointerSlot(int touchId) { + for (int i = 0; i < Multitouch::MAX_POINTERS; ++i) { + if (g_touchPointerIds[i] == touchId) { + g_touchPointerIds[i] = -1; + return; + } + } +} + +static EM_BOOL touch_callback(int eventType, const EmscriptenTouchEvent* touchEvent, void* userData) { + if (!touchEvent) return 0; + + const bool isStart = eventType == EMSCRIPTEN_EVENT_TOUCHSTART; + const bool isMove = eventType == EMSCRIPTEN_EVENT_TOUCHMOVE; + const bool isEnd = eventType == EMSCRIPTEN_EVENT_TOUCHEND; + const bool isCancel = eventType == EMSCRIPTEN_EVENT_TOUCHCANCEL; + + if (isCancel) { + for (int i = 0; i < Multitouch::MAX_POINTERS; ++i) { + if (g_touchPointerIds[i] >= 0) { + Multitouch::feed(1, 0, Multitouch::getX(i), Multitouch::getY(i), i); + g_touchPointerIds[i] = -1; + } + } + return 1; + } + + for (int i = 0; i < touchEvent->numTouches; ++i) { + const EmscriptenTouchPoint& touch = touchEvent->touches[i]; + if (!touch.isChanged) continue; + + const int slot = isEnd ? getTouchPointerSlot(touch.identifier) : allocateTouchPointerSlot(touch.identifier); + if (slot < 0) continue; + + const short x = (short)touch.targetX; + const short y = (short)touch.targetY; + + if (isStart) { + Multitouch::feed(1, 1, x, y, slot); + } else if (isMove) { + Multitouch::feed(0, 0, x, y, slot); + } else if (isEnd) { + Multitouch::feed(1, 0, x, y, slot); + releaseTouchPointerSlot(touch.identifier); + } + } + + return 1; +} +#endif int transformKey(int glfwkey) { if (glfwkey >= GLFW_KEY_F1 && glfwkey <= GLFW_KEY_F12) { @@ -176,12 +257,19 @@ int main(void) { glfwSetKeyCallback(platform->window, key_callback); glfwSetCharCallback(platform->window, character_callback); - glfwSetCursorPosCallback(platform->window, cursor_position_callback); - glfwSetMouseButtonCallback(platform->window, mouse_button_callback); - glfwSetScrollCallback(platform->window, scroll_callback); - glfwSetWindowSizeCallback(platform->window, window_size_callback); - - glfwMakeContextCurrent(platform->window); + glfwSetCursorPosCallback(platform->window, cursor_position_callback); + glfwSetMouseButtonCallback(platform->window, mouse_button_callback); + glfwSetScrollCallback(platform->window, scroll_callback); + glfwSetWindowSizeCallback(platform->window, window_size_callback); + #ifdef __EMSCRIPTEN__ + resetTouchPointerIds(); + emscripten_set_touchstart_callback("#canvas", 0, 1, touch_callback); + emscripten_set_touchmove_callback("#canvas", 0, 1, touch_callback); + emscripten_set_touchend_callback("#canvas", 0, 1, touch_callback); + emscripten_set_touchcancel_callback("#canvas", 0, 1, touch_callback); + #endif + + glfwMakeContextCurrent(platform->window); #ifndef __EMSCRIPTEN__ gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); glfwSwapInterval(0);