Files
cup_edit/examples/dart/js_wasm/web/web_input_handler.dart
2025-05-07 17:06:38 +08:00

234 lines
6.8 KiB
Dart

import 'dart:js_interop';
import 'package:web/web.dart' as web;
import 'package:thermion_dart/thermion_dart.dart';
class WebInputHandler {
final DelegateInputHandler inputHandler;
final web.HTMLCanvasElement canvas;
late double pixelRatio;
final Map<int, Vector2> _touchPositions = {};
WebInputHandler({
required this.inputHandler,
required this.canvas,
}) {
pixelRatio = web.window.devicePixelRatio;
_initializeEventListeners();
}
void _initializeEventListeners() {
canvas.addEventListener('mousedown', _onMouseDown.toJS);
canvas.addEventListener('mousemove', _onMouseMove.toJS);
canvas.addEventListener('mouseup', _onMouseUp.toJS);
canvas.addEventListener('wheel', _onMouseWheel.toJS);
web.window.addEventListener('keydown', _onKeyDown.toJS);
web.window.addEventListener('keyup', _onKeyUp.toJS);
canvas.addEventListener('touchstart', _onTouchStart.toJS);
canvas.addEventListener('touchmove', _onTouchMove.toJS);
canvas.addEventListener('touchend', _onTouchEnd.toJS);
canvas.addEventListener('touchcancel', _onTouchCancel.toJS);
}
void _onMouseDown(web.MouseEvent event) {
final localPos = _getLocalPositionFromEvent(event);
final isMiddle = event.button == 1;
inputHandler.onPointerDown(localPos, isMiddle);
event.preventDefault();
}
void _onMouseMove(web.MouseEvent event) {
final localPos = _getLocalPositionFromEvent(event);
final delta = Vector2(event.movementX ?? 0, event.movementY ?? 0);
final isMiddle = event.buttons & 4 != 0;
inputHandler.onPointerMove(localPos, delta, isMiddle);
event.preventDefault();
}
void _onMouseUp(web.MouseEvent event) {
final isMiddle = event.button == 1;
inputHandler.onPointerUp(isMiddle);
event.preventDefault();
}
void _onMouseWheel(web.WheelEvent event) {
final localPos = _getLocalPositionFromEvent(event);
final delta = event.deltaY;
inputHandler.onPointerScroll(localPos, delta);
event.preventDefault();
}
void _onKeyDown(web.KeyboardEvent event) {
PhysicalKey? key;
switch (event.code) {
case 'KeyW':
key = PhysicalKey.W;
break;
case 'KeyA':
key = PhysicalKey.A;
break;
case 'KeyS':
key = PhysicalKey.S;
break;
case 'KeyD':
key = PhysicalKey.D;
break;
}
if (key != null) inputHandler.keyDown(key);
event.preventDefault();
}
void _onKeyUp(web.KeyboardEvent event) {
PhysicalKey? key;
switch (event.code) {
case 'KeyW':
key = PhysicalKey.W;
break;
case 'KeyA':
key = PhysicalKey.A;
break;
case 'KeyS':
key = PhysicalKey.S;
break;
case 'KeyD':
key = PhysicalKey.D;
break;
}
if (key != null) inputHandler.keyUp(key);
event.preventDefault();
}
void _onTouchStart(web.TouchEvent event) {
for (var touch in event.changedTouches.toList()) {
final pos = _getLocalPositionFromTouch(touch);
_touchPositions[touch.identifier] = pos;
}
final touchCount = event.touches.toList().length;
if (touchCount == 1) {
final touch = event.touches.toList().first;
final pos = _getLocalPositionFromTouch(touch);
inputHandler.onPointerDown(pos, false);
}
_handleScaleStart(touchCount, null);
event.preventDefault();
}
void _onTouchMove(web.TouchEvent event) {
for (var touch in event.changedTouches.toList()) {
final id = touch.identifier;
final currPos = _getLocalPositionFromTouch(touch);
final prevPos = _touchPositions[id];
if (prevPos != null) {
final delta = currPos - prevPos;
inputHandler.onPointerMove(currPos, delta, false);
}
_touchPositions[id] = currPos;
}
final touchCount = event.touches.toList().length;
if (touchCount >= 2) {
final touches = event.touches.toList().toList();
final touch0 = touches[0];
final touch1 = touches[1];
final pos0 = _getLocalPositionFromTouch(touch0);
final pos1 = _getLocalPositionFromTouch(touch1);
final prevPos0 = _touchPositions[touch0.identifier];
final prevPos1 = _touchPositions[touch1.identifier];
if (prevPos0 != null && prevPos1 != null) {
final prevDist = (prevPos0 - prevPos1).length;
final currDist = (pos0 - pos1).length;
final scale = currDist / prevDist;
final focalPoint = (pos0 + pos1) * 0.5;
inputHandler.onScaleUpdate(
focalPoint,
Vector2(0, 0),
0.0,
0.0,
scale,
touchCount,
0.0,
null,
);
}
}
event.preventDefault();
}
void _onTouchEnd(web.TouchEvent event) {
for (var touch in event.changedTouches.toList()) {
_touchPositions.remove(touch.identifier);
}
final touchCount = event.touches.toList().length;
inputHandler.onScaleEnd(touchCount, 0.0);
event.preventDefault();
}
void _onTouchCancel(web.TouchEvent event) {
for (var touch in event.changedTouches.toList()) {
_touchPositions.remove(touch.identifier);
}
final touchCount = event.touches.toList().length;
inputHandler.onScaleEnd(touchCount, 0.0);
event.preventDefault();
}
void _handleScaleStart(int pointerCount, Duration? sourceTimestamp) {
inputHandler.onScaleStart(Vector2.zero(), pointerCount, sourceTimestamp);
}
Vector2 _getLocalPositionFromEvent(web.Event event) {
final rect = canvas.getBoundingClientRect();
double clientX = 0, clientY = 0;
if (event is web.MouseEvent) {
clientX = event.clientX.toDouble();
clientY = event.clientY.toDouble();
} else if (event is web.TouchEvent) {
final touch = event.touches.toList().firstOrNull;
if (touch != null) {
clientX = touch.clientX;
clientY = touch.clientY;
}
}
return Vector2(
(clientX - rect.left) * pixelRatio,
(clientY - rect.top) * pixelRatio,
);
}
Vector2 _getLocalPositionFromTouch(web.Touch touch) {
final rect = canvas.getBoundingClientRect();
return Vector2(
(touch.clientX - rect.left) * pixelRatio,
(touch.clientY - rect.top) * pixelRatio,
);
}
void dispose() {
canvas.removeEventListener('mousedown', _onMouseDown.toJS);
canvas.removeEventListener('mousemove', _onMouseMove.toJS);
canvas.removeEventListener('mouseup', _onMouseUp.toJS);
canvas.removeEventListener('wheel', _onMouseWheel.toJS);
web.window.removeEventListener('keydown', _onKeyDown.toJS);
web.window.removeEventListener('keyup', _onKeyUp.toJS);
canvas.removeEventListener('touchstart', _onTouchStart.toJS);
canvas.removeEventListener('touchmove', _onTouchMove.toJS);
canvas.removeEventListener('touchend', _onTouchEnd.toJS);
canvas.removeEventListener('touchcancel', _onTouchCancel.toJS);
}
}