fix(nds): wrong touch detection
All checks were successful
Build and Push Docker Image / build (push) Successful in 2m31s

This commit is contained in:
2026-02-13 16:21:54 +01:00
parent 43cad4f36b
commit e454a48532
2 changed files with 60 additions and 40 deletions

View File

@@ -326,26 +326,6 @@ const dispatchScreenEvent = (
); );
}; };
const dispatchScreenTouchEvent = (
type: string,
canvas: HTMLCanvasElement,
intersection: THREE.Intersection,
) => {
const coords = toScreenCoords(canvas, intersection);
if (!coords) return;
const touch = new Touch({ identifier: 0, target: canvas, ...coords });
canvas.dispatchEvent(
new TouchEvent(type, {
bubbles: true,
cancelable: true,
touches: type === "touchend" ? [] : [touch],
changedTouches: [touch],
}),
);
};
const BUTTON_MAP = { const BUTTON_MAP = {
[X_BUTTON]: "X", [X_BUTTON]: "X",
[A_BUTTON]: "A", [A_BUTTON]: "A",
@@ -441,10 +421,40 @@ const handleMouseUp = (event: MouseEvent) => {
if (canvas) dispatchScreenEvent("mouseup", canvas, intersection); if (canvas) dispatchScreenEvent("mouseup", canvas, intersection);
}; };
const SWIPE_THRESHOLD = 30;
let swipeStartX = 0;
let swipeStartY = 0;
const dispatchSwipe = (endX: number, endY: number) => {
const deltaX = endX - swipeStartX;
const deltaY = endY - swipeStartY;
const absDeltaX = Math.abs(deltaX);
const absDeltaY = Math.abs(deltaY);
if (Math.max(absDeltaX, absDeltaY) < SWIPE_THRESHOLD) return;
const direction =
absDeltaX > absDeltaY
? deltaX > 0
? "RIGHT"
: "LEFT"
: deltaY > 0
? "DOWN"
: "UP";
window.dispatchEvent(
new KeyboardEvent("keydown", { key: `NDS_SWIPE_${direction}` }),
);
};
const handleTouchStart = (event: TouchEvent) => { const handleTouchStart = (event: TouchEvent) => {
const touch = event.touches[0]; const touch = event.touches[0];
if (!touch) return; if (!touch) return;
event.preventDefault();
swipeStartX = touch.clientX;
swipeStartY = touch.clientY;
if (!hasAnimated.value) { if (!hasAnimated.value) {
animateIntro(); animateIntro();
return; return;
@@ -452,7 +462,6 @@ const handleTouchStart = (event: TouchEvent) => {
handleInteraction(touch.clientX, touch.clientY, (canvas, intersection) => { handleInteraction(touch.clientX, touch.clientY, (canvas, intersection) => {
dispatchScreenEvent("mousedown", canvas, intersection); dispatchScreenEvent("mousedown", canvas, intersection);
dispatchScreenTouchEvent("touchstart", canvas, intersection);
}); });
}; };
@@ -462,14 +471,22 @@ const handleTouchEnd = (event: TouchEvent) => {
const touch = event.changedTouches[0]; const touch = event.changedTouches[0];
if (!touch) return; if (!touch) return;
dispatchSwipe(touch.clientX, touch.clientY);
const intersection = raycast(touch.clientX, touch.clientY); const intersection = raycast(touch.clientX, touch.clientY);
if (!intersection?.uv) return; if (!intersection?.uv) return;
const canvas = getScreenCanvas(intersection.object.name); const canvas = getScreenCanvas(intersection.object.name);
if (canvas) { if (canvas) {
dispatchScreenEvent("click", canvas, intersection); dispatchScreenEvent("click", canvas, intersection);
dispatchScreenTouchEvent("touchend", canvas, intersection);
} }
document.dispatchEvent(
new MouseEvent("mouseup", {
clientX: touch.clientX,
clientY: touch.clientY,
}),
);
}; };
onMounted(() => { onMounted(() => {

View File

@@ -33,16 +33,19 @@ const registerScreenMouseWheelCallback = (
return () => screenMouseWheelCallbacks.delete(callback); return () => screenMouseWheelCallbacks.delete(callback);
}; };
const handleCanvasClick = (event: MouseEvent) => { const toLogicalCoords = (clientX: number, clientY: number) => {
if (!canvas.value) return; const rect = canvas.value!.getBoundingClientRect();
const rect = canvas.value.getBoundingClientRect();
const scaleX = LOGICAL_WIDTH / rect.width; const scaleX = LOGICAL_WIDTH / rect.width;
const scaleY = LOGICAL_HEIGHT / rect.height; const scaleY = LOGICAL_HEIGHT / rect.height;
return [
(clientX - rect.left) * scaleX,
(clientY - rect.top) * scaleY,
] as const;
};
const x = (event.clientX - rect.left) * scaleX; const handleCanvasClick = (event: MouseEvent) => {
const y = (event.clientY - rect.top) * scaleY; if (!canvas.value) return;
const [x, y] = toLogicalCoords(event.clientX, event.clientY);
for (const callback of screenClickCallbacks) { for (const callback of screenClickCallbacks) {
callback(x, y); callback(x, y);
} }
@@ -50,14 +53,7 @@ const handleCanvasClick = (event: MouseEvent) => {
const handleCanvasMouseDown = (event: MouseEvent) => { const handleCanvasMouseDown = (event: MouseEvent) => {
if (!canvas.value) return; if (!canvas.value) return;
const [x, y] = toLogicalCoords(event.clientX, event.clientY);
const rect = canvas.value.getBoundingClientRect();
const scaleX = LOGICAL_WIDTH / rect.width;
const scaleY = LOGICAL_HEIGHT / rect.height;
const x = (event.clientX - rect.left) * scaleX;
const y = (event.clientY - rect.top) * scaleY;
for (const callback of screenMouseDownCallbacks) { for (const callback of screenMouseDownCallbacks) {
callback(x, y); callback(x, y);
} }
@@ -97,6 +93,7 @@ const handleTouchStart = (event: TouchEvent) => {
const touch = event.touches[0]; const touch = event.touches[0];
if (!touch) return; if (!touch) return;
event.preventDefault();
swipeStartX = touch.clientX; swipeStartX = touch.clientX;
swipeStartY = touch.clientY; swipeStartY = touch.clientY;
@@ -113,6 +110,14 @@ const handleTouchEnd = (event: TouchEvent) => {
if (!touch) return; if (!touch) return;
dispatchSwipe(touch.clientX, touch.clientY); dispatchSwipe(touch.clientX, touch.clientY);
canvas.value?.dispatchEvent(
new MouseEvent("click", {
clientX: touch.clientX,
clientY: touch.clientY,
}),
);
document.dispatchEvent( document.dispatchEvent(
new MouseEvent("mouseup", { new MouseEvent("mouseup", {
clientX: touch.clientX, clientX: touch.clientX,
@@ -188,9 +193,7 @@ onMounted(() => {
canvas.value.addEventListener("click", handleCanvasClick); canvas.value.addEventListener("click", handleCanvasClick);
canvas.value.addEventListener("mousedown", handleCanvasMouseDown); canvas.value.addEventListener("mousedown", handleCanvasMouseDown);
canvas.value.addEventListener("wheel", handleCanvasWheel, { passive: true }); canvas.value.addEventListener("wheel", handleCanvasWheel, { passive: true });
canvas.value.addEventListener("touchstart", handleTouchStart, { canvas.value.addEventListener("touchstart", handleTouchStart);
passive: true,
});
canvas.value.addEventListener("touchend", handleTouchEnd, { passive: true }); canvas.value.addEventListener("touchend", handleTouchEnd, { passive: true });
canvas.value.addEventListener("mousedown", handleSwipeMouseDown); canvas.value.addEventListener("mousedown", handleSwipeMouseDown);
canvas.value.addEventListener("mouseup", handleSwipeMouseUp); canvas.value.addEventListener("mouseup", handleSwipeMouseUp);