278 lines · 12.9 KB · JavaScript
RawDownload
"use strict"; //  webSurfaceLaserInput.js////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html /* global Script, Entities, enableDispatcherModule, disableDispatcherModule, makeRunningValues,   makeDispatcherModuleParameters, Overlays, HMD, TRIGGER_ON_VALUE, TRIGGER_OFF_VALUE, getEnabledModuleByName,   Picks, makeLaserParams, Settings, MyAvatar, RIGHT_HAND, LEFT_HAND*/ Script.include("/~/system/libraries/controllerDispatcherUtils.js");Script.include("/~/system/libraries/controllers.js"); (function() {    const intersectionType = {        None: 0,        WebOverlay: 1,        WebEntity: 2,        HifiKeyboard: 3,        Overlay: 4,        HifiTablet: 5,    };     function WebSurfaceLaserInput(hand) {        this.hand = hand;        this.otherHand = this.hand === RIGHT_HAND ? LEFT_HAND : RIGHT_HAND;        this.running = false;        this.ignoredObjects = [];        this.intersectedType = intersectionType["None"];         this.parameters = makeDispatcherModuleParameters(            160,            this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"],            [],            100,            makeLaserParams(hand, true));         this.getFarGrab = function () {            return getEnabledModuleByName(this.hand === RIGHT_HAND ? ("RightFarGrabEntity") : ("LeftFarGrabEntity"));        };         this.farGrabActive = function () {            var farGrab = this.getFarGrab();            // farGrab will be null if module isn't loaded.            if (farGrab) {                return farGrab.targetIsNull();            } else {                return false;            }        };         this.grabModuleWantsNearbyOverlay = function(controllerData) {            if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE || controllerData.secondaryValues[this.hand] > BUMPER_ON_VALUE) {                var nearGrabName = this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay";                var nearGrabModule = getEnabledModuleByName(nearGrabName);                if (nearGrabModule) {                    var candidateOverlays = controllerData.nearbyOverlayIDs[this.hand];                    var grabbableOverlays = candidateOverlays.filter(function(overlayID) {                        //V8TODO: this needs to be checked if it works                        return Entities.getEntityProperties(overlayID, ["grab.grabbable"]).grab.grabbable;                    });                    var target = nearGrabModule.getTargetID(grabbableOverlays, controllerData);                    if (target) {                        return true;                    }                }                nearGrabName = this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity";                nearGrabModule = getEnabledModuleByName(nearGrabName);                if (nearGrabModule && nearGrabModule.isReady(controllerData)) {                    // check for if near parent module is active.                    var isNearGrabModuleActive = nearGrabModule.isReady(controllerData).active;                    if (isNearGrabModuleActive) {                        // if true, return true.                        return isNearGrabModuleActive;                    } else {                        // check near action grab entity as a second pass.                        nearGrabName = this.hand === RIGHT_HAND ? "RightNearActionGrabEntity" : "LeftNearActionGrabEntity";                        nearGrabModule = getEnabledModuleByName(nearGrabName);                        if (nearGrabModule && nearGrabModule.isReady(controllerData)) {                            return nearGrabModule.isReady(controllerData).active;                        }                    }                }            }             var nearTabletHighlightModule = getEnabledModuleByName(this.hand === RIGHT_HAND                ? "RightNearTabletHighlight" : "LeftNearTabletHighlight");            if (nearTabletHighlightModule) {                return nearTabletHighlightModule.isNearTablet(controllerData);            }             return false;        };         this.getOtherModule = function() {            return this.hand === RIGHT_HAND ? leftOverlayLaserInput : rightOverlayLaserInput;        };         this.addObjectToIgnoreList = function(controllerData) {            if (Window.interstitialModeEnabled && !Window.isPhysicsEnabled()) {                var intersection = controllerData.rayPicks[this.hand];                var objectID = intersection.objectID;                 if (intersection.type === Picks.INTERSECTED_OVERLAY) {                    var overlayIndex = this.ignoredObjects.indexOf(objectID);                     var overlayName = Entities.getEntityProperties(objectID, ["name"]).name;                    if (overlayName !== "Loading-Destination-Card-Text" && overlayName !== "Loading-Destination-Card-GoTo-Image" &&                        overlayName !== "Loading-Destination-Card-GoTo-Image-Hover") {                        var data = {                            action: 'add',                            id: objectID                        };                        Messages.sendMessage('Hifi-Hand-RayPick-Blocklist', JSON.stringify(data));                        this.ignoredObjects.push(objectID);                    }                } else if (intersection.type === Picks.INTERSECTED_ENTITY) {                    var entityIndex = this.ignoredObjects.indexOf(objectID);                    var data = {                        action: 'add',                        id: objectID                    };                    Messages.sendMessage('Hifi-Hand-RayPick-Blocklist', JSON.stringify(data));                    this.ignoredObjects.push(objectID);                }            }        };         this.restoreIgnoredObjects = function() {            for (var index = 0; index < this.ignoredObjects.length; index++) {                var data = {                    action: 'remove',                    id: this.ignoredObjects[index]                };                Messages.sendMessage('Hifi-Hand-RayPick-Blocklist', JSON.stringify(data));            }             this.ignoredObjects = [];        };         this.getInteractableType = function(controllerData, triggerPressed) {            // allow pointing at tablet, unlocked web entities, or web overlays automatically without pressing trigger,            // but for pointing at locked web entities or non-web overlays user must be pressing trigger            var intersection = controllerData.rayPicks[this.hand];            var objectID = intersection.objectID;            var entityProperties = Entities.getEntityProperties(objectID, ["type","locked"]);            var entityType = entityProperties.type;            var isLocked = entityProperties.locked;            if (entityType === "Web" && (!isLocked || triggerPressed)) {                return intersectionType["WebEntity"];            }            return intersectionType["None"];        };         this.updateAlwaysOn = function(type) {            var PREFER_STYLUS_OVER_LASER = "preferStylusOverLaser";            this.parameters.handLaser.alwaysOn = (!Settings.getValue(PREFER_STYLUS_OVER_LASER, false) || type === intersectionType["HifiKeyboard"]);        };         this.getDominantHand = function() {            return MyAvatar.getDominantHand() === "right" ? 1 : 0;        };         this.dominantHandOverride = false;         this.isReady = function (controllerData) {            // Trivial rejection for when FarGrab is active.            if (this.farGrabActive()) {                return makeRunningValues(false, [], []);            }             var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE &&                                   controllerData.triggerValues[this.otherHand] <= TRIGGER_OFF_VALUE;            var type = this.getInteractableType(controllerData, isTriggerPressed);             if (type !== intersectionType["None"] && !this.grabModuleWantsNearbyOverlay(controllerData)) {                if (type === intersectionType["WebEntity"]) {                    var otherModuleRunning = this.getOtherModule().running;                    otherModuleRunning = otherModuleRunning && this.getDominantHand() !== this.hand; // Auto-swap to dominant hand.                    var allowThisModule = !otherModuleRunning || isTriggerPressed;                     if (!allowThisModule) {                        return makeRunningValues(true, [], []);                    }                     if (isTriggerPressed) {                        this.dominantHandOverride = true; // Override dominant hand.                        this.getOtherModule().dominantHandOverride = false;                    }                }                 this.updateAlwaysOn(type);                if (this.parameters.handLaser.alwaysOn || isTriggerPressed) {                    return makeRunningValues(true, [], []);                }            }             if (Window.interstitialModeEnabled && Window.isPhysicsEnabled()) {                this.restoreIgnoredObjects();            }            return makeRunningValues(false, [], []);        };         this.shouldThisModuleRun = function(controllerData) {            var otherModuleRunning = this.getOtherModule().running;            otherModuleRunning = otherModuleRunning && this.getDominantHand() !== this.hand; // Auto-swap to dominant hand.            otherModuleRunning = otherModuleRunning || this.getOtherModule().dominantHandOverride; // Override dominant hand.            var grabModuleNeedsToRun = this.grabModuleWantsNearbyOverlay(controllerData);            // only allow for non-near grab            return !otherModuleRunning && !grabModuleNeedsToRun;        };         const SCROLL_MAPPING_NAME = `overte.thumbstick_scroll_${this.hand}.web`;        this.scrollMappingEnabled = false;        this.scrollMapping = Controller.newMapping(SCROLL_MAPPING_NAME);        this.stickXMapping = this.scrollMapping.from(            this.hand == LEFT_HAND ? Controller.Standard.LX : Controller.Standard.RX        ).to(function(_value) { /* dummy to temporarily eat stick input */ });        this.stickYMapping = this.scrollMapping.from(            this.hand == LEFT_HAND ? Controller.Standard.LY : Controller.Standard.RY        ).to(function(_value) { /* dummy to temporarily eat stick input */ });         this.run = function(controllerData, deltaTime) {            this.addObjectToIgnoreList(controllerData);            var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE;            var type = this.getInteractableType(controllerData, isTriggerPressed);            var laserOn = isTriggerPressed || this.parameters.handLaser.alwaysOn;            this.addObjectToIgnoreList(controllerData);             if (type === intersectionType["HifiTablet"] && laserOn) {                if (this.shouldThisModuleRun(controllerData)) {                    if (!this.scrollMappingEnabled) {                        this.scrollMapping.enable();                        this.scrollMappingEnabled = true;                    }                    this.running = true;                    return makeRunningValues(true, [], []);                }            } else if ((type === intersectionType["WebOverlay"] || type === intersectionType["WebEntity"]) && laserOn) { // auto laser on WebEntities andWebOverlays                if (this.shouldThisModuleRun(controllerData)) {                    if (!this.scrollMappingEnabled) {                        this.scrollMapping.enable();                        this.scrollMappingEnabled = true;                    }                    this.running = true;                    return makeRunningValues(true, [], []);                }            } else if ((type === intersectionType["HifiKeyboard"] && laserOn) || type === intersectionType["Overlay"]) {                if (!this.scrollMappingEnabled) {                    this.scrollMapping.enable();                    this.scrollMappingEnabled = true;                }                this.running = true;                return makeRunningValues(true, [], []);            }             this.scrollMapping.disable();            this.scrollMappingEnabled = false;            this.running = false;            this.dominantHandOverride = false;            return makeRunningValues(false, [], []);        };    }     var leftOverlayLaserInput = new WebSurfaceLaserInput(LEFT_HAND);    var rightOverlayLaserInput = new WebSurfaceLaserInput(RIGHT_HAND);     enableDispatcherModule("LeftWebSurfaceLaserInput", leftOverlayLaserInput);    enableDispatcherModule("RightWebSurfaceLaserInput", rightOverlayLaserInput);     function cleanup() {        disableDispatcherModule("LeftWebSurfaceLaserInput");        disableDispatcherModule("RightWebSurfaceLaserInput");    }    Script.scriptEnding.connect(cleanup);}());