82 lines
2.8 KiB
Rust
82 lines
2.8 KiB
Rust
use std::cell::OnceCell;
|
|
|
|
use js_sys::{Object, Promise};
|
|
use tracing::error;
|
|
use wasm_bindgen::closure::Closure;
|
|
use wasm_bindgen::prelude::wasm_bindgen;
|
|
use wasm_bindgen::{JsCast, JsValue};
|
|
use web_sys::{Document, DomException, Element, Navigator, console};
|
|
|
|
pub(crate) fn is_cursor_lock_raw(navigator: &Navigator, document: &Document) -> bool {
|
|
thread_local! {
|
|
static IS_CURSOR_LOCK_RAW: OnceCell<bool> = const { OnceCell::new() };
|
|
}
|
|
|
|
IS_CURSOR_LOCK_RAW.with(|cell| {
|
|
*cell.get_or_init(|| {
|
|
// TODO: Remove when Chrome can better advertise that they don't support unaccelerated
|
|
// movement on Linux.
|
|
// See <https://issues.chromium.org/issues/40833850>.
|
|
if super::web_sys::chrome_linux(navigator) {
|
|
return false;
|
|
}
|
|
|
|
let element: ElementExt = document.create_element("div").unwrap().unchecked_into();
|
|
let promise = element.request_pointer_lock();
|
|
|
|
if promise.is_undefined() {
|
|
false
|
|
} else {
|
|
thread_local! {
|
|
static REJECT_HANDLER: Closure<dyn FnMut(JsValue)> = Closure::new(|_| ());
|
|
}
|
|
|
|
let promise: Promise = promise.unchecked_into();
|
|
let _ = REJECT_HANDLER.with(|handler| promise.catch(handler));
|
|
true
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
pub(crate) fn request_pointer_lock(navigator: &Navigator, document: &Document, element: &Element) {
|
|
if is_cursor_lock_raw(navigator, document) {
|
|
thread_local! {
|
|
static REJECT_HANDLER: Closure<dyn FnMut(JsValue)> = Closure::new(|error: JsValue| {
|
|
if let Some(error) = error.dyn_ref::<DomException>() {
|
|
error!("Failed to lock pointer. {}: {}", error.name(), error.message());
|
|
} else {
|
|
console::error_1(&error);
|
|
error!("Failed to lock pointer");
|
|
}
|
|
});
|
|
}
|
|
|
|
let element: &ElementExt = element.unchecked_ref();
|
|
let options: PointerLockOptions = Object::new().unchecked_into();
|
|
options.set_unadjusted_movement(true);
|
|
let _ = REJECT_HANDLER
|
|
.with(|handler| element.request_pointer_lock_with_options(&options).catch(handler));
|
|
} else {
|
|
element.request_pointer_lock();
|
|
}
|
|
}
|
|
|
|
#[wasm_bindgen]
|
|
extern "C" {
|
|
type ElementExt;
|
|
|
|
#[wasm_bindgen(method, js_name = requestPointerLock)]
|
|
fn request_pointer_lock(this: &ElementExt) -> JsValue;
|
|
|
|
#[wasm_bindgen(method, js_name = requestPointerLock)]
|
|
fn request_pointer_lock_with_options(
|
|
this: &ElementExt,
|
|
options: &PointerLockOptions,
|
|
) -> Promise;
|
|
|
|
type PointerLockOptions;
|
|
|
|
#[wasm_bindgen(method, setter, js_name = unadjustedMovement)]
|
|
fn set_unadjusted_movement(this: &PointerLockOptions, value: bool);
|
|
}
|