Skip to content

Commit 4da6d75

Browse files
olga-microsoftdmarcos
authored andcommitted
Added support and tests for vrdisplaypointerrestricted events to the a-scene element (#3014)
1 parent 20e640a commit 4da6d75

File tree

2 files changed

+138
-1
lines changed

2 files changed

+138
-1
lines changed

src/core/scene/a-scene.js

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ var warn = utils.debug('core:a-scene:warn');
3131
* @member {object} object3D - Root three.js Scene object.
3232
* @member {object} renderer
3333
* @member {bool} renderStarted
34-
* @member (object) effect - three.js VREffect
34+
* @member {object} effect - three.js VREffect
3535
* @member {object} systems - Registered instantiated systems.
3636
* @member {number} time
3737
*/
@@ -119,6 +119,8 @@ module.exports.AScene = registerElement('a-scene', {
119119
this.enterVRBound = function () { self.enterVR(); };
120120
this.exitVRBound = function () { self.exitVR(); };
121121
this.exitVRTrueBound = function () { self.exitVR(true); };
122+
this.pointerRestrictedBound = function () { self.pointerRestricted(); };
123+
this.pointerUnrestrictedBound = function () { self.pointerUnrestricted(); };
122124

123125
// Enter VR on `vrdisplayactivate` (e.g. putting on Rift headset).
124126
window.addEventListener('vrdisplayactivate', this.enterVRBound);
@@ -131,6 +133,14 @@ module.exports.AScene = registerElement('a-scene', {
131133

132134
// Exit VR on `vrdisplaydisconnect` (e.g. unplugging Rift headset).
133135
window.addEventListener('vrdisplaydisconnect', this.exitVRTrueBound);
136+
137+
// Register for mouse restricted events while in VR
138+
// (e.g. mouse no longer available on desktop 2D view)
139+
window.addEventListener('vrdisplaypointerrestricted', this.pointerRestrictedBound);
140+
141+
// Register for mouse unrestricted events while in VR
142+
// (e.g. mouse once again available on desktop 2D view)
143+
window.addEventListener('vrdisplaypointerunrestricted', this.pointerUnrestrictedBound);
134144
},
135145
writable: window.debug
136146
},
@@ -178,6 +188,8 @@ module.exports.AScene = registerElement('a-scene', {
178188
window.removeEventListener('vrdisplaydeactivate', this.exitVRBound);
179189
window.removeEventListener('vrdisplayconnect', this.enterVRBound);
180190
window.removeEventListener('vrdisplaydisconnect', this.exitVRTrueBound);
191+
window.removeEventListener('vrdisplaypointerrestricted', this.pointerRestrictedBound);
192+
window.removeEventListener('vrdisplaypointerunrestricted', this.pointerUnrestrictedBound);
181193
}
182194
},
183195

@@ -202,6 +214,16 @@ module.exports.AScene = registerElement('a-scene', {
202214
}
203215
},
204216

217+
/**
218+
* For tests.
219+
*/
220+
getPointerLockElement: {
221+
value: function () {
222+
return document.pointerLockElement;
223+
},
224+
writable: window.debug
225+
},
226+
205227
/**
206228
* For tests.
207229
*/
@@ -317,6 +339,31 @@ module.exports.AScene = registerElement('a-scene', {
317339
writable: window.debug
318340
},
319341

342+
pointerRestricted: {
343+
value: function () {
344+
if (this.canvas) {
345+
var pointerLockElement = this.getPointerLockElement();
346+
if (pointerLockElement && pointerLockElement !== this.canvas && document.exitPointerLock) {
347+
// Recreate pointer lock on the canvas, if taken on another element.
348+
document.exitPointerLock();
349+
}
350+
351+
if (this.canvas.requestPointerLock) {
352+
this.canvas.requestPointerLock();
353+
}
354+
}
355+
}
356+
},
357+
358+
pointerUnrestricted: {
359+
value: function () {
360+
var pointerLockElement = this.getPointerLockElement();
361+
if (pointerLockElement && pointerLockElement === this.canvas && document.exitPointerLock) {
362+
document.exitPointerLock();
363+
}
364+
}
365+
},
366+
320367
/**
321368
* Handle `vrdisplaypresentchange` event for exiting VR through other means than
322369
* `<ESC>` key. For example, GearVR back button on Oculus Browser.

tests/core/scene/a-scene.test.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,96 @@ suite('a-scene (without renderer)', function () {
403403
});
404404
});
405405

406+
suite('pointerRestricted', function () {
407+
setup(function () {
408+
var sceneEl = this.el;
409+
410+
// Stub canvas.
411+
sceneEl.canvas = document.createElement('canvas');
412+
});
413+
414+
test('requests pointerlock when restricted', function (done) {
415+
var sceneEl = this.el;
416+
var event;
417+
var requestPointerLockSpy;
418+
419+
requestPointerLockSpy = this.sinon.spy(sceneEl.canvas, 'requestPointerLock');
420+
event = new CustomEvent('vrdisplaypointerrestricted');
421+
window.dispatchEvent(event);
422+
423+
process.nextTick(function () {
424+
assert.ok(requestPointerLockSpy.called);
425+
done();
426+
});
427+
});
428+
429+
test('exits pointerlock when unrestricted', function (done) {
430+
var sceneEl = this.el;
431+
var event;
432+
var exitPointerLockSpy;
433+
434+
exitPointerLockSpy = this.sinon.spy(document, 'exitPointerLock');
435+
436+
event = new CustomEvent('vrdisplaypointerunrestricted');
437+
438+
this.sinon.stub(sceneEl, 'getPointerLockElement', function () {
439+
return sceneEl.canvas;
440+
});
441+
window.dispatchEvent(event);
442+
443+
process.nextTick(function () {
444+
assert.ok(exitPointerLockSpy.called);
445+
done();
446+
});
447+
});
448+
449+
test('does not exit pointerlock when unrestricted on different locked element', function (done) {
450+
var sceneEl = this.el;
451+
var event;
452+
var exitPointerLockSpy;
453+
454+
exitPointerLockSpy = this.sinon.spy(document, 'exitPointerLock');
455+
456+
event = new CustomEvent('vrdisplaypointerunrestricted');
457+
458+
this.sinon.stub(sceneEl, 'getPointerLockElement', function () {
459+
// Mock that pointerlock is taken by the page itself,
460+
// independently of the a-scene handler for vrdisplaypointerrestricted event
461+
return document.createElement('canvas');
462+
});
463+
window.dispatchEvent(event);
464+
465+
process.nextTick(function () {
466+
assert.notOk(exitPointerLockSpy.called);
467+
done();
468+
});
469+
});
470+
471+
test('update existing pointerlock target when restricted', function (done) {
472+
var sceneEl = this.el;
473+
var event;
474+
var exitPointerLockSpy;
475+
var requestPointerLockSpy;
476+
477+
exitPointerLockSpy = this.sinon.spy(document, 'exitPointerLock');
478+
requestPointerLockSpy = this.sinon.spy(sceneEl.canvas, 'requestPointerLock');
479+
event = new CustomEvent('vrdisplaypointerrestricted');
480+
481+
this.sinon.stub(sceneEl, 'getPointerLockElement', function () {
482+
// Mock that pointerlock is taken by the page itself,
483+
// independently of the a-scene handler for vrdisplaypointerrestricted event
484+
return document.createElement('canvas');
485+
});
486+
window.dispatchEvent(event);
487+
488+
process.nextTick(function () {
489+
assert.ok(exitPointerLockSpy.called);
490+
assert.ok(requestPointerLockSpy.called);
491+
done();
492+
});
493+
});
494+
});
495+
406496
suite('system', function () {
407497
teardown(function () {
408498
delete components.test;

0 commit comments

Comments
 (0)