From 2689d3f21a9b4600ee14f31e26630797fa240830 Mon Sep 17 00:00:00 2001 From: Alexander Rose <alexander.rose@weirdbyte.de> Date: Tue, 28 Mar 2023 23:22:55 -0700 Subject: [PATCH] more input/controls fixes & tweaks - no identify when pointer-lock & controls movement - limit controls key bindings to viewport - take controls minDistance into account for movement --- src/mol-canvas3d/canvas3d.ts | 2 +- src/mol-canvas3d/controls/trackball.ts | 24 +++++++++++++++---- src/mol-canvas3d/helper/interaction-events.ts | 5 ++-- src/mol-util/input/input-observer.ts | 23 +++++++++++++++++- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts index 9e38b7613..0732dd719 100644 --- a/src/mol-canvas3d/canvas3d.ts +++ b/src/mol-canvas3d/canvas3d.ts @@ -337,7 +337,7 @@ namespace Canvas3D { const helper = new Helper(webgl, scene, p); const pickHelper = new PickHelper(webgl, renderer, scene, helper, passes.pick, { x, y, width, height }, attribs.pickPadding); - const interactionHelper = new Canvas3dInteractionHelper(identify, getLoci, input, camera, p.interaction); + const interactionHelper = new Canvas3dInteractionHelper(identify, getLoci, input, camera, controls, p.interaction); const multiSampleHelper = new MultiSampleHelper(passes.multiSample); passes.draw.postprocessing.background.update(camera, p.postprocessing.background, changed => { diff --git a/src/mol-canvas3d/controls/trackball.ts b/src/mol-canvas3d/controls/trackball.ts index fe9dfb3f9..44117c8c3 100644 --- a/src/mol-canvas3d/controls/trackball.ts +++ b/src/mol-canvas3d/controls/trackball.ts @@ -106,6 +106,7 @@ export { TrackballControls }; interface TrackballControls { readonly viewport: Viewport readonly isAnimating: boolean + readonly isMoving: boolean readonly props: Readonly<TrackballControlsProps> setProps: (props: Partial<TrackballControlsProps>) => void @@ -379,8 +380,9 @@ namespace TrackballControls { const moveEye = Vec3(); function moveCamera(deltaT: number) { + const minDistance = Math.max(camera.state.minNear, p.minDistance); Vec3.sub(moveEye, camera.position, camera.target); - Vec3.setMagnitude(moveEye, moveEye, camera.state.minNear); + Vec3.setMagnitude(moveEye, moveEye, minDistance); const moveSpeed = deltaT * (60 / 1000) * p.moveSpeed * (keyState.boostMove === 1 ? p.boostMoveFactor : 1); @@ -389,7 +391,7 @@ namespace TrackballControls { Vec3.scaleAndSub(camera.position, camera.position, moveDir, moveSpeed); const dt = Vec3.distance(camera.target, camera.position); const ds = Vec3.distance(scene.boundingSphereVisible.center, camera.position); - if (p.flyMode || input.pointerLock || (dt < camera.state.minNear && ds < camera.state.radiusMax)) { + if (p.flyMode || input.pointerLock || (dt < minDistance && ds < camera.state.radiusMax)) { Vec3.sub(camera.target, camera.position, moveEye); } } @@ -636,7 +638,9 @@ namespace TrackballControls { Vec2.copy(_rotCurr, getMouseOnCircle(movementX + cx, movementY + cy)); } - function onKeyDown({ modifiers, code }: KeyInput) { + function onKeyDown({ modifiers, code, x, y }: KeyInput) { + if (outsideViewport(x, y)) return; + if (Binding.matchKey(b.keyMoveForward, code, modifiers)) { keyState.moveForward = 1; } else if (Binding.matchKey(b.keyMoveBack, code, modifiers)) { @@ -672,7 +676,9 @@ namespace TrackballControls { } } - function onKeyUp({ modifiers, code }: KeyInput) { + function onKeyUp({ modifiers, code, x, y }: KeyInput) { + if (outsideViewport(x, y)) return; + if (Binding.matchKey(b.keyMoveForward, code, modifiers)) { keyState.moveForward = 0; } else if (Binding.matchKey(b.keyMoveBack, code, modifiers)) { @@ -784,6 +790,16 @@ namespace TrackballControls { return { viewport, get isAnimating() { return p.animate.name !== 'off'; }, + get isMoving() { + return ( + keyState.moveForward === 1 || keyState.moveBack === 1 || + keyState.moveLeft === 1 || keyState.moveRight === 1 || + keyState.moveUp === 1 || keyState.moveDown === 1 || + keyState.rollLeft === 1 || keyState.rollRight === 1 || + keyState.pitchUp === 1 || keyState.pitchDown === 1 || + keyState.yawLeft === 1 || keyState.yawRight === 1 + ); + }, get props() { return p as Readonly<TrackballControlsProps>; }, setProps: (props: Partial<TrackballControlsProps>) => { diff --git a/src/mol-canvas3d/helper/interaction-events.ts b/src/mol-canvas3d/helper/interaction-events.ts index ad2046dfa..8279a92eb 100644 --- a/src/mol-canvas3d/helper/interaction-events.ts +++ b/src/mol-canvas3d/helper/interaction-events.ts @@ -13,6 +13,7 @@ import { Vec2, Vec3 } from '../../mol-math/linear-algebra'; import { Camera } from '../camera'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { Bond } from '../../mol-model/structure'; +import { TrackballControls } from '../controls/trackball'; type Canvas3D = import('../canvas3d').Canvas3D type HoverEvent = import('../canvas3d').Canvas3D.HoverEvent @@ -68,7 +69,7 @@ export class Canvas3dInteractionHelper { } private identify(e: InputEvent, t: number) { - const xyChanged = this.startX !== this.endX || this.startY !== this.endY || this.input.pointerLock; + const xyChanged = this.startX !== this.endX || this.startY !== this.endY || (this.input.pointerLock && !this.controls.isMoving); if (e === InputEvent.Drag) { if (xyChanged && !this.outsideViewport(this.startX, this.startY)) { @@ -188,7 +189,7 @@ export class Canvas3dInteractionHelper { this.ev.dispose(); } - constructor(private canvasIdentify: Canvas3D['identify'], private lociGetter: Canvas3D['getLoci'], private input: InputObserver, private camera: Camera, props: Partial<Canvas3dInteractionHelperProps> = {}) { + constructor(private canvasIdentify: Canvas3D['identify'], private lociGetter: Canvas3D['getLoci'], private input: InputObserver, private camera: Camera, private controls: TrackballControls, props: Partial<Canvas3dInteractionHelperProps> = {}) { this.props = { ...PD.getDefaultValues(Canvas3dInteractionHelperParams), ...props }; input.drag.subscribe(({ x, y, buttons, button, modifiers }) => { diff --git a/src/mol-util/input/input-observer.ts b/src/mol-util/input/input-observer.ts index fa9ea2180..cca94225a 100644 --- a/src/mol-util/input/input-observer.ts +++ b/src/mol-util/input/input-observer.ts @@ -194,7 +194,10 @@ export type KeyInput = { key: string, code: string, modifiers: ModifiersKeys - + x: number, + y: number, + pageX: number, + pageY: number, /** for overwriting browser shortcuts like `ctrl+s` as needed */ preventDefault: () => void } @@ -203,6 +206,10 @@ export const EmptyKeyInput: KeyInput = { key: '', code: '', modifiers: ModifiersKeys.None, + x: -1, + y: -1, + pageX: -1, + pageY: -1, preventDefault: noop, }; @@ -327,6 +334,12 @@ namespace InputObserver { control: false, meta: false }; + const position = { + x: -1, + y: -1, + pageX: -1, + pageY: -1, + }; function pixelRatio() { return window.devicePixelRatio * pixelScale; @@ -468,6 +481,7 @@ namespace InputObserver { key: event.key, code: event.code, modifiers: getModifierKeys(), + ...position, preventDefault: () => event.preventDefault(), }); } @@ -490,6 +504,7 @@ namespace InputObserver { key: event.key, code: event.code, modifiers: getModifierKeys(), + ...position, preventDefault: () => event.preventDefault(), }); } @@ -502,6 +517,7 @@ namespace InputObserver { key: event.key, code: event.code, modifiers: getModifierKeys(), + ...position, preventDefault: () => event.preventDefault(), }); } @@ -669,6 +685,11 @@ namespace InputObserver { } isInside = inside; + position.x = x; + position.y = y; + position.pageX = pageX; + position.pageY = pageY; + move.next({ x, y, pageX, pageY, movementX, movementY, buttons, button, modifiers: getModifierKeys(), inside, onElement: ev.target === element }); if (dragging === DraggingState.Stopped) return; -- GitLab