Browse Source

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
Alexander Rose 2 years ago
parent
commit
2689d3f21a

+ 1 - 1
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 => {

+ 20 - 4
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>) => {

+ 3 - 2
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 }) => {

+ 22 - 1
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;