Path: blob/master/platform/web/js/libs/library_godot_display.js
10279 views
/**************************************************************************/1/* library_godot_display.js */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930const GodotDisplayVK = {3132$GodotDisplayVK__deps: ['$GodotRuntime', '$GodotConfig', '$GodotEventListeners'],33$GodotDisplayVK__postset: 'GodotOS.atexit(function(resolve, reject) { GodotDisplayVK.clear(); resolve(); });',34$GodotDisplayVK: {35textinput: null,36textarea: null,3738available: function () {39return GodotConfig.virtual_keyboard && 'ontouchstart' in window;40},4142init: function (input_cb) {43function create(what) {44const elem = document.createElement(what);45elem.style.display = 'none';46elem.style.position = 'absolute';47elem.style.zIndex = '-1';48elem.style.background = 'transparent';49elem.style.padding = '0px';50elem.style.margin = '0px';51elem.style.overflow = 'hidden';52elem.style.width = '0px';53elem.style.height = '0px';54elem.style.border = '0px';55elem.style.outline = 'none';56elem.readonly = true;57elem.disabled = true;58GodotEventListeners.add(elem, 'input', function (evt) {59const c_str = GodotRuntime.allocString(elem.value);60input_cb(c_str, elem.selectionEnd);61GodotRuntime.free(c_str);62}, false);63GodotEventListeners.add(elem, 'blur', function (evt) {64elem.style.display = 'none';65elem.readonly = true;66elem.disabled = true;67}, false);68GodotConfig.canvas.insertAdjacentElement('beforebegin', elem);69return elem;70}71GodotDisplayVK.textinput = create('input');72GodotDisplayVK.textarea = create('textarea');73GodotDisplayVK.updateSize();74},75show: function (text, type, start, end) {76if (!GodotDisplayVK.textinput || !GodotDisplayVK.textarea) {77return;78}79if (GodotDisplayVK.textinput.style.display !== '' || GodotDisplayVK.textarea.style.display !== '') {80GodotDisplayVK.hide();81}82GodotDisplayVK.updateSize();8384let elem = GodotDisplayVK.textinput;85switch (type) {86case 0: // KEYBOARD_TYPE_DEFAULT87elem.type = 'text';88elem.inputmode = '';89break;90case 1: // KEYBOARD_TYPE_MULTILINE91elem = GodotDisplayVK.textarea;92break;93case 2: // KEYBOARD_TYPE_NUMBER94elem.type = 'text';95elem.inputmode = 'numeric';96break;97case 3: // KEYBOARD_TYPE_NUMBER_DECIMAL98elem.type = 'text';99elem.inputmode = 'decimal';100break;101case 4: // KEYBOARD_TYPE_PHONE102elem.type = 'tel';103elem.inputmode = '';104break;105case 5: // KEYBOARD_TYPE_EMAIL_ADDRESS106elem.type = 'email';107elem.inputmode = '';108break;109case 6: // KEYBOARD_TYPE_PASSWORD110elem.type = 'password';111elem.inputmode = '';112break;113case 7: // KEYBOARD_TYPE_URL114elem.type = 'url';115elem.inputmode = '';116break;117default:118elem.type = 'text';119elem.inputmode = '';120break;121}122123elem.readonly = false;124elem.disabled = false;125elem.value = text;126elem.style.display = 'block';127elem.focus();128elem.setSelectionRange(start, end);129},130hide: function () {131if (!GodotDisplayVK.textinput || !GodotDisplayVK.textarea) {132return;133}134[GodotDisplayVK.textinput, GodotDisplayVK.textarea].forEach(function (elem) {135elem.blur();136elem.style.display = 'none';137elem.value = '';138});139},140updateSize: function () {141if (!GodotDisplayVK.textinput || !GodotDisplayVK.textarea) {142return;143}144const rect = GodotConfig.canvas.getBoundingClientRect();145function update(elem) {146elem.style.left = `${rect.left}px`;147elem.style.top = `${rect.top}px`;148elem.style.width = `${rect.width}px`;149elem.style.height = `${rect.height}px`;150}151update(GodotDisplayVK.textinput);152update(GodotDisplayVK.textarea);153},154clear: function () {155if (GodotDisplayVK.textinput) {156GodotDisplayVK.textinput.remove();157GodotDisplayVK.textinput = null;158}159if (GodotDisplayVK.textarea) {160GodotDisplayVK.textarea.remove();161GodotDisplayVK.textarea = null;162}163},164},165};166mergeInto(LibraryManager.library, GodotDisplayVK);167168/*169* Display server cursor helper.170* Keeps track of cursor status and custom shapes.171*/172const GodotDisplayCursor = {173$GodotDisplayCursor__deps: ['$GodotOS', '$GodotConfig'],174$GodotDisplayCursor__postset: 'GodotOS.atexit(function(resolve, reject) { GodotDisplayCursor.clear(); resolve(); });',175$GodotDisplayCursor: {176shape: 'default',177visible: true,178cursors: {},179set_style: function (style) {180GodotConfig.canvas.style.cursor = style;181},182set_shape: function (shape) {183GodotDisplayCursor.shape = shape;184let css = shape;185if (shape in GodotDisplayCursor.cursors) {186const c = GodotDisplayCursor.cursors[shape];187css = `url("${c.url}") ${c.x} ${c.y}, default`;188}189if (GodotDisplayCursor.visible) {190GodotDisplayCursor.set_style(css);191}192},193clear: function () {194GodotDisplayCursor.set_style('');195GodotDisplayCursor.shape = 'default';196GodotDisplayCursor.visible = true;197Object.keys(GodotDisplayCursor.cursors).forEach(function (key) {198URL.revokeObjectURL(GodotDisplayCursor.cursors[key]);199delete GodotDisplayCursor.cursors[key];200});201},202lockPointer: function () {203const canvas = GodotConfig.canvas;204if (canvas.requestPointerLock) {205canvas.requestPointerLock();206}207},208releasePointer: function () {209if (document.exitPointerLock) {210document.exitPointerLock();211}212},213isPointerLocked: function () {214return document.pointerLockElement === GodotConfig.canvas;215},216},217};218mergeInto(LibraryManager.library, GodotDisplayCursor);219220const GodotDisplayScreen = {221$GodotDisplayScreen__deps: ['$GodotConfig', '$GodotOS', '$GL', 'emscripten_webgl_get_current_context'],222$GodotDisplayScreen: {223desired_size: [0, 0],224hidpi: true,225getPixelRatio: function () {226return GodotDisplayScreen.hidpi ? window.devicePixelRatio || 1 : 1;227},228isFullscreen: function () {229const elem = document.fullscreenElement || document.mozFullscreenElement230|| document.webkitFullscreenElement || document.msFullscreenElement;231if (elem) {232return elem === GodotConfig.canvas;233}234// But maybe knowing the element is not supported.235return document.fullscreen || document.mozFullScreen236|| document.webkitIsFullscreen;237},238hasFullscreen: function () {239return document.fullscreenEnabled || document.mozFullScreenEnabled240|| document.webkitFullscreenEnabled;241},242requestFullscreen: function () {243if (!GodotDisplayScreen.hasFullscreen()) {244return 1;245}246const canvas = GodotConfig.canvas;247try {248const promise = (canvas.requestFullscreen || canvas.msRequestFullscreen249|| canvas.mozRequestFullScreen || canvas.mozRequestFullscreen250|| canvas.webkitRequestFullscreen251).call(canvas);252// Some browsers (Safari) return undefined.253// For the standard ones, we need to catch it.254if (promise) {255promise.catch(function () {256// nothing to do.257});258}259} catch (e) {260return 1;261}262return 0;263},264exitFullscreen: function () {265if (!GodotDisplayScreen.isFullscreen()) {266return 0;267}268try {269const promise = document.exitFullscreen();270if (promise) {271promise.catch(function () {272// nothing to do.273});274}275} catch (e) {276return 1;277}278return 0;279},280_updateGL: function () {281const gl_context_handle = _emscripten_webgl_get_current_context();282const gl = GL.getContext(gl_context_handle);283if (gl) {284GL.resizeOffscreenFramebuffer(gl);285}286},287updateSize: function () {288const isFullscreen = GodotDisplayScreen.isFullscreen();289const wantsFullWindow = GodotConfig.canvas_resize_policy === 2;290const noResize = GodotConfig.canvas_resize_policy === 0;291const dWidth = GodotDisplayScreen.desired_size[0];292const dHeight = GodotDisplayScreen.desired_size[1];293const canvas = GodotConfig.canvas;294let width = dWidth;295let height = dHeight;296if (noResize) {297// Don't resize canvas, just update GL if needed.298if (canvas.width !== width || canvas.height !== height) {299GodotDisplayScreen.desired_size = [canvas.width, canvas.height];300GodotDisplayScreen._updateGL();301return 1;302}303return 0;304}305const scale = GodotDisplayScreen.getPixelRatio();306if (isFullscreen || wantsFullWindow) {307// We need to match screen size.308width = Math.floor(window.innerWidth * scale);309height = Math.floor(window.innerHeight * scale);310}311const csw = `${Math.floor(width / scale)}px`;312const csh = `${Math.floor(height / scale)}px`;313if (canvas.style.width !== csw || canvas.style.height !== csh || canvas.width !== width || canvas.height !== height) {314// Size doesn't match.315// Resize canvas, set correct CSS pixel size, update GL.316canvas.width = width;317canvas.height = height;318canvas.style.width = csw;319canvas.style.height = csh;320GodotDisplayScreen._updateGL();321return 1;322}323return 0;324},325},326};327mergeInto(LibraryManager.library, GodotDisplayScreen);328329/**330* Display server interface.331*332* Exposes all the functions needed by DisplayServer implementation.333*/334const GodotDisplay = {335$GodotDisplay__deps: ['$GodotConfig', '$GodotRuntime', '$GodotDisplayCursor', '$GodotEventListeners', '$GodotDisplayScreen', '$GodotDisplayVK'],336$GodotDisplay: {337window_icon: '',338getDPI: function () {339// devicePixelRatio is given in dppx340// https://drafts.csswg.org/css-values/#resolution341// > due to the 1:96 fixed ratio of CSS *in* to CSS *px*, 1dppx is equivalent to 96dpi.342const dpi = Math.round(window.devicePixelRatio * 96);343return dpi >= 96 ? dpi : 96;344},345},346347godot_js_display_is_swap_ok_cancel__proxy: 'sync',348godot_js_display_is_swap_ok_cancel__sig: 'i',349godot_js_display_is_swap_ok_cancel: function () {350const win = (['Windows', 'Win64', 'Win32', 'WinCE']);351const plat = navigator.platform || '';352if (win.indexOf(plat) !== -1) {353return 1;354}355return 0;356},357358godot_js_tts_is_speaking__proxy: 'sync',359godot_js_tts_is_speaking__sig: 'i',360godot_js_tts_is_speaking: function () {361return window.speechSynthesis.speaking;362},363364godot_js_tts_is_paused__proxy: 'sync',365godot_js_tts_is_paused__sig: 'i',366godot_js_tts_is_paused: function () {367return window.speechSynthesis.paused;368},369370godot_js_tts_get_voices__proxy: 'sync',371godot_js_tts_get_voices__sig: 'vi',372godot_js_tts_get_voices: function (p_callback) {373const func = GodotRuntime.get_func(p_callback);374try {375const arr = [];376const voices = window.speechSynthesis.getVoices();377for (let i = 0; i < voices.length; i++) {378arr.push(`${voices[i].lang};${voices[i].name}`);379}380const c_ptr = GodotRuntime.allocStringArray(arr);381func(arr.length, c_ptr);382GodotRuntime.freeStringArray(c_ptr, arr.length);383} catch (e) {384// Fail graciously.385}386},387388godot_js_tts_speak__proxy: 'sync',389godot_js_tts_speak__sig: 'viiiffii',390godot_js_tts_speak: function (p_text, p_voice, p_volume, p_pitch, p_rate, p_utterance_id, p_callback) {391const func = GodotRuntime.get_func(p_callback);392393function listener_end(evt) {394evt.currentTarget.cb(1 /* TTS_UTTERANCE_ENDED */, evt.currentTarget.id, 0);395}396397function listener_start(evt) {398evt.currentTarget.cb(0 /* TTS_UTTERANCE_STARTED */, evt.currentTarget.id, 0);399}400401function listener_error(evt) {402evt.currentTarget.cb(2 /* TTS_UTTERANCE_CANCELED */, evt.currentTarget.id, 0);403}404405function listener_bound(evt) {406evt.currentTarget.cb(3 /* TTS_UTTERANCE_BOUNDARY */, evt.currentTarget.id, evt.charIndex);407}408409const utterance = new SpeechSynthesisUtterance(GodotRuntime.parseString(p_text));410utterance.rate = p_rate;411utterance.pitch = p_pitch;412utterance.volume = p_volume / 100.0;413utterance.addEventListener('end', listener_end);414utterance.addEventListener('start', listener_start);415utterance.addEventListener('error', listener_error);416utterance.addEventListener('boundary', listener_bound);417utterance.id = p_utterance_id;418utterance.cb = func;419const voice = GodotRuntime.parseString(p_voice);420const voices = window.speechSynthesis.getVoices();421for (let i = 0; i < voices.length; i++) {422if (voices[i].name === voice) {423utterance.voice = voices[i];424break;425}426}427window.speechSynthesis.resume();428window.speechSynthesis.speak(utterance);429},430431godot_js_tts_pause__proxy: 'sync',432godot_js_tts_pause__sig: 'v',433godot_js_tts_pause: function () {434window.speechSynthesis.pause();435},436437godot_js_tts_resume__proxy: 'sync',438godot_js_tts_resume__sig: 'v',439godot_js_tts_resume: function () {440window.speechSynthesis.resume();441},442443godot_js_tts_stop__proxy: 'sync',444godot_js_tts_stop__sig: 'v',445godot_js_tts_stop: function () {446window.speechSynthesis.cancel();447window.speechSynthesis.resume();448},449450godot_js_display_alert__proxy: 'sync',451godot_js_display_alert__sig: 'vi',452godot_js_display_alert: function (p_text) {453window.alert(GodotRuntime.parseString(p_text)); // eslint-disable-line no-alert454},455456godot_js_display_screen_dpi_get__proxy: 'sync',457godot_js_display_screen_dpi_get__sig: 'i',458godot_js_display_screen_dpi_get: function () {459return GodotDisplay.getDPI();460},461462godot_js_display_pixel_ratio_get__proxy: 'sync',463godot_js_display_pixel_ratio_get__sig: 'f',464godot_js_display_pixel_ratio_get: function () {465return GodotDisplayScreen.getPixelRatio();466},467468godot_js_display_fullscreen_request__proxy: 'sync',469godot_js_display_fullscreen_request__sig: 'i',470godot_js_display_fullscreen_request: function () {471return GodotDisplayScreen.requestFullscreen();472},473474godot_js_display_fullscreen_exit__proxy: 'sync',475godot_js_display_fullscreen_exit__sig: 'i',476godot_js_display_fullscreen_exit: function () {477return GodotDisplayScreen.exitFullscreen();478},479480godot_js_display_desired_size_set__proxy: 'sync',481godot_js_display_desired_size_set__sig: 'vii',482godot_js_display_desired_size_set: function (width, height) {483GodotDisplayScreen.desired_size = [width, height];484GodotDisplayScreen.updateSize();485},486487godot_js_display_size_update__proxy: 'sync',488godot_js_display_size_update__sig: 'i',489godot_js_display_size_update: function () {490const updated = GodotDisplayScreen.updateSize();491if (updated) {492GodotDisplayVK.updateSize();493}494return updated;495},496497godot_js_display_screen_size_get__proxy: 'sync',498godot_js_display_screen_size_get__sig: 'vii',499godot_js_display_screen_size_get: function (width, height) {500const scale = GodotDisplayScreen.getPixelRatio();501GodotRuntime.setHeapValue(width, window.screen.width * scale, 'i32');502GodotRuntime.setHeapValue(height, window.screen.height * scale, 'i32');503},504505godot_js_display_window_size_get__proxy: 'sync',506godot_js_display_window_size_get__sig: 'vii',507godot_js_display_window_size_get: function (p_width, p_height) {508GodotRuntime.setHeapValue(p_width, GodotConfig.canvas.width, 'i32');509GodotRuntime.setHeapValue(p_height, GodotConfig.canvas.height, 'i32');510},511512godot_js_display_has_webgl__proxy: 'sync',513godot_js_display_has_webgl__sig: 'ii',514godot_js_display_has_webgl: function (p_version) {515if (p_version !== 1 && p_version !== 2) {516return false;517}518try {519return !!document.createElement('canvas').getContext(p_version === 2 ? 'webgl2' : 'webgl');520} catch (e) { /* Not available */ }521return false;522},523524/*525* Canvas526*/527godot_js_display_canvas_focus__proxy: 'sync',528godot_js_display_canvas_focus__sig: 'v',529godot_js_display_canvas_focus: function () {530GodotConfig.canvas.focus();531},532533godot_js_display_canvas_is_focused__proxy: 'sync',534godot_js_display_canvas_is_focused__sig: 'i',535godot_js_display_canvas_is_focused: function () {536return document.activeElement === GodotConfig.canvas;537},538539/*540* Touchscreen541*/542godot_js_display_touchscreen_is_available__proxy: 'sync',543godot_js_display_touchscreen_is_available__sig: 'i',544godot_js_display_touchscreen_is_available: function () {545return 'ontouchstart' in window;546},547548/*549* Clipboard550*/551godot_js_display_clipboard_set__proxy: 'sync',552godot_js_display_clipboard_set__sig: 'ii',553godot_js_display_clipboard_set: function (p_text) {554const text = GodotRuntime.parseString(p_text);555if (!navigator.clipboard || !navigator.clipboard.writeText) {556return 1;557}558navigator.clipboard.writeText(text).catch(function (e) {559// Setting OS clipboard is only possible from an input callback.560GodotRuntime.error('Setting OS clipboard is only possible from an input callback for the Web platform. Exception:', e);561});562return 0;563},564565godot_js_display_clipboard_get__proxy: 'sync',566godot_js_display_clipboard_get__sig: 'ii',567godot_js_display_clipboard_get: function (callback) {568const func = GodotRuntime.get_func(callback);569try {570navigator.clipboard.readText().then(function (result) {571const ptr = GodotRuntime.allocString(result);572func(ptr);573GodotRuntime.free(ptr);574}).catch(function (e) {575// Fail graciously.576});577} catch (e) {578// Fail graciously.579}580},581582/*583* Window584*/585godot_js_display_window_title_set__proxy: 'sync',586godot_js_display_window_title_set__sig: 'vi',587godot_js_display_window_title_set: function (p_data) {588document.title = GodotRuntime.parseString(p_data);589},590591godot_js_display_window_icon_set__proxy: 'sync',592godot_js_display_window_icon_set__sig: 'vii',593godot_js_display_window_icon_set: function (p_ptr, p_len) {594let link = document.getElementById('-gd-engine-icon');595const old_icon = GodotDisplay.window_icon;596if (p_ptr) {597if (link === null) {598link = document.createElement('link');599link.rel = 'icon';600link.id = '-gd-engine-icon';601document.head.appendChild(link);602}603const png = new Blob([GodotRuntime.heapSlice(HEAPU8, p_ptr, p_len)], { type: 'image/png' });604GodotDisplay.window_icon = URL.createObjectURL(png);605link.href = GodotDisplay.window_icon;606} else {607if (link) {608link.remove();609}610GodotDisplay.window_icon = null;611}612if (old_icon) {613URL.revokeObjectURL(old_icon);614}615},616617/*618* Cursor619*/620godot_js_display_cursor_set_visible__proxy: 'sync',621godot_js_display_cursor_set_visible__sig: 'vi',622godot_js_display_cursor_set_visible: function (p_visible) {623const visible = p_visible !== 0;624if (visible === GodotDisplayCursor.visible) {625return;626}627GodotDisplayCursor.visible = visible;628if (visible) {629GodotDisplayCursor.set_shape(GodotDisplayCursor.shape);630} else {631GodotDisplayCursor.set_style('none');632}633},634635godot_js_display_cursor_is_hidden__proxy: 'sync',636godot_js_display_cursor_is_hidden__sig: 'i',637godot_js_display_cursor_is_hidden: function () {638return !GodotDisplayCursor.visible;639},640641godot_js_display_cursor_set_shape__proxy: 'sync',642godot_js_display_cursor_set_shape__sig: 'vi',643godot_js_display_cursor_set_shape: function (p_string) {644GodotDisplayCursor.set_shape(GodotRuntime.parseString(p_string));645},646647godot_js_display_cursor_set_custom_shape__proxy: 'sync',648godot_js_display_cursor_set_custom_shape__sig: 'viiiii',649godot_js_display_cursor_set_custom_shape: function (p_shape, p_ptr, p_len, p_hotspot_x, p_hotspot_y) {650const shape = GodotRuntime.parseString(p_shape);651const old_shape = GodotDisplayCursor.cursors[shape];652if (p_len > 0) {653const png = new Blob([GodotRuntime.heapSlice(HEAPU8, p_ptr, p_len)], { type: 'image/png' });654const url = URL.createObjectURL(png);655GodotDisplayCursor.cursors[shape] = {656url: url,657x: p_hotspot_x,658y: p_hotspot_y,659};660} else {661delete GodotDisplayCursor.cursors[shape];662}663if (shape === GodotDisplayCursor.shape) {664GodotDisplayCursor.set_shape(GodotDisplayCursor.shape);665}666if (old_shape) {667URL.revokeObjectURL(old_shape.url);668}669},670671godot_js_display_cursor_lock_set__proxy: 'sync',672godot_js_display_cursor_lock_set__sig: 'vi',673godot_js_display_cursor_lock_set: function (p_lock) {674if (p_lock) {675GodotDisplayCursor.lockPointer();676} else {677GodotDisplayCursor.releasePointer();678}679},680681godot_js_display_cursor_is_locked__proxy: 'sync',682godot_js_display_cursor_is_locked__sig: 'i',683godot_js_display_cursor_is_locked: function () {684return GodotDisplayCursor.isPointerLocked() ? 1 : 0;685},686687/*688* Listeners689*/690godot_js_display_fullscreen_cb__proxy: 'sync',691godot_js_display_fullscreen_cb__sig: 'vi',692godot_js_display_fullscreen_cb: function (callback) {693const canvas = GodotConfig.canvas;694const func = GodotRuntime.get_func(callback);695function change_cb(evt) {696if (evt.target === canvas) {697func(GodotDisplayScreen.isFullscreen());698}699}700GodotEventListeners.add(document, 'fullscreenchange', change_cb, false);701GodotEventListeners.add(document, 'mozfullscreenchange', change_cb, false);702GodotEventListeners.add(document, 'webkitfullscreenchange', change_cb, false);703},704705godot_js_display_window_blur_cb__proxy: 'sync',706godot_js_display_window_blur_cb__sig: 'vi',707godot_js_display_window_blur_cb: function (callback) {708const func = GodotRuntime.get_func(callback);709GodotEventListeners.add(window, 'blur', function () {710func();711}, false);712},713714godot_js_display_notification_cb__proxy: 'sync',715godot_js_display_notification_cb__sig: 'viiiii',716godot_js_display_notification_cb: function (callback, p_enter, p_exit, p_in, p_out) {717const canvas = GodotConfig.canvas;718const func = GodotRuntime.get_func(callback);719const notif = [p_enter, p_exit, p_in, p_out];720['mouseover', 'mouseleave', 'focus', 'blur'].forEach(function (evt_name, idx) {721GodotEventListeners.add(canvas, evt_name, function () {722func(notif[idx]);723}, true);724});725},726727godot_js_display_setup_canvas__proxy: 'sync',728godot_js_display_setup_canvas__sig: 'viiii',729godot_js_display_setup_canvas: function (p_width, p_height, p_fullscreen, p_hidpi) {730const canvas = GodotConfig.canvas;731GodotEventListeners.add(canvas, 'contextmenu', function (ev) {732ev.preventDefault();733}, false);734GodotEventListeners.add(canvas, 'webglcontextlost', function (ev) {735alert('WebGL context lost, please reload the page'); // eslint-disable-line no-alert736ev.preventDefault();737}, false);738GodotDisplayScreen.hidpi = !!p_hidpi;739switch (GodotConfig.canvas_resize_policy) {740case 0: // None741GodotDisplayScreen.desired_size = [canvas.width, canvas.height];742break;743case 1: // Project744GodotDisplayScreen.desired_size = [p_width, p_height];745break;746default: // Full window747// Ensure we display in the right place, the size will be handled by updateSize748canvas.style.position = 'absolute';749canvas.style.top = 0;750canvas.style.left = 0;751break;752}753GodotDisplayScreen.updateSize();754if (p_fullscreen) {755GodotDisplayScreen.requestFullscreen();756}757},758759/*760* Virtual Keyboard761*/762godot_js_display_vk_show__proxy: 'sync',763godot_js_display_vk_show__sig: 'viiii',764godot_js_display_vk_show: function (p_text, p_type, p_start, p_end) {765const text = GodotRuntime.parseString(p_text);766const start = p_start > 0 ? p_start : 0;767const end = p_end > 0 ? p_end : start;768GodotDisplayVK.show(text, p_type, start, end);769},770771godot_js_display_vk_hide__proxy: 'sync',772godot_js_display_vk_hide__sig: 'v',773godot_js_display_vk_hide: function () {774GodotDisplayVK.hide();775},776777godot_js_display_vk_available__proxy: 'sync',778godot_js_display_vk_available__sig: 'i',779godot_js_display_vk_available: function () {780return GodotDisplayVK.available();781},782783godot_js_display_tts_available__proxy: 'sync',784godot_js_display_tts_available__sig: 'i',785godot_js_display_tts_available: function () {786return 'speechSynthesis' in window;787},788789godot_js_display_vk_cb__proxy: 'sync',790godot_js_display_vk_cb__sig: 'vi',791godot_js_display_vk_cb: function (p_input_cb) {792const input_cb = GodotRuntime.get_func(p_input_cb);793if (GodotDisplayVK.available()) {794GodotDisplayVK.init(input_cb);795}796},797};798799autoAddDeps(GodotDisplay, '$GodotDisplay');800mergeInto(LibraryManager.library, GodotDisplay);801802803