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