Last active
July 11, 2019 21:41
-
-
Save Jimbly/07ea52f8380f7de3a592567d50dde47c to your computer and use it in GitHub Desktop.
Deal with pointerlockerror on Safari
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<!-- Modified version of pointer lock code to lock on click from the main loop, works on Safari --> | |
<html lang="en"><head> | |
<title>Pointer Lock Test</title> | |
</head> | |
<body onload="startup()"> | |
<div id="status-element" style="background-color: #FEE; white-space: pre-wrap;">dragx=0, dragy=0 | |
double clicks: 0</div> | |
<script> | |
/* eslint no-bitwise:off, no-unused-expressions:off, vars-on-top:off, no-implicit-coercion:off */ | |
// The element we'll make pointer locked. | |
var dragx=0; | |
var dragy=0; | |
var doubleclicks=0; | |
var down_mask = 0; | |
var pointerLock; | |
// An immediate-mode, frame-based engine, like GLOV.js | |
var engine = { global_frame_index: 0 }; | |
function updateStatus() { | |
document.getElementById('status-element').textContent = 'dragx=' + dragx + ', dragy=' + dragy + | |
'\ndouble clicks: ' + doubleclicks + ' down=' + down_mask; | |
} | |
function assert(exp) { | |
if (!exp) { | |
throw new Error('Assertion failed'); | |
} | |
} | |
function pointerLockCreate(elem) { | |
var deferred_lock_id = 0; | |
var want_lock_async = false; | |
var trying_direct_lock = 0; | |
var direct_lock_works = false; // unknown at start | |
var direct_lock_disabled = false; | |
var async_pointer_lock_start_frame = 0; | |
function isLocked() { | |
return !!document.pointerLockElement; | |
} | |
function exitLock() { | |
document.exitPointerLock(); | |
} | |
function onPointerLockChange() { | |
if (document.pointerLockElement || document.mozPointerLockElement || document.webkitPointerLockElement) { | |
console.log('Pointer Lock was successful.'); | |
if (trying_direct_lock) { | |
console.log('Direct lock works!'); | |
direct_lock_works = true; | |
trying_direct_lock = 0; | |
} | |
} else { | |
console.log('Pointer Lock was lost.'); | |
} | |
} | |
function onPointerLockError() { | |
console.log('Error while locking pointer.'); | |
if (trying_direct_lock) { | |
direct_lock_disabled = true; | |
want_lock_async = true; | |
trying_direct_lock = 0; | |
} | |
} | |
function asyncPointerLockCheck() { | |
deferred_lock_id = 0; | |
// If we asked for a lock, and direct locks are disabled, lock it | |
if (want_lock_async) { | |
want_lock_async = false; | |
console.log('Async pointer lock watcher executing lock'); | |
elem.requestPointerLock(); | |
return; | |
} | |
// If we successfully locked through any means, stop | |
if (direct_lock_works) { | |
console.log('Async pointer lock watcher canceled, direct lock worked'); | |
return; | |
} | |
if (trying_direct_lock) { | |
// If we tried a direct lock 2+ frames ago, lock it, disable direct locks | |
if (engine.global_frame_index - trying_direct_lock >= 1) { | |
console.log('2 frames since attempting a direct pointer lock, assuming failed'); | |
direct_lock_disabled = true; | |
trying_direct_lock = 0; | |
elem.requestPointerLock(); | |
return; | |
} | |
} else if (engine.global_frame_index !== async_pointer_lock_start_frame) { | |
// tick has happened, no request for lock, stop watching | |
console.log('Async pointer lock watcher done, no lock request'); | |
return; | |
} | |
deferred_lock_id = setTimeout(asyncPointerLockCheck, 1); | |
} | |
function enterLock() { | |
// Assert that we got a mouse down event recently, otherwise this won't work | |
assert(engine.global_frame_index - async_pointer_lock_start_frame <= 2); | |
// If direct locks are disabled, just ask for async lock | |
if (direct_lock_disabled) { | |
console.log('Requesting async pointer lock'); | |
want_lock_async = true; | |
return; | |
} | |
console.log('Trying direct pointer lock'); | |
if (!direct_lock_works) { // if we don't know yet | |
trying_direct_lock = engine.global_frame_index; | |
} | |
elem.requestPointerLock(); | |
} | |
function allowAsync() { | |
async_pointer_lock_start_frame = engine.global_frame_index; | |
// If we know direct locks work, do nothing, otherwise start watcher | |
if (!direct_lock_works) { | |
console.log('Starting async pointer lock watcher'); | |
if (deferred_lock_id) { | |
clearTimeout(deferred_lock_id); | |
} | |
deferred_lock_id = setTimeout(asyncPointerLockCheck, 1); | |
} else { | |
console.log('Direct lock works, not starting async watcher'); | |
} | |
} | |
elem.requestPointerLock = elem.requestPointerLock || elem.mozRequestPointerLock || | |
elem.webkitRequestPointerLock || function () { /* nop */ }; | |
document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock || | |
document.webkitExitPointerLock || function () { /* nop */ }; | |
document.addEventListener('pointerlockchange', onPointerLockChange, false); | |
document.addEventListener('mozpointerlockchange', onPointerLockChange, false); | |
document.addEventListener('webkitpointerlockchange', onPointerLockChange, false); | |
document.addEventListener('pointerlockerror', onPointerLockError, false); | |
document.addEventListener('mozpointerlockerror', onPointerLockError, false); | |
document.addEventListener('webkitpointerlockerror', onPointerLockError, false); | |
return { | |
isLocked: isLocked, | |
allowAsync: allowAsync, | |
enter: enterLock, | |
exit: exitLock, | |
}; | |
} | |
document.addEventListener('mousemove', function (e) { | |
var movementX = e.movementX || | |
e.mozMovementX || | |
e.webkitMovementX || | |
0; | |
var movementY = e.movementY || | |
e.mozMovementY || | |
e.webkitMovementY || | |
0; | |
// Print the mouse movement delta values | |
if (pointerLock.isLocked()) { | |
dragx += movementX; | |
dragy += movementY; | |
updateStatus(); | |
//console.log('movementX=' + movementX, 'movementY=' + movementY); | |
} | |
}, false); | |
var had_click = false; | |
function ondown(event) { | |
had_click = event.which; | |
down_mask |= (1 << event.which); | |
updateStatus(); | |
pointerLock.allowAsync(); // Put this in any event handler that may indirectly cause a lock | |
} | |
function onup(event) { | |
down_mask &= ~(1 << event.which); | |
// if (!down_mask) { | |
// exitLock(); | |
// } | |
updateStatus(); | |
pointerLock.allowAsync(); // Put this in any event handler that may indirectly cause a lock | |
} | |
document.addEventListener('mousedown', ondown, false); | |
document.addEventListener('mouseup', onup, false); | |
document.addEventListener('dblclick', function () { | |
++doubleclicks; | |
updateStatus(); | |
}, false); | |
function tick() { | |
++engine.global_frame_index; | |
requestAnimationFrame(tick); | |
if (had_click === 1 && !pointerLock.isLocked()) { | |
pointerLock.enter(); | |
} else if (had_click === 3) { | |
pointerLock.exit(); | |
} | |
had_click = 0; | |
} | |
function startup() { | |
pointerLock = pointerLockCreate(document.getElementById('status-element')); | |
requestAnimationFrame(tick); | |
} | |
</script> | |
</body></html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment