Fix inverted touch controls

This commit is contained in:
Brian Beck 2026-03-15 09:07:36 -07:00
parent cd2819d28a
commit d336c20098
27 changed files with 46 additions and 31 deletions

View file

@ -201,6 +201,8 @@
.IconButton:disabled {
opacity: 0.6;
box-shadow: inset 0 0 12px 1px rgba(54, 54, 54, 0.5);
color: rgba(255, 255, 255, 0.8);
cursor: default;
}

View file

@ -9,6 +9,7 @@ import {
} from "./SettingsProvider";
import { useCameras } from "./CamerasProvider";
import { useInputContext } from "./InputContext";
import { useTouchDevice } from "./useTouchDevice";
export enum Controls {
forward = "forward",
@ -71,6 +72,8 @@ function quantizeSpeed(speedMultiplier: number): number {
}
export function MouseAndKeyboardHandler() {
const isTouch = useTouchDevice();
// Don't let KeyboardControls handle stuff when metaKey is held.
useEffect(() => {
const handleKey = (e: KeyboardEvent) => {
@ -110,6 +113,7 @@ export function MouseAndKeyboardHandler() {
const getInvertDrag = useEffectEvent(() => invertDrag);
const getMode = useEffectEvent(() => mode);
const getMouseSensitivity = useEffectEvent(() => mouseSensitivity);
const getIsTouch = useEffectEvent(() => isTouch);
// Accumulated mouse deltas between frames.
const mouseDeltaYaw = useRef(0);
@ -129,6 +133,13 @@ export function MouseAndKeyboardHandler() {
};
}, [camera, gl.domElement]);
// Exit pointer lock when switching to touch mode.
useEffect(() => {
if (isTouch && controlsRef.current?.isLocked) {
controlsRef.current.unlock();
}
}, [isTouch]);
// Mouse handling: accumulate deltas for input frames.
// In local mode, drag-to-look works without pointer lock.
// Pointer lock and click behavior depend on mode.
@ -191,7 +202,7 @@ export function MouseAndKeyboardHandler() {
nextCamera();
}
// In fly mode, clicks while locked do nothing special.
} else if (e.target === canvas && !didDrag) {
} else if (e.target === canvas && !didDrag && !getIsTouch()) {
controls?.lock();
}
};

View file

@ -57,7 +57,7 @@ export function TouchHandler() {
const dy = touch.clientY - lastTouchPos.current.y;
lastTouchPos.current = { x: touch.clientX, y: touch.clientY };
const dragSign = getInvertDrag() ? -1 : 1;
const dragSign = getInvertDrag() ? 1 : -1;
touchDeltaYaw.current += dragSign * dx * LOOK_SENSITIVITY;
touchDeltaPitch.current += dragSign * dy * LOOK_SENSITIVITY;
break;
@ -109,7 +109,7 @@ export function TouchHandler() {
const lookX = Math.cos(lookAngle);
const lookY = Math.sin(lookAngle);
const joySign = invertJoystick ? -1 : 1;
const joySign = invertJoystick ? 1 : -1;
deltaYaw -=
joySign *
lookX *
@ -134,7 +134,7 @@ export function TouchHandler() {
// Map joystick to movement axes, pre-scaled by speedMultiplier.
x = Math.max(
-1,
Math.min(1, -joyX * normalizedMoveForce * speedMultiplier),
Math.min(1, joyX * normalizedMoveForce * speedMultiplier),
);
y = Math.max(
-1,
@ -153,7 +153,7 @@ export function TouchHandler() {
const normalizedLookForce =
(moveForce - SINGLE_STICK_DEADZONE) / (1 - SINGLE_STICK_DEADZONE);
const singleJoySign = invertJoystick ? -1 : 1;
const singleJoySign = invertJoystick ? 1 : -1;
deltaYaw -=
singleJoySign *
lookX *

View file

@ -43,6 +43,7 @@ export function TouchJoystick() {
position: { left: "70px", bottom: "70px" },
size: 120,
restOpacity: 0.9,
dynamicPage: true,
});
applyNippleStyles(moveZone);
@ -80,6 +81,7 @@ export function TouchJoystick() {
position: { right: "70px", bottom: "70px" },
size: 120,
restOpacity: 0.9,
dynamicPage: true,
});
applyNippleStyles(lookZone);