function DeviceOrientationControls(camera, domElement) {
    var scope = this;
    var changeEvent = { type: "change" };

    var rotY = 0;
    var rotX = 0;
    var tempX = 0;
    var tempY = 0;

    this.camera = camera;
    this.camera.rotation.reorder("YXZ");
    this.domElement = domElement !== undefined ? domElement : document;

    this.enabled = true;

    this.deviceOrientation = {};
    this.screenOrientation = 0;

    this.alpha = 0;
    this.alphaOffsetAngle = 0;

    var onDeviceOrientationChangeEvent = function (event) {
        scope.deviceOrientation = event;
    };

    var onScreenOrientationChangeEvent = function () {
        scope.screenOrientation = window.orientation || 0;
    };

    var onTouchStartEvent = function (event) {
        event.preventDefault();
        event.stopPropagation();

        tempX = event.touches[0].pageX;
        tempY = event.touches[0].pageY;
    };

    var onTouchMoveEvent = function (event) {
        event.preventDefault();
        event.stopPropagation();

        rotY += Math$1.degToRad((event.touches[0].pageX - tempX) / 4);
        rotX += Math$1.degToRad((tempY - event.touches[0].pageY) / 4);

        scope.updateAlphaOffsetAngle(rotY);

        tempX = event.touches[0].pageX;
        tempY = event.touches[0].pageY;
    };

    // The angles alpha, beta and gamma form a set of intrinsic Tait-Bryan angles of type Z-X'-Y''

    var setCameraQuaternion = function (
        quaternion,
        alpha,
        beta,
        gamma,
        orient
    ) {
        var zee = new Vector3(0, 0, 1);

        var euler = new Euler();

        var q0 = new Quaternion();

        var q1 = new Quaternion(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5)); // - PI/2 around the x-axis

        var vectorFingerY;
        var fingerQY = new Quaternion();
        var fingerQX = new Quaternion();

        if (scope.screenOrientation == 0) {
            vectorFingerY = new Vector3(1, 0, 0);
            fingerQY.setFromAxisAngle(vectorFingerY, -rotX);
        } else if (scope.screenOrientation == 180) {
            vectorFingerY = new Vector3(1, 0, 0);
            fingerQY.setFromAxisAngle(vectorFingerY, rotX);
        } else if (scope.screenOrientation == 90) {
            vectorFingerY = new Vector3(0, 1, 0);
            fingerQY.setFromAxisAngle(vectorFingerY, rotX);
        } else if (scope.screenOrientation == -90) {
            vectorFingerY = new Vector3(0, 1, 0);
            fingerQY.setFromAxisAngle(vectorFingerY, -rotX);
        }

        q1.multiply(fingerQY);
        q1.multiply(fingerQX);

        euler.set(beta, alpha, -gamma, "YXZ"); // 'ZXY' for the device, but 'YXZ' for us

        quaternion.setFromEuler(euler); // orient the device

        quaternion.multiply(q1); // camera looks out the back of the device, not the top

        quaternion.multiply(q0.setFromAxisAngle(zee, -orient)); // adjust for screen orientation
    };

    this.connect = function () {
        onScreenOrientationChangeEvent(); // run once on load

        window.addEventListener(
            "orientationchange",
            onScreenOrientationChangeEvent,
            { passive: true }
        );
        window.addEventListener(
            "deviceorientation",
            onDeviceOrientationChangeEvent,
            { passive: true }
        );
        window.addEventListener("deviceorientation", this.update.bind(this), {
            passive: true,
        });

        scope.domElement.addEventListener("touchstart", onTouchStartEvent, {
            passive: false,
        });
        scope.domElement.addEventListener("touchmove", onTouchMoveEvent, {
            passive: false,
        });

        scope.enabled = true;
    };

    this.disconnect = function () {
        window.removeEventListener(
            "orientationchange",
            onScreenOrientationChangeEvent,
            false
        );
        window.removeEventListener(
            "deviceorientation",
            onDeviceOrientationChangeEvent,
            false
        );
        window.removeEventListener(
            "deviceorientation",
            this.update.bind(this),
            false
        );

        scope.domElement.removeEventListener(
            "touchstart",
            onTouchStartEvent,
            false
        );
        scope.domElement.removeEventListener(
            "touchmove",
            onTouchMoveEvent,
            false
        );

        scope.enabled = false;
    };

    this.update = function (ignoreUpdate) {
        if (scope.enabled === false) return;

        var alpha = scope.deviceOrientation.alpha
            ? Math$1.degToRad(scope.deviceOrientation.alpha) +
              scope.alphaOffsetAngle
            : 0; // Z
        var beta = scope.deviceOrientation.beta
            ? Math$1.degToRad(scope.deviceOrientation.beta)
            : 0; // X'
        var gamma = scope.deviceOrientation.gamma
            ? Math$1.degToRad(scope.deviceOrientation.gamma)
            : 0; // Y''
        var orient = scope.screenOrientation
            ? Math$1.degToRad(scope.screenOrientation)
            : 0; // O

        setCameraQuaternion(
            scope.camera.quaternion,
            alpha,
            beta,
            gamma,
            orient
        );
        scope.alpha = alpha;

        if (ignoreUpdate !== true) {
            scope.dispatchEvent(changeEvent);
        }
    };

    this.updateAlphaOffsetAngle = function (angle) {
        this.alphaOffsetAngle = angle;
        this.update();
    };

    this.dispose = function () {
        this.disconnect();
    };

    this.connect();
}
@classdesc Device Orientation Control
@constructor
@external DeviceOrientationControls
@param {THREE.Camera} camera
@param {HTMLElement} domElement