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