"use strict";//// androidControls.js//// Created by keeshii on September 26th, 2023.// Copyright 2022-2023 Overte e.V.//// This script read touch screen events and triggers mouse events.//// Distributed under the Apache License, Version 2.0.// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// SPDX-License-Identifier: Apache-2.0// (function () { Script.include("/~/system/libraries/controllerDispatcherUtils.js"); var DISPATCHER_TOUCH_PROPERTIES = ["id", "position", "rotation", "dimensions", "registrationPoint"]; var TAP_DELAY = 300; function AndroidControls() { this.onTouchStartFn = null; this.onTouchEndFn = null; this.touchStartTime = 0; } AndroidControls.prototype.intersectsEntity = function (intersection) { if (intersection && intersection.intersects && intersection.entityID) { return true; } return false; }; AndroidControls.prototype.findRayIntersection = function (pickRay) { // Check all entities. Argument is an object with origin and direction. var entityRayIntersection = Entities.findRayIntersection(pickRay, Picks.PICK_DOMAIN_ENTITIES | Picks.PICK_AVATAR_ENTITIES | Picks.PICK_LOCAL_ENTITIES); var isEntityInters = this.intersectsEntity(entityRayIntersection); if (isEntityInters) { return {type: 'entity', obj: entityRayIntersection}; } return false; }; AndroidControls.prototype.createEventProperties = function (entityId, info, eventType) { var pointerEvent = { type: eventType, id: 1, pos2D: {x: 0, y: 0}, pos3D: info.obj.intersection, normal: info.obj.surfaceNormal, direction: info.obj.direction, button: "Primary", isPrimaryButton: true, isLeftButton: true, isPrimaryHeld: eventType === 'Press', isSecondaryHeld: false, isTertiaryHeld: false, keyboardModifiers: 0 }; var properties = Entities.getEntityProperties(entityId, DISPATCHER_TOUCH_PROPERTIES); if (properties.id === entityId) { pointerEvent.pos2D = projectOntoEntityXYPlane(entityId, info.obj.intersection, properties); } return pointerEvent; }; AndroidControls.prototype.triggerClick = function (event) { var info = this.findRayIntersection(Camera.computePickRay(event.x, event.y)); if (!info) { return; } var entityId = info.obj.entityID; var pressEvent = this.createEventProperties(entityId, info, 'Press'); var releaseEvent = this.createEventProperties(entityId, info, 'Release'); Entities.sendMousePressOnEntity(entityId, pressEvent); Entities.sendClickDownOnEntity(entityId, pressEvent); Script.setTimeout(function () { Entities.sendMouseReleaseOnEntity(entityId, releaseEvent); Entities.sendClickReleaseOnEntity(entityId, releaseEvent); }, 75); }; AndroidControls.prototype.onTouchStart = function (_event) { this.touchStartTime = Date.now(); }; AndroidControls.prototype.onTouchEnd = function (event) { var now = Date.now(); if (now - this.touchStartTime < TAP_DELAY) { this.triggerClick(event); } this.touchStartTime = 0; }; AndroidControls.prototype.init = function () { var self = this; this.onTouchStartFn = function (ev) { self.onTouchStart(ev); }; this.onTouchEndFn = function (ev) { self.onTouchEnd(ev); }; Controller.touchBeginEvent.connect(this.onTouchStartFn); Controller.touchEndEvent.connect(this.onTouchEndFn); }; AndroidControls.prototype.ending = function () { if (this.onTouchStartFn) { Controller.touchBeginEvent.disconnect(this.onTouchStartFn); } if (this.onTouchEndFn) { Controller.touchEndEvent.disconnect(this.onTouchEndFn); } this.touchStartTime = 0; this.onTouchStartFn = null; this.onTouchEndFn = null; }; var androidControls = new AndroidControls(); Script.scriptEnding.connect(function () { androidControls.ending(); }); androidControls.init(); module.exports = androidControls;}());
"use strict";
//
// androidControls.js
//
// Created by keeshii on September 26th, 2023.
// Copyright 2022-2023 Overte e.V.
//
// This script read touch screen events and triggers mouse events.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// SPDX-License-Identifier: Apache-2.0
//
(function () {
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
var DISPATCHER_TOUCH_PROPERTIES = ["id", "position", "rotation", "dimensions", "registrationPoint"];
var TAP_DELAY = 300;
function AndroidControls() {
this.onTouchStartFn = null;
this.onTouchEndFn = null;
this.touchStartTime = 0;
}
AndroidControls.prototype.intersectsEntity = function (intersection) {
if (intersection && intersection.intersects && intersection.entityID) {
return true;
}
return false;
};
AndroidControls.prototype.findRayIntersection = function (pickRay) {
// Check all entities. Argument is an object with origin and direction.
var entityRayIntersection = Entities.findRayIntersection(pickRay, Picks.PICK_DOMAIN_ENTITIES | Picks.PICK_AVATAR_ENTITIES | Picks.PICK_LOCAL_ENTITIES);
var isEntityInters = this.intersectsEntity(entityRayIntersection);
if (isEntityInters) {
return {type: 'entity', obj: entityRayIntersection};
}
return false;
};
AndroidControls.prototype.createEventProperties = function (entityId, info, eventType) {
var pointerEvent = {
type: eventType,
id: 1,
pos2D: {x: 0, y: 0},
pos3D: info.obj.intersection,
normal: info.obj.surfaceNormal,
direction: info.obj.direction,
button: "Primary",
isPrimaryButton: true,
isLeftButton: true,
isPrimaryHeld: eventType === 'Press',
isSecondaryHeld: false,
isTertiaryHeld: false,
keyboardModifiers: 0
};
var properties = Entities.getEntityProperties(entityId, DISPATCHER_TOUCH_PROPERTIES);
if (properties.id === entityId) {
pointerEvent.pos2D = projectOntoEntityXYPlane(entityId, info.obj.intersection, properties);
}
return pointerEvent;
};
AndroidControls.prototype.triggerClick = function (event) {
var info = this.findRayIntersection(Camera.computePickRay(event.x, event.y));
if (!info) {
return;
}
var entityId = info.obj.entityID;
var pressEvent = this.createEventProperties(entityId, info, 'Press');
var releaseEvent = this.createEventProperties(entityId, info, 'Release');
Entities.sendMousePressOnEntity(entityId, pressEvent);
Entities.sendClickDownOnEntity(entityId, pressEvent);
Script.setTimeout(function () {
Entities.sendMouseReleaseOnEntity(entityId, releaseEvent);
Entities.sendClickReleaseOnEntity(entityId, releaseEvent);
}, 75);
};
AndroidControls.prototype.onTouchStart = function (_event) {
this.touchStartTime = Date.now();
};
AndroidControls.prototype.onTouchEnd = function (event) {
var now = Date.now();
if (now - this.touchStartTime < TAP_DELAY) {
this.triggerClick(event);
}
this.touchStartTime = 0;
};
AndroidControls.prototype.init = function () {
var self = this;
this.onTouchStartFn = function (ev) {
self.onTouchStart(ev);
};
this.onTouchEndFn = function (ev) {
self.onTouchEnd(ev);
};
Controller.touchBeginEvent.connect(this.onTouchStartFn);
Controller.touchEndEvent.connect(this.onTouchEndFn);
};
AndroidControls.prototype.ending = function () {
if (this.onTouchStartFn) {
Controller.touchBeginEvent.disconnect(this.onTouchStartFn);
}
if (this.onTouchEndFn) {
Controller.touchEndEvent.disconnect(this.onTouchEndFn);
}
this.touchStartTime = 0;
this.onTouchStartFn = null;
this.onTouchEndFn = null;
};
var androidControls = new AndroidControls();
Script.scriptEnding.connect(function () {
androidControls.ending();
});
androidControls.init();
module.exports = androidControls;
}());