Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/src/lib/libhtml5.js
6162 views
1
/**
2
* @license
3
* Copyright 2014 The Emscripten Authors
4
* SPDX-License-Identifier: MIT
5
*/
6
7
var LibraryHTML5 = {
8
$JSEvents__deps: [
9
#if PTHREADS
10
'_emscripten_run_callback_on_thread',
11
#endif
12
'$addOnExit',
13
],
14
$JSEvents: {
15
16
#if USE_CLOSURE_COMPILER
17
// pointers to structs malloc()ed to Emscripten HEAP for JS->C interop.
18
batteryEvent: 0,
19
gamepadEvent: 0,
20
keyEvent: 0,
21
mouseEvent: 0,
22
wheelEvent: 0,
23
uiEvent: 0,
24
focusEvent: 0,
25
deviceOrientationEvent: 0,
26
orientationChangeEvent: 0,
27
deviceMotionEvent: 0,
28
fullscreenChangeEvent: 0,
29
pointerlockChangeEvent: 0,
30
visibilityChangeEvent: 0,
31
touchEvent: 0,
32
#endif
33
34
/* We do not depend on the exact initial values of falsey member fields - these
35
fields can be populated on-demand to save code size.
36
(but still documented here to keep track of what is supposed to be present)
37
38
// When we transition from fullscreen to windowed mode, we remember here the
39
// element that was just in fullscreen mode so that we can report
40
// information about that element in the event message.
41
previousFullscreenElement: null,
42
43
// When the C runtime exits via exit(), we unregister all event handlers
44
// added by this library to be nice and clean.
45
// Track in this field whether we have yet registered that onExit handler.
46
removeEventListenersRegistered: false,
47
48
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
49
// If we are in an event handler, specifies the event handler object from
50
// the eventHandlers array that is currently running.
51
currentEventHandler: null,
52
#endif
53
*/
54
removeAllEventListeners() {
55
while (JSEvents.eventHandlers.length) {
56
JSEvents._removeHandler(JSEvents.eventHandlers.length - 1);
57
}
58
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
59
JSEvents.deferredCalls = [];
60
#endif
61
},
62
63
#if EXIT_RUNTIME
64
registerRemoveEventListeners() {
65
if (!JSEvents.removeEventListenersRegistered) {
66
addOnExit(JSEvents.removeAllEventListeners);
67
JSEvents.removeEventListenersRegistered = true;
68
}
69
},
70
#endif
71
72
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
73
// If positive, we are currently executing in a JS event handler.
74
// (this particular property must be initialized to zero, as we ++/-- it)
75
inEventHandler: 0,
76
77
deferredCalls: [],
78
79
// Queues the given function call to occur the next time we enter an event handler.
80
// Existing implementations of pointerlock apis have required that
81
// the target element is active in fullscreen mode first. Therefore give
82
// fullscreen mode request a precedence of 1 and pointer lock a precedence of 2
83
// and sort by that to always request fullscreen before pointer lock.
84
deferCall(targetFunction, precedence, argsList) {
85
function arraysHaveEqualContent(arrA, arrB) {
86
if (arrA.length != arrB.length) return false;
87
88
for (var i in arrA) {
89
if (arrA[i] != arrB[i]) return false;
90
}
91
return true;
92
}
93
// Test if the given call was already queued, and if so, don't add it again.
94
for (var call of JSEvents.deferredCalls) {
95
if (call.targetFunction == targetFunction && arraysHaveEqualContent(call.argsList, argsList)) {
96
return;
97
}
98
}
99
JSEvents.deferredCalls.push({
100
targetFunction,
101
precedence,
102
argsList
103
});
104
105
JSEvents.deferredCalls.sort((x,y) => x.precedence < y.precedence);
106
},
107
108
// Erases all deferred calls to the given target function from the queue list.
109
removeDeferredCalls(targetFunction) {
110
JSEvents.deferredCalls = JSEvents.deferredCalls.filter((call) => call.targetFunction != targetFunction);
111
},
112
113
canPerformEventHandlerRequests() {
114
if (navigator.userActivation) {
115
// Verify against transient activation status from UserActivation API
116
// whether it is possible to perform a request here without needing to defer. See
117
// https://developer.mozilla.org/en-US/docs/Web/Security/User_activation#transient_activation
118
// and https://caniuse.com/mdn-api_useractivation
119
// At the time of writing, Firefox does not support this API: https://bugzil.la/1791079
120
return navigator.userActivation.isActive;
121
}
122
123
return JSEvents.inEventHandler && JSEvents.currentEventHandler.allowsDeferredCalls;
124
},
125
126
runDeferredCalls() {
127
if (!JSEvents.canPerformEventHandlerRequests()) {
128
return;
129
}
130
var deferredCalls = JSEvents.deferredCalls;
131
JSEvents.deferredCalls = [];
132
for (var call of deferredCalls) {
133
call.targetFunction(...call.argsList);
134
}
135
},
136
#endif
137
138
// Stores objects representing each currently registered JS event handler.
139
eventHandlers: [],
140
141
// Removes all event handlers on the given DOM element of the given type.
142
// Pass in eventTypeString == undefined/null to remove all event handlers
143
// regardless of the type.
144
removeAllHandlersOnTarget: (target, eventTypeString) => {
145
for (var i = 0; i < JSEvents.eventHandlers.length; ++i) {
146
if (JSEvents.eventHandlers[i].target == target &&
147
(!eventTypeString || eventTypeString == JSEvents.eventHandlers[i].eventTypeString)) {
148
JSEvents._removeHandler(i--);
149
}
150
}
151
},
152
153
_removeHandler(i) {
154
var h = JSEvents.eventHandlers[i];
155
h.target.removeEventListener(h.eventTypeString, h.eventListenerFunc, h.useCapture);
156
JSEvents.eventHandlers.splice(i, 1);
157
},
158
159
registerOrRemoveHandler(eventHandler) {
160
if (!eventHandler.target) {
161
#if ASSERTIONS
162
err('registerOrRemoveHandler: the target element for event handler registration does not exist, when processing the following event handler registration:');
163
console.dir(eventHandler);
164
#endif
165
return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
166
}
167
if (eventHandler.callbackfunc) {
168
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
169
eventHandler.eventListenerFunc = function(event) {
170
// Increment nesting count for the event handler.
171
++JSEvents.inEventHandler;
172
JSEvents.currentEventHandler = eventHandler;
173
// Process any old deferred calls the user has placed.
174
JSEvents.runDeferredCalls();
175
// Process the actual event, calls back to user C code handler.
176
eventHandler.handlerFunc(event);
177
// Process any new deferred calls that were placed right now from this event handler.
178
JSEvents.runDeferredCalls();
179
// Out of event handler - restore nesting count.
180
--JSEvents.inEventHandler;
181
};
182
#else
183
eventHandler.eventListenerFunc = eventHandler.handlerFunc;
184
#endif
185
186
eventHandler.target.addEventListener(eventHandler.eventTypeString,
187
eventHandler.eventListenerFunc,
188
eventHandler.useCapture);
189
JSEvents.eventHandlers.push(eventHandler);
190
#if EXIT_RUNTIME
191
JSEvents.registerRemoveEventListeners();
192
#endif
193
} else {
194
for (var i = 0; i < JSEvents.eventHandlers.length; ++i) {
195
if (JSEvents.eventHandlers[i].target == eventHandler.target
196
&& JSEvents.eventHandlers[i].eventTypeString == eventHandler.eventTypeString) {
197
JSEvents._removeHandler(i--);
198
}
199
}
200
}
201
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
202
},
203
204
removeSingleHandler(eventHandler) {
205
let success = false;
206
for (let i = 0; i < JSEvents.eventHandlers.length; ++i) {
207
const handler = JSEvents.eventHandlers[i];
208
if (handler.target === eventHandler.target
209
&& handler.eventTypeId === eventHandler.eventTypeId
210
&& handler.callbackfunc === eventHandler.callbackfunc
211
&& handler.userData === eventHandler.userData) {
212
// in some very rare cases (ex: Safari / fullscreen events), there is more than 1 handler (eventTypeString is different)
213
JSEvents._removeHandler(i--);
214
success = true;
215
}
216
}
217
return success ? {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}} : {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}};
218
},
219
220
#if PTHREADS
221
getTargetThreadForEventCallback(targetThread) {
222
switch (targetThread) {
223
case {{{ cDefs.EM_CALLBACK_THREAD_CONTEXT_MAIN_RUNTIME_THREAD }}}:
224
// The event callback for the current event should be called on the
225
// main browser thread. (0 == don't proxy)
226
return 0;
227
case {{{ cDefs.EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD }}}:
228
// The event callback for the current event should be backproxied to
229
// the thread that is registering the event.
230
// This can be 0 in the case that the caller uses
231
// EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD but on the main thread
232
// itself.
233
return PThread.currentProxiedOperationCallerThread;
234
default:
235
// The event callback for the current event should be proxied to the
236
// given specific thread.
237
return targetThread;
238
}
239
},
240
#endif
241
242
getNodeNameForTarget(target) {
243
if (!target) return '';
244
if (target == window) return '#window';
245
if (target == screen) return '#screen';
246
return target?.nodeName || '';
247
},
248
249
fullscreenEnabled() {
250
return document.fullscreenEnabled
251
#if MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED
252
// Safari 13.0.3 on macOS Catalina 10.15.1 still ships with prefixed webkitFullscreenEnabled.
253
// TODO: If Safari at some point ships with unprefixed version, update the version check above.
254
|| document.webkitFullscreenEnabled
255
#endif
256
;
257
},
258
},
259
260
$getFullscreenElement__internal: true,
261
$getFullscreenElement() {
262
return document.fullscreenElement || document.mozFullScreenElement ||
263
document.webkitFullscreenElement || document.webkitCurrentFullScreenElement ||
264
document.msFullscreenElement;
265
},
266
267
$registerKeyEventCallback__noleakcheck: true,
268
$registerKeyEventCallback__deps: ['$JSEvents', '$findEventTarget', '$stringToUTF8', 'malloc'],
269
$registerKeyEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
270
#if PTHREADS
271
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
272
#endif
273
var eventSize = {{{ C_STRUCTS.EmscriptenKeyboardEvent.__size__ }}};
274
JSEvents.keyEvent ||= _malloc(eventSize);
275
276
var keyEventHandlerFunc = (e) => {
277
#if ASSERTIONS
278
assert(e);
279
#endif
280
281
var keyEventData = JSEvents.keyEvent;
282
{{{ makeSetValue('keyEventData', C_STRUCTS.EmscriptenKeyboardEvent.timestamp, 'e.timeStamp', 'double') }}};
283
284
var idx = {{{ getHeapOffset('keyEventData', 'i32') }}};
285
286
HEAP32[idx + {{{ C_STRUCTS.EmscriptenKeyboardEvent.location / 4 }}}] = e.location;
287
HEAP8[keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.ctrlKey }}}] = e.ctrlKey;
288
HEAP8[keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.shiftKey }}}] = e.shiftKey;
289
HEAP8[keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.altKey }}}] = e.altKey;
290
HEAP8[keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.metaKey }}}] = e.metaKey;
291
HEAP8[keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.repeat }}}] = e.repeat;
292
HEAP32[idx + {{{ C_STRUCTS.EmscriptenKeyboardEvent.charCode / 4 }}}] = e.charCode;
293
HEAP32[idx + {{{ C_STRUCTS.EmscriptenKeyboardEvent.keyCode / 4 }}}] = e.keyCode;
294
HEAP32[idx + {{{ C_STRUCTS.EmscriptenKeyboardEvent.which / 4 }}}] = e.which;
295
stringToUTF8(e.key || '', keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.key }}}, {{{ cDefs.EM_HTML5_SHORT_STRING_LEN_BYTES }}});
296
stringToUTF8(e.code || '', keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.code }}}, {{{ cDefs.EM_HTML5_SHORT_STRING_LEN_BYTES }}});
297
stringToUTF8(e.char || '', keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.charValue }}}, {{{ cDefs.EM_HTML5_SHORT_STRING_LEN_BYTES }}});
298
stringToUTF8(e.locale || '', keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.locale }}}, {{{ cDefs.EM_HTML5_SHORT_STRING_LEN_BYTES }}});
299
300
#if PTHREADS
301
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, keyEventData, eventSize, userData);
302
else
303
#endif
304
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, keyEventData, userData)) e.preventDefault();
305
};
306
307
var eventHandler = {
308
target: findEventTarget(target),
309
eventTypeString,
310
eventTypeId,
311
userData,
312
callbackfunc,
313
handlerFunc: keyEventHandlerFunc,
314
useCapture
315
};
316
return JSEvents.registerOrRemoveHandler(eventHandler);
317
},
318
319
// In DOM capturing and bubbling sequence, there are two special elements at the top of the event chain that can be of interest
320
// to register many events to: document and window. These cannot be addressed by using document.querySelector(), so
321
// a special mechanism to address them is needed. (For any other special object, such as screen.orientation, no general access
322
// scheme should be needed, but the object-specific event callback registration functions should handle them individually).
323
//
324
// Users can also add more special event targets, basically by just doing something like
325
// specialHTMLTargets["!canvas"] = Module.canvas;
326
// (that will let !canvas map to the canvas held in Module.canvas).
327
$specialHTMLTargets__docs: '/** @type {Object} */',
328
#if ENVIRONMENT_MAY_BE_WORKER || ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL || PTHREADS
329
$specialHTMLTargets: "[0, globalThis.document ?? 0, globalThis.window ?? 0]",
330
#else
331
$specialHTMLTargets: "[0, document, window]",
332
#endif
333
334
#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
335
$maybeCStringToJsString: (cString) => {
336
// "cString > 2" checks if the input is a number, and isn't of the special
337
// values we accept here, EMSCRIPTEN_EVENT_TARGET_* (which map to 0, 1, 2).
338
// In other words, if cString > 2 then it's a pointer to a valid place in
339
// memory, and points to a C string.
340
return cString > 2 ? UTF8ToString(cString) : cString;
341
},
342
343
// Find a DOM element with the given ID, or null if none is found.
344
$findEventTarget__deps: ['$maybeCStringToJsString', '$specialHTMLTargets'],
345
$findEventTarget: (target) => {
346
target = maybeCStringToJsString(target);
347
#if ENVIRONMENT_MAY_BE_WORKER || ENVIRONMENT_MAY_BE_NODE
348
var domElement = specialHTMLTargets[target] || globalThis.document?.querySelector(target);
349
#else
350
var domElement = specialHTMLTargets[target] || document.querySelector(target);
351
#endif
352
return domElement;
353
},
354
355
#if OFFSCREENCANVAS_SUPPORT
356
$findCanvasEventTarget__deps: ['$GL', '$maybeCStringToJsString', '$specialHTMLTargets'],
357
$findCanvasEventTarget: (target) => {
358
target = maybeCStringToJsString(target);
359
360
// When compiling with OffscreenCanvas support and looking up a canvas to target,
361
// we first look up if the target Canvas has been transferred to OffscreenCanvas use.
362
// These transfers are represented/tracked by GL.offscreenCanvases object, which contain
363
// the OffscreenCanvas element for each regular Canvas element that has been transferred.
364
365
// Note that each pthread/worker have their own set of GL.offscreenCanvases. That is,
366
// when an OffscreenCanvas is transferred from a pthread/main thread to another pthread,
367
// it will move in the GL.offscreenCanvases array between threads. Hence GL.offscreenCanvases
368
// represents the set of OffscreenCanvases owned by the current calling thread.
369
370
// First check out the list of OffscreenCanvases by CSS selector ID ('#myCanvasID')
371
return GL.offscreenCanvases[target.slice(1)] // Remove '#' prefix
372
// If not found, if one is querying by using DOM tag name selector 'canvas', grab the first
373
// OffscreenCanvas that we can find.
374
|| (target == 'canvas' && Object.values(GL.offscreenCanvases)[0])
375
// If not found, check specialHTMLTargets
376
|| specialHTMLTargets[target]
377
// If that is not found either, query via the regular DOM selector.
378
#if PTHREADS
379
|| globalThis.document?.querySelector(target);
380
#else
381
|| document.querySelector(target);
382
#endif
383
},
384
#else
385
$findCanvasEventTarget: '$findEventTarget',
386
#endif
387
388
#else
389
// Find a DOM element with the given ID, or null if none is found.
390
$findEventTarget__deps: ['$specialHTMLTargets'],
391
$findEventTarget: (target) => {
392
#if ASSERTIONS
393
warnOnce('Rules for selecting event targets in HTML5 API are changing: instead of using document.getElementById() that only can refer to elements by their DOM ID, new event target selection mechanism uses the more flexible function document.querySelector() that can look up element names, classes, and complex CSS selectors. Build with -sDISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR to change to the new lookup rules. See https://github.com/emscripten-core/emscripten/pull/7977 for more details.');
394
#endif
395
// The sensible "default" target varies between events, but use window as the default
396
// since DOM events mostly can default to that. Specific callback registrations
397
// override their own defaults.
398
if (!target) return window;
399
if (typeof target == "number") target = specialHTMLTargets[target] || UTF8ToString(target);
400
if (target === '#window') return window;
401
else if (target === '#document') return document;
402
else if (target === '#screen') return screen;
403
else if (target === '#canvas') return Module['canvas'];
404
else if (typeof target == 'string')
405
#if ENVIRONMENT_MAY_BE_WORKER || ENVIRONMENT_MAY_BE_NODE
406
return globalThis.document?.getElementById(target);
407
#else
408
return document.getElementById(target);
409
#endif
410
return target;
411
},
412
413
// Like findEventTarget, but looks for OffscreenCanvas elements first
414
$findCanvasEventTarget__deps: ['$findEventTarget'],
415
$findCanvasEventTarget: (target) => {
416
if (typeof target == 'number') target = UTF8ToString(target);
417
if (!target || target === '#canvas') {
418
if (typeof GL != 'undefined' && GL.offscreenCanvases['canvas']) return GL.offscreenCanvases['canvas']; // TODO: Remove this line, target '#canvas' should refer only to Module['canvas'], not to GL.offscreenCanvases['canvas'] - but need stricter tests to be able to remove this line.
419
return Module['canvas'];
420
}
421
if (typeof GL != 'undefined' && GL.offscreenCanvases[target]) return GL.offscreenCanvases[target];
422
return findEventTarget(target);
423
},
424
#endif
425
426
emscripten_html5_remove_event_listener__proxy: 'sync',
427
emscripten_html5_remove_event_listener__deps: ['$JSEvents', '$findEventTarget'],
428
emscripten_html5_remove_event_listener: (target, userData, eventTypeId, callback) => {
429
var eventHandler = {
430
target: findEventTarget(target),
431
userData,
432
eventTypeId,
433
callbackfunc: callback,
434
};
435
return JSEvents.removeSingleHandler(eventHandler);
436
},
437
438
emscripten_set_keypress_callback_on_thread__proxy: 'sync',
439
emscripten_set_keypress_callback_on_thread__deps: ['$registerKeyEventCallback'],
440
emscripten_set_keypress_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
441
registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYPRESS }}}, "keypress", targetThread),
442
443
emscripten_set_keydown_callback_on_thread__proxy: 'sync',
444
emscripten_set_keydown_callback_on_thread__deps: ['$registerKeyEventCallback'],
445
emscripten_set_keydown_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
446
registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYDOWN }}}, "keydown", targetThread),
447
448
emscripten_set_keyup_callback_on_thread__proxy: 'sync',
449
emscripten_set_keyup_callback_on_thread__deps: ['$registerKeyEventCallback'],
450
emscripten_set_keyup_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
451
registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYUP }}}, "keyup", targetThread),
452
453
// Outline access to function .getBoundingClientRect() since it is a long string. Closure compiler does not outline access to it by itself, but it can inline access if
454
// there is only one caller to this function.
455
$getBoundingClientRect__deps: ['$specialHTMLTargets'],
456
$getBoundingClientRect: (e) => specialHTMLTargets.indexOf(e) < 0 ? e.getBoundingClientRect() : {'left':0,'top':0},
457
458
// Copies mouse event data from the given JS mouse event 'e' to the specified Emscripten mouse event structure in the HEAP.
459
// eventStruct: the structure to populate.
460
// e: The JS mouse event to read data from.
461
// target: Specifies a target DOM element that will be used as the reference to populate targetX and targetY parameters.
462
$fillMouseEventData__deps: ['$getBoundingClientRect'],
463
$fillMouseEventData: (eventStruct, e, target) => {
464
#if ASSERTIONS
465
assert(eventStruct % 4 == 0);
466
#endif
467
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.timestamp, 'e.timeStamp', 'double') }}};
468
var idx = {{{ getHeapOffset('eventStruct', 'i32') }}};
469
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.screenX / 4 }}}] = e.screenX;
470
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.screenY / 4 }}}] = e.screenY;
471
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.clientX / 4 }}}] = e.clientX;
472
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.clientY / 4 }}}] = e.clientY;
473
HEAP8[eventStruct + {{{ C_STRUCTS.EmscriptenMouseEvent.ctrlKey }}}] = e.ctrlKey;
474
HEAP8[eventStruct + {{{ C_STRUCTS.EmscriptenMouseEvent.shiftKey }}}] = e.shiftKey;
475
HEAP8[eventStruct + {{{ C_STRUCTS.EmscriptenMouseEvent.altKey }}}] = e.altKey;
476
HEAP8[eventStruct + {{{ C_STRUCTS.EmscriptenMouseEvent.metaKey }}}] = e.metaKey;
477
HEAP16[idx*2 + {{{ C_STRUCTS.EmscriptenMouseEvent.button / 2 }}}] = e.button;
478
HEAP16[idx*2 + {{{ C_STRUCTS.EmscriptenMouseEvent.buttons / 2 }}}] = e.buttons;
479
480
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.movementX / 4 }}}] = e["movementX"];
481
482
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.movementY / 4 }}}] = e["movementY"];
483
484
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
485
if (Module['canvas']) {
486
var rect = getBoundingClientRect(Module['canvas']);
487
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.canvasX / 4 }}}] = e.clientX - (rect.left | 0);
488
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.canvasY / 4 }}}] = e.clientY - (rect.top | 0);
489
} else { // Canvas is not initialized, return 0.
490
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.canvasX / 4 }}}] = 0;
491
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.canvasY / 4 }}}] = 0;
492
}
493
#endif
494
// Note: rect contains doubles (truncated to placate SAFE_HEAP, which is the same behaviour when writing to HEAP32 anyway)
495
var rect = getBoundingClientRect(target);
496
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.targetX / 4 }}}] = e.clientX - (rect.left | 0);
497
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.targetY / 4 }}}] = e.clientY - (rect.top | 0);
498
},
499
500
$registerMouseEventCallback__noleakcheck: true,
501
$registerMouseEventCallback__deps: ['$JSEvents', '$fillMouseEventData', '$findEventTarget', 'malloc'],
502
$registerMouseEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
503
#if PTHREADS
504
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
505
#endif
506
var eventSize = {{{ C_STRUCTS.EmscriptenMouseEvent.__size__ }}};
507
JSEvents.mouseEvent ||= _malloc(eventSize);
508
target = findEventTarget(target);
509
510
var mouseEventHandlerFunc = (e) => {
511
// TODO: Make this access thread safe, or this could update live while app is reading it.
512
fillMouseEventData(JSEvents.mouseEvent, e, target);
513
514
#if PTHREADS
515
if (targetThread) {
516
__emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, JSEvents.mouseEvent, eventSize, userData);
517
} else
518
#endif
519
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, JSEvents.mouseEvent, userData)) e.preventDefault();
520
};
521
522
var eventHandler = {
523
target,
524
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
525
allowsDeferredCalls: eventTypeString != 'mousemove' && eventTypeString != 'mouseenter' && eventTypeString != 'mouseleave', // Mouse move events do not allow fullscreen/pointer lock requests to be handled in them!
526
#endif
527
eventTypeString,
528
eventTypeId,
529
userData,
530
callbackfunc,
531
handlerFunc: mouseEventHandlerFunc,
532
useCapture
533
};
534
return JSEvents.registerOrRemoveHandler(eventHandler);
535
},
536
537
emscripten_set_click_callback_on_thread__proxy: 'sync',
538
emscripten_set_click_callback_on_thread__deps: ['$registerMouseEventCallback'],
539
emscripten_set_click_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
540
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_CLICK }}}, "click", targetThread),
541
542
emscripten_set_mousedown_callback_on_thread__proxy: 'sync',
543
emscripten_set_mousedown_callback_on_thread__deps: ['$registerMouseEventCallback'],
544
emscripten_set_mousedown_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
545
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEDOWN }}}, "mousedown", targetThread),
546
547
emscripten_set_mouseup_callback_on_thread__proxy: 'sync',
548
emscripten_set_mouseup_callback_on_thread__deps: ['$registerMouseEventCallback'],
549
emscripten_set_mouseup_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
550
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEUP }}}, "mouseup", targetThread),
551
552
emscripten_set_dblclick_callback_on_thread__proxy: 'sync',
553
emscripten_set_dblclick_callback_on_thread__deps: ['$registerMouseEventCallback'],
554
emscripten_set_dblclick_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
555
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DBLCLICK }}}, "dblclick", targetThread),
556
557
emscripten_set_mousemove_callback_on_thread__proxy: 'sync',
558
emscripten_set_mousemove_callback_on_thread__deps: ['$registerMouseEventCallback'],
559
emscripten_set_mousemove_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
560
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEMOVE }}}, "mousemove", targetThread),
561
562
emscripten_set_mouseenter_callback_on_thread__proxy: 'sync',
563
emscripten_set_mouseenter_callback_on_thread__deps: ['$registerMouseEventCallback'],
564
emscripten_set_mouseenter_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
565
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEENTER }}}, "mouseenter", targetThread),
566
567
emscripten_set_mouseleave_callback_on_thread__proxy: 'sync',
568
emscripten_set_mouseleave_callback_on_thread__deps: ['$registerMouseEventCallback'],
569
emscripten_set_mouseleave_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
570
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSELEAVE }}}, "mouseleave", targetThread),
571
572
emscripten_set_mouseover_callback_on_thread__proxy: 'sync',
573
emscripten_set_mouseover_callback_on_thread__deps: ['$registerMouseEventCallback'],
574
emscripten_set_mouseover_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
575
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEOVER }}}, "mouseover", targetThread),
576
577
emscripten_set_mouseout_callback_on_thread__proxy: 'sync',
578
emscripten_set_mouseout_callback_on_thread__deps: ['$registerMouseEventCallback'],
579
emscripten_set_mouseout_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
580
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEOUT }}}, "mouseout", targetThread),
581
582
// HTML5 does not really have a polling API for mouse events, so implement one
583
// manually by returning the data from the most recently received event. This
584
// requires that user has registered at least some no-op function as an event
585
// handler to any of the mouse function.
586
_emscripten_get_last_mouse_event__proxy: 'sync',
587
_emscripten_get_last_mouse_event__internal: true,
588
_emscripten_get_last_mouse_event__deps: ['$JSEvents'],
589
_emscripten_get_last_mouse_event: () => JSEvents.mouseEvent,
590
591
$registerWheelEventCallback__noleakcheck: true,
592
$registerWheelEventCallback__deps: ['$JSEvents', '$fillMouseEventData', 'malloc'],
593
$registerWheelEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
594
#if PTHREADS
595
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
596
#endif
597
var eventSize = {{{ C_STRUCTS.EmscriptenWheelEvent.__size__ }}};
598
JSEvents.wheelEvent ||= _malloc(eventSize)
599
600
// The DOM Level 3 events spec event 'wheel'
601
var wheelHandlerFunc = (e) => {
602
var wheelEvent = JSEvents.wheelEvent;
603
fillMouseEventData(wheelEvent, e, target);
604
{{{ makeSetValue('wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaX, 'e["deltaX"]', 'double') }}};
605
{{{ makeSetValue('wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaY, 'e["deltaY"]', 'double') }}};
606
{{{ makeSetValue('wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaZ, 'e["deltaZ"]', 'double') }}};
607
{{{ makeSetValue('wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaMode, 'e["deltaMode"]', 'i32') }}};
608
#if PTHREADS
609
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, wheelEvent, eventSize, userData);
610
else
611
#endif
612
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, wheelEvent, userData)) e.preventDefault();
613
};
614
615
var eventHandler = {
616
target,
617
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
618
allowsDeferredCalls: true,
619
#endif
620
eventTypeString,
621
eventTypeId,
622
userData,
623
callbackfunc,
624
handlerFunc: wheelHandlerFunc,
625
useCapture
626
};
627
return JSEvents.registerOrRemoveHandler(eventHandler);
628
},
629
630
emscripten_set_wheel_callback_on_thread__proxy: 'sync',
631
emscripten_set_wheel_callback_on_thread__deps: ['$registerWheelEventCallback', '$findEventTarget'],
632
emscripten_set_wheel_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) => {
633
target = findEventTarget(target);
634
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
635
if (typeof target.onwheel != 'undefined') {
636
return registerWheelEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_WHEEL }}}, "wheel", targetThread);
637
} else {
638
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
639
}
640
},
641
642
$registerUiEventCallback__noleakcheck: true,
643
$registerUiEventCallback__deps: ['$JSEvents', '$findEventTarget', 'malloc'],
644
$registerUiEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
645
#if PTHREADS
646
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
647
#endif
648
var eventSize = {{{ C_STRUCTS.EmscriptenUiEvent.__size__ }}};
649
JSEvents.uiEvent ||= _malloc(eventSize);
650
651
#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
652
target = findEventTarget(target);
653
#else
654
if (eventTypeId == {{{ cDefs.EMSCRIPTEN_EVENT_SCROLL }}} && !target) {
655
target = document; // By default read scroll events on document rather than window.
656
} else {
657
target = findEventTarget(target);
658
}
659
#else
660
#endif
661
662
var uiEventHandlerFunc = (e) => {
663
if (e.target != target) {
664
// Never take ui events such as scroll via a 'bubbled' route, but always from the direct element that
665
// was targeted. Otherwise e.g. if app logs a message in response to a page scroll, the Emscripten log
666
// message box could cause to scroll, generating a new (bubbled) scroll message, causing a new log print,
667
// causing a new scroll, etc..
668
return;
669
}
670
var b = document.body; // Take document.body to a variable, Closure compiler does not outline access to it on its own.
671
if (!b) {
672
// During a page unload 'body' can be null, with "Cannot read property 'clientWidth' of null" being thrown
673
return;
674
}
675
var uiEvent = JSEvents.uiEvent;
676
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.detail, '0', 'i32') }}}; // always zero for resize and scroll
677
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.documentBodyClientWidth, 'b.clientWidth', 'i32') }}};
678
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.documentBodyClientHeight, 'b.clientHeight', 'i32') }}};
679
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.windowInnerWidth, 'innerWidth', 'i32') }}};
680
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.windowInnerHeight, 'innerHeight', 'i32') }}};
681
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.windowOuterWidth, 'outerWidth', 'i32') }}};
682
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.windowOuterHeight, 'outerHeight', 'i32') }}};
683
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.scrollTop, 'pageXOffset | 0', 'i32') }}}; // scroll offsets are float
684
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.scrollLeft, 'pageYOffset | 0', 'i32') }}};
685
#if PTHREADS
686
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, uiEvent, eventSize, userData);
687
else
688
#endif
689
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, uiEvent, userData)) e.preventDefault();
690
};
691
692
var eventHandler = {
693
target,
694
eventTypeString,
695
eventTypeId,
696
userData,
697
callbackfunc,
698
handlerFunc: uiEventHandlerFunc,
699
useCapture
700
};
701
return JSEvents.registerOrRemoveHandler(eventHandler);
702
},
703
704
emscripten_set_resize_callback_on_thread__proxy: 'sync',
705
emscripten_set_resize_callback_on_thread__deps: ['$registerUiEventCallback'],
706
emscripten_set_resize_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
707
registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_RESIZE }}}, "resize", targetThread),
708
709
emscripten_set_scroll_callback_on_thread__proxy: 'sync',
710
emscripten_set_scroll_callback_on_thread__deps: ['$registerUiEventCallback'],
711
emscripten_set_scroll_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
712
registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_SCROLL }}}, "scroll", targetThread),
713
714
$registerFocusEventCallback__noleakcheck: true,
715
$registerFocusEventCallback__deps: ['$JSEvents', '$findEventTarget', 'malloc', '$stringToUTF8'],
716
$registerFocusEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
717
#if PTHREADS
718
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
719
#endif
720
var eventSize = {{{ C_STRUCTS.EmscriptenFocusEvent.__size__ }}};
721
JSEvents.focusEvent ||= _malloc(eventSize);
722
723
var focusEventHandlerFunc = (e) => {
724
var nodeName = JSEvents.getNodeNameForTarget(e.target);
725
var id = e.target.id ? e.target.id : '';
726
727
var focusEvent = JSEvents.focusEvent;
728
stringToUTF8(nodeName, focusEvent + {{{ C_STRUCTS.EmscriptenFocusEvent.nodeName }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}});
729
stringToUTF8(id, focusEvent + {{{ C_STRUCTS.EmscriptenFocusEvent.id }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}});
730
731
#if PTHREADS
732
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, focusEvent, eventSize, userData);
733
else
734
#endif
735
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, focusEvent, userData)) e.preventDefault();
736
};
737
738
var eventHandler = {
739
target: findEventTarget(target),
740
eventTypeString,
741
eventTypeId,
742
userData,
743
callbackfunc,
744
handlerFunc: focusEventHandlerFunc,
745
useCapture
746
};
747
return JSEvents.registerOrRemoveHandler(eventHandler);
748
},
749
750
emscripten_set_blur_callback_on_thread__proxy: 'sync',
751
emscripten_set_blur_callback_on_thread__deps: ['$registerFocusEventCallback'],
752
emscripten_set_blur_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
753
registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BLUR }}}, "blur", targetThread),
754
755
emscripten_set_focus_callback_on_thread__proxy: 'sync',
756
emscripten_set_focus_callback_on_thread__deps: ['$registerFocusEventCallback'],
757
emscripten_set_focus_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
758
registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUS }}}, "focus", targetThread),
759
760
emscripten_set_focusin_callback_on_thread__proxy: 'sync',
761
emscripten_set_focusin_callback_on_thread__deps: ['$registerFocusEventCallback'],
762
emscripten_set_focusin_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
763
registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUSIN }}}, "focusin", targetThread),
764
765
emscripten_set_focusout_callback_on_thread__proxy: 'sync',
766
emscripten_set_focusout_callback_on_thread__deps: ['$registerFocusEventCallback'],
767
emscripten_set_focusout_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
768
registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUSOUT }}}, "focusout", targetThread),
769
770
$fillDeviceOrientationEventData: (eventStruct, e, target) => {
771
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceOrientationEvent.alpha, 'e.alpha', 'double') }}};
772
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceOrientationEvent.beta, 'e.beta', 'double') }}};
773
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceOrientationEvent.gamma, 'e.gamma', 'double') }}};
774
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceOrientationEvent.absolute, 'e.absolute', 'i8') }}};
775
},
776
777
$registerDeviceOrientationEventCallback__noleakcheck: true,
778
$registerDeviceOrientationEventCallback__deps: ['$JSEvents', '$fillDeviceOrientationEventData', '$findEventTarget'],
779
$registerDeviceOrientationEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
780
#if PTHREADS
781
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
782
#endif
783
var eventSize = {{{ C_STRUCTS.EmscriptenDeviceOrientationEvent.__size__ }}};
784
JSEvents.deviceOrientationEvent ||= _malloc(eventSize);
785
786
var deviceOrientationEventHandlerFunc = (e) => {
787
fillDeviceOrientationEventData(JSEvents.deviceOrientationEvent, e, target); // TODO: Thread-safety with respect to emscripten_get_deviceorientation_status()
788
789
#if PTHREADS
790
if (targetThread) {
791
__emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, JSEvents.deviceOrientationEvent, eventSize, userData);
792
} else
793
#endif
794
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, JSEvents.deviceOrientationEvent, userData)) e.preventDefault();
795
};
796
797
var eventHandler = {
798
target: findEventTarget(target),
799
eventTypeString,
800
eventTypeId,
801
userData,
802
callbackfunc,
803
handlerFunc: deviceOrientationEventHandlerFunc,
804
useCapture
805
};
806
return JSEvents.registerOrRemoveHandler(eventHandler);
807
},
808
809
emscripten_set_deviceorientation_callback_on_thread__proxy: 'sync',
810
emscripten_set_deviceorientation_callback_on_thread__deps: ['$registerDeviceOrientationEventCallback'],
811
emscripten_set_deviceorientation_callback_on_thread: (userData, useCapture, callbackfunc, targetThread) => {
812
return registerDeviceOrientationEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DEVICEORIENTATION }}}, "deviceorientation", targetThread);
813
},
814
815
// HTML5 does not really have a polling API for device orientation events, so
816
// implement one manually by returning the data from the most recently
817
// received event. This requires that user has registered at least some
818
// no-op function as an event handler.
819
_emscripten_get_last_deviceorientation_event__proxy: 'sync',
820
_emscripten_get_last_deviceorientation_event__internal: true,
821
_emscripten_get_last_deviceorientation_event__deps: ['$JSEvents'],
822
_emscripten_get_last_deviceorientation_event: () => JSEvents.deviceOrientationEvent,
823
824
$fillDeviceMotionEventData: (eventStruct, e, target) => {
825
var supportedFields = 0;
826
var a = e['acceleration'];
827
supportedFields |= a && {{{ cDefs.EMSCRIPTEN_DEVICE_MOTION_EVENT_SUPPORTS_ACCELERATION }}};
828
var ag = e['accelerationIncludingGravity'];
829
supportedFields |= ag && {{{ cDefs.EMSCRIPTEN_DEVICE_MOTION_EVENT_SUPPORTS_ACCELERATION_INCLUDING_GRAVITY }}};
830
var rr = e['rotationRate'];
831
supportedFields |= rr && {{{ cDefs.EMSCRIPTEN_DEVICE_MOTION_EVENT_SUPPORTS_ROTATION_RATE }}};
832
a = a || {};
833
ag = ag || {};
834
rr = rr || {};
835
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.supportedFields, 'supportedFields', 'i32') }}};
836
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationX, 'a["x"]', 'double') }}};
837
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationY, 'a["y"]', 'double') }}};
838
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationZ, 'a["z"]', 'double') }}};
839
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationIncludingGravityX, 'ag["x"]', 'double') }}};
840
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationIncludingGravityY, 'ag["y"]', 'double') }}};
841
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationIncludingGravityZ, 'ag["z"]', 'double') }}};
842
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.rotationRateAlpha, 'rr["alpha"]', 'double') }}};
843
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.rotationRateBeta, 'rr["beta"]', 'double') }}};
844
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.rotationRateGamma, 'rr["gamma"]', 'double') }}};
845
},
846
847
$registerDeviceMotionEventCallback__noleakcheck: true,
848
$registerDeviceMotionEventCallback__deps: ['$JSEvents', '$fillDeviceMotionEventData', '$findEventTarget', 'malloc'],
849
$registerDeviceMotionEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
850
#if PTHREADS
851
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
852
#endif
853
var eventSize = {{{ C_STRUCTS.EmscriptenDeviceMotionEvent.__size__ }}};
854
JSEvents.deviceMotionEvent ||= _malloc(eventSize);
855
856
var deviceMotionEventHandlerFunc = (e) => {
857
fillDeviceMotionEventData(JSEvents.deviceMotionEvent, e, target); // TODO: Thread-safety with respect to emscripten_get_devicemotion_status()
858
859
#if PTHREADS
860
if (targetThread) {
861
__emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, JSEvents.deviceMotionEvent, eventSize, userData);
862
} else
863
#endif
864
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, JSEvents.deviceMotionEvent, userData)) e.preventDefault();
865
};
866
867
var eventHandler = {
868
target: findEventTarget(target),
869
eventTypeString,
870
eventTypeId,
871
userData,
872
callbackfunc,
873
handlerFunc: deviceMotionEventHandlerFunc,
874
useCapture
875
};
876
return JSEvents.registerOrRemoveHandler(eventHandler);
877
},
878
879
emscripten_set_devicemotion_callback_on_thread__proxy: 'sync',
880
emscripten_set_devicemotion_callback_on_thread__deps: ['$registerDeviceMotionEventCallback'],
881
emscripten_set_devicemotion_callback_on_thread: (userData, useCapture, callbackfunc, targetThread) =>
882
registerDeviceMotionEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DEVICEMOTION }}}, "devicemotion", targetThread),
883
884
// HTML5 does not really have a polling API for device motion events, so
885
// implement one manually by returning the data from the most recently
886
// received event. This requires that user has registered at least some
887
// no-op function as an event handler.
888
_emscripten_get_last_devicemotion_event__proxy: 'sync',
889
_emscripten_get_last_devicemotion_event__internal: true,
890
_emscripten_get_last_devicemotion_event__deps: ['$JSEvents'],
891
_emscripten_get_last_devicemotion_event: () => JSEvents.deviceMotionEvent,
892
893
$screenOrientation: () => {
894
if (!window.screen) return undefined;
895
return screen.orientation || screen['mozOrientation'] || screen['webkitOrientation'];
896
},
897
898
$fillOrientationChangeEventData__deps: ['$screenOrientation'],
899
$fillOrientationChangeEventData: (eventStruct) => {
900
// OrientationType enum
901
var orientationsType1 = ['portrait-primary', 'portrait-secondary', 'landscape-primary', 'landscape-secondary'];
902
// alternative selection from OrientationLockType enum
903
var orientationsType2 = ['portrait', 'portrait', 'landscape', 'landscape'];
904
905
var orientationIndex = {{{ cDefs.EMSCRIPTEN_ORIENTATION_UNSUPPORTED }}};
906
var orientationAngle = 0;
907
var screenOrientObj = screenOrientation();
908
if (typeof screenOrientObj === 'object') {
909
orientationIndex = orientationsType1.indexOf(screenOrientObj.type);
910
if (orientationIndex < 0) {
911
orientationIndex = orientationsType2.indexOf(screenOrientObj.type);
912
}
913
if (orientationIndex >= 0) {
914
orientationIndex = 1 << orientationIndex;
915
}
916
orientationAngle = screenOrientObj.angle;
917
}
918
#if MIN_SAFARI_VERSION < 160400
919
else {
920
// fallback for Safari earlier than 16.4 (March 2023)
921
orientationAngle = window.orientation;
922
}
923
#endif
924
925
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenOrientationChangeEvent.orientationIndex, 'orientationIndex', 'i32') }}};
926
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenOrientationChangeEvent.orientationAngle, 'orientationAngle', 'i32') }}};
927
},
928
929
$registerOrientationChangeEventCallback__noleakcheck: true,
930
$registerOrientationChangeEventCallback__deps: ['$JSEvents', '$fillOrientationChangeEventData', 'malloc'],
931
$registerOrientationChangeEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
932
#if PTHREADS
933
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
934
#endif
935
var eventSize = {{{ C_STRUCTS.EmscriptenOrientationChangeEvent.__size__ }}};
936
JSEvents.orientationChangeEvent ||= _malloc(eventSize);
937
938
var orientationChangeEventHandlerFunc = (e) => {
939
var orientationChangeEvent = JSEvents.orientationChangeEvent;
940
fillOrientationChangeEventData(orientationChangeEvent);
941
942
#if PTHREADS
943
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, orientationChangeEvent, eventSize, userData);
944
else
945
#endif
946
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, orientationChangeEvent, userData)) e.preventDefault();
947
};
948
949
var eventHandler = {
950
target,
951
eventTypeString,
952
eventTypeId,
953
userData,
954
callbackfunc,
955
handlerFunc: orientationChangeEventHandlerFunc,
956
useCapture
957
};
958
return JSEvents.registerOrRemoveHandler(eventHandler);
959
},
960
961
emscripten_set_orientationchange_callback_on_thread__proxy: 'sync',
962
emscripten_set_orientationchange_callback_on_thread__deps: ['$registerOrientationChangeEventCallback'],
963
emscripten_set_orientationchange_callback_on_thread: (userData, useCapture, callbackfunc, targetThread) => {
964
if (!window.screen || !screen.orientation) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
965
return registerOrientationChangeEventCallback(screen.orientation, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_ORIENTATIONCHANGE }}}, 'change', targetThread);
966
},
967
968
emscripten_get_orientation_status__proxy: 'sync',
969
emscripten_get_orientation_status__deps: ['$fillOrientationChangeEventData', '$screenOrientation'],
970
emscripten_get_orientation_status: (orientationChangeEvent) => {
971
// screenOrientation() resolving standard, window.orientation being the deprecated mobile-only
972
if (!screenOrientation() && typeof orientation == 'undefined') return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
973
fillOrientationChangeEventData(orientationChangeEvent);
974
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
975
},
976
977
emscripten_lock_orientation__proxy: 'sync',
978
emscripten_lock_orientation: (allowedOrientations) => {
979
var orientations = [];
980
if (allowedOrientations & 1) orientations.push("portrait-primary");
981
if (allowedOrientations & 2) orientations.push("portrait-secondary");
982
if (allowedOrientations & 4) orientations.push("landscape-primary");
983
if (allowedOrientations & 8) orientations.push("landscape-secondary");
984
var succeeded;
985
if (screen.lockOrientation) {
986
succeeded = screen.lockOrientation(orientations);
987
} else if (screen.mozLockOrientation) {
988
succeeded = screen.mozLockOrientation(orientations);
989
} else if (screen.webkitLockOrientation) {
990
succeeded = screen.webkitLockOrientation(orientations);
991
} else {
992
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
993
}
994
if (succeeded) {
995
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
996
}
997
return {{{ cDefs.EMSCRIPTEN_RESULT_FAILED }}};
998
},
999
1000
emscripten_unlock_orientation__proxy: 'sync',
1001
emscripten_unlock_orientation: () => {
1002
if (screen.unlockOrientation) {
1003
screen.unlockOrientation();
1004
} else if (screen.mozUnlockOrientation) {
1005
screen.mozUnlockOrientation();
1006
} else if (screen.webkitUnlockOrientation) {
1007
screen.webkitUnlockOrientation();
1008
} else {
1009
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1010
}
1011
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1012
},
1013
1014
$fillFullscreenChangeEventData__deps: ['$JSEvents', '$stringToUTF8', '$getFullscreenElement'],
1015
$fillFullscreenChangeEventData: (eventStruct) => {
1016
var fullscreenElement = getFullscreenElement();
1017
var isFullscreen = !!fullscreenElement;
1018
// Assigning a boolean to HEAP32 with expected type coercion.
1019
/** @suppress{checkTypes} */
1020
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.isFullscreen, 'isFullscreen', 'i8') }}};
1021
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.fullscreenEnabled, 'JSEvents.fullscreenEnabled()', 'i8') }}};
1022
// If transitioning to fullscreen, report info about the element that is now fullscreen.
1023
// If transitioning to windowed mode, report info about the element that just was fullscreen.
1024
var reportedElement = isFullscreen ? fullscreenElement : JSEvents.previousFullscreenElement;
1025
var nodeName = JSEvents.getNodeNameForTarget(reportedElement);
1026
var id = reportedElement?.id || '';
1027
stringToUTF8(nodeName, eventStruct + {{{ C_STRUCTS.EmscriptenFullscreenChangeEvent.nodeName }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}});
1028
stringToUTF8(id, eventStruct + {{{ C_STRUCTS.EmscriptenFullscreenChangeEvent.id }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}});
1029
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.elementWidth, 'reportedElement ? reportedElement.clientWidth : 0', 'i32') }}};
1030
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.elementHeight, 'reportedElement ? reportedElement.clientHeight : 0', 'i32') }}};
1031
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.screenWidth, 'screen.width', 'i32') }}};
1032
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.screenHeight, 'screen.height', 'i32') }}};
1033
if (isFullscreen) {
1034
JSEvents.previousFullscreenElement = fullscreenElement;
1035
}
1036
},
1037
1038
$registerFullscreenChangeEventCallback__noleakcheck: true,
1039
$registerFullscreenChangeEventCallback__deps: ['$JSEvents', '$fillFullscreenChangeEventData', 'malloc'],
1040
$registerFullscreenChangeEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
1041
#if PTHREADS
1042
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
1043
#endif
1044
var eventSize = {{{ C_STRUCTS.EmscriptenFullscreenChangeEvent.__size__ }}};
1045
JSEvents.fullscreenChangeEvent ||= _malloc(eventSize);
1046
1047
var fullscreenChangeEventHandlerFunc = (e) => {
1048
var fullscreenChangeEvent = JSEvents.fullscreenChangeEvent;
1049
fillFullscreenChangeEventData(fullscreenChangeEvent);
1050
1051
#if PTHREADS
1052
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, fullscreenChangeEvent, eventSize, userData);
1053
else
1054
#endif
1055
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, fullscreenChangeEvent, userData)) e.preventDefault();
1056
};
1057
1058
var eventHandler = {
1059
target,
1060
eventTypeString,
1061
eventTypeId,
1062
userData,
1063
callbackfunc,
1064
handlerFunc: fullscreenChangeEventHandlerFunc,
1065
useCapture
1066
};
1067
return JSEvents.registerOrRemoveHandler(eventHandler);
1068
},
1069
1070
emscripten_set_fullscreenchange_callback_on_thread__proxy: 'sync',
1071
emscripten_set_fullscreenchange_callback_on_thread__deps: ['$JSEvents', '$registerFullscreenChangeEventCallback', '$findEventTarget',
1072
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1073
'$specialHTMLTargets'
1074
#endif
1075
],
1076
emscripten_set_fullscreenchange_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) => {
1077
if (!JSEvents.fullscreenEnabled()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1078
#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1079
target = findEventTarget(target);
1080
#else
1081
target = target ? findEventTarget(target) : specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}];
1082
#endif
1083
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
1084
1085
#if MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED
1086
// As of Safari 13.0.3 on macOS Catalina 10.15.1 still ships with prefixed webkitfullscreenchange. TODO: revisit this check once Safari ships unprefixed version.
1087
// TODO: When this block is removed, also change test/test_html5_remove_event_listener.c test expectation on emscripten_set_fullscreenchange_callback().
1088
registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FULLSCREENCHANGE }}}, "webkitfullscreenchange", targetThread);
1089
#endif
1090
1091
return registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FULLSCREENCHANGE }}}, "fullscreenchange", targetThread);
1092
},
1093
1094
emscripten_get_fullscreen_status__proxy: 'sync',
1095
emscripten_get_fullscreen_status__deps: ['$JSEvents', '$fillFullscreenChangeEventData'],
1096
emscripten_get_fullscreen_status: (fullscreenStatus) => {
1097
if (!JSEvents.fullscreenEnabled()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1098
fillFullscreenChangeEventData(fullscreenStatus);
1099
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1100
},
1101
1102
$JSEvents_requestFullscreen__deps: ['$JSEvents', '$JSEvents_resizeCanvasForFullscreen'],
1103
$JSEvents_requestFullscreen: (target, strategy) => {
1104
// EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT + EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE is a mode where no extra logic is performed to the DOM elements.
1105
if (strategy.scaleMode != {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT }}} || strategy.canvasResolutionScaleMode != {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE }}}) {
1106
JSEvents_resizeCanvasForFullscreen(target, strategy);
1107
}
1108
1109
if (target.requestFullscreen) {
1110
target.requestFullscreen();
1111
#if MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED
1112
} else if (target.webkitRequestFullscreen) {
1113
target.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
1114
#endif
1115
} else {
1116
return JSEvents.fullscreenEnabled() ? {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}} : {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1117
}
1118
1119
currentFullscreenStrategy = strategy;
1120
1121
if (strategy.canvasResizedCallback) {
1122
#if PTHREADS
1123
if (strategy.canvasResizedCallbackTargetThread) __emscripten_run_callback_on_thread(strategy.canvasResizedCallbackTargetThread, strategy.canvasResizedCallback, {{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData);
1124
else
1125
#endif
1126
{{{ makeDynCall('iipp', 'strategy.canvasResizedCallback') }}}({{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData);
1127
}
1128
1129
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1130
},
1131
1132
$JSEvents_resizeCanvasForFullscreen__deps: ['$registerRestoreOldStyle', '$getCanvasElementSize', '$setLetterbox', '$setCanvasElementSize', '$getBoundingClientRect'],
1133
$JSEvents_resizeCanvasForFullscreen: (target, strategy) => {
1134
var restoreOldStyle = registerRestoreOldStyle(target);
1135
var cssWidth = strategy.softFullscreen ? innerWidth : screen.width;
1136
var cssHeight = strategy.softFullscreen ? innerHeight : screen.height;
1137
var rect = getBoundingClientRect(target);
1138
var windowedCssWidth = rect.width;
1139
var windowedCssHeight = rect.height;
1140
var canvasSize = getCanvasElementSize(target);
1141
var windowedRttWidth = canvasSize[0];
1142
var windowedRttHeight = canvasSize[1];
1143
1144
if (strategy.scaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_CENTER }}}) {
1145
setLetterbox(target, (cssHeight - windowedCssHeight) / 2, (cssWidth - windowedCssWidth) / 2);
1146
cssWidth = windowedCssWidth;
1147
cssHeight = windowedCssHeight;
1148
} else if (strategy.scaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT }}}) {
1149
if (cssWidth*windowedRttHeight < windowedRttWidth*cssHeight) {
1150
var desiredCssHeight = windowedRttHeight * cssWidth / windowedRttWidth;
1151
setLetterbox(target, (cssHeight - desiredCssHeight) / 2, 0);
1152
cssHeight = desiredCssHeight;
1153
} else {
1154
var desiredCssWidth = windowedRttWidth * cssHeight / windowedRttHeight;
1155
setLetterbox(target, 0, (cssWidth - desiredCssWidth) / 2);
1156
cssWidth = desiredCssWidth;
1157
}
1158
}
1159
1160
// If we are adding padding, must choose a background color or otherwise Chrome will give the
1161
// padding a default white color. Do it only if user has not customized their own background color.
1162
target.style.backgroundColor ||= 'black';
1163
// IE11 does the same, but requires the color to be set in the document body.
1164
document.body.style.backgroundColor ||= 'black'; // IE11
1165
// Firefox always shows black letterboxes independent of style color.
1166
1167
target.style.width = cssWidth + 'px';
1168
target.style.height = cssHeight + 'px';
1169
1170
if (strategy.filteringMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_FILTERING_NEAREST }}}) {
1171
target.style.imageRendering = 'optimizeSpeed';
1172
target.style.imageRendering = '-moz-crisp-edges';
1173
target.style.imageRendering = '-o-crisp-edges';
1174
target.style.imageRendering = '-webkit-optimize-contrast';
1175
target.style.imageRendering = 'optimize-contrast';
1176
target.style.imageRendering = 'crisp-edges';
1177
target.style.imageRendering = 'pixelated';
1178
}
1179
1180
var dpiScale = (strategy.canvasResolutionScaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF }}}) ? devicePixelRatio : 1;
1181
if (strategy.canvasResolutionScaleMode != {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE }}}) {
1182
var newWidth = (cssWidth * dpiScale)|0;
1183
var newHeight = (cssHeight * dpiScale)|0;
1184
setCanvasElementSize(target, newWidth, newHeight);
1185
if (target.GLctxObject) target.GLctxObject.GLctx.viewport(0, 0, newWidth, newHeight);
1186
}
1187
return restoreOldStyle;
1188
},
1189
1190
$registerRestoreOldStyle__deps: ['$getCanvasElementSize', '$setCanvasElementSize', '$currentFullscreenStrategy'],
1191
$registerRestoreOldStyle: (canvas) => {
1192
var canvasSize = getCanvasElementSize(canvas);
1193
var oldWidth = canvasSize[0];
1194
var oldHeight = canvasSize[1];
1195
var oldCssWidth = canvas.style.width;
1196
var oldCssHeight = canvas.style.height;
1197
var oldBackgroundColor = canvas.style.backgroundColor; // Chrome reads color from here.
1198
var oldDocumentBackgroundColor = document.body.style.backgroundColor; // IE11 reads color from here.
1199
// Firefox always has black background color.
1200
var oldPaddingLeft = canvas.style.paddingLeft; // Chrome, FF, Safari
1201
var oldPaddingRight = canvas.style.paddingRight;
1202
var oldPaddingTop = canvas.style.paddingTop;
1203
var oldPaddingBottom = canvas.style.paddingBottom;
1204
var oldMarginLeft = canvas.style.marginLeft; // IE11
1205
var oldMarginRight = canvas.style.marginRight;
1206
var oldMarginTop = canvas.style.marginTop;
1207
var oldMarginBottom = canvas.style.marginBottom;
1208
var oldDocumentBodyMargin = document.body.style.margin;
1209
var oldDocumentOverflow = document.documentElement.style.overflow; // Chrome, Firefox
1210
var oldDocumentScroll = document.body.scroll; // IE
1211
var oldImageRendering = canvas.style.imageRendering;
1212
1213
function restoreOldStyle() {
1214
if (!getFullscreenElement()) {
1215
document.removeEventListener('fullscreenchange', restoreOldStyle);
1216
1217
#if MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED
1218
// As of Safari 13.0.3 on macOS Catalina 10.15.1 still ships with prefixed webkitfullscreenchange. TODO: revisit this check once Safari ships unprefixed version.
1219
document.removeEventListener('webkitfullscreenchange', restoreOldStyle);
1220
#endif
1221
1222
setCanvasElementSize(canvas, oldWidth, oldHeight);
1223
1224
canvas.style.width = oldCssWidth;
1225
canvas.style.height = oldCssHeight;
1226
canvas.style.backgroundColor = oldBackgroundColor; // Chrome
1227
// IE11 hack: assigning 'undefined' or an empty string to document.body.style.backgroundColor has no effect, so first assign back the default color
1228
// before setting the undefined value. Setting undefined value is also important, or otherwise we would later treat that as something that the user
1229
// had explicitly set so subsequent fullscreen transitions would not set background color properly.
1230
if (!oldDocumentBackgroundColor) document.body.style.backgroundColor = 'white';
1231
document.body.style.backgroundColor = oldDocumentBackgroundColor; // IE11
1232
canvas.style.paddingLeft = oldPaddingLeft; // Chrome, FF, Safari
1233
canvas.style.paddingRight = oldPaddingRight;
1234
canvas.style.paddingTop = oldPaddingTop;
1235
canvas.style.paddingBottom = oldPaddingBottom;
1236
canvas.style.marginLeft = oldMarginLeft; // IE11
1237
canvas.style.marginRight = oldMarginRight;
1238
canvas.style.marginTop = oldMarginTop;
1239
canvas.style.marginBottom = oldMarginBottom;
1240
document.body.style.margin = oldDocumentBodyMargin;
1241
document.documentElement.style.overflow = oldDocumentOverflow; // Chrome, Firefox
1242
document.body.scroll = oldDocumentScroll; // IE
1243
canvas.style.imageRendering = oldImageRendering;
1244
if (canvas.GLctxObject) canvas.GLctxObject.GLctx.viewport(0, 0, oldWidth, oldHeight);
1245
1246
if (currentFullscreenStrategy.canvasResizedCallback) {
1247
#if PTHREADS
1248
if (currentFullscreenStrategy.canvasResizedCallbackTargetThread) __emscripten_run_callback_on_thread(currentFullscreenStrategy.canvasResizedCallbackTargetThread, currentFullscreenStrategy.canvasResizedCallback, {{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, currentFullscreenStrategy.canvasResizedCallbackUserData);
1249
else
1250
#endif
1251
{{{ makeDynCall('iipp', 'currentFullscreenStrategy.canvasResizedCallback') }}}({{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, currentFullscreenStrategy.canvasResizedCallbackUserData);
1252
}
1253
}
1254
}
1255
document.addEventListener('fullscreenchange', restoreOldStyle);
1256
#if MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED
1257
// As of Safari 13.0.3 on macOS Catalina 10.15.1 still ships with prefixed webkitfullscreenchange. TODO: revisit this check once Safari ships unprefixed version.
1258
document.addEventListener('webkitfullscreenchange', restoreOldStyle);
1259
#endif
1260
return restoreOldStyle;
1261
},
1262
1263
// Walks the DOM tree and hides every element by setting "display: none;" except the given element.
1264
// Returns a list of [{node: element, displayState: oldDisplayStyle}] entries to allow restoring previous
1265
// visibility states after done.
1266
$hideEverythingExceptGivenElement: (onlyVisibleElement) => {
1267
var child = onlyVisibleElement;
1268
var parent = child.parentNode;
1269
var hiddenElements = [];
1270
while (child != document.body) {
1271
var children = parent.children;
1272
for (var currChild of children) {
1273
if (currChild != child) {
1274
hiddenElements.push({ node: currChild, displayState: currChild.style.display });
1275
currChild.style.display = 'none';
1276
}
1277
}
1278
child = parent;
1279
parent = parent.parentNode;
1280
}
1281
return hiddenElements;
1282
},
1283
1284
// Applies old visibility states, given a list of changes returned by hideEverythingExceptGivenElement().
1285
$restoreHiddenElements: (hiddenElements) => {
1286
for (var elem of hiddenElements) {
1287
elem.node.style.display = elem.displayState;
1288
}
1289
},
1290
1291
// Add letterboxes to a fullscreen element in a cross-browser way.
1292
$setLetterbox: (element, topBottom, leftRight) => {
1293
// Cannot use margin to specify letterboxes in FF or Chrome, since those ignore margins in fullscreen mode.
1294
element.style.paddingLeft = element.style.paddingRight = leftRight + 'px';
1295
element.style.paddingTop = element.style.paddingBottom = topBottom + 'px';
1296
},
1297
1298
$currentFullscreenStrategy: {},
1299
$restoreOldWindowedStyle: null,
1300
1301
$softFullscreenResizeWebGLRenderTarget__deps: ['$setLetterbox', '$currentFullscreenStrategy', '$getCanvasElementSize', '$setCanvasElementSize', '$jstoi_q'],
1302
$softFullscreenResizeWebGLRenderTarget: () => {
1303
var dpr = devicePixelRatio;
1304
var inHiDPIFullscreenMode = currentFullscreenStrategy.canvasResolutionScaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF }}};
1305
var inAspectRatioFixedFullscreenMode = currentFullscreenStrategy.scaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT }}};
1306
var inPixelPerfectFullscreenMode = currentFullscreenStrategy.canvasResolutionScaleMode != {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE }}};
1307
var inCenteredWithoutScalingFullscreenMode = currentFullscreenStrategy.scaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_CENTER }}};
1308
var screenWidth = inHiDPIFullscreenMode ? Math.round(innerWidth*dpr) : innerWidth;
1309
var screenHeight = inHiDPIFullscreenMode ? Math.round(innerHeight*dpr) : innerHeight;
1310
var w = screenWidth;
1311
var h = screenHeight;
1312
var canvas = currentFullscreenStrategy.target;
1313
var canvasSize = getCanvasElementSize(canvas);
1314
var x = canvasSize[0];
1315
var y = canvasSize[1];
1316
var topMargin;
1317
1318
if (inAspectRatioFixedFullscreenMode) {
1319
if (w*y < x*h) h = (w * y / x) | 0;
1320
else if (w*y > x*h) w = (h * x / y) | 0;
1321
topMargin = ((screenHeight - h) / 2) | 0;
1322
}
1323
1324
if (inPixelPerfectFullscreenMode) {
1325
setCanvasElementSize(canvas, w, h);
1326
if (canvas.GLctxObject) canvas.GLctxObject.GLctx.viewport(0, 0, w, h);
1327
}
1328
1329
// Back to CSS pixels.
1330
if (inHiDPIFullscreenMode) {
1331
topMargin /= dpr;
1332
w /= dpr;
1333
h /= dpr;
1334
// Round to nearest 4 digits of precision.
1335
w = Math.round(w*1e4)/1e4;
1336
h = Math.round(h*1e4)/1e4;
1337
topMargin = Math.round(topMargin*1e4)/1e4;
1338
}
1339
1340
if (inCenteredWithoutScalingFullscreenMode) {
1341
var t = (innerHeight - jstoi_q(canvas.style.height)) / 2;
1342
var b = (innerWidth - jstoi_q(canvas.style.width)) / 2;
1343
setLetterbox(canvas, t, b);
1344
} else {
1345
canvas.style.width = w + 'px';
1346
canvas.style.height = h + 'px';
1347
var b = (innerWidth - w) / 2;
1348
setLetterbox(canvas, topMargin, b);
1349
}
1350
1351
if (!inCenteredWithoutScalingFullscreenMode && currentFullscreenStrategy.canvasResizedCallback) {
1352
#if PTHREADS
1353
if (currentFullscreenStrategy.canvasResizedCallbackTargetThread) __emscripten_run_callback_on_thread(currentFullscreenStrategy.canvasResizedCallbackTargetThread, currentFullscreenStrategy.canvasResizedCallback, {{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, currentFullscreenStrategy.canvasResizedCallbackUserData);
1354
else
1355
#endif
1356
{{{ makeDynCall('iipp', 'currentFullscreenStrategy.canvasResizedCallback') }}}({{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, currentFullscreenStrategy.canvasResizedCallbackUserData);
1357
}
1358
},
1359
1360
// https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Using_full_screen_mode
1361
$doRequestFullscreen__deps: ['$JSEvents', '$JSEvents_requestFullscreen', '$findEventTarget'],
1362
$doRequestFullscreen: (target, strategy) => {
1363
if (!JSEvents.fullscreenEnabled()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1364
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1365
target ||= '#canvas';
1366
#endif
1367
target = findEventTarget(target);
1368
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
1369
1370
if (!target.requestFullscreen
1371
#if MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED
1372
&& !target.webkitRequestFullscreen
1373
#endif
1374
) {
1375
return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}};
1376
}
1377
1378
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1379
// Queue this function call if we're not currently in an event handler and
1380
// the user saw it appropriate to do so.
1381
if (!JSEvents.canPerformEventHandlerRequests()) {
1382
if (strategy.deferUntilInEventHandler) {
1383
JSEvents.deferCall(JSEvents_requestFullscreen, 1 /* priority over pointer lock */, [target, strategy]);
1384
return {{{ cDefs.EMSCRIPTEN_RESULT_DEFERRED }}};
1385
}
1386
return {{{ cDefs.EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED }}};
1387
}
1388
#endif
1389
1390
return JSEvents_requestFullscreen(target, strategy);
1391
},
1392
1393
emscripten_request_fullscreen__deps: ['$doRequestFullscreen'],
1394
emscripten_request_fullscreen__proxy: 'sync',
1395
emscripten_request_fullscreen: (target, deferUntilInEventHandler) => {
1396
var strategy = {
1397
// These options perform no added logic, but just bare request fullscreen.
1398
scaleMode: {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT }}},
1399
canvasResolutionScaleMode: {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE }}},
1400
filteringMode: {{{ cDefs.EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT }}},
1401
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1402
deferUntilInEventHandler,
1403
#endif
1404
canvasResizedCallbackTargetThread: {{{ cDefs.EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD }}}
1405
};
1406
return doRequestFullscreen(target, strategy);
1407
},
1408
1409
emscripten_request_fullscreen_strategy__deps: ['$doRequestFullscreen'],
1410
emscripten_request_fullscreen_strategy__proxy: 'sync',
1411
emscripten_request_fullscreen_strategy: (target, deferUntilInEventHandler, fullscreenStrategy) => {
1412
var strategy = {
1413
scaleMode: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.scaleMode, 'i32') }}},
1414
canvasResolutionScaleMode: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.canvasResolutionScaleMode, 'i32') }}},
1415
filteringMode: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.filteringMode, 'i32') }}},
1416
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1417
deferUntilInEventHandler,
1418
#endif
1419
#if PTHREADS
1420
canvasResizedCallbackTargetThread: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.canvasResizedCallbackTargetThread, 'i32') }}},
1421
#endif
1422
canvasResizedCallback: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.canvasResizedCallback, 'i32') }}},
1423
canvasResizedCallbackUserData: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.canvasResizedCallbackUserData, 'i32') }}}
1424
};
1425
1426
return doRequestFullscreen(target, strategy);
1427
},
1428
1429
emscripten_enter_soft_fullscreen__deps: ['$JSEvents', '$hideEverythingExceptGivenElement', '$restoreOldWindowedStyle', '$restoreHiddenElements', '$currentFullscreenStrategy', '$softFullscreenResizeWebGLRenderTarget', '$JSEvents_resizeCanvasForFullscreen', '$findEventTarget'],
1430
emscripten_enter_soft_fullscreen__proxy: 'sync',
1431
emscripten_enter_soft_fullscreen: (target, fullscreenStrategy) => {
1432
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1433
target ||= '#canvas';
1434
#endif
1435
target = findEventTarget(target);
1436
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
1437
1438
var strategy = {
1439
scaleMode: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.scaleMode, 'i32') }}},
1440
canvasResolutionScaleMode: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.canvasResolutionScaleMode, 'i32') }}},
1441
filteringMode: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.filteringMode, 'i32') }}},
1442
canvasResizedCallback: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.canvasResizedCallback, 'i32') }}},
1443
canvasResizedCallbackUserData: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.canvasResizedCallbackUserData, 'i32') }}},
1444
#if PTHREADS
1445
canvasResizedCallbackTargetThread: JSEvents.getTargetThreadForEventCallback(),
1446
#endif
1447
target,
1448
softFullscreen: true
1449
};
1450
1451
var restoreOldStyle = JSEvents_resizeCanvasForFullscreen(target, strategy);
1452
1453
document.documentElement.style.overflow = 'hidden'; // Firefox, Chrome
1454
document.body.scroll = "no"; // IE11
1455
document.body.style.margin = '0px'; // Override default document margin area on all browsers.
1456
1457
var hiddenElements = hideEverythingExceptGivenElement(target);
1458
1459
function restoreWindowedState() {
1460
restoreOldStyle();
1461
restoreHiddenElements(hiddenElements);
1462
removeEventListener('resize', softFullscreenResizeWebGLRenderTarget);
1463
if (strategy.canvasResizedCallback) {
1464
#if PTHREADS
1465
if (strategy.canvasResizedCallbackTargetThread) __emscripten_run_callback_on_thread(strategy.canvasResizedCallbackTargetThread, strategy.canvasResizedCallback, {{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData);
1466
else
1467
#endif
1468
{{{ makeDynCall('iipp', 'strategy.canvasResizedCallback') }}}({{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData);
1469
}
1470
currentFullscreenStrategy = 0;
1471
}
1472
restoreOldWindowedStyle = restoreWindowedState;
1473
currentFullscreenStrategy = strategy;
1474
addEventListener('resize', softFullscreenResizeWebGLRenderTarget);
1475
1476
// Inform the caller that the canvas size has changed.
1477
if (strategy.canvasResizedCallback) {
1478
#if PTHREADS
1479
if (strategy.canvasResizedCallbackTargetThread) __emscripten_run_callback_on_thread(strategy.canvasResizedCallbackTargetThread, strategy.canvasResizedCallback, {{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData);
1480
else
1481
#endif
1482
{{{ makeDynCall('iipp', 'strategy.canvasResizedCallback') }}}({{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData);
1483
}
1484
1485
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1486
},
1487
1488
emscripten_exit_soft_fullscreen__deps: ['$restoreOldWindowedStyle'],
1489
emscripten_exit_soft_fullscreen__proxy: 'sync',
1490
emscripten_exit_soft_fullscreen: () => {
1491
restoreOldWindowedStyle?.();
1492
restoreOldWindowedStyle = null;
1493
1494
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1495
},
1496
1497
emscripten_exit_fullscreen__deps: [
1498
'$JSEvents',
1499
'$specialHTMLTargets',
1500
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1501
'$JSEvents_requestFullscreen',
1502
#endif
1503
],
1504
emscripten_exit_fullscreen__proxy: 'sync',
1505
emscripten_exit_fullscreen: () => {
1506
if (!JSEvents.fullscreenEnabled()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1507
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1508
// Make sure no queued up calls will fire after this.
1509
JSEvents.removeDeferredCalls(JSEvents_requestFullscreen);
1510
#endif
1511
1512
var d = specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}];
1513
if (d.exitFullscreen) {
1514
d.fullscreenElement && d.exitFullscreen();
1515
#if MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED // https://caniuse.com/#feat=mdn-api_document_exitfullscreen
1516
} else if (d.webkitExitFullscreen) {
1517
d.webkitFullscreenElement && d.webkitExitFullscreen();
1518
#endif
1519
} else {
1520
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1521
}
1522
1523
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1524
},
1525
1526
$fillPointerlockChangeEventData__deps: ['$JSEvents', '$stringToUTF8'],
1527
$fillPointerlockChangeEventData: (eventStruct) => {
1528
var pointerLockElement = document.pointerLockElement;
1529
var isPointerlocked = !!pointerLockElement;
1530
// Assigning a boolean to HEAP32 with expected type coercion.
1531
/** @suppress{checkTypes} */
1532
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenPointerlockChangeEvent.isActive, 'isPointerlocked', 'i8') }}};
1533
var nodeName = JSEvents.getNodeNameForTarget(pointerLockElement);
1534
var id = pointerLockElement?.id || '';
1535
stringToUTF8(nodeName, eventStruct + {{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.nodeName }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}});
1536
stringToUTF8(id, eventStruct + {{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.id }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}});
1537
},
1538
1539
$registerPointerlockChangeEventCallback__noleakcheck: true,
1540
$registerPointerlockChangeEventCallback__deps: ['$JSEvents', '$fillPointerlockChangeEventData', 'malloc'],
1541
$registerPointerlockChangeEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
1542
#if PTHREADS
1543
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
1544
#endif
1545
var eventSize = {{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.__size__ }}};
1546
JSEvents.pointerlockChangeEvent ||= _malloc(eventSize);
1547
1548
var pointerlockChangeEventHandlerFunc = (e) => {
1549
var pointerlockChangeEvent = JSEvents.pointerlockChangeEvent;
1550
fillPointerlockChangeEventData(pointerlockChangeEvent);
1551
1552
#if PTHREADS
1553
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, pointerlockChangeEvent, eventSize, userData);
1554
else
1555
#endif
1556
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, pointerlockChangeEvent, userData)) e.preventDefault();
1557
};
1558
1559
var eventHandler = {
1560
target,
1561
eventTypeString,
1562
eventTypeId,
1563
userData,
1564
callbackfunc,
1565
handlerFunc: pointerlockChangeEventHandlerFunc,
1566
useCapture
1567
};
1568
return JSEvents.registerOrRemoveHandler(eventHandler);
1569
},
1570
1571
emscripten_set_pointerlockchange_callback_on_thread__proxy: 'sync',
1572
emscripten_set_pointerlockchange_callback_on_thread__deps: ['$registerPointerlockChangeEventCallback', '$findEventTarget',
1573
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1574
'$specialHTMLTargets'
1575
#endif
1576
],
1577
emscripten_set_pointerlockchange_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) => {
1578
if (!document.body?.requestPointerLock) {
1579
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1580
}
1581
1582
#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1583
target = findEventTarget(target);
1584
#else
1585
target = target ? findEventTarget(target) : specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}]; // Pointer lock change events need to be captured from 'document' by default instead of 'window'
1586
#endif
1587
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
1588
return registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKCHANGE }}}, "pointerlockchange", targetThread);
1589
},
1590
1591
$registerPointerlockErrorEventCallback__deps: ['$JSEvents'],
1592
$registerPointerlockErrorEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
1593
#if PTHREADS
1594
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
1595
#endif
1596
1597
var pointerlockErrorEventHandlerFunc = (e) => {
1598
#if PTHREADS
1599
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, 0, userData);
1600
else
1601
#endif
1602
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, 0, userData)) e.preventDefault();
1603
};
1604
1605
var eventHandler = {
1606
target,
1607
eventTypeString,
1608
eventTypeId,
1609
userData,
1610
callbackfunc,
1611
handlerFunc: pointerlockErrorEventHandlerFunc,
1612
useCapture
1613
};
1614
return JSEvents.registerOrRemoveHandler(eventHandler);
1615
},
1616
1617
emscripten_set_pointerlockerror_callback_on_thread__proxy: 'sync',
1618
emscripten_set_pointerlockerror_callback_on_thread__deps: ['$registerPointerlockErrorEventCallback', '$findEventTarget',
1619
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1620
'$specialHTMLTargets'
1621
#endif
1622
],
1623
emscripten_set_pointerlockerror_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) => {
1624
if (!document.body?.requestPointerLock) {
1625
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1626
}
1627
1628
#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1629
target = findEventTarget(target);
1630
#else
1631
target = target ? findEventTarget(target) : specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}]; // Pointer lock change events need to be captured from 'document' by default instead of 'window'
1632
#endif
1633
1634
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
1635
return registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKERROR }}}, "pointerlockerror", targetThread);
1636
},
1637
1638
emscripten_get_pointerlock_status__proxy: 'sync',
1639
emscripten_get_pointerlock_status__deps: ['$fillPointerlockChangeEventData'],
1640
emscripten_get_pointerlock_status: (pointerlockStatus) => {
1641
if (pointerlockStatus) fillPointerlockChangeEventData(pointerlockStatus);
1642
if (!document.body?.requestPointerLock) {
1643
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1644
}
1645
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1646
},
1647
1648
$requestPointerLock: (target) => {
1649
if (target.requestPointerLock) {
1650
target.requestPointerLock();
1651
} else {
1652
// document.body is known to accept pointer lock, so use that to differentiate if the user passed a bad element,
1653
// or if the whole browser just doesn't support the feature.
1654
if (document.body.requestPointerLock) {
1655
return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}};
1656
}
1657
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1658
}
1659
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1660
},
1661
1662
emscripten_request_pointerlock__proxy: 'sync',
1663
emscripten_request_pointerlock__deps: ['$requestPointerLock', '$findEventTarget',
1664
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1665
'$JSEvents',
1666
#endif
1667
],
1668
emscripten_request_pointerlock: (target, deferUntilInEventHandler) => {
1669
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1670
target ||= '#canvas';
1671
#endif
1672
target = findEventTarget(target);
1673
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
1674
if (!target.requestPointerLock) {
1675
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1676
}
1677
1678
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1679
// Queue this function call if we're not currently in an event handler and
1680
// the user saw it appropriate to do so.
1681
if (!JSEvents.canPerformEventHandlerRequests()) {
1682
if (deferUntilInEventHandler) {
1683
JSEvents.deferCall(requestPointerLock, 2 /* priority below fullscreen */, [target]);
1684
return {{{ cDefs.EMSCRIPTEN_RESULT_DEFERRED }}};
1685
}
1686
return {{{ cDefs.EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED }}};
1687
}
1688
#endif
1689
1690
return requestPointerLock(target);
1691
},
1692
1693
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1694
emscripten_exit_pointerlock__deps: ['$JSEvents', '$requestPointerLock'],
1695
#endif
1696
emscripten_exit_pointerlock__proxy: 'sync',
1697
emscripten_exit_pointerlock: () => {
1698
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1699
// Make sure no queued up calls will fire after this.
1700
JSEvents.removeDeferredCalls(requestPointerLock);
1701
#endif
1702
if (!document.exitPointerLock) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1703
document.exitPointerLock();
1704
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1705
},
1706
1707
emscripten_vibrate__proxy: 'sync',
1708
emscripten_vibrate: (msecs) => {
1709
if (!navigator.vibrate) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1710
navigator.vibrate(msecs);
1711
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1712
},
1713
1714
emscripten_vibrate_pattern__proxy: 'sync',
1715
emscripten_vibrate_pattern: (msecsArray, numEntries) => {
1716
if (!navigator.vibrate) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1717
1718
var vibrateList = [];
1719
for (var i = 0; i < numEntries; ++i) {
1720
var msecs = {{{ makeGetValue('msecsArray', 'i*4', 'i32') }}};
1721
vibrateList.push(msecs);
1722
}
1723
navigator.vibrate(vibrateList);
1724
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1725
},
1726
1727
$fillVisibilityChangeEventData: (eventStruct) => {
1728
var visibilityStates = [ "hidden", "visible", "prerender", "unloaded" ];
1729
var visibilityState = visibilityStates.indexOf(document.visibilityState);
1730
1731
// Assigning a boolean to HEAP32 with expected type coercion.
1732
/** @suppress{checkTypes} */
1733
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenVisibilityChangeEvent.hidden, 'document.hidden', 'i8') }}};
1734
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenVisibilityChangeEvent.visibilityState, 'visibilityState', 'i32') }}};
1735
},
1736
1737
$registerVisibilityChangeEventCallback__noleakcheck: true,
1738
$registerVisibilityChangeEventCallback__deps: ['$JSEvents', '$fillVisibilityChangeEventData', 'malloc'],
1739
$registerVisibilityChangeEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
1740
#if PTHREADS
1741
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
1742
#endif
1743
var eventSize = {{{ C_STRUCTS.EmscriptenVisibilityChangeEvent.__size__ }}};
1744
JSEvents.visibilityChangeEvent ||= _malloc(eventSize);
1745
1746
var visibilityChangeEventHandlerFunc = (e) => {
1747
var visibilityChangeEvent = JSEvents.visibilityChangeEvent;
1748
fillVisibilityChangeEventData(visibilityChangeEvent);
1749
1750
#if PTHREADS
1751
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, visibilityChangeEvent, eventSize, userData);
1752
else
1753
#endif
1754
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, visibilityChangeEvent, userData)) e.preventDefault();
1755
};
1756
1757
var eventHandler = {
1758
target,
1759
eventTypeString,
1760
eventTypeId,
1761
userData,
1762
callbackfunc,
1763
handlerFunc: visibilityChangeEventHandlerFunc,
1764
useCapture
1765
};
1766
return JSEvents.registerOrRemoveHandler(eventHandler);
1767
},
1768
1769
emscripten_set_visibilitychange_callback_on_thread__proxy: 'sync',
1770
emscripten_set_visibilitychange_callback_on_thread__deps: ['$registerVisibilityChangeEventCallback', '$specialHTMLTargets'],
1771
emscripten_set_visibilitychange_callback_on_thread: (userData, useCapture, callbackfunc, targetThread) => {
1772
#if ENVIRONMENT_MAY_BE_WORKER || ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL
1773
if (!specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}]) {
1774
return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
1775
}
1776
#endif
1777
return registerVisibilityChangeEventCallback(specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}], userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_VISIBILITYCHANGE }}}, "visibilitychange", targetThread);
1778
},
1779
1780
emscripten_get_visibility_status__proxy: 'sync',
1781
emscripten_get_visibility_status__deps: ['$fillVisibilityChangeEventData'],
1782
emscripten_get_visibility_status: (visibilityStatus) => {
1783
if (typeof document.visibilityState == 'undefined' && typeof document.hidden == 'undefined') {
1784
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1785
}
1786
fillVisibilityChangeEventData(visibilityStatus);
1787
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1788
},
1789
1790
$registerTouchEventCallback__noleakcheck: true,
1791
$registerTouchEventCallback__deps: ['$JSEvents', '$findEventTarget', '$getBoundingClientRect', 'malloc'],
1792
$registerTouchEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
1793
#if PTHREADS
1794
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
1795
#endif
1796
var eventSize = {{{ C_STRUCTS.EmscriptenTouchEvent.__size__ }}};
1797
JSEvents.touchEvent ||= _malloc(eventSize);
1798
1799
target = findEventTarget(target);
1800
1801
var touchEventHandlerFunc = (e) => {
1802
#if ASSERTIONS
1803
assert(e);
1804
#endif
1805
var t, touches = {}, et = e.touches;
1806
// To ease marshalling different kinds of touches that browser reports (all touches are listed in e.touches,
1807
// only changed touches in e.changedTouches, and touches on target at a.targetTouches), mark a boolean in
1808
// each Touch object so that we can later loop only once over all touches we see to marshall over to Wasm.
1809
1810
for (let t of et) {
1811
// Browser might recycle the generated Touch objects between each frame (Firefox on Android), so reset any
1812
// changed/target states we may have set from previous frame.
1813
t.isChanged = t.onTarget = 0;
1814
touches[t.identifier] = t;
1815
}
1816
// Mark which touches are part of the changedTouches list.
1817
for (let t of e.changedTouches) {
1818
t.isChanged = 1;
1819
touches[t.identifier] = t;
1820
}
1821
// Mark which touches are part of the targetTouches list.
1822
for (let t of e.targetTouches) {
1823
touches[t.identifier].onTarget = 1;
1824
}
1825
1826
var touchEvent = JSEvents.touchEvent;
1827
{{{ makeSetValue('touchEvent', C_STRUCTS.EmscriptenTouchEvent.timestamp, 'e.timeStamp', 'double') }}};
1828
HEAP8[touchEvent + {{{ C_STRUCTS.EmscriptenTouchEvent.ctrlKey }}}] = e.ctrlKey;
1829
HEAP8[touchEvent + {{{ C_STRUCTS.EmscriptenTouchEvent.shiftKey }}}] = e.shiftKey;
1830
HEAP8[touchEvent + {{{ C_STRUCTS.EmscriptenTouchEvent.altKey }}}] = e.altKey;
1831
HEAP8[touchEvent + {{{ C_STRUCTS.EmscriptenTouchEvent.metaKey }}}] = e.metaKey;
1832
var idx = touchEvent + {{{ C_STRUCTS.EmscriptenTouchEvent.touches }}};
1833
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1834
var canvasRect = Module['canvas'] ? getBoundingClientRect(Module['canvas']) : undefined;
1835
#endif
1836
var targetRect = getBoundingClientRect(target);
1837
var numTouches = 0;
1838
for (let t of Object.values(touches)) {
1839
var idx32 = {{{ getHeapOffset('idx', 'i32') }}}; // Pre-shift the ptr to index to HEAP32 to save code size
1840
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.identifier / 4 }}}] = t.identifier;
1841
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.screenX / 4 }}}] = t.screenX;
1842
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.screenY / 4 }}}] = t.screenY;
1843
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.clientX / 4 }}}] = t.clientX;
1844
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.clientY / 4 }}}] = t.clientY;
1845
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.pageX / 4 }}}] = t.pageX;
1846
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.pageY / 4 }}}] = t.pageY;
1847
HEAP8[idx + {{{ C_STRUCTS.EmscriptenTouchPoint.isChanged }}}] = t.isChanged;
1848
HEAP8[idx + {{{ C_STRUCTS.EmscriptenTouchPoint.onTarget }}}] = t.onTarget;
1849
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.targetX / 4 }}}] = t.clientX - (targetRect.left | 0);
1850
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.targetY / 4 }}}] = t.clientY - (targetRect.top | 0);
1851
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1852
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.canvasX / 4 }}}] = canvasRect ? t.clientX - (canvasRect.left | 0) : 0;
1853
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.canvasY / 4 }}}] = canvasRect ? t.clientY - (canvasRect.top | 0) : 0;
1854
#endif
1855
1856
idx += {{{ C_STRUCTS.EmscriptenTouchPoint.__size__ }}};
1857
1858
if (++numTouches > 31) {
1859
break;
1860
}
1861
}
1862
{{{ makeSetValue('touchEvent', C_STRUCTS.EmscriptenTouchEvent.numTouches, 'numTouches', 'i32') }}};
1863
1864
#if PTHREADS
1865
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, touchEvent, eventSize, userData);
1866
else
1867
#endif
1868
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, touchEvent, userData)) e.preventDefault();
1869
};
1870
1871
var eventHandler = {
1872
target,
1873
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1874
allowsDeferredCalls: eventTypeString == 'touchstart' || eventTypeString == 'touchend',
1875
#endif
1876
eventTypeString,
1877
eventTypeId,
1878
userData,
1879
callbackfunc,
1880
handlerFunc: touchEventHandlerFunc,
1881
useCapture
1882
};
1883
return JSEvents.registerOrRemoveHandler(eventHandler);
1884
},
1885
1886
emscripten_set_touchstart_callback_on_thread__proxy: 'sync',
1887
emscripten_set_touchstart_callback_on_thread__deps: ['$registerTouchEventCallback'],
1888
emscripten_set_touchstart_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
1889
registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHSTART }}}, "touchstart", targetThread),
1890
1891
emscripten_set_touchend_callback_on_thread__proxy: 'sync',
1892
emscripten_set_touchend_callback_on_thread__deps: ['$registerTouchEventCallback'],
1893
emscripten_set_touchend_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
1894
registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHEND }}}, "touchend", targetThread),
1895
1896
emscripten_set_touchmove_callback_on_thread__proxy: 'sync',
1897
emscripten_set_touchmove_callback_on_thread__deps: ['$registerTouchEventCallback'],
1898
emscripten_set_touchmove_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
1899
registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHMOVE }}}, "touchmove", targetThread),
1900
1901
emscripten_set_touchcancel_callback_on_thread__proxy: 'sync',
1902
emscripten_set_touchcancel_callback_on_thread__deps: ['$registerTouchEventCallback'],
1903
emscripten_set_touchcancel_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
1904
registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHCANCEL }}}, "touchcancel", targetThread),
1905
1906
$fillGamepadEventData__deps: ['$stringToUTF8'],
1907
$fillGamepadEventData: (eventStruct, e) => {
1908
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.timestamp, 'e.timestamp', 'double') }}};
1909
for (var i = 0; i < e.axes.length; ++i) {
1910
{{{ makeSetValue('eventStruct+i*8', C_STRUCTS.EmscriptenGamepadEvent.axis, 'e.axes[i]', 'double') }}};
1911
}
1912
for (var i = 0; i < e.buttons.length; ++i) {
1913
if (typeof e.buttons[i] == 'object') {
1914
{{{ makeSetValue('eventStruct+i*8', C_STRUCTS.EmscriptenGamepadEvent.analogButton, 'e.buttons[i].value', 'double') }}};
1915
} else {
1916
{{{ makeSetValue('eventStruct+i*8', C_STRUCTS.EmscriptenGamepadEvent.analogButton, 'e.buttons[i]', 'double') }}};
1917
}
1918
}
1919
for (var i = 0; i < e.buttons.length; ++i) {
1920
if (typeof e.buttons[i] == 'object') {
1921
{{{ makeSetValue('eventStruct+i', C_STRUCTS.EmscriptenGamepadEvent.digitalButton, 'e.buttons[i].pressed', 'i8') }}};
1922
} else {
1923
// Assigning a boolean to HEAP32, that's ok, but Closure would like to warn about it:
1924
/** @suppress {checkTypes} */
1925
{{{ makeSetValue('eventStruct+i', C_STRUCTS.EmscriptenGamepadEvent.digitalButton, 'e.buttons[i] == 1', 'i8') }}};
1926
}
1927
}
1928
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.connected, 'e.connected', 'i8') }}};
1929
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.index, 'e.index', 'i32') }}};
1930
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.numAxes, 'e.axes.length', 'i32') }}};
1931
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.numButtons, 'e.buttons.length', 'i32') }}};
1932
stringToUTF8(e.id, eventStruct + {{{ C_STRUCTS.EmscriptenGamepadEvent.id }}}, {{{ cDefs.EM_HTML5_MEDIUM_STRING_LEN_BYTES }}});
1933
stringToUTF8(e.mapping, eventStruct + {{{ C_STRUCTS.EmscriptenGamepadEvent.mapping }}}, {{{ cDefs.EM_HTML5_MEDIUM_STRING_LEN_BYTES }}});
1934
},
1935
1936
$registerGamepadEventCallback__noleakcheck: true,
1937
$registerGamepadEventCallback__deps: ['$JSEvents', '$fillGamepadEventData', '$findEventTarget', 'malloc'],
1938
$registerGamepadEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
1939
#if PTHREADS
1940
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
1941
#endif
1942
var eventSize = {{{ C_STRUCTS.EmscriptenGamepadEvent.__size__ }}};
1943
JSEvents.gamepadEvent ||= _malloc(eventSize);
1944
1945
var gamepadEventHandlerFunc = (e) => {
1946
var gamepadEvent = JSEvents.gamepadEvent;
1947
fillGamepadEventData(gamepadEvent, e["gamepad"]);
1948
1949
#if PTHREADS
1950
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, gamepadEvent, eventSize, userData);
1951
else
1952
#endif
1953
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, gamepadEvent, userData)) e.preventDefault();
1954
};
1955
1956
var eventHandler = {
1957
target: findEventTarget(target),
1958
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1959
allowsDeferredCalls: true,
1960
#endif
1961
eventTypeString,
1962
eventTypeId,
1963
userData,
1964
callbackfunc,
1965
handlerFunc: gamepadEventHandlerFunc,
1966
useCapture
1967
};
1968
return JSEvents.registerOrRemoveHandler(eventHandler);
1969
},
1970
1971
emscripten_set_gamepadconnected_callback_on_thread__proxy: 'sync',
1972
emscripten_set_gamepadconnected_callback_on_thread__deps: ['$registerGamepadEventCallback', 'emscripten_sample_gamepad_data'],
1973
emscripten_set_gamepadconnected_callback_on_thread: (userData, useCapture, callbackfunc, targetThread) => {
1974
if (_emscripten_sample_gamepad_data()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1975
return registerGamepadEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_GAMEPADCONNECTED }}}, "gamepadconnected", targetThread);
1976
},
1977
1978
emscripten_set_gamepaddisconnected_callback_on_thread__proxy: 'sync',
1979
emscripten_set_gamepaddisconnected_callback_on_thread__deps: ['$registerGamepadEventCallback', 'emscripten_sample_gamepad_data'],
1980
emscripten_set_gamepaddisconnected_callback_on_thread: (userData, useCapture, callbackfunc, targetThread) => {
1981
if (_emscripten_sample_gamepad_data()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1982
return registerGamepadEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED }}}, "gamepaddisconnected", targetThread);
1983
},
1984
1985
emscripten_sample_gamepad_data__docs: '/** @suppress {checkTypes} */', // We assign null to navigator.getGamepads, which Closure would like to complain about.
1986
emscripten_sample_gamepad_data__proxy: 'sync',
1987
emscripten_sample_gamepad_data__deps: ['$JSEvents'],
1988
emscripten_sample_gamepad_data: () => {
1989
try {
1990
if (navigator.getGamepads) return (JSEvents.lastGamepadState = navigator.getGamepads())
1991
? {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}} : {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1992
} catch(e) {
1993
#if ASSERTIONS
1994
err(`navigator.getGamepads() exists, but failed to execute with exception ${e}. Disabling Gamepad access.`);
1995
#endif
1996
navigator.getGamepads = null; // Disable getGamepads() so that it won't be attempted to be used again.
1997
}
1998
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1999
},
2000
2001
emscripten_get_num_gamepads__proxy: 'sync',
2002
emscripten_get_num_gamepads__deps: ['$JSEvents'],
2003
emscripten_get_num_gamepads: () => {
2004
#if ASSERTIONS
2005
assert(JSEvents.lastGamepadState, 'emscripten_get_num_gamepads() can only be called after having first called emscripten_sample_gamepad_data() and that function has returned EMSCRIPTEN_RESULT_SUCCESS!');
2006
#endif
2007
// N.B. Do not call emscripten_get_num_gamepads() unless having first called emscripten_sample_gamepad_data(), and that has returned EMSCRIPTEN_RESULT_SUCCESS.
2008
// Otherwise the following line will throw an exception.
2009
return JSEvents.lastGamepadState.length;
2010
},
2011
2012
emscripten_get_gamepad_status__proxy: 'sync',
2013
emscripten_get_gamepad_status__deps: ['$JSEvents', '$fillGamepadEventData'],
2014
emscripten_get_gamepad_status: (index, gamepadState) => {
2015
#if ASSERTIONS
2016
assert(JSEvents.lastGamepadState, 'emscripten_get_gamepad_status() can only be called after having first called emscripten_sample_gamepad_data() and that function has returned EMSCRIPTEN_RESULT_SUCCESS!');
2017
#endif
2018
// INVALID_PARAM is returned on a Gamepad index that never was there.
2019
if (index < 0 || index >= JSEvents.lastGamepadState.length) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}};
2020
2021
// NO_DATA is returned on a Gamepad index that was removed.
2022
// For previously disconnected gamepads there should be an empty slot (null/undefined/false) at the index.
2023
// This is because gamepads must keep their original position in the array.
2024
// For example, removing the first of two gamepads produces [null/undefined/false, gamepad].
2025
if (!JSEvents.lastGamepadState[index]) return {{{ cDefs.EMSCRIPTEN_RESULT_NO_DATA }}};
2026
2027
fillGamepadEventData(gamepadState, JSEvents.lastGamepadState[index]);
2028
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
2029
},
2030
2031
$registerBeforeUnloadEventCallback__deps: ['$JSEvents', '$findEventTarget'],
2032
$registerBeforeUnloadEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) => {
2033
var beforeUnloadEventHandlerFunc = (e) => {
2034
// Note: This is always called on the main browser thread, since it needs synchronously return a value!
2035
var confirmationMessage = {{{ makeDynCall('pipp', 'callbackfunc') }}}(eventTypeId, 0, userData);
2036
2037
if (confirmationMessage) {
2038
confirmationMessage = UTF8ToString(confirmationMessage);
2039
}
2040
if (confirmationMessage) {
2041
e.preventDefault();
2042
e.returnValue = confirmationMessage;
2043
return confirmationMessage;
2044
}
2045
};
2046
2047
var eventHandler = {
2048
target: findEventTarget(target),
2049
eventTypeString,
2050
eventTypeId,
2051
userData,
2052
callbackfunc,
2053
handlerFunc: beforeUnloadEventHandlerFunc,
2054
useCapture
2055
};
2056
return JSEvents.registerOrRemoveHandler(eventHandler);
2057
},
2058
2059
emscripten_set_beforeunload_callback_on_thread__proxy: 'sync',
2060
emscripten_set_beforeunload_callback_on_thread__deps: ['$registerBeforeUnloadEventCallback'],
2061
emscripten_set_beforeunload_callback_on_thread: (userData, callbackfunc, targetThread) => {
2062
if (typeof onbeforeunload == 'undefined') return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
2063
// beforeunload callback can only be registered on the main browser thread, because the page will go away immediately after returning from the handler,
2064
// and there is no time to start proxying it anywhere.
2065
if (targetThread !== {{{ cDefs.EM_CALLBACK_THREAD_CONTEXT_MAIN_RUNTIME_THREAD }}}) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}};
2066
return registerBeforeUnloadEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, true, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BEFOREUNLOAD }}}, "beforeunload");
2067
},
2068
2069
$fillBatteryEventData: (eventStruct, battery) => {
2070
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenBatteryEvent.chargingTime, 'battery.chargingTime', 'double') }}};
2071
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenBatteryEvent.dischargingTime, 'battery.dischargingTime', 'double') }}};
2072
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenBatteryEvent.level, 'battery.level', 'double') }}};
2073
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenBatteryEvent.charging, 'battery.charging', 'i8') }}};
2074
},
2075
2076
$hasBatteryAPI__internal: true,
2077
$hasBatteryAPI: () => globalThis.navigator?.getBattery,
2078
2079
$registerBatteryEventCallback__noleakcheck: true,
2080
$registerBatteryEventCallback__deps: ['$JSEvents', '$fillBatteryEventData', 'malloc'],
2081
$registerBatteryEventCallback: (battery, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
2082
#if PTHREADS
2083
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
2084
#endif
2085
var eventSize = {{{ C_STRUCTS.EmscriptenBatteryEvent.__size__ }}};
2086
JSEvents.batteryEvent ||= _malloc(eventSize)
2087
2088
var batteryEventHandlerFunc = (e) => {
2089
var batteryEvent = JSEvents.batteryEvent;
2090
fillBatteryEventData(batteryEvent, battery);
2091
2092
#if PTHREADS
2093
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, batteryEvent, eventSize, userData);
2094
else
2095
#endif
2096
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, batteryEvent, userData)) e.preventDefault();
2097
};
2098
2099
var eventHandler = {
2100
target: battery,
2101
eventTypeString,
2102
eventTypeId,
2103
userData,
2104
callbackfunc,
2105
handlerFunc: batteryEventHandlerFunc,
2106
useCapture
2107
};
2108
return JSEvents.registerOrRemoveHandler(eventHandler);
2109
},
2110
2111
emscripten_set_batterychargingchange_callback_on_thread__proxy: 'sync',
2112
emscripten_set_batterychargingchange_callback_on_thread__deps: ['$registerBatteryEventCallback', '$hasBatteryAPI'],
2113
emscripten_set_batterychargingchange_callback_on_thread: (userData, callbackfunc, targetThread) => {
2114
if (!hasBatteryAPI()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
2115
navigator.getBattery().then((b) => {
2116
registerBatteryEventCallback(b, userData, true, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE }}}, "chargingchange", targetThread);
2117
});
2118
},
2119
2120
emscripten_set_batterylevelchange_callback_on_thread__proxy: 'sync',
2121
emscripten_set_batterylevelchange_callback_on_thread__deps: ['$registerBatteryEventCallback', '$hasBatteryAPI'],
2122
emscripten_set_batterylevelchange_callback_on_thread: (userData, callbackfunc, targetThread) => {
2123
if (!hasBatteryAPI()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
2124
navigator.getBattery().then((b) => {
2125
registerBatteryEventCallback(b, userData, true, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE }}}, "levelchange", targetThread);
2126
});
2127
},
2128
2129
$batteryManager: undefined,
2130
$batteryManager__internal: true,
2131
2132
emscripten_get_battery_status__proxy: 'sync',
2133
emscripten_get_battery_status__deps: ['$fillBatteryEventData', '$hasBatteryAPI', '$batteryManager'],
2134
emscripten_get_battery_status: (batteryState) => {
2135
if (!hasBatteryAPI()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
2136
if (!batteryManager) {
2137
navigator.getBattery().then((b) => {
2138
batteryManager = b;
2139
});
2140
return {{{ cDefs.EMSCRIPTEN_RESULT_NO_DATA }}};
2141
}
2142
fillBatteryEventData(batteryState, batteryManager);
2143
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
2144
},
2145
2146
#if PTHREADS
2147
$setCanvasElementSizeCallingThread__deps: [
2148
#if OFFSCREENCANVAS_SUPPORT
2149
'$setOffscreenCanvasSizeOnTargetThread',
2150
#endif
2151
'$findCanvasEventTarget'],
2152
$setCanvasElementSizeCallingThread: (target, width, height) => {
2153
var canvas = findCanvasEventTarget(target);
2154
if (!canvas) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
2155
2156
#if OFFSCREENCANVAS_SUPPORT
2157
if (canvas.canvasSharedPtr) {
2158
// N.B. We hold the canvasSharedPtr info structure as the authoritative source for specifying the size of a canvas
2159
// since the actual canvas size changes are asynchronous if the canvas is owned by an OffscreenCanvas on another thread.
2160
// Therefore when setting the size, eagerly set the size of the canvas on the calling thread here, though this thread
2161
// might not be the one that actually ends up specifying the size, but the actual size change may be dispatched
2162
// as an asynchronous event below.
2163
{{{ makeSetValue('canvas.canvasSharedPtr', 0, 'width', 'i32') }}};
2164
{{{ makeSetValue('canvas.canvasSharedPtr', 4, 'height', 'i32') }}};
2165
}
2166
2167
if (canvas.offscreenCanvas || !canvas.controlTransferredOffscreen) {
2168
if (canvas.offscreenCanvas) canvas = canvas.offscreenCanvas;
2169
#else
2170
if (!canvas.controlTransferredOffscreen) {
2171
#endif
2172
var autoResizeViewport = false;
2173
if (canvas.GLctxObject?.GLctx) {
2174
var prevViewport = canvas.GLctxObject.GLctx.getParameter(0xBA2 /* GL_VIEWPORT */);
2175
// TODO: Perhaps autoResizeViewport should only be true if FBO 0 is currently active?
2176
autoResizeViewport = (prevViewport[0] === 0 && prevViewport[1] === 0 && prevViewport[2] === canvas.width && prevViewport[3] === canvas.height);
2177
#if GL_DEBUG
2178
dbg(`Resizing canvas from ${canvas.width}x${canvas.height} to ${width}x${height}. Previous GL viewport size was ${prevViewport}, so autoResizeViewport=${autoResizeViewport}`);
2179
#endif
2180
}
2181
canvas.width = width;
2182
canvas.height = height;
2183
if (autoResizeViewport) {
2184
#if GL_DEBUG
2185
dbg(`Automatically resizing GL viewport to cover whole render target ${width}x${height}`);
2186
#endif
2187
// TODO: Add -sCANVAS_RESIZE_SETS_GL_VIEWPORT=0/1 option (default=1). This is commonly done and several graphics engines depend on this,
2188
// but this can be quite disruptive.
2189
canvas.GLctxObject.GLctx.viewport(0, 0, width, height);
2190
}
2191
#if OFFSCREENCANVAS_SUPPORT
2192
} else if (canvas.canvasSharedPtr) {
2193
var targetThread = {{{ makeGetValue('canvas.canvasSharedPtr', 8, '*') }}};
2194
setOffscreenCanvasSizeOnTargetThread(targetThread, target, width, height);
2195
return {{{ cDefs.EMSCRIPTEN_RESULT_DEFERRED }}}; // This will have to be done asynchronously
2196
#endif
2197
} else {
2198
#if GL_DEBUG
2199
dbg('canvas.controlTransferredOffscreen but we do not own the canvas, and do not know who has (no canvas.canvasSharedPtr present, an internal bug?)!\n');
2200
#endif
2201
return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
2202
}
2203
#if OFFSCREEN_FRAMEBUFFER
2204
if (canvas.GLctxObject) GL.resizeOffscreenFramebuffer(canvas.GLctxObject);
2205
#endif
2206
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
2207
},
2208
2209
#if OFFSCREENCANVAS_SUPPORT
2210
$setOffscreenCanvasSizeOnTargetThread__deps: ['$stringToNewUTF8', '_emscripten_set_offscreencanvas_size_on_thread'],
2211
$setOffscreenCanvasSizeOnTargetThread: (targetThread, targetCanvas, width, height) => {
2212
targetCanvas = targetCanvas ? UTF8ToString(targetCanvas) : '';
2213
var targetCanvasPtr = 0;
2214
if (targetCanvas) {
2215
targetCanvasPtr = stringToNewUTF8(targetCanvas);
2216
}
2217
__emscripten_set_offscreencanvas_size_on_thread(targetThread, targetCanvasPtr, width, height);
2218
},
2219
#endif
2220
2221
$setCanvasElementSizeMainThread__proxy: 'sync',
2222
$setCanvasElementSizeMainThread__deps: ['$setCanvasElementSizeCallingThread'],
2223
$setCanvasElementSizeMainThread: (target, width, height) => setCanvasElementSizeCallingThread(target, width, height),
2224
2225
emscripten_set_canvas_element_size__deps: ['$setCanvasElementSizeCallingThread', '$setCanvasElementSizeMainThread', '$findCanvasEventTarget'],
2226
emscripten_set_canvas_element_size: (target, width, height) => {
2227
#if GL_DEBUG
2228
dbg(`emscripten_set_canvas_element_size(target=${target},width=${width},height=${height}`);
2229
#endif
2230
var canvas = findCanvasEventTarget(target);
2231
if (canvas) {
2232
return setCanvasElementSizeCallingThread(target, width, height);
2233
}
2234
return setCanvasElementSizeMainThread(target, width, height);
2235
},
2236
#else
2237
emscripten_set_canvas_element_size__deps: ['$findCanvasEventTarget'],
2238
emscripten_set_canvas_element_size: (target, width, height) => {
2239
#if GL_DEBUG
2240
dbg(`emscripten_set_canvas_element_size(target=${target},width=${width},height=${height}`);
2241
#endif
2242
var canvas = findCanvasEventTarget(target);
2243
if (!canvas) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
2244
canvas.width = width;
2245
canvas.height = height;
2246
#if OFFSCREEN_FRAMEBUFFER
2247
if (canvas.GLctxObject) GL.resizeOffscreenFramebuffer(canvas.GLctxObject);
2248
#endif
2249
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
2250
},
2251
#endif
2252
2253
$setCanvasElementSize__deps: ['emscripten_set_canvas_element_size', '$stackSave', '$stackRestore', '$stringToUTF8OnStack'],
2254
$setCanvasElementSize: (target, width, height) => {
2255
#if GL_DEBUG
2256
dbg(`setCanvasElementSize(target=${target},width=${width},height=${height}`);
2257
#endif
2258
if (!target.controlTransferredOffscreen) {
2259
target.width = width;
2260
target.height = height;
2261
} else {
2262
// This function is being called from high-level JavaScript code instead of asm.js/Wasm,
2263
// and it needs to synchronously proxy over to another thread, so marshal the string onto the heap to do the call.
2264
var sp = stackSave();
2265
var targetInt = stringToUTF8OnStack(target.id);
2266
_emscripten_set_canvas_element_size(targetInt, width, height);
2267
stackRestore(sp);
2268
}
2269
},
2270
2271
#if PTHREADS
2272
$getCanvasSizeCallingThread__deps: ['$findCanvasEventTarget'],
2273
$getCanvasSizeCallingThread: (target, width, height) => {
2274
var canvas = findCanvasEventTarget(target);
2275
if (!canvas) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
2276
2277
#if OFFSCREENCANVAS_SUPPORT
2278
if (canvas.canvasSharedPtr) {
2279
// N.B. Reading the size of the Canvas takes priority from our shared state structure, which is not the actual size.
2280
// However if is possible that there is a canvas size set event pending on an OffscreenCanvas owned by another thread,
2281
// so that the real sizes of the canvas have not updated yet. Therefore reading the real values would be racy.
2282
var w = {{{ makeGetValue('canvas.canvasSharedPtr', 0, 'i32') }}};
2283
var h = {{{ makeGetValue('canvas.canvasSharedPtr', 4, 'i32') }}};
2284
{{{ makeSetValue('width', 0, 'w', 'i32') }}};
2285
{{{ makeSetValue('height', 0, 'h', 'i32') }}};
2286
} else if (canvas.offscreenCanvas) {
2287
{{{ makeSetValue('width', 0, 'canvas.offscreenCanvas.width', 'i32') }}};
2288
{{{ makeSetValue('height', 0, 'canvas.offscreenCanvas.height', 'i32') }}};
2289
} else
2290
#endif
2291
if (!canvas.controlTransferredOffscreen) {
2292
{{{ makeSetValue('width', 0, 'canvas.width', 'i32') }}};
2293
{{{ makeSetValue('height', 0, 'canvas.height', 'i32') }}};
2294
} else {
2295
#if GL_DEBUG
2296
dbg('canvas.controlTransferredOffscreen but we do not own the canvas, and do not know who has (no canvas.canvasSharedPtr present, an internal bug?)!\n');
2297
#endif
2298
return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
2299
}
2300
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
2301
},
2302
2303
$getCanvasSizeMainThread__proxy: 'sync',
2304
$getCanvasSizeMainThread__deps: ['$getCanvasSizeCallingThread'],
2305
$getCanvasSizeMainThread: (target, width, height) => getCanvasSizeCallingThread(target, width, height),
2306
2307
emscripten_get_canvas_element_size__deps: ['$getCanvasSizeCallingThread', '$getCanvasSizeMainThread', '$findCanvasEventTarget'],
2308
emscripten_get_canvas_element_size: (target, width, height) => {
2309
var canvas = findCanvasEventTarget(target);
2310
if (canvas) {
2311
return getCanvasSizeCallingThread(target, width, height);
2312
}
2313
return getCanvasSizeMainThread(target, width, height);
2314
},
2315
#else
2316
emscripten_get_canvas_element_size__deps: ['$findCanvasEventTarget'],
2317
emscripten_get_canvas_element_size: (target, width, height) => {
2318
var canvas = findCanvasEventTarget(target);
2319
if (!canvas) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
2320
{{{ makeSetValue('width', '0', 'canvas.width', 'i32') }}};
2321
{{{ makeSetValue('height', '0', 'canvas.height', 'i32') }}};
2322
},
2323
#endif
2324
2325
// JavaScript-friendly API, returns pair [width, height]
2326
$getCanvasElementSize__deps: ['emscripten_get_canvas_element_size', '$stackSave', '$stackRestore', '$stringToUTF8OnStack'],
2327
$getCanvasElementSize: (target) => {
2328
var sp = stackSave();
2329
var w = stackAlloc(8);
2330
var h = w + 4;
2331
2332
var targetInt = stringToUTF8OnStack(target.id);
2333
var ret = _emscripten_get_canvas_element_size(targetInt, w, h);
2334
var size = [{{{ makeGetValue('w', 0, 'i32')}}}, {{{ makeGetValue('h', 0, 'i32')}}}];
2335
stackRestore(sp);
2336
return size;
2337
},
2338
2339
emscripten_set_element_css_size__proxy: 'sync',
2340
emscripten_set_element_css_size__deps: ['$findEventTarget'],
2341
emscripten_set_element_css_size: (target, width, height) => {
2342
#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
2343
target = findEventTarget(target);
2344
#else
2345
target = target ? findEventTarget(target) : Module['canvas'];
2346
#endif
2347
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
2348
2349
target.style.width = width + "px";
2350
target.style.height = height + "px";
2351
2352
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
2353
},
2354
2355
emscripten_get_element_css_size__proxy: 'sync',
2356
emscripten_get_element_css_size__deps: ['$findEventTarget', '$getBoundingClientRect'],
2357
emscripten_get_element_css_size: (target, width, height) => {
2358
#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
2359
target = findEventTarget(target);
2360
#else
2361
target = target ? findEventTarget(target) : Module['canvas'];
2362
#endif
2363
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
2364
2365
var rect = getBoundingClientRect(target);
2366
{{{ makeSetValue('width', '0', 'rect.width', 'double') }}};
2367
{{{ makeSetValue('height', '0', 'rect.height', 'double') }}};
2368
2369
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
2370
},
2371
2372
emscripten_html5_remove_all_event_listeners__deps: ['$JSEvents'],
2373
emscripten_html5_remove_all_event_listeners: () => JSEvents.removeAllEventListeners(),
2374
2375
emscripten_request_animation_frame: (cb, userData) =>
2376
requestAnimationFrame((timeStamp) => {{{ makeDynCall('idp', 'cb') }}}(timeStamp, userData)),
2377
2378
emscripten_cancel_animation_frame: (id) => cancelAnimationFrame(id),
2379
2380
emscripten_request_animation_frame_loop: (cb, userData) => {
2381
function tick(timeStamp) {
2382
if ({{{ makeDynCall('idp', 'cb') }}}(timeStamp, userData)) {
2383
requestAnimationFrame(tick);
2384
}
2385
}
2386
return requestAnimationFrame(tick);
2387
},
2388
2389
emscripten_get_device_pixel_ratio__proxy: 'sync',
2390
emscripten_get_device_pixel_ratio: () => {
2391
#if ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL
2392
return globalThis.devicePixelRatio ?? 1.0;
2393
#else // otherwise, on the web and in workers, things are simpler
2394
return devicePixelRatio;
2395
#endif
2396
}
2397
};
2398
2399
addToLibrary(LibraryHTML5);
2400
2401