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 = 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 . 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 = 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 = Closure::new(|error: JsValue| { if let Some(error) = error.dyn_ref::() { 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); }